Think Deeply

static을 깊게 이해해보자

S_N_Y 2024. 1. 13. 22:46

java 코드를 보다 static 키워드의 실사용성에 대해 궁금한 점이 생겨 찾아보고 정리한 부분을 블로그에 정리하려고 한다. 

public class hi {
    
    public static void main(String[] args) {
        Solution Foo1(); // static이 붙은 함수'Foo1'의 호출 방식

        var sol = new Solution(); // static이 붙지 않은 함수'Foo2'의 호출 방식
        sol.Foo2();

    }

    public class Solution{

        public static void Foo1() {} // static 선언

        public void Foo2() {}
    }
}

new 키워드가 붙은 메모리는 heap공간에 할당이 된다

우리가 올리려는 것에 적당한 heap공간이 있는지 먼저 확인을 해주고 그 만큼의 크기가 있으면 해당 공간에 메모리를 적재한다

그리고 그 메모리에 접근할 수 있는 포인터를 받아서 이렇게 Foo2 함수를 호출할 수 있는 것이다

=> 메모리에 코드가 올라가있지 않으면 Foo2함수를 호출할 수 없다는 말이다.

 

🤔. Foo1 함수는 어떻게 호출이 될까? ststic 키워드는 어디 메모리에 위치할까?

static은 heap stack과 다르게 static 키워드가 붙은 함수나 변수, 클래스들이 올라갈 수 있는 static 공간이 따로 존재한다

컴파일러는 static이 붙은 함수나 변수, 클래스들을 프로그램 실행과 동시에 static 메모리 공간에 다 적재를 시킨다

=> new를 하지 않지만 컴파일러가 다 적재시켰다는 말이다

=> 이 메모리 공간은 프로그램이 끝나기 전까지 절대 지워지지 않는다

=> 그래서 new 같은 메모리를 생성하지 않아도 바로 접근이 가능하다

nonStaticVar에 에러가 뜨는 모습

알다시피 static 키워드가 붙은 Foo1함수는 이미 시작과 동시에 메모리에 올라가있으니

이 함수 안에서 올라가는 nonStaticVar는 사용자가 new 키워드를 이용해서 메모리에 올리지 않는 한 이런 식으로 에러가 난다 그리고 Foo1이 메모리에 올라가있는 상태에서 nonStaticVar 는 올라와있지 않을 확률이 있다

-> 그래서 static 함수나 static 클래스는 static이 붙은 것들만 참조 가능한 것

public class hi {

    public static void main(String[] args) {


        int a = 10;
        addOne(a);

        System.out.println(a);
    }
    private static void addOne(int a) {
        a = a+1;
    }
}

 -> Q : 이렇게 하면 11이 출력이 될까?

      A : 아니다. main에서 사용한 int a와 addOne 변수에서 사용한 int a는 전혀 다른 메모리에 할당된 다른 변수이기 때문에 그대로 10이 출력된다

// 1. 리턴값으로 해결하기
public class hi {

    public static void main(String[] args) {


        int a = 10;
        a = addOne(a); // 변경된 부분 - 밑에서 return한 값 받아주기

        System.out.println(a);
    }
    private static int addOne(int a) { // 변경된 부분 : void -> int로 받기
        a = a+1;
        return a; // 변경된 부분 - return값으로 돌려주기
    }
}
// 2. 클래스 멤버 변수로 해결하기 - 일단 예시이므로 참고만(굳이 이런 식으로 변경x)
public class hi {

    int a; // 변경된 부분 : 지역변수가 아닌 이런 식으로 클래스 멤버 변수로 선언하기
    
    public static void main(String[] args) {
       Score score = new Score(10); // 변경된 부분 : main에서 클래스 객체를 선언
    
    // public Score(int i) {  // 변경된 부분 : 이때 a를 초기화하는 생성자를 하나 만들어놓으면 편하다
    // this.a=10;
    // }
        addOne(score);  // 변경된 부분 : a -> score
        System.out.println(score.a); // 변경된 부분 : a -> score.a
    }
    private static int addOne(Score score) { // 변경된 부분 : 파라미터를 클래스 객체로 변경
       score.a = score.a+1;  // 변경된 부분 : 받은 클래스 객체의 멤버변수인 a값에 1를 더해주는 로직으로 변경
    }
}
// 3. static으로 해결하기
public class hi {

    static int a;

    public static void main(String[] args) {
        a = 10;
        a = addOne(a);
        System.out.println(a);
    }
    private static int addOne( ) { 
        a = a+1;
    }
}