๐Ÿ“– ๋ถˆ๋ณ€ ๊ฐ์ฒด (Immutable Class)


๋ถˆ๋ณ€ ๊ฐ์ฒด (Immutable Class)๋ž€?

๋ถˆ๋ณ€ ๊ฐ์ฒด๋ž€ ๋ง ๊ทธ๋Œ€๋กœ ๋ณ€๊ฒฝ์ด ๋ถˆ๊ฐ€๋Šฅํ•œ ๊ฐ์ฒด์ด๋‹ค.
๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ ํ›„ ์™ธ๋ถ€์— ์˜ํ•ด ๊ทธ ์ƒํƒœ๋ฅผ ๋ฐ”๊ฟ€ ์ˆ˜ ์—†๋‹ค.
์—ฌ๊ธฐ์„œ ๋ฐ”๊ฟ€ ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์€ heap ์˜์—ญ์—์„œ ๊ทธ ๊ฐ์ฒด๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๊ณ  ์žˆ๋Š”
๋ฐ์ดํ„ฐ ์ž์ฒด์˜ ๋ณ€ํ™”๊ฐ€ ๋ถˆ๊ฐ€๋Šฅ ํ•จ์„ ์˜๋ฏธํ•˜๋ฉฐ stack์— ์žˆ๋Š” ์ฃผ์†Œ๊ฐ’์„ ๋‹ค๋ฅธ ์ฃผ์†Œ๊ฐ’์„ ๊ฐ€๋ฆฌํ‚ค๋„๋ก ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์€ ๋ฌธ์ œ ์—†๋‹ค.

โž• ์—ฌ๊ธฐ์„œ ๋งํ•˜๋Š” heap ์˜์—ญ์ด๋ž€ ๋ฌด์—‡์ธ๊ฐ€?

๊ฐ„๋‹จํ•˜๊ฒŒ ๋งํ•ด ์›์‹œํƒ€์ž…(int, boolean ๋“ฑ)์€ ๊ทธ๋Œ€๋กœ stack ์˜์—ญ์— ์˜ฌ๋ผ๊ฐ€์ง€๋งŒ,
์ฐธ์กฐ๋ณ€์ˆ˜๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ํƒ€์ž…(Object, Array ๋“ฑ)์€ ๊ทธ ์‹ค์ œ ๋ฐ์ดํ„ฐ๋“ค์€ heap ์˜์—ญ์— ์ €์žฅํ•˜๊ณ  ์ด ์ฃผ์†Œ๊ฐ’์„ Stack ์˜์—ญ์— ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

์˜ˆ์‹œ๋กœ String name = "amazzi";์—์„œ name = "newwisdom";์œผ๋กœ
name์ด ๊ฐ€๋ฆฌํ‚ค๋Š” ์ฃผ์†Œ์˜ ๋ณ€๊ฒฝ์€ ๊ฐ€๋Šฅํ•˜๋‹ค.
์—ฌ๊ธฐ์„œ String์€ ๋ถˆ๋ณ€ ๊ฐ์ฒด๋กœ name์˜ ๊ฐ’์„ ๋ฐ”๊ฟ”์ค€ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด์ง€๋งŒ ์‹ค์ œ๋กœ๋Š”
String ๊ฐ์ฒด์— "newwisdom"์„ ์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜๋กœ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.
์ฆ‰ name์ด ์ฒ˜์Œ์— ์ฐธ์กฐํ•˜๋Š” ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜๋Š”๊ฒŒ ์•„๋‹Œ ์•„์˜ˆ ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค๊ณ 
์ด๋ฅผ name์ด ์ฐธ์กฐํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.

๋ถˆ๋ณ€ ๊ฐ์ฒด์˜ ํŠน์ง•

์žฅ์ 

  • ์ƒ์„ฑ์ž, ์ ‘๊ทผ ๋ฉ”์†Œ๋“œ์— ๋Œ€ํ•œ ๋ฐฉ์–ด์  ๋ณต์‚ฌ๊ฐ€ ํ•„์š”์—†๋‹ค.
  • ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์ด๋ผ๋ฉด ๋™๊ธฐํ™” ์ฒ˜๋ฆฌ ์—†์ด ๊ฐ์ฒด๋ฅผ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋ถˆ๋ณ€์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ์ฒด๋ฅผ ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋‹ค.

๋‹จ์ 

  • ๊ฐ์ฒด๊ฐ€ ๊ฐ€์ง€๋Š” ๊ฐ’๋งˆ๋‹ค ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•ด์•ผํ•œ๋‹ค.

