java.lang
패키지는 자바 프로그래밍에 가장 기본이 되는 클래스들을 포함하고 있다. 그래서 이 클래스들은 import 없이도 사용할 수 있다.
Object 클래스는 모든 클래스의 최고 조상이기 때문에 Object 클래스의 멤버들은 모든 클래스에서 바로 사용 가능하다.
Object 클래스는 멤버변수는 없고 오직 11개의 메서드만 가지고 있다. 이 메서드들은 모든 인스턴스가 가져야 할 기본적인 것들이며, 우선 이 중에서 중요한 몇 가지만 살펴보자.
notify()
, notifyAll()
, wait()
은 쓰레드와 관련된 메서드이다.
object 클래스의 메서드 | 설명 |
---|---|
protected Object clone() | 객체 자신의 복사본을 반환한다. |
public boolean equals (Object obj) | 객체 자신과 객체 obj가 같은 객체인지 알려준다. (같으면 true) |
protected void finalize() | 객체가 소멸될 때 가비지 컬렉터에 의해 자동적으로 호출된다. 이 때 수행되어야하는 코드가 있을 때 오버라이딩한다. (거의 사용 안 함) |
public Class getClass() | 객체 자신의 클래스 정보를 담고 있는 class 인스턴스를 반환한다. |
public int hashCode() | 객체 자신의 해시코드를 반환한다. |
public String toString() | 객체 자신의 정보를 문자열로 반환한다. |
public void notify() | 객체 자신을 사용하려고 기다리는 쓰레드를 하나만 깨운다. |
public void notifyAll() | 객체 자신을 기다리는 모든 쓰레드를 깨운다. |
public void wait() public void wait(long timeout) public void wait(long timeout, int nanos) | 다른 쓰레드가 notify()나 notifyAll()을 호출할 때까지 현재 쓰레드를 무한히 또는 지정된 시간 (timeout, nanos) 동안 기다리게 한다. (timeout은 천 분의 1초, nanos는 10^9분의 1초) |
매개변수로 객체의 참조변수를 받아서 주소를 비교하여 결과를 boolean 값으로 반환한다.
public boolean equals(Object obj) {
return (this == obj);
}
객체를 생성할 때, 메모리의 비어있는 공간을 찾아 생성하므로 서로 다른 두 객체가 같은 주소를 갖는 일을 없다. 두 개 이상의 참조변수가 같은 주소값을 갖는 것 (한 객체를 참조하는 것)은 가능하다.
일반적으로 equals()은 그대로 사용하지 않고 인스턴스의 멤버 변수 값을 비교하도록 오버라이딩된다.
String 클래스 역시 Object의 equals 메서드를 그대로 사용하는 것이 아니라 오버라이딩을 통해서 String 인스턴스가 갖는 문자열 값을 비교하도록 되어있다. 그래서 같은 내용의 문자열을 갖는 두 String 인스턴스에 equals 메서드를 사용하면 true 값을 얻을 수 있다.
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String aString = (String)anObject;
if (coder() == aString.coder()) {
return isLatin1() ? StringLatin1.equals(value, aString.value)
: StringUTF16.equals(value, aString.value);
}
}
return false;
}
String 클래스 뿐만 아니라 Date, File, wrapper 클래스 (Integer, Double 등)의 equals 메서드도 주소값이 아닌 내용을 비교하도록 오버라이딩되어 있다. 의외로 StringBuffer 클래스는 오버라이딩되어 있지 않다.
💡 String 문자열 비교할 때는
equals()
메서드 사용하자
class INum {
int num;
INum(int num) {
this.num = num;
}
@Override
public boolean equals (Object O) {
if (O instanceof INum) { //같은 클래스인지 확인
INum n = (INum) O; //다운캐스팅
if (this.num == n.num) {
return true;
}
}
return false;
}
}
public class OEqualsTest {
public static void main(String[] args) {
INum num1 = new INum(10);
INum num2 = new INum(12);
INum num3 = new INum(10);
if(num1.equals(num2))
System.out.println("num1, num2 내용 동일하다.");
else
System.out.println("num1, num2 내용 다르다.");
if(num1.equals(num3))
System.out.println("num1, num3 내용 동일하다.");
else
System.out.println("num1, num3 내용 다르다.");
if(num1 == num3)
System.out.println("num1, num3 주소는 동일하다.");
else
System.out.println("num1, num3 주소는 다르다.");
}
}
//result
num1, num2 내용 다르다.
num1, num3 내용 동일하다.
num1, num3 주소는 다르다.
이 메서드는 인스턴스에 대한 정보를 문자열 (String)로 제공한다. 인스턴스의 정보란 대부분 인스턴스 변수에 저장된 값들을 문자열로 표현한다는 뜻이다.
클래스를 작성할 때 toString()을 오버라이딩하지 않는다면, 클래스이름에 16진수의 해시코드를 얻게 될 것이다.
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
💡 참고 : toBinaryString()
(2진수), toOctalString()
(8진수), toHexString()
(16진수) 을 이용하여 진수를 변환할 수 있다.
일반적으로 toString()은 인스턴스나 클래스에 대한 정보 또는 인스턴스 변수들의 값을 문자열로 변환하여 반환하도록 오버라이딩된다.
예)
String.toString() : String 인스턴스가 갖고 있는 문자열을 반환
Data.toString() : Data 인스턴스가 갖고 있는 날짜와 시간을 문자열로 변환하여 반환
Date today = new Date();
System.out.println(today.toString());
//result
Thu Sep 29 21:55:22 KST 2022
toString()
과 println()
println()
에 객체
를 넣었을 때와 객체.toString()
은 출력값이 같다.
Object O = new Object();
System.out.println(O);
System.out.println(O.toString());
//result
java.lang.Object@2c8d66b2
java.lang.Object@2c8d66b2
이 이유는 println()의 정의에 객체가 매개변수로 주어지면 객체.toString()
이 출력되도록 정의했기 때문이다.
public void println(Object x) {
String s = String.valueOf(x);
synchronized (this) {
print(s);
newLine();
}
}
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
해싱 (hashing) 기법에 사용되는 '해시함수 (hash function)'를 구현한 것이다. 해싱은 데이터 관리 기법 중의 하나인데 다량의 데이터를 저장하고 검색하는 데 유용하다.
해시함수는 찾고자하는 값을 입력하면, 그 값이 저장된 위치를 알려주는 해시코드 (hash code)를 반환한다.
일반적으로 해시코드가 같은 두 객체가 존재하는 것이 가능하지만, Object 클래스에 정의된 hashCode 메서드는 객체의 주소값으로 해시코드를 만들어 반환하기 때문에 32 bit JVM에서는 서로 다른 두 객체는 결코 같은 해시코드를 가질 수 없다. (64bit JVM에서는 8 byte 주소값으로 해시코드 (4byte)를 만들기 때문에 해시코드가 중복될 수 있다.)
클래스의 인스턴스변수 값으로 객체의 같고 다름을 판단해야하는 경우라면 equals 메서드 뿐 아니라 hashCode 메서드도 적절히 오버라이딩해야 한다. 같은 객체라면 hashCode 메서드를 호출했을 때의 결과 값인 해시코드도 동일해야 하기 때문이다.
String은 문자열이 같으면 동일한 해시코드를 반환하도록 hashCode 메서드가 오버라이딩되어 있다.
반면에 System.identityHashCode(Object x)sms Object 클래스의 hashCode 메서드처럼 객체의 주소값으로 해시코드를 생성하기 때문에 모든 객체에 대해 항상 다른 해시코드값을 반환할 것을 보장한다. 호출결과는 실행 할 때마다 달라질 수 있다.