라봉이의 개발 블로그

java의 정석 9강. java.lang 패키지(상) 본문

Java/Java의 정석 읽고 정리

java의 정석 9강. java.lang 패키지(상)

Labhong 2018. 6. 11. 14:24
반응형

자바에서 java.lang 패키지는 기본이 되는 패키지이기 때문에 import 없이 사용할 수 있다.

그 중 많이 사용되는 것들을 알아보자



1. Object 클래스


Object는 모든 클래스의 최고 조상이기 때문에 Object 클래스의 모든 멤버들은 모든 클래스에서 모두 사용할 수 있다.


Object 메서드에서 중요한 몇가지를 살펴보자



1.1 equals 메서드


객체의 참조변수를 받아서 비교하여 그 결과를 boolean 값으로 알려주는 역할을 한다.

public boolean equals(Object obj) {
  return (this == obj);
}


코드를 보면 알 수 있듯이 서로 다른 두 객체를 equals 메서드로 비교하면 항상 false를 반환한다.


equals 메서드는 결국 두 개의 참조변수가 같은 객체를 참조하고 있는지, 즉 두 참조변수에 저장된 값(주소값)이 같은지를 판단하는 기능 밖에 할 수 없다.

물론 override 하여 사용자가 정의한 기능대로 바꿀 수 있다.



class Person {
    long id;

    public boolean equals(Object obj) {
        if(obj != null && obj instanceof Person) {
            return id == ((Person)obj).id;
        } else {
            return false;
        }
    }

    Person(long id) {
        this.id = id;
    }
}

public class Main {
    public static void main(String[] args) {
        Person p1 = new Person(8011081111222L);
        Person p2 = new Person(8011081111222L);

        if(p1 == p2) {
            System.out.println("p1과 p2는 같은 사람입니다.");
        } else {
            System.out.println("p1과 p2는 다른 사람입니다.");
        }

        if(p1.equals(p2)) {
            System.out.println("p1과 p2는 같은 사람입니다.");
        } else {
            System.out.println("p1과 p2는 다른 사람입니다.");
        }
    }
}

출력 결과:

p1과 p2는 다른 사람입니다.

p1과 p2는 같은 사람입니다.



1.2 hashCode 메서드


이 메서드는 해싱 기법에 사용되는 해시함수를 구현한 것이다.

hashCode 메서드는 객체의 주소값을 이용해서 해시코드를 만들어 반환하기 때문에 서로 다른 두 객체는 절대 같은 값을 가질 수 없다.


위의 equals와 마찬가지로 사용자가 적절하게 오버라이딩 할 수 있다.

public class Main {
    public static void main(String[] args) {
        String str1 = new String("abc");
        String str2 = new String("abc");

        System.out.println(str1.hashCode());        // String은 hashCode 메서드를 같은 문자열이면
        System.out.println(str2.hashCode());        // 출력 결과가 같도록 오버라이딩 했다.
        System.out.println(System.identityHashCode(str1));  // System.identityHashCode는 객체의 주소값으로 해시코드를
        System.out.println(System.identityHashCode(str2));  // 생성하기 때문에 항상 다른 해시코드값을 반환할 것을 보장한다.
    }
}



1.3 toString 메서드


toString()은 인스턴스에 대한 정보를 문자열로 제공할 목적으로 정의한 것이다.

Object클래스에 정의된 toString()은 다음과 같다.

public String toString() {
    return getClass().getName() + "@"
            + Integer.toHexString(hashCode());
}


따로 오버라이딩 하지 않는다면 클래스이름16진수의 해시코드를 얻게될 것이다.



1.4 clone 메서드


이 메서드는 자신을 복제하여 새로운 인스턴스를 생성하는 일을 한다.

Object클래스에 정의된 clone 메서드는 단순히 멤버변수의 값만 복사하기 때문에 배열이나 인스턴스가 멤버로 정의되어 있는 클래스의 인스턴스는 완전한 복제가 이루어지지 않는다.(얕은 복사)


이런 경우 clone 메서드를 오버라이딩해서 새로운 배열을 생성하고 배열의 내용을 복사하도록 해야 한다.(깊은 복사)

class Point implements Cloneable {
    // Cloneable인터페이스를 구현한 클래스에서만 clone()을 호출할 수 있다. 이 인터페이스를 구현하지 않고
    // clone()을 호출하면 예외가 발생한다.
    int x;
    int y;

    Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public String toString() {
        return "x=" + x + ", y=" + y;
    }
    public Object clone() {
        Object obj = null;
        try {
            // clone 메서드에는 CloneNotSupportedException이 선언되어 있으므로 try catch문 안에서 사용해야한다.
            obj = super.clone();
        } catch (CloneNotSupportedException e) {}
        return obj;
    }
}

public class Main {
    public static void main(String[] args) {
        Point original = new Point(3, 5);
        Point copy = (Point)original.clone();

        System.out.println(original);
        System.out.println(copy);
    }
}

출력 결과:

x=3, y=5

x=3, y=5


사실 clone은 아무렇게 오버로딩하는 것이 아니라 특정한 조건을 만족시켜야 한다.

clone()을 지원하려면 먼저 cloneable 인터페이스를 implements 해야하며 Object 클래스에 정의되어 있는 protected native Object clone() 메서드를 public으로 재정의해서 사용해야 합니다.(재정의하지 않으면 다른 패키지에서 호출할 수 없다.)



