Object 클래스
Object 클래스는 모든 클래스의 최상위 클래스다.
java.lang.Object 클래스이며 모든 클래스는 Object클래스에서 상속받는다.
모든 클래스는 Object 클래스의 메서드를 사용할 수 있으며 일부 메서드를 재정의하여 사용할 수 있다.
단, 당연히 final 메서드는 재정의할 수 없다.
Object 클래스는 직접 코딩하지 않아도 컴파일러가 import 해주기 때문에 따로 import하지 않아도 사용할 수 있다.
Object 클래스는 주로 toString(), equals(), hashCode(), clone() 을 흔히 재정의해서 사용한다.
toString()
toString 메서드의 원형은
getClass().getName() + "@" + Integer.toHexString(hashCode()); 이렇게 되어있다.
기본 동작은 객체의 해시코드를 출력하게 되며 재정의 하는 목적은 객체의 정보를 문자열 형태로 표현하고 할 때
사용하기 위함이다.
예제코드
class Book {
String title;
String author;
public Book(String title, String author) {
this.title = title;
this.author = author;
}
public String toString(){
return title + ", " + author;
}
}
public class ToStringTest {
public static void main(String[] args) {
Book book = new Book("Java", "name");
System.out.println(book);
String str = new String("Java");
System.out.println(str);
}
}
이 코드를 실행하면 결과는 Java, name Java가 출력된다. 만약 Book 클래스에서 toString을 재정의 하지 않았다면
메모리 주소값을 출력하고 str인 Java를 출력한다.
str의 경우 String 클래스 안에 toString이 이미 정의되어 있기 때문에 문자열이 그대로 출력되지만 Book에서는
toString을 정의하지 않은 상태이기 때문에 메모리주소값이 출력되는 것이다.
이것으로 인해 toString의 원형은 메모리주소라는 것을 확인할 수 있다.
equals()
두 객체의 동일함을 논리적으로 재정의 할 수 있다.
물리적 동일함은 같은 주소를 갖는 객체이고 논리적 동일함은 같은 학번의 학생, 같은 주문번호의 주문과 같은
것이다.
물리적으로 다른 메모리에 위치한 객체라도 논리적으로 동일함을 구현하기 위해 사용하는 메서드다.
예제코드
class Student {
int studentNum;
String name;
public Student(int studentNum, String name) {
this.studentNum = studentNum;
this.name = name;
}
public boolean equals(Object o) {
if(o instanceof Student) {
Student std = (Student)o;
if(this.studentNum == std.studentNum)
return true;
else
return false;
}
return false;
}
}
public class EqualsTest {
public static void main(String[] args) {
String str1 = new String("abc");
String str2 = new String("abc");
System.out.println(str1 == str2);
System.out.println(str1.equals(str2));
Student Lee = new Student(100, "이순신");
Student Lee2 = Lee;
Student Shin = new Student(100, "이순신");
System.out.println(Lee = Lee2);
System.out.println(Lee = Shin);
System.out.println(Lee.equals(Shin));
}
}
결과값은 false true true false true 가 출력된다.
str1 과 str2 부터 보자면 둘다 abc라는 동일한 값을 갖고 있다.
하지만 str1과 str2의 메모리주소값은 다르기 때문에 같지 않다고 판단하여 false를 반환한다.
두번째 출력문에서는 true가 출력되는데 equals에서 str1과 str2의 문자열이 같은지를 비교했기 때문에
문자열이 같은지 확인하고 true를 반환한 것이다.
아래 출력문을 보자면 Lee와 Shin은 모두 100번의 이순신이라는 이름을 갖고 있다.
그리고 Lee2는 Lee를 갖고 있는데 그렇기 때문에 첫 출력문인 Lee == Lee2는 true가 출력된다.
Lee2가 Lee를 그대로 포함하고 있기 때문에 같다고 판단하게 되고 두번째 출력문에서는 Lee와 Shin을 비교하지만
둘의 메모리주소가 다르기 때문에 false를 출력하게 된다.
그래서 역시 equals를 이용해 논리적으로 true를 넘겨줘서 같은 값이라고 처리할 수 있는 것이다.
이러한 형태가 되기 때문이다. Lee2는 Lee를 그대로 참조하는 것이므로 같은 메모리주소를 갖게 되는것이고
Shin의 경우는 새로 만들어졌으니 다른 메모리주소를 갖게 된다.
이렇게 물리적으로 다른 위치에 있지만 논리적으로 같은 학생임을 구현하는 부분이 equals() 메서드다.
hashCode()
hashCode메서드의 반환값은 인스턴스가 저장된 가상머신의 주소를 10진수로 반환한다.
두개의 서로 다른 메모리에 위치한 인스턴스가 동일하다는 것은
equals의 반환값을 true로 받은 논리적으로 동일한 값이라는 것이다.
동일한 hashCode값을 갖는다는 것은 hashCode의 반환값이 동일하다는 것이다.
메모리 주소값의 10진수로 된 코드가 해시코드이며 16진수로 나온 메모리주소에 .hashCode() 를 붙여주면
10진수형태로 출력된다.
두개의 서로 다른 메모리에 위치한 인스턴스가 동일하다는 것은 equals의 반환값이 true이면서
같은 hashCode를 가져야 동일하다고 보는 것이기 때문에 보통 equals를 재정의할 때 hashCode도 재정의한다.
예제코드
class Student {
int studentNum;
String name;
public Student(int studentNum, String name) {
this.studentNum = studentNum;
this.name = name;
}
@Override
public boolean equals(Object o) {
if(o instanceof Student) {
Student std = (Student)o;
if(this.studentNum == std.studentNum)
return true;
else
return false;
}
return false;
}
@Override
public int hashCode() {
return studentNum;
}
}
public class EqualsTest {
public static void main(String[] args) {
Student Lee = new Student(100, "이순신");
Student Lee2 = Lee;
Student Shin = new Student(100, "이순신");
System.out.println(Lee.hashCode());
System.out.println(Shin.hashCode());
System.out.println(System.identityHashCode(Lee));
System.out.println(System.identityHashCode(Shin));
}
}
hashCode를 재정의하면서 studentNum을 반환하도록 했기 때문에 Lee와 Shin은 같은 100이 출력된다.
그리고 실제 해시코드의 값을 보려 한다면 System.identityHashCode( ) 를 사용하면 된다.
두개의 서로 다른 메모리에 위치한 인스턴스가 동일하다는 것은 equals의 반환값이 true이면서 hashCode가 같아야
하기 때문에 equals와 hashCode를 같이 재정의 한다고 했다.
해시코드를 따로 재정의 하기 전에 실행해보면 Lee의 해시코드와 Shin의 해시코드가 다른것을 확인할 수 있다.
이것을 동일한 인스턴스라는 것을 확인하기 위해 위 코드에서는 equals메서드안에서 studentNum 으로 확인을 했기
때문에 hashCode() 메서드에서도 같은 값을 갖도록 하기 위해 studentNum을 반환해주는것이다.
그럼 equals() 메서드에서도 true를 반환해주었고 hashCode() 메서드에서도 같은 100을 반환해주었기 때문에
둘은 동일한 인스턴스라고 볼 수 있게 되는 것이다.
clone()
clone()메서드는 객체의 복사본을 만든다.
기본틀(prototype)으로부터 같은 속성 값을 가진 객체의 복사본을 생성할 수 있다.
객체지향 프로그래밍의 정보 은닉을 위배할 가능성이 있으므로 복제할 객체는 cloneable 인터페이스를 명시해야 한다.
예제코드
class Book inmplements Cloneable {
String title;
String author;
public Book(String title, String author) {
this.title = title;
this.author = author;
}
@Override
public String toString() {
return title + ", " + author;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class CloneTest {
public static void main(String[] args) throws CloneNotSupportedException {
Book book = new Book("Java", "name");
Book book2 = (Book)book.clone();
System.out.println(book2);
}
}
결과값으로는 Java, name이 출력된다.
clone() 메서드는 특별히 구현하지 않는다.
그리고 clone() 메서드의 원형이 Object로 반환되기 때문에 (Book)이라고 명시적으로 캐스팅 해줘야 한다.
Book클래스에서 Cloneable을 implements하지 않으면 CloneNotSupportedException이 발생한다.
Book 클래스는 복제가 가능하지 않은 클래스인데 복제하려 했기 때문에 오류가 발생했다는 것이다.
그래서 implements해줘야 복제가 가능하다.
레퍼런스
패스트캠퍼스 올인원 패키지 - 자바 객체지향프로그래밍
'JAVA' 카테고리의 다른 글
내부클래스(Inner Class) (0) | 2021.02.05 |
---|---|
Class 클래스 (0) | 2021.02.04 |
final 키워드 (0) | 2021.02.02 |
템플릿 메서드(Template Method) (0) | 2021.02.02 |
싱글톤 패턴(Singleton Pattern) (0) | 2021.02.01 |