본문 바로가기
JAVA

[자바/JAVA] Static변수와 Static메서드

by wook99 2024. 6. 13.

멤버 변수에는 인스턴스 변수와 클래스 변수가 존재한다.

static변수는 클래스 변수, 정적 변수라고도 불린다. 

 

1. 인스턴스 변수 : static이 붙지 않음

  • 인스턴스를 생성해야 사용할 수 있고, 인스턴스에 소속되어 있다.
  • 인스턴스를 만들 때 마다 새로 만들어진다.

2. 클래스 변수 : static 붙음

  • static이 붙은 멤버변수. 클래스에 바로 접근해서 사용할 수 있다. 클래스 자체에 소속되어 있다.
  • 자바 프로그램을 시작할 때 딱 1개가 만들어진다. 보통 여러곳에서 공유하는 목적으로 사용된다.

 

 

static을 이해하기 위해 코드를 통해 먼저 알아볼 필요가 있다.


1. Static 변수

1) static 사용 전

아래의 예제는 Data1클래스의 객체를 3개 생성하고 생성할 때마다 count를 1씩 증가시켜 count를 3으로 할당 시키려고 시도한 예제이다.

public class Data1 {
    public String name;
    public int count;

    public Data1(String name){
        this.name = name;
        count++;
    }
}
public class DataCountMain1 {
    public static void main(String[] args) {
        Data1 data1 = new Data1("A");
        System.out.println("A count = " + data1.count);

        Data1 data2 = new Data1("B");
        System.out.println("B count = " + data2.count);

        Data1 data3 = new Data1("C");
        System.out.println("C count = " + data2.count);
    }
}

/*실행 결과
A count = 1
B count = 1
C count = 1
/*

 

실행결과는 당연히 1이 된다.

객체를 생성할 때마다 변수 count는 data1, data2, data3 에 각각 존재하기 때문에, 같은 count를 공유하고 있는것이 아니므로 1씩 할당받게 되는것이다. 그렇다면 세 개의 객체가 같은 count를 공유하고 1씩 증가시키려면 어떻게 해야할까?

static을 이용하면 된다. 


2) static 사용 후

public class Data3 {
    public String name;
    public static int count;

    public Data3(String name){
        this.name = name;
        count++;
    }
}
public class DataCountMain3 {
    public static void main(String[] args) {
        Data3 data1 = new Data3("A");
        System.out.println("A count = " + Data3.count);

        Data3 data2 = new Data3("B");
        System.out.println("B count = " + Data3.count);

        Data3 data3 = new Data3("C");
        System.out.println("C count = " + Data3.count);

        //추가
        //인스턴스를 통한 접근
        Data3 data4 = new Data3("D");
        System.out.println(data4.count);

        //클래스를 통한 접근
        System.out.println(Data3.count);
    }
}

/*실행 결과
A count = 1
B count = 2
C count = 3
4
4
*/

 

이렇게 count라는 필드에 static을 붙여주면, 자바 메모리 구조에서 method영역에 count라는 변수가 존재하게 되고, 자바가heap 영역에 count라는 변수가 없는 것을 확인한 후 method영역에서 count를 꺼내서 쓴다고 이해를 하였다. method영역은 프로그램의 모든 영역에서 공유하기 때문에, 어떤 객체에서 접근해서 수정해도 모든 영역에 반영된다.

 

//추가 이 부분은 static 변수에 접근하는 방법 2가지를 나타낸 것이다.

인스턴스를 이용해서(data4.count)접근을 할 수도 있고, 클래스를 통해 접근(Data3.count)할 수도 있다. 

 


2. Static 메서드

1) static 사용 전

public class DecoUtil1 {

    public String deco(String str){
        return "*" + str + "*";
    }
}
public class DecoMain1 {
    public static void main(String[] args) {
        String s = "hello java";
        DecoUtil1 utils = new DecoUtil1();
        String deco = utils.deco(s);

        System.out.println("before = " + s);
        System.out.println("after = " + deco);
    }
}

/*실행 결과
before = hello java
after = *hello java*
*/

 