๊ทผ๋ฐ ์ˆ˜์—…์‹œ๊ฐ„์—์„œ ์ œ์ด์Šจ์ด ๋งํ•˜๊ธฐ๋ฅผ Oracle ๊ณต์‹ ๋ฌธ์„œ์—๋Š” โ€œ๋ถˆ๋ณ€ ๊ฐ์ฒด๋Š” ์—ฌ๋Ÿฌ๋ถ„์ด ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ฑฑ์ •ํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ํ›จ์”ฌ ํฐ ์ด์ต์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.โ€ ์ด๋Ÿฐ ๋‰˜์•™์Šค์˜ ๋ฌธ์žฅ์ด ์žˆ๋‹ค๊ณ  ํ•œ๋‹ค.

์—ฌ๋Ÿฌ ํƒ€์ž…์—์„œ์˜ ๋ถˆ๋ณ€

์›์‹œ ํƒ€์ž…๋งŒ ์žˆ๋Š” ๊ฒฝ์šฐ์—์„œ ๋ถˆ๋ณ€

์›์‹œ ํƒ€์ž…์—์„œ์˜ ๋ถˆ๋ณ€์€ ์‰ฝ๋‹ค.
์›์‹œ ํƒ€์ž…์€ ์ฐธ์กฐ ๊ฐ’์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ’์„ ๊ทธ๋Œ€๋กœ ์™ธ๋ถ€์— ๋‚ด๋ณด๋‚ด๋„ ๋‚ด๋ถ€ ๊ฐ์ฒด๋Š” ๋ถˆ๋ณ€์ด๋‹ค.

Example

class Person {
    private final int age;
    private final int name;
    
    public Person(int age, int name) {
    	this.age = age;
        this.name = name;
    }
}

์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜๋“ค์ด final๋กœ ์„ ์–ธ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ธ์Šคํ„ด์Šค ๊ฐ’์˜ ๋ณ€๊ฒฝ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.
๋”ฐ๋ผ์„œ setter ๋ฉ”์†Œ๋“œ๋„ ์‚ฌ์šฉ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.

์ด ๊ฐ์ฒด์˜ ์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜๋“ค์˜ ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๋ ค๋ฉด ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ• ๋ฟ์ด๋‹ค.

์ฐธ์กฐ ํƒ€์ž…์ด ์žˆ๋Š” ๊ฒฝ์šฐ์—์„œ ๋ถˆ๋ณ€

โ€œ์›์‹œ ํƒ€์ž…๋งŒ ์žˆ๋Š” ๊ฒฝ์šฐ ์ฒ˜๋Ÿผ ๋‹จ์ˆœํžˆ final์„ ๋ถ™์ด๊ณ  setter ๋ฉ”์†Œ๋“œ๋งŒ ์•ˆ์‚ฌ์šฉํ•˜๋ฉด ๋˜์ง€ ์•Š์•„?โ€๋ผ๋Š”
์งˆ๋ฌธ์— ๋Œ€ํ•œ ๋Œ€๋‹ต์€ ์•„๋ž˜์™€ ๊ฐ™์€ ์˜ˆ์‹œ๋ฅผ ๋ณด๋ฉด ๋œ๋‹ค.

public class Car {
    
    private final Position position;

    public Car(final Position position) {
        this.position = position;
    }
    
    public Position getPosition() {
    	return position;
    }
}
public class Position {
    
    private int value;

    public Position(final int value) {
        this.value = value;
    }

    public void setValue(final int value) {
        this.value = value;
    }
    
    public int getValue() {
    	return value;
    }
}

์—ฌ๊ธฐ์„œ Car๋Š” ๋ถˆ๋ณ€ ๊ฐ์ฒด์ธ๊ฐ€?
์•„๋‹ˆ๋‹ค.
Car๋Š” final์„ ์‚ฌ์šฉํ•˜๊ณ , setter๊ฐ€ ์—†์ง€๋งŒ ์šฐ๋ฆฌ๋Š” Car์˜ position์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.

public static void main(String[] args) {
    Position position = new Position(1);
    Car car = new Car(position);

    System.out.println(car.getPosition().getValue());
    // 1

    car.getPosition().setValue(10);
    System.out.println(car.getPosition().getValue());
    // 10
}

๋ถˆ๋ณ€ ๊ฐ์ฒด๋ผ๊ณ  ์ƒ๊ฐํ–ˆ๋˜ Car ๋‚ด๋ถ€์˜ ์ฐธ์กฐ๋ณ€์ˆ˜ Position์€ ๋ถˆ๋ณ€ ๊ฐ์ฒด๊ฐ€ ์•„๋‹ˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์—
Car ๋˜ํ•œ ๋ถˆ๋ณ€ ๊ฐ์ฒด๊ฐ€ ๋  ์ˆ˜ ์—†์—ˆ๋‹ค.
์ฆ‰, ๋ถˆ๋ณ€ ๊ฐ์ฒด์˜ ์ฐธ์กฐ ๋ณ€์ˆ˜ ๋˜ํ•œ ๋ถˆ๋ณ€, ๋ถˆ๋ณ€ ๊ฐ์ฒด์—ฌ์•ผ ํ•œ๋‹ค.

