๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Language/Java

[Java] ๋ถˆ๋ณ€๊ฐ์ฒด(Immutable Object)์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์ž

by jaee_ 2021. 8. 29.

๐Ÿ“š ์ด๋ฒˆ์ฃผ ๋ฉ˜ํ† ๋ง ์‹œ๊ฐ„์— <์ž๋ฐ”์˜ ์‹ > ์ฑ…์„ ๊ผผ๊ผผํžˆ ์ฝ์—ˆ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ๋Š”๋ฐ ๋ง‰์ƒ ์งˆ๋ฌธ ์ฃผ์‹  ๊ฒƒ์— ๋Œ€ํ•ด ๋‹ต๋ณ€์„ ๋ชปํ–ˆ๋‹ค. ๊ทธ ์ด์œ ๋Š” ์˜จ์ „ํžˆ ๋‚ด ๊ฒƒ์œผ๋กœ ๋งŒ๋“ค์ง€ ๋ชปํ–ˆ๊ธฐ ๋•Œ๋ฌธ์—๋ผ๊ณ  ์ƒ๊ฐํ•œ๋‹ค. ์ด๋ฒˆ์ฃผ๋ถ€ํ„ฐ๋Š” ์ฝ์€ ๋‚ด์šฉ๊ณผ ์ดํ•ดํ•œ ๋‚ด์šฉ์„ ๋ชจ๋‘ ๋ธ”๋กœ๊ทธ์— ์ •๋ฆฌํ•˜๋ฉฐ "~~๊ฐ€ ๋ญ”๊ฐ€์š”?"๋ผ๋Š” ์งˆ๋ฌธ์— ๋Œ€๋‹ตํ•  ์ˆ˜ ์žˆ๊ฒŒ๋” ๊ณต๋ถ€ํ•œ ๋‚ด์šฉ์„ ๋จธ๋ฆฟ์†์— ์ง‘์–ด๋„ฃ์„ ์˜ˆ์ •์ด๋‹ค.


๋ถˆ๋ณ€ ๊ฐ์ฒด(immutable object) ๋ž€?

๊ฐ์ฒด ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์— ์žˆ์–ด์„œ ๋ถˆ๋ณ€๊ฐ์ฒด(immutable object)๋Š” ์ƒ์„ฑ ํ›„ ๊ทธ ์ƒํƒœ๋ฅผ ๋ฐ”๊ฟ€ ์ˆ˜ ์—†๋Š” ๊ฐ์ฒด๋ฅผ ๋งํ•œ๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ํ•œ ๋ฒˆ ์ƒ์„ฑ์ด ๋˜๋ฉด ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ์ฒด๊ฐ€ ๋œ๋‹ค.

๊ฐ€์žฅ ๋Œ€ํ‘œ์ ์ธ ๋ถˆ๋ณ€๊ฐ์ฒด๋กœ๋Š” String, Integer, Boolean, BigDecimal ...์ด ์žˆ๋‹ค. ์•„๋ž˜์˜ ์˜ˆ์ œ๋Š” String์„ ์˜ˆ๋กœ ๋“ค์—ˆ๋‹ค.

String str = "a"; //(1) 
str = "b"; //(2) 
str = "Immutable"; //(3)

String์€ ์ฐธ์กฐ๋ณ€์ˆ˜์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ฉ”๋ชจ๋ฆฌ ์ƒ heap์˜์—ญ์— ์ €์žฅ์ด ๋œ๋‹ค. ์œ„์˜ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ๋ฉ”๋ชจ๋ฆฌ์ƒ ๊ฐ์ฒด ์ƒ์„ฑ๊ณผ ์ฐธ์กฐ๊ฐ€ ์–ด๋–ป๊ฒŒ ์ผ์–ด๋‚˜๋Š”์ง€ ์‚ดํŽด๋ณด์ž.

