/ JAVA

Java_equals와 '=='연산자 그리고 hashCode()


안녕하세요 오늘은 비교비교 equals 와 ‘==’ 에 대해 알아보려합니다.
우선 equals는 메서드
==연산자는 비교를 위한 연산자입니다.

== 연산자는 대상의 주소값을 비교하고 equals는 오버라이딩을 통해 원하는 값을 비교할 수 있도록 한다.
우선 equals(Object obj) 매개변수로 객체의 참조변수를 받아서 비교하여 그 결과를 boolean값으로 알려 주는 역할을 한다. Object 클래스에 정의되어 있는 equals메서드의 실제 내용

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

이 코드에서 알 수 있듯이 두 객체의 같고 다름을 참조변수(주소값)의 값으로 판단한다. 그렇기 때문에 서로 다른 두 객체를 equals 메서드로 비교하면 항상 false를 결과로 얻게 된다.


public static void main(String[] args) {

 Obj obj1 = new obj(10);
 Obj obj2 = new obj(10);
 
 System.out.println(obj1.equals(obj2));// false 

class Obj {
  int value;
  
  Obj(int value) {
    this.value=value;
  }
}

**그렇다면 equals 메서드로 Obj 인스턴스가 가지고 있는 value값을 비교 하도록 할 수는 없을까? 이럴땐 Obj 클래스에서 equals메서드를 오버라이딩하여 주소가 아니라 객체에 저장된 내용을 비교하도록 변경하면 된다.

class Person {
  int value;
  
  public boolean equals(Object obj) {
     if(obj instanceof Person) {
         return id==((Person).obj).id; //obj가 Object타입이므로 id 값을 참조하기 위해서는 Person타입으로 형변환이 필요하다. 
     }else{
         return false;
     } 
  }

}
class EqualEx2 {

 public static void main(String[] args) {
    Person p1 = new Person(1020);
    Person p2 = new Person(1020);

 if(p1 == p2) {
    System.out.println("두 객체는 같다");
 }else {
    System.out.println("두 객체는 다르다");
 
 }
 if(p1.equals(p2)) {
    System.out.println("두 객체는 같다");
 }else {
    System.out.println("두 객체는 다르다");
 
 }

결과값은 “두 객체는 다르다” “두 객체는 같다” 가 나왔다.

String 클래스 역시

hashCode란?

Object클래스는 hashCode() 라는 메서드를 가지고 있습니다
hashCode() 메서드는 말그대로 hashCode를 생성해 리턴해주는 메서드이죠
hashcode란 Object클래스의 메서드가 리턴하는 각 객체에 대응하는 고유한 정수값을 이야기하며


기본적으로 hashCode는 객체의 주소값과 연관이 있습니다

ex_screenshot

ex_screenshot

비교했을때 주소값이 다른 obj와 obj2의 hashcode값이 다르죠
그리고
obj2의 주소값 @ 뒤의 값 6d06d69c (16진수) -> hashCode 1829164700(10진수) 값으로 변환이 되는것을 볼 수 있습니다.

그렇다면 주소값만으로도 hashCode처럼 대상을 비교할 수 있지않나? 그럼 equals랑 ==이랑 같게 쓰여야하는거 아닌가? 라는 생각을 했었는데
멍-충
주소값이 서로 다르지만 문자열은 같은 두 String 객체를 가지고 hashCode를 비교해보았습니다.

ex_screenshot ex_screenshot 주소값은 다르지만 같은 문자열에 대해 hashCode가 같은 것을 볼 수 있습니다.
[응? 주소값으로 hashCode만드는데 주소값이 다른데 hashCode가 같네? 모순모순!] 이라고 할 뻔 했지만

String의 hashCode() 는 재정의가 되어 사용된다.

가 정답입니다.

String은 문자열이고 “에이”와 “에이”가 주소가 다르다고 다른말이라면 hashCode의 의미가 없을뿐더러 발생할 수 있는 나쁜 예로
-> HashMap에서 일치하는 key 값을 찾아낼 수 없게 되겠죠
그래서 String은 hashCode를 생성할 때 주소값 말고 문자열로 생성하는 것으로 hashCode() 메서드가 재정의 된 것이랍니다.

여기까지 equals메서드와 ‘==’연산자의 간단한 차이였습니다.


아래는 String 기본 설명 살짝 덧붙여봤습니다.

우선 spring 둘의 주소값이 다른 이유

String aa = "에이";
String bb =new String("에이");

리터널 aa변수는 stack 메모리에, “에이”라는 문자열은 Heap 메모리 내에 String pool 이라는 곳에 저장. 그 주소가 aa변수에 저장됩니다. 또한 String pool에 저장될때 intern() 이라는 메서드가 실행되는데
intern() = 같은 값이 있는 경우 기존 값의 메모리 주소를 사용하고, 다른 값일 경우 객체를 생성해 값을 저장하고 그 메모리 주소를 리턴합니다. Spring pool이 HashMap 자료구조 형태로 중복된 데이터 저장을 막습니다. 그래서

String c = "씨";
String cc = "씨";
c == cc --> true 

라는 결과를 얻게되는것이죠.

반대로
new 연산자 사용시 bb은 stack메모리에, “Hello” 는 일반 Heap 메모리 내에 생성되어 문자열이 같더라도 계속 새로운 인스턴스가 생성되게 되는것입니다.
그렇다면 메모리관리를 위해서라도 String은 리터널로 생성하는것이 권장되겠죠?
오늘도 화이팅입니다!