F-lab Java 1์ฃผ์ฐจ / Phase 4 / Unit 4.2 ๋ณธ๊ฒฉ ํ์ต ์๋ฃ
9-์น์ ๋ง์คํฐ ํ๋กฌํํธ ํ์์ผ๋ก ๊น์ด ํํค์น๋ค.์ ์ ์ง์: Unit 4.1 (JVM ๋ฐํ์ ๋ฐ์ดํฐ ์์ญ)
๋ค์ Phase: Phase 5 โ GC ๊น์ด ํ๊ธฐ์ด Unit์ ์๋ฏธ: ์๋ฐ ๋ฉด์ ์ ๊ฐ์ฅ ํท๊ฐ๋ฆฌ๋ ์์ญ.
"์๋ฐ๋ Pass by Reference ๊ฐ ์๋๊ฐ์?" ๋ผ๋ ํํ ์คํด์ ์ง์ค.
๋ฉ๋ชจ๋ฆฌ ๊ตฌ์กฐ ์์์ ๊ฐ/์ฐธ์กฐ ์ ๋ฌ์ ๋ณธ์ง์ ์ดํด.
๋น์ ์ด ์น๊ตฌ์๊ฒ ์ง ์ฃผ์ ๋ฅผ ์๋ ค์ฃผ๋ ค ํฉ๋๋ค.
Case 1 โ ์ฃผ์๋ฅผ ์ข ์ด์ ์ ์ด์ค (Pass by Value):
Case 2 โ ์น๊ตฌ๊ฐ ๊ทธ ์ฃผ์๋ก ๊ฐ์ ์ง์ ์น ํจ (์ฐธ์กฐ์ ํ์ฉ):
ํต์ฌ:
โ ์ด๊ฒ ์๋ฐ์ Pass by Value ์ ์ง์ค.
๋น์ ์ด TV ๋ฆฌ๋ชจ์ปจ์ ์น๊ตฌ์๊ฒ ๋น๋ ค์ค๋ค๊ณ ํฉ์๋ค.
์ง์ง ๋ฆฌ๋ชจ์ปจ์ ๋น๋ ค์ค = Pass by Reference (์๋ฐ์ ์์):
๋ฆฌ๋ชจ์ปจ ๋ณต์ฌ๋ณธ์ ๋ง๋ค์ด ์ค = Pass by Value (์๋ฐ ๋ฐฉ์):
ํต์ฌ:
โ ์๋ฐ์ ๋ฉ์๋ ํธ์ถ์ด ์ ํํ ์ด ๋ฐฉ์.
"์๋ฐ๋ ํญ์ Pass by Value ๋ค. ๋จ, ๊ฐ์ฒด์ ๊ฒฝ์ฐ '์ฐธ์กฐ์ ๊ฐ(์ฃผ์)' ์ด ๋ณต์ฌ๋๋ค."
์ฉ์ด ์ ๋ฆฌ:
ํํ ์คํด:
๋น์ ์ ๋ฆฌ:
| ๋น์ ์์ | ์๋ฐ ์ ์ฉ |
|---|---|
| ์ข ์ด (์ฃผ์) | ์ฐธ์กฐ ๋ณ์ |
| ์ข ์ด์ ๋ณต์ฌ๋ณธ | ์ฐธ์กฐ์ ๊ฐ ๋ณต์ฌ |
| ์ค์ ์ง | Heap ์ ๊ฐ์ฒด |
| ์ง ์น ํ๊ธฐ | ๊ฐ์ฒด ๋ณ๊ฒฝ |
| ์ข ์ด ์ฐข๊ธฐ | ์ฐธ์กฐ ๋ณ๊ฒฝ (์ธ๋ถ ๋ฌด๊ด) |
์ธ์ด๋ง๋ค ๋ฉ์๋ ํธ์ถ ์ ์ธ์๋ฅผ ์ ๋ฌํ๋ ๋ฐฉ์์ด ๋ค๋ฆ ๋๋ค:
void modify(int x) {
x = 100; // ๋ณต์ฌ๋ ๊ฐ๋ง ๋ณ๊ฒฝ
}
int n = 10;
modify(n);
printf("%d", n); // 10 (๋ณ๊ฒฝ ์ ๋จ)
& ์ฐธ์กฐ ๋งค๊ฐ๋ณ์void modify(int& x) { // & ์ฐธ์กฐ ๋งค๊ฐ๋ณ์
x = 100;
}
int n = 10;
modify(n);
cout << n; // 100 โ ๏ธ (๋ณ๊ฒฝ๋จ)
void modify(int* x) {
*x = 100;
}
int n = 10;
modify(&n);
printf("%d", n); // 100 (ํฌ์ธํฐ๋ก ๋ณ๊ฒฝ)
์๋ฐ ์ค๊ณ์๋ค์ ๊ฒฐ์ (1995):
"์๋ฐ๋ Pass by Value ๋ง ์ง์ํ๋ค. ๋จ, ๊ฐ์ฒด๋ ์ฐธ์กฐ๋ก ๋ค๋ฃฌ๋ค."
์?:
๊ทธ๋ฌ๋ ๋ง์ ๊ฐ๋ฐ์๊ฐ ํท๊ฐ๋ฆฝ๋๋ค:
public void modify(Customer c) {
c.setName("Bob"); // โ ๏ธ ๋ณ๊ฒฝ๋จ!
}
Customer alice = new Customer("Alice");
modify(alice);
System.out.println(alice.getName()); // "Bob" โ ๋ณ๊ฒฝ๋จ!
์คํด:
์ง์ค:
โ ์ด ํจ์ ์ ์ ํํ ์ดํดํ๋ ๊ฒ ์๋์ด ์๋ฐ ๊ฐ๋ฐ์์ ์ฐจ๋ณํ.
์๋ฐ ์ฐฝ์์ James Gosling์ ๋ช ์์ ์ผ๋ก ๋งํจ:
"Java has no pass by reference. Everything is pass by value."
("์๋ฐ๋ Pass by Reference๊ฐ ์๋ค. ๋ชจ๋ ๊ฒ์ด Pass by Value ๋ค.")
โ ์๋ฐ ๊ณต์ ์ ์ฅ.
๋ฉด์ ๋จ๊ณจ ์ง๋ฌธ:
"์๋ฐ๋ Pass by Value ์ธ๊ฐ Pass by Reference ์ธ๊ฐ?"
์๋ชป๋ ๋ต:
์ฌ๋ฐ๋ฅธ ๋ต:
โ ์ด ๋ต์ผ๋ก ์๋์ด ํ๋ณด ์ฐจ๋ณํ.
"Pass by Value ์ ์ง์ค์ 'JVM ๋ฉ๋ชจ๋ฆฌ ๊ตฌ์กฐ' ์์์ ๋ช ํํด์ง๋ค."
Stack์๋ ๋ณ์์ ๊ฐ (๊ธฐ๋ณธํ์ ๊ฐ ์์ฒด, ๊ฐ์ฒด๋ ์ฐธ์กฐ = ์ฃผ์), Heap์๋ ๊ฐ์ฒด. ๋ฉ์๋ ํธ์ถ ์ Stack์ ๊ฐ ์ด ๋ณต์ฌ๋์ด ์ Stack Frame ์ผ๋ก. ๊ทธ๋์ ๊ฐ์ฒด์ ๊ฒฝ์ฐ ๋ ์ฐธ์กฐ๊ฐ ๊ฐ์ Heap ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํด.
๋ฉ๋ชจ๋ฆฌ ๊ตฌ์กฐ (Unit 4.1) ๋ฅผ ๋ชจ๋ฅด๋ฉด Pass by Value ๋ ์ง์ง ์ดํด ๋ชป ํจ.
Pass by Value์ ์ง์ค์ ๋ชจ๋ฅด๋ฉด ๋ค์ํ ๋ฒ๊ทธ์ ํผ๋์ด ๋ฐ์ํฉ๋๋ค.
public class FareService {
public void applyDiscount(Fare fare, int rate) {
int discount = fare.getAmount() * rate / 100;
fare.setAmount(fare.getAmount() - discount);
}
}
Fare myFare = new Fare(50000);
fareService.applyDiscount(myFare, 20);
System.out.println(myFare.getAmount()); // 40000? 50000?
Pass by Value ์ง์ค ๋ชจ๋ฅด๋ฉด:
Pass by Value ์ง์ค ์๋ฉด:
myFare ์ ์ฐธ์กฐ ๊ฐ (์ฃผ์) ์ด ๋ณต์ฌ๋์ด ์ ๋ฌmyFare ์ fare) ๊ฐ ๊ฐ์ Heap ๊ฐ์ฒด ๊ฐ๋ฆฌํดpublic class FareService {
public void replace(Fare fare) {
fare = new Fare(10000); // ์ ๊ฐ์ฒด๋ก ๊ต์ฒด ์๋
}
}
Fare myFare = new Fare(50000);
fareService.replace(myFare);
System.out.println(myFare.getAmount()); // 50000? 10000?
Pass by Reference ๋ผ๊ณ ์คํดํ๋ฉด:
์ง์ค (Pass by Value):
fare = myFare ์ ์ฐธ์กฐ ๋ณต์ฌ๋ณธfare = new Fare(10000) โ ๋ฉ์๋ ์์ fare ๋ง ์ ๊ฐ์ฒด ๊ฐ๋ฆฌํดmyFare ๋ ์ฌ์ ํ 50000 ๊ฐ์ฒด ๊ฐ๋ฆฌํด๋ฉ๋ชจ๋ฆฌ ๋ณํ:
ํธ์ถ ์งํ:
[Stack โ main]
myFare โโโโโโ
โ
[Stack โ replace]
fare โโโโโโโโค
โ
[Heap] โผ
Fare(50000)
fare = new Fare(10000) ํ:
[Stack โ main]
myFare โโโโโโ
โ
[Stack โ replace]
fare โโโโโโโโ
โ
[Heap] โผ โผ
Fare(50000) Fare(10000) โ ์ ๊ฐ์ฒด
๋ฉ์๋ ์ข
๋ฃ ํ:
[Stack โ main]
myFare โโโโโโ
โ
[Heap] โผ
Fare(50000) Fare(10000)
โ GC ๋์ (์ฐธ์กฐ X)
โ ๊ฐ์ฒด ๊ต์ฒด๋ Pass by Value ๋ก ์ ๋จ.
// โ ์๋ชป๋ ์ฝ๋
public void increment(Integer count) {
count = count + 1; // ์ธ๋ถ ์ํฅ ์์
}
Integer myCount = 10;
increment(myCount);
System.out.println(myCount); // 10 (๋ณ๊ฒฝ ์ ๋จ)
์?:
Integer ๋ ๊ฐ์ฒด์ด์ง๋ง ๋ถ๋ณ (immutable)count = count + 1 โ ์ Integer ๊ฐ์ฒด ๋ง๋ค์ด ๋ฉ์๋ ์์ count์ ํ ๋นmyCount ๋ฌด๊ดํด๊ฒฐ โ ๋ฐํ ์ฌ์ฉ:
public Integer increment(Integer count) {
return count + 1;
}
Integer myCount = 10;
myCount = increment(myCount); // โ ๋ฐํ๋ฐ์์
System.out.println(myCount); // 11 โ
public void sort(List<Integer> list) {
list.sort(Comparator.naturalOrder()); // ์ ๋ ฌ
}
List<Integer> myList = new ArrayList<>(List.of(3, 1, 2));
sort(myList);
System.out.println(myList); // [3, 1, 2]? [1, 2, 3]?
์ง์ค: [1, 2, 3] โ ๏ธ
์?:
list ๋ myList ์ ์ฐธ์กฐ ๋ณต์ฌlist.sort() โ ๊ฐ์ฒด ๋ด๋ถ ๋ณ๊ฒฝโ ๊ฐ์ฒด์ ๋ฉ์๋๋ก ๋ณ๊ฒฝํ๋ฉด ์ธ๋ถ ์ํฅ.
public void process(List<Integer> list) {
list.add(100); // ์ธ๋ถ ์ํฅ โ
list = new ArrayList<>(); // ์ฌํ ๋น
list.add(200); // ์ธ๋ถ ์ํฅ X
}
List<Integer> myList = new ArrayList<>(List.of(1, 2, 3));
process(myList);
System.out.println(myList); // ?
๋ต: [1, 2, 3, 100]
์?:
1. list.add(100) โ ๊ฐ์ ๊ฐ์ฒด ๋ณ๊ฒฝ โ myList ์๋ 100 ์ถ๊ฐ
2. list = new ArrayList<>() โ ๋ฉ์๋ ์์ list๋ง ์ ๊ฐ์ฒด ๊ฐ๋ฆฌํด, myList ๋ฌด๊ด
3. list.add(200) โ ์ ๊ฐ์ฒด์๋ง ์ถ๊ฐ, myList ๋ฌด๊ด
โ ์ฌํ ๋น ์ ํ์ ๋์์ด ์์ ํ ๋ค๋ฆ.
"์๋ฐ๋ Pass by Value ์ธ๊ฐ์ Pass by Reference ์ธ๊ฐ์?"
๋ต ๋ชปํจ ๋๋ ํท๊ฐ๋ฆผ:
์ ๋ตํจ:
์๋ฐ์ ๋ชจ๋ ๋ฉ์๋ ํธ์ถ ์ ๋ค์ ๊ท์น์ ๋ฐ๋ฆ ๋๋ค:
public void modify(int x) {
x = 100;
}
int n = 10;
modify(n);
System.out.println(n); // 10
๋ฉ๋ชจ๋ฆฌ:
ํธ์ถ ์งํ:
[Stack โ main]
n = 10
[Stack โ modify]
x = 10 โ ๊ฐ ๋ณต์ฌ
x = 100 ํ:
[Stack โ main]
n = 10 โ ๊ทธ๋๋ก
[Stack โ modify]
x = 100 โ ๋ฉ์๋ ์๋ง ๋ณ๊ฒฝ
โ ๊ฐ ๋ณต์ฌ. ์ธ๋ถ ๋ฌด๊ด.
public void modify(Customer c) {
c.setName("Bob"); // ๊ฐ์ฒด ๋ด๋ถ ๋ณ๊ฒฝ
}
Customer alice = new Customer("Alice");
modify(alice);
System.out.println(alice.getName()); // "Bob"
๋ฉ๋ชจ๋ฆฌ:
ํธ์ถ ์งํ:
[Stack โ main]
alice (์ฐธ์กฐ = 0x1234)
โ
[Stack โ modify] โ
c (์ฐธ์กฐ = 0x1234) โโค โ ๊ฐ์ ์ฃผ์
โ
[Heap] โผ
Customer ("Alice") ์ฃผ์ 0x1234
c.setName("Bob") ํ:
[Stack โ main]
alice (์ฐธ์กฐ = 0x1234)
โ
[Stack โ modify] โ
c (์ฐธ์กฐ = 0x1234) โโค
โ
[Heap] โผ
Customer ("Bob") โ ๊ฐ์ฒด ์์ฒด ๋ณ๊ฒฝ
โ ์ฐธ์กฐ์ ๊ฐ(์ฃผ์) ์ด ๋ณต์ฌ. ๊ฐ์ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํค๋ฏ๋ก ๋ณ๊ฒฝ ๊ณต์ .
public void modify(Customer c) {
c = new Customer("Bob"); // ์ฌํ ๋น
}
Customer alice = new Customer("Alice");
modify(alice);
System.out.println(alice.getName()); // "Alice" (๋ณ๊ฒฝ ์ ๋จ)
๋ฉ๋ชจ๋ฆฌ:
ํธ์ถ ์งํ:
[Stack โ main]
alice (์ฐธ์กฐ = 0x1234)
โ
[Stack โ modify] โ
c (์ฐธ์กฐ = 0x1234) โโค
โ
[Heap] โผ
Customer ("Alice") ์ฃผ์ 0x1234
c = new Customer("Bob") ํ:
[Stack โ main]
alice (์ฐธ์กฐ = 0x1234)
โ
[Stack โ modify]
c (์ฐธ์กฐ = 0x5678) โ ์ ์ฃผ์
โ
[Heap] โผ โผ
Customer ("Alice") Customer ("Bob") ์ฃผ์ 0x5678
โ c๋ง ๊ฐ๋ฆฌํด
๋ฉ์๋ ์ข
๋ฃ ํ:
[Stack โ main]
alice (์ฐธ์กฐ = 0x1234)
โ
[Heap] โผ โผ
Customer ("Alice") Customer ("Bob")
โ GC ๋์ (์ฐธ์กฐ X)
โ ์ฌํ ๋น = ๋ฉ์๋ ์์ ๋ณ์๋ง ๋ณ๊ฒฝ. ์ธ๋ถ ๋ฌด๊ด.
| ์ผ์ด์ค | ๋ฉ์๋ ์ ๋ณ๊ฒฝ | ์ธ๋ถ ์ํฅ |
|---|---|---|
| ๊ธฐ๋ณธํ ๋ณ๊ฒฝ | ๋ฉ์๋ ์๋ง ๋ณ๊ฒฝ | X |
๊ฐ์ฒด ๋ฉ์๋ ํธ์ถ (c.setName()) | ๊ฐ์ฒด ๋ด๋ถ ๋ณ๊ฒฝ | O โ ๏ธ |
๊ฐ์ฒด ์ฌํ ๋น (c = new ...) | ๋ฉ์๋ ์๋ง ์ ๊ฐ์ฒด ๊ฐ๋ฆฌํด | X |
| ๋ถ๋ณ ๊ฐ์ฒด ๋ณ๊ฒฝ ์๋ (Integer + 1) | ์ ๊ฐ์ฒด ๋ง๋ค์ด ์ฌํ ๋น | X |
โ ์ด ํ๋ฅผ ๊ทธ๋ฆด ์ ์์ผ๋ฉด ์๋ฐ ๋ฉด์ OK.
Java 8 ๋๋ค๋ ๊ฐ์ ๊ท์น:
public void process(Function<Integer, Integer> func) {
int result = func.apply(10);
}
process(x -> x * 2); // ๋๋ค ์์ฒด๊ฐ ๊ฐ์ฒด๋ก ์ ๋ฌ
โ ๋๋ค๋ ๊ฐ์ฒด โ ์ฐธ์กฐ์ ๊ฐ ๋ณต์ฌ.
๊ธฐ๋ณธํ์ ๋ฉ์๋์์ ๋ณ๊ฒฝํ๋ ค๋ฉด:
// โ ์ ๋จ
public void increment(int x) {
x++;
}
// โ
Wrapper ์ฌ์ฉ
public void increment(int[] arr) {
arr[0]++; // ๋ฐฐ์ด์ ๊ฐ์ฒด
}
int[] count = {0};
increment(count);
System.out.println(count[0]); // 1
// โ
๋๋ AtomicInteger
public void increment(AtomicInteger count) {
count.incrementAndGet();
}
AtomicInteger count = new AtomicInteger(0);
increment(count);
System.out.println(count.get()); // 1
โ ๊ฐ์ฒด๋ก ๊ฐ์ธ์ ์ฐธ์กฐ์ ๊ฐ ๋ณต์ฌ ํ์ฉ.
๊ทธ๋ฌ๋ โ ๋ณดํต ๋ฐํ ์ฌ์ฉ ์ด ๋ ๊น๋:
public int increment(int x) {
return x + 1;
}
int n = 10;
n = increment(n);
์ง๋ฌธ: "์๋ฐ๋ Pass by Value ์ธ๊ฐ Pass by Reference ์ธ๊ฐ?"
๋ต๋ณ ๊ตฌ์กฐ:
๊ฒฐ๋ก (10์ด): "์๋ฐ๋ ํญ์ Pass by Value ์ ๋๋ค."
๊ธฐ๋ณธํ ์ค๋ช (30์ด):
๊ฐ์ฒด ์ค๋ช (1๋ถ):
๋ฉ๋ชจ๋ฆฌ ๊ทธ๋ฆผ (1๋ถ):
ํํ ์คํด (30์ด):
์ค์ฉ์ ํจ์ (1๋ถ):
โ ์ด ๊ตฌ์กฐ๋ฉด ์๋์ด ๋ต๋ณ.
public class Demo {
public static void main(String[] args) {
int x = 10;
Customer c = new Customer("Alice");
process(x, c);
System.out.println(x); // ?
System.out.println(c.getName()); // ?
}
public static void process(int n, Customer cust) {
n = 100;
cust.setName("Bob");
}
}
Step 1 โ main ์์:
[Method Area]
Demo ํด๋์ค ์ ๋ณด, Customer ํด๋์ค ์ ๋ณด
[Heap]
(์์ง ๋น์ด์์)
[Stack โ main]
args (์ฐธ์กฐ)
x (์์ง ๋ฏธํ ๋น)
c (์์ง ๋ฏธํ ๋น)
Step 2 โ int x = 10:
[Stack โ main]
args
x = 10 โ Stack ์ ์ง์ ๊ฐ ์ ์ฅ
c
Step 3 โ Customer c = new Customer("Alice"):
[Heap]
Customer ์ธ์คํด์ค ("Alice") ์ฃผ์ 0x1234
โ
[Stack โ main]
args
x = 10
c = 0x1234 โ ์ฐธ์กฐ (์ฃผ์) ์ ์ฅ
Step 4 โ process(x, c) ํธ์ถ:
[Heap]
Customer ("Alice") 0x1234
โ
โ
[Stack โ main]
args
x = 10
c = 0x1234 โโโ
โ
[Stack โ process] (์ Frame)
n = 10 โ x์ ๊ฐ ๋ณต์ฌ
cust = 0x1234 โโโ โ c์ ๊ฐ(์ฃผ์) ๋ณต์ฌ
Step 5 โ n = 100:
[Stack โ main]
x = 10 โ ๊ทธ๋๋ก
[Stack โ process]
n = 100 โ ๋ฉ์๋ ์๋ง ๋ณ๊ฒฝ
Step 6 โ cust.setName("Bob"):
[Heap]
Customer ("Bob") โ ๊ฐ์ฒด ์์ฒด ๋ณ๊ฒฝ
โ โ
โ โ
[Stack โ main]
c = 0x1234 โโโ
โ
[Stack โ process]
n = 100
cust = 0x1234 โโโ
โ ๊ฐ์ ์ฃผ์ ๊ฐ๋ฆฌํด
Step 7 โ process ์ข ๋ฃ:
[Stack โ main]
c = 0x1234 โโโ
โ
โผ
[Heap]
Customer ("Bob") โ ๋ณ๊ฒฝ๋จ
(process Frame ์ ๊ฑฐ)
์ต์ข ์ถ๋ ฅ:
System.out.println(x) โ 10 (๋ฉ์๋ ์ ๋ณ๊ฒฝ ๋ฌด๊ด)System.out.println(c.getName()) โ "Bob" (๊ฐ์ฒด ๋ณ๊ฒฝ๋จ)์๋ฐ์ ์ฐธ์กฐ์ C์ ํฌ์ธํฐ์ ์ฐจ์ด:
| C ํฌ์ธํฐ | Java ์ฐธ์กฐ | |
|---|---|---|
| ๋ช ์์ | int* p | ๋ชจ๋ ๊ฐ์ฒด ๋ณ์ |
| ์ฐ์ ์ฐ์ฐ | ๊ฐ๋ฅ (p++) | ๋ถ๊ฐ |
| null ์ฒดํฌ | ์๋ X | ์๋ (NPE) |
| ๋ฉ๋ชจ๋ฆฌ ์์ | ์ํ | ์์ |
| ์ง์ ์ฃผ์ ๋ณด๊ธฐ | printf("%p", p) | ๋ถ๊ฐ |
โ ์๋ฐ ์ฐธ์กฐ = "์์ ํ ํฌ์ธํฐ".
== vs .equals() ์ ์ง์ง ์๋ฏธ โญString a = new String("hello");
String b = new String("hello");
a == b; // false
a.equals(b); // true
์?:
== ๋ ์ฐธ์กฐ์ ๊ฐ(์ฃผ์) ๋น๊ต.equals() ๋ ๊ฐ์ฒด ๋ด์ฉ ๋น๊ต๋ฉ๋ชจ๋ฆฌ:
[Heap]
String ("hello") ์ฃผ์ 0x1111
String ("hello") ์ฃผ์ 0x2222
[Stack]
a = 0x1111
b = 0x2222
a == b โ 0x1111 == 0x2222 โ falsea.equals(b) โ ๋ด์ฉ "hello" == "hello" โ true๊ธฐ๋ณธํ ๋น๊ต:
int x = 10;
int y = 10;
x == y; // true (๊ฐ ๋น๊ต)
โ ๊ธฐ๋ณธํ์ == ๋ ๊ฐ, ๊ฐ์ฒด์ == ๋ ์ฐธ์กฐ.
Integer a = 100;
Integer b = 100;
a == b; // true โ ๏ธ
Integer c = 200;
Integer d = 200;
c == d; // false โ ๏ธ
์?:
-128 ~ 127 ๋ฒ์ Integer ๋ฅผ ์บ์ ํจํด๊ฒฐ: ํญ์ equals() ์ฌ์ฉ:
a.equals(b); // true (์์ )
c.equals(d); // true
โ ์๋ฐ ๋ฉด์ ํจ์ ์ง๋ฌธ.
String a = "hello";
String b = "hello";
a == b; // true!
String c = new String("hello");
a == c; // false
์?:
"hello" ๋ String Pool (Method Area ๋๋ Heap์ ํน๋ณ ์์ญ) ์ ์ ์ฅnew String() โ Heap ์ ์ ๊ฐ์ฒด โ ๋ค๋ฅธ ์ฐธ์กฐโ Unit 6์์ ์์ธํ.
@Service
public class FareUpdateService {
public void applyDiscount(Fare fare, int rate) {
int discount = fare.getAmount() * rate / 100;
fare.setAmount(fare.getAmount() - discount);
// โ ๏ธ ์ธ๋ถ fare ๋ ๋ณ๊ฒฝ๋จ
}
}
@Service
public class CheckoutService {
private final FareUpdateService updateService;
public Fare checkout(Long fareId) {
Fare fare = fareRepository.findById(fareId).orElseThrow();
// ์๋: ์์ ํ ์ธ ์ ์ฉ ํ ์์์ฆ ์ถ๋ ฅ
updateService.applyDiscount(fare, 20);
return fare;
// โ ๏ธ DB ์ fare ๋ ์ํฅ?
// โ JPA ์์์ฑ ์ปจํ
์คํธ์ ์ํด ๋ณ๊ฒฝ ๊ฐ์ง โ DB UPDATE
}
}
๋ถ์ํจ๊ณผ ์ํ:
fare ๋ ์์์ฑ ์ปจํ
์คํธ์ ์์applyDiscount ๊ฐ ๊ฐ์ฒด ๋ณ๊ฒฝํด๊ฒฐ:
public Fare calculateDiscountedFare(Fare fare, int rate) {
int discountedAmount = fare.getAmount() * (100 - rate) / 100;
return new Fare(discountedAmount); // ์ ๊ฐ์ฒด ๋ฐํ
}
โ ๋ถ๋ณ์ฑ + ๋ฐํ ์ ํ์ฉ.
public class ArrayDemo {
public void modify(int[] arr) {
arr[0] = 100; // ์ธ๋ถ ์ํฅ โ
arr = new int[]{1, 2}; // ์ธ๋ถ ์ํฅ X
}
public static void main(String[] args) {
int[] myArr = {10, 20, 30};
new ArrayDemo().modify(myArr);
System.out.println(Arrays.toString(myArr));
// [100, 20, 30] โ ๏ธ
}
}
์?:
arr[0] = 100 โ Heap ์ ๋ฐฐ์ด ๊ฐ์ฒด ๋ด๋ถ ๋ณ๊ฒฝ โ ์ธ๋ถ์์ ๋ณด์arr = new int[]{...} โ ๋ฉ์๋ ์๋ง ์ ๋ฐฐ์ด ๊ฐ๋ฆฌํด๋ฉ๋ชจ๋ฆฌ:
ํธ์ถ ์งํ:
[Heap]
int[] {10, 20, 30} ์ฃผ์ 0x1234
โ
[Stack โ main]
myArr = 0x1234 โโโ
โ
[Stack โ modify] โ
arr = 0x1234 โโโโโโ
arr[0] = 100 ํ:
[Heap]
int[] {100, 20, 30} โ ๋ณ๊ฒฝ
arr = new int[]{1, 2} ํ:
[Heap]
int[] {100, 20, 30} โ myArr ๊ฐ ๊ฐ๋ฆฌํด
int[] {1, 2} ์ฃผ์ 0x5678 โ arr ๋ง ๊ฐ๋ฆฌํด
public void process(List<Integer> list) {
list.add(100); // ์ธ๋ถ ์ํฅ โ
list.remove(0); // ์ธ๋ถ ์ํฅ โ
list.set(0, 999); // ์ธ๋ถ ์ํฅ โ
list = new ArrayList<>(); // ์ธ๋ถ ์ํฅ X
list.add(200); // ์ธ๋ถ ์ํฅ X
}
List<Integer> myList = new ArrayList<>(List.of(1, 2, 3));
process(myList);
System.out.println(myList); // ?
์งํ ๋จ๊ณ:
1. ์์: [1, 2, 3]
2. add(100) โ [1, 2, 3, 100] (์ธ๋ถ ์ํฅ)
3. remove(0) โ [2, 3, 100] (์ธ๋ถ ์ํฅ)
4. set(0, 999) โ [999, 3, 100] (์ธ๋ถ ์ํฅ)
5. list = new ArrayList<>() โ ๋ฉ์๋ ์์ list๋ง, myList ๊ทธ๋๋ก
6. list.add(200) โ ์ ๊ฐ์ฒด์๋ง, myList ๋ฌด๊ด
์ต์ข
: [999, 3, 100]
public void process(String s) {
s = s + "!"; // ์ String ๊ฐ์ฒด ์์ฑ
}
String myStr = "hello";
process(myStr);
System.out.println(myStr); // "hello"
์ ๋ณ๊ฒฝ ์ ๋จ?:
s + "!" โ ์ String ๊ฐ์ฒด ์์ฑ, s ์ ์ฌํ ๋น๋ถ๋ณ ๊ฐ์ฒด์ ์ฅ์ :
ILIC ์ ์ฉ:
public class FareSnapshot { // ๋ถ๋ณ
private final Long id;
private final int amount;
private final FareStatus status;
// setter ์์
// ๋ณ๊ฒฝ ์ ์ ๊ฐ์ฒด ๋ฐํ
public FareSnapshot withAmount(int newAmount) {
return new FareSnapshot(id, newAmount, status);
}
}
โ ๋ถ๋ณ ๊ฐ์ฒด๋ก ๋ถ์ํจ๊ณผ ๋ฐฉ์ง.
public class Counter {
private int value;
public Counter(int value) { this.value = value; }
public void increment() { value++; }
public int getValue() { return value; }
}
public void process(Counter counter) {
counter.increment();
}
Counter myCounter = new Counter(0);
process(myCounter);
process(myCounter);
process(myCounter);
System.out.println(myCounter.getValue()); // 3
ํต์ฌ:
increment() ํธ์ถ โ ๊ฐ์ฒด ๋ด๋ถ ๋ณ๊ฒฝ โ ์ธ๋ถ์์ ๋ณด์โ Wrapper ํจํด.
๋ ๋์ ๋ฐฉ๋ฒ โ AtomicInteger (์ค๋ ๋ ์์ ):
AtomicInteger counter = new AtomicInteger(0);
public void process(AtomicInteger counter) {
counter.incrementAndGet();
}
public class Order {
private final List<Item> items;
public Order(List<Item> items) {
// ๋ฐฉ์ด์ ๋ณต์ฌ โ ์ธ๋ถ ๋ณ๊ฒฝ์ผ๋ก๋ถํฐ ๋ณดํธ
this.items = new ArrayList<>(items);
}
public List<Item> getItems() {
// ๋ฐฉ์ด์ ๋ณต์ฌ โ ์ธ๋ถ์์ ๋ณ๊ฒฝ ๋ชปํ๊ฒ
return new ArrayList<>(items);
// ๋๋ Collections.unmodifiableList(items);
}
}
List<Item> myItems = new ArrayList<>();
myItems.add(new Item("A"));
Order order = new Order(myItems);
myItems.add(new Item("B")); // ์ธ๋ถ์์ ์ถ๊ฐ
order.getItems(); // [Item("A")] โ ์ํฅ ์์ โ
์?:
this.items = items ํ๋ฉด ์ธ๋ถ ๋ณ๊ฒฝ์ ์ํฅ ๋ฐ์new ArrayList<>(items) ๋ก ์ ๋ฆฌ์คํธ ์์ฑโ Effective Java ์ ๊ถ์ฅ ํจํด.
Q: "๊ฐ์ฒด๋ฅผ ๋ฉ์๋์ ๋๊ธฐ๋ฉด?"
A: "Pass by Reference ์
๋๋ค" โ
์ ๋ต: Pass by Value โ ์ฐธ์กฐ์ ๊ฐ ๋ณต์ฌ.
== ๋ก ๊ฐ์ฒด ๋น๊ตString a = new String("hello");
String b = new String("hello");
if (a == b) { ... } // โ false ๋์ด
ํด๊ฒฐ: .equals() ์ฌ์ฉ:
if (a.equals(b)) { ... } // โ
โ ๊ฐ์ฒด ๋น๊ต๋ ํญ์ equals().
@Service
public class FareService {
public void process(Fare fare) {
fare.setStatus(FareStatus.PROCESSING);
// โ ๏ธ ํธ์ถ์์ fare ๋ ์ํฅ
}
}
Fare myFare = repository.findById(1L).orElseThrow();
service.process(myFare);
// myFare ์ status ๋ ๋ณ๊ฒฝ๋จ
// ํธ๋์ญ์
์์ด๋ฉด DB UPDATE๊น์ง!
ํด๊ฒฐ: ์๋๋ฅผ ๋ช ํํ ๋๋ ๋ถ๋ณ ๊ฐ์ฒด:
public Fare process(Fare fare) {
return new Fare(fare.getId(), fare.getAmount(), FareStatus.PROCESSING);
}
Integer a = 200;
Integer b = 200;
if (a == b) { ... } // โ ๏ธ false (์บ์ ๋ฒ์ ๋ฐ)
ํด๊ฒฐ: ํญ์ equals():
if (a.equals(b)) { ... } // โ
๋๋ ๊ธฐ๋ณธํ ์ฌ์ฉ:
int a = 200;
int b = 200;
if (a == b) { ... } // โ
true
public void process(int count) {
count = count + 1; // โ ์๋ฏธ X
// count ๋ณ๊ฒฝํด๋ ์ธ๋ถ ์ํฅ ์์
}
ํด๊ฒฐ: ๋ฐํ:
public int process(int count) {
return count + 1;
}
public void clear(List<Integer> list) {
list = new ArrayList<>(); // โ ์ธ๋ถ list ์ ๋น์์ง
}
ํด๊ฒฐ:
public void clear(List<Integer> list) {
list.clear(); // โ
๊ฐ์ฒด ๋ด๋ถ ๋ฉ์๋ ํธ์ถ
}
public class Order {
private List<Item> items;
public Order(List<Item> items) {
this.items = items; // โ ์ธ๋ถ list ์ ๊ณต์
}
public List<Item> getItems() {
return items; // โ ์ธ๋ถ์์ ๋ณ๊ฒฝ ๊ฐ๋ฅ
}
}
ํด๊ฒฐ: ๋ฐฉ์ด์ ๋ณต์ฌ:
this.items = new ArrayList<>(items);
return Collections.unmodifiableList(items);
[Unit 4.1: JVM ๋ฐํ์ ๋ฐ์ดํฐ ์์ญ]
โ
[Unit 4.2: Pass by Value] โ ์ง๊ธ ์ฌ๊ธฐ โ
โ
[Phase 4 ์๋ฃ]
โ Phase 4 ์๋ฃ. ๋ค์์ Phase 5 GC.
| ํ์ต | Pass by Value ๊ด์ |
|---|---|
| Unit 1.1 (๊ฐ์ฒด์งํฅ) | ๊ฐ์ฒด๋ ์ฐธ์กฐ๋ก ๋ค๋ฃธ (Pass by Value) |
| Unit 2.1 (๋ฉ์๋) | ๋ฉ์๋ ํธ์ถ ์ ์ธ์ ๋ณต์ฌ |
| Unit 2.4 (๋คํ์ฑ) | ์ฐธ์กฐ์ ํ์ ๊ณผ ์ค์ ๊ฐ์ฒด ๊ตฌ๋ถ |
| Unit 4.1 (JVM ๋ฉ๋ชจ๋ฆฌ) | Stack/Heap ์์์ ๋์ |
โ Pass by Value ๋ ๋ฉ๋ชจ๋ฆฌ ๋ชจ๋ธ ์์์ ์ดํด.
3์ฃผ์ฐจ (์ ๋ค๋ฆญ/๋๋ค):
4์ฃผ์ฐจ (๋์์ฑ):
5์ฃผ์ฐจ (Spring DI):
11-12์ฃผ์ฐจ (JPA):
Effective Java ์ ๊ถ์ฅ:
| ์ง๋ฌธ | ์ด Unit์์์ ๋ต |
|---|---|
| "์๋ฐ๋ Pass by Value? Reference?" | ํญ์ Pass by Value, ๊ฐ์ฒด๋ ์ฐธ์กฐ์ ๊ฐ ๋ณต์ฌ |
| "๊ฐ์ฒด๋ฅผ ๋ฉ์๋์์ ๋ณ๊ฒฝ ์ ์ธ๋ถ ์ํฅ?" | ๊ฐ์ฒด ๋ด๋ถ ๋ณ๊ฒฝ ์ ์ํฅ, ์ฌํ ๋น์ X |
| "== ์ equals() ์ฐจ์ด?" | == ๋ ์ฐธ์กฐ (๊ฐ์ฒด) ๋๋ ๊ฐ (๊ธฐ๋ณธํ) ๋น๊ต, equals() ๋ ๋ด์ฉ |
| "Integer ๋น๊ต ํจ์ ?" | -128~127 ์บ์, ๊ทธ ์ธ ๋ค๋ฅธ ๊ฐ์ฒด |
| "๋ฐฉ์ด์ ๋ณต์ฌ๊ฐ ๋ญ๊ฐ์?" | Pass by Value ์ ๋ถ์ํจ๊ณผ ๋ฐฉ์ง |
1๏ธโฃ ์๋ฐ๋ ํญ์ Pass by Value ๋ค โ ๊ฐ์ฒด๋ ๋ง์ฐฌ๊ฐ์ง.
James Gosling ๋ ๋ช ์: "Java has no pass by reference." ๊ธฐ๋ณธํ์ ๊ฐ ์์ฒด ๋ณต์ฌ, ๊ฐ์ฒด๋ ์ฐธ์กฐ์ ๊ฐ(์ฃผ์) ๋ณต์ฌ. ๋ ๋ค Stack ์ ๊ฐ์ ์ Stack Frame ์ ๋ณต์ฌํ๋ ๋ฐฉ์. ์ด ์ฌ์ค์ JVM ๋ฉ๋ชจ๋ฆฌ ๋ชจ๋ธ (Unit 4.1) ์์์ ๋ช ํํด์ง๋ค.
2๏ธโฃ ๊ฐ์ฒด ๋ฉ์๋ ํธ์ถ vs ์ฌํ ๋น โ ๊ฒฐ๊ณผ๊ฐ ์์ ํ ๋ค๋ฅด๋ค.
๋ฉ์๋์์
c.setName("Bob")๊ฐ์ ๊ฐ์ฒด ๋ด๋ถ ๋ณ๊ฒฝ ์ ์ธ๋ถ์ ์ํฅ โญ (๊ฐ์ Heap ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํค๋ ๋ ์ฐธ์กฐ์ด๊ธฐ ๋๋ฌธ). ๋ฐ๋ฉดc = new Customer()๊ฐ์ ์ฌํ ๋น ์ ๋ฉ์๋ ์์ ๋ณ์๋ง ์ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌ์ผ ์ธ๋ถ ๋ฌด๊ด. ์ด ๊ตฌ๋ถ์ด ์๋ฐ ๋ฉด์ ์ ๊ฐ์ฅ ํท๊ฐ๋ฆฌ๋ ์์ญ.3๏ธโฃ ๋ถ๋ณ ๊ฐ์ฒด์ ๋ฐฉ์ด์ ๋ณต์ฌ๋ก ๋ถ์ํจ๊ณผ๋ฅผ ํต์ ํ๋ผ.
Pass by Value ์ ๊ฐ์ฒด ๋ณ๊ฒฝ ์ํฅ์ ๋ฐฉ์งํ๋ ค๋ฉด: โ ๋ถ๋ณ ๊ฐ์ฒด ์ฌ์ฉ (String, Integer ์ฒ๋ผ ๋ณ๊ฒฝ ์ ์ ๊ฐ์ฒด), โก ๋ฐฉ์ด์ ๋ณต์ฌ (์์ฑ์/getter ์์ ์ ์ปฌ๋ ์ ์์ฑ), โข ๋ฐํ ๊ฐ ํ์ฉ (๋ณ๊ฒฝ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํด์ ๋ช ์์ ํ ๋น). Effective Java ๊ฐ ๊ถ์ฅํ๋ ํจํด๋ค โ ๋ชจ๋ Pass by Value ์ ํจ์ ํํผ.
Q1: ์๋ฐ์๋ ์ ๋ง Pass by Reference๊ฐ ์๋๊ฐ?
ํ ์ค ๋ต: YES, ์ ๋ ์๋ค. James Gosling ๋ ๋ช ์.
์์ธ ์ค๋ช :
์๋ฐ๋ ๋ชจ๋ ์ธ์๋ฅผ ๊ฐ์ผ๋ก ์ ๋ฌ:
Pass by Reference ๋ผ๋ฉด (์๋ฐ์ ์๋ ๊ฒ):
// ๊ฐ์ โ ์๋ฐ์ ์ด๋ฐ ๋ฌธ๋ฒ ์์
public void modify(Customer& c) { // & ์ฐธ์กฐ ๋งค๊ฐ๋ณ์ (C++)
c = new Customer("Bob"); // ์ธ๋ถ๋ ์ ๊ฐ์ฒด ๊ฐ๋ฆฌํด
}
Customer alice = new Customer("Alice");
modify(alice);
// alice ๊ฐ ์ Customer("Bob") ๋ฅผ ๊ฐ๋ฆฌ์ผ์ผ Pass by Reference
// โ ์๋ฐ์์๋ ๋ถ๊ฐ๋ฅ
์๋ฐ์ ์ค์ (Pass by Value):
public void modify(Customer c) {
c = new Customer("Bob"); // ๋ฉ์๋ ์๋ง
}
Customer alice = new Customer("Alice");
modify(alice);
System.out.println(alice.getName()); // "Alice" โ ๋ณ๊ฒฝ ์ ๋จ
โ Pass by Reference ๋ผ๋ฉด "Bob" ์ด ๋์์ผ ํจ. ๊ทธ๋ฐ๋ฐ ์ ๋์ด โ Pass by Reference ๊ฐ ์๋.
์ ํท๊ฐ๋ฆฌ๋?:
c.setName("Bob")) ์ ์ธ๋ถ์ ์ํฅ๋น์ :
Q2: ๊ธฐ๋ณธ ์๋ฃํ๊ณผ ๊ฐ์ฒด ์๋ฃํ์ ๋ฉ์๋ ์ธ์ ์ ๋ฌ ์ฐจ์ด๋?
ํ ์ค ๋ต: ๋ ๋ค Pass by Value, ๋จ ๋ณต์ฌ๋๋ ๋์ ์ด ๋ค๋ฆ.
์์ธ ์ค๋ช :
public void modify(int x) {
x = 100;
}
int n = 10;
modify(n);
System.out.println(n); // 10
๋ณต์ฌ ๋์: ๊ฐ ์์ฒด (10)
๋ฉ๋ชจ๋ฆฌ:
[Stack โ main]
n = 10
[Stack โ modify]
x = 10 โ ๊ฐ ๋ณต์ฌ
ํจ๊ณผ: ๋ฉ์๋ ์ ๋ณ๊ฒฝ โ ์ธ๋ถ ๋ฌด๊ด.
public void modify(Customer c) {
c.setName("Bob");
}
Customer alice = new Customer("Alice");
modify(alice);
System.out.println(alice.getName()); // "Bob"
๋ณต์ฌ ๋์: ์ฐธ์กฐ์ ๊ฐ(์ฃผ์)
๋ฉ๋ชจ๋ฆฌ:
[Heap]
Customer ("Alice") ์ฃผ์ 0x1234
โ โ
โ โ
[Stack โ main] [Stack โ modify]
alice = 0x1234 c = 0x1234 โ ๊ฐ์ ์ฃผ์
ํจ๊ณผ: ๋ ์ฐธ์กฐ๊ฐ ๊ฐ์ ๊ฐ์ฒด โ ๊ฐ์ฒด ๋ณ๊ฒฝ ์ ์์ชฝ ์ํฅ.
| ์ธก๋ฉด | ๊ธฐ๋ณธํ | ๊ฐ์ฒด |
|---|---|---|
| ๋ณต์ฌ ๋์ | ๊ฐ ์์ฒด | ์ฐธ์กฐ์ ๊ฐ (์ฃผ์) |
| ๋ฉ์๋ ์ ๋ณ๊ฒฝ ์ | ๋ฉ์๋ ์๋ง | ๊ฐ์ฒด ๋ด๋ถ ๋ณ๊ฒฝ โ ์ธ๋ถ ์ํฅ |
| ์ฌํ ๋น ์ | ๋ฉ์๋ ์๋ง | ๋ฉ์๋ ์๋ง |
| ๋ฉ๋ชจ๋ฆฌ ์์น | Stack ์ ์ง์ | ์ฐธ์กฐ๋ Stack, ๊ฐ์ฒด๋ Heap |
ํต์ฌ ํต์ฐฐ โญ :
"๋ ๋ค Pass by Value ์ธ๋ฐ, '๊ฐ' ์ ์๋ฏธ๊ฐ ๋ค๋ฅด๋ค.
๊ธฐ๋ณธํ์ ๊ฐ = ์ค์ ๋ฐ์ดํฐ, ๊ฐ์ฒด์ ๊ฐ = ์ฐธ์กฐ(์ฃผ์)"
์๊ฐํ:
๊ธฐ๋ณธํ:
[๋ณต์ฌ๋๋ ๊ฒ]: โโโโโ (์ค์ ๋ฐ์ดํฐ)
๊ฐ์ฒด:
[๋ณต์ฌ๋๋ ๊ฒ]: โ โ โ โ โ (์ฃผ์๋ง)
โ
์ค์ ๊ฐ์ฒด (Heap, 1๊ฐ)
โ ๋ฉ๋ชจ๋ฆฌ ๊ตฌ์กฐ (Unit 4.1) ์์์ ๋ช ํํด์ง.
| Unit | ์ฃผ์ | ํต์ฌ |
|---|---|---|
| 4.1 | JVM ๋ฐํ์ ๋ฐ์ดํฐ ์์ญ โ โ โ | 5๊ฐ์ง ๋ฉ๋ชจ๋ฆฌ ์์ญ |
| 4.2 | Pass by Value โ โ โ | ์๋ฐ์ ์ธ์ ์ ๋ฌ ์ง์ค |
"๋ฉ๋ชจ๋ฆฌ ๊ตฌ์กฐ๋ฅผ ์์์ผ ์๋ฐ๋ฅผ ์ง์ง ์ดํดํ ๊ฒ์ด๋ค."
Pass by Value, ๋์์ฑ, GC, JPA ์์์ฑ โ ๋ชจ๋ ์๋ฐ์ ๊น์ ์ฃผ์ ๊ฐ ์ด ๋ฉ๋ชจ๋ฆฌ ๋ชจ๋ธ ์์ ์ ์๋ค. ์ถ์์ ์ธ๊ณ (Phase 1-3) ์ ๋ฌผ๋ฆฌ์ ์ธ๊ณ (Phase 4) ๊ฐ ๋ง๋๋ ์ง์ .
์ด์ Heap ์ ๊ฐ์ฒด๊ฐ ์ด๋ป๊ฒ ์๊ฑฐ๋๋์ง:
โ Heap ์ดํด (Unit 4.1) ๊ฐ ๊ฒฐ์ ์ ํ ๋.