(1)์„ ์‹คํ–‰ํ•˜๋ฉด heap์˜์—ญ์— str์ด ์ฐธ์กฐํ•˜๊ณ  ์žˆ๋Š” "a"๋ผ๋Š” ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค.
(2)๋ฅผ ์‹คํ–‰ํ•˜๋ฉด "a"๋ผ๋Š” ๊ฐ์ฒด๊ฐ€ "b"๋ผ๋Š” ๊ฐ’์œผ๋กœ ๋ณ€ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ "b"๋ผ๋Š” ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ ๋‹ค. ๊ทธ๋ฆฌ๊ณ  (1)์—์„œ ์ƒ์„ฑ๋˜์—ˆ๋˜ str์€ "b"๊ฐ์ฒด๋ฅผ ๋ฐ”๋ผ๋ณธ๋‹ค.
(3)์„ ์‹คํ–‰ํ•˜๋ฉด "Immutable"์ด๋ผ๋Š” ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ ๋‹ค. ๊ทธ๋ฆฌ๊ณ  (1)์—์„œ ์ƒ์„ฑ๋˜์—ˆ๋˜ str์€ "Immutable"๊ฐ์ฒด๋ฅผ ๋ฐ”๋ผ๋ณธ๋‹ค.

์œ„์˜ ์ฝ”๋“œ๋ฅผ (3)๊นŒ์ง€ ์‹คํ–‰ํ•˜๊ฒŒ ๋˜๋ฉด (1),(2)์—์„œ ์ƒ์„ฑํ–ˆ๋˜ "a","b"๋ผ๋Š” ๊ฐ์ฒด๋Š” ์•„๋ฌด๊ฒƒ๋„ ์ฐธ์กฐํ•˜๊ณ  ์žˆ์ง€ ์•Š๋Š” ๊ฐ์ฒด๊ฐ€ ๋˜์–ด GC์˜ ๋Œ€์ƒ์ด ๋œ๋‹ค.

์œ„์˜ ์˜ˆ์ œ์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋“ฏ์ด String์€ ๋ถˆ๋ณ€๊ฐ์ฒด๋ผ "a"์—์„œ "b" ๋กœ ๋ณ€ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

์™œ ๋ถˆ๋ณ€ ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๊ฐ€?

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

2. ๋ถˆ๋ณ€๊ฐ์ฒด๋Š” ๊ทธ ์ž์ฒด๋กœ ์‹คํŒจ ์›์ž์„ฑ์„ ์ œ๊ณตํ•œ๋‹ค.
์‹คํŒจ ์›์ž์„ฑ์ด๋ž€ ํ˜ธ์ถœ๋œ ๋ฉ”์†Œ๋“œ๊ฐ€ ์‹คํŒจํ•˜๋”๋ผ๋„ ํ•ด๋‹น ๊ฐ์ฒด๋Š” ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ ์ „ ์ƒํƒœ๊ฐ€ ์œ ์ง€๋˜์–ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ๋ถˆ๋ณ€๊ฐ์ฒด๋Š” ์ƒํƒœ๊ฐ€ ์ ˆ๋Œ€๋กœ ๋ณ€ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

๋ถˆ๋ณ€ ๊ฐ์ฒด๋ฅผ ์–ด๋–ป๊ฒŒ ๋งŒ๋“œ๋Š”๊ฐ€?

1. setter๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค. (๊ฐ์ฒด์˜ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฉ”์†Œ๋“œ ๋ฏธ์ œ๊ณต)
2. private์œผ๋กœ ์„ ์–ธํ•œ๋‹ค.
3. final์„ ์„ ์–ธํ•œ๋‹ค. (final์— ๋Œ€ํ•ด์„œ ๊ถ๊ธˆํ•˜๋‹ค๋ฉด "final ์„ ์•Œ์•„๋ณด์ž "๊ฒŒ์‹œ๋ฌผ์„ ์ฐธ๊ณ ํ•ด๋ณด์ž)

