ksouth9

java.lang 패키지(1) 본문

Java

java.lang 패키지(1)

ksouth9 2022. 3. 20. 00:45

java.lang 패키지


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

그렇기 때문에 java.lang패키지의 클래스들은 import문 없이도 사용할 수 있게 되어 있다. String클래스나 System클래스를 import문 없이 사용할 수 있었던 이유이다.

Object클래스


Object클래스는 모든 클래스의 최고 조상이기 때문에 Object클래스의 멤버들은 모든 클래스에서 바로 사용 가능하다.

Object클래스의 메서드 설 명
protected Object clone() 객체 자신의 복사본을 반환한다.
public boolean equals(Object obj) 객체 자신과 객체 obj가 같은 객체인지 알려준다.(같으면 true)
public Calss 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초)

Object클래스는 멤버변수는 없고 오직 11개의 메서드만 가지고 있다. 이 메서드들은 모든 인스턴스가 가져야 할 기본적인 것들이다.

 

equals(Object obj)


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

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

두 객체의 같고 다름을 참조변수의 값으로 판단한다.

public class equalsTest {

	public static void main(String[] args) {

		Value v1 = new Value(10);
		Value v2 = new Value(10);
		
		if(v1.equals(v2)){
			System.out.println("v1과 v2는 같습니다.");
		} else {
			System.out.println("v1과 v2는 다릅니다.");
		}
		v2 = v1;
		if(v1.equals(v2)) {
			System.out.println("v1과 v2는 같습니다.");
		} else {
			System.out.println("v1과 v2는 다릅니다.");
		}
	}
}
class Value {
	int value;
	
	Value(int value){
		this.value = value;
	}
}//실행결과
v1과 v2는 다릅니다.
v1과 v2는 같습니다.

value라는 멤버변수를 갖는 Value클래스를 정의하고, 두 개의 Value클래스의 인스턴스를 생성한 다음 equals메서드를 이용해서 두 인스턴스를 비교하도록 했다. equals메서드는 주소값으로 비교를 하기 때문에, 두 Value인스턴스의 멤버변수 value 값이 10으로 서로 같을지라도 equals메서드로 비교한 결과는 false일 수 밖에 없다.

하지만, 'v2 = v1;'을 수행한 후에는 참조변수 v2v1이 참조하고 있는 인스턴스의 주소 값이 저장되므로 v2v1과 같은 주소값이 저장된다. 그래서 두 번째 if문에 v1.equals(v2)의 결과는 true이다.

 

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

하지만 오버라이딩을 통해서 주소가 아닌 객체에 저장된 내용을 비교할 수 있다.

class Person{
	long id;
	
	Person(long id){
		this.id = id;
	}
	
	public boolean equals(Object obj) {
		if(obj instanceof Person){
			return id == ((Person)obj).id;
		} else {
			return false;
		}		
		
	}

}

public class EqualsEx2 {

	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는 같은 사람입니다.

equals메서드가 Person인스턴스의 주소값이 아닌 멤버변수 id의 값을 비교하도록 하기위해 equals메서드를 오버라이딩했다. 이렇게 함으로써 서로 다른 인스턴스일지라도 같은 id(주민등록번호)를 가지고 있다면 equals메서드로 비교했을 때 true를 결과로 얻게 할 수 있다.

 

Object클래스의 equals메서드는 주소값을 비교하고, String클래스의  equals메서드는 객체의 문자열을 비교한다.

hashCode()


이 메서드는 해싱(hashing)기법에 사용되는 '해시함수'를 구현한 것이다. 해싱은 데이터관리기법 중의 하나인데 다량의 데이터를 저장하고 검색하는 데 유용하다. 해시함수는 찾고자하는 값을 입력하면, 그 값이 저장된 위치를 알려주는 해시코드(hashcode)를 반환한다. 

해싱기법을 사용하는 HashMap이나 HashSet과 같은 클래스에 저장할 객체라면 반드시 hashCode메서드를 오버라이딩해야 한다.

public class HashCodeTest {

