μλ°μμ ν΄λμ€λ₯Ό λ§λ€ λ extends
λ₯Ό λͺ
μνμ§ μμΌλ©΄ μλμΌλ‘ Object
λ₯Ό μμ λ°κ² λλ€.
Object ν΄λμ€λ java.lang ν¨ν€μ§
μ μν΄ μμΌλ©°, μ΄ ν¨ν€μ§λ μλ import λμμ΄κΈ° λλ¬Έμ λ³λλ‘ importλ₯Ό λͺ
μνμ§ μμλ λλ€.
λλ¬Έμ java.lang.Object
λ λͺ¨λ μλ° ν΄λμ€μ μ‘°μ(μ΅μμ ν΄λμ€)μ΄λΌκ³ ν μ μλ€.
class Person {
...
}
class Person extends Object {
...
}
μ λ μ½λλ λμΌνλ€.
κ·Έλ κΈ°μ μ°λ¦¬κ° Javaμμ ν΄λμ€λ₯Ό λ§λ€ λ, λ°λ‘ Object ν΄λμ€λ₯Ό extends νμ§ μλλΌλ toString(), equals()
κ°μ λ©μλλ₯Ό μ΄μ©ν μ μλ κ²μ΄λ€.
1. μΌκ΄μ±
λͺ¨λ κ°μ²΄κ° 곡ν΅μ μΌλ‘ μ¬μ©ν μ μλ κΈ°λ₯(toString, equals λ©μλ λ±)μ μ 곡νλ€.
2. λ€νμ± κΈ°λ°
Object νμ
νλλ‘ λͺ¨λ κ°μ²΄λ₯Ό λ΄μ μ μλ€.Object obj = "hello"; // λ¬Έμμ΄ obj = new ArrayList<>(); // 리μ€νΈ
λ©μλ | μ€λͺ |
---|---|
toString() | κ°μ²΄ μ 보λ₯Ό λ¬Έμμ΄λ‘ λ°ννλ€. (κΈ°λ³Έ ꡬνμ ν΄λμ€μ΄λ¦@ν΄μμ½λ ) |
equals(Object obj) | λ κ°μ²΄μ λ Όλ¦¬μ λλ±μ±μ λΉκ΅νλ€. (κΈ°λ³Έμ μ°Έμ‘° λΉκ΅, νμμ μ€λ²λΌμ΄λ©) |
hashCode() | κ°μ²΄μ ν΄μ κ°μ λ°ννλ€. HashMap, HashSet λ±μμ μ¬μ©λλ€. |
getClass() | λ°νμ μ μ€μ ν΄λμ€ μ 보λ₯Ό λ°ννλ€. 리νλ μ λ±μ μ¬μ©λλ€. |
clone() | κ°μ²΄λ₯Ό 볡μ νλ€. λ¨, Cloneable μΈν°νμ΄μ€ ꡬνμ΄ νμνλ€. |
finalize() | κ°μ²΄κ° GC λμμ΄ λκΈ° μ λ§μ§λ§ μ 리 μμ
μ μ μν μ μλ€. (νμ¬λ Deprecated ) |
μ΄λ² κΈμμλ μ΄ μ€
toString(), equals(), hashCode()
λ©μλμ λν΄ μμΈν λ€λ£¨μ΄λ³΄λ €κ³ νλ€.
/**
* Returns a string representation of the object.
* @apiNote
* In general, the
* {@code toString} method returns a string that
* "textually represents" this object. The result should
* be a concise but informative representation that is easy for a
* person to read.
* It is recommended that all subclasses override this method.
* The string output is not necessarily stable over time or across
* JVM invocations.
* @implSpec
* The {@code toString} method for class {@code Object}
* returns a string consisting of the name of the class of which the
* object is an instance, the at-sign character `{@code @}', and
* the unsigned hexadecimal representation of the hash code of the
* object. In other words, this method returns a string equal to the
* value of:
* <blockquote>
* <pre>
* getClass().getName() + '@' + Integer.toHexString(hashCode())
* </pre></blockquote>
*
* @return a string representation of the object.
*/
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
toString()
λ©μλλ κ°μ²΄λ₯Ό λ¬Έμμ΄λ‘ ννν κ°μ λ°ννλ€.
μ΄λ κ°μ²΄μ μ 보λ₯Ό μ¬λμ΄ μ½μ μ μλ ννλ‘ λ³νν λ¬Έμμ΄μ΄λΌκ³ ν μ μλ€.
@return a string representation of the object.
return getClass().getName() + "@" + Integer.toHexString(hashCode());
ν΄λμ€ μ΄λ¦ + @ + 16μ§μ ν΄μμ½λ νν
λ‘ λ°ννλ€.
Person ν΄λμ€
static class Person {
String name;
int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
}
public static void main(String[] args) {
Person person = new Person("Sangho", 26);
System.out.println(person.toString());
}
κ²°κ³Ό
{ν¨ν€μ§λͺ }.test$Person@251a69d7
λ©μλμ μ μλ λ΄μ©λλ‘ μ μΆλ ₯λλ κ²μ λ³Ό μ μλ€.
νμ§λ§ λ³΄ν΅ μΆλ ₯μ ν λ, toString()
μ λͺ
μν΄μ μ¬μ©νλ κ²½μ°λ λλ¬Όλ€.
public static void main(String[] args) {
Person person = new Person("Sangho", 26);
System.out.println(person);
}
κ²°κ³Ό
{ν¨ν€μ§λͺ }.test$Person@251a69d7
μμ²λΌ toString()
λ©μλλ₯Ό λΆμ΄μ§ μλλΌλ λμΌν κ²°κ³Όλ₯Ό μ»μ μ μλ€.
κ·Έ μ΄μ κ° λ¬΄μμΌκΉ?
System.out.println()
λ©μλλ₯Ό νΈμΆνλ©΄, μμ νκ² μΆλ ₯μ νκΈ° μν΄μ λͺ¨λ νμ
μ λ¨Όμ String.valueOf()
λ‘ κ°μΈκ² λλ€.
System.out.println(person); // λ΄λΆμ μΌλ‘ β μ΄λ κ² λμν¨
PrintStream.println(String.valueOf(person));
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
κ·Έλ¦¬κ³ String.valueOf()
λ©μλλ μμ κ°μ΄ λμνκ² λλ€.
μ¦,
null
μΈμ§ λ¨Όμ 체ν¬νκ³ , nullμ΄ μλλ©΄toString()
μ νΈμΆν΄μ κ·Έ κ²°κ³Όλ₯Ό μΆλ ₯ν΄μ€λ€.
μ΄ λλ¬Έμ System.out.println()
λ‘ μΆλ ₯μ ν λμλ μλμ μΌλ‘ toString()
λ©μλκΉμ§ νΈμΆμ΄ λλ κ²μ΄λ€.
μ μ΄λ κ² μ€κ³νμκΉ?
κ·ΈλΌ
String.valueOf()
λ₯Ό νΈμΆνμ§ μκ³ , λ°λ‘toString()
μ νΈμΆν΄λ λμ§ μλλ νλ κΆκΈμ¦μ΄ μκΈΈ μ μλ€.λ§μ½ null κ°μ λν΄μ,
null.toString()
μ λ°λ‘ νΈμΆνλ©΄NPE(NullPointerException)
κ° λ°μνκ² λλ€.
κ·Έλ κΈ°μ λ¨Όμ valueOf()
λ‘ κ°μΈμ μμ νκ² nullλ μ²λ¦¬ν μ μκ² λ§λ κ²μ΄λ€.
public static void main(String[] args) {
Person person = new Person("Sangho", 26);
System.out.println(person.name);
System.out.println(person.age);
}
κ·Έλ λ€λ©΄ λ§μ½ μμ²λΌ κ°μ²΄ μμ²΄κ° μλ, κ°μ²΄ μμμ κ°κ° νμ μ΄ μ‘΄μ¬νλ νλ κ°μ μΆλ ₯ν λλ μ΄λ»κ² λμν κΉ?
κ²°κ³Ό
Sangho
26
λͺ¨λκ° μλ€μνΌ κ·Έλλ‘ κ°μ΄ μΆλ ₯λμ΄μ λμ¨λ€.
κ·Έ μ΄μ λ String.valueOf()
λ©μλκ° μ€λ²λ‘λ©λμ΄ μκΈ° λλ¬Έμ΄λ€.
νμ | λ©μλ μκ·Έλμ² | μ€λͺ |
---|---|---|
boolean | public static String valueOf(boolean b) | "true" λλ "false" λ‘ λ°ν |
char | public static String valueOf(char c) | λ¬Έμ νλλ₯Ό λ¬Έμμ΄λ‘ λ³ν |
int | public static String valueOf(int i) | Integer.toString(i) νΈμΆ |
long | public static String valueOf(long l) | Long.toString(l) νΈμΆ |
float | public static String valueOf(float f) | Float.toString(f) νΈμΆ |
double | public static String valueOf(double d) | Double.toString(d) νΈμΆ |
char[] | public static String valueOf(char[] data) | λ¬Έμ λ°°μ΄ μ 체λ₯Ό λ¬Έμμ΄λ‘ λ³ν (new String(data) ) |
char[], int, int | public static String valueOf(char[] data, int offset, int count) | λ¬Έμ λ°°μ΄μ μΌλΆλ₯Ό λ¬Έμμ΄λ‘ λ³ν |
String | public static String valueOf(String s) | null μ΄λ©΄ "null" , μλλ©΄ κ·Έλλ‘ λ°ν |
Object | public static String valueOf(Object obj) | null μ΄λ©΄ "null" , μλλ©΄ obj.toString() νΈμΆ |
μ΄λ String
ν΄λμ€ λ΄λΆμμ μ΄ν΄λ³Ό μ μλ€.
int, long, float, double
κ°μ μμ νμ
μ System.out.println()
λ±μμ λ¬Έμμ΄λ‘ μΆλ ₯λ λ, λ΄λΆμ μΌλ‘ ν΄λΉ λνΌ ν΄λμ€(Integer, Long, Float, Double
)μ toString() λ©μλλ₯Ό μ¬μ©νμ¬ λ¬Έμμ΄λ‘ λ³νλλ€.
μ¬κΈ°μ Integer, String λ§ μ΄ν΄λ³΄λλ‘ νκ² λ€.
/**
* Returns a {@code String} object representing this {@code Integer}'s value.
* The value is converted to signed decimal representation and returned as a string,
* exactly as if the integer value were given as an argument to the {@link java.lang.Integer#toString(int)} method.
*
* @return a string representation of the value of this object in base 10.
*/
public String toString() {
return toString(value);
}
Integer ν΄λμ€ λν Objectλ₯Ό μμλ°κ³ μμΌλ©°, toString() λ©μλλ₯Ό μ€λ²λΌμ΄λνμ¬ λ΄λΆ μ μ κ°μ μ¬λμ΄ μ½μ μ μλ λ¬Έμμ΄λ‘ λ°ννλ€.
μ λ©μλκ° μ€λ²λΌμ΄λ λ(@Override μλ΅) toString()μ΄λ©°, μ΄λ λ΄λΆμ μΈ static λ©μλ toString() μ ν λ² λ νΈμΆνκ² λλ€.
/**
* Returns a {@code String} object representing the specified integer.
* The argument is converted to signed decimal representation and returned as a string,
* exactly as if the argument and radix 10 were given as arguments to the {@link #toString(int, int)} method.
*
* @param i an integer to be converted.
* @return a string representation of the argument in base 10.
*/
@IntrinsicCandidate
public static String toString(int i) {
int size = stringSize(i);
if (COMPACT_STRINGS) {
byte[] buf = new byte[size];
getChars(i, size, buf);
return new String(buf, LATIN1);
} else {
byte[] buf = new byte[size * 2];
StringUTF16.getChars(i, size, buf);
return new String(buf, UTF16);
}
}
μ΄λ μ μ κ°μ 10μ§μ λ¬Έμμ΄λ‘ λΉ λ₯΄κ² λ³νν΄ μ£Όλ λ©μλμ΄λ€.
Integer ν΄λμ€κ° Object.toString()
μ μ€λ²λΌμ΄λ©ν λ μ΄ λ©μλλ₯Ό λ΄λΆμ μΌλ‘ νΈμΆνλ€.
COMPACT_STRINGS
μ΅μ ν λΆκΈ°κΉμ§ ν¬ν¨λ κ³ μ±λ₯ λ²μ μ΄λΌκ³ λ³Ό μ μλ€.
@IntrinsicCandidate
ν΄λΉ μ΄λ Έν μ΄μ μ
JVM HotSpot
μ΄ μ΄ λ©μλλ₯Ό λ€μ΄ν°λΈ μ½λλ‘ μΈλΌμΈ μ΅μ νν μ μλ€λ κ²μ μλ―Ένλ€.μ¦,
int β String λ³ν
μ΄ μμ£Ό μ°μ΄κΈ° λλ¬Έμ,JIT μ»΄νμΌλ¬
κ° μμ£Ό λΉ λ₯΄κ² μ²λ¦¬ν μ μλλ‘ νΉλ³ λμ°λ₯Ό ν΄ μ£Όλ κ²μ΄λ€.
/**
* Returns a string representation of the first argument in the radix specified by the second argument.
* If the radix is smaller than {@code Character.MIN_RADIX} or larger than {@code Character.MAX_RADIX}, then radix 10 is used.
*
* @param i an integer to be converted to a string.
* @param radix the radix to use in the string representation.
* @return a string representation of the argument in the specified radix.
*/
public static String toString(int i, int radix) {
if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
radix = 10;
if (radix == 10) {
return toString(i);
}
if (COMPACT_STRINGS) {
byte[] buf = new byte[33];
boolean negative = (i < 0);
int charPos = 32;
if (!negative) {
i = -i;
}
while (i <= -radix) {
buf[charPos--] = (byte)digits[-(i % radix)];
i = i / radix;
}
buf[charPos] = (byte)digits[-i];
if (negative) {
buf[--charPos] = '-';
}
return StringLatin1.newString(buf, charPos, (33 - charPos));
}
return toStringUTF16(i, radix);
}
2μ§μ, 8μ§μ, 16μ§μ
λ± μνλ μ§μλ‘ λ³νν λ μ°λ μ€λ²λ‘λ© λ©μλμ΄λ€.
λ§μ½ radix == 10
μ΄λΌλ©΄ μμ toString(int)
μ νΈμΆν΄μ μ²λ¦¬νλ€.
μλλ©΄ digits[] λ°°μ΄
λ‘ μ§μ λ¬Έμ λ³ννκ³ StringLatin1 λλ toStringUTF16λ₯Ό μ¬μ©νλ€.
/**
* This object (which is already a string!) is itself returned.
*
* @return the string itself.
*/
public String toString() {
return this;
}
String ν΄λμ€λ κ·Έ μμ²΄κ° λ¬Έμμ΄μ΄κΈ° λλ¬Έμ, λ³ν κ³Όμ μμ΄ κ·Έλλ‘ μμ μ λ°ννκ² λλ€. return this
μ΄ λν Object.toString() λ©μλλ₯Ό μ€λ²λΌμ΄λ ν κ²μ΄λ€.
μ΄λ ν λ κ°μ²΄μ κ°μ΄ κ°μμ§, μ¦ λλ±νμ§
μ¬λΆλ₯Ό μλ €μ£Όλ λ©μλμ΄λ€.
λμ λ§€μ° μ μ¬νμ§λ§ μ½κ°μ λ€λ₯Έ μ μ΄ μ‘΄μ¬νλ€.
μ°μ λμΌνλ€
λ κ²μ λ κ°μ²΄κ° μμ ν κ°μμ μλ―Ένλ€. Javaλ‘ λ°μ§μλ©΄, κ°μ²΄μ μ°Έμ‘° μ£Όμκ° λμΌν κ°μ²΄λΌκ³ ν μ μκ² λ€.
λ°λ©΄ λλ±νλ€
λ κ²μ λ
Όλ¦¬μ μΌλ‘ κ°μ κ°μ κ°μ§λ€λ μλ―Έμ΄λ€. μ¦ κ°μ²΄ μμ²΄κ° μλλΌ, κ°μ²΄μ κ°μ΄ κ°μμ§λ₯Ό νλ¨νκ² λλ€.
λλ¬Έμ λμΌνμ§ μ¬λΆλ λλΈ μ΄ν ==
μ, λλ±νμ§ μ¬λΆλ equals()
λ‘ νλ¨νκ² λλ€.
κ·Έλ λ€λ©΄ equals()
λ©μλλ μ μ€λ²λΌμ΄λ ν΄μ μ¬μ©νλΌλ κ²μΌκΉ? μ΄λ Object ν΄λμ€μ μλ κΈ°λ³Έμ μΈ λμμ 보면 μ΄ν΄ν μ μλ€.
public boolean equals(Object obj) {
return (this == obj);
}
equals()
λ΄λΆμμλ ==
λ‘ λΉκ΅λ₯Ό ν νμ λ°ννλ κ²μ λ³Ό μ μλ€. λλ¬Έμ μ€λ²λΌμ΄λλ₯Ό νμ§ μλλ€λ©΄, κ·Έλ₯ ==
λ₯Ό μ¬μ©νλ κ²κ³Ό μ ν λ€λ¦μ΄ μλ€.
μ¬κΈ°μ ν κ°μ§ μλ¬Έμ΄ λ λ€.
λ΄λΆμ μΌλ‘ ==
μ°μ°μ μ§νν λ€ λ°νν κ±°λΌλ©΄, λ©μλλ₯Ό λ§λ€μ§ μκ³ λ°λ‘ μ°μ°νλ©΄ μ λλ κ²μ΄μμκΉ?
μ¬κΈ°μλ μλμ λͺ κ°μ§ μ΄μ λ€μ΄ μ‘΄μ¬νλ€.
κ³΅ν΅ μΈν°νμ΄μ€ μ 곡
μλ°μμ λͺ¨λ ν΄λμ€λ Objectλ₯Ό μμ λ°κ² λκΈ°μ, Objectλ λͺ¨λ κ°μ²΄μμ 곡ν΅μ μΌλ‘ νμν κΈ°λ₯μ μ μν΄μΌ νλ€.
κ°μ²΄ κ°μ
λλ±μ± λΉκ΅
λ κ±°μ λͺ¨λ νλ‘κ·Έλ¨μμ νμν μ μκΈ° λλ¬Έμ, μ΄λ₯Ό μνequals()
λ©μλλ₯Ό κΈ°λ³ΈμΌλ‘ μ 곡ν κ²μ΄λ€.
μ κΈ°λ³Έ ꡬνμ
==
μΈκ°?Objectλ
λͺ¨λ ν΄λμ€μ μ΅μμ ν΄λμ€
μ΄κΈ° λλ¬Έμ, κ·Έ κ°μ²΄κ° 무μμ μλ―Ένλμ§, λ΄λΆ κ°μ΄ 무μμ λνλ΄λμ§ μ μ μλ€.κ·Έλ κΈ° λλ¬Έμ Object μ μ₯μμλ λ©λͺ¨λ¦¬ μ κ°μ κ°μ²΄μΈμ§(λμΌμ±)λ§ λΉκ΅νλ κ²μ΄ κ°μ₯ 보νΈμ μ΄κ³ μμ ν κΈ°λ³Έκ°μ΄ λλ€.
μ¦, λ΄λΆ κ° κΈ°λ° λΉκ΅λ₯Ό κΈ°λ³ΈμΌλ‘ μ 곡νκΈ°μλ Object μμ€μμλ λ무 μΌλ°μ μ΄μ΄μ μ μ©μ΄ λΆκ°λ₯νλ κ²μ΄λ€.
μ€λ²λΌμ΄λλ₯Ό μΌλμ λ μ€κ³
equals()
λ μ²μλΆν° νμν λ κ° ν΄λμ€μμ μ€λ²λΌμ΄λνλλ‘ μ€κ³λ λ©μλμ΄λ€.μ¦, κ°λ°μκ° ν΄λμ€μ μλ―Έμ λ§κ² λ Όλ¦¬μ λλ±μ±μ μ μνλλ‘ μλλ κ²μ΄λ€.
μ΄ μ λ€μ μλ°μ 곡μ API λ¬Έμ λ° λμμμ μ΄ν΄λ³Ό μ μλ€.
λ νΌλ°μ€
1. Java SE 곡μ API λ¬Έμ (Object ν΄λμ€)
The equals method implements an equivalence relation on non-null object references. It is recommended that all subclasses override this method.
- equals()λ λͺ¨λ κ°μ²΄μμ λλ±μ±μ ννν μ μλλ‘ μ 곡λ λ©μλλ€.
- λͺ¨λ μλΈ ν΄λμ€λ νμνλ©΄ μ΄ λ©μλλ₯Ό μ¬μ μνλΌ(recommended).
2. Effective Java (Joshua Bloch)
Always override equals when logical equality is important.
- λ Όλ¦¬μ λλ±μ±μ΄ μ€μν ν΄λμ€μμλ equalsλ₯Ό λ°λμ μ€λ²λΌμ΄λνλΌ.
μμμ μ΄ν΄ λ³Έ λ°μ λ°λ₯΄λ©΄, equals()
λ©μλλ ==
κ³Ό λμΌν κΈ°λ₯μ νκ² λλ€.
νμ§λ§ λ μ¬λ € 보면 μ°λ¦¬λ€μ λ String νμ
λ¬Έμμ΄μ λΉκ΅ν λ μμ°μ€λ½κ² equals()
λ₯Ό μ¬μ©νλ€.
μ€λ²λΌμ΄λ ν κΈ°μ΅μ μλλ°, μ΄λ»κ² λ μΌμΌκΉ?
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
return (anObject instanceof String aString)
&& (!COMPACT_STRINGS || this.coder == aString.coder)
&& StringLatin1.equals(value, aString.value);
}
κ·Έ μ΄μ λ, String ν΄λμ€μμ μ΄λ―Έ equals()
λ₯Ό μ€λ²λΌμ΄λ ν΄λμκΈ° λλ¬Έμ΄λ€. μ΄λ Integer
μ κ°μ λλΆλΆμ λνΌ ν΄λμ€μμ μ μ©λλ λ΄μ©μΈλ°, μ¬κΈ°μλ Stringλ§ μμλ³΄λ €κ³ νλ€.
λμμ μλμ κ°λ€.
this == anObject
- λ¨Όμ λμΌμ±(μ°Έμ‘°κ°)μ λΉκ΅νλ€.
- μ°Έμ‘° κ°μ΄ κ°λ€λ©΄ μμ ν λμΌν κ°μ²΄μ΄λ―λ‘
true
λ₯Ό λ°λ‘ λ°ννλ€.
instanceof String
anObject
κ°String μΈμ€ν΄μ€
μΈμ§ νμΈνλ€.- String ν΄λμ€ λ΄λΆ λ©μλμ΄λ―λ‘, λ§μ½ μλλΌλ©΄
false
λ₯Ό λ°ννλ€.
coder λΉκ΅ (Compact String μ΅μ ν)
COMPACT_STRINGS
κ° νμ±νλ κ²½μ° λ¬Έμ μΈμ½λ©coder
μ΄ κ°μμ§ νμΈνλ€.- λ΄λΆμμ
Latin1
μΈμ§UTF-16
μΈμ§ ꡬλΆνκΈ° μν μ΅μ ν λ¨κ³μ΄λ€.
StringLatin1.equals()
νΈμΆ
- λ§μ§λ§μΌλ‘ λ΄λΆ value λ°°μ΄(λ¬Έμ λ°μ΄ν°)μ λΉκ΅νμ¬ λ΄μ©μ΄ κ°μμ§λ₯Ό νλ¨νλ€.
@IntrinsicCandidate
public static boolean equals(byte[] value, byte[] other) {
if (value.length == other.length) {
for (int i = 0; i < value.length; i++) {
if (value[i] != other[i]) {
return false;
}
}
return true;
}
return false;
}
μ΅μ’ μ μΌλ‘ νΈμΆλλ λ©μλλ μλμ κ°μ΄ λμνλ€.
- λ°°μ΄ κΈΈμ΄λ₯Ό λ¨Όμ λΉκ΅νλ©°, κΈΈμ΄κ° λ€λ₯΄λ©΄ λ°λ‘ falseλ₯Ό λ°ννλ€.
- κΈΈμ΄κ° κ°μΌλ©΄ κ° byteλ₯Ό μμ°¨μ μΌλ‘ λΉκ΅νλ€.
- νλλΌλ λ€λ₯΄λ©΄ false, λͺ¨λ κ°μΌλ©΄ trueλ₯Ό λ°ννλ€.
κ²°κ³Όμ μΌλ‘ String ν΄λμ€λ μ΄λ―Έ equals()λ₯Ό μ μ ν μ€λ²λΌμ΄λνκ³ μ΅μ ν κΈ°λ₯κΉμ§ μ 곡νλ―λ‘, μ°λ¦¬λ νΈλ¦¬νκ² νΈμΆλ§ νμ¬ λ¬Έμμ΄ λ΄μ©μ λΉκ΅ν μ μλ κ²μ΄λ€.
π§π»βπ» μμμ μΈκΈλ
coder, COMPACT_STRINGS, Latin1, UTF-16
κΉμ§ μ΄ κΈμμ λ€λ£¨κΈ°μ λ무 λ°©λν΄μ§ κ² κ°μ λ°λ‘ λΉΌλ €κ³ νλ€.
hashCode()
λ©μλλ κ°μ²΄λ₯Ό ν΄μ κΈ°λ° μλ£κ΅¬μ‘°(HashMap, HashSet λ±)μ μ μ₯νκ±°λ κ²μν λ μ¬μ©λλ ν΄μ κ°μ λ°ννλ λ©μλμ΄λ€.
ν΄μ κ°
μ΄λ μΌμ ν κ·μΉμ λ°λΌ κ³μ°ν΄ μ»μ κ³ μ ν¬κΈ°μ μ«μ(λ³΄ν΅ μ μ intν)λ₯Ό μλ―Ένλ€.
μ΄ κ°μ λ°μ΄ν°μ λ΄μ©μ μ§§κ³ κ³ μ ν μ«μλ‘ μμ½ν κ²μ΄λΌκ³ λ³Ό μ μλ€. λμΌν λ°μ΄ν°λ λμΌν ν΄μ κ°μ κ°μ§λ©°, λ€λ₯Έ λ°μ΄ν°λ λλλ‘μ΄λ©΄ λ€λ₯Έ ν΄μ κ°μ κ°μ§λλ‘ μ€κ³λλ€.
μ¬κΈ°μ 'λλλ‘'μ΄λΌκ³ ννν μ΄μ λ, λΆκ°νΌνκ² ν΄μ κ°μ΄ κ°μ κ²½μ°κ° λ°μν μ μκΈ° λλ¬Έμ΄λ€.
μ΄λ¬ν ν΄μ κ°μ μ λ§λ€κ³ , μ μ°λ κ²μΌκΉ? μ΄μ λ μλμ κ°λ€.
- ν΄μ κΈ°λ° μλ£κ΅¬μ‘°(μ: HashMap, HashSet)λ ν΄μ κ°μ νμ©ν΄μ λ°μ΄ν°μ μμΉλ₯Ό λΉ λ₯΄κ² μ°Ύμ μ μλ€.
- λ°μ΄ν°κ° ν¬λλΌλ μ§§μ ν΄μ κ°λ§ λΉκ΅νλ©΄ λλ―λ‘ μ±λ₯μ΄ λ μ’λ€.
μ¦, hashCode()
μμ λ°ννλ κ°μ κ°μ²΄μ λ΄μ©μ κΈ°λ°μΌλ‘ κ³μ°λ μ μμ΄λ©°, ν΄μ ν
μ΄λΈμμ λΉ λ₯΄κ² λ°μ΄ν°λ₯Ό μ°ΎκΈ° μν μ£Όμ μν μ νκ² λλ€.
κ·ΈλΌ μ΄λ¬ν ν΄μ κ°μ μ΄λ ν κ³Όμ μ ν΅ν΄μ λ§λ€μ΄μ§λ κ±ΈκΉ? μ§κΈλΆν°λ μ΄μ λν΄ νμ ν΄λ³΄κ³ μ νλ€.
@IntrinsicCandidate
public native int hashCode();
Object ν΄λμ€μμ μ μλμ΄ μλ hashCode() λ©μλλ μμ κ°λ€.
μμν native
λΌλ λΆλΆμ΄ λ³΄μΌ κ²μ΄λ€.
native λ©μλλ μλ° μ½λλ‘ κ΅¬νλμ΄ μμ§ μκ³ , JVM λ΄λΆ(λ€μ΄ν°λΈ μ½λ)
μ ꡬνλμ΄ μλ€. JNI(Java Native Interface)
λ₯Ό ν΅ν΄ JVM λ 벨, μμ€ν
λ 벨μμ μλνκ² λλ κ²μ΄λ€.
κΈ°λ³Έμ μΌλ‘λ κ°μ²΄μ λ©λͺ¨λ¦¬ μ£Όμλ κ·Έ μ£Όμλ₯Ό κΈ°λ°μΌλ‘ κ³μ°ν μμΉλ₯Ό ν΄μ μ½λλ‘ λ°ννκ² λλλ°, JVM ꡬνλ§λ€ λ°©μμ΄ λ€λ₯Ό μκ° μλ€.
String
ν΄λμ€μμ hashCode() λ©μλκ° μ΄λ»κ² μ€λ²λΌμ΄λ λμ΄ μλμ§ μμ보λλ‘ νμ.
/**
* Returns a hash code for this string. The hash code for a
* {@code String} object is computed as
* <blockquote><pre>
* s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
* </pre></blockquote>
* using {@code int} arithmetic, where {@code s[i]} is the
* <i>i</i>th character of the string, {@code n} is the length of
* the string, and {@code ^} indicates exponentiation.
* (The hash value of the empty string is zero.)
*
* @return a hash code value for this object.
*/
public int hashCode() {
// The hash or hashIsZero fields are subject to a benign data race,
// making it crucial to ensure that any observable result of the
// calculation in this method stays correct under any possible read of
// these fields. Necessary restrictions to allow this to be correct
// without explicit memory fences or similar concurrency primitives is
// that we can ever only write to one of these two fields for a given
// String instance, and that the computation is idempotent and derived
// from immutable state
int h = hash;
if (h == 0 && !hashIsZero) {
h = isLatin1() ? StringLatin1.hashCode(value)
: StringUTF16.hashCode(value);
if (h == 0) {
hashIsZero = true;
} else {
hash = h;
}
}
return h;
}
λμ κ³Όμ μ μλμ κ°λ€.
int h = hash;
hash
λ String μΈμ€ν΄μ€ λ΄λΆμ μΊμ±λ ν΄μ μ½λ κ°μΌλ‘, μ΅μ΄μλ 0μΌλ‘ μ΄κΈ°νλμ΄ μλ€.
if (h == 0 && !hashIsZero) {
hash κ°μ΄ 0μ΄κ³ , hashIsZero
νλκ·Έλ falseμΌ λλ§ μλ‘ ν΄μ μ½λλ₯Ό κ³μ°νλ€.
μλνλ©΄ λΉ λ¬Έμμ΄μ ν΄μ κ°μ 0μ΄ λλλ°, μ΄λ₯Ό ꡬλΆνκΈ° μν΄ hashIsZero
νλκ·Έλ₯Ό λ°λ‘ λ κ²μ΄λ€.
h = isLatin1() ? StringLatin1.hashCode(value)
: StringUTF16.hashCode(value);
isLatin1()
μΌλ‘ λ΄λΆ μΈμ½λ© λ°©μμ νμΈνκ² λλ€.
Latin1
μ΄λ©΄StringLatin1.hashCode()
νΈμΆ
public static int hashCode(byte[] value) {
int h = 0;
for (byte v : value) {
h = 31 * h + (v & 0xff);
}
return h;
}
1λ°μ΄νΈ
μ© μ½μΌλ©° (v & 0xff)λ‘ λΆνΈ μλ κ°μΌλ‘ λ³ν ν 31 * h + v λ°©μ
μΌλ‘ ν΄μ κ°μ κ³μ°νλ€.
UTF-16
μ΄λ©΄StringUTF16.hashCode()
νΈμΆ
public static int hashCode(byte[] value) {
int h = 0;
int length = value.length >> 1; // 2λ°μ΄νΈμ© λ¬Άμ΄μ char λ¨μλ‘ μ²λ¦¬
for (int i = 0; i < length; i++) {
h = 31 * h + getChar(value, i); // UTF-16μμ char κ°μ κ°μ Έμ΄
}
return h;
}
2λ°μ΄νΈ(char)
λ¨μλ‘ μ½μΌλ©° getChar()
λ₯Ό ν΅ν΄ char κ°μ μΆμΆνκ³ λμΌνκ² 31 * h + char λ°©μ
μΌλ‘ ν΄μ κ°μ κ³μ°νλ€.
if (h == 0) {
hashIsZero = true;
} else {
hash = h;
}
κ³μ°λ ν΄μ κ°μ΄ 0μ΄λ©΄, λΉ λ¬Έμμ΄μ΄κ±°λ μ€μ λ‘ κ°μ΄ 0μΈ κ²½μ°μ΄λ―λ‘ hashIsZero = true
λ‘ νλκ·Έλ₯Ό μ€μ νλ€.
κ·Έλ μ§ μλ€λ©΄, hash
μ μΊμ±νλ€.
return h;
μ΅μ’ μ μΌλ‘ κ³μ° or μΊμ±λ ν΄μ κ°μ λ°ννλ€.
equals()
λ©μλλ₯Ό μ¬μ μνλ€λ©΄, hashCode()
λ©μλλ ν¨κ» μ¬μ μν΄μΌ νλ€λ λ§μ λ€μ΄λ³΄μμ κ²μ΄λ€.
μ§κΈλΆν°λ κ·Έ μ΄μ μ λν΄μ μμμ ν¨κ» μμλ³΄κ³ μ νλ€.
import java.util.Objects;
public class Person {
int age;
String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}
}
equals() λ©μλλ₯Ό μ¬μ μν Person
ν΄λμ€μ΄λ€.
age
μ name
μ΄ λͺ¨λ κ°μ κ²½μ°μλ§ λλ±νλ€κ³ νλ¨λλ€.
π‘
Objects.equals()
λ©μλκ° μν΄ μλjava.util.Objects ν΄λμ€
λ, Java 7λΆν° μΆκ°λ μ νΈλ¦¬ν° ν΄λμ€μ΄λ€.
null
μ²λ¦¬λ₯Ό μμ νκ³ κ°κ²°νκ² νκ±°λ, κ°μ²΄ κ΄λ ¨ κ³΅ν΅ μμ μ λμμ£Όλ μ μ λ©μλλ€μ μ 곡νλ€.
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class test {
public static void main(String[] args) {
Person person1 = new Person(21, "sangho");
Person person2 = new Person(21, "sangho");
// == λΉκ΅
System.out.println(person1 == person2); // false
// equals λΉκ΅
System.out.println(person1.equals(person2)); // true
// Listμ μΆκ° ν ν¬κΈ° μΆλ ₯
List<Person> list = new ArrayList<>();
list.add(person1);
list.add(person2);
System.out.println("List size : " + list.size()); // 2
// HashSetμ μΆκ° ν ν¬κΈ° μΆλ ₯
Set<Person> set = new HashSet<>();
set.add(person1);
set.add(person2);
System.out.println("HashSet size : " + set.size()); // 2 (hashCode() μ€λ²λΌμ΄λ μ νμΌλ―λ‘ 2)
}
}
age, name
μ΄ κ°μ λ κ°μ²΄λ₯Ό μμ±νλ€.
==
λ‘ λΉκ΅νλ€.
false
κ° μΆλ ₯λλ€.
equals()
λ‘ λΉκ΅νλ€.
Person
ν΄λμ€μμ equals()
λ©μλλ₯Ό μ¬μ μνμμΌλ―λ‘, true
κ° μΆλ ₯λλ€.
- λ κ°μ²΄λ₯Ό
ArrayList
μ λ£κ³ μ¬μ΄μ¦λ₯Ό μΆλ ₯νλ€.
- λ κ°μ²΄λ₯Ό
HashSet
μ λ£κ³ μ¬μ΄μ¦λ₯Ό μΆλ ₯νλ€.
HashSet
μ λλ±ν κ°μ²΄λ κ°μ λν΄μ μ€λ³΅μ νμ©νμ§ μλλ€.κ·Έ μ΄μ κ° λ¬΄μμΌκΉ?
μ΄λ λμν΄μ μ½λ
κ° λ€λ₯΄κΈ° λλ¬Έμ΄λ€.
ν΄μ κ°μ μ¬μ©νλ 컬λ μ
λ€(HashMap, HashSet ..)
μ κ°μ²΄κ° λ
Όλ¦¬μ μΌλ‘ λλ±νμ§λ₯Ό νλ³ν λ μλμ κ°μ κ³Όμ μ κ±°μΉλ€.
- μ°μ λ κ°μ²΄μ ν΄μ μ½λλ₯Ό λΉκ΅νλ€.
- λ€μμΌλ‘
equals()
λ©μλμ λ¦¬ν΄ κ°μΌλ‘ μ΅μ’ νλ³νλ€.
μ¦, equals()
λ μ¬μ μ νμκΈ°μ true
λ‘ λμ€κ² μ§λ§, μ΄λ―Έ κ·Έ μ΄μ μ λ κ°μ²΄μ ν΄μ μ½λκ° λ€λ₯΄κΈ°μ λλ±νμ§ μλ€κ³ νλ³λ κ²μ΄λ€.
κ·ΈλΌ μ΄μ hashCode()
λ μ¬μ μλ₯Ό ν ν κ²°κ³Όκ° μ΄λ»κ² λμ€λμ§ μ΄ν΄λ³΄μ.
import java.util.Objects;
public class Person {
int age;
String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(age, name);
}
}
hashCode()λ₯Ό μ¬μ μν λͺ¨μ΅μ΄λ©°, Objects.hash()
λ©μλλ₯Ό μ¬μ©νμλ€.
public static int hash(Object... values) {
return Arrays.hashCode(values);
}
Objects ν΄λμ€μ hash() λ©μλλ μ΄λ κ² μ¬λ¬ νλΌλ―Έν°λ₯Ό λ°μ μ μλλ‘ κ΅¬νλμ΄ μλ€.
κ°λ³ μΈμλ₯Ό λ°μ λ°°μ΄μ λ§λ€κ³ μ²λ¦¬νκΈ° λλ¬Έμ, λ€μ μ€λ²ν€λ(λΆνμν λ°°μ΄ μμ± λΉμ©)κ° μμ μλ μλ€κ³ νλ€.
κ·Έλ¦¬κ³ μ΄λ₯Ό Arrays.hashCode()
λ©μλλ‘ λκΈ΄λ€.
public static int hashCode(Object a[]) {
if (a == null)
return 0;
int result = 1;
for (Object element : a)
result = 31 * result + (element == null ? 0 : element.hashCode());
return result;
}
λ€μ΄μ¨ νλΌλ―Έν°λ€μ λν΄μ ν΄μ μ°μ°μ μνν ν, ν΄μ μ½λλ₯Ό λ°ννλ€.
package equals;
import java.util.HashSet;
import java.util.Set;
public class test {
public static void main(String[] args) {
Person person1 = new Person(21, "sangho");
Person person2 = new Person(21, "sangho");
// hashCode μΆλ ₯
System.out.println("person1 hashCode : " + person1.hashCode()); // -909652454
System.out.println("person2 hashCode : " + person2.hashCode()); // -909652454
// HashSetμ μΆκ° ν ν¬κΈ° μΆλ ₯
Set<Person> set = new HashSet<>();
set.add(person1);
set.add(person2);
System.out.println("HashSet size : " + set.size());
}
}
ν μ€νΈ κ²°κ³Ό, λ κ°μ²΄μ ν΄μ μ½λκ° λμΌνκ³ κ·Έλ‘ μΈν΄ HashSetμλ 1κ°μ κ°μ²΄λ§ μ μμ μΌλ‘ λ€μ΄κ° μλ λͺ¨μ΅μ λ³Ό μ μλ€.
- HashSet, HashMapκ³Ό κ°μ ν΄μ κΈ°λ° μλ£κ΅¬μ‘°λ λ΄λΆμ μΌλ‘ hashCode()λ‘ λ¨Όμ ν보λ₯Ό μ’νκ³ equals()λ‘ μ΅μ’ λΉκ΅λ₯Ό νλ€.
equals()
λ§ μ¬μ μνκ³hashCode()
λ₯Ό μ¬μ μνμ§ μμΌλ©΄,equals()
κ° trueλΌλ μλ‘ λ€λ₯Έ λ²ν·μ μ μ₯λλ€.-> μ΄λ‘ μΈν΄ λ Όλ¦¬μ μΌλ‘ κ°μ κ°μ²΄κ° μ€λ³΅ μ½μ λλ λ¬Έμ κ° λ°μνκ² λλ€.
Java
μ κ·μ½μequals()
κ° trueλ©΄hashCode()
λ κ°μμΌ νλ€κ³ λͺ μνκ³ μλ€.μ΄ κ·μ½μ μ΄κΈ°λ©΄ ν΄μ κΈ°λ° μλ£κ΅¬μ‘°μμ μκΈ°μΉ λͺ»ν λμ(μ€λ³΅, κ²μ μ€ν¨ λ±)μ΄ λ°μν μ μλ€.
hashCode()
λ₯Ό μ¬μ μνκ² λλ©΄, κ°μ²΄μ μλ³ κ°μ΄ μλ -> ν΄λμ€μ λ
Όλ¦¬μ λλ±μ± κΈ°μ€μ λ§μΆ° ν΄μ μ½λλ₯Ό λ°ννκ² λλ€.
νμ§λ§ λλ‘λ JVM λ΄λΆ, λλ²κΉ , λ©λͺ¨λ¦¬ λΆμ λ±μ μ΄μ λ‘ κ°μ²΄ μ체μ μλ³ κ°(ν΄μ μ½λ)μ΄ νμν λκ° μλ€.
μ΄λ° κ²½μ°μμλ Javaμ identityHashCode()
λ©μλλ₯Ό μ΄μ©ν μ μλ€.
/**
* Returns the same hash code for the given object as
* would be returned by the default method hashCode(),
* whether or not the given object's class overrides
* hashCode().
* The hash code for the null reference is zero.
*
* @param x object for which the hashCode is to be calculated
* @return the hashCode
* @since 1.1
* @see Object#hashCode
* @see java.util.Objects#hashCode(Object)
*/
@IntrinsicCandidate
public static native int identityHashCode(Object x);
μ΄λ Object
ν΄λμ€μ hashCode() λ©μλμ λ‘μ§μ΄ λμΌνλ€. λν Objects
ν΄λμ€μ hashCode()μλ μ μ¬νλ°, λλ¬Έμ μ£Όμμ μ΄μ λν λ΄μ©μ΄ κΈ°μ¬λμ΄ μλ€.
public class test {
public static void main(String[] args) {
Person person1 = new Person(21, "sangho");
Person person2 = new Person(21, "sangho");
// μ¬μ μλ hashCode μΆλ ₯
System.out.println("person1 hashCode : " + person1.hashCode()); // -909652454
System.out.println("person2 hashCode : " + person2.hashCode()); // -909652454
// identityHashCode μΆλ ₯ (μ£Όμ κΈ°λ° ν΄μ κ°)
System.out.println("person1 identityHashCode : " + System.identityHashCode(person1)); // 1159190947
System.out.println("person2 identityHashCode : " + System.identityHashCode(person2)); // 925858445
}
}
ν
μ€νΈ κ²°κ³Ό, identityHashCode()
λ‘ μΆλ ₯ν λ κ°μ²΄μ ν΄μ μ½λλ λ€λ₯Έ κ²μ λ³Ό μ μλ€.
μ΄λ μ€λ²λΌμ΄λ©κ³Ό 무κ΄νκ², κ°μ²΄ μ체μ ν΄μ μ½λμ΄κΈ° λλ¬Έμ λͺ¨λ κ°μ²΄λ€μ λν΄μ νμ λ€λ₯Έ ν΄μ μ½λλ₯Ό λ°νν κ²μ 보μ₯νλ€.
π§π»βπ» νμ§λ§ κ³Όμ° λͺ¨λ κ°μ²΄λ€μ μλ‘ λ€λ₯Έ ν΄μ μ½λλ₯Ό κ°μ§κΉ? λ€μ κΈμ μ΄μ λν΄ μμλ³΄κ³ μ νλ€.
μ°Έκ³ ν λΈλ‘κ·Έ 1
μ°Έκ³ ν λΈλ‘κ·Έ 2
μ°Έκ³ ν λΈλ‘κ·Έ 3