13. static 키워드


javalogo

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 멤버는 객체를 생성하지 않고 사용할 수 있는 멤버이다. 다음 표를 통해 차이점을 요약하였다.

table

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 멤버 mf()는 이미 존재하며 사용이 가능하다
      StaticSample s1, s2;
      
    • static 멤버 mf()는 객체 s1, s2가 생성되기 이전에 이미 생성되어 있으며, s1, s2가 생성될 때 static 멤버가 별도로 생성되는 것은 아니다.
    • 다음 코드의 실행에 의해 인스턴스 멤버인 n, g(), h()는 모두 각 객체마다 생성된다.
      s1 = new StaticSample();
      s2 = new StaticSample();
      
    • 다음 코드는 static 멤버를 접근한다.
      s1.m = 50;
      s2.f();
      
  • static 멤버의 공유
    • code_12에서 객체 s1과 객체 s2static 멤버를 공유하고 있다.
    • 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 사용 불가
}





© 2019. by RaP0d

Powered by aiden