본문 바로가기
책벌레와 벌레 그 사이 어딘가/개념쌓기

[개념쌓기] Object class? 자바의 최상위 클래스

by veganwithbacon 2023. 1. 12.
반응형

자바의 최상위 클래스가 Object클래스인 것은 익히 알고 있을 것이다.

몰랐다면 이제 알면 된다.

 

Object 클래스 : 모든 자바 클래스들의 부모 클래스이며 모든 자식 클래스는 Object의 메소드를 가진다.

 

*System.out.println(new A()); 와 같이 모든 클래스 타입을 출력할 수 있는 것이 Object클래스가 있기 때문이다

 

class B extends A{~~ }
class A{~~ }
class A extends Object{~~ } 

마지막의 경우 상속을 하지 않으면 자동으로 Object를 상속한다

즉, 모든 class는 object class의 메소드를 사용가능하며, 일부는 overriding 할 수 있다.

Object 클래스는 필드없이 메소드로 구성된다

이 메소드들은 모든 클래스들의 Object 클래스를 상속하므로, 모든 클래스에서 이용가능하다.

 

  Object 클래스의 메소드


1. equals() : 객체 비교

형태

public boolean equals(Object obj){ ... }

- 매개 타입 : Object 로 모든 객체가 매개 값으로 대입될 수 있다.

  (Object가 최상위 타입이므로 모든 객체는 Object 타입으로 자동 타입 변환될 수 있다)

 

- 리턴 타입 : boolean 두 객체가 동일한 객체라면 true, 그렇지 않으면 false를 리턴한다

 

equals() 메소드는 비교 연산자인 "=="과 동일한 결과가 리턴된다

 

논리적 동등하다는 의미 : 같은 객체나 다른 객체나 저장하고 있는 데이터가 동일하다

 

equals 메소드는 이 객체가 다른 객체와 같은지 아니지를 나타낸다.

즉, 주소값을 비교함으로 동일하다면 true를, 아니라면 false를 리턴한다

 

위와 같은 결과를 알게 됐다한들, 한가지 의문이 생긴다.

🤔'=='과 equals()메소드가 같은 의미라면 둘을 왜 분리해둔 것일까?

동일성 비교 :  ' == '

동등성 비교 : equals()

 

동일성과 동등성의 차이부터 알아보자.

동일성('==')이란 이름에서 알 수 있듯이 동일하다는 의미로, 두 개의 객체가 완전히 같은 경우를 의미한다.

즉, 두 객체가 하나의 객체로 봐도 무방하며, 주소가 같기에 두 변수가 같은 객체를 가리키는 것이다.

Primitive타입은 객체가 아니라 주소가 없어 == 연산자를 사용했을 때 내용이 동일하면 동일하다고 한다.

(Primitive data type은 ==를 통해 값 비교가 가능하다~ 내마음에 저장)

엄밀히 말하면 primitive type도 주소값 비교가 되긴한다.참고 정도로만 알고 있자.

 

동등성(equals() )은 두 개의 객체가 같은 정보를 갖고 있는 경우를 의미로, 두 개의 객체가 서로 다른 주소를 가리키고 있어도 내용이 같다면 두 변수는 동등하다고 얘기할 수 있다.

동일하면 동등하나, 동등하다고 동일한 것은 아니다.


2. hashCode() : 객체 해시코드

객체 해시코드 : 객체를 식별할 하나의 정수값

 

hashTable이라는 배열을 통해 데이터와 주소값을 저장하기에 많은 양의 데이터를 저장하고도 빠른 검색이 가능하다.

각 객체의 메모리 번지를 이용해 HashCode를 만들어 리턴하기 때문에, 객체마다 다른 값을 가지고 있다.
즉, HashCode는 유일하며 같은 값을 가질 수 없다.

또한 객체가 변경 되어도 hashCode는 변하지 않는다.

 

논리적 동등 비교 시 hashCode()를 오버라이딩할 필요성이 있는데,

컬렉션 프레임워크에서 HashSet, HashMap, Hashtable은 다음과 같다.

우선 hashCode() 메소드를 실행해서 리턴된 해시코드 값이 같은지 검사한다.

해시코드 값이 다르면 다른 객체로 판단, 같으면 equals() 메소드로 다시 검사한다.

때문에 hashCode() 메소드가 true가 나와도 equals()의 리턴 값이 다르면 다른 객체가 되는 것이다.

  Java HashTable 

equals와 hashcode 메서드를 이해하려면 자바에서 HashTable이 작동하는 원리를 알아야한다.

(HashTable, HashMap, HashSet 모두 동일한 동작 원리를 지닌다)

 

HashTable은 <key, value> 형태로 데이터를 저장하는데, 이 때 해시 함수(Hash Function)을 이용하여 key값을 기준으로 고유 식별값인 해시값을 만든다. (hashCode가 해시값을 만드는 역할을 한다.) 해시값을 버킷(Bucket)에 저장한다.

