final

λ°•λ³‘μš±Β·2025λ…„ 5μ›” 31일

Java

λͺ©λ‘ 보기
8/38
post-thumbnail

πŸ€ final λ³€μˆ˜μ™€ μƒμˆ˜

final ν‚€μ›Œλ“œλŠ” 말 κ·ΈλŒ€λ‘œ β€œλβ€ μ΄λΌλŠ” λœ»μ΄λ‹€. final둜 λ³€μˆ˜λ₯Ό μ„ μ–Έν•˜λ©΄ κ·Έ 값을 더 이상 λ°”κΏ€ 수 μ—†λ‹€. final ν‚€μ›Œλ“œλŠ” λ³€μˆ˜, λ©”μ„œλ“œ, ν΄λž˜μŠ€μ— μ‚¬μš©λ  수 μžˆμ§€λ§Œ, 일단 μ§€κΈˆμ€ λ³€μˆ˜μ— 뢙을 κ²½μš°μ— λŒ€ν•΄ μ•Œμ•„λ³΄μž.

package final1;

public class FinalLocalMain {
    public static void main(String[] args) {
        final int data1 = 10;

        // Cannot assign a value to final variable 'data1'
        // data1 = 20;

        finalMethod(30);
    }

    // Value of parameter 'parameter' is always '30'
    static void finalMethod(final int parameter) {
        // Cannot assign a value to final variable 'parameter'
        // parameter = 20;
    }
}

λ³΄λ‹€μ‹œν”Ό final을 data1처럼 μ§€μ—­ λ³€μˆ˜λ‘œ μ„€μ •ν•  경우, 졜초 ν•œλ²ˆλ§Œ ν• λ‹Ή κ°€λŠ₯ν•˜λ‹€. 이후에 κ·Έ λ³€μˆ˜μ˜ 값을 λ³€κ²½ν•˜λ €κ³  ν•œλ‹€λ©΄ 컴파일 였λ₯˜κ°€ λ°œμƒν•œλ‹€. λ§ˆμ°¬κ°€μ§€λ‘œ, 맀개 λ³€μˆ˜μ— final이 뢙은 κ²½μš°μ—λ„ λ©”μ„œλ“œ λ‚΄λΆ€μ—μ„œ 맀개 λ³€μˆ˜μ˜ 값을 λ³€κ²½ν•  수 μ—†λ‹€. λ”°λΌμ„œ λ©”μ„œλ“œ 호좜 μ‹œμ μ— μ‚¬μš©λœ 값이 λκΉŒμ§€ μ‚¬μš©λ˜λŠ” 것이닀.

Β 

🀿 멀버 λ³€μˆ˜μ—μ„œμ˜ final μ‚¬μš©

λ‹€μŒμœΌλ‘œ, final을 멀버 λ³€μˆ˜μ— μ‚¬μš©ν•΄λ³΄μž.

package final1;

public class ConstructInit {

    final int value;

	// μƒμ„±μžλ₯Ό 톡해 ν•œλ²ˆλ§Œ μ΄ˆκΈ°ν™”
    public ConstructInit(int value) {
        this.value = value;
    }
}

μœ„μ²˜λŸΌ 멀버 λ³€μˆ˜μ— final이 λΆ™μœΌλ©΄ μƒμ„±μžλ₯Ό ν†΅ν•΄μ„œ ν•œλ²ˆλ§Œ μ΄ˆκΈ°ν™” 될 수 μžˆλ‹€. 그리고 static λ³€μˆ˜μ—μ„œ final을 μ„ μ–Έν•  수 μžˆλ‹€.

package final1;

public class FieldInit {

    static final int CONST_VALUE = 10;  // 정적 μƒμˆ˜
    final int value = 10;  // μ΄ˆκΈ°ν™”λœ μΈμŠ€ν„΄μŠ€ final λ³€μˆ˜

    // Cannot assign a value to final variable 'value'
    public FieldInit(int value) {
        this.value = value;
    }
}

ν•˜μ§€λ§Œ, μœ„μ˜ μ½”λ“œμ—μ„œλŠ” value 값에 이미 값이 ν• λ‹Ήλ˜μ—ˆκΈ° λ•Œλ¬Έμ—, μƒμ„±μžμ—μ„œ λ‹€μ‹œ μ΄ˆκΈ°ν™”λ₯Ό μ‹œλ„ν•˜λ©΄ μ€‘λ³΅λœ μ΄ˆκΈ°ν™”κ°€ λ˜μ–΄μ„œ 컴파일 μ—λŸ¬κ°€ λ°œμƒν•œλ‹€. λ”°λΌμ„œ λ³€μˆ˜ μ„ μ–Έ μ‹œ μ΄ˆκΈ°ν™”λ₯Ό ν•˜μ§€ μ•Šκ³  μƒμ„±μžμ—μ„œ μ΄ˆκΈ°ν™”λ₯Ό ν•˜λ“ μ§€, μ„ μ–Έ μ‹œ μ΄ˆκΈ°ν™”λ₯Ό ν•˜κ³  μƒμ„±μžμ—μ„œλŠ” λ‹€μ‹œ μ΄ˆκΈ°ν™”ν•˜μ§€ 말아야 ν•œλ‹€.

