정적(static)

정적 멤버(혹은 변수)와 메소드라는 것은 무엇일까요? 우선 아래와 같은 상황이 있다고 가정해봅시다. Counter라는 클래스가 있으며 Counter는 멤버로 cnt를 갖고 있습니다. 그리고 count라는 메소드가 있는데, 이 count 메소드는 단순히 cnt를 하나 증가하는 역할을 합니다.

그리고 메인에서는 Counter의 두 객체 counter1, counter2를 생성하고 둘은 counter() 메소드를 통해서 cnt를 증가시키고 있습니다. 여기서 저의 의도는 두 객체가 cnt를 같이 증가시키고 싶습니다.

class Counter{
	public int cnt;
	public void count() {
		cnt++;
	}
	
}

public class TestMain {
	
    public static void main(String[] args){
    	Counter counter1=new Counter();
    	Counter counter2=new Counter();
    	counter1.count();
    	counter2.count();
    	System.out.println("counter1:"+counter1.cnt+", counter2:"+counter2.cnt);
    	
    }
}

 

만약 프로그램이 저의 의도대로 동작한다면 counter2까지 왔을때 cnt는 2가 되어야합니다. (물론 그렇게 동작하지 않습니다.) 결과를 보면 아래와 같네요.

counter1:1, counter2:1

 

정적 변수(Static variable)

여기서 저의 희망은 cnt라는 맴버를 공통으로 사용하는 것입니다. 이때 static하나만 써주면 저의 목적이 달성됩니다. Counter 클래스에서 cnt를 선언할때 static만 붙여봅시다.

class Counter{
	public static int cnt;
	public void count() {
		cnt++;
	}
}

public class TestMain {
	
    public static void main(String[] args){
    	Counter counter1=new Counter();
    	Counter counter2=new Counter();
    	counter1.count();
    	counter2.count();
    	System.out.println("counter1:"+counter1.cnt+", counter2:"+counter2.cnt);
    	
    }
}

그리고 결과를 봐야겠죠.

counter1:2, counter2:2

 

제가 말한대로 동작하는 것을 알 수 있습니다.

어떻게 이런것이 가능할까요? static 변수나 메소드는 static 메모리 구역에 따로 고정적(정적)으로 할당되어 관리됩니다. 그래서 이 static 변수와 메소드는 모든 Counter 클래스가 공통적으로 사용할 수 있습니다. 이러한 특징 때문에 클래스 변수, 메소드라고 합니다.

 

static에 대해서 가볍게 아시려면 "공용 변수, 메소드" 라고 쉽게 기억하시면 됩니다.

 

그렇지만 static에 대해서 좀 더 자세히 알려면 여러분은 우선 프로그램이 실행될때의 메모리 구조에 대해서 아셔야합니다. 우리가 항상쓰던 new로 객체를 생성하는 것은 heap 영역에 저장되어 프로그램이 실행하는 중간에 메모리를 할당합니다. 그래서 메소드가 끝나서 쓸일이 없어질때 자바의 Garbage Collector에 의해서 메모리에서 수거가 됩니다.

하지만 static은 프로그램이 실행 전 먼저 메모리에 잡히게 됩니다. 이때 실행 전이라고 하는 것은 프로그램이 메모리에 적재되고 명령어를 수행하기 전을 말합니다. 그리고 프로그램이 종료될때 해제가 되지요. 즉, heap의 영역보다 나중에 정리된다는 뜻입니다.

메모리 구조

 

가장 먼저 메모리에 적재되어 정적(static)으로 존재하기 때문에 static 멤버나 메소드는 클래스의 객체 생성없이 클래스의 이름만가지고도 사용할 수 있습니다.

public static void main(String[] args){
	Counter.cnt++;
    Counter.cnt++;
    System.out.println("cnt:"+Counter.cnt);
}
cnt:2

 

정적 메소드(static method)

이제 정적 변수는 알았는데, 정적 메소드는 그렇다면 무엇일까요? 역시 변수와 개념은 다르지 않습니다. 메모리에 메소드하나를 고정적으로 두어서 사용이 가능합니다. Counter 클래스를 변형시켜서 보도록 합시다. 

class Counter{
	public static int count(int cnt) {
		return cnt+1;
	}
}

public class TestMain {
	
    public static void main(String[] args){
    	Counter counter=new Counter();
    	System.out.println("count 1:"+Counter.count(1));
    	System.out.println("count 2:"+Counter.count(2));
    	System.out.println("counter's count 5:"+counter.count(5));
    }
}

 

그러면 메모리에는 이런식으로 잡히게 됩니다. 마치 counter라는 메소드를 공용으로 사용하듯 말이죠.

 

실행을 시켜보면 아래와 같은 결과를 갖게 됩니다.

count 1:2
count 2:3
counter's count 5:6

 

이제 메모리에 정적변수나 메소드가 다른 동적으로 메모리를 할당(new 키워드로 할당하거나 일반 메소드)하는 시점보다 먼저 메모리에 잡히게 되었다는 것을 알았다면 다음과 같은 규칙을 이해하게 될 것입니다.

 - 정적 메소드에서는 정적 메소드나 정적 변수만 사용할 수 있다. 멤버 변수는 사용할 수 없다.

이러한 이유는 정적 메소드에서는 자신보다 나중에 메모리가 할당되는 멤버 변수나 메소드는 언제 할당되는지 알수가 없습니다. 만약 아래의 코드처럼 count가 먼저 호출되는 상황에서 cnt가 메모리에 할당되지 않았다면요. 그래서 이처럼 빨간줄이 쳐지면서 static 만이 올수가 있다고 메시지를 띄워줍니다.

 

main 메소드에서 static 메소드만 호출 가능했던 이유

main 메소드 역시 static 메소드이기 때문에 여러분들이 클래스를 배우기 전 메소드를 배울때 묻지도 따지지도 않고 우선 static을 붙여서 메소드를 구현해보셨을 것입니다. main 메소드는 프로그램 실행 전 먼저 메모리에 할당되어야하기 때문이고, 메인이 static이기 때문에 호출되는 메소드 역시 static이어야하기 때문입니다.

 

이상으로 자바에서 static 개념에 대한 설명이었습니다. 무엇보다 메모리가 할당되는 시점만 이해한다면 왜 이런 결과가 나오는지 이해하기가 쉬울 것입니다.

반응형
블로그 이미지

REAKWON

와나진짜

,