친구들이랑 게임을 하다보면 찐막? 이라고 한판 더하는게 국룰이다. (물론 찐*N + 막 이 있긴하지만)
저말은 곧? "이것만하고 무조건 끈다!" 라는 거다. final
이 그렇다 ㅎㅎ..
스프링을 쓰다보면 생성자주입(DI)을 하기위해 final
을 사용하여 주입하는 경우가 많다.
@Service
@RequiredArgsConstructor
public class UserService {
//final을 활용한 생성자 주입
private final UserRepository userRepository;
private final MemberService memberService;
public void register(String name) {
userRepository.add(name);
}
}
final은 "최종적인" 이라는 의미이다.
즉, 해당 객체에 값이 저장되면 최종적인 값이 되므로, 수정이 불가능하다는 의미이다.
final 키워드는 변수, 메서드, 클래스를 선언할 때 사용되며 모두 재할당이 불가능하다는 특징이 있다.
final 변수의 값은 한 번만 설정할 수 있음을 의미하고 초기화 이후에는 값을 변경할 수 없다. 이는 데이터의 불변성을 보장하고, 코드의 예측 가능성과 안정성을 높여준다.
public class FinalVariableExample {
private final int number;
public FinalVariableExample(int number) {
this.number = number; // 생성자에서 초기화
}
public static void main(String[] args) {
final int number = 10;
number = 20; // 컴파일 오류: final 변수는 값을 변경할 수 없다.
}
}
final 메서드는 서브클래스에서 오버라이드할 수 없다. 이는 메서드의 동작을 보장하고, 의도치 않은 수정으로 인한 오류를 방지할 수 있다.
public class ParentClass {
public final void display() {
System.out.println("This is a final method.");
}
}
public class ChildClass extends ParentClass {
// 컴파일 오류: final 메소드는 오버라이드할 수 없다.
@Override
public void display() {
System.out.println("Trying to override.");
}
}
final 클래스는 상속될 수 없다. 이는 클래스의 구현을 고정하고, 확장을 통한 변경을 방지한다.
public final class FinalClass {
// 클래스 내용
}
// 컴파일 오류: final 클래스는 상속할 수 없다.
public class SubClass extends FinalClass {
// 서브클래스 내용
}
즉, 재할당이 불가능해진다.
혹여나 누군가가 해당 변수를 변경하는 경우 컴파일타임에서 오류가 발생하기 때문에 값이 변경되는것을 쉽게 감지할 수 있고 방지하기도 편하다.
동시성 환경(멀티 쓰레드 환경)에서 final로 불변객체를 만들어서 여러 스레드가 동시에 접근해도 동일한 값을 보장받을 수 있다.
객체의 변화를 감지할 필요가 없으므로 가비지 컬렉터가 객체를 스캔할때와 제거할 때의 횟수가 줄어들기 때문에 성능적인 이점을 보인다.
final을 쓰는 경우 컴파일 시에 조금 특별한 일이 벌어진다.
public class Example {
public static final String CONSTANT = "상수";
}
public class Test {
public void printConstant() {
System.out.println(Example.CONSTANT);
// "상수" 문자열이 직접 코드에 삽입됨
}
}
이는 컴파일타임에서 최적화가 진행되기 때문이다.
상수로 최적화 : 컴파일러는 final 변수는 컴파일러가 컴파일 시점에 해당 값을 알고 있으며, 이 값을 코드에 직접 삽입할 수 있다. 이는 해당 값을 사용하는 모든 코드에 실제 값이 삽입된다는 것을 의미한다.
불변성 유지 : final 변수는 초기화 후 변경할 수 없으므로 런타임에 final 변수의 값을 변경하지 않음을 보장한다.
메서드 호출 최적화 : final 메서드는 오버라이드될 수 없으므로, JVM은 메서드 호출을 정적 바인딩으로 처리할 수 있다. 이는 런타임에 메서드 호출 성능을 향상시킨다.
static final은 클래스 수준의 변수로서 메모리에 단 한 번 할당되고, 그 이후에는 값이 변경되지 않는 특성을 가지고 있다.
static : 객체마다 가질 필요가 없는 공용으로 사용하는 필드 혹은 인스턴스 필드를 포함하지 않는 메소드
final : 한 번 값이 정해지고 나면 값을 바꿀 수 없는 필드
static final : 모든 영역에서 고정된 값으로 사용하는 상수