2. String 클래스


자바에서는 문자열을 위한 클래스 String이 있다.



2.1 String클래스의 특징


String클래스에는 문자열을 저장하기 위해서 문자형 배열변수 (char[]) value를 인스턴스 변수로 정의해놓고 있다.

인스턴스 생성 시 생성자의 매개변수로 입력받는 문자열은 이 인스턴스 변수에 문자열 배열(char[])로 저장되는 것이다.

public class Main {
    public static void main(String[] args) {
        String str1 = "abc";
        String str2 = "abc";

        System.out.println("String str1 = \"abc\";");
        System.out.println("String str2 = \"abc\";");

        if (str1 == str2)
            System.out.println("str1 == str2 ? true");
        else
            System.out.println("str1 == str2 ? false");

        if (str1.equals(str2))
            System.out.println("str1.equals(str2) ? true");
        else
            System.out.println("str1.equals(str2) ? false");
        System.out.println();

        String str3 = new String("\"abc\"");
        String str4 = new String("\"abc\"");

        System.out.println("String str3 = new String(\"abc\");");
        System.out.println("String str4 = new String(\"abc\");");

        if (str3 == str4)
            System.out.println("str3 == str4 ? true");
        else
            System.out.println("str3 == str4 ? false");

        if (str3.equals(str4))
            System.out.println("str3.equals(str4) ? true");
        else
            System.out.println("str3.equals(str4) ? false");
    }
}

출력 결과:

String str1 = "abc";

String str2 = "abc";

str1 == str2 ? true

str1.equals(str2) ? true


String str3 = new String("abc");

String str4 = new String("abc");

str3 == str4 ? false

str3.equals(str4) ? true


이 코드를 보여주는 이유는 문자열을 리터럴로 지정하는 방법과 String클래스의 생성자를 사용했을 때의 차이점을 보여주기 위한 것이다.

리터럴로 생성하게 되면 "abc" 문자열의 주소값은 같으므로 비교 연산자로 비교했을 때 true가 나온다.

하지만 String클래스 생성자로 생성했을 경우 둘의 인스턴스의 주소값은 각각 따로 생겨나기 때문에 다르다. 따라서 비교 연산자로 비교했을 때 false가 나오는 것이다.


String클래스의 특징 중 또 한가지는 한번 생성된 String인스턴스가 갖고 있는 문자열은 읽어올 수만 있고, 변경할 수는 없다.

그래서 덧셈연산자(+)를 사용해서 문자열을 결합하는 것은 매 연산 시 마다 새로운 문자열을 가진 String인스턴스가 생성되어 메모리 공간을 차지하기 때문에 가능한 사용하지 않는 것이 좋다.


문자열간의 결합이나 추출 등 문자열 작업이 많을 때는 StirngBuffer클래스를 사용하는 것이 좋다.



2.2 빈 문자열(empty string)


크기가 0인 배열이 존재할 수 있을까? 답은 그렇다 이다.

문자열 배열도 마찬가지이다. String str = ""; 이렇게 빈 문자열을 선언할 수 있다.

보통 빈 문자열을 선언할 시에 String str = null 보다는 String str = "" 이렇게 선언하는 것이 좋다.



2.3 String 클래스의 생성자와 메서드


생성자:

- String(String s)

- String(char[] val): char배열과 같은 문자열을 갖는 String인스턴스 생성

- String(StringBuffer buf) : StringBuffer와 같은 문자열을 갖는 String인스턴스 생성


메서드:

- char charAt(int index): 지정된 위치에 있는 문자를 알려줌

- String concat(String str): 문자열str을 뒤에 덧붙임

- boolean contains(CharSequence s): 지정된 문자열s가 포함되었는지를 검사

- boolean endsWith(String suffix): 지정된 문자열suffix로 끝나는지 검사

- boolean equals(Object obj): 매개변수로 받은 문자열 obj와 String인스턴스의 문자열을 비교

- boolean equalsIgnoreCase(String str): 문자열과 String인스턴스의 문자열을 대소문자 구분없이 비교

- int indexOf(int ch): 주어진 문자ch가 문자열에 존재하는 지 확인하여 위치 반환. 없으면 -1

- int indexOf(String str): 위와 같다.

- int lastIndexOf(int ch): 지정된 문자 또는 문자코드를 문자열의 오른쪽 끝에서부터 찾아서 위치를 반환. 없으면 -1

- int lastIndexOf(String str): 위와 같다.

- int length(): 문자열의 길이를 알려줌.

- String replace(CharSequence old, CharSequence nw): 문자열old를 문자열nw로 바꿈

- String replaceAll(String regex, String replacement): 문자열regex와 일치하는 것을 모두 문자열replacement로 바꾼다.

- String[] split(String regex): 문자열을 지정된 분리자(regex)로 나누어 문자열 배열에 담아 반환.

- String substring(int begin[, int end]): 시작위치부터 끝 위치 범위에 포함된 문자열을 얻는다.

- String toLowerCase, toUpperCase(): 문자열을 소문자 혹은 대문자로 바꿔서 반환

- static String valueOf(anything): 지정된 값을 문자열로 변환하여 반환, Object의 경우 toString()을 호출한다.

반응형
Comments