Final: 고정 - 수정 불가능
1. final 필드: 값이 변하지 않는다.
- 필드(클래스 내 변수)에 final예약어가 사용되면, 값이 변하지 않는다는 의미
- 언제 사용? 단위나 고정값을 사용할 때
2. final메서드: 상속(Override)되지 않는다.
- 메서드(클래스 내 함수)에 final 예약어가 사용된다면, Override(상속)가 되지 않는다는 의미
- 언제 사용? 해당 메서드가 꼭 한가지의 구현만으로만 다양한 곳에서 사용되는 경우
- 상속 받았다고, 상속받은 메서드를 너무 쉽게 Override하면, 해당 사용처서 side effect발생 가능
아래 코드는 `Member` 클래스에 정의된 final 메소드이다. add() 메서드에서는 나이에 10만 더하는 기능만 사용하고 싶다면 아래와 같이 final로 메소드 오버라이딩 하는 걸 방지할 수 있다.
public final void add(){
this.age += 10;
}
`Member` 객체를 상속받은 객체가 `add()` 함수를 오버라이딩해서 사이드이펙트를 막을 수 있다.
3. final클래스: 상속(Extends) 되지 않는다.
- 클래스에 final 예약어가 사용된다면, 상속되지 않는다는 의미 (extends를 사용할 수 없다.)
- 언제 사용? 디장니 패턴 원칙 "상속보다는 합성" - 상속은 잃는 것이 많다.
상속: Inheritance
class Animal {
public void hello() { // hello 로직이 바뀌었을 경우에 다른 Puppy 등의 객체에 영향을 준다 : 시부모님의 영향력
}
public void world() { // Cat 에서 밖으로 노출 : 부모의 빚
}
}
// Inheritance
class Cat extends Animal {
public void cat() {
this.hello();
}
}
합성: Comopsition
class CAnimal implements IAnimal {
public void hello() {
}
}
class BAnimal implements IAnimal {
public void hello() {
}
}
// Composition
class CCat {
// private CAnimal cAnimal = new CAnimal();
private IAnimal cAnimal = new BAnimal();
public void cat() {
cAnimal.hello();
}
}
극단적으로는, "사실상 모든 Class를 정의할 때 Final을 붙여도 된다." 라고 말하는 책도 있다.
Static: 정적
인스턴스화 필요 없이 바로 사용 가능
⭐️Static 메소드 안에서는 static 필드만 사용 가능
1. 정적 필드
인스턴스 없이 사용 가능한 필드: 정적 필드
2. 정적 메서드
인스턴스 없이 사용가능한 메서드: 정적 메서드
- 인스턴스 생성 없이 호출이 가능하여, 유틸리티 관련 메서드를 만드는데 유용하게 사용된다.
3. 정적 클래스
인스턴스 없이 사용 가능한 (Nested) 클래스: 정적 (Nested) 클래스
- 정적 (Nested) 클래스가 아니라면: 상위 클래스 인스턴스화를 해야하므로 아래 코드 같이 new new 두번 인스턴스화를 해야한다.
OuterClass.InnerClass innerObject = new OuterClass().new InnerClass();
- 정적 (Inner or Nested) 클래스라면
OuterClass.NestedStaticClass printer = new OuterClass.NestedStaticClass();
헷갈림 방지를 위한 정적 메서드, 정적 클래스 예시
유틸리티 메서드를 위해 Static 사용 시, 상속 및 Override방지를 위해 웬만해선 final도 같이 쓰는 편
`System.out.println`
유틸리티 메서드에서는 static이 사용되었고, 유틸리티 클래스에는 Final이 사용되었다.
유틸리티 클래스로 모두 Override를 방어(클래스가 final이라서 상속불가)할 수 있으므로 유틸리티 메서드에 final을 사용하지 않음
굳이 정적 메서드를 갖고 있는 클래스를 정적으로 정의할 필욘없다. 정적 메서드 내 필드만 정적 변수로 정의하면 된다.
유틸리티 메소드를 왜 static으로 정의하나?
유틸리티 메소드는 필드가 필요없음. 파라미터에만 의존
즉 유틸리티 메소드 == 정적메소드라고 생각하면 된다.
`System.out.println()` 같은 경우도 파라미터만 넘겨주는 유틸리티 함수이다.
정적 클래스와 정적 메서드의 관계
1. 정적 메서드는 정적 클래스 안에 위치할 필요가 없다.
2. 정적 Inner or Nested 클래스는 왜 쓰는가
- Inner or Nested 클래스에서 Outer 클래스의 정적 메서드나 정적 필드를 접근할 때, 정적 Inner or Nested 클래스 만이 Outer Class의 정적 필드인 hala에 접근할 수 있다.
오해하지말자, 정적 Inner or Nested 클래스는 인스턴스화하지 않고 쓸 수 있는게 아니다
정적 Inner or Nested 클래스도 인스턴스화가 가능하다.
상위 outer클래스의 인스턴스화 없이도, Inner or Nested클래스를 인스턴스화할 수 있단 것이다.
아래 코드로 이해해보자
public class OuterClass {
public static int hala = 10;
static class InnerClass {
public void publicFunction() {
System.out.println(hala);
}
}
private void hello() {
OuterClass.InnerClass instantiatedStaticClass = new OuterClass.InnerClass();
// X - OuterClass.InnerClass.publicFunction();
instantiatedStaticClass.publicFunction();
}
}
InnerClass를 상위 클래스 인스턴스화 없이 객체 생성 가능
상수 사용시 static final을 사용하는 이유
`public static final`와 같은 형태의 쓰임새를 많이 봤을 것이다.
전역에서 사용하며, 메모리 한 영역에 정적으로 할당하여 자원을 공유하고, 불변성을 보장하는 데이터를 의미한다.
즉, 자주 사용하는 자원을 효율적으로 불변성을 보장받고 사용하기 위해 이런 식으로 사용한다는 것을 알 수 있다.
따라서 `static final` 에서 static은 메모리에 계속 상주하기에 필요할 때만 사용하도록 static을 빼는 것이 더 합리적인 것이 아닌가? 라는 의구심이 든다.
상수라는게 불변이므로 매번 인스턴스를 말들 때마다 생성할 이유가 없음. 모든 인스턴스들이 final변수를 바라보면 모두 같은 값일 것이므로 굳이 인스턴스당 같은 값을 가지는 final 변수를 둘 필요가 없다는 것.
`static`이 붙었으므로 JVM에서 Static/Method 영역에 할당되어 메모리에 상주해 있으며, 스레드의 공유 영역으로 활용된다.
ref
'ASAC 웹 풀스택 > Spring Boot' 카테고리의 다른 글
Java 기본 문법 및 JVM 구성(12) - 다형성 (0) | 2024.09.29 |
---|---|
Java 기본 문법 및 JVM 구성(11) - Generic, Interface, Abstract Class (0) | 2024.09.29 |
Java 기본 문법 및 JVM 구성(9) - DTO, VO (0) | 2024.09.28 |
Java 기본 문법 및 JVM 구성(8) - 정적 팩토리 메서드 (1) | 2024.09.28 |
Java 기본 문법 및 JVM 구성(7) - Builder: 객체 생성의, 모든 경우의 수를 지원 (0) | 2024.09.28 |