티스토리 뷰

▶자바의 Object 클래스에 대해 알아보자

오늘은 자바의 Object 클래스에 대해 알아보도록 하겠습니다.

 

🔎 java.lang 클래스


java.lang 패키지는 자바에서 가장 기본적인 동작을 수행하는 클래스들의 집합입니다.

따라서 자바에서는 java.lang 패키지의 클래스들은 import 문을 사용하지 않아도 클래스 이름만으로 바로 사용할 수 있도록 하고 있습니다.

 

🔎 java.lang.Object 클래스


java.lang 패키지 중에서도 가장 많이 사용되는 클래스는 바로 Object 클래스입니다.

Object 클래스는 모든 자바 클래스의 최고 조상 클래스가 됩니다.

따라서 자바의 모든 클래스는 Object 클래스의 모든 메소드를 바로 사용할 수 있습니다.

 

이러한 Object 클래스는 필드를 가지지 않으며, 총 11개의 메소드만으로 구성되어 있습니다.

 

💡 모든 자바 클래스의 부모는 Object 클래스다!

 

1️⃣  toString() 메소드

toString() 메소드는 해당 인스턴스에 대한 정보를 문자열로 반환합니다.

이때 반환되는 문자열은 클래스 이름과 함께 구분자로 '@'가 사용되며, 그 뒤로 16진수 해시코드(hash Code)가 추가됩ㄴ디ㅏ.

16진수 해시코드 값은 인스턴스의 주소를 가리키는 값으로, 인스턴스마다 모두 다르게 반환됩니다.

 

단순하게 객체를 출력해 보겠습니다.

 

📄 Student.java 파일

public class Student {
	private int number;
	private String name;
	
	public Student() {;}
	
	public Student(int number, String name) {
		super();
		this.number = number;
		this.name = name;
	}

	public int getNumber() {
		return number;
	}

	public void setNumber(int number) {
		this.number = number;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
}

 

📄 ToStringTest.java 파일

public class ToStringTest {
    public static void main(String[] args) {
        Student student = new Student(1, "doeunnkimm");
        System.out.println(student);
    }
}

출력 화면

사실 출력된 결과는 .toString()을 붙였을 때와 동일한데요.

즉, toString()을 붙이지 않아도 자동으로 붙여지는 것인데요.

public class ToStringTest {
	public static void main(String[] args) {
		Student student = new Student(1, "doeunnkimm");
		System.out.println(student);
		System.out.println(student.toString());
	}
}

출력 화면

❓ 난 메모리 주소 말고 필드 값이 궁금한데

객체를 출력했을 때 초기화된 필드를 바로 보고 싶을 때는 어떻게 해야 할까요?

toString 메소드는 Object 클래스의 메소드 입니다.

따라서 toString 메소드를 오버라이딩 한다면 그 기능을 재정의할 수 있습니다.

 

💡toString 메소드를 오버라이딩하여 재정의해서 쓰자

 

📄 toString()메소드를 오버라이딩 - Student.java 파일

// 단축키 : Alt + Shift + S, S
@Override
public String toString() {
    return "Student [number=" + number + ", name=" + name + "]";
}

 

📄 ToStringTest.java 파일

public class ToStringTest {
	public static void main(String[] args) {
		Student student = new Student(1, "doeunnkimm");
		System.out.println(student);
		System.out.println(student.toString());
	}
}

출력해보면 오버라이딩 하기 전과는 달리 초기화한 필드명이 출력되는 것을 확인할 수 있습니다.

출력 화면

 

2️⃣ equals() 메소드

equals() 메소드는 해당 인스턴스를 매개변수로 전달받는 참조 변수와 비교하여, 그 결과를 반환합니다.

이때 참조 변수가 가리키는 값을 비교하므로, 서로 다른 두 객체는 언제나 false를 반환하게 됩니다.

 

new를 사용하면 새로운 메모리 주소를 할당 받게 되면서 자바에서는 메모리 주소가 같은 것이 같은 것이므로

만약 new String으로 같은 문자열을 한번 두번 선언하여 같냐고 물어본다면 다르다고 말할 것입니다.

public class EqualsTest {
    Student student = new Student(1, "doeunnkimm");
    
