13. static 키워드
Overview
Java의 키워드 중 하나인 static에 대한 정리를 기술한 문서
static의 사용
static으로 선언된 멤버는 모든 클래스에서 공유할 수 있게 된다.
static 멤버를 선언하는 방법은 멤버 선언 시 앞에 static이라고 붙이면 된다.
class StaticSample {
int n; // non-static 필드
void g() {...} // non-static 필드
static int m; // static 필드
static void f() {...} // static 필드
}
non-static 멤버와 static 멤버의 차이
static 멤버는 객체를 생성하지 않고 사용할 수 있는 멤버이다. 다음 표를 통해 차이점을 요약하였다.
static 멤버는 클래스당 하나만 생성되는 멤버로서 동일한 클래스의 모든 객체들이 공유한다.
그리고 어떤 객체도 생성되기 전 프로그램을 시작할 때 이미 생성된다.
그러므로 객체를 생성하기 전에도 static 멤버는 사용할 수 있다.
반면 non-static 멤버는 객체가 생길 때 객체 내부에 하나씩 생성되며 객체마다 자신의 고유한 멤버공간을 가지며 객체들이 공유하지 않는다.
객체가 사라지면 non-static 멤버도 함께 사라지고 더 이상 접근할 수 없다.
static 멤버는 클래스당 하나씩 생긴다고 해서 클래스 멤버라고도 부르며, non-static 멤버는 각 객체마다 하나씩 생긴다고 해서 인스턴스 멤버라고도 부른다.
static 멤버 사용 1 : 객체.static 멤버
static 멤버도 역시 멤버이기 때문에 다음과 같이 일반적인 멤버 사용법과 다를바 없다.
객체.static필드
객체.static메소드
static 필드는 클래스의 모든 객체에 공통으로 사용되는 변수가 된다.
즉 C/C++의 전역 변수(global variable)와 유사하다고 볼 수 있다.
또한 클래스의 어떤 멤버도 static 멤버를 접근할 수 있다.
우선 지금까지 설명한 static 에 대한 여러 지식을 다음 소스를 통해 명확히 확인할 수 있다.
/**
* code_12
* static 멤버를 객체의 멤버로 접근하는 경우
*/
class StaticSample {
public int n;
public void g() {
m = 20;
}
public void h() {
m = 30;
}
public static int m;
public static void f() {
m = 5;
}
}
public class Ex {
public static void main(String[] args) {
StaticSample s1, s2;
s1 = new StaticSample();
s1.n = 5;
s1.g();
s1.m = 50; // static
s2 = new StaticSample();
s2.n = 8;
s2.h();
s2.f(); // static
System.out.println(s1.m);
}
}
- static 멤버의 생성
- 위 코드에서 static 멤버가 생성되는 시점은 main() 메소드가 실행을 시작한 후
StaticSample
이 등장하는 시점이다. - 다음 코드가 실행되기 이전부터 static 멤버
m
과f()
는 이미 존재하며 사용이 가능하다StaticSample s1, s2;
- static 멤버
m
과f()
는 객체s1, s2
가 생성되기 이전에 이미 생성되어 있으며,s1, s2
가 생성될 때 static 멤버가 별도로 생성되는 것은 아니다. - 다음 코드의 실행에 의해 인스턴스 멤버인
n, g(), h()
는 모두 각 객체마다 생성된다.s1 = new StaticSample(); s2 = new StaticSample();
- 다음 코드는 static 멤버를 접근한다.
s1.m = 50; s2.f();
- 위 코드에서 static 멤버가 생성되는 시점은 main() 메소드가 실행을 시작한 후
- static 멤버의 공유
code_12
에서 객체s1
과 객체s2
는 static 멤버를 공유하고 있다.s1, s2
모두 자신의 멤버라고 생각하여g(), h()
메소드에서 static 멤버m
을 공유하여 사용하고 있다.
static 멤버의 사용 2 : 클래스명.static 멤버
static 멤버를 사용하는 또 다른 방법이 있다.
static 멤버는 클래스당 하나만 있기 때문에 다음과 같이 클래스 이름으로 바로 접근할 수 있다.
클래스명.static멤버
main()
메소드의 첫 번째 문장인 다음 코드는 클래스명.static
멤버를 사용하는 실례를 보여주며, 동시에 new
에 의해 객체가 생기기 전에 static 멤버를 접근하는 사례를 보여준다.
StaticSample.m = 10;
또한 static 메소드의 사용에 있어서도 다음 두 가지 방법이 모두 가능하다.
s1.f(); // 객체 레퍼런스로 static 멤버 f() 호출
StaticSample.f(); // 클래스명을 이용하여 static 멤버 f() 호출
static 의 활용
전역 변수와 전역 함수를 만들 때 활용
자바에서는 C와 C++과 달리 어떤 변수나 함수도 클래스 바깥에 존재할 수 없으며 클래스의 멤버로 존재하여야 한다.
이는 캡슐화의 원칙 때문이다.
그러나 응용프로그램 작성 시 모든 클래스에서 공유하는 전역 변수(global variable)나 모든 클래스에서 언제든지 호출할 수 있는 전역 함수(global function)를 만들어 사용할 필요가 생긴다.
static은 이런 문제에 대한 해결책이다.
대표적인 클래스가 JDK와 함께 배포되는 java.lang.Math
클래스이다.
이 클래스는 다음과 같이 객체를 생성하지 않고 바로 호출할 수 있는 수학 계산용 상수와 메소드를 제공한다.
public class Math {
public static int abs(int a);
public static double cos(double a);
public static int max(int a, int b);
public static double random();
...
}
Math의 멤버를 사용하기 위해 다음과 같이 하지 않는다.
Math m = new Math();
int n = m.abs(-5);
객체를 만들지 않고 다음과 같이 바로 static 멤버를 사용한다.
int n = Math.abs(-5);
공유 멤버를 만들고자 할 때 활용
static으로 선언된 필드나 메소드는 모두 이 클래스의 각 객체들의 공통 멤버가 되며 객체들 사이에서 공유된다.
static 메소드의 제약 조건
static 메소드는 오직 static 멤버만 접근할 수 있다.
static 메소드는 객체가 생성되지 않은 상황에서도 사용이 가능하므로 객체에 속한 인스턴스 메소드, 인스턴스 변수 등을 사용할 수 없다.
다만 static 멤버들만 사용가능하다.
그러나 인스턴스 메소드는 static 멤버들을 모두 사용할 수 있다.
static 메소드를 사용하는 예를 들어보자.
class StaticMethod {
int n;
void f1(int x) {n = x;} // 정상
void f2(int x) {m = x;} // 정상
static int m;
static void s1(int x) {n = x;} // 컴파일 오류. static 메소드는 non-static 필드 사용 불가
static void s2(int x) {f1(3);} // 컴파일 오류. static 메소드는 non-static 필드 사용 불가
static void s3(int x) {m = x;} // 정상. static 메소드는 static 필드 사용 가능
static void s4(int x) {s3(3);} // 정상. static 메소드는 static 필드 사용 가능
}
static 메소드에서는 this 키워드를 사용할 수 없다.
static 메소드는 객체가 생성되지 않은 상황에서도 클래스 이름을 이용하여 호출이 가능하기 때문에 호출 당시 실행 중인 객체를 가리키는 this 레퍼런스를 사용할 수 없다.
static 메소드에서 this를 사용할 수 없는 경우의 예를 들어보자.
class StaticAndThis {
int n;
static int m;
void f1(int x) {this.n = x;} // 정상
void f2(int x) {this.m = x;} // non-static 메소드에서는 static 멤버 접근 가능
static void s1(int x) {this.n = x;} // 컴파일 오류. static 메소드는 this 사용 불가
}