Java

Java(9) 자주 쓰는 API - Object 클래스, String 클래스, 이스케이프 문자

hyomee2 2024. 8. 8. 21:43

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: 탭

- \': 작은 따옴표

- \": 큰 따옴표

- \\: 역슬래쉬

- 이스케이프 문자를 사용 안하는 특수 문자: ~ ` ! @ # % & - _ = ; : ' \ " , < > /

- 이스케이프 문자를 사용하는 특수 문자: $ ^ * ( ) + | { } [ ] . ?