์ฌ์ค ์๋ฐ ์ฝ๋๋ฅผ ์์ฑ๋ง ํด๋ดค์ง, ๊น๊ฒ ์ ๋ฆฌํ๋ ค๊ณ ํ ์ ์ ์์๋ ๊ฒ ๊ฐ๋ค. ๋งค๋ฒ โ๋นจ๋ฆฌ ์ทจ์ ํด์ผ์ง!โ๋ผ๋ ์๊ฐ์ ์กฐ๊ธํ๊ฒ ํ๋ก์ ํธ๋ง ํ๊ณ , ๊ธฐ๋ณธ ๊ฐ๋ ๋ง ๋์ถฉ ํ๊ณ ๋์ด๊ฐ๋ ๋ฉด์ ๋ ์กฐ๊ธ๋ง ๊น๊ฒ ๋ค์ด๊ฐ๋ ๋๋ต์ ์ ๋๋ก ๋ชป ํ๋ค. ๊ทธ๋ด ๋๋ง๋ค ๋ด ์์ ์ด ํ์ฌํ๊ฒ ๋๊ปด์ก๋ค.
์ด์ ๋ ์กฐ๊ธํดํ์ง ๋ง๊ณ , ์ฒ์๋ถํฐ ์ฐจ๊ทผ์ฐจ๊ทผ ์ ๋๋ก ์ค๋นํด๋ณด๋ ค ํ๋ค.
๋์ผ์ฑ์ ๋ง ๊ทธ๋๋ก ๋ ๊ฐ์ ๊ฐ์ฒด๊ฐ ์์ ํ ๊ฐ์ ๊ฒฝ์ฐ๋ฅผ ์๋ฏธํ๋ค. ๋ง๋ณด๋ค๋ ์ฝ๋๋ก ๋ณด๋ฉด ์ฌ์ธ ๊ฒ ๊ฐ๋ค.
class Person {
String name;
Person(String name) {
this.name = name;
}
}
public class Main {
public static void main(String[] args) {
Person personA = new Person("์ฒ ์");
Person personB = new Person("์ฒ ์");
Person personC = personB;
System.out.println(personA == personB); // false (์๋ก ๋ค๋ฅธ ๊ฐ์ฒด)
System.out.println(personB == personC); // true (๊ฐ์ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐ)
}
}
personA์ personB๋ ์ด๋ฆ์ ๊ฐ์ง๋ง ์๋ก ๋ค๋ฅธ ๊ฐ์ฒด๋ค.
์๋ํ๋ฉด new ํค์๋๋ก ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ฉด heap ๋ฉ๋ชจ๋ฆฌ ์์ญ์ ์๋ก ๋ง๋ค์ด์ง๊ธฐ ๋๋ฌธ์, ์๋ก ๋ค๋ฅธ ์ฃผ์๋ฅผ ๊ฐ์ง๊ฒ ๋๋ค.
ํ์ง๋ง personC๋ personB๋ฅผ ๊ทธ๋๋ก ์ฐธ์กฐํ๋ฏ๋ก, ๊ฐ์ ์ฃผ์๋ฅผ ๊ฐ๋ฆฌํค๊ฒ ๋๋ค.
์ฐธ๊ณ ๋ก ์์(Primitive) ํ์ ์ ๊ฐ์ฒด๊ฐ ์๋๋ผ ์ฃผ์๊ฐ ์๋ค.
์ด๋ฐ ๊ธฐ๋ณธ ํ์ ๋ณ์๋ค์ Stack ๋ฉ๋ชจ๋ฆฌ ์์ญ์ ๊ฐ์ด ์ง์ ์ ์ฅ๋๋ค.
int a = 10;
int b = 10;
System.out.println(a == b); // true
๊ทธ๋์ == ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ์ ๋๋ ๊ฐ์ด ๊ฐ์ผ๋ฉด ๋์ผํ๋ค๊ณ ๋งํ๋ค.
โ๏ธ ์๋ฐ์ ๋ฉ๋ชจ๋ฆฌ ์์ญ์๋ Stack, Heap, ๋ฉ์๋(Method) ์์ญ์ด ์๋ค.
Stack ์์ญ์๋ ๊ธฐ๋ณธ ํ์ ๋ณ์๋ ์ฐธ์กฐ ๋ณ์(์ฃผ์๊ฐ)๊ฐ ์ ์ฅ๋๋ค.
Heap ์์ญ์๋ new ํค์๋๋ก ์์ฑํ ์ค์ ๊ฐ์ฒด๊ฐ ์ ์ฅ๋๋ค.
๋ฉ์๋ ์์ญ์๋ ํด๋์ค ์ ๋ณด(๋ฉ์๋, static ๋ณ์, ์์ ๋ฑ)๊ฐ ์ ์ฅ๋๋ค.
๋ง ๊ทธ๋๋ก ๋๋ฑํ๋ค๋ ๋ป์ผ๋ก, ๋ ๊ฐ์ฒด๊ฐ ๊ฐ์ ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ ์๋ ๊ฒฝ์ฐ๋ฅผ ์๋ฏธํ๋ค.
๋๋ฑ์ฑ์ ๋ณ์๊ฐ ์ฐธ์กฐํ๊ณ ์๋ ๊ฐ์ฒด์ ์ฃผ์๊ฐ ๋ค๋ฅด๋๋ผ๋,
๋ด์ฉ์ด ๊ฐ์ผ๋ฉด ๋ ๋ณ์๋ ๋๋ฑํ๋ค๊ณ ๋งํ๋ค.
๋๋ฑํ์ง๋ ์ฃผ๋ก equals() ๋ฉ์๋๋ฅผ ์ฌ์ฉํด์ ํ๋ณํ๋ค.
String str1 = new String("hello");
String str2 = new String("hello");
System.out.println(str1 == str2); // false (์ฃผ์ ๋ค๋ฆ)
System.out.println(str1.equals(str2)); // true (๋ด์ฉ ๊ฐ์)
๐จ ๋์ผํ๋ฉด ๋๋ฑ, ํ์ง๋ง ๋๋ฑํ๋ค๊ณ ๋์ผ์ ์๋๋ค.
๋ชจ๋ ๊ฐ์ฒด์ ๋ํด equals() ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ๋ค๊ณ ํด์ ๋ฌด์กฐ๊ฑด ๋๋ฑ์ฑ ๋น๊ต๊ฐ ๊ฐ๋ฅํ ๊ฑด ์๋๋ค.
public boolean equals(Object obj) {
return (this == obj);
}
์ด ๋ฉ์๋๋ ๋ชจ๋ ํด๋์ค์ ์ต์์ ์กฐ์์ธ Object ํด๋์ค์์ ์ ์๋์ด ์๋ค.
์ฝ๋๋ฅผ ๋ณด๋ฉด ์ ์ ์๋ฏ์ด, ๋จ์ํ == ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํด ๋์ผ์ฑ(์ฃผ์๊ฐ ๋น๊ต)๋ง ์ํํ๋ค.
์ฆ, ์์ ํด๋์ค์์ equals() ๋ฉ์๋๋ฅผ ์ฌ์ ์(override) ํ์ง ์๋ ์ด์, equals()๋ ์ฌ์ค์ ==์ ๋์ผํ๊ฒ ์๋ํ๋ค.
์ด์ ๋ํ์ ์ผ๋ก equals() ๋ฉ์๋๋ฅผ ์ฌ์ ์ํ ๋ช ๊ฐ์ง ํด๋์ค๋ค์ ์ดํด๋ณด์.
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String) anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
String ํด๋์ค๋ ์์ฒ๋ผ equals()๋ฅผ ์ฌ์ ์ํด์, ์ธ์๋ก ์ ๋ฌ๋ ๋ฌธ์์ด์ ๋ด์ฉ์ ํ ๊ธ์์ฉ ๋น๊ตํ๋ค.
์ฝ๋ ํ๋ฆ์ ๋ณด๋ฉด,
๋จผ์ ==๋ก ๋์ผ์ฑ(์ฃผ์)์ ํ์ธํ๊ณ ,
์ฃผ์๊ฐ ๋ค๋ฅด๋ฉด instanceof๋ก String ํ์ ์ธ์ง ๊ฒ์ฌํ ๋ค,
๋ฌธ์ ํ๋ํ๋๋ฅผ ๋น๊ตํด์ ๋ชจ๋ ๊ฐ์ผ๋ฉด true๋ฅผ ๋ฐํํ๋ค.
์ฆ, ๋ฌธ์์ด์ ์ฃผ์๊ฐ ๋ฌ๋ผ๋ ๋ด์ฉ์ด ๊ฐ์ผ๋ฉด ๋๋ฑํ๋ค๊ณ ํ๋จํ๋ ๊ฒ์ด๋ค.
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
Integer ํด๋์ค๋ equals()๋ฅผ ์ฌ์ ์ํด์, ์ธ์๋ก ์ ๋ฌ๋ ๊ฐ์ฒด๊ฐ Integer์ธ์ง ํ์ธํ ํ, ๊ทธ ์์ ๊ฐ(value)์ ==์ผ๋ก ๋น๊ตํ๋ค.
๊ฒฐ๊ตญ ๋ ๊ฐ์ฒด์ ์ฃผ์๋ ๋ค๋ฅด๋๋ผ๋ ์ ์ฅ๋ ์ ์ ๊ฐ์ด ๊ฐ์ผ๋ฉด ๋๋ฑํ๋ค๊ณ ๋ณธ๋ค.
public static boolean equals(Object a, Object b) {
return (a == b) || (a != null && a.equals(b));
}
Objects ํด๋์ค์ equals()๋ ์กฐ๊ธ ๋ค๋ฅด๋ค. ๋ ๊ฐ์ฒด๊ฐ ๋์ผํ๋ฉด ๋ฐ๋ก true๋ฅผ ๋ฐํํ๊ณ ,
๊ทธ๋ ์ง ์์ผ๋ฉด ์ฒซ ๋ฒ์งธ ๊ฐ์ฒด์ equals() ๋ฉ์๋๋ฅผ ํธ์ถํด์ ๋น๊ตํ๋ค.
์ฆ, ์ด ๋ฉ์๋๋ ๋ด๋ถ์ ์ผ๋ก ์ฒซ ๋ฒ์งธ ์ธ์์ equals() ๊ตฌํ์ ์ ์ ์ผ๋ก ์์กดํ๋ค.
๋ง์ฝ ์ฒซ ๋ฒ์งธ ๊ฐ์ฒด๊ฐ equals()๋ฅผ ์ฌ์ ์ํ์ง ์์๋ค๋ฉด, ๊ฒฐ๊ตญ ๋์ผ์ฑ(์ฃผ์) ๋น๊ต๋ง ํ๊ฒ ๋๋ค.
๊ทธ๋์ ๊ฐ๋ฐ์๊ฐ ์ง์ ๋ง๋ ํด๋์ค์์ ๋ด์ฉ ๋น๊ต๊ฐ ํ์ํ๋ค๋ฉด, ๋ฐ๋์ equals()๋ฅผ ์ฌ์ ์ํด์ค์ผ ํ๋ค.
private boolean equalsArrayList(ArrayList<?> other) {
final int otherModCount = other.modCount;
final int s = size;
boolean equal;
if (equal = (s == other.size)) {
final Object[] otherEs = other.elementData;
final Object[] es = elementData;
if (s > es.length || s > otherEs.length) {
throw new ConcurrentModificationException();
}
for (int i = 0; i < s; i++) {
if (!Objects.equals(es[i], otherEs[i])) {
equal = false;
break;
}
}
}
other.checkForComodification(otherModCount);
return equal;
}
ArrayList๋ ์์ ์ด ๊ฐ์ง ์์(element)๋ค๊ณผ ๋น๊ต ๋์ ๋ฆฌ์คํธ์ ์์๋ค์ ํ๋์ฉ ๋น๊ตํด์ ๋ชจ๋ ๊ฐ์ผ๋ฉด true๋ฅผ ๋ฐํํ๋ค.
์ด ๊ณผ์ ์์ ์์ ํ๋ํ๋๋ฅผ ๋น๊ตํ๊ธฐ ์ํด Objects.equals()๋ฅผ ํ์ฉํ๊ณ ์๋ค.
์ฆ, ArrayList์ equals()๋ ๋ ๋ฆฌ์คํธ์ ๋ชจ๋ ์์๊ฐ ๋๋ฑํ๋ฉด ์ ์ฒด๊ฐ ๋๋ฑํ๋ค๊ณ ํ๋จํ๋ค๋ ๊ฒ์ด๋ค.
์ฌ์ค equals()๋ฅผ ์ด์ผ๊ธฐํ ๋ hashCode()๋ฅผ ๋นผ๋์ ์ ์๋ค.
์๋ํ๋ฉด ์ด ๋ ๋ฉ์๋๋ ํญ์ ํจ๊ป ๋์ํ๋ ์ธํธ์ด๊ธฐ ๋๋ฌธ์ด๋ค.
HashMap, HashSet ๊ฐ์ ์ปฌ๋ ์ ์ ๊ฐ์ฒด๋ฅผ ๋น๊ตํ ๋, ๋จผ์ hashCode()๋ก ๋น ๋ฅด๊ฒ ํ๋ณด๋ฅผ ์ฐพ๊ณ , ๊ทธ๋ค์์ equals()๋ก ์ค์ ๋ด์ฉ์ด ๊ฐ์์ง ํ์ธํ๋ค.
import java.util.Objects;
class Person {
String name;
int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
// ๋ด์ฉ(๋๋ฑ์ฑ) ๋น๊ต
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof Person)) return false;
Person other = (Person) obj;
return age == other.age && name.equals(other.name);
}
// ํด์ ๊ธฐ๋ฐ ์ปฌ๋ ์
์ ์ํ hashCode ์ฌ์ ์
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
Person p1 = new Person("์ฒ ์", 20);
Person p2 = new Person("์ฒ ์", 20);
System.out.println(p1.equals(p2)); // true
System.out.println(p1.hashCode() == p2.hashCode()); // true
๐จ equals๋ง ์ฌ์ ์ํ๊ณ hashCode๋ฅผ ์ฌ์ ์ํ์ง ์์ผ๋ฉด?
Person p1 = new Person("์ฒ ์", 20);
Person p2 = new Person("์ฒ ์", 20);
HashSet<Person> set = new HashSet<>();
set.add(p1);
set.add(p2);
System.out.println(set.size()); // 2 (๐จ ์ค๋ณต ํ๋จ ์คํจ)
โ ์ฐธ๊ณ
equals()๊ฐ true๋ผ๋ฉด, hashCode()๋ ๊ฐ์์ผ ํ๋ค.
hashCode()๊ฐ ๊ฐ๋ค๊ณ ํด์ equals()๋ true์ธ ๊ฑด ์๋๋ค.
๋ ๊ฐ์ฒด๊ฐ ํ ๋น๋ ๋ฉ๋ชจ๋ฆฌ ์ฃผ์๊ฐ ๊ฐ์ผ๋ฉด ๋์ผํ๊ณ , ๋ ๊ฐ์ฒด์ ๋ด์ฉ์ด ๊ฐ์ผ๋ฉด ๋๋ฑํ๋ค๊ณ ๋งํ๋ค. ๋์ผ์ฑ์ == ์ฐ์ฐ์๋ฅผ ํตํด, ๋๋ฑ์ฑ์ eqauls ์ฐ์ฐ์๋ฅผ ํตํด ํ๋ณํ๋ค.
== ์ฐ์ฐ์, eqauls ์ฐ์ฐ์์ ๋ํด ์ข ๋ ์์ธํ๊ฒ ์๋ ค์ฃผ์ธ์== ์ฐ์ฐ์๋ ๊ฐ์ฒด์ ๋์ผ์ฑ์ ํ๋ณํ๊ธฐ ์ํด ์ฌ์ฉํ๋ฉฐ, eqauls ์ฐ์ฐ์๋ ๋ ๊ฐ์ฒด์ ๋๋ฑ์ฑ์ ํ๋ณํ๊ธฐ ์ํด ์ฌ์ฉํ๋ค. eqauls ์ฐ์ฐ์๋ ์ฌ์ ์(์ค๋ฒ๋ผ์ด๋ฉ) ํ์ง ์์ผ๋ฉด ๋ด๋ถ์ ์ผ๋ก == ์ฐ์ฐ์์ ๊ฐ์ ๋ก์ง์ ์ํํ๋ฏ๋ก ์ฐจ์ด๊ฐ ์๊ณ , ๋ฐ๋ผ์ eqauls ์ฐ์ฐ์๋ ๊ฐ ๊ฐ์ฒด์ ํน์ฑ์ ๋ง๊ฒ ์ฌ์ ์(์ค๋ฒ๋ผ์ด๋ฉ) ํด์ผํ๋ค.
์๋ฅผ ๋ค์ด, String ํด๋์ค๋ equals()๋ฅผ ์ฌ์ ์ํด์ "hello".equals(new String("hello")) ์ ๊ฐ์ด
๋ด์ฉ์ด ๊ฐ์ผ๋ฉด true๋ฅผ ๋ฐํํ๋๋ก ๊ตฌํ๋์ด ์๋ค.
Integer ํด๋์ค๋ ๋ง์ฐฌ๊ฐ์ง๋ก ๋ด๋ถ์ ๊ฐ(value)์ด ๊ฐ์ผ๋ฉด true๋ฅผ ๋ฐํํ๋๋ก equals()๊ฐ ์ฌ์ ์๋์ด ์๋ค.
equals()๋ ๋ด์ฉ ๋น๊ต, hashCode()๋ ํด์ ๊ธฐ๋ฐ ์ปฌ๋ ์ ์์ ๊ฐ์ฒด ์์น๋ฅผ ์ฐพ์ ๋ ์ฌ์ฉ๋๋ค.
HashSet, HashMap์ ๋จผ์ hashCode()๋ก ๋น ๋ฅด๊ฒ ํ๋ณด๋ฅผ ์ฐพ๊ณ , ๊ทธ๋ค์ equals()๋ก ์ค์ ๋๋ฑ ์ฌ๋ถ๋ฅผ ํ์ธํ๊ธฐ ๋๋ฌธ์, equals()๊ฐ true์ธ๋ฐ hashCode()๊ฐ ๋ค๋ฅด๋ฉด ๊ฐ์ ๊ฐ์ฒด**๋ก ์ธ์๋์ง ์๋๋ค.