하지만 HashTable 크기는 한정적이기에 서로 다른 객체라 하더라도 같은 해시값을 가진다.

이것을 해시 충돌(Hash Collisions)라고 한다.

해시 충돌이 발생하는 경우 해당 버킷에 LinkedList 형태로 객체를 추가한다.

 

해시값의 버킷 안에 다른 객체가 있는 경우 equals 메소드가 사용된다

 

  HashTable에 put 메소드로 객체를 추가하는 경우

  • 값이 같은 객체가 이미 있다면  (equals()가 true) 기존 객체를 덮어쓴다
  • 값이 같은 객체가 없다면 (equals()가 false) 해당 entry를 LinkedList에 추가한다.

  HashTable에 get 메소드로 객체를 조회하는 경우

  • 값이 같은 객체가 있다면 (equals()가 true) 그 객체를 리턴한다
  • 값이 같은 객체가 없다면 (equals()가 false) null을 리턴한다

위 그림에서 세 객체 (Entry<K1,V1>, Entry<K2,V2>, Entry<K3,V3>)는 서로 같은 해시값을 같는다. 따라서 hashcode() 메서드는 같은 값을 리턴한다. 하지만 서로 값이 다른 객체이기 때문에 equals() 메서드는 false를 리턴한다.

 

해시에 대한 자세한 내용은 다른 글에서 다루도록 하겠다

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

hashCode()를 재정의하지 않으면 같은 값이라도 다른 해시값을 가지게 될 수 있다.

따라서 HashTable 내 해당 객체가 저장된 버킷을 찾을 수 없게 된다.

위와 달리 equals()를 재정의하지 않을 시 hashCode()가 만든 해시값을 통해 객체가 저장된 버킷을 찾을 수 있으나, 자신과 같은 같은 객체인지를 비교할 수 없기 때문에  null을 리턴하게 된다. hashCode()만을 재정의하는 것과 마찬가지로 원하는 객체를 찾을 수 없다.

그러므로 객체의 정확한 동등 비교를 위해서는 객체의 equals(), hashCode() 메소드 모두 재정의해서 논리적 동등 객체일 경우 동일한 해시코드가 리턴되도록 해야한다.

 

https://jisooo.tistory.com/entry/java-hashcode%EC%99%80-equals-%EB%A9%94%EC%84%9C%EB%93%9C%EB%8A%94-%EC%96%B8%EC%A0%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B3%A0-%EC%99%9C-%EC%82%AC%EC%9A%A9%ED%95%A0%EA%B9%8C.  에서 HashTable에 대한 내용 발췌

 

두둥탁 결론

두 객체가 할당된 메모리 주소가 같으면 동일하고, 두 객체의 내용이 같으면 동등하다고 말한다. 

동일성은 '=='연산자를 통해, 동등성은 equals 연산자를 통해 판별가능하다.


3. 객체 문자 정보 toString()

Object 클래스의 toString() 메소드는 객체가 지닌 정보나 값들을 문자열로 만들어 리턴하는 메소드다.

toString() 메소드 : "클래스명@16진수해시코드"로 구성된 문자 정보를 리턴

Object obj = new Object();
System.out.println(obj.toString());

[결과]
java.lang.Object@de6ced

toString()는 Object의 모든 서브클래스에 대해 이 메소드의 오버라이드를 권장한다.

 

System.out.println() 메소드를 콘솔에 출력하기 위해 사용한다.

매개값이 기본 타입(byte, short, int, long, float, double, boolean)일 경우 해당 값을 그대로 출력한다.

매개값을 객체로 주면, 객체의 toString() 메소드를 호출해서 리턴값을 받아 출력하게 된다.

"String" 클래스나 "File"클래스에서는 "toString"에 메소드를 재정의해 의미있는 값을 리턴한다.

 

 

두둥탁 결론

오버라이딩을 통해 toString()메소드를 재정의해서 사용할 수 있다.

또한 toString() 메소드는 자동으로 호출된다.

 

 

 

참고 자료 :

https://velog.io/@msk102948/%EC%8A%A4%ED%94%84%EB%A6%B0%ED%84%B0%EC%8A%A4-%EC%9E%90%EB%B0%94%EC%9D%98-%EC%B5%9C%EC%83%81%EC%9C%84-%EB%B6%80%EB%AA%A8%ED%81%B4%EB%9E%98%EC%8A%A4 

https://opentutorials.org/course/1223/6241 

https://yeomboyeon.tistory.com/67 

https://dongkka.tistory.com/23 

https://steady-coding.tistory.com/534 

https://backback.tistory.com/68 

https://kephilab.tistory.com/92 

 

 

 

 

반응형

댓글