์œ„์˜ ์„ธ๊ฐœ๋ฅผ ๊ธฐ์–ตํ•˜๊ณ  ๋ถˆ๋ณ€๊ฐ์ฒด๋ฅผ ์ง์ ‘ ๋งŒ๋“ค์–ด๋ณด์ž.

    public class ImmutablePhone {

        private final String name; //final๋กœ ์„ ์–ธ
        private final int number; //final๋กœ ์„ ์–ธ 

        public ImmutablePhone(String name, int number) { // ๊ฐ์ฒด์ƒ์„ฑ ๋ฐ ๋ณ€์ˆ˜ ๊ฐ’ ๋ถ€์—ฌ๋Š” ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด์„œ๋งŒ 
            this.name = name;
            this.number = number;
        }
        // setter๋ฏธ์กด์žฌ 
    }

์œ„์ฒ˜๋Ÿผ ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜๋ฉด ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด์„œ๋งŒ name, number์˜ ๊ฐ’์„ ๋„ฃ์„ ์ˆ˜ ์žˆ๊ณ , ์™ธ๋ถ€์—์„œ๋Š” final๋กœ ์„ ์–ธ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ’์ด ๋ณ€๊ฒฝ์ด ๋˜์ง€ ์•Š๋Š”๋‹ค.

ํ•˜์ง€๋งŒ ๋ถˆ๋ณ€๊ฐ์ฒด ๋‚ด์— ๊ฐ€๋ณ€๊ฐ์ฒด๋ฅผ ์ฐธ์กฐ๋ฐ›๊ณ  ์žˆ๋‹ค๋ฉด ์ด์•ผ๊ธฐ๊ฐ€ ๋‹ฌ๋ผ์ง„๋‹ค. ์•„๋ž˜์˜ ์˜ˆ์‹œ๋ฅผ ๋ณด์ž

    public class ImmutablePhone { // (1) 

        private final Iphone iphone;

        public ImmutablePhone(final Iphone iphone) {
            this.iphone = iphone;
        }

        public Iphone getIphone() {
            return iphone;
        }
    }

    class Iphone { // (2) 

        private int version;

        public Iphone(int version) {
            this.version = version;
        }

        public void setVersion(int version) {
            this.version = version;
        }

        public int getVersion() {
            return version;
        }
    }

(1) ์€ final์„ ์ด์šฉํ•˜์—ฌ ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•˜์˜€๊ณ , setter๋ฉ”์†Œ๋“œ ์—ญ์‹œ ๋งŒ๋“ค์ง€ ์•Š์•˜๋‹ค. (2)๋ฅผ ์ฐธ์กฐ ๋ณ€์ˆ˜๋กœ ๋ฐ›๊ณ  ์žˆ๋‹ค.
(2) ๋Š” ๊ทธ๋ƒฅ ์ผ๋ฐ˜ ๊ฐ์ฒด์ด๋‹ค. setter์™€ getter๊ฐ€ ์กด์žฌ.

// ์‹คํ–‰์ฝ”๋“œ 
    public static void main(String[] args) {
        
        Iphone iphone = new Iphone(10);
        ImmutablePhone phone = new ImmutablePhone(iphone);

        System.out.println(phone.getIphone().getVersion()); // 10

        phone.getIphone().setVersion(14);
        System.out.println(phone.getIphone().getVersion()); // 14
    
    }

}

