Object 클래스는 자바 클래스들의 조상이라고 할 수 있다. 명시적으로 Object 클래스를 import 하지 않더라도 이미 Object 클래스는 import가 되어 있다. 그렇기 때문에 Object 클래스에 속하는 클래스 및 메서드들은 import 없이 사용이 가능하다.
java.lang 패키지
java.lang 패키지의 Object 클래스 내의 클래스들의 계층 구조
Object.lang 패키지는 Object 클래스에서 가장 기본적인 동작을 수행하는 클래스들을 모아놓은 패키지이다. 이번 포스팅에서 다룰 Object 클래스 또한 java.lang 패키지에 속하는 클래스이다. Object 클래스가 별도의 import 과정 없이 사용 가능한 것도 Object 클래스가 속하는 java.lang 패키지가 import 없이 자바 프로그램에 자동으로 포함되기 때문이다.
java.lang.Object
java.lang 패키지의 클래스들의 import 없이 바로 사용 가능하기 때문에 java.lang.Object 또한 그러하다.
java.lang.Object의 메서드는 총 11가지가 있다.
clone()
object의 복사본을 생성하고 return 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
publicclass Main {
publicstaticvoid main(String[] args) {
User user =new User("pseudocode", 99);
User userCopy = user.clone();
System.out.println(user);
System.out.println(userCopy);
}
staticclass User implements Cloneable {
String name;
int age;
User(String name, int age) {
this.age = age;
this.name = name;
}
@Override
public User clone() {
try {
User clone= (User) super.clone();
// TODO: copy mutable state here, so the clone can't change the internals of the original
equals() 메서드의 디폴트가 두 객체의 참조가 같은지 비교(두 객체가 메모리 상에서 같은 위치를 가르키는지) 하는 것이기 때문에 값을 기준으로 동등 비교를 하기 위해서는 오버라이딩을 통해 메서드 재정의를 해야 한다. 일반적으로 참조를 기준으로 비교할 때 '==' 연산자를 사용하고 값을 기준으로 비교할 때는 equals() 메서드를 재정의하여 사용한다.
equals()를 통해 비교할 때, 객체의 주소를 비교하여 같은 객체인지 판단하기 때문에 객체 간 주소가 다르면 false가 출력된다.
user1과 user2는 서로 다른 객체이기 때문에 주소 또한 다르기 때문에 다른 객체로 인식하여 false가 출력된다.
user1을 참조하는 user3는 주소가 같기 때문에 서로 같은 객체로 인식하여 true가 출력된다.
user1과 user2는 내부 값이 같지만 참조 값이 서로 다르기 때문에 equals 메서드로 비교할 경우 서로 다른 객체로 인식된다. 같은 객체로 인식하기 위해서는 아래처럼 오버라이딩을 통한 재정의가 필요하다.
import java.util.Objects;
public class EqualsTest {
public static void main(String[] args) {
User user1 = new User("pseudocode");
User user2 = new User("pseudocode");
System.out.println(user1.equals(user2)); // true
}
static class User {
String name;
User(String name) {
this.name = name;
}
@Override
public boolean equals(Object o) {
// 같은 객체인 경우 true 반환
if(this == o) {
return true;
}
// o가 null이거나 class가 다를 경우 false 반환
if(o == null || getClass() != o.getClass()) {
return false;
}
User u = (User) o; // User 타입으로 캐스팅
return Objects.equals(name, u.name); // name 필드 값이 같은지 비교
}
}
}
.finalize()
자바에서 더 이상 참조되지 않는 객체가 존재할 때 Garbage Collector가 메모리를 자동으로 수거한다. GC가 수행되기 전에 호출되어 객체가 점유하고 있던 자원들을 해제할 때 사용되는 메서드가 finalize() 메서드이다.
finalize()는 객체소멸자라고도 부른다. 다만 해당 메서드는 JDK 9 버전부터 deprecated 처리가 되어 Object 클래스에서 제거될 예정이다.
hashCode() 메서드도 마찬가지로 오버라이딩 가능하다. 주로 equals() 메서드를 재정의할 때 hashCode() 메서드 또한 같이 재정의한다.
equals() 메서드가 객체 내부 값을 기준으로 비교하기 때문에 객체 자체의 해시코드 값을 반환하는 디폴트 hashCode() 메서드도 객체 내부 값의 해시코드 값을 반환하도록 변경해야 하는 것이 바람직하다.
import java.util.Objects;
public class EqualsTest {
public static void main(String[] args) {
User user1 = new User("pseudocode");
User user2 = new User("pseudocode");
System.out.println(user1.hashCode() == user2.hashCode()); // true
}
static class User {
String name;
User(String name) {
this.name = name;
}
@Override
public int hashCode() {
return Objects.hash(name); // 객체의 name값을 기반으로 해시 코드 생성
}
}
}