article thumbnail image
Published 2022. 7. 18. 21:34

 

 

 

 

static(정적) 이란?

 

Java에서 static 키워드는 변수, 메소드, 블록 및 중첩 클래스에 사용할 수 있다.

 

정적 키워드가 붙은 멤버들은 인스턴스(객체)가 아니라 타입 자체에 속하는데,

이는 정적 멤버들의 인스턴스는 하나만 생성되며 해당 클래스의 모든 인스턴스에서 공유된다는 것을 의미한다.

 

따라서 각 인스턴스들이 공통적으로 같은 값을 유지해야하는 경우 사용된다.

 

 

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으로 만들라

복사했습니다!