본문 바로가기
IT 개인 공부/Java

[JAVA] Static 이란?

by Libi 2021. 7. 13.
반응형

자바로 프로그래밍을 하다 보면 다음과 같은 Static 키워드를 접해봤을 것이다.

public static void main(String[] args) { ... }

 

상당히 중요한 개념이기 때문에 Static에 대해서 한 번 공부 및 정리해보도록 하자

 

Static은 '정적', '고정된'이라는 의미를 가지며 Static 변수와 Static 메서드로 사용할 수 있다. 이를 합쳐서 정적 멤버라고 부른다.

그렇다면 일반적인 멤버와 Static 키워드가 붙은 정적 멤버의 차이는 무엇일까?

일반적인 멤버는 자신들이 선언된 클래스의 객체를 통해서 접근할 수 있는 반면, 정적 멤버는 객체 없이 접근할 수 있다. (물론 객체를 통해서도 접근이 가능하다)

간단한 예시로 Math 클래스의 변수나 메서드를 사용할 때 우리는 따로 객체를 생성하지 않고 사용하였다.

public class Main {
	public static void main(String[] args) {
		System.out.println(Math.PI);
		System.out.println(Math.max(10, 30));
	}
}

 

이는 Math 클래스의 멤버들이 Static으로 선언되어 있기 때문이다. (대부분의 Util 클래스는 Static으로 선언되어 있다)

 

그렇다면 객체 없이 접근이 가능한 이유는 무엇일까?

정적 멤버는 객체에 소속된 멤버가 아니라 클래스 자체에 고정된 멤버이기 때문이다.

일반적인 멤버는 그 멤버를 가지는 객체가 생성될 때 메모리에 적재되는 반면, 정적 멤버는 .class 파일이 Class Loader를 통해 메모리 영역에 적재될 때 함께 적재되기 때문에 적재가 완료되는 시점부터 바로 사용할 수 있다.

그렇다면 객체 선언이 필요 없는 Static 멤버들을 사용하는 게 항상 효율적인 것이 아닌가?라고 의문이 들 수 있다.

한번 잘 생각해보면 비효율적인 상황을 쉽게 떠올릴 수 있을 것이다. 일반 멤버는 객체가 생성될 시에 메모리에 할당되지만 정적 멤버는 객체를 사용하지 않아도 클래스 파일이 할당될 때 함께 메모리에 할당된다고 하였다.

즉, 클래스의 객체를 사용하지 않더라도 메모리를 점유하고 있기 때문에 메모리를 비효율적으로 사용할 수 있을 것이다.

그렇다면 Unreachable Object인 경우 Garbage Collector가 제거해 주면 되는 것 아닌가?라고 생각할 수 있지만 아쉽게도 정적 멤버들은 GC의 대상이 될 수 없다.

그 이유는 Static 키워드를 사용한 정적 멤버들은 객체가 할당되는 Heap 영역이 아닌 Static 영역(메서드 영역)에 할당되기 때문이다. Static 영역은 GC의 관리 영역 밖에 존재하기 때문에 메모리에 할당된 시점부터 프로그램이 종료되기 전까지 제거되지 않고 계속해서 메모리를 차지하고 있게 된다.

따라서 모든 멤버들을 Static으로 선언하는 것은 상황에 따라 메모리를 굉장히 비효율적으로 사용할 수 있게 된다.

그렇다면 어떤 경우에 Static 키워드를 사용하는 것이 좋을까? Static의 특징 중 하나는 Static 영역에 할당된 메모리는 모든 객체가 공유하며 어디서든지 참조할 수 있다는 것이다.

class Test {
	static int count = 1;
}

public class Main {
	public static void main(String[] args) {
		System.out.println(Test.count);
		Test A = new Test();
		Test B = new Test();
		A.count++;
		System.out.println(B.count);
	}
}

 

A 객체와 B 객체는 같은 count를 참조하기 때문에 A 객체의 count를 1 증가한 후 B 객체의 count를 출력하면 2가 출력되는 것을 확인할 수 있다.

 

따라서 클래스의 해당 멤버를 공유하여 사용할 경우 Static 키워드를 사용하면 된다. 주로 싱글톤 패턴을 사용할 때 자주 사용된다.

마지막으로 Static 메서드에서는 일반 멤버(변수, 메서드)를 사용할 수 없음을 주의하자. 반대로 일반 메서드에서는 정적 멤버를 사용할 수 있다.

그 이유는 앞서 언급한 정적 멤버와 일반 멤버들이 메모리에 할당되는 시점을 생각하면 된다.

정적 메서드에서 일반 멤버를 사용할 경우 그 멤버들이 메모리에 할당되어 있지 않을 수도 있기 때문이다. 반대로 정적 멤버들은 클래스 로딩 시 메모리에 할당되기 때문에 후에 객체를 생성하여 사용할 때 정적 멤버가 메모리에 존재한다는 것이 보장된다.

public class Main {
	public static void main(String[] args) {
		A(); //정적 멤버 o
		//B(); 일반 멤버 x
	}
	
	public void aa () {
		A(); //정적 멤버 o
		B(); //일반 멤버 o
	}
	
	public static void A() {}
	public void B() {}
}
반응형

댓글