static 변수, final 변수

황희윤·2023년 11월 7일

static 변수

클래스(class) 변수로 클래스가 메모리에 적재(load)될 때 한 번만 메모리에 할당되는 변수

static 특징

  1. 생명주기 : 프로그램의 실행부터 종료까지

    • 클래스프로그램의 시작과 동시에 메모리에 적재되는데 클래스 변수 역시 이 때 클래스와 함께 자동으로 메모리의 static 영역에 할당된다.
    • 즉, 클래스가 메모리에서 해제되는 시점, 즉 프로세스가 종료되는 시점에 클래스 변수의 메모리가 해제된다.
  2. 전역 변수의 성격을 갖는다.

    • 자주 변하지 않는 값이나 공용 자원에 접근하면서 매번 메모리에 적재하거나 값을 읽어 들이는 것보다 전역 변수를 사용하는게 효율적이다.
  3. JVM메서드 영역(method area)에 저장된다.

    • JVM의 메서드 영역에는 컴파일된 코드나 메서드의 바이트 코드, 클래스 변수, 클래스 메서드를 저장하고 있어 객체 생성과 관계없이 언제든지 접근할 수 있다.
  4. 모든 인스턴스에 공통적으로 사용해야 할 경우 static을 붙인다.

    • static이 붙지 않은 메서드나 변수의 경우 객체가 생성될 때마다 호출되어 서로 다른 값을 가지고 있을 수 있습니다. 그렇기 때문에 각 객체들에서 공통적으로 하나의 값이 유지되어야 할 경우 static을 유용하게 사용할 수 있습니다.
    • 동일한 클래스로부터 생성된 모든 객체클래스(static) 변수를 공유한다.
  5. 객체지향은 모듈화된 객체를 전면에 내세우기 때문에 프로그램 전체에서 동일하게 사용되는 전역 변수의 필요성은 줄어든다.

static 장단점

😇 장점 : 공용 자원에 대한 접근

👿 단점 : 위의 이유로 static은 테스트를 힘들게 할 수 있는 요인이 된다.

❗️주의사항 : 다중 스레드 환경에서 공유된 데이터에 대한 동기화가 필요하다. 여러 스레드에서 동시에 접근이 일어날 수 있기 때문이다.

🖥 올바른 사용 : static 사용은 최소화하고, 주로 속성 정보를 변경하지 않는 방식(final)을 사용한다.

static 메서드

  • 클래스와 함께 자동으로 메모리의 static 영역에 생성되어서, static 메서드는 객체 생성할 필요 없이 사용 가능하다.

  • 🚯 Garbage Collector가 처리하지 못한다.

    • 일반적인 메서드는 객체를 생성하면 메모리의 Heap 영역에 올라가게 된다. 메모리의 이 Heap 영역은 Garbage Collector에 의해 자동으로 관리되지만 static 메서드는 static 영역에 남게 되어 GC의 영향을 받지 않는다.
    • 따라서 static 메서드를 무분별하게 사용하는 것은 메모리에 좋지 않다.
  • static 메서드 내에서는 this를 사용할 수 없다(❌).

  • java.lang.Math 클래스의 메서드들은 주로 static으로 선언되어 있다. 왜냐하면 자주 사용하는 클래스이기 때문에 프로세스 실행 중에 따로 객체를 생성하지 않고도 바로 사용할 수 있도록 한 것이다.

  • static 메서드는 몸체가 있는 메서드(구현 기능이 있는 메서드)에서만 사용 가능하기 때문에 abstract 제어자와는 함께 사용할 수 없다(❌).

public class Main {
 
    public void print(){
        System.out.print("이게 실행될까요"); // (❌)
    }
 
    public static void main(String[] args){
        print();
    }
}
  • 위의 코드는 컴파일 에러를 발생시킨다. 왜냐하면 print 메서드가 static이 아니라서 Main 클래스 객체가 만들어진 후에야 사용이 가능하다.

final 변수

  • 값을 변경할 수 없는 상숫값

  • 값을 재할당 할 수 없다.

  • final 변수의 이름은 관례적으로 대문자를 많이 사용한다.

    • final int PERSON_NUMB = 10;
  • final 은 해당 변수의 재할당만을 막아줄 뿐, 참조하고 있는 객체 내부의 상태가 변할 수 있다.

final List<Integer> numbers = new ArrayList<>(Arrays.asList(1, 2, 3));
System.out.println(numbers); // [1, 2, 3]

numbers.add(4);
System.out.println(numbers); // [1, 2, 3, 4]
  • 위의 코드에 불변성을 지키고 싶으면 Collection을 사용하거나 List.of()를 사용한다.
final List<Integer> numbers = Collections.unmodifiableList(new ArrayList<>(Arrays.asList(1, 2, 3)));
System.out.println(numbers); // [1, 2, 3]

// 아래의 코드는 변경을 시도하면 예외가 발생합니다.
numbers.add(4); // UnsupportedOperationException 발생


// List.of() 사용
final List<Integer> numbers = List.of(1, 2, 3);
System.out.println(numbers); // [1, 2, 3]

// 아래의 코드는 변경을 시도하면 예외가 발생합니다.
numbers.add(4); // UnsupportedOperationException 발생
profile
HeeYun's programming study

0개의 댓글