99클럽 코테 스터디 6일차 TIL final keyword, static keyword
728x90

Final Keyword 란

Java 에서 final keyword 는 유저(사용자) 를 제한한다.

final keyword 는 많은 부분에서 사용되는데 final keyword 는 아래 나온 내용에서 사용된다.

  • 변수
  • 메소드
  • 클래스

final keyword 는 변수와 함께 적용될 수 있는데, 값이 없는 final 변수를 공백 final 변수 또는 초기화 되지 않은 final 변수라고 한다.

이때는 생성자에서만 초기화 할 수 있다.

public class FinalKeyword{
    final String uninitializedValue;

    FinalKeyWord() {
        this.uninitializedValue = "Hello World";
    }
}
...

public class FinalKeyWordTest() {
    FinalKeyword fkw = new FinalKeyWord();
    System.out.println(fkw.uninitializedValue);
}
...
출력 결과물 : Hello World

또한 공백 final 변수는 정적 블록에서만 초기화되는 정적 변수일 수도 있음. 아래에서 자세하게 보자.

1. Java Final Variable

임의의 변수를 final 로 만들면 final variable 의 값을 변경할 수 있음.(상수가 되..)

ex)

public class Bike9 {
    final int speedLimit = 90; // final variable

    void run() {
        speedLimit = 400;
    }

    public static void main(String args[]) {
        Bike9 obj = new Bike9();
        obj.run();
    }
}
출력 : Compile Time Error남

2. Java Final Method

메소드를 final 로 만들면 이를 재정의 할 수 없음.

ex)

public class Bike{
    final void run() {System.out.println("running");}
}

public class Honda extends Bike{
    void run(){System.out.println("running safely with 100kmph");}

    public static void main(String args[]) {
        Honda honda = new Honda();
        honda.run();
    }
}
출력 : Compile Time Error

3. Java Final Class

final class Bike{}

class Honda1 extends Bike{
    void run() {
        System.out.println("running safely with 100kmph");
    }

    public static void main(String args[]) {
        Honda1 honda = new Honda1();
        honda.run();
    }
}
출력 : Compile Time Error

그러면 final method 는 상속됨?

ㅇㅇ

public class Bike{
    final void run() {
        System.out.println("running...");
    }
}

class Honda2 extends Bike{
    public static void main(String args[]) {
        new Honda2().run();
    }
}
출력: running...

그러면 static final 도 공백 final 변수이면 초기화 가능?

ㅇㅇ 가능. 대신에 static 안에서 초기화 해야함.

class A{
    static final int data; // static blank final variable
    static{ data = 50; }
    public static void main(String args[]){
        System.out.println(A.data);
    }
}

final parameter 라는 것도 있는데...

class Bike11{
    int cute(final int n) {
        n = n + 2; // n 이 final 이므로 변경이 안됨.
        n *= n;
    }
    public static void main(String args[]) {
        Bike11 b = new Bile11();
        b.cute(5);
    }
}
Compile Error

생성자 final 로 만들 수 있음?

?


Static

Static 이란?

  • 사전적 정의로는 정적인 이라는 뜻을 가지고 있음.
    • 사전적인 의미로만 봐도 불변한다는 걸 알 수 있다.. 막 건들면 에러날거 같은...
  • Java 에서는 최초 클래스를 로드할 때 메모리에 할당해 종료될 때 해제 되는 것을 의미한다.

메모리 할당?

JVM

위 글의 Runtime Data 영역을 보면 method area, heap area 가 보이는데 method area 설명을 보면

클래스 정보를 처음 메모리에 올릴 때 초기화 되는 대상을 저장하기 위한 영역

  • 올라가는 정보
    1. Field Information
      • member 변수에 대한 정보 (이름, 타입, 접근 지정자 등)
    2. Method Information
      • 메서드에 대한 정보(이름, 리턴타입, 파라미터, 접근 지정자 등)
    3. Type Information이렇게 설명이 되어 있는데 이때 static 변수가 method area 에 저장되고, GC의 관리를 받지 않고 프로그램 종료 시 까지 유지된다.

GC 의 대상은 Heap 영역이다.

Static Keyword 의 특징

  1. 클래스 레벨 공유
    • static 변수는 클래스의 모든 인스턴스에 의해 공유됨. 이 변수들은 클래스가 메모리에 로드될 때 생성되고, 프로그램이 종료될 때까지 유지됨.
  2. 메모리 효율
    • 같은 클래스의 모든 객체들이 하나의 static 변수를 공유하기 때문에 메모리 사용이 줄어듬.
  3. 인스턴스 없이 접근 가능
    • static 메서드나 변수는 객체의 인스턴스를 생성하지 않고도 호출할 수 있음. 클래스 이름을 통해 직접 접근 가능.
    • 이미 method area 에 있으므로 객체가 생성되기 전에 할당되어 있기 때문
