Java(9) 자주 쓰는 API - Object 클래스, String 클래스, 이스케이프 문자
1. Object 클래스
- 자바에서의 최상위 부모 클래스로, 모든 클래스는 Object 클래스를 상속하고 있으므로 Object 안에 있는 메소드 사용 가능
- java.lang.Object
(1) toString()
: "인스턴스 생성 시 사용한 full class name + "@" + 16진수 해시코드" 가 문자열로 반환
- 16진수 해시코드는 인스턴스의 주소를 가리키는 값으로 인스턴스마다 다른 값 반환
(2) equals()
: 매개변수로 전달받은 인스턴스와 동일 객체인지 비교
- 동일 객체 : 주소가 동일한 인스턴스
- 동등 객체 : 주소가 다르더라도 필드 값이 동일한 인스턴스
(3) hashCode()
: 객체의 메모리 주소값을 이용해 해시코드(객체를 식별하는 값)를 만들어 반환
- equals() 메소드를 재정의하는 경우 반드시 hashCode() 메소드도 재정의하도록 되어 있다.
public class Book {
private int number;
private String title;
private String author;
private int price;
public Book(int number, String title, String author, int price) {
this.number = number;
this.title = title;
this.author = author;
this.price = price;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
@Override
public String toString() {
return "Book{" +
"number=" + number +
", title='" + title + '\'' +
", author='" + author + '\'' +
", price=" + price +
'}';
}
@Override
public boolean equals(Object o) {
// 주소 값이 같은 경우(동일 객체), 필드 값 비교 없이 바로 true 반환
if (this == o) return true;
// 전달 객체가 null이거나 다른 타입이면 바로 false 반환
if (o == null || getClass() != o.getClass()) return false;
// Book 타입이면서 동일 객체가 아니므로 동등 객체인지 비교
Book book = (Book) o;
// 모든 필드 값이 동일할 경우 true 반환
return number == book.number && price == book.price && Objects.equals(title, book.title) && Objects.equals(author, book.author);
}
@Override
public int hashCode() {
return Objects.hash(number, title, author, price);
}
}
public class Application {
public static void main(String[] args) {
Book book1 = new Book(1, "홍길동전", "허균", 50000);
Book book2 = new Book(2, "목민심서", "정약용", 60000);
Book book3 = new Book(3, "삼국사기", "김부식", 70000);
System.out.println(book1.toString());
System.out.println(book2.toString());
System.out.println(book3.toString());
// 레퍼런스 변수를 출력하면 자동으로 toString() 을 호출. 이 점을 이용하여 toString()를 재정의해서 사용
System.out.println(book1);
System.out.println(book2);
System.out.println(book3);
Book book4 = new Book(4, "혼공자", "저자", 30000);
Book book5 = new Book(4, "혼공자", "저자", 30000);
// Object의 hashCode(), equals()는 주소값을 기반으로 동일 객체에 대한 판단을 하지만
// Book에 재작성 된 메소드는 동등 객체에 대한 판단을 하도록 한다.
System.out.println(book4.hashCode());
System.out.println(book5.hashCode());
System.out.println(book4 == book5);
System.out.println(book4.equals(book5));
}
}
2. String 클래스
- String 인스턴스는 한 번 생성되면 그 값을 읽기만 가능하고 변경할 수는 없다 = 불변 객체
ㄴ> 자바에서 덧셈 연산자를 이용해 문자열 결합을 하는 경우 기존 문자열이 변경되는 것이 아니라
문자열이 합쳐진 새로운 String 인스턴스 가 생성된다.
(1) 자주 쓰는 함수들
// 1. charAt(): 해당 문자열의 특정 인덱스에 해당하는 문자 반환
String str1 = "apple";
for(int i = 0; i < str1.length(); i++) {
System.out.println("charAt(" + i + ") : " + str1.charAt(i));
}
/* 실행결과
charAt(0) : a
charAt(1) : p
charAt(2) : p
charAt(3) : l
charAt(4) : e */
/* 2. compareTo() : 인자로 전달 된 문자열과 사전 순으로 비교해서
인자로 전달 된 문자열보다 작으면 음수, 같으면 0, 크면 양수를 반환 (대소문자 구분) */
String str2 = "java";
String str3 = "java";
String str4 = "JAVA";
String str5 = "oracle";
System.out.println("compareTo() : " + (str2.compareTo(str3))); // compareTo() : 0
// 대문자와 소문자는 32만큼 차이난다.
System.out.println("compareTo() : " + (str2.compareTo(str4))); // compareTo() : 32
System.out.println("compareTo() : " + (str4.compareTo(str2))); // compareTo() : -32
// j부터 o까지 5만큼 차이난다.
System.out.println("compareTo() : " + (str2.compareTo(str5))); // compareTo() : -5
System.out.println("compareTo() : " + (str5.compareTo(str2))); // compareTo() : 5
// 3. compareToIgnoreCase() : 대소문자를 구분하지 않고 비교
System.out.println("compareToIgnoreCase() : " + (str3.compareToIgnoreCase(str4))); // compareToIgnoreCase() : 0
// 4. concat() : 문자열에 인자로 전달된 문자열을 합쳐서 새로운 문자열을 반환
// 원본 문자열에는 영향을 주지 않는다.
String str6 = "java";
String str7 = "oracle";
System.out.println("concat() : " + (str6.concat(str7))); // concat() : javaoracle
System.out.println("str6 : " + str6); // str6 : java
// 5. indexOf() : 문자열에서 특정 문자와 처음 일치하는 인덱스 위치를 정수형으로 반환
// 일치하는 문자가 없는 경우 -1 반환
String indexOf = "java oracle";
System.out.println("indexOf('a') : " + indexOf.indexOf('a')); // indexOf('a') : 1
System.out.println("indexOf('z') : " + indexOf.indexOf('z')); // indexOf('z') : -1
// 6. lastIndexOf() : 문자열 탐색을 뒤에서부터 하고 처음 일치하는 위치의 인덱스를 반환
// 일치하는 문자가 없는 경우 -1을 반환
System.out.println("lastIndexOf('a') : " + indexOf.lastIndexOf('a')); // lastIndexOf('a') : 7
System.out.println("lastIndexOf('z') : " + indexOf.lastIndexOf('z')); // lastIndexOf('z') : -1
// 7. trim() : 문자열의 앞 뒤에 공백을 제거한 문자열을 반환
String trimStr = " java "; //앞 뒤 공백 3칸
// 앞 뒤 공백을 확인하기 위해 # 기호를 붙였다.
System.out.println("trimStr : #" + trimStr + "#");
System.out.println("trim() : #" + trimStr.trim() + "#"); //공백 제거됨
// 원본에 영향을 주지는 않는다.
System.out.println("trimStr : #" + trimStr + "#");
// 8. toLowerCase() : 모든 문자를 소문자로 변환
// 9. toUpperCase() : 모든 문자를 대문자로 변환시킨다.
// 원본에는 영향을 주지 않는다.
String caseStr = "JavaOracle";
System.out.println("toLowerCase() : " + caseStr.toLowerCase()); // toLowerCase() : javaoracle
System.out.println("toUpperCase() : " + caseStr.toUpperCase()); // toUpperCase() : JAVAORACLE
System.out.println("caseStr : " + caseStr); // caseStr : JavaOracle
// 10. substring() : 문자열의 일부분을 잘라내어 새로운 문자열을 반환 (원본에 영향을 주지 않는다.)
String javaoracle = "javaoracle";
System.out.println("substring(3, 6) : " + javaoracle.substring(3, 6)); // substring(3, 6) : aor
System.out.println("substring(3) : " + javaoracle.substring(3)); // substring(3) : aoracle
System.out.println("javaoracle : " + javaoracle); // javaoracle : javaoracle
// 11. replace() : 문자열에서 대체할 문자열로 기존 문자열을 변경해서 반환 (원본에 영향주지 않는다.)
System.out.println("replace() : " + javaoracle.replace("java", "python")); // replace() : pythonoracle
System.out.println("javaoracle : " + javaoracle); // javaoracle : javaoracle
// 12. length() : 문자열의 길이를 정수형으로 반환
System.out.println("length() : " + javaoracle.length()); // length() : 10
System.out.println("빈 문자열 길이 : " + ("".length())); // 빈 문자열 길이 : 0
// 13. isEmpty() : 문자열의 길이가 0이면 true, 아니면 false 반환
// 길이가 0인 문자열은 null과는 다르다.
System.out.println("isEmpty() : " + "".isEmpty()); // isEmpty() : true
System.out.println("isEmpty() : " + "abc".isEmpty()); isEmpty() : false
(2) split()과 StringTokenizer
: 문자열을 특정 구분자로 하여 분리하여 반환
1) split()
- 정규표현식을 이용해서 문자열 분리
- 비정형화된 문자열을 분리할 때 좋지만(공백 문자열 값 포함), 정규표현식을 이용하기 때문에 속도가 느리다는 단점을 갖는다.
String emp1 = "100/홍길동/서울/영업부"; //모든 값 존재
String emp2 = "200/유관순//총무부"; //주소 없음
String emp3 = "300/이순신/경기도/"; //부서 없음
// split()을 이용한 분리
String[] empArr1 = emp1.split("/");
String[] empArr2 = emp2.split("/");
String[] empArr3 = emp3.split("/");
for(int i = 0; i < empArr1.length; i++)
System.out.println("empArr1[" + i + "] : " + empArr1[i]); //정상 출력
for(int i = 0; i < empArr2.length; i++)
System.out.println("empArr2[" + i + "] : " + empArr2[i]); //중간값 빈 문자열
for(int i = 0; i < empArr3.length; i++)
System.out.println("empArr3[" + i + "] : " + empArr3[i]); //마지막 값 출력 안됨
/* 실행 결과
empArr1[0] : 100
empArr1[1] : 홍길동
empArr1[2] : 서울
empArr1[3] : 영업부
empArr2[0] : 200
empArr2[1] : 유관순
empArr2[2] :
empArr2[3] : 총무부
empArr3[0] : 300
empArr3[1] : 이순신
empArr3[2] : 경기도 // empArr3[3]은 아예 출력 안된다.
*/
// 마지막 구분자 사이에 값이 존재하지 않는 경우 이후 값도 추출하고 싶을 때 몇 개의 토큰으로 분리할 지를 두번째 인자로 넣어줄 수 있다.
// 이 때 음수를 넣으면 마지막 구분자 뒤의 값이 존재하지 않는 경우 빈 문자열로 토큰 생성
String[] empArr4 = emp3.split("/", -1);
String[] empArr5 = emp3.split("/", 0);
String[] empArr6 = emp3.split("/", 1);
String[] empArr7 = emp3.split("/", 2);
for(int i = 0; i < empArr4.length; i++)
System.out.println("empArr4[" + i + "] : " + empArr4[i]); // 마지막 값도 출력 됨
/* 실행 결과
empArr4[0] : 300
empArr4[1] : 이순신
empArr4[2] : 경기도
empArr4[3] :
*/
for(int i = 0; i < empArr5.length; i++)
System.out.println("empArr[" + i + "] : " + empArr5[i]);
/* 실행 결과
empArr4[0] : 300
empArr4[1] : 이순신
empArr4[2] : 경기도
*/
for(int i = 0; i < empArr6.length; i++)
System.out.println("empArr6[" + i + "] : " + empArr6[i]);
/* 실행 결과
empArr4[0] : 300/이순신/경기도/
*/
for(int i = 0; i < empArr7.length; i++)
System.out.println("empArr7[" + i + "] : " + empArr7[i]);
/* 실행 결과
empArr4[0] : 300
empArr4[1] : 이순신/경기도/
*/
2) StringTokenizer
- 문자열의 모든 문자들을 구분자로 하여 문자열 분리.
- 정형화된 문자열 패턴을 분리할 때 사용하기 좋다.(공백 문자열 무시)
- split()보다 속도면에서 더 빠르다.
- 구분자를 생략하는 경우 공백이 기본 구분자
String emp1 = "100/홍길동/서울/영업부"; //모든 값 존재
String emp2 = "200/유관순//총무부"; //주소 없음
String emp3 = "300/이순신/경기도/"; //부서 없음
// StringTokenizer의 경우 공백으로 존재하는 값을 무시
StringTokenizer st1 = new StringTokenizer(emp1, "/");
StringTokenizer st2 = new StringTokenizer(emp2, "/");
StringTokenizer st3 = new StringTokenizer(emp3, "/");
while(st1.hasMoreTokens())
System.out.println("st1 : " + st1.nextToken());
while(st2.hasMoreTokens())
System.out.println("st2 : " + st2.nextToken());
while(st3.hasMoreTokens())
System.out.println("st3 : " + st3.nextToken());
/* 실행 결과
st1 : 100
st1 : 홍길동
st1 : 서울
st1 : 영업부
st2 : 200
st2 : 유관순
st2 : 총무부
st3 : 300
st3 : 이순신
st3 : 경기도
*/
// nextToken()으로 토큰을 꺼내면 해당 StingTokenizer의 토큰을 재사용하는 것 불가
// split()은 정규표현식 이용(문자열 패턴), StringTokenizer는 구분자 문자열 이용
String colorStr = "red*oranage#blue/yellow green";
// "*#/ " 이라는 문자열이 구분자로 존재하지 않아서 에러 발생
// String[] colors = colorStr.split("*#/ "); //에러
// 대괄호로 묶은 문자열은 문자열이 아닌 각 문자들의 패턴으로 볼 수 있다.
// 따라서 순서 상관 없이 존재하는 문자들을 이용해서 구분자로 사용할 수 있다.
String[] colors = colorStr.split("[*/# ]"); //순서 상관 없다
for(int i = 0; i < colors.length; i++)
System.out.println("colors[" + i + "] : " + colors[i]);
/* 실행 결과
colors[0] : red
colors[1] : oranage
colors[2] : blue
colors[3] : yellow
colors[4] : green
*/
// StringTokenizer의 두 번째 인자 문자열 자체는 연속된 문자열이 아닌 하나하나를 구분자로 이용하겠다는 의미
StringTokenizer colorStringTokenizer = new StringTokenizer(colorStr, "*#/ ");
while(colorStringTokenizer.hasMoreTokens())
System.out.println(colorStringTokenizer.nextToken());
/* 실행 결과
red
oranage
blue
yellow
green
*/
(3) 이스케이프 문자
: 문자열 내에서 사용하는 문자 중 특수문자를 표현하거나 특수기능을 사용할 때 사용하는 문자
- \n: 줄바꿈
- \t: 탭
- \': 작은 따옴표
- \": 큰 따옴표
- \\: 역슬래쉬
- 이스케이프 문자를 사용 안하는 특수 문자: ~ ` ! @ # % & - _ = ; : ' \ " , < > /
- 이스케이프 문자를 사용하는 특수 문자: $ ^ * ( ) + | { } [ ] . ?