Β 

이제 μœ„μ˜ μ˜ˆμ œλ“€μ„ μ‹€μ œλ‘œ μ‚¬μš©ν•΄λ³΄μž.

package final1;

public class FinalFieldMain {
    public static void main(String[] args) {
        System.out.println("--μƒμ„±μžλ‘œ μ΄ˆκΈ°ν™”--");
        ConstructInit c1 = new ConstructInit(10);
        ConstructInit c2 = new ConstructInit(20);

        System.out.println("μƒμ„±μžλ‘œ μ΄ˆκΈ°ν™”λœ c1 κ°’: " + c1.value);
        // c1.value = 20;  // Cannot assign a value to final variable 'value'

        System.out.println("μƒμ„±μžλ‘œ μ΄ˆκΈ°ν™”λœ c2 κ°’: " + c2.value);

        System.out.println("--ν•„λ“œμ—μ„œ λ°”λ‘œ μ΄ˆκΈ°ν™”--");
        FieldInit f1 = new FieldInit();
        FieldInit f2 = new FieldInit();
        FieldInit f3 = new FieldInit();

        System.out.println("멀버 λ³€μˆ˜ f1 κ°’: "+ f1.value);
        System.out.println("멀버 λ³€μˆ˜ f1 κ°’: "+ f2.value);
        System.out.println("멀버 λ³€μˆ˜ f1 κ°’: "+ f3.value);

        System.out.println("--μƒμˆ˜(CONST_VALUE) 좜λ ₯--");
        System.out.println(FieldInit.CONST_VALUE);
    }
}

/*
--μƒμ„±μžλ‘œ μ΄ˆκΈ°ν™”--
μƒμ„±μžλ‘œ μ΄ˆκΈ°ν™”λœ c1 κ°’: 10
μƒμ„±μžλ‘œ μ΄ˆκΈ°ν™”λœ c2 κ°’: 20
--ν•„λ“œμ—μ„œ λ°”λ‘œ μ΄ˆκΈ°ν™”--
멀버 λ³€μˆ˜ f1 κ°’: 10
멀버 λ³€μˆ˜ f1 κ°’: 10
멀버 λ³€μˆ˜ f1 κ°’: 10
--μƒμˆ˜(CONST_VALUE) 좜λ ₯--
10
*/

μœ„μ˜ ConstructInitκ³Ό 같이 μƒμ„±μžλ₯Ό μ΄μš©ν•΄μ„œ final ν•„λ“œλ₯Ό μ΄ˆκΈ°ν™” ν•˜λŠ” 경우, 각 μΈμŠ€ν„΄μŠ€λ§ˆλ‹€ final ν•„λ“œμ— 각각 λ‹€λ₯Έ 값을 ν• λ‹Ήν•  수 μžˆλ‹€. λ¬Όλ‘  이미 값을 ν• λ‹Ήν–ˆλ‹€λ©΄ κ·Έ 값을 λ‹€μ‹œ λ³€κ²½ν•  μˆ˜λŠ” μ—†λ‹€. ν•˜μ§€λ§Œ, 이미 멀버 λ³€μˆ˜μ—μ„œ μ΄ˆκΈ°ν™”κΉŒμ§€ μ§„ν–‰ν•œ FieldInit의 valueλŠ” μΈμŠ€ν„΄μŠ€λ₯Ό 아무리 많이 생성해도 μ΄ˆκΈ°ν™”λœ κ°’ 10으둜 κ³ μ •μ μœΌλ‘œ 좜λ ₯λ˜λŠ” 것을 확인할 수 μžˆλ‹€. μ•„λž˜ 그림을 톡해 더 μžμ„Έν•˜κ²Œ μ‚΄νŽ΄λ³΄μž.