    boolean isSame = student.equals(new Student(1, "doeunnkimm")); // false
}

 

❓ 실제 서비스를 한다고 생각해보자

실제 서비스를 한다고 했을 때 위 코드를 다시 본다면 필드 값을 동일하게 주었는데도 메모리 주소가 다르다고

사용자에게도 다르다고 이야기하는 것이 맞을까요?

 

실제 서비스를 한다고 하면 필드값이 동일하면 사용자들에게도 동일하다고 이야기하는 것이 맞다고 볼 수 있습니다.

따라서 이번에도 Object 클래스의 메소드인 equals() 메소드를 오버라이딩 하여

원하는 기능에 맞게 재정의해 주면 됩니다.

 

📄 equals() 메소드 오버라이딩 - Student.java 파일

@Override
public boolean equals(Object obj) {
    if(this == obj) {
        return true;
    }
    if(obj instanceof Student) {
        Student anotherStudent = (Student) obj; // 다운캐스팅
        return true;
    }
    return false;
}

 

❓ equals와 ==

==는 인스턴스의 주소값을 비교

equals()는 객체 내부의 값을 비교

 

3️⃣ hashCode() 메소드

hashCode() 메소드는 메모리에 생성된 객체의 주소를 정수로 반환합니다.

이때 이 정수는 중복되지 않는 고유의 값입니다.

따라서 변수를 선언을 하면 서로 다른 주소값을 가지고 있기 때문에

객체의 값이 동일한지 비교하기 위해서는 hashCode() 메소드를 오버라이딩할 필요성이 있습니다.

 

메소드를 실행해서 리턴된 해시코드 값이 같은지를 봅니다.

해시 코드값이 다르면 다른 객체로 판단하고, 해시 코드값이 같으면

equals() 메소드로 다시 비교합니다.

이 두개가 모두 맞아야 동등 객체로 판단합니다.

즉, 해시코드 값이 다른 엔트리끼리는 동등 비교를 시도 조차 하지 않습니다.

 

💡 equals()와 hashCode()를 같이 재정의해야 하는 이유

만약 equals()와 hashCode() 중 하나만 재정의 하면 어떻게 될까요?

위 예에서도 봤듯이 hashCode()를 재정의 하지 않으면 같은 값 객체라도 해시값이 다를 수 있습니다.

반대로 equals()를 재정의하지 않으면 hashCode()가 만든 해시값을 이용해 객체가 저장된 버킷을 찾을 수는 있지만 해당 객체가 자신과 같은 객체인지 값을 비교할 수 없기 때문에 null을 리턴하게 됩니다.

따라서 역시 원하는 객체를 찾을 수 없는데요.

이러한 이유로 객체의 정확한 동등 비교를 위해서는 Object의 equals() 메소드만 재정의하지 말고 hashCode() 메소드도 재정의해서 논리적 동등 객체일 경우 동일한 해시코드가 리턴되도록 해야 합니다.

 

그런데 이미 hashCode는 Object 클래스에서 재정의되어 있습니다.

따라서 값이 같다면 동일한 값의 주소값을 가지도록 되어 있는데요.

String data1 = "ABC"
String data2 = new String("ABC");

System.out.println(data1.hashCode()); // 64578
System.out.println(data2.hashCode()); // 64578

또한 동일한 버전의 JDK를 사용 중이라면

동일한 패턴으로 값의 주소를 부여하므로 동일한 값에 대해서는 모두 동일한 값의 주소값으로 보이게 될 것입니다.

이때 출력되는 해시 코드값은 정확한 메모리 주소는 아닙니다.

 

위에서 해시 코드 값이 동일하면 equals로 값이 동일한지를 비교한다고 했었습니다.

그리고 ==는 객체의 메모리 주소값을 비교한다고 했으며 바로 위 코드에 출력된 해시 코드값은 정확한 메모리 주소값은 아니라고 했습니다.

System.out.println(data1.equals(data2)); // true
System.out.println(data1 == data2); // false
728x90
LIST
250x250
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/09   »
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
글 보관함