본문 바로가기
멀티캠퍼스 풀스택 과정/Java의 정석

자바의 정석6-1 Java.lang패키지, eqauls, hasecode, toString

by 이쟝 2022. 1. 7.

Java.lang패키지

- java.lang패키지는 자바프로그래밍에 가장 기본이 되는 클래스를 포함하고 있어서 java.lang패키지의 클래스들은 import문 없이도 사용가능함

 

Object클래스

- 모든 클래스의 최고조상으로 11개의 메서드만을 가지고 있다.

 

 

- protected는 오버라이딩해서 public으로 변경해야 사용할 수 있음!(아니면 작성한 클래스의 자손클래스나 같은 패키지에서만 사용 가능하기 때문)

- public Class getClass( ) 객체의 클래스 정보(설계도 정보)를 반환

-> 이 설계도 객체를 통해서 1) 객체 생성 2) 객체 정보 얻을 수 있음

- notify( ), notifyAll( ), wait( )은 쓰레드(thread)와 관련된 것들이며, 나중에 쓰레드에서 자세히 설명!


equals(Object obj)

- 객체 자신(this)과 주어진 객체(obj)를 비교한다.

- 반환타입 boolean이라서 같으면 true, 다르면 false

- object클래스의 equals( )객체의 주소를 비교(매개변수로 객체의 참조변수를 받아서 비교) -> 서로 다른 두 객체를 equals 메서드로 비교하면 항상 false를 결과로 얻게 됨!

- 인스턴스의 값(내용)을 비교하려면(주소가 아닌) equals( )메서드를 오버라이딩 해야함!

 

equals의 기본형

public boolean equals(Object obj) {
	return (this==obj);  // 주소 비교
}

Value v1 = new Value(10);
Value v2 = new Value(10);
System.out.println(v1.equals(v2));  //false
	
class Value {
	int value;
	Value(int value) {
		this.value = value;
	}
}

 

- 서로 다른 두 객체는 항상 주소가 다르다!

 


예제1) 객체(참조변수)의 주소가 아니라 iv값을 비교하도록 equals()를 오버라이딩 Value클래스를 생성하고 value 인스턴스 변수를 가지는 생성자를 만들고 equals를 오버라이딩

 

public class Ex9_1 {
	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는 다릅니다.");
	} // main 
}
class Value {
	int value;
	Value(int value) {
		this.value = value;
	}
	// value의 조상인 Object의 equals를 오버라이딩해서 주소가 아닌 value를 비교
	public boolean equals(Object obj) {
		// 참조변수의 형변환 전에는 반드시 instanceof로 확인해야 함
		if(!(obj instanceof Value)) return false;
		
		// obj를 value로 형변환(Value 클래스에는 value가 있지만 Objcet클래스에는 없기 때문)
		Value o = (Value)obj; 
		return this.value == o.value;
	}
    
//equals의 기본형 
//	public boolean equals(Object obj) {
//		return (this==obj); // 기본형은 주소 비교. 서로 다른 객체는 항상 거짓 
//	}
}

 

<출력값>

v1 v2 같습니다.


예제2) 객체(참조변수)의 주소가 아니라 iv값을 비교하도록 equals()를 오버라이딩. Person 클래스를 생성하고, long타입의 주민번호 iv를 생성한 뒤에 equlas메서드 오버라이딩!

 

public class Ex9_2 {
	public static void main(String[] args) {
		Person p1 = new Person(123456789L);
		Person p2 = new Person(123456789L);
		System.out.println(p1.equals(p2)); 

		if(p1==p2) { // 객체(주소값)비교
			System.out.println("p1과 p2는 같습니다.");
		} else {
			System.out.println("p1과 p2는 다릅니다.");
		}
		if(p1.equals(p2)) { // iv값 비교
			System.out.println("p1과 p2는 같습니다.");
		} else {
			System.out.println("p1과 p2는 다릅니다.");
		}
	}
}
class Person {
	long id;
	Person(long l) {  // 생성자
		this.id = l;
	}
	public boolean equals(Object obj) {
		if (obj instanceof Person)  //obj가 Object타입이므로 id값을 참조하려면 Person타입으로 형변환 필요
			return id == ((Person)obj).id; 
		else 
			return false;   // 타입이 Person이 아니면 값을 비교할 필요도 없다.
	}
}

 

더보기

<출력값>

true

p1 p2 다릅니다.

p1 p2 같습니다.

 

서로 다른 두 객체가 값은 같지만 다른 곳을 가리킴

 

p1 == p2 -> 0x100 == 0x200 -> false (오버라이딩 하지 않으면 객체를 가르키는 주소로 비교)

p1.equals(p2) -> this.id = ((Person)obj).id -> 8011081111222L == 8011081111222L -> true


hashCode( )

- 객체 주소값으로 해시코드(hash code)를 반환하는 메서드  

- 이 메서드는 해싱(hashing)기법에 사용되는 해시함수(hash function)’을 구현한 것