FieldInitκ³Ό 같이 final ν•„λ“œλ₯Ό ν•„λ“œμ—μ„œ μ΄ˆκΈ°ν™”ν•˜λ©΄, λͺ¨λ“  FieldInit μΈμŠ€ν„΄μŠ€μ˜ 값은 μ΄ˆκΈ°ν™”λœ 값을 κ°–λŠ”λ‹€. μ™œλƒν•˜λ©΄, μƒμ„±μž μ΄ˆκΈ°ν™”μ™€λŠ” λ‹€λ₯΄κ²Œ 멀버 λ³€μˆ˜λ₯Ό μ΄ˆκΈ°ν™”ν•˜λŠ” 것은 μ΄ˆκΈ°ν™”ν•˜λŠ” κ°’μœΌλ‘œ λ°”λ‘œ λ°•ν˜€λ²„λ¦¬λŠ” 것이기 λ•Œλ¬Έμ΄λ‹€. 이러면 무슨 λ¬Έμ œκ°€ λ°œμƒν• κΉŒ? μΈμŠ€ν„΄μŠ€λŠ” λ¬΄μ§€ν•˜κ²Œ λ§Žμ€λ° λͺ¨λ‘ 같은 값을 μ‚¬μš©ν•˜κΈ° λ•Œλ¬Έμ— 결과적으둜 보면 λ©”λͺ¨λ¦¬λ₯Ό λ‚­λΉ„ν•˜λŠ” 꼴이닀. μ–΄μ°¨ν”Ό λ‹€ 값이 10인데, 심지어 λ°”λ€Œμ§€λ„ μ•ŠλŠ”λ‹€. 이런 상황은 λͺ…ν™•νžˆ 쀑볡이 λ°œμƒν•œ 상황이닀. λ°”λ‘œ 이럴 λ•Œ μ‚¬μš©ν•˜λ©΄ 쒋은 것이 static μ˜μ—­μ΄λ‹€.

Β 

μ•„κΉŒ CONST_VALUE처럼 static final을 같이 써 μ£Όλ©΄ 곡용 λ³€μˆ˜μΈλ° 값이 λ°”λ€Œμ§€ μ•Šκ²Œ λœλ‹€. μ•Œλ‹€μ‹œν”Ό static μ˜μ—­μ€ 단 ν•˜λ‚˜λ§Œ μ‘΄μž¬ν•˜λŠ” μ˜μ—­μ΄λ‹€. λ”°λΌμ„œ CONST_VALUE λ³€μˆ˜λŠ” JVM μƒμ—μ„œ 단 ν•˜λ‚˜λ§Œ μ‘΄μž¬ν•˜λ―€λ‘œ 쀑볡과 λ©”λͺ¨λ¦¬ λΉ„νš¨μœ¨ 문제λ₯Ό νšŒν”Όν•  수 μžˆλŠ” 것이닀.

Β 

β›“ static final : μƒμˆ˜

이런 CONST_VALUE와 같은 값을 β€œμƒμˆ˜β€ 라고 ν•œλ‹€. μƒμˆ˜λŠ” λ³€ν•˜μ§€ μ•Šκ³ , 항상 같은 값을 κ°–λŠ” 것을 λ§ν•œλ‹€. μžλ°”μ—μ„œλŠ” 단 ν•˜λ‚˜λ§Œ μ‘΄μž¬ν•˜κ³  λ³€ν•˜μ§€ μ•ŠλŠ” κ³ μ •λœ 값을 μƒμˆ˜λΌ ν•œλ‹€. μ΄λŸ¬ν•œ 이유둜 μƒμˆ˜λŠ” static final ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•œλ‹€. μƒμˆ˜λŠ” κΈ°λŠ₯이 μ•„λ‹ˆλΌ κ³ μ •λœ κ°’ 자체λ₯Ό μ‚¬μš©ν•˜λŠ” 것이 λͺ©μ μ΄λ‹€. 값이 κ³ μ •λ˜μ–΄ 있기 λ•Œλ¬Έμ— ν•„λ“œμ— 직접 μ ‘κ·Όν•΄μ„œ μ‚¬μš©ν•œλ‹€.

package final1;

public class Constant {

    public static final double PI = 3.141592;

    public static final int HOURS_IN_DAY = 24;
    public static final int MINUTES_IN_HOUR = 60;
    public static final int SECONDS_IN_MINUTE = 60;
    
    public static final int MAX_USERS = 2000;
}