์ฐธ์กฐ ๋ณ€์ˆ˜๊ฐ€ ์ผ๋ฐ˜ ๊ฐ์ฒด์ธ ๊ฒฝ์šฐ

์œ„ ์˜ˆ์ œ์—์„œ ์ฐธ์กฐ ๋ณ€์ˆ˜์ธ Position๋„ ๋ถˆ๋ณ€ ๊ฐ์ฒด๋กœ ๋งŒ๋“ ๋‹ค.

public class Car {
    
    private final Position position;

    public Car(final Position position) {
        this.position = position;
    }
    
    public Position getPosition() {
    	return position;
    }
}
public class Position {
    
    private final int value;

    public Position(final int value) {
        this.value = value;
    }

    public void setValue(final int value) {
        this.value = value;
    }
    
    public int getValue() {
    	return value;
    }
}

์ฐธ์กฐ ๋ณ€์ˆ˜๊ฐ€ List์ผ ๊ฒฝ์šฐ

์ฐธ์กฐ๋ณ€์ˆ˜๊ฐ€ List์ผ ๊ฒฝ์šฐ๋Š” List์— ๋‹ด๊ณ  ์žˆ๋Š” ๊ฐ์ฒด๊ฐ€ ๋ถˆ๋ณ€ ๊ฐ์ฒด์—ฌ๋„ ์ฃผ์˜ํ•ด์•ผํ•œ๋‹ค.
์ด ๊ฒฝ์šฐ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์กฐ๊ฑด์„ ๋งŒ์กฑ ์‹œ์ผœ์•ผ ํ•œ๋‹ค.

์ƒ์„ฑ ์‹œ ์ƒ์„ฑ ์ธ์ž๋ฅผ ๊ทธ๋Œ€๋กœ ์ฐธ์กฐํ•˜์ง€ ์•Š์•„์•ผ ํ•œ๋‹ค. (new ArrayList<>())

์ƒ์„ฑ๋  ๋•Œ ์ธ์ž๋กœ ๋„˜์–ด์˜จ List๋ฅผ ์™ธ๋ถ€์—์„œ ๋ณ€๊ฒฝํ•˜๋ฉด List๋ฅผ ๊ฐ€์ง„ ๊ฐ์ฒด์˜ ๋‚ด๋ถ€ ์ธ์Šคํ„ด์Šค ๋˜ํ•œ ๋ณ€ํ•œ๋‹ค.
๋•Œ๋ฌธ์— ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด ๊ฐ’์„ ์ „๋‹ฌ ๋ฐ›์„ ๋•Œ new ArrayList<>()๋ฅผ ํ†ตํ•ด
์ƒˆ๋กœ์šด ๊ฐ’์„ ์ฐธ์กฐํ•˜๋„๋ก ๋ฐฉ์–ด์  ๋ณต์‚ฌ๋ฅผ ๋„์ž…ํ•ด์•ผ ํ•œ๋‹ค.
์ด๋Ÿฌ๋ฉด ์™ธ๋ถ€์—์„œ ๋„˜๊ฒจ์ฃผ๋Š” List์™€ ๊ฐ์ฒด ๋‚ด๋ถ€์˜ ์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜๊ฐ€ ์ฐธ์กฐํ•˜๋Š” ๊ฐ’์ด
๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ์™ธ๋ถ€์—์„œ ์ œ์–ด๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.

getter๋ฅผ ํ†ตํ•ด add/remove๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋„๋ก Collectiions.unmodifiableList() ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉ

getter๋ฅผ ํ†ตํ•ด List์˜ ์ฐธ์กฐ๋ณ€์ˆ˜๋ฅผ ๊ทธ๋Œ€๋กœ ๋‚ด๋ณด๋‚ด๊ฒŒ ๋˜๋ฉด
Collections์˜ API๋ฅผ ํ†ตํ•ด ์ด ๊ฐ’์„ ์ถ”๊ฐ€/์‚ญ์ œํ•  ์ˆ˜ ์žˆ๋‹ค.
๋•Œ๋ฌธ์— getter ๋ฉ”์†Œ๋“œ ๊ตฌํ˜„ ์‹œ ์ด๋ฅผ ํ†ตํ•ด add/remove๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋„๋ก
List์˜ ๊ฐ’ ๋ณ€๊ฒฝ์„ ๋ง‰๋Š” Collectiions.unmodifiableList() ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

public class Positions {
    
    private final List<Position> positions;

    public Positions(final List<Position> positions) {
        this.positions = new ArrayList<>(positions);
    }
    
    public Position getPosition() {
    	return Collections.unmodifiableList(position);
    }
}

์ฐธ๊ณ  ์ž๋ฃŒ