코드에서 상수 선언이란 무엇일까.
객체를 상수로서 선언하면 어떤 의미가 있는지 탐구하였습니다.
나는 코딩할 때 final, const 선언을 즐겨한다. 변수를 상수로 선언함으로써 나중에 이 코드를 보게될 사람에게 “이건 변하지 않아요”라는 확신을 주고 싶었다. 이는 단순히 기본 데이터 타입들(int, float, double 등)에서는 한 번 선언을 하면서 할당하면 더 이상 값을 바꿀 수 없다.
하지만, 불현듯 생각이 든 것이 있다. Class를 이용하여 객체를 만들어 사용한다고 해보자. 이들은 캡슐화의 원칙에 의해서 Class 내의 변수들은 private로 선언 된다. 내부 상태를 참조 또는 제어하기 위해서는 으레 getter, setter를 사용한다. 어라? 그렇다면, “객체를 상수로 선언할 때 생성자(Constructor)로 내부 상태를 정의해준 뒤, setter로 변경하는 경우에는 허용이 될까?”라는 의문과 동시에 “이 것이 허용 된다면 정녕 기본 자료형이 아닌 객체를 상수로서 선언하는 의미가 존재할까?”라는 생각이 혼재했다.
먼저, Java를 이용하여 이를 실험해보았다. ‘Car'라는 객체를 정의하고 여기에 내부 상태로 brand, modelName을 주어준다. 그 다음, 메소드들을 만들어 Class의 뼈대를 맞춰준다.
package me.cocoblue.dto;
public class Car {
public String brand;
public String modelName;
public Car() {
}
public Car(String brand, String modelName) {
this.brand = brand;
this.modelName = modelName;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getModelName() {
return modelName;
}
public void setModelName(String modelName) {
this.modelName = modelName;
}
@Override
public String toString() {
return "Car{" +
"brand='" + brand + '\'' +
", modelName='" + modelName + '\'' +
'}';
}
}
캡슐화의 원칙이 있지만, 테스트를 위해서 변수들을 public으로 선언한다. 원래는 private으로 선언해야할 것이다.
그 다음 3가지 케이스를 테스트한다.
- 상기 객체를 상수로 선언할 때 생성자로 값들을 모두 정의해준 뒤, 직접 접근의 형태로 값들을 변경해본다.
- 상기 객체를 상수로 선언하고, setter를 통해서 값을 정의해본다.
- 상기 객체를 변수로서 선언한다.
package me.cocoblue;
import me.cocoblue.dto.Car;
public class Main {
public static void main(String[] args) {
final Car constCarOne = new Car("A", "NamedCarOne");
final Car constCarTwo = new Car();
Car freeCar = new Car();
System.out.println(constCarOne);
// 안 돼야하지 않을까?
constCarTwo.setBrand("B");
constCarTwo.setModelName("NamedCarTwo");
System.out.println(constCarTwo);
// 안 돼야하지 않을까?
constCarTwo.brand = "B-1";
constCarTwo.modelName = "NamedCarTwo-1";
System.out.println(constCarTwo);
freeCar.setBrand("C");
freeCar.setModelName("NamedCarThree");
System.out.println(freeCar);
}
}이 경우 출력은 어떻게 될까?

사진과 같은 출력이 나오게 된다.
즉, Java에서 객체 변수에 붙은 final은 변수가 가리키는 대상(참조값)을 바꿀 수 없다는 뜻이지, 그 대상의 내부 내용(필드값)을 바꿀 수 없다는 뜻이 아닌 것이다.
쉽게 말하면, 각 객체를 선언하면 메모리 공간에 데이터를 적재하는데, 적재하는 데이터의 주소를 바꿀 수 없다는 것이다. 또한 이 결과는 Node에서도 동일한 결과를 나타내고 있다.
그렇다면, 객체를 상수로서 선언하는 것은 어떤 의미를 가질까? 내가 생각하기로는 이렇다.
코드를 작성할 때 그냥 반사적으로 final을 사용하고 그랬는데, 실제로는 큰 의미가 없다는 사실을 알게 되었다. 하지만, 코드 컨벤션과 유지보수의 관점에서 봤을 때 다른 날에 코드를 봐야할 때 선언한 변수가 바뀔리 없다는 믿음을 주는 선언으로 사용하면 좋을 것 같다는 생각을 하게 되었다.
예제 소스코드는 아래에서 확인할 수 있다.