์ ์ฌ์ง์ ์์ ์ ์ฌ๋ฆ์ ๋จ์์ฃผ๋ฅผ ๋ฐฉ๋ฌธํ์ ๋ ๋จธ๋ฌผ๋ ๋ ์์๋ค.
ํ๋ก๊ทธ๋๋จธ์ค ๋ฐฑ์๋ ๋ฐ๋ธ์ฝ์ค ๋ฐฉํ ๊ธฐ๊ฐ ์ค์ ๋ฐฉ๋ฌธํ๋๋ฐ, ๊ณต๊ธฐ๋ ๋ง๊ณ ํ๋ง๋๋ ๊ธฐ๋ถ์ด์๋ค.
๋ค๋ง ๋ฒ๋ ๊ฐ ๋ง์์ ๊ฝค ๊ณ ์ํ๋ ๊ธฐ์ต๋ ์๋ค. ๊ทธ๋๋ ์ธ์ ๊ฐ ๋ค์ ํ ๋ฒ ๋ฐฉ๋ฌธํ๊ณ ์ถ๋ค.
์์ฆ ๋ง์์ด ๋๋ฌด ์กฐ๊ธํ ๊ฒ ๊ฐ๋ค. ์คํธ๋ ์ค๋ ๋ฐ๊ณ , ๋ถ์ํ ๋๋ ๋ง์ง๋ง ๊ทธ๋๋ ๋ค์ ๋ง์์ ๋ค์ก๊ณ ์ฒ์ฒํ ๊ณต๋ถํด๋ณด๋ ค ํ๋ค.
โ์ฒ์ฒํ ๊ฐ๋ ๊ด์ฐฎ๋ค. ์ค์ํ ๊ฑด ๋ฉ์ถ์ง ์๋ ๊ฒ์ด๋ค.โ