본문 바로가기
JAVA/이재환의 자바 프로그래밍 입문

[Java] Ch.11 스태틱의 이해

by ♡˖GYURI˖♡ 2023. 10. 20.

스태틱

스태틱 변수 및 스태틱 메서드는 메서드 영역에 저장되며, 프로그램 시작 전에 로드되고 프로그램 종료 시 소멸됨

  1. 코드가 메서드 영역에 다 로딩되면
  2. 그 중에서 스태틱으로 지정된 변수와 메서드는 메서드 영역 내 스태틱 영역으로 옮겨짐

 

먼저 추려내져야 하는 변수와 메서드가 있다면 static 예약어 표시를 하여 메모리의 특정 영역에 따로, 그리고 미리 로딩시켜놓은 것 뿐임

이 때 스태틱 변수(쩡적 변수)는 값이 메모리에 로딩될 때 대입되고, 블록이 있다면 메모리 로딩 때 실행됨

메서드는 누가 호출해줘야 실행이 되는 것이기 때문에 로딩만 됨

 

 

전역 변수로 사용

메서드 영역 내 스태틱 영역의 변수 및 메서드는 어떤 객체에서도 접근해서 사용할 수 있음

(스태틱 변수전역 변수라고 부르기도 하는 이유)

 

class Cat 
{
	static int a = 5;
	int num = 3;
	
	void printValue(int num)
	{
		this.num = num;
		System.out.println("num: " + this.num);
		System.out.println("a: " + a);
	}
}


public class Ex01_GlobalVariable
{
	public static void main(String[] args)
	{
		int num1 = 5;
		int num2 = 2;
		System.out.println(num1 + ", "  + num2);
		
		Cat cat1 = new Cat();
		cat1.num = 1;
		cat1.a = 10;
		cat1.printValue(20);
		System.out.println(cat1.num);
		System.out.println(cat1.a);
		
		Cat cat2 = new Cat();
		cat2.num = 2;
		cat2.a = 11;
		cat2.printValue(10);
		System.out.println(cat2.num);
		System.out.println(cat2.a);
		System.out.println(cat1.a);
		
	}
}

 

cat2.a 값을 바꾸었는데 cat1.a값도 같이 바뀜

→ a는 스태틱 변수라서 cat2.a와 cat1.a 둘 다 같은 a를 가리키고 있기 때문

 

 

 

생성된 위치에 따라 a는 스태틱 변수, num은 인스턴스 변수라고도 함

 

 

main()보다 먼저 실행

스태틱 예약어는 변수, 영역, 메서드에 붙일 수 있음

메서드는 호출을 해야 실행이 되는 것이므로 스태틱 예약어로 지정한 영역이 프로그램 실행 전 메모리에 먼저 로드가 되고 실행이 되는지 확인하면 됨

 

▼프로그램 실행 전 스태틱 예약어가 붙은 변수에 값의 대입이 끝나 있는지를 확인하는 예제

// 인스턴스 생성과 관계 없이 static 변수가 메모리 공간에 할당될 때 실행이 된다.

import java.util.Random;

public class Ex02_Preload
{
	static int num;	// 스태틱 멤버 변수
	
    	// 스태틱 초기화 블록
	static {
		Random rand = new Random();
        // main() 실행 전에 이미 난숫값이 대입이 된다.
		num = rand.nextInt(100);
	}
	
	public static void main(String[] args)
	{
		System.out.println(num);
	}

}

 

num = rand.nextInt(100); → 정수로 100을 매개변수로 넣어주면 0부터 99 사이의 임의의 숫자를 반환함

 

스태틱 멤버 변수도, 스태틱 초기화 블록도 프로그램 실행 전 미리 로드될 것이기에, main()에서 별다른 값을 변수에 대입하지 않았음에도 임의의 수가 값으로 들어가 있을 것임

 

스태틱 변수 남발의 단점

  • 사용하는 메모리의 정확한 크기 계산을 하지 않더라도 힙 영역을 사용하지 않고 메서드 영역의 일부분만 사용하므로 메모리 사용이 비효율적임
  • 한 객체가 가지고 있는 데이터들은 외부에서 함부로 접근하여 수정할 수 없도록 해야 한다는 객체지향 프로그래밍 원칙에 위배됨

 

유틸 메서드로 사용

스태틱 변수는 가급적 사용을 지양하라고 하였지만, 스태틱 메서드는 유틸리티 성격의 프로그램에서 많이 사용함

특정 기능이 필요한데 자주 사용된다면 많은 클래스에서 중복되어 만들어지지 않게 하려는 의도

 

메서드에 스태틱 예약어를 붙여 만들어놓으면 스태틱 영역에 만들어지기 때문에 서로 다른 클래스에서 얼마를 사용하든 간에 메모리에는 딱 한 번만 올라와 있게 됨

 


public class Ex03_UtilMethod
{

	public static void main(String[] args)
	{
		MyCalculator calc1 = new MyCalculator(); 	// 객체 생성 후 사용
		int num1 = MyCalculator.adder(1,  2);
		System.out.println(num1);
		
		int num2 = MyCalculator.adder(2,  3);		// 새로 객체를 생성하지 않고 사용
		System.out.println(num2);

	}

}

 

만약 계산기 클래스가 다른 패키지, 즉 다른 폴더에 있었다면 import 기능을 사용해야 사용할 수 있음

같은 패키지, 즉 같은 폴더에 있기 때문에 import를 사용하지 않아도 계산기 클래스를 사용할 수 있음

 

 

System.out.println(...)

  • System은 대문자로 시작하기 때문에 클래스
  • 점 .연산자를 이용함 → 객체를 만들지 않고 바로 클래스명으로 접근해 사용했으므로 out에는 static이 붙어 있다는 것을 알 수 있음
  • 하지만 out에는 메서드의 특징인 소괄호가 없음 → out은 메서드가 아니라 멤버 변수이기 때문!
  • . 연산자를 사용하여 println() 메서드를 호출하고 있으므로 일반 자료형의 변수가 아닌 객체형의 변수임을 알 수 있음

종합 : System 클래스의 멤버 변수 out은 객체를 참조하고 있고, 그 참조한 객체의 println() 메서드를 이용해 출력 기능을 제공함

 

import java.lang.System;	// 자동삽입

→ 자바 컴파일러가 자동으로 import시켜 주고 있음