이처럼 μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ•ˆμ—λŠ” λ‹€μ–‘ν•œ μƒμˆ˜κ°€ μ‘΄μž¬ν•  수 μžˆλ‹€. 이런 μƒμˆ˜λ“€μ€ μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ „λ°˜μ— κ±Έμ³μ„œ μ‚¬μš©λ  수 있기 λ•Œλ¬Έμ— λŒ€λΆ€λΆ„ public을 λΆ™μ΄λŠ” 것이 μ μ ˆν•˜λ‹€. λ˜ν•œ, μƒμˆ˜λŠ” λŸ°νƒ€μž„μ— λ³€κ²½ν•  수 μ—†λ‹€. μƒμˆ˜λ₯Ό λ³€κ²½ν•˜λ €λ©΄ ν”„λ‘œκ·Έλž¨μ„ μ’…λ£Œν•˜κ³  μ½”λ“œλ₯Ό λ³€κ²½ν•œ λ‹€μŒ, ν”„λ‘œκ·Έλž¨μ„ λ‹€μ‹œ μ‹€ν–‰ν•΄μ•Ό ν•œλ‹€.

Β 

그리고 μƒμˆ˜λŠ” μ€‘μ•™μ—μ„œ 값을 관리할 수 μžˆλ‹€λŠ” μž₯점이 μžˆλ‹€. μ•„λž˜ μ½”λ“œλ₯Ό 보자.

package final1;

public class ConstantMain1 {
    public static void main(String[] args) {
        System.out.println("--ν”„λ‘œκ·Έλž¨ μ΅œλŒ€ μ°Έμ—¬μž 수: 1000λͺ…");
        int currentUserCount = 999;

        process(currentUserCount++);
        process(currentUserCount++);
        process(currentUserCount++);
        process(currentUserCount++);

    }

    private static void process(int currentUserCount) {
        System.out.println("μ°Έμ—¬μž 수:" + currentUserCount);
        if (currentUserCount > 1000) {
            System.out.println("λŒ€κΈ°μžλ‘œ λ“±λ‘ν•©λ‹ˆλ‹€...");
        } else {
            System.out.println("κ²Œμž„μ— μ°Έμ—¬ν•©λ‹ˆλ‹€!");
        }
    }
}

/*
--ν”„λ‘œκ·Έλž¨ μ΅œλŒ€ μ°Έμ—¬μž 수: 1000λͺ…
μ°Έμ—¬μž 수:999
κ²Œμž„μ— μ°Έμ—¬ν•©λ‹ˆλ‹€!
μ°Έμ—¬μž 수:1000
κ²Œμž„μ— μ°Έμ—¬ν•©λ‹ˆλ‹€!
μ°Έμ—¬μž 수:1001
λŒ€κΈ°μžλ‘œ λ“±λ‘ν•©λ‹ˆλ‹€...
μ°Έμ—¬μž 수:1002
λŒ€κΈ°μžλ‘œ λ“±λ‘ν•©λ‹ˆλ‹€...
*/

이런 μ½”λ“œμ˜ λ¬Έμ œλŠ”, λ§Œμ•½ ν”„λ‘œκ·Έλž¨μ— μ°Έμ—¬ν•  수 μžˆλŠ” μ œν•œ μΈμ›μˆ˜λ₯Ό λ°”κΎΈλ €κ³  ν•œλ‹€λ©΄ μ—¬λŸ¬ μ½”λ“œλ₯Ό λ°”κΏ”μ•Ό ν•  수 μžˆλ‹€λŠ” 점이닀. 그리고 μ§€κΈˆμ΄μ•Ό μ„€λͺ…이 μ ν˜€ μžˆμ–΄μ„œ 망정이지, 1000λͺ…에 λŒ€ν•œ μ„€λͺ…이 μ—†λ‹€λ©΄ 처음 이 μ½”λ“œλ₯Ό λ³Έ μ‚¬λžŒμ€ 1000λͺ…이 μ–΄λ–€ μ˜λ―ΈμΈμ§€ μ•ŒκΈ°κ°€ νž˜λ“€ 것이닀. 이런 것을 β€œMagic Number” 라고 ν•œλ‹€.

Β 

이럴 λ•Œ μƒμˆ˜λ₯Ό μ‚¬μš©ν•˜λ©΄ 값을 λ³€κ²½ν•  λ•Œ μΌκ΄„μ μœΌλ‘œ κΉ”λ”ν•˜κ²Œ μ²˜λ¦¬ν•  수 있고, μ˜λ―Έλ„ μ•„μ£Ό 잘 λ…Ήμ•„ 있기 λ•Œλ¬Έμ— μ•„μ£Ό μ’‹λ‹€.

package final1;

public class ConstantMain1 {
    public static void main(String[] args) {
        System.out.println("--ν”„λ‘œκ·Έλž¨ μ΅œλŒ€ μ°Έμ—¬μž 수: " + Constant.MAX_USERS + "λͺ…");
        int currentUserCount = 999;

        process(currentUserCount++);
        process(currentUserCount++);
        process(currentUserCount++);
        process(currentUserCount++);

    }

