static 키워드의 개념과 잘못 사용했을 때 발생할 수 있는 문제에 대해 설명해주세요.
static 키워드는 정적
또는 고정된
이라는 의미이며, static이라는 키워드를 사용하여 static변수와 static메소드를 만들 수 있는데 다른 말로는 정적필드
와 정적메소드
라고 하며 이 둘을 합쳐 정적 멤버
라고 한다.
정적 필드와 정적 메소드는 객체에 소속된 멤버가 아니라 클래스에 고정된 멤버이다. 그렇기에 클래스 로더가 클래스를 로딩해서 메모리 메소드 영역에 적재할때 클래스 별로 관리된다. 따라서 클래스의 로딩이 끝나는 즉시 바로 사용할 수 있다.
메소드 영역(Method Area): JVM이 시작할 때 생성되는 영역으로 JVM에 의해 사용된다. 이 영역에는 각 클래스와 인터페이스의 실행에 필요한
바이트 코드, 이름, 데이터 타입, 상수, static 변수, 공유 자원 등이 저장
된다.힙 영역(Heap Area):
모든 객체와 배열이 이 영역에 할당
된다. 힙 영역은 JVM의 시작과 동시에 할당되며, 자바 런타임에 동적으로 할당되고 해제된다. 즉,new 키워드를 통해 생성된 객체는 모두 힙 영역에 생성
되며,가비지 컬렉터에 의해 이 영역의 불필요한 객체들이 정리
된다.스택 영역(Stack Area): 스택 영역은 각
스레드가 호출하는 메소드에 대한 정보를 저장
하는 영역이다. 메소드가 호출되면 스택 프레임이라는 블록이 스택 영역에 생성되며, 이 블록은 지역 변수, 매개 변수, 중간 연산 결과 등 메소드의 작업을 위한 데이터를 포함한다. 메소드가 작업을 완료하면 해당 스택 프레임은 스택에서 제거된다.
위의 그림과 같이 static 키워드로 생성된 정적멤버들은 Heap 영역이 아닌 static 영역 (Class 영역)
에 할당된다. static 영역에 할당된 메모리는 모든 객체가 공유하여 하나의 멤버를 어디서든 참조할 수 있는 장점
을 가지지만 가비지 컬렉터의 관리 영역 밖에 존재하기 때문에 static영역에서 있는 멤버들은 프로그램이 종료시까지 메모리에 할당된 채로 존재하게 된다.
그렇기에 static을 너무 남발하게 되면 만들고자하는 시스템에 악영향
을 줄 수 있다.
static
을 사용하면 객체 지향의 캡슐화, 상속, 다형성을 활용하기 어려워진다.static 메소드나 변수
는 보통 전역상태를 나타내기 때문에 테스트시 원하는 상태로 쉽게 변경할 수 없기 때문이다.public class Main {
public static void main(String args[]) {
System.out.println(Static.staticStr);
//System.out.println(Static.str); //Non-static field 'str' cannot be referenced from a static context
Static.staticMethod();
Static staticInstance = new Static();
System.out.println(staticInstance.str);
staticInstance.method();
}
}
public class Static {
public static String staticStr = "Hello, I'm static string";
public String str = "Hello, I'm string";
public static void staticMethod() {
System.out.println("Hello I'm static method");
System.out.println(staticStr);
//System.out.println(str); //Non-static field 'str' cannot be referenced from a static context
}
public void method() {
System.out.println("Hello I'm method");
System.out.println(staticStr);
System.out.println(str);
}
}
위의 코드에서 staticMethod
살펴보면 static 변수 staticStr
는 호출가능하지만 str
변수를 호출하지 못한다.
하지만 method
에서는 staticStr
와 str
둘 다 호출이 가능한 걸 확인할 수 있다.
그리고 Main
메소드를 살펴보면 static 메소드나 변수는 클래스명.변수
또는 클래스명.메소드명
로 바로 호출할 수 있지만 str
, method
는 new 연산자를 통한 객체 참조를 통해 호출할 수 있다.