static(정적) 이란?
Java에서 static 키워드는 변수, 메소드, 블록 및 중첩 클래스에 사용할 수 있다.
정적 키워드가 붙은 멤버들은 인스턴스(객체)가 아니라 타입 자체에 속하는데,
이는 정적 멤버들의 인스턴스는 하나만 생성되며 해당 클래스의 모든 인스턴스에서 공유된다는 것을 의미한다.
따라서 각 인스턴스들이 공통적으로 같은 값을 유지해야하는 경우 사용된다.
Java8 이후 Static Object는 heap 영역에서 관리되며, 참조를 잃은 정적 오브젝트는 GC 대상이 될 수 있다.
(참고) https://jgrammer.tistory.com/144
The static Fields (Or Class Variables)
정적 필드 (또는 클래스 변수)
static 필드를 선언하면 해당 필드는 힙 메모리에 저장되며
해당 클래스의 모든 인스턴스에서 공유된다.
아래의 예시를 살펴보자.
여러 인스턴스 변수가 있는 Fruit 클래스가 있다.
Fruit 클래스로 새 객체를 만들면 객체마다 고유한 인스턴스 변수의 값이 생길 것이다.
이러한 경우에 만약 내가 초기화 된 Fruit 클래스 객체의 수를 알고싶고
그 값을 모든 인스턴스에서 공유하고 싶다면 정적 변수를 사용하면 된다.
public class Fruit {
// 인스턴스 변수
private String name;
private String color;
// 정적 변수
static int numberOfFruits;
public Fruit(String name, String color) {
this.name = name;
this.color = color;
numberOfFruits++;
}
// getters and setters
}
이제 Fruit 클래스의 모든 객체가 초기화될 때 마다 numberOfFruits 값은 1씩 증가하게 된다.
아래 테스트코드로 확인해 볼 수 있다.
@Test
public void Fruit객체가초기화되면_staticCounter가증가한다() {
new Fruit("Banana", "Yellow");
new Fruit("Apple", "Red");
assertEquals(2, Fruit.numberOfFruits);
}
static 필드를 사용하는 이유
- 변수의 값이 객체와 무관할 때
- 값이 모든 객체에서 공유되어야할 때
키포인트
- 정적 변수는 클래스에 속하기 때문에 클래스 이름을 사용하여 직접 접근할 수 있다. (객체 참조가 필요하지 않다.)
- 객체 초기화 없이 정적 변수에 접근할 수 있다.
- 객체 참조를 사용하여 정적 필드에 접근할 수 있지만 사용하지 않는 것이 좋다.
- 인스턴스 변수인지 클래스 변수인지 파악하기 어렵기 때문.
- banana.numberOfFruits (X) Fruit.numberOfFruits(O)
The static Methods (Or Class Methods)
정적 메서드 (또는 클래스 메서드)
정적 필드와 같이 정적 메서드도 클래스에 속한다.
따라서 클래스의 객체를 생성하지 않고 메서드를 호출할 수 있다.
아래 예시를 살펴보자.
public static void setNumberOfFruits(int numberOfFruits) {
Fruit.numberOfFruits = numberOfFruits;
}
numberOfFruits 변수의 setter를 static으로 생성하면
새 객체를 생성하지 않고도 공통으로 사용하는 변수의 값을 변경할 수 있다.
또는 아래와 같이 유틸 클래스를 생성할 때 사용된다.
// DateTime 처리와 관련 된 메서드를 모아놓은 유틸 클래스
public class DateTimeUtils {
public static Timestamp timestampOf(LocalDateTime time) {
return time == null ? null : Timestamp.valueOf(time);
}
public static LocalDateTime dateTimeOf(Timestamp timestamp) {
return timestamp == null ? null : timestamp.toLocalDateTime();
}
}
static 메서드를 사용하는 이유
- 객체에 의존하지 않고 정적 변수 및 정적 메서드에 접근/조작하기 위해
- 유틸 클래스에서 많이 사용됨
키포인트
- 정적 메서드는 컴파일 시 메모리에 저장되기 때문에 오버라이딩 불가
- 추상 메서드는 static으로 생성 불가
- this, super 키워드 사용 불가
A static Block
정적 블록
미리 정의해둔 값으로 객체를 초기화하는 경우 사용된다.
public class StaticBlockDemo {
public static List<String> ranks = new LinkedList<>();
static {
ranks.add("Lieutenant");
ranks.add("Captain");
ranks.add("Major");
}
static {
ranks.add("Colonel");
ranks.add("General");
}
}
A static Class
정적 클래스
클래스 내에 생성하는 정적 내부(중첩) 클래스
한 곳에서만 사용할 요소를 그룹화하거나 싱글톤 객체를 생성하는 경우 사용된다.
중첩 클래스는 자신을 감싼 바깥 클래스에서만 쓰여야하며, 그 외의 쓰임새가 있다면 톱레벨 클래스로 만들어야한다.
싱글톤 객체 생성 예시
public class Singleton {
private Singleton() {}
private static class SingletonHolder {
public static final Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
}
정적 클래스를 사용하는 이유
- 한 곳에서만 사용되는 그룹화 클래스는 캡슐화를 증가시킴
- 흔히 바깥 클래스와 함께 쓰일 때 유용한 public helper class로 사용됨
- 중첩 클래스가 outer 클래스의 인스턴스 멤버에 대해 접근하지 않는 경우 static 으로 선언하는 것이 좋다.
- 바깥 클래스에 연결되지 않기 때문에 힙이나 스택 메모리가 필요하지 않으므로 최적화됨
- static을 생략하면 바깥 인스턴스로의 숨은 외부 참조를 갖게 되어 GC가 바깥 클래스의 인스턴스를 수거하지 못하게 되면 메모리 누수가 생길 수 있다.
키포인트
- 정적 중첩 클래스 vs 내부 클래스(Non-static Nested Class)
- static 중첩 클래스는 outer 클래스의 인스턴스 멤버에 접근할 수 없다. (개체의 참조를 통해서 접근)
- static 중첩 클래스는 outer 클래스의 모든 static 멤버에 접근할 수 있다.
- 참고 자료
https://www.baeldung.com/java-static
이펙티브 자바, 아이템 24 멤버 클래스는 되도록 static으로 만들라
'Java' 카테고리의 다른 글
[Java] Wrapper class 와 일급 컬렉션 (1) | 2022.08.25 |
---|---|
[Java] Reflection 이란? (0) | 2022.08.15 |
[Java8] 비동기 처리 CompletableFuture (0) | 2022.06.17 |
[Java] Sync vs. Async / Blocking vs. Non-Blocking (0) | 2022.06.14 |
[Java] Builder Design Pattern 빌더 패턴 (0) | 2022.02.20 |