์๋ฐ์๋ final์ด๋ผ๋ ํค์๋๊ฐ ์์ต๋๋ค. ํด๋์ค, ๋ฉ์๋, ๋ณ์(๋ฉ์๋ ๋งค๊ฐ๋ณ์ ํฌํจ)์ ์ ์ฉํ ์ ์์ต๋๋ค. ํด๋์ค์ ๊ฒฝ์ฐ final ํค์๋๋ ํด๋์ค๊ฐ ํ์ ํด๋์ค๋ฅผ ๊ฐ์ง ์ ์์์ ์๋ฏธํฉ๋๋ค. ์ฆ, ์์์ด ๊ธ์ง๋ฉ๋๋ค... ์ด๋ ๋ณ๊ฒฝ ๋ถ๊ฐ๋ฅํ(๋ณ๊ฒฝ ๋ถ๊ฐ๋ฅํ) ๊ฐ์ฒด๋ฅผ ์์ฑํ ๋ ์ ์ฉํฉ๋๋ค. ์๋ฅผ ๋ค์ด, String ํด๋์ค๋ final๋ก ์ ์ธ๋ฉ๋๋ค.
public final class String {
}
class SubString extends String { // Compilation error
}
๋ํ ์ต์ข
์์ ์๋ ์ถ์ ํด๋์ค(ํค์๋ abstract๊ฐ ์๋ ํด๋์ค)์๋ ์ํธ ๋ฐฐํ์ ์ธ ๊ฐ๋
์ด๊ธฐ ๋๋ฌธ์ ์ ์ฉํ ์ ์๋ค๋ ์ ์ ์ ์ํด์ผ ํฉ๋๋ค. ์ต์ข
๋ฉ์๋์ ๊ฒฝ์ฐ ํ์ ์๋ ํด๋น ๋ฉ์๋๋ฅผ ํ์ ํด๋์ค์์ ์ฌ์ ์ํ ์ ์์์ ์๋ฏธํฉ๋๋ค. ์ด๋ ์๋ ๊ตฌํ์ ๋ณ๊ฒฝ์ ๋ฐฉ์งํ๋ ค๋ ๊ฒฝ์ฐ์ ์ ์ฉํฉ๋๋ค.
public class SuperClass {
public final void printReport() {
System.out.println("Report");
}
}
class SubClass extends SuperClass {
public void printReport() { //Compilation error
System.out.println("MyReport");
}
}
๊ธฐ๋ณธ ์ ํ์ ๋ณ์์ ๊ฒฝ์ฐ final ํค์๋๋ ํ ๋ฒ ํ ๋น๋ ๊ฐ์ ๋ณ๊ฒฝํ ์ ์์์ ์๋ฏธํฉ๋๋ค. ์ฐธ์กฐ ๋ณ์์ ๊ฒฝ์ฐ ๊ฐ์ฒด๊ฐ ํ ๋น๋ ํ์๋ ํด๋น ๊ฐ์ฒด์ ๋ํ ์ฐธ์กฐ๋ฅผ ๋ณ๊ฒฝํ ์ ์์์ ์๋ฏธํฉ๋๋ค. ์ด๊ฑด ์ค์ํ๋ค! ์ฐธ์กฐ๋ ๋ณ๊ฒฝํ ์ ์์ง๋ง ๊ฐ์ฒด์ ์ํ๋ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค. Java 8์ ์ฌ์ค์ ์ต์ข
์ด๋ผ๋ ์๋ก์ด ๊ฐ๋
์ ๋์
ํ์ต๋๋ค. ๋ณ์(๋ฉ์๋ ๋งค๊ฐ๋ณ์ ํฌํจ)์๋ง ์ ์ฉ๋ฉ๋๋ค. ๊ฒฐ๋ก ์ final ํค์๋๊ฐ ์์์๋ ๋ถ๊ตฌํ๊ณ ๋ณ์์ ๊ฐ์ ์ด๊ธฐํ ํ์ ๋ณ๊ฒฝ๋์ง ์๋๋ค๋ ๊ฒ์
๋๋ค. ์ฆ, ์ปดํ์ผ ์ค๋ฅ ์์ด ์ด๋ฌํ ๋ณ์์ final ํค์๋๋ฅผ ์ ์ฉํ ์ ์์ต๋๋ค. ํจ๊ณผ์ ์ผ๋ก ์ต์ข
๋ณ์๋ ๋ก์ปฌ ํด๋์ค(๋ก์ปฌ ๋ด๋ถ ํด๋์ค), ์ต๋ช
ํด๋์ค(์ต๋ช
๋ด๋ถ ํด๋์ค) ๋ฐ ์คํธ๋ฆผ(Stream API) ๋ด์์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
public void someMethod() {
// In the example below, both a and b are effectively final, since they are assigned values only once:
int a = 1;
int b;
if (a == 2) b = 3;
else b = 4;
// c is NOT effectively final since its value changes
int c = 10;
c++;
Stream.of(1, 2).forEach(s-> System.out.println(s + a)); // OK
Stream.of(1, 2).forEach(s-> System.out.println(s + c)); // Compilation error
}
์, ์ ์ ์ธํฐ๋ทฐ๋ฅผ ํด๋ณด์. ๊ฒฐ๊ตญ CodeGym ๊ณผ์ ์ ์ด์ํ๋ ๋ชฉํ๋ Java ๊ฐ๋ฐ์๊ฐ ๋์ด ํฅ๋ฏธ๋กญ๊ณ ๋ณด์๊ฐ ์ข์ ์ง์
์ ์ฐพ๋ ๊ฒ์
๋๋ค. ์, ์์ํ๊ฒ ์ต๋๋ค.
-
์ต์ข ์ ์ธ๋ ๋ฐฐ์ด์ ๋ํด ๋ฌด์์ ๋งํ ์ ์์ต๋๊น?
-
์ฐ๋ฆฌ๋ String ํด๋์ค๊ฐ ๋ถ๋ณ์ด๋ผ๋ ๊ฒ์ ์๊ณ ์์ต๋๋ค. ํด๋์ค๋ final๋ก ์ ์ธ๋ฉ๋๋ค. ๋ฌธ์์ด ๊ฐ์ final ํค์๋๋ก ํ์๋ char ๋ฐฐ์ด์ ์ ์ฅ๋ฉ๋๋ค.
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
๊ฐ์ฒด์ ๋ํ ์ฐธ์กฐ๋ฅผ ๋ณ๊ฒฝํ์ง ์๊ณ String ๊ฐ์ฒด์ ๊ฐ์ ๋ฐ๊ฟ ์ ์์ต๋๊น? ์ค์ ๋ฉด์ ์ง๋ฌธ์
๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ฐ์ต์ ๋ฐ๋ฅด๋ฉด ๋ง์ ํ๋ณด์๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ๋๋ตํ์ง ์์ต๋๋ค. ํนํ ์ฐธ์กฐ ๋ณ์์ ๋ํด final ํค์๋๊ฐ ์ฌ์ฉ๋๋ ๋ฐฉ์์ ์ดํดํ๋ ๊ฒ์ ๋งค์ฐ ์ค์ํฉ๋๋ค. ๊ณ ๋ฏผํ๋ค๊ฐ ์ฝ๋์งํ์ ์์ ๋ถํ ํ๋ ํ ๊ฒ์. ํ
์คํธ ํธ์ง๊ธฐ๋ฅผ ํด๋ฆญํ๋ฉด ๋ด์ฉ์ ํ์ํ๊ฑฐ๋ ์จ๊ธธ ์ ์๋ ๋ธ๋ก์ ์ถ๊ฐํ ์ ์๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ์ญ์์ค. ๋ต๋ณ:
-
๋ฐฐ์ด์ ๊ฐ์ฒด์ด๋ฏ๋ก final ํค์๋๋ ๋ฐฐ์ด์ ๋ํ ์ฐธ์กฐ๊ฐ ํ ๋น๋๋ฉด ์ฐธ์กฐ๋ฅผ ๋ณ๊ฒฝํ ์ ์์์ ์๋ฏธํฉ๋๋ค. ์ฆ, ๊ฐ์ฒด์ ์ํ๋ฅผ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
final int[] array = {1, 2, 3, 4, 5}; array[0] = 9; // OK, because we're changing the contents of the array: {9, 2, 3, 4, 5} array = new int[5]; // Compilation error
-
๊ทธ๋ ์ฐ๋ฆฌ๋ ํ ์์์ด. ๊ฐ์ฅ ์ค์ํ ๊ฒ์ ๊ฐ์ฒด์ ํจ๊ป ์ฌ์ฉ๋ ๋ ๊น๋ค๋ก์ด ์ต์ข ํค์๋๊ฐ ๋ฌด์์ ์๋ฏธํ๋์ง ์ดํดํ๋ ๊ฒ์ ๋๋ค. Reflection API๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ์ ๋ฐ๊ฟ ์ ์์ต๋๋ค.
import java.lang.reflect.Field;
class B {
public static void main(String[] args) throws Exception {
String value = "Old value";
System.out.println(value);
// Get the String class's value field
Field field = value.getClass().getDeclaredField("value");
// Make it mutable
field.setAccessible(true);
// Set a new value
field.set(value, "CodeGym".toCharArray());
System.out.println(value);
/* Output:
* Old value
* CodeGym
*/
}
}
์ด๋ฐ ์์ผ๋ก ๊ธฐ๋ณธ ์ ํ์ ์ต์ข
๋ณ์๋ฅผ ๋ณ๊ฒฝํ๋ ค๊ณ ์๋ํ๋ค๋ฉด ์๋ฌด ์ผ๋ ์ผ์ด๋์ง ์์์ ๊ฒ์
๋๋ค. ์๋ฅผ ๋ค์ด ์ต์ข
int ํ๋๊ฐ ์๋ Java ํด๋์ค๋ฅผ ๋ง๋ค๊ณ Reflection API๋ฅผ ์ฌ์ฉํ์ฌ ํด๋น ๊ฐ์ ๋ณ๊ฒฝํด ๋ณด์ญ์์ค. ๋ชจ๋์๊ฒ ํ์ด์ ๋น๋๋ค!