본문 바로가기
JAVA

[JAVA] 객체와 클래스 - static 키워드

by Amy IT 2022. 5. 25.

static 키워드는 클래스, 변수, 메소드의 지정자로 사용할 수 있습니다. 지금까지 main 함수를 만들 때 항상 보았던 static 키워드입니다. 

 

자바 프로그램은 일반적으로 다음과 같은 과정을 거쳐서 결과값이 출력됩니다. 

클래스가 로딩될 때 static 키워드를 사용한 static 변수와 메소드가 메모리에 자동으로 로딩됩니다. 이렇게 미리 만들어진 여러 static 메소드들 중에서 시작점 기능을 하는 main 메소드가 실행된 후, 필요에 따라 객체를 생성하여 인스턴스 변수와 메소드를 메모리에 로딩하고, 메소드를 호출하면 메소드 안에서 선언된 로컬변수가 생성됩니다. 

static 변수와 메소드는 프로그램이 실행될 때 단 한 번 생성되고 프로그램이 종료될 때 삭제됩니다. 프로그램이 실행될 때 자동으로 로딩되기 때문에 객체를 생성하지 않아도 사용할 수 있으며, 클래스명으로 접근이 가능하고 공유가 가능합니다. 반면 인스턴스 변수와 메소드는 new 키워드로 객체를 생성할 때마다 생성되고 객체 소멸 시 삭제됩니다. 객체 생성 후 참조변수를 이용해 접근할 수 있습니다. 여기서 주의해야 할 점은, static 키워드가 붙은 변수와 메소드와, static 키워드가 붙지 않은 non-static 변수와 메소드의 생성 시점이 다르다는 것입니다. 예를 들어 알아보기 위해 Person 클래스를 만들어 보겠습니다.

public class Person {
	String name; //인스턴스 변수 
	static int age; //static 변수
	
	public void print() { //멤버함수
		System.out.println(this.name); //인스턴스 변수
		System.out.println(age); //static 변수
	}
	
	public static void printB() { //static 함수 - 클래스 로딩시 생성
//		System.out.println(name); //인스턴스 변수 사용 불가
//		print(); //멤버함수 호출 불가
		System.out.println(age); //static 변수 
	}
	
}

static 변수인 age와 static 함수인 printB() 함수는 프로그램이 실행되며 클래스가 로딩될 때 생성됩니다. 하지만 print() 함수와 name 변수는 new 키워드를 사용해 Person 객체를 생성한 후에야 생성되는 멤버함수, 인스턴스 변수이기 때문에 static 함수 내에서 객체 생성 없이 사용하면 오류가 발생하게 됩니다. 이번엔 메인함수가 포함된 클래스를 만들어 보겠습니다.

 

public class TestMain {

	public static void main(String[] args) {
		Person.printB(); //age 0 //클래스이름.함수이름 으로 static 함수 호출 
		System.out.println(Person.age); //age 0 //클래스이름.변수이름 으로 static 변수 사용 
		
		Person p = new Person(); //객체 생성
		p.print(); //name null, age 0 
		p.age=20; //p의 age 값 변경?
		
		Person p2 = new Person(); //다른 객체 생성
		p2.print(); //name null, age 20
		p2.age=100; //p2의 age 값 변경?
		System.out.println(p.age); //age 100
		System.out.println(Person.age); //age 100
	}

}

static 키워드가 붙은 변수와 메소드는 클래스명.변수명 혹은 클래스명.메소드명으로 객체 생성 없이 사용 가능합니다. 멤버변수는 선언과 동시에 기본값으로 초기화되어 있기 때문에 값을 따로 지정하지 않으면 name은 null, age는 0이 출력됩니다. Person 객체를 생성한 후 p 변수에 참조시키고, p가 참조하는 Person 객체의 age 값을 20으로 변경하고 있습니다. 이후 다른 Person 객체를 생성한 후 p2 변수에 참조시키고, p2 변수를 이용해 print() 함수를 호출하는데, age 값이 20으로 출력됩니다. 즉, 여기서 사용되는 age 변수가 동일한 변수라는 것입니다. p2 변수가 참조하는 Person 객체의 age 값을 100으로 변경하는데, 마찬가지로 동일한 변수기 때문에 p.age 값을 출력해도 100이 나오게 됩니다. 결론적으로 static 키워드가 붙은 변수는 객체 생성과 상관 없이 프로그램 실행시 생성되며, 객체들 간 공유 변수로 사용된다는 것입니다. 

 

 

한 가지 예시를 더 들어보겠습니다. 다음은 객체를 생성한 횟수를 구하는 프로그램입니다.

class Counter{
	static int count;
	int num;
	public Counter() { 
		count++; //생성자 호출할때 마다 count
		num = count;
	}
	public int getNum() {
		return num;
	}
}

public class Ex05_18 {

	public static void main(String[] args) {
		System.out.println("객체생성 횟수 : "+Counter.count);
		Counter c = new Counter();
		System.out.println("객체생성 횟수 : "+c.getNum());
		Counter c2 = new Counter();
		System.out.println("객체생성 횟수 : "+c2.getNum());
		System.out.println("객체생성 횟수 : "+Counter.count);
	}

}

count를 static 변수로 설정하여 프로그램 시작 시 단 한 번 생성되고 생성자가 한 번 호출될 때마다 값이 누적되도록 하고 있습니다. 누적된 값을 num 이라는 인스턴스 변수에 저장하여, get() 함수를 통해 num 값을 얻을 수 있도록 하고 있습니다. 이렇듯 static 변수를 이용하면 여러 인스턴스에서 데이터를 누적하여 저장하고 공유할 수 있게 됩니다. 

 

 

 

* 초기화 블록

 

static 키워드를 공부하는 김에 초기화 블록에 대해서도 알아보겠습니다. 초기화 블록은 클래스에서 생성자와 비슷하게 초기화 작업을 할 수 있습니다. static 초기화 블록과 인스턴스 초기화 블록이 제공됩니다. 

public class TestMain {

	static {
		System.out.println("static 초기화 블럭");
	}
    
	public TestMain() {
		System.out.println("TestMain 생성자");
	}
	
	{
		System.out.println("인스턴스 초기화 블럭");
	}

	public static void main(String[] args) {
		TestMain m = new TestMain();
		TestMain m2 = new TestMain();
	}

}

static 초기화 블록은 프로그램 시작 시 단 한 번만 수행되며, static 변수의 초기화 및 프로그램 시작시 초기화 작업이 필요한 경우 사용합니다. 인스턴스 초기화 블록은 객체를 생성할 때마다 수행되며, 생성자보다 먼저 수행되고, 인스턴스 변수의 초기화에 사용할 수 있습니다. 이에 따라 static 초기화 블록의 출력문이 가장 먼저 나오고, 객체 생성 시 인스턴스 초기화 블록이 수행된 후 생성자가 사용되는 것을 확인할 수 있습니다. 

 

 

이상으로 static 키워드에 대해 정리해 보았습니다. 

 

 

댓글