본문 바로가기

프로그래밍/JAVA

[JAVA} Object 클래스


java.lnag 패키지는 자바프로그래밍에 가장 기본이 되는 클래스들을 포함하고 있다.

따라서 import 문 없이도 사용할 수 있다.


0. 개 론


가장 많이 사용하는 메서드는 equals, toString, hashCode이며 사용할 떄는 반드시 "오버라이딩"해야 한다.

equals와 hashCode는 사용자가 알맞게 정의해야 사용할 수 있다.

오버라이딩 하기 위해서 메뉴중에 Soruce메뉴를 보면, Generate라는 도구가 있다.

워낙 자주 사용하기 때문에 이렇게 이클립스가 지원하는 부분이다.


1. Object 클래스


모든 클래스의 최고조상이기 때문에 Object 클래스의 멤버들은 모든 클래스에서 바로 사용이 가능하다. 멤버변수는 없고, 11개의 메서드만 가지고 있다.


Object 클래스 내에 정의된 메서드를 "오버라이딩"하고 있는 경우가 많으므로 이 개념에 대해 적절하게 학습할 필요가 있다.

     1. 오버라이딩(overriding)

오버라이딩이란 상속관계에 있는 자식클래스에서 상속받은 자원을 재정의 하는 것이다.

오버라이딩은 자식클래스에서만 가능하고 오버로딩하고자 하는 메서드의 선언부를 그대로 사용해야 한다.


2. 자손의 접근제어자는 조상의 접근제어자 보다 같거나 넓어야 한다.



1.1 equals 메서드


equals 메서드는 주소값으로 비교를 한다.

따라서 e와 f에서 새로운 객체를 생성(new)한 뒤 비교하면 e.equals(f)false값을 내뱉는다.


단, String 클래스에서는 equals 메서드를 오버라이딩(재정의)하기 때문에 내용이 같으면 true값을 준다.

그래서 String c와 String d는 true를 반환한다.


(1. 상식적으로 너무나 자주쓰는 String 클래스를 누가 "주소값"으로 비교하고 싶겠는가? 

따라서 내용으로만 비교하도록 String 클래스에서 equals 메서드를 재정의했다.)


(2. 모든 클래스의 조상은 Object 클래스라고 했다. 따라서 상속(extends)없이도 Object 내 메서드인 equals를 재정의할 수 있다.)


그렇다면 String 클래스가 아닌 일반 클래스에서 equals메서드를 이용해 주소값이 아닌 "내용"을 비교하게 하려면 마찬가지로 오버라이딩 하면 된다.


obj!=null을 통해 널 체크(Null Check)를 하고, id값을 참조하기 위해 Person 타입으로 형변환을 통해 id값을 참조한다.



1.2 hashCode 메서드


이 메서드는 데이터관리 기법 중의 하나이다. Hash는 내부적으로 배열(=Hash Table)을 사용해 데이터를 저장하기 때문에 다량의 데이터를 저장하는 것이 가능하고 빠른 검색 속도를 갖는다.


이 Hash Table에 데이터를 저장하는 특별한 알고리즘이 존재하는데, 이 알고리즘을 구현한 메서드를 hashCode 메서드라고 한다. 여기에 찾고자 하는 을 입력하면, 그 값이 저장된 위치를 알려주는 "정수"의 코드를 반환한다.


hashCode메서드는 "객체의 주소값"을 이용해 해시코드를 만들어 반환한다.

따라서 한 번의 실행에서 서로 다른 두 객체가 같은 해시코드를 가질 수 없다.

class exercise {
public static void main(String[] args) {

String str1 = new String ("abc");
String str2 = new String ("abc");

System.out.println(str1.hashCode());
System.out.println(str2.hashCode());
System.out.println(System.identityHashCode(str1));
System.out.println(System.identityHashCode(str2));

}
} <출력값> : 정수로 출력되는 것을 볼 수 있다. 96354 96354 705927765 366712642


String클래스는 문자열의 내용이 같으면 동일한 해시코드를 반환하도록 hashCode메서드를 오버라이딩 해놓았다.