    private static void process(int currentUserCount) {
        System.out.println("μ°Έμ—¬μž 수:" + currentUserCount);
        if (currentUserCount > Constant.MAX_USERS) {
            System.out.println("λŒ€κΈ°μžλ‘œ λ“±λ‘ν•©λ‹ˆλ‹€...");
        } else {
            System.out.println("κ²Œμž„μ— μ°Έμ—¬ν•©λ‹ˆλ‹€!");
        }
    }
}

/*
--ν”„λ‘œκ·Έλž¨ μ΅œλŒ€ μ°Έμ—¬μž 수: 2000λͺ…
μ°Έμ—¬μž 수:999
κ²Œμž„μ— μ°Έμ—¬ν•©λ‹ˆλ‹€!
μ°Έμ—¬μž 수:1000
κ²Œμž„μ— μ°Έμ—¬ν•©λ‹ˆλ‹€!
μ°Έμ—¬μž 수:1001
κ²Œμž„μ— μ°Έμ—¬ν•©λ‹ˆλ‹€!
μ°Έμ—¬μž 수:1002
κ²Œμž„μ— μ°Έμ—¬ν•©λ‹ˆλ‹€!
*/

Β 

🎯 final λ³€μˆ˜μ™€ μ°Έμ‘°

λ³€μˆ˜μ—λŠ” β€œκΈ°λ³Έν˜• λ³€μˆ˜β€ 와 β€œμ°Έμ‘°ν˜• λ³€μˆ˜β€ κ°€ μžˆμ—ˆλ‹€. final을 κΈ°λ³Έν˜• λ³€μˆ˜μ— μ‚¬μš©ν•˜λ©΄ 값을 λ³€κ²½ν•  수 μ—†κ³ , μ°Έμ‘°ν˜• λ³€μˆ˜μ— μ‚¬μš©ν•˜λ©΄ 참쑰값을 λ³€κ²½ν•  수 μ—†λŠ” 것이닀. μ•„λž˜ 예제λ₯Ό μ‚΄νŽ΄λ³΄μž.

package final1;

public class Data {
    public int value;
}
package final1;

public class FinalRefMain {
    public static void main(String[] args) {
        final Data data = new Data();  // μ°Έμ‘°ν˜• λ³€μˆ˜μ— final μ„ μ–Έ
        
        // Cannot assign a value to final variable 'data'
        // data = new Data();

        // μ°Έμ‘° λŒ€μƒμ˜ 값은 λ³€κ²½ κ°€λŠ₯ν•˜λ‹€.
        data.value = 10;
        System.out.println("dataκ°€ μ°Έμ‘°ν•˜λŠ” μΈμŠ€ν„΄μŠ€μ˜ value κ°’ = " + data.value);
        data.value = 20;
        System.out.println("dataκ°€ μ°Έμ‘°ν•˜λŠ” μΈμŠ€ν„΄μŠ€μ˜ value κ°’ = " + data.value);
    }
}

/*
dataκ°€ μ°Έμ‘°ν•˜λŠ” μΈμŠ€ν„΄μŠ€μ˜ value κ°’ = 10
dataκ°€ μ°Έμ‘°ν•˜λŠ” μΈμŠ€ν„΄μŠ€μ˜ value κ°’ = 20
*/

μ°Έμ‘°ν˜• λ³€μˆ˜μ— final이 λΆ™μ—ˆκ³ , μ°Έμ‘°ν˜• λ³€μˆ˜ data에 이미 참쑰값을 ν• λ‹Ήν–ˆμœΌλ―€λ‘œ 참쑰값을 λ³€κ²½ν•˜λŠ” 것은 λΆˆκ°€λŠ₯ν•˜λ‹€.

ν•˜μ§€λ§Œ... β€œμ°Έμ‘° λŒ€μƒμ˜ 값은 변경이 κ°€λŠ₯ν•˜λ‹€.”

생각해보면 λ‹Ήμ—°ν•œ 것이, 참쑰값이 κ³ μ •λ˜μ—ˆλ‹€λŠ” 말은 λ‹€λ₯Έ 객체λ₯Ό μ°Έμ‘°ν•  수 μ—†λ‹€λŠ” 말이지, κ·Έ μ•ˆμ˜ μΈμŠ€ν„΄μŠ€ λ³€μˆ˜λ₯Ό λ³€κ²½ν•  수 μ—†λ‹€λŠ” 말은 μ•„λ‹ˆλ‹€.

profile
도메인을 μ΄ν•΄ν•˜λŠ” λ°±μ—”λ“œ 개발자(feat. OOP)

0개의 λŒ“κΈ€