자바와 코틀린에서의 동등성 비교(==, ===, equals())

  • 동일성(Identity): 참조 주소를 비교
  • 동등성(Equality): 내용 기반 비교

자바에서의 참조타입 동작

==와 != 연산자는 참조 동등성을 뜻하며, 내용을 기반으로 하는 동등성은 equals() 호출을 통해 구현한다.

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import java.util.*;

public class Main
{
public static void main(String[] args) {
String[] arr1 = {"1", "2"};
String[] arr2 = {"1", "2"};
System.out.println("arr1 address: " + arr1 + " / arr2 address: "+ arr2);

if (arr1 == arr1) {
System.out.println("array Identity");
}
if (arr1.equals(arr2)) {
System.out.println("array Equality");
}

Data d1 = new Data("x");
Data d2 = new Data("y");
ArrayList<Data> list1 = new ArrayList();
list1.add(d1);
list1.add(d2);
ArrayList<Data> list2 = new ArrayList();
list2.add(d1);
list2.add(d2);
System.out.println("list1 address: " + list1 + " / list2 address: "+ list2);

if (list1 == list2) {
System.out.println("list Identity");
}
if (list1.equals(list2)) {
System.out.println("list Equality");
}
}
}

class Data
{
Data(String a) {
this.a = a;
}
private String a = null;
}

/** 출력
array Identity
list Equality
*/

참고로 new ArrayList()로 리스트 객체를 생성하는 게 아니라 list를 대입하게 되면 주소값이 동일해진다.

1
2
3
4
5
6
7
8
9
10
11
list1 = list2;
if (list1 == list2) {
System.out.println("list Identity");
}
if (list1.equals(list2)) {
System.out.println("list Equality");
}
/** 출력
list Identity
list Equality
*/

반면, 코틀린에서의 참조타입 동작

연산자 형태(== 또는 !=)로 호출하는 경우 equals()를 호출하기 때문에 두 방식은 같은 결과가 나온다.
참조 동등성을 비교하려면 === 또는 !== 연산자를 사용하면 된다.

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
fun main() {
val dataclass1: DataClass = DataClass()
val dataclass2: DataClass = DataClass()
val list1: List<DataClass> = listOf(dataclass1, dataclass2)
val list2: List<DataClass> = listOf(dataclass1, dataclass2)

if (list1 == list2) println("list used data class == Equality")
if (list1.equals(list2)) println("list used data class equals() Equality")
if (list1 === list2) println("list used data class Identity")

val data1: Data = Data()
val data2: Data = Data()
val list3: List<Data> = listOf(data1, data2)
val list4: List<Data> = listOf(data1, data2)

if (list3 == list4) println("list used class == Equality")
if (list3.equals(list4)) println("list used class equals() Equality")
if (list3 === list4) println("list used class Identity")
}

data class DataClass(val x: String = "x")
class Data(val y: String = "y")

/** 출력
list used data class == Equality
list used data class equals() Equality
list used class == Equality
list used class equals() Equality
*/

String 변수의 동작

변수 타입은 기본형(Primitive type)과 참조형(Reference type)이 있다. 그 중 String은 참조형이지만 기본형처럼 쓰이는데 위의 예제와 동작이 약간 다르다. 자바에서는 String str1 = "a"와 같이 일반적인 대입 방식으로 값을 초기화하면 String str2 = "a"처럼 같은 값(“a”)을 가진 변수는 같은 주소를 참조하게 된다. 따라서 아래 예제에서 ==와 equals 동작이 동일하게 true로 출력된다.
그리고 같은 값이라도 이 참조 주소를 다르게 설정하고자 new String()으로 객체를 생성하게 되는 경우 참조 동등성(==)을 비교하면 false가 반환된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
String str1 = "a";
String str2 = "a";

if (str1 == str2) System.out.println("string Identity");
if (str1.equals(str2)) System.out.println("string Equality");

String strNew1 = new String("b");
String strNew2 = new String("b");

if (strNew1 == strNew2) System.out.println("stringNew Identity");
if (strNew1.equals(strNew2)) System.out.println("stringNew Equality");

/** 출력
string Identity
string Equality
stringNew Equality
*/

코틀린에서는 new 키워드가 없어 다음 세 가지를 비교하면 이러하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
fun main() {
val str1: String = "a"
val str2: String = "a"

if (str1 == str2) println("string == Equality")
if (str1.equals(str2)) println("string equals() Equality")
if (str1 === str2) println("string Identity")
}
/** 출력
string == Equality
string equals() Equality
string Identity
*/

Nullable 값

자바에서는 NPE를 방지하기 위해 equals()에서도 수신 객체가 널인 경우 악명높은 NPE(Null Point Exception) 오류가 나기 때문에 null이 아님을 보장하기 위해 obj != null과 같이 조건문을 추가해 주어야 한다.

1
2
String obj = null;
if (obj.equals(something)) {} // NPE

반면, 코틀린에서는 ==와 != 두 연산자로 비교하는 값이 null이라도 오류가 나지 않는다. 연산자의 왼쪽 피연산자가 null인 경우에는 참조 동등성을 사용해 널과 비교하면 된다.

참고
알렉세이 세두노프 <코틀린 완벽 가이드>

자바와 코틀린에서의 동등성 비교(==, ===, equals())

https://dl137584.github.io/2022/04/18/021-kotlin-equality-and-identity/

Author

LEEJS

Posted on

2022-04-18

Updated on

2022-05-02

Licensed under

댓글