√ String 클래스
문자열 값 수정 불가능, immutable(불변)
수정 시 수정된 문자열이 새로 할당 되어 새 주소를 넘김
√ StringBuffer 클래스
문자열 값 수정 가능, mutable(가변)
수정, 삭제 등이 기존 문자열에 수정되어 적용
기본 16문자 크기로 지정된 버퍼를 이용하며 크기 증가 가능
쓰레드 safe기능 제공(성능 저하 요인)
√ StringBuilder 클래스
StringBuffer와 동일하나 쓰레드 safe기능을 제공하지 않음
√ StringTokenizer 클래스
String클래스에서 제공하는 split()메서드와 같은 기능을 하는 클래스로 생성 시 전달받은 문자열을 구분자로 나누어 각 토큰에 저장
√ 예시
import java.util.*;
public class TestStringTokenizer {
public static void main(String[] args) {
String str = "AA|BB|CC";
StringTokenizer st = new StringTokenizer(str, "|");
while(st.hasMoreTokens()) {
System.out.println(st.nextToken());
}
}
}
primitive Data Type을 객체화 해주는 클래스
-(proxy 패턴) 대신, 대체
√ String을 기본 자료형으로 바꾸기
casting : 같은 유형 끼리 변환
parsing : 다른 유형으로 변환
byte b = Byte.parseByte("1");
short s = Short.ParseShort("2");
int i = Integer.parseInt("3");
long l = Long.parseLong("4");
float f = Float.parseFloat("0.1");
double d = Double.parseDouble("0.2");
boolean bool = Boolean.parseBoolean("true");
char c = "abc".charAt(0);
√ 기본 자료형을 String으로 바꾸기
String b = Byte.valueOf((byte)1).toString();
String s = Short.valueOf((short)2).toString();
String i = Integer.valueOf(3).toString();
String l = Long.valueOf(4L).toString();
String f = Float.valueOf(0.1f).toString();
String d = Double.valueOf(0.2).toString();
String bool = Boolean.valueOf(true).toString();
String ch = Character.valueOf('a').toString();
√ Date 클래스
시스템으로부터 현재 날짜, 시간 정보를 가져와서 다룰 수 있게 만들어진 클래스
생성자 2개와 몇 개의 메서드만 사용 가능하고 나머지는 모두 deprecatedCalendar 클래스 혹은 GregorianCalendar 클래스 사용 권장
√ 예시
Date today = new Date();
// 시스템으로부터 현재 날짜, 시간 정보를 가져와 기본 값으로 사용
Date when = new Date(123456789L);
// long형 정수 값을 가지고 날짜 시간 계산
// 1970년 1월 1일 0시 0분 0초를 기준으로 함
√ Calendar 클래스
Calendar클래스는 생성자가 protected이기 때문에 new연산자를 통해 객체 생성 불가능
getInstance() 메서드를 통해서 객체 생성
√ GregorianCalendar 클래스
GregorianCalendar클래스는 Calendar클래스의 후손 클래스
년, 월, 일, 시, 분, 초 정보를 필드를 이용하여 다룰 수 있음
√ SimpleDateFormat 클래스
Date의 날짜, 시간 정보를 원하는 format으로 출력하는 기능 제공
java.text 패키지에 속해있음
√ 예시
Date today = new Date();
SimpleDateFormat ft = new SimpleDateFormat("yyyy-MM-dd");
String ftToday = ft.format(today);
// today에 포맷을 적용한 결과를 문자열로 리턴
package edu.kh.api.run;
import edu.kh.api.view.APIView;
public class APIRun {
public static void main(String[] args) {
APIView view = new APIView();
view.displayMenu();
}
}
package edu.kh.api.dto;
public class Student {
private int grade;
private int classRoom;
private int number;
private String name;
// 기본 생성자
public Student() {}
// 매개변수 생성자
public Student(int grade, int classRoom, int number, String name) {
this.grade = grade;
this.classRoom = classRoom;
this.number = number;
this.name = name;
}
// getter / setter
public int getGrade() {
return grade;
}
public void setGrade(int grade) {
this.grade = grade;
}
public int getClassRoom() {
return classRoom;
}
public void setClassRoom(int classRoom) {
this.classRoom = classRoom;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// toString() 오버라이딩
@Override
public String toString() {
return String.format("%d / %d / %d / %s", grade, classRoom, number, name);
}
// Object.equals() 오버라이딩
// -> 현재 객체와 다른 객체가 동등(필드 값이 같은지) 비교
// -> 필드를 가지고 있는 자식 클래스
// 알맞은 형태로 재정의(오버라이딩)
@Override
public boolean equals(Object obj) {
// 같은 객체를 참조할 경우
if(this == obj) return true;
// null인 경우 비교 자체가 불필요
if(obj==null) return false;
// 비교를 위해 전달받은 객체는 Student가 맞는가?
// false인 경우 실행
if(!(obj instanceof Student)) return false;
// 필드 비교
Student other = (Student)obj; // obj 다운 캐스팅
if(this.grade != other.grade) return false;
if(this.classRoom != other.classRoom) return false;
if(this.number != other.number) return false;
if(!this.name.equals(other.name)) return false;
return true; // 모든 필드가 같을 경우
}
// Object.hashCode()
// - 두 객체의 필드 값이 같다면
// hashCode()도 똑같은 정수 값을 반환해야 한다.
// - hash 함수 : 입력 받은 문자열/숫자를
// 특정한 길이의 문자열/숫자로 변환
// --> 최대한 중복되지 않는 숫자를 만들어냄
// hashCode() : 객체의 필드 값을 이용해서
// 일정한 길이의 숫자를 만드는 함수
// 왜 필요한가? Java 실행 시 내부에서 객체 검색하는 속도 증가
// 어떻게 작성하는가?
// 필드 값이 같다면 항상 같은 수가 나올 수 있도록 구현
// + equals() 오버라이딩 시 필수적으로 같이 오버라이딩
@Override
public int hashCode() {
int result = 1;
final int PRIME = 31; // 소수 (곱연산 시 속도가 빠름)
result = result * PRIME + grade;
result = result * PRIME + classRoom;
result = result * PRIME + number;
result = result * PRIME
+ (name==null ? 0 : name.hashCode());
return result;
}
}
package edu.kh.api.service;
import edu.kh.api.dto.Student;
public class APIService {
// API (Application Programming Interface)
// 응용 프로그래밍 접점
// -> 프로그래밍 언어가 이미 가지고 있는 클래스/기능/기술을
// 사용자가 쉽게 사용할 수 있도록 제공하는 것
private Student[] studentList = new Student[10];
public APIService() {
studentList[0] = new Student(1, 1, 1, "김영희");
studentList[1] = new Student(2, 3, 4, "홍길동");
studentList[2] = new Student(3, 5, 12, "박민지");
}
// alt + shift + j
/**학생 추가 서비스
* @param grade
* @param classRoom
* @param number
* @param name
* @return 추가 성공 시 true / 실패 시 false
*/
public boolean addStudent(int grade, int classRoom, int number, String name) {
int index = 0; // 비어있는 index 저장
for(Student s : studentList) {
if(s==null) break;
boolean check1 = s.getGrade() == grade;
boolean check2 = s.getClassRoom() == classRoom;
boolean check3 = s.getNumber() == number;
boolean check4 = s.getName().equals(name);
// 학생 배열에 입력 받은 학생이 존재 한다면
if(check1&&check2&&check3&&check4) return false;
index++;
}
// 학생 배열에 학생이 가득 찬 경우
if(index == studentList.length) return false;
// 지정된 index에 학생 추가
studentList[index] = new Student(grade, classRoom, number, name);
return true;
}
/**학생 추가 서비스2 (equals / hashCode 사용)
* @param grade
* @param classRoom
* @param number
* @param name
* @return 추가 성공 시 true / 실패 시 false
*/
public boolean addStudent2(int grade, int classRoom, int number, String name) {
// 1. equals()를 이용한 비교
// 1) 전달 받은 값을 임시 학생 객체 생성
Student temp = new Student(grade, classRoom, number, name);
// 2) 학생 배열을 순차 접근하면서 동등한 학생이 있는지 검사
int index = 0;
for(Student s : studentList) {
if(s == null) break;
// s가 참조하는 학생과
// temp가 참조하는 학생의
// 필드 값이 같을 경우(동등한 경우)
// if(s.equals(temp)) return false;
System.out.println(s.hashCode());
System.out.println(temp.hashCode());
System.out.println("-----------------------");
// hashCode()가 같다 == 필드가 같다 == 중복되는 학생이다
if(s.hashCode() == temp.hashCode()) return false;
index++;
}
// 3) 학생 배열에 학생이 가득 찬 경우
if(index == studentList.length) return false;
// 4) 임시 학생 객체를 학생 배열에 추가
studentList[index] = temp;
return true;
}
/**학생 배열에서 이름 검색
* @param input
* @return 일치하는 학생이 있으면 Student[]
* 없으면 null
*/
public Student[] selectName(String input) {
// 김영희
// 손흥민,김영희,박민지
// String.split([구분자]) : 문자열을 구분자를 기준으로 나누어
// String[] 형태로 반환
// String[] names = input.split(",");
String[] names = input.split(",|/"); // , 또는 / 를 기준으로 구분
// 검색된 학생을 저장할 배열
Student[] result = new Student[studentList.length];
int index = 0; // result 배열에 저장될 위치를 지정할 변수
for(String n : names) {
for(Student s : studentList) {
if(s==null) break;
// 입력받은 이름이랑 학생의 이름이 같다면
if(s.getName().equals(n)) {
result[index++] = s;
}
}
}
if(index==0) {
return null;
}
// 검색된 학생이 있으면 검색 결과를 저장한 배열 반환
return result;
}
/**모든 학생 이름을 하나의 문자열로 반환
* @return
*/
public String printName() {
// [김영희, 홍길동, 박민지, null, null, null, null, null, null, null]
int size = 0;
// 현재 학생의 수 구하기
for(Student s : studentList) {
if(s==null) break;
size++;
}
// 이름만 저장할 배열 생성
String[] names = new String[size];
for(int i=0;i<size;i++) {
names[i] = studentList[i].getName();
}
// String.join("구분자", String[])
// -> String[]의 요소를 하나의 문자열로 합침
// 단, 요소 사이사이에 "구분자" 추가
// ex) String[] arr = {"aaa", "bbb", "ccc"};
// Stirng.join("@", arr);
// -> "aaa@bbb@ccc"
return String.join("<>", names);
}
}
package edu.kh.api.view;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.InputMismatchException;
import java.util.Scanner;
import edu.kh.api.dto.Student;
import edu.kh.api.service.APIService;
public class APIView {
private Scanner sc = new Scanner(System.in);
private APIService service = new APIService();
public void displayMenu() {
int input = 0;
do {
System.out.println("--- API 테스트 프로그램 ---");
System.out.println("1. equals() + hashCode() ");
System.out.println("2. String 클래스 제공 메서드1(split)");
System.out.println("3. String 클래스 제공 메서드2(join)");
System.out.println("4. String 클래스의 특징, 문제점");
System.out.println("5. StringBuffer/Builder");
System.out.println("6. 문자열을 계속 입력 받아 한번에 출력하기");
System.out.println("7. Wrapper Class");
System.out.println("8. Date 클래스");
System.out.println("0. 프로그램 종료");
System.out.print("메뉴 선택 : ");
try {
input = sc.nextInt();
sc.nextLine(); // 버퍼에 남은 개행문자 제거
switch(input) {
case 1 : ex1(); break;
case 2 : ex2(); break;
case 3 : ex3(); break;
case 4 : ex4(); break;
case 5 : ex5(); break;
case 6 : ex6(); break;
case 7 : ex7(); break;
case 8 : ex8(); break;
case 0 : break;
default: System.out.println("메뉴에 존재하는 번호만 입력 해주세요.");
}
} catch(InputMismatchException e) {
// Scanner 입력이 잘못된 경우
System.out.println("잘못된 형식을 입력 하셨습니다. 다시 시도해주세요.");
sc.nextLine(); // 입력 버퍼에 남아있는
// 잘못 입력된 문자열을 읽어와 없앰
input = -1; // input값에 0이 아닌 값을 대입하여
// while이 종료되지 않게함
}
} while(input!=0);
}
private void ex1() {
// 한 학생의 정보를 입력받아 Service의 학생 배열에 추가
// 단, 중복되는 학생은 제외
System.out.println("\n--- 학생 정보 입력---\n");
System.out.print("학년 : ");
int grade = sc.nextInt();
System.out.print("반 : ");
int classRoom = sc.nextInt();
System.out.print("번호 : ");
int number = sc.nextInt();
sc.nextLine(); // 입력 버퍼에 남아있는 개행문자 제거
System.out.print("이름 : ");
String name = sc.nextLine();
if(service.addStudent2(grade, classRoom, number, name)) {
System.out.println("[추가되었습니다]");
} else {
System.out.println("중복되는 학생이 존재하거나 배열이 가득 찼습니다.");
}
}
public void ex2() {
// 이름을 여려명을 한 줄로 입력 받아
// 학생 배열에 같은 이름의 학생이 있다면 출력
System.out.println("\n--- 학생 검색 ---\n");
System.out.println("검색할 이름(여러 명 검색 시 / 또는 , 로 구분) : ");
// 손흥민,김영희,박찬호
Student[] result = service.selectName(sc.nextLine());
if(result == null) {
System.out.println("[검색 결과가 없습니다]");
}else {
for(Student s : result) {
if(s==null) break;
System.out.println(s.toString());
}
}
}
public void ex3() {
System.out.println("\n--- 모든 학생 이름 출력 ---\n");
System.out.println(service.printName());
}
public void ex4() {
// String 특징, 문제점
// 1. String 객체 생성 방법
String s1 = new String("abc"); // Heap 메모리 영역에 String 객체 생성
String s2 = "abc"; // String은 사용 빈도가 높기 때문에
// 별도의 리터럴 표기법을 부여하여 쉽게 객체 생성
// -> Heap 영역 중 String Pool에 객체 생성
String s3 = "abc";
// hashCode() : 필드값이 같으면 같은 수
// System.out.println(s1.hashCode());
// System.out.println(s2.hashCode());
// System.out.println(s3.hashCode());
// System.identityHashCode(객체주소)
// -> 객체 주소를 이용해서 만든 정수를 반환
System.out.println("s1 : " + System.identityHashCode(s1));
System.out.println("s2 : " + System.identityHashCode(s2));
System.out.println("s3 : " + System.identityHashCode(s3));
// "abc"
s3 += "def"; // "abcdef"
System.out.println("-----------------------");
System.out.println("s2 : " + System.identityHashCode(s2));
System.out.println("s3 : " + System.identityHashCode(s3));
// 왜 값이 달라졌을까??
// String은 불변성(한 번 저장된 값은 변할 수 없음) 특징 때문에
// String 값을 변경할 경우
// 기존 객체가 변경되는 것이 아닌
// 새 객체를 생성해서 참조하게 된다.
}
private void ex5() {
System.out.println("\n--- StringBuffer/Builder ---\n");
// StringBuffer, StringBuilder 두 클래스는 제공하는 메서드가 동일하다
// StringBuffer sb = new StringBuffer();
StringBuilder sb = new StringBuilder();
// StringBuffer.capacity() : 현재 버퍼의 크기
System.out.println(sb.capacity());
System.out.println("현재 주소 : " + System.identityHashCode(sb));
// StringBuffer.append(문자열)
// StringBuffer 객체에 문자열을 기존 데이터 뒤에 붙임
sb.append("abc");
// StringBuffer.toString()
// - StringBuffer에 저장된 문자열을 String 형태로 반환
System.out.println("sb에 저장된 문자열 : " + sb.toString());
System.out.println("abc 추가 후 주소 : " + System.identityHashCode(sb));
sb.append("def");
System.out.println("sb에 저장된 문자열 : " + sb.toString());
System.out.println("abc 추가 후 주소 : " + System.identityHashCode(sb));
// 새로운 문자열이 추가되어도
// 객체의 주소는 변하지 않음 == 가변성(mutable)
// -> 문자열 수정 시 새로운 객체를 생성하지 않아
// 메모리 소비를 절약할 수 있다.
// insert(인덱스, 문자열) : 중간 삽입
sb.insert(2, "@");
System.out.println(sb.toString());
// delete(int start, int end) : 삭제(start 이상 end 미만)
sb.delete(3, 5); // ab@ cd ef
System.out.println(sb.toString());
System.out.println(sb.length());
// replace(int start, int end, String str)
// - start 이상 end 미만을 str로 변경
sb.replace(0, 2, "AB");
System.out.println(sb.toString());
}
private void ex6() {
System.out.println("\n--- 문자열을 계속 입력 받아 한번에 출력하기 ---\n");
StringBuffer sb = new StringBuffer();
System.out.println("문자열 입력 (종료를 원할 경우 !wq 입력)");
String str = null;
while(true) {
// sc.nextLine(); : 한 줄을 입력 받아 String 반환
// sb.append(String str) : 기존 문자열 뒤에 추가
str = sc.nextLine();
// 입력 종료를 원하는 경우
if(str.equals("!wq")) {
break;
}
sb.append(str);
sb.append("\n"); // \n : 개행문자 (new line)
}
// delete()를 이용해 마지막 문자열 제거
sb.delete(sb.length()-1, sb.length());
System.out.println("----- 입력 받은 내용 -----");
System.out.println(sb.toString());
}
private void ex7() {
System.out.println("\n--- Wrapper Class ---\n");
/* Wrapper Class
* - 기본 자료형을 객체로 다룰 수 있도록 포장하는 클래스
*
* 왜 포장이 필요한가?
* 1) 기본 자료형이 제공하지 않는 추가 필드, 메서드 제공하기 위해
* 2) 기본 자료형을 객체로 다뤄야 하는 경우가 있기 때문에
* (컬렉션)
* */
// Integer(+ 모든 Wrapper 클래스) 제공 상수 필드
System.out.println(Integer.BYTES); // byte 단위 크기
System.out.println(Integer.SIZE); // bit 단위 크기
System.out.println(Integer.MAX_VALUE); // 자료형 최대값
System.out.println(Integer.MIN_VALUE); // 자료형 최소값
System.out.println(Integer.TYPE); // Wrapper 클래스 대상 타입
// String을 기본자료형으로 변환
int i = Integer.parseInt("100") + 50;
System.out.println("i = " + i);
long l = Long.parseLong("10000000000") + 10_000_000_000L;
System.out.println("l = " + l);
double d = Double.parseDouble("3.1415926534") + 10.0;
System.out.println("d = " + d);
// 기본 자료형 -> String 변환
String str1 = Integer.valueOf(123).toString();
String str2 = 999 + "";
// "" : 빈 문자열 (내용이 없는 길이 0짜리 String)
// Wrapper Class를 이용하여 객체 생성
Integer iNum1 = new Integer(10);
int iNum2 = iNum1;
// (int) = (Integer) -> (int) [AutoUnboxing]
System.out.println("iNum2 : " + iNum2);
Integer iNum3 = 50;
// (Integer) = (int) -> (Integer) [AutoBoxing]
/* Boxing / Unboxing
* Boxing : 기본 자료형 -> Wrapper Class 객체
* Unboxing : Wrapper Class 객체 -> 기본 자료형
*
* AutoBoxing / AutoUnboxing
* - 사용자가 신경쓰지 않아도
* 상황에 따라 기본 자료형 <-> Wrapper Class 객체로
* 자동으로 변하는 기술
* */
}
private void ex8() {
System.out.println("\n--- Date Class ---\n");
// java.util.Date
Date d1 = new Date(); // 기본 생성자
// 객체 생성 시점의 시간 저장
System.out.println(d1.toString());
Date d2 = new Date(0L); // Date(long date)
// Date 기준 시간으로 부터
// ms 단위로 지난 시간을 계산해서 저장
System.out.println(d2.toString());
// Thu Jan 01 09:00:00 KST 1970
Date d3 = new Date(1000L);
System.out.println(d3.toString());
// System.currentTimeMillis()
// -> 기준 시간으로 부터 지난 시간 (ms)
System.out.println("현재시간 - 기준시간 (ms) : " + System.currentTimeMillis());
// 현재 시간으로 부터 1시간 후를 저장
long temp = 60 * 60 * 1000; // 3600000 ms == 1시간
// 분 초 ms
Date d4 = new Date(System.currentTimeMillis() + temp);
System.out.println(d4.toString());
// SimpleDateFormat : 간단하게 날짜 형식을 지정하는 객체
// java.text 패키지에서 제공
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat sdf2 = new SimpleDateFormat("G yyyy년 MM월 dd일 HH시 mm분 ss초");
SimpleDateFormat sdf3 = new SimpleDateFormat("yyyy년 MM월 dd일 E요일 a HH시 mm분 ss초");
System.out.println(sdf1.format(d4));
System.out.println(sdf2.format(d4));
System.out.println(sdf3.format(d4));
}
}