본문 바로가기
언어/Java

[Java] == 연산자와 equals() 매서드의 차이

by Geunny 2020. 8. 4.
반응형

두 값 비교하기

 

Java 언어에서 두 변수의 값을 비교할 때

'==' 연산자를 이용한다.

 

== 연산자는 Primitive value의 경우 두 변수의 값을 비교하게 된다.

Java 에서 Primitive value는 다음과 같이 8가지 종류가 존재한다.

byte 8bits -2^7 ~ 2^7-1 (-128 ~ 127)
short 16bits -2^15 ~ 2^15-1 (-32768 ~ 32767)
int 32bits -2^31 ~ 2^31-1 (-2147483648 ~ 2147483647)
long 64bits -2^63 ~ 2^63-1 (-9223372036854775808 ~ 9223372036854775807)
float 32bits 0x0.000002P-126f ~ 0x1.fffffeP+127f
double 64bits 0x0.0000000000001P-1022 ~ 0x1.fffffffffffffP+1023
char 16bits \u0000 ~ \uffff (0 ~ 2^15-1) * 자바에서 unsgined로 동작하는 자료형 
boolean 1bit true, false

위 변수들은 == 매서드로 비교할 때 값으로 두변수를 비교한다.

 

public class EqualsMethod {
	public static void main(String[] args) {
		
		byte b1 = 1;
		byte b2 = 1;
		System.out.println(b1==b2);

		short s1 = 128;
		short s2 = 128;
		System.out.println(s1==s2);
		
		int i1 = 327678;
		int i2 = 327678;
		System.out.println(i1==i2);
		
		long l1 = 2147483648L;
		long l2 = 2147483648L;
		System.out.println(l1==l2);
		
		float f1 = 1234.1234f;
		float f2 = 1234.1234f;
		System.out.println(f1==f2);
		
		double d1 =  0x2.fffffeP+127;
		double d2 =  0x2.fffffeP+127;
		System.out.println(d1==d2);
		
		char c1 = 'a';
		char c2 = 'a';
		System.out.println(c1==c2);
		
		boolean bo1 = false;
		boolean bo2 = false;
		System.out.println(bo1==bo2);
		
		
	}
}

 

위 변수들은 선언시 모두 Stack 메모리 영역에 할당되어 변수를 사용할 때

값으로 사용되므로 == 연산자로 비교시에도 값으로 비교되게 된다.

이러한 특징은 String 문자열을 값으로 직접 만들었을 때도 똑같이 작용한다.

 

public class StringObject {
	public static void main(String[] args) {
		String s1 = "abcd";
		String s2 = "abcd";

		System.out.println(s1 == s2);

		String so1 = new String("abcd");
		String so2 = new String("abcd");

		System.out.println(so1 == so2);
	}
}

위 코드에서 보다시피

String 문자열은 객체로 이루어져 있으나

" " 를 이용하여 리터럴 변수로 사용하게 되면

Primitive value와 유사하게 String constant pool 메모리에 할당되어 사용시 값으로 사용된다.

(이는 String 내부에 intern() method를 통해 해당 pool에 할당되는데

이는 나중에 다시 정리 하도록 하겠습니다.)

 

String literal 과 String Object 메모리 저장

 

즉 == 연산자는 해당 변수(객체) 의 메모리 주소를 비교하는 연산자이다.

Primitive value 나 스트링 리터럴 같은 경우는

메모리에서 해당 값이 1개만 존재하여 ==으로 비교시 값 비교가 이루어 지게 된다.

하지만 실제 == 연산자는 메모리 주소를 비교하게 되므로

위의 코드에서 아래 String 객체로 생성하였을 때는

각각의 객체가 Heap 메모리에 저장이 되어 두 객체가 서로 다른 주소값을 갖고 있어

== 비교시 false를 반환하게 된다.

 

 

 

 

하지만 아래 new 연산자를 이용하여 객체로 생성할 때는

기본적인 객체들 처럼 Heap영역에 할당되어

주소값을 참조하는 형태로 생성되게 된다.

 

그렇다면 Heap 영역에 할당되는 객체들을 비교할 때는 어떤 방식으로 이루어져 질까?

이를 알기 위해서는 먼저 모든 객체의 최상의 부모 클래스인

Object 객체에 대해 먼저 알아보자.

 

Object 객체

 

자바의 모든 객체는 Object 객체를 상속받는 형태로 이루어져 있다.

Object 객체는 기본적으로 equals method를 갖고 있다.

 

만약 class 를 직접 만들었을 때의 equals method를 생성하면

아래와 같이 method Overide를 진행해 주도록 나타난다.

class myObject{
	
	@Override
	public boolean equals(Object obj) {
		return super.equals(obj);
	}
}

 

 

 

Object 의 eauals method를 보면 다음과 같다.

 

// Object class 내부

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

기본적인 Object class는 equals method는

기존의 == 매서드를 이용하여 비교하는 상태로 되어있다.

 

그렇다면 두 객체가 같다는 의미는 무엇일까?

먼저 Heap에 있는 한 객체를 서로 다른 reference로 참조하는 경우

두 reference에 대해서 hashCode() method를 호출하면 같은 결과가 나타난다.

 

public class StringObject {
	public static void main(String[] args) {
		String s1 = "abcd";
		String s2 = "abcd";
		System.out.println(s1.hashCode());
		System.out.println(s2.hashCode());
	}
}

 

 

더 나아가 객체 동치에 대해 알아보면

Heap에  객체가 두 개 들어있고, 두 reference가 각 객체를 참조하지만

그 두 객체가 동치인 것으로 간주할 수 있는 경우

 

Object class 로 부터 상속받은 hashCode() 와 equals() method를 모두 override 해주어야 한다.

hashCode()와 equals()에 관련된 규칙은 아래와 같다.

 

더보기

1. 두 객체가 같으면 반드시 같은 hashcode를 가져야 한다.

2. 두 객체가 같으면 equals() method를 호출했을 때 true를 반환해야 한다.

즉, a,b 가 같으면 a.equlas(b)와 b.equals(a) 모두 true를 반환해야 한다.

 

3. 두 객체가 같다면 두 객체의 hashcode는 반드시 같아야 한다.

하지만 두 객체의 hashcode값이 같다고 해서 반드시 같은 것은 아니다.

 

4. equals()를 override 하면 반드시 hashCode()도 override 해줘야 한다.

 

5. hashCode() 에서는 기본적으로 Heap에 있는 각 객체마다 서로 다른 값을 가지는 유일한 정수를 반환한다.

Class 에서 hashCode() method를 override 하지 않으면 절대로 그 유형의 두 객체가 같은 것으로 간주될 수 없다.

 

6. equals() method 에서는 기본적으로 == 연산자를 써서 객체를 비교한다.

즉, 두 reference가 Heap에 있는 한 객체를 참조하는지를 확인한다.

따라서 equals() 를 override 하지 않으면 절대 그 유형의 두 객체가 같아질수 없다.

즉!

객체가 같지 않더라도 hashCode는 같을 수 있다..

댓글