publicclassMain { publicstaticvoidmain(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"); } } } classData { 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()를 호출하기 때문에 두 방식은 같은 결과가 나온다. 참조 동등성을 비교하려면 === 또는 !== 연산자를 사용하면 된다.
funmain() { 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") } dataclassDataClass(val x: String = "x") classData(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
funmain() { 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인 경우에는 참조 동등성을 사용해 널과 비교하면 된다.