- 해싱(데이터관리기법 중 하나)은 다량의 데이터를 저장하고 검색하는데 유용

- 해시함수: 찾고자 하는 값을 입력 -> 그 값이 저장된 위치를 알려주는 해시코드(hash code)반환

- Object클래스의 hashCode( )객체의 주소를 int로 변환해서 반환(객체마다 각각의 값을 가짐)

- 해시코드 => 정수 값(객체의 지문이라고도 함: 객체마다 다른 값을 가져서)

 

더보기

public class Object {

       ...

       public native int hashCode() ; // 내용 xx

}

native(네이티브메서드): OS의 메서드(C언어)

-> 이미 작성 되어있는 메서드를 호출하기 때문에 내용이 없음

-> C언어로 작성되어서 안의 내용을 볼 수 없음

 

- equals( )를 오버라이딩하면, hashCode( )도 오버라이딩해야 한다. (equalshahCode 둘 다 객체의 주소를 가지고 작업) -> equalsiv를 가지고 작업을 한다면 hashCodeiv를 가지고 작업!

- equals의 결과가 true이면 두 객체의 해시코드는 같아야 하기 때문

 

String str1 = new String("abc");
String str2 = new String("abc");
System.out.println(str1.equals(str2)); // true
System.out.println(str1.hashCode());   // 96354
System.out.println(str2.hashCode());   // 96354
System.out.println(System.identityHashCode(str1)); //1694819250
System.out.println(System.identityHashCode(str2)); //1365202186

 

-> String클래스는 문자열의 내용이 같으면, 동일한 해시코드를 반환하도록 hashCode메서드가 오버라이딩 되어 있음!(그래서 문자열 str1str2에 대해 hashCode( )를 호출하면 동일한 해시코드 값을 얻음)

-> System.identityHashCode(Object obj)Object클래스의 hashCode( )와 동일(주소값을 사용하기때문에 모든 객체에 대해 항상 다른 해시코드값을 반환함)


toString( )

- toString( ): 객체를 문자열(String)으로 변환하기 위한 메서드

 

toString의 기본형

- 객체 == ‘iv 집합이므로 객체를 문자열로 변환한다는 것은 iv의 값을 문자열로 변환한다는 것과 같다.

- 클래스를 작성할 때 toString()을 오버라이딩하지 않으면, Card@4b8cfb5 이렇게 출력됨!(16진수의 해시코드)

- 오버라이딩 할 때 문자열의 결합을 사용해서 iv값 이용


예제1) Card클래스에서 멤버변수인 kindnumber를 생성하고 toString을 오버라이딩

 

public class Ex9_4 {
	public static void main(String[] args) {
		Card c = new Card();
//		System.out.println(c.to());  // to 메서드를 출력 결과값은 동일함
		System.out.println(new Card());
		System.out.println(c);
		System.out.println(c.toString());
	}
}
class Card {
	String kind;
	int number;

	Card() {
		this("SPADE", 1); //생성자로 kind와 number 초기화
	}

	Card(String k, int num) {
		this.kind = k;
		this.number = num;
	}	
	//오버라이딩 하려면 선언부 같아야 함
	public String toString() { //Card인스턴스의 kind와 number를 문자열로 반환
		return  "Kind: " + kind + ", number: " + number;
	}
//	public String to() {  // to( ) 메서드
//		return "Kind: " + kind + ", number: " + number;
//	}
}

 

<출력값>

Kind: SPADE, number: 1

Kind: SPADE, number: 1

Kind: SPADE, number: 1

 


예제2) 예제1 + equalsHashCode 오버라이딩 하기!

 

import java.util.Objects;
public class Ex9_4 {
	public static void main(String[] args) {
		Card c = new Card();
		Card c2 = new Card();
		System.out.println(new Card());    // kind: STAR, number: 6
		System.out.println(c.equals(c2));  // true
		System.out.println(c.hashCode());  // -1842861219
		System.out.println(c2.hashCode()); // -1842861219
	}
}
class Card {
	String kind;
	int number;

	Card() {
		this("STAR", 6);
	}

	Card(String k, int num) {
		this.kind = k;
		this.number = num;
	}	
	//Object클래스의 toString을 오버라이딩 선언부는 그대로!!
	public String toString() {
		return "kind: " + kind + ", number: " + number;
	}
	// equals 오버라이딩
	public boolean equals(Object obj) {
		if(!(obj instanceof Card)) 
			return false;
			Card c = (Card)obj;
			return kind.equals(c.kind) && this.number == c.number; //kind는 string이어서 equals
//			return this.kind.equals(((Card)obj).kind) && this.number == ((Card)obj).number;
	}
	// equals()를 오버라이딩하면 hashCode()도 오버라이딩 해야한다. 
	public int hashCode() {
		return Objects.hash(kind, number);  // hash가 가변인자라서 호출시 지정하는 값의 개수 정해져 있지 않음
	}
}

 

더보기

-> hashCode의 오버라이딩 코드에서 Objects클래스는 객체와 관련된 유용한 메서드를 제공하는 유틸 클래스