하지만 System.identityHashCode(Obejct x)는 모든 객체에 대해 항상 다른 해시코드값을 반환한다. (서로 다른 객체임)


1.3 toString 메서드


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

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

자바 API에 정의된 toString메서드이다. 클래스를 작성할 때 toString()을 오버라이딩하지 않는다면, 클래스이름에 16진수의 해시코드를 얻게 될 것이다.

해시코드는 인스턴스의 주소와 관련된 값으로, 서로 다른 인스턴스는 서로 다른 해시코드값을 가진다. (아래 코드를 보자!)


class exercise {
public static void main(String[] args) {

Card c1 = new Card();
Card c2 = new Card();


System.out.println(c1.toString());
System.out.println(c2.toString());

}
}
class Card{ } 출력값

Card@2a139a55 // 클래스이름 @ 해시코드값 형태로 출력 Card@15db9742 // 클래스이름 @ 해시코드값 형태로 출력

위 코드는 toString 메서드를 오버라이딩 해라! 라는 뜻이다.

오버라이딩 하지 않는다면 "클래스이름 + 16진수의 해시코드"와 같은 형태로 나오게 된다. 

따라서 아래와 같이 오버라이딩 해야 원하는 문자열이 출력된다.


오른쪽 코드와 같이 Card 클래스에서 toString 메서드를 재정의하고 있다.

단, Object에 정의된 toString의 접근제어자가 public이므로, Card클래스에서 오버라이딩 할 때 public으로 했다는 것을 눈 여겨 보자.


조상클래스에 정의된 메서드를 자손클래스에서 오버라이딩할 떄는 조상클래스에서 정의된 접근범위보다 같거나 넓어야 한다.


그런데! String 클래스와 Date 클래스의 toString()을 호출하면 클래스이름@해시코드값 형태가 아니라

"문자열"로 반환된다. 그 이유는 태생적으로 그렇게 오버라이딩 되어 있기 때문이다.


toString()은 일반적으로 인스턴스나 클래스에 대한 정보 또는 인스턴스 변수들의 값을 "문자열로 반환"하도록 오버라이딩된다.


1.4 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() { // Object 클래스의 toString메서드를 재정의하고 있다.
return "x="+x +", y="+y;
}

public Object clone() { // 기존의 protected 접근 제어자에서 → public으로 오버라이딩                                     // 만약 private로 한다면 오버라이딩은 가능하지만                             // 조상클래스에 작성된 clone메서드를 호출(super.clone() 할 수 없음
Object obj=null;
try {
obj = super.clone();
} catch(CloneNotSupportedException e) {}

// clone메서드에는 CloneNotSupportedException이 선언되어 있으므로 // 이 메서드를 호출할 때는 try-catch문을 사용해야한다.

return (Point)obj;
}
}

class CloneTest {
public static void main(String[] args){
Point original = new Point(3, 5);
Point copy = original.clone(); // 객체를 복제해서 새로운 객체를 만든다.
System.out.println(original);
System.out.println(copy);
}
}

데이터 보호를 하기 위해서, 클래스 작성자가 복제를 허용하는 경우 Clonnable 인터페이스를 구현한 경우에만 복제가 가능하게 한다.


Object 클래스의 정의된 clone메서드의 접근제어자가 protected이므로 자손클래스에서는 이보다 더 넓거나 같은 접근 제어자를 사용해야 한다.


접근 제어자를 public으로 바꾸고, Object클래스의 clone메서드를 통해 인스턴스를 복제할 것이다.


'프로그래밍 > JAVA' 카테고리의 다른 글

[JAVA] String 클래스  (0) 2016.08.25
[JAVA] 내부 클래스(inner class)  (0) 2016.08.13
[JAVA} 예외처리(Exceptpion Handing)  (0) 2016.08.07
[JAVA] 인터페이스(Interface)  (1) 2016.08.04
[JAVA] 추상클래스(Abstract Class)  (0) 2016.08.02