DecoUtil1이라는 클래스는 deco메서드를 가지고 있고, deco메서드는 멤버 변수도 없고, 단순히 기능만 제공한다. 이 메서드를 사용하려면 인스턴스를 생성해야 하는데, 인스턴스가 필요한 이유는 멤버 변수등을 사용하려는 목적이 크다. 그렇기 때문에 static을 붙여 정적 메서드로 만들고, 객체 생성도 따로 하지 않고 deco메서드를 사용할 수 있다. 아래에서 적용해보자.

 

2) static 사용 후

public class DecoUtil2 {

    public static String deco(String str){
        return "*" + str + "*";
    }
}
public class DecoMain2 {
    public static void main(String[] args) {
        String s = "hello java";
        String deco = DecoUtil2.deco(s);

        System.out.println("before = " + s);
        System.out.println("after = " + deco);
    }
}

/*실행 결과
before = hello java
after = *hello java*
*/

 

위의 배운 내용을 적용해보자.

DecoUtil2의 deco메서드에 static을 붙여 main메서드에서 객체 생성없이 클래스로 접근하여 바로 사용하였고, 불필요한 객체 생성을 하지 않게 되었다. 

 

3) static메서드 사용법

  • static메서드는 static만 사용할 수 있다 - static메서드는 static이 붙은 정적 메서드나 정적 변수만 사용할 수 있다.
  • 반대로 모든 곳에서 static을 호출할 수 있다.

말로는 이해가 잘 안간다. 코드로 알아보자

 

public class DecoData {

    private int instanceValue;
    private static int staticValue;

    public static void staticCall(){
//        instanceValue++; //인스턴스 변수 접근, 컴파일 에러
//        instanceMethod();//인스턴스 메서드 접근, 컴파일 에러

        staticValue++; //정적 변수 접근
        staticMethod(); //정적 메서드 접근
    }

    public void instanceCall(){
        instanceValue++;//인스턴스 변수 접근
        instanceMethod();//인스턴스 메서드 접근

        staticValue++; //정적 변수 접근
        staticMethod(); //정적 메서드 접근
    }

    public static void staticCall(DecoData data){
        data.instanceValue++;
        data.instanceCall();
    }

    private void instanceMethod(){
        System.out.println("instanceValue = " + instanceValue);
    }

    private static void staticMethod(){
        System.out.println("staticValue = " + staticValue);
    }
}

 

staticCall메서드에서 instance메서드와 변수를 사용하려고 하면 컴파일 에러가 뜬다. 

하지만 static변수와 메서드를 사용할 수는 있다.

 

instanceCall메서드에서는 static변수와 메서드, instance변수와 메서드를 모두 사용할 수 있다.

 

public class DecoDataMain {
    public static void main(String[] args) {
        System.out.println("1. 정적 호출");
        DecoData.staticCall();

        System.out.println("2. 인스턴스 호출1");
        DecoData data1 = new DecoData();
        data1.instanceCall();

        System.out.println("3. 인스턴스 호출1");
        DecoData data2 = new DecoData();
        data2.instanceCall();

        //추가
        //인스턴스를 통한 접근
        DecoData data3 = new DecoData();
        data3.staticCall();

        //클래스를 통한 접근
        DecoData.staticCall();
    }
}

/*실행 결과
1. 정적 호출
staticValue = 1
2. 인스턴스 호출1
instanceValue = 1
staticValue = 2
3. 인스턴스 호출1
instanceValue = 1
staticValue = 3
staticValue = 4
staticValue = 5
*/

 

static메서드가 instance 기능을 사용할 수 없는 이유는,

static메서드는 클래스의 이름을 통해 바로 호출한다. 그래서 인스턴스처럼 참조값의 개념이 없고, 특정 인스턴스의 기능을 사용하려면 참조값을 알아야 하지만, static메서드는 참조값 없이 호출하기에 instance변수나 메서드를 사용할 수 없다.

하지만 매개변수에 직접 참조값을 전달하면, 인스턴스의 변수나 메서드를 호출할 수 있다.

 

//추가 이부분은 static변수와 마찬가지로 인스턴스와 클래스를 통해 모두 접근 가능하다는 것을 보여주는 예제이다.