public class MyClass{
    public static String staticValue = "HI";
    public static int staticMethod(int a, int b) {
        return a + b;
    }
}

public class TestClass {
    public static void main(String args[]) {
        String a = MyClass.staticValue;
        int resultA = MyClass.staticMethod(1,2);

        MyClass m1 = new MyClass();

        int resultB = m1.staticMethod(1,2);
    }
}

좋은데 왜 다 static 안함?

객체 지향 설계 위반

  • 캡슐화 저하
    static 변수는 클래스의 모든 인스턴스에 의해 공유됨. 이는 데이터 캡슐화를 저하시켜, 객체 간의 상호 작용을 예측하기 어렵게 만들 수 있음.
    객체 지향의 핵심은 각 객체가 독립적인 상태와 행동을 갖는건데 static 많이 쓰면 이 원칙이 박살남.

  • 의존성 문제
    static 메서드는 인스턴스 변수나 메서드에 접근할 수 없음.
    이로 인해 static 메서드가 많아지면, 클래스의 다른 비 static 부분과의 결합도가 낮아져, 객체 지향적 설계가 어려워짐.

테스트와 유지보수의 어려움이 있음

  • 테스트의 어려움
    static 변수나 메서드는 테스트가 어렵다. static 변수는 애플리케이션의 생명 주기 동안 초기화 되거나 변경된 값이 유지되기 때문에, 테스트 간 상태를 초기화 하기 어려워짐. ▶️ 격리된 테스트 환경을 만드는데 어려움을 가짐.

  • 유지보수 복잡성
    static 메서드나 변수가 많은 시스템은 시간이 지남에 따라 관리하기가 더 복잡해짐.
    static 요소들은 시스템의 다른 부분과 강하게 결합될 수 있고, 이로 인해 코드의 변경이 필요할 때 예상치 못한 부작용을 발생시킬 수 있음.

메모리 관리

  • 메모리 사용증가
    static 변수는 프로그램이 종료될 때 까지 메모리에 남아있음. 따라서, 많은 양의 데이터를 static 으로 관리하면서 메모리 사용량이 증가하고, 필요하지 않은 데이터도 계속 메모리를 차지하게 된다. ▶️ 장시간 실행되는 애플리케이션에서 문제가 될 수 있음.

동시성 문제

  • 스레드 안전 문제
    멀티스레드 환경에서 static 변수에 여러 스레드가 동시에 접근하게 되면 동시성 문제가 발생할 수 있음.▶️ 데이터의 일관성과 정확성을 보장하기 어렵게 만들며, 추가적인 동기화 처리가 필요하게 됨.

그럼 언제씀?

1. 공유된 상수

  • 여러 인스턴스에서 공통적으로 사용되는 상수 값은 static final 로 선언하여 사용함.
    public class MathConstants {
      public static final double PI = 3.14159;
    }

2. 유틸리티 메서드

  • 객체의 상태에 의존하지 않는 메서드, 즉 입력 값만으로 결과를 반환하는 순수 함수는 static 메서드로 선언이 됨.
    public class StringUtils {
    	public static boolean isEmpty(String s) {
    		return s == null || s.isEmpty();
    	}
    }

3. 싱글턴 패턴

최근에 DB Connection Pool 을 start up 되는 시점부터 잡아서 DB 점검일 때 DB 연결이 안되면 어플리케이션 전체가 실행 안되는 상황이 있었는데 기존 프레임워크에서 제공해주는 DataSource 를 지우고, Custom DataSource 를 만들어서 해결했는데 이렇게 싱글턴 패턴으로 만들어서 해결했음.

public class Singleton{
	private static Singleton instance;
	privatet Singleton() {}
	
	public static Singleton getInstance() {
		if(instance == null) {
			instance = new Singleton();
		}
		return instance;
	}
}

4. 클래스 초기화 블록

  • 클래스 변수를 초기화할 때 복잡한 로직이 필요한 경우 static 초기화 블록을 사용할 수 있음. 이 블록은 클래스가 메모리에 로드될 때 한 번만 실행됨.
    public class Configuration {
      public static int bufferSize;
      static {
          bufferSize = loadBufferSize();
      }
      private static int loadBufferSize() {
          // 복잡한 로직을 통해 버퍼 사이즈를 계산
          return 512;
      }
    }

5. 특정 리소스의 전역 접근

  • 애플리케이션 전반에서 공유되어야 하는 리소스나 서비스 객체 등을 관리할 때 사용됨.
public class DatabaseConnection {
    public static Connection connection = initializeDatabaseConnection();
}

 

static 의 사용은 객체 지향적인 설계를 저해할 수 있기 때문에, 공통 리소스의 접근이나 상태가 변하지 않는 메서드에 국한하여 사용하는 것이 바람직하다.

728x90