โ๏ธ ๋๋์ด ์ฒซ ๋ฉํ ๋ง์ ์์ํ๋ค! ์ฌ๋ฌ ๋ํ๊ฐ ์ค๊ฐ์ง๋ง, ๊ฐ์ฅ ์์ ์์๋ ์ฐธ์กฐ ํ์ ๊ณผ ํด๋น ํ์ ์ด ๋ฉ๋ชจ๋ฆฌ ์์์ ์ด๋ป๊ฒ ์ด์ฉ๋๋์ง ๊ธฐ๋กํด๋ณด๋ ค๊ณ ํ๋ค. ์๋๋ฉด ๋ฉํ ๋๊ป์ ํด๋น ์ง๋ฌธ์ ์ฃผ์ จ๋๋ฐ ๋๋ต์ ์๋ชปํ๊ธฐ ๋๋ฌธ์ด๋ค. ๊ทธ๋์ ๋ค์ ๋์ง์ด๋ณด๋ ์๊ฐ์ ๊ฐ์ง๋ ค๊ณ ํ๋ค.
์ฐธ์กฐ ์๋ฃํ
์ฐธ์กฐ ์๋ฃํ์ ์์ ๊ณต๋ถํ ๊ธฐ๋ณธ ์๋ฃํ์ ์ ์ธํ ๋ชจ๋ ์๋ฃํ์ ๋ปํ๋ค. ๋ค๋ง String ํด๋์ค์ ๊ฒฝ์ฐ new ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ์ง ์๊ณ Literal ํํ๋ก ๋ณ์๊ฐ์ ์ ์ธ ํ ์ ์๊ณ , + ์ฐ์ฐ์ด ๊ฐ๋ฅํ ์ ์ผํ ์ฐธ์กฐ ์๋ฃํ์ด๋ค.
๋ชจ๋ ์ฐธ์กฐ ์๋ฃํ์ java.lang.Object ๋ฅผ ์์๋ฐ๋๋ค. ์ด๋ฌํ ์ฐธ์กฐ ์๋ฃํ์๋
- Annotation(@์ฃผ์)
- Arrays(๋ฐฐ์ด)
- Class
- Enum
- Interface
๊ฐ ์กด์ฌํ๋ค.
์ฐธ์กฐ ์๋ฃํ๊ณผ ๊ธฐ๋ณธ ์๋ฃํ์ ์ฐจ์ด๋ฅผ ์ดํด๋ณด์.
Reference Type | Primitive Type |
Unlimited number of reference types, as they are defined by the user. (๊ธฐ๋ณธ ์๋ฃํ์ ์ ์ธํ ๋ชจ๋ ์ฌ์ฉ์ ์ ์ ์๋ฃํ) |
Consists of boolean and numeric types: char, byte, short, int, long, float, and double. |
Memory location stores a reference to the data. (Stack ๋ฉ๋ชจ๋ฆฌ์ ํด๋น ๊ฐ์ ์ ์ฅํ๋ ๊ฒ์ด ์๋ Heap ๋ฉ๋ชจ๋ฆฌ์ ํ ๋น๋ ๊ฐ์ ์ฃผ์๋ฅผ ์ฐธ์กฐํ์ฌ ์ ์ฅํ๋ค.) |
Memory location stores actual data held by the primitive type. (Stack ๋ฉ๋ชจ๋ฆฌ์ ๊ธฐ๋ณธ ์๋ฃํ์ ๊ฐ์ด ๊ทธ๋๋ก ์ ์ฅ๋๋ค.) |
When a reference type is assigned to another reference type, both will point to the same object. (ํ ์ฐธ์กฐ ๊ฐ์ฒด๊ฐ ๋ค๋ฅธ ์ฐธ์กฐ ๊ฐ์ฒด์ ํ ๋น๋๋ฉด, ๋ ๋ค ๋์ผํ ์ฐธ์กฐ ๊ฐ์ฒด๋ฅผ ๋ฐ๋ผ๋ณธ๋ค.) |
When a value of a primitive is assigned to another variable of the same type, a copy is made. (ํ ๊ธฐ๋ณธ ์๋ฃํ์ด ๋ค๋ฅธ ๊ธฐ๋ณธ ์๋ฃํ์ ํ ๋นํ๋ฉด ๊ฐ์ ๊ธฐ๋ณธ ์๋ฃํ์ ๋ฐ๋ผ๋ณด๋ ๊ฒ์ด ์๋๋ผ ์๋ก์ด ๋ณต์ฌ๋ณธ์ด ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅ๋๋ค.) |
When an object is passed into a method, the called method can change the contents of the object passed to it but not the address of the object. (๊ฐ์ฒด๊ฐ ๋ฉ์๋์ ์ ๋ฌ๋๋ฉด ์ ๋ฌ๋ ๊ฐ์ฒด์ ๋ฐ์ดํฐ๋ ๋ฉ์๋์์ ๋ณ๊ฒฝ ํ ์ ์์ง๋ง, ์ฃผ์๋ ๋ณ๊ฒฝ ํ ์ ์๋ค.) |
When a primitive is passed into a method, only a copy of the primitive is passed. The called method does not have access to the original primitive value and therefore cannot change it. The called method can change the copied value. (๊ธฐ๋ณธ ์๋ฃํ์ด ๋ฉ์๋์ ์ ๋ฌ๋๋ฉด ๊ธฐ์กด์ ๊ธฐ๋ณธ ์๋ฃํ์ ํธ์ถํ ๋ฉ์๋๊ฐ ์ฐพ์ ์ ์๊ธฐ ๋๋ฌธ์ ๊ฐ์ ๋ณ๊ฒฝ ํ ์ ์์ง๋ง, ์ ๋ฌ๋ ๊ธฐ๋ณธ ์๋ฃํ์ ๊ธฐ์กด์ ๊ธฐ๋ณธ ์๋ฃํ์ ๋ณต์ฌ๋ณธ์ด๊ธฐ ๋๋ฌธ์ ํธ์ถ๋ ๋ฉ์๋์์ ๊ฐ์ ๋ณ๊ฒฝ ํ ์ ์๋ค.) |
.hashCode()
Returns a hash code value for the object. This method is supported for the benefit of hash tables such as those provided by HashMap.
- Java 8 Reference Docs
ํด๋น ๋ฉ์๋๋ java.lang.Object์ ์ํ๋ ๋ฉ์๋๋ก, ๋ชจ๋ ์ฐธ์กฐ ์๋ฃํ์ Object๋ฅผ ์์ ๋ฐ์ผ๋ ํด๋น ๋ฉ์๋๋ฅผ Override ํ ์ ์๋ค. ๋ํ, ํด๋น ๋ฉ์๋ ํธ์ถ ์ ๊ฐ์ฒด์ ํด์์ฝ๋๋ฅผ int ํ์ ์ผ๋ก ๋ฐํํ๋๋ฐ ์ด ๊ฐ์ ๋ฉ์๋๋ฅผ ํธ์ถํ ๊ฐ์ฒด๊ฐ ํ ๋น๋ ๋ฉ๋ชจ๋ฆฌ ์ฃผ์๊ฐ์ ํด์ํํด์ ๋ฐํํ ๊ฐ์ด๋ค.
public class HashCodeTest {
public String desc;
public HashCodeTest(String desc) {
this.desc = desc;
}
public static void main(String[] args) {
HashCodeTest test0 = new HashCodeTest("Constant Pool");
HashCodeTest test1 = new HashCodeTest(new String("Heap Memory"));
HashCodeTest test2 = test1;
System.out.println("test0.hashCode() = " + test0.hashCode());
System.out.println("test1.hashCode() = " + test1.hashCode());
System.out.println("test2.hashCode() = " + test2.hashCode());
}
}
/*
test0.hashCode() = 1878246837
test1.hashCode() = 929338653
test2.hashCode() = 929338653
*/
์ฝ๋๋ฅผ ํตํด ๊ฐ ๊ฐ์ฒด์ ํด์์ฝ๋ ๊ฐ์ ํ์ธํด๋ณด์. test0๊ณผ test1์ ๊ฐ์ HashCodeTest ํด๋์ค์ด์ง๋ง Heap Meory์๋ ๊ฐ์ ํ ๋น ๋ฐ๋๋ค. test2์ ๊ฒฝ์ฐ test1 ๊ฐ์ฒด๋ฅผ ํ ๋น ๋ฐ์ ์ด๊ธฐํ ๋์์ผ๋ test1๊ณผ ๊ฐ์ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ๊ณ ์๋ค.
ํ์ง๋ง, ์ด .hashCode() ๋ฉ์๋๋ String ํด๋์ค์ ํํด์ ๋ค๋ฅด๊ฒ ์ฌ์ ์ ๋์ด ์๋ค.
/**
* 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() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
String ํด๋์ค์ ์ฌ์ ์๋ .hashCode() ์ฝ๋ ๋ธ๋ญ์ด๋ค. ์ดํด๋ณด๋ฉด ๋ฌธ์์ด ํ ๊ธ์ ์ฉ ๊ฐ์ ธ์ ๊ฐ ์ ์์ ์์คํค ์ฝ๋๋ฅผ ๋ํ ์ต์ข ๊ฐ์ ๋ฐํํ๋ค. ๋๋ฌธ์ String ํด๋์ค์ ๊ฒฝ์ฐ ์ค๋ณต๋๋ ํด์์ฝ๋๊ฐ ์กด์ฌ ํ ์ ์๋ค. ํด๋น ๊ฒฝ์ฐ๋ ๋ฌธ์์ด์ด ๊ฐ์ ๋ ์กด์ฌํ๋ค.
public class StringHashCodeTest {
public static void main(String[] args) {
String test0 = "abc";
String test1 = "abc";
String test2 = "๊ฐ๋๋ค";
System.out.println("test0.hashCode() = " + test0.hashCode());
System.out.println("test1.hashCode() = " + test1.hashCode());
System.out.println("test2.hashCode() = " + test2.hashCode());
String test3 = new String("def");
String test4 = new String("def");
System.out.println("test3.hashCode() = " + test3.hashCode());
System.out.println("test4.hashCode() = " + test4.hashCode());
}
}
/*
test0.hashCode() = 96354
test1.hashCode() = 96354
test2.hashCode() = 43761996
test3.hashCode() = 99333
test4.hashCode() = 99333
*/
์์ ์ฝ๋๋ฅผ ๋ณด๋ฉด ์ ์ ์๋ฏ, test3๊ณผ test4๋ Heap Memory์ ๊ฐ๊ฐ ๋ค๋ฅด๊ฒ ํ ๋น๋์๋๋ฐ hashCode์ ๊ฐ์ด ๊ฐ์ ๊ฒ์ ํ์ธ ํ ์ ์๋ค. ์ด๋ ๋ ๊ฐ์ฒด์ ๊ฐ(๋ฌธ์์ด)์ด ๊ฐ๊ธฐ ๋๋ฌธ์ด๋ค.
.equals()
ํด๋น ๋ฉ์๋ ๋ํ java.lang.Object์ ์ํ ๋ฉ์๋๋ก, ๋ชจ๋ ์ฐธ์กฐ ์ฐจ๋ฃํ์ ํด๋น ๋ฉ์๋๋ฅผ ์์๋ฐ์ ์ฌ์ ์ ๊ฐ๋ฅํ๋ค. ๋๋ฌธ์ ๊ฐ ์ฐธ์กฐ ์๋ฃํ์์ ์ด๋ป๊ฒ ์ ์ํ๋๋์ ๋ฐ๋ผ ๊ธฐ์ค์ด ๋ฌ๋ผ์ง๋ค.
.equals() ๋ฉ์๋์ == ์ฐ์ฐ์๋ ์๋ก ๋น์ทํ์ง๋ง ๋ค๋ฅด๋ค. == ์ฐ์ฐ์๋ ๊ธฐ๋ณธ ์๋ฃํ ๊ฐ ์ฐ์ฐ์ ์ํ ํ ๋๋ ๊ฐ์ ๋น๊ตํ์ง๋ง, ์ฐธ์กฐ ์๋ฃํ ๊ฐ ์ฐ์ฐ์ ์ํ ํ ๋๋ ์ฐธ์กฐ ์๋ฃํ์ ์ฃผ์๊ฐ์ ๋น๊ตํ๋ค. String ํด๋์ค์์ .equals() ๋ฉ์๋๋ ํ ๊ธ์ ์ฉ ๋๋์ด ๋น๊ตํ ํ ๋ฌธ์์ด ๊ฐ์ด ๊ฐ์์ง ์๋์ง ๋ ผ๋ฆฌ๊ฐ์ ๋ฐํํ๋ค. ์ด๋ฅผ ์ด๋ค ํด๋์ค์์๋ ์ด๋ฆ์ด ๊ฐ์ผ๋ฉด ๊ฐ์ ๊ฐ์ฒด๋ก ๋ณผ ์ ์๊ฒ๋ ์ ์ ๋ด๋ฆด ์๋ ์๋ค.
String
The String class represents character strings. All string literals in Java programs, such as "abc", are implemented as instances of this class. Strings are constant; their values cannot be changed after they are created. String buffers support mutable strings. Because String objects are immutable they can be shared.
์์ ์ค๋ช ํ ๊ฒ ์ฒ๋ผ String ํด๋์ค๋ ๋ ๊ฐ์ง ๋ฐฉ์์ผ๋ก ์ ์ธ ํ ์ ์๋ค.
- new ์ฐ์ฐ์๋ฅผ ์ด์ฉํ ์ ์ธ → Heap Memory ์์ญ์ ํ ๋น
String str0 = new String("abcd");
String str1 = new String("abcd");
- Literal์ ์ด์ฉํ ์ ์ธ → Constant Pool(์์ ํ) ์์ญ์ ํ ๋น
String str2 = "abcd";
String str3 = "abcd";
์ด ๋ ๊ฐ์ง ๋ฐฉ์์ ํตํด ์ค๋ณต๋๋ ๋ฌธ์์ด 4๊ฐ๋ฅผ ๋ณ์๋ก ์ ์ธํ๋ค. ํ์ง๋ง ๋ฉ๋ชจ๋ฆฌ ์์ 4๊ฐ์ ๋ฌธ์์ด์ด ๋ชจ๋ ํ ๋น๋ ๊น? HashCode๋ฅผ ํตํด ์์๋ณด์.
public static void main(String[] args) {
String str0 = new String("abcd");
String str1 = new String("abcd");
String str2 = "abcd";
String str3 = "abcd";
System.out.println("str0.hashCode() = " + System.identityHashCode(str0));
System.out.println("str1.hashCode() = " + System.identityHashCode(str1));
System.out.println("str2.hashCode() = " + System.identityHashCode(str2));
System.out.println("str3.hashCode() = " + System.identityHashCode(str3));
}
/*
str0 = 1163157884
str1 = 1956725890
str2 = 356573597
str3 = 356573597
*/
์ ์ฝ๋๋ฅผ ๋ณด๋ฉด ๋ฉ๋ชจ๋ฆฌ ์์ 3๊ฐ์ ๋ฐ์ดํฐ๋ง ํ ๋น๋ ๊ฒ์ ์ ์ ์๋ค. ๊ทธ ์ด์ ๋ Literal๋ก ์ ์ธ๋ String ๋ณ์๋ Constant Pool์ ํ ๋น๋๋ฉฐ, String ํด๋์ค๋ ๋ด๋ถ์ ์ผ๋ก intern() ๋ฉ์๋๋ฅผ ์คํํด์ ๊ฐ์ฅ ๋จผ์ Constant Pool์ ํด๋น String ๊ฐ์ ์ฐพ์๋ณธ ํ ํด๋นํ๋ ๊ฐ์ด ์๋ค๋ฉด Constant Pool์ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ , ๊ทธ ์ฃผ์๊ฐ์ ๋ฐํํ๋ค.
์ด ๋, str0 ๋ณ์์ str1 ๋ณ์๊ฐ ๊ฐ์ ๊ฐ์๋ฐ ์ ๊ฐ๊ธฐ ๋ค๋ฅธ ๊ฐ์ฒด ์ฃผ์๋ฅผ ํ ๋น ๋ฐ์์๊น? ๊ทธ ์ด์ ๋ ๋ ๋ณ์๊ฐ new ์์ฑ์๋ฅผ ํตํด ์ ์ธ๋ ๊ฐ์ฒด์ด๊ธฐ ๋๋ฌธ์ Constant Pool์ด ์๋ Heap Memory ์ ๊ฐ๊ฐ ํ ๋น ๋์๊ธฐ ๋๋ฌธ์ด๋ค.
.intern()
ํด๋น ๋ฉ์๋๋ ์์ ์ธ๊ธํ ๊ฒ ์ฒ๋ผ Constant Pool์ ํด๋นํ๋ ๋ฌธ์์ด์ ์ฐพ๋๋ค. ํด๋น ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ ์ฝ๋๋ก ํ์ธํด๋ณด์.
public void stringInternMethod() {
String strA = new String("stringA");
String strAa = new String("stringA");
String strB = "stringA";
String strBa = "stringA";
String strBb = strB.intern();
String strC = new String("stringB");
String strCa = strC.intern();
String strCb = strC.intern();
System.out.println("strA = " + System.identityHashCode(strA));
System.out.println("strAa = " + System.identityHashCode(strAa));
System.out.println("strB = " + System.identityHashCode(strB));
System.out.println("strBa = " + System.identityHashCode(strBa));
System.out.println("strBb = " + System.identityHashCode(strBb));
System.out.println("strC = " + System.identityHashCode(strC));
System.out.println("strCa = " + System.identityHashCode(strCa));
System.out.println("strCb = " + System.identityHashCode(strCb));
}
/*
strA = 1163157884
strAa = 1956725890
strB = 356573597
strBa = 356573597
strBb = 356573597
strC = 1735600054
strCa = 21685669
strCb = 21685669
*/
์์ ์ฝ๋๋ฅผ ๋ณด๋ฉด strA ์ strAa ๋ ๊ฐ์ ๊ฐ์ด์ง๋ง ๋ค๋ฅธ ์ฃผ์๋ฅผ ์ถ๋ ฅํ๋ ๊ฑธ ํ์ธ ํ ์ ์๋๋ฐ, ์ด๋ ๋ ๋ณ์๊ฐ new ์์ฑ์๋ก ์ ์ธ๋์ด Heap Memory์ ๊ฐ๊ฐ ํ ๋น๋์๊ธฐ ๋๋ฌธ์ด๋ค.
๋ฐ๋ฉด, strB ๊ด๋ จ ๋ณ์๋ค์ ์ดํด๋ณด๋ฉด strB ๋ณ์๊ฐ Literal ๋ก ์ ์ธ๋์ด ํด๋น ๊ฐ์ Constant Pool์ ํ ๋นํ๋ค. ๊ทธ ํ strBa ๋ณ์๊ฐ Literal๋ก ์ ์ธ๋ ๋ String ํด๋์ค ๋ด๋ถ์ ์ผ๋ก intern()์ด ํธ์ถ๋์ด Constant Pool ์์ ํด๋น ๊ฐ์ ๋จผ์ ์ฐพ๋๋ค. ์ด ๋ ๋จผ์ ํ ๋น๋ strB์ ๊ฐ์ด ์กด์ฌํ๊ธฐ ๋๋ฌธ์ strBa๋ ํด๋น ์ฃผ์๋ฅผ ์ฐธ์กฐํ๋ค. strBb ๋ณ์ ๋ํ intern() ๋ฉ์๋๋ฅผ ํตํด ํด๋น ๊ฐ์ ๋ํ ์ฃผ์๋ฅผ ์ฐธ์กฐํ๋ค.
strC ๊ด๋ จ ๋ณ์๋ค์ ์ดํด๋ณด๋ฉด strC๋ new ์์ฑ์๋ก ์ ์ธ๋์๊ธฐ ๋๋ฌธ์ Heap Memory์ ํ ๋น๋์ด Constant Pool์ ์กด์ฌํ์ง ์๋๋ค. ๋๋ฌธ์ strCa ๋ณ์๋ intern() ๋ฉ์๋๊ฐ Constant Pool์์ ํด๋น ๊ฐ์ ์ฐพ๋ค๊ฐ ์กด์ฌํ์ง ์๋ ๊ฒ์ ํ์ธํ๊ณ Constant Pool์ ํด๋น ๊ฐ์ ์๋ก ํ ๋นํ๊ณ ๊ฐ์ ์ฃผ์๋ฅผ strCa ๋ณ์๊ฐ ์ฐธ์กฐํ๋ค. strCb ๋ณ์์ ๊ฒฝ์ฐ, strCa ๋ณ์๊ฐ ์ ์ธ๋๋ฉด์ Constant Pool์ ๋ง๋ค์ด ๋์ ๊ฐ์ ์ฐพ๊ณ ํด๋น ๊ฐ์ ์ฃผ์๋ฅผ ์ฐธ์กฐํ๋ค.
๊ณผ๊ฑฐ Java 7 ์ด์ ์๋ Perm ์์ญ์์ Constant Pool์ด ๊ด๋ฆฌ๋์๋๋ฐ, ๋ฉ๋ชจ๋ฆฌ ํ์ฅ ๋ถ๊ฐ๋ก ์ธํ OOM ๋ฐ์์ผ๋ก Java 7 ์ดํ๋ก Heap Memory์์ Constant Pool์ ๊ด๋ฆฌํ๋๋ก ๋ณ๊ฒฝ๋์๋ค. ์ฆ, ๋ฌธ์์ด์ด GC์ ์์ญ์ ํฌํจ๋์๋ค๋ ์๋ฏธ์ด๋ค.
'Programming > Java' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
F006 - Throwable, Exception, Error (0) | 2021.05.11 |
---|---|
F005 - Stack & Heap Memory (0) | 2021.05.08 |
F003 - Access Modifier (0) | 2021.05.06 |
F002 - Primitive Type (0) | 2021.05.06 |
F001 - psvm (0) | 2021.05.06 |