JAVA

4-2.Object 클래스의 다른 메서드들 활용하기

개발자 김혜린 2022. 1. 26. 15:25

인스턴스가 생성되면, 동적(힙)메모리에 메모리 공간이 생기고

인스턴스의 이름은 그 메모리를 가리키는 참조변수가 된다.

 

만약 두 개의 인스턴스의 주소값을 찍었을 때, 같은 값이 나온다면 같은 객체인 것이다. 

 

1. equals() 메서드 -> 저장 주소 비교 

  • 두 인스턴스의 주소 값(hash code,물리적인 저장 주소)을 비교하여 true/false를 반환
  • 우리가 재정의 하여 두 인스턴스가 논리적으로 동일함의 여부를 구현함(hashCode()도 오버라이딩해줘야함)
  • 인스턴스가 물리적으로(메모리상에서의 주소) 다르더라도, 논리적으로(인스턴스의 값) 동일한 경우 true를 반환하도록 재정의 할 수 있음
  • (같은 학번, 같은 사번, 같은 아이디의 회원.... 을 유일한 키로 지정하여 hashCode값이 학번/사번/아이디로 나오게 해보자))

2. hashCode() 메서드 -> 저장 주소 반환

  • hashCode()는 인스턴스의 저장 주소를 반환함
  • 힙메모리에 인스턴스가 저장되는 방식이 hash 방식
  • hash : 정보를 저장, 검색하는 자료구조
  • 자료의 특정 값(키 값)에 대한 저장 위치를 반환해주는 해시 함수를 사용

 

  • 두 인스턴스가 같다는 것은?
  • 두 인스턴스에 대한 equals()의 반환 값이 true 동일한 hashCode() 값을 반환
  • 논리적으로 동일함을 위해 equals() 메서드를 재정의 하였다면 hashCode()메서드도 재정의 하여 동일한 hashCode 값이 반환되도록 한다

Student.java

package ch2;

public class Student implements Cloneable{ //클론이 가능하도록 명시
	private int studentNum;	
	private String studentName;
	
	public void setStudentName(String studentName) {
		this.studentName = studentName;
	}
	
	public Student(int studentNum,String studentName) {
		this.studentNum=studentNum;
		this.studentName=studentName;
	}
	
	public String toString() {
		return studentNum+","+studentName;
	}

	@Override
	public boolean equals(Object obj) { //equals 재정의
		if (obj instanceof Student) { //다운캐스팅 하기 전에 instanceof
			Student std = (Student)obj; //다운캐스팅
			if(this.studentNum==std.studentNum) { //학생 번호가 같다면
				return true; //true가 나오도록 재정의
				}
			else return false;
		}
		return false;
	}
    
	@Override
	public int hashCode() { //hashCode 재정의
		return studentNum; //주소값이 아니라 학생 번호가 나오도록 재정의
	}

	@Override
	protected Object clone() throws CloneNotSupportedException { //clone 함수
		return super.clone();
	}
}

 

처음에 std1과 std2는 다른 객체이기 때문에, 두 결과 모두 false가 나온다.

 

 

주소는 다르지만, Student.java에서 equals를 학생 번호가 같으면 같은 객체라고 나오도록 재정의했기 때문에 true가 반환된다.

 

equals()로 같다는 것을 재정의했으니, std1과 std2는 같은 객체라고 판단되어

hashCode()로 두 객체의 주소값을 반환하면 같은 값이 나온다.

(그 아래 코드는 정수는 hashCode로 정수값을 반환한다는 것을 보여주는 코드)

 

hashCode() 또한 학생 번호를 리턴하도록 재정의하였으니,

두 객체가 같으므로(equals로 재정의) 같은 학생 번호를 리턴한다.

 

하지만 만약, 재정의해버린 hashCode() 메서드로는 진짜 그 객체의 hashCode값을 알 수 없다.

그렇다면

System.identityHashCode() 함수를 사용하여 각 객체의 진짜 물리적 hashCode값을 알 수 있다.

 

 

EqualsTest.java

package ch2;

public class EqualsTest {

	public static void main(String[] args) throws CloneNotSupportedException {
		
		Student std1 = new Student(100,"Lee");
		Student std2=new Student(100,"Lee");
		
//		System.out.println(std1==std2); // 주소는 다르지만,
//		System.out.println(std1.equals(std2)); //논리적으로 같다는 것을 재정의했기 때문에 true 반환
//		
//		System.out.println(std1.hashCode()); //논리적으로 같기 때문에
//		System.out.println(std2.hashCode()); //같은 hashcode값 리턴
		
//		System.out.println(System.identityHashCode(std1)); //그렇다면 객체의 진짜 hashcode값을 알고 싶을때?
//		System.out.println(System.identityHashCode(std2));
		
		std1.setStudentName("Kim");
		Student copyStudent = (Student)std1.clone(); //인스턴스의 상태를 그대로 복제 가능
		System.out.println(copyStudent);
		
	}
}

 

 

3. clone() 메서드

  • 객체의 원본을 복제하는데 사용하는 메서드 
  • 생성과정의 복잡한 과정을 반복하지 않고 복제 할 수 있음(생성자는 초기값을 갖고 인스턴스가 생성되지만, 중간에 멤버변수의 값이 변한다면 변한 값 그대로 복제하는 함수임)
  • clone()메서드를 사용하면 객체의 정보(멤버 변수 값등...)가 동일한 또 다른 인스턴스가 생성되는 것이므로, 객체 지향 프로그램에서의 정보 은닉, 객체 보호의 관점에서 위배될 수 있음
  • 해당 클래스의 clone() 메서드의 사용을 허용한다는 의미로 cloneable 인터페이스를 명시해 줌

클론 복제해보려 했으나 오류가 발생하여, throws처리를 해주었다.

 

또한 Student 클래스에 clone이 가능하다고 명시해주었다.

 

 

set 메소드로 이름을 바꾼 것마저도 

완전 복제해버리는 clone 메소드!