phone์ด๋ผ๋Š” ์ผ๋ฐ˜๊ฐ์ฒด๋ฅผ ๋งŒ๋“  ๋’ค ImmutablePhone ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ ํ›„ ์ฐธ์กฐ๊ฐ์ฒด๋กœ Iphone์„ ๋„ฃ๋Š”๋‹ค. ์ผ๋ฐ˜๊ฐ์ฒด๋กœ ์ฐธ์กฐ๋ณ€์ˆ˜๋ฅผ ๋ฐ›์•„์„œ ์ผ๋ฐ˜๊ฐ์ฒด์— ์ ‘๊ทผํ•˜์—ฌ setter๋ฅผ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ์ฆ‰ (1)์— ์•„๋ฌด๋ฆฌ final์„ ์„ ์–ธํ•˜๊ณ  setter๋ฅผ ์—†์•ค๋‹ค ํ•ด๋„ ์ฐธ์กฐ๋˜๋Š” ๊ฐ์ฒด๊ฐ€ ๋ถˆ๋ณ€๊ฐ์ฒด๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด ์ ‘๊ทผํ•˜์—ฌ ๊ฐ’ ์กฐ์ž‘์ด ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ๋ถˆ๋ณ€๊ฐ์ฒด๊ฐ€ ๋˜๋ ค๋ฉด ์ฐธ์กฐ๊ฐ์ฒด ์—ญ์‹œ ๋ถˆ๋ณ€๊ฐ์ฒด์—ฌ์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด List๊ฐ™์€ ๊ฒฝ์šฐ๋Š” ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ•ด์•ผ ํ• ๊นŒ?

public class ListObject {

    private final List<ImmutablePhone> phone;

    public ListObject(final List<ImmutablePhone> phone) { // ์ƒˆ๋กœ์šด List๋ฅผ ๋งŒ๋“ค์–ด ์›๋ณธ ๊ฐ์ฒด์— ์ ‘๊ทผ ๋ชปํ•˜๋„๋ก ํ•œ๋‹ค. 
        this.phone = new ArrayList<>(phone);

    }

    public List<ImmutablePhone> getPhone() {
        // return์‹œ ๋ณต์‚ฌ๋ณธ์„ returnํ•˜๋ฉด ๋œ๋‹ค 
        // unmodifiableList()๋กœ ๋ฆฌํ„ด๋˜๋Š” ๊ฐ์ฒด๋Š” ์›๋ณธ์„ ์ˆ˜์ •ํ•  ์ˆ˜ ์—†๋‹ค. 
        // ์ฆ‰, read-only๋งŒ ๊ฐ€๋Šฅํ•œ ๋ฉ”์†Œ๋“œ์ด๋‹ค. 
        return Collections.unmodifiableList(phone);
    }
}

์œ„์˜ ์ฝ”๋“œ์™€ ๊ฐ™์ด ๋ณต์‚ฌ๋ณธ์„ return์‹œํ‚จ๋‹ค. Collection.unmodifiableList() ๋ฉ”์†Œ๋“œ๋กœ ์ธํ•ด return๋˜๋Š” ๊ฐ์ฒด๋Š” ์›๋ณธ ์ปฌ๋ ‰์…˜์œผ๋กœ ์ ‘๊ทผ์ด ๋ถˆ๊ฐ€ํ•˜๋ฉฐ read-only์ƒํƒœ๊ฐ€ ๋œ๋‹ค.

public class ImmutableTest {

    public static void main(String[] args) {
        List<ImmutablePhone> immutablePhone = new ArrayList<>();
        immutablePhone.add(new ImmutablePhone(new Iphone(3)));
        immutablePhone.add(new ImmutablePhone(new Iphone(4)));
        ListObject listObject = new ListObject(immutablePhone);
        for (ImmutablePhone list : listObject.getPhone()) {
            System.out.println(list.getIphone().getVersion()); // 3 // 4 
        }
        immutablePhone.add(new ImmutablePhone(new Iphone(5)));
        immutablePhone.add(new ImmutablePhone(new Iphone(6)));
        for (ImmutablePhone list : listObject.getPhone()) {
            System.out.println(list.getIphone().getVersion()); // 3 // 4 
        }
    }
}

์ด์ฒ˜๋Ÿผ ๋ถˆ๋ณ€๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค๋ ค๋ฉด ์ฐธ์กฐ๊ฐ์ฒด ์—ญ์‹œ ๋ถˆ๋ณ€์ด์–ด์•ผ ํ•œ๋‹ค๋Š” ์ ์„ ๊ผญ ์œ ์˜ํ•ด์•ผ ํ•œ๋‹ค.

๋Œ“๊ธ€