	public static void main(String[] args) {
		String str1 = new String("Hello");
		String str2 = new String("Hello");
		
		System.out.println(str1.equals(str2));
		System.out.println(str1.hashCode());
		System.out.println(str2.hashCode());
		System.out.println(System.identityHashCode(str1));
		System.out.println(System.identityHashCode(str2));

	}

}//실행결과
true
69609650
69609650
1940447180
245565335

String클래스문자열의 내용이 같으면, 동일한 해시코드를 반환하도록 hashCode메서드가 오버라이딩되어 있기 때문에, 문자열의 내용이 같은 str1과 str2에 대해 hashCode()를 호출하면 항상 동일한 해시코드값을 얻는다.

반면에 System.identityHashCode(Object x)는 Object클래스의 hashCode메서드처럼 객체의 주소값으로 해시코드를 생성하기 때문에 모든 객체에 대해 항상 다른 해시코드값을 반환할 것을 보장한다. 그래서 str1과 str2가 해시코드는 같지만 서로 다른 객체라는 것을 알 수 있다.

toString()


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

인스턴스의 정보를 제공한다는 것은 대부분의 경우 인스턴스 변수에 저장된 값들을 문자열로 표현한다는 뜻이다.

 

Object클래스에 정의된 toString()

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

클래스를 작성할 때 toString()을 오버라이딩하지 않는다면, 위와 같은 내용이 그대로 사용될 것이다. 즉, toString()을 호출하면 클래스이름에 16진수의 해시코드를 얻게 될 것이다.

class Card {
	String kind;
	int number;
	
	Card(){
		this("SPADE",1);
	}
	Card(String kind, int number){
		this.kind = kind;
		this.number = number;
	}
}
public class CardToString {

	public static void main(String[] args) {
		Card c1 = new Card();
		Card c2 = new Card();
		
		System.out.println(c1.toString()); 
		System.out.println(c2.toString());
	}

}//실행결과
Test.Card@6bf2d08e
Test.Card@7e774085

Card인스턴스 두 개를 생성한 다음, 각 인스턴스에 toString()을 호출한 결과를 출력했다. Card클래스에서 Object클래스로부터 상속받은 toString()을 오버라이딩하지 않았기 때문에 Card인스턴스에 toString()을 호출하면, Object클래스의 toString()이 호출된다. 그래서 위의 결과에 클래스이름과 해시코드가 출력되었다. 서로 다른 인스턴스에 대해서 toString()을 호출하였으므로 클래스의 이름은 같아도 해시코드값이 다르다는 것을 확인할 수 있다.

public class ToStringTest {

	public static void main(String[] args) {
		String str = new String("KOREA");
		java.util.Date today = new java.util.Date();
		
		System.out.println(str);
		System.out.println(str.toString());
		System.out.println(today);
		System.out.println(today.toString());

	}

}//실행결과
KOREA
KOREA
Sun Mar 27 01:51:21 KST 2022
Sun Mar 27 01:51:21 KST 2022

String클래스와 Date클래스의 toString()을 호출하였더니 클래스이름과 해시코드 대신 다른 결과가 출력되었다. String클래스의 toString()은 String인스턴스가 갖고 있는 문자열을 반환하도록 오버라이딩되어 있고, Date클래스의 경우, Date인스턴스가 갖고 있는 날짜와 시간을 문자열로 변환하여 반환하도록 오버라이딩되어 있다.

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

class Card {
	String kind;
	int number;
	
	Card(){
		this("SPADE",1);	// Card(String kind, int number)를 호출
	}
	Card(String kind, int number){
		this.kind = kind;
		this.number = number;
	}
	@Override
	public String toString() {
		return "kind : "+kind+", number : "+number;	// Card인스턴스의 kind와 number를 문자열로 반환한다.
	}
	
}

public class CardToString2 {

	public static void main(String[] args) {
		Card c1 = new Card();
		Card c2 = new Card("HEART",10);
		System.out.println(c1.toString());
		System.out.println(c2.toString());

	}

}//실행결과
kind : SPADE, number : 1
kind : HEART, number : 10

Card인스턴스의 toString()을 호출하면 인스턴스가 갖고 있는 인스턴스변수 kind와 number의 값을 문자열로 변환하여 반환하도록 toString()을 오버라이딩했다. 오버라이딩할 때, Object클래스에 정의된 toString()의 접근 제어자가 public이므로 Card클래스의 toString()의 접근 제어자도 public으로 해주어야 한다.

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

'Java' 카테고리의 다른 글

java.lang 패키지(3) - String클래스  (0) 2022.03.28
java.lang 패키지(2)  (0) 2022.03.27
예외처리(exception handling)(3)  (0) 2022.03.18
예외처리(exception handling)(2)  (0) 2022.03.18
예외처리(exception handling)(1)  (0) 2022.03.17