네트워크 캠퍼스/JAVA

240112 사용 제한자(static 변수와 메서드)

gayeon_ 2024. 1. 12. 15:55

사용 제한자(Usage Level modifier)

static

  • static 제한자는 변수, 메서드에 적용되는 자바의 키워드이다.
  • static 메서드나 변수는 해당 클래스의 객체 없이도 참조할 수 있다.
  • static 블록(static 메서드, 정적 초기화자) 안에는 static 변수만 사용해야하고, static 메서드만 호출할 수 있다. 즉 static 블록에서 non-static 멤버를 객체 생성 없이 직접 참조할 수 없다.
  • static 제한자는 지정된 변수와 메서드를 객체와 무관하게 만들어주기 때문에 this를 가질 수 없다.
  • static 메서드는 non-static 메서드로 재정의(Overriding) 될 수 없다.
  • 대표적인 static 메서드는 애플리케이션의 main() 메서드다.
  • static에 단순히 블록({ })을 사용한 경우에는 정적 초기화자라고 부르며, static 변수를 초기화하는 역할을 가지고 클래스가 로딩될 때 main() 메서드가 있더라도 그보다 앞서 딱 한 번 실행된다.

 

static 예제

// Asean 클래스
package static_;

public class Asean {
	public String name;
	private int attendanceScore; // 출결점수
	private int finalTermScore; // 기말점수
	
	public static int presentationScore; // 29
	
	// presentationScore 빼고 초기화
	public Asean(String name, int attendanceScore, int finalTermScore) {
		this.name = name;
		this.attendanceScore = attendanceScore;
		this.finalTermScore = finalTermScore;
	}
	
	// 스태틱 블록 내부 코드는 프로그램 시작 시 즉시 자동으로 한 번 호출된다.
	static { // static은 this를 사용하지 못한다.
		presentationScore = 29;
	}
	
	public void showStudentScore() {
		System.out.println("학생명: " + this.name);
		System.out.println("출석 점수: " + this.attendanceScore);
		System.out.println("발표 점수: " + presentationScore);
		System.out.println("기말 점수: " + this.finalTermScore);
		System.out.println("최종성적: " + (this.attendanceScore + presentationScore + this.finalTermScore));
		System.out.println("---------------------------");
	}
}
// 메인 메서드
package static_;

public class MainClass {

	public static void main(String[] args) {
		// 인스턴스 생성 전부터 이미 조회 가능한 팀점수
		System.out.println(Asean.presentationScore);
		
		// 학생 4명 생성
		Asean a1 = new Asean("춘식이", 5, 30);
		Asean a2 = new Asean("라이언", 7, 20);
		Asean a3 = new Asean("콘", 6, 18);
		Asean a4 = new Asean("무지", 8, 22);
		
		a1.showStudentScore();
		a2.showStudentScore();
		a3.showStudentScore();
		a4.showStudentScore();

		// 어떤 인스턴스를 활용해도 팀 점수 조회가 가능하다.
		System.out.println(a1.presentationScore);
		System.out.println(a2.presentationScore);
		System.out.println(a3.presentationScore);
		System.out.println(a4.presentationScore);
	}

}

 

 

위 코드의 메모리 구조를 스텝별로 확인할 것이다.

 

 

T메모리 구조

 

 

 

 

프로그램 시작 시 클래스 로더가 asean 클래스 구조부터 스태틱 영역에 올린다.

 

 

 

그리고 static 변수인 presentationScore가 스태틱 영역에 올라가며 이후로 다시는 실행되지 않는다.

 

 

그 후에 메인 영역이 생기는 것이다.

 

 

 

7번 라인에서 presentationScore를 출력할 때 메모리 구조는 위와 같다.

 

 

 

a1 객체 생성 후의 메모리 구조다. 

 

 

※ this를 사용하지 못하는 이유

static 변수는 힙 영역에 저장되지 않기 때문에 

주소로 참조하는 this 키워드를 사용할 수 없다.

+ 디버깅할 때도 변수 목록에서 static 변수를 찾아볼 수 없다.

 

 

정적 변수(static field)

  • static 변수는 모든 객체들이 공유하는 공유변수가 된다.
  • 객체 생성 없이 클래스 이름만으로 참조가 가능합니다.
  • 정적 변수는 객체를 만들어 참조할 수도 있지만, 객체를 만들지 않고 클래스 이름만으로도 참조가 가능하기 때문에 이를 "클래스 변수"라고도 부른다.

 

 

정적 메서드(static method)

  • static 메서드는 static 변수와 마찬가지로 해당 클래스의 객체 생성 없이도 참조가 가능하다.
  • static 메서드에서 멤버를 참조할 때 주의해야 할 사항은 "static 메서드 안에서는 non-static 멤버를 객체 생성 없이 직접 참조할 수 없다"는 것이다.
  • static 메서드 안에서는 static 변수를 선언할 수 없다.

 

스태틱 메서드 예제

package static_;

public class Asean {
	public String name;
	private int attendanceScore; // 출결점수
	private int finalTermScore; // 기말점수
	
	// public static int presentationScore; // 29 변수용
	private static int presentationScore; // 29 메서드용
	
	// presentationScore 빼고 초기화
	public Asean(String name, int attendanceScore, int finalTermScore) {
		this.name = name;
		this.attendanceScore = attendanceScore;
		this.finalTermScore = finalTermScore;
	}
	
	// 스태틱 블록 내부 코드는 프로그램 시작 시 즉시 자동으로 한 번 호출된다.
	static { // static은 this를 사용하지 못한다.
		presentationScore = 29;
	}
	// 스태틱 메서드도 객체 없이 바로 호출 가능하다.
	public static void showPresentationScore() {
		System.out.println(presentationScore);
	}
	
	// 이 메서드는 객체 생성하고 나서 사용 가능한 메서드.
	public void showStudentScore() {
		System.out.println("학생명: " + this.name);
		System.out.println("출석 점수: " + this.attendanceScore);
		System.out.println("발표 점수: " + presentationScore);
		System.out.println("기말 점수: " + this.finalTermScore);
		System.out.println("최종성적: " + (this.attendanceScore + presentationScore + this.finalTermScore));
		System.out.println("---------------------------");
	}
}
package static_;

public class MainClass {

	public static void main(String[] args) {
    
		// 스태틱 메서드도 스태틱 변수처럼 객체 생성 이전에 할당된다.
		Asean.showPresentationScore();
		
		// 어떤 인스턴스를 활용해도 팀 점수 조회가 가능하다.
//		System.out.println(a1.presentationScore); // 변수가 private이 되면 호출 불가능해진다.
//		System.out.println(a2.presentationScore);
//		System.out.println(a3.presentationScore);
//		System.out.println(a4.presentationScore);
	}

}

presentationScore가 private이 되면 메인 메서드에서 직접적으로 호출 불가능해진다.

또한 기존에 있던 showStudentScore() 메서드도 객체 생성 후 사용 가능하기 때문에 객체 없이 사용 불가능하다.

 

이때 스태틱 메서드를 선언하면 private static 변수도 호출할 수 있다.

 

 

 

정적 메서드 또한 최초 실행 시 가장 먼저 스태틱 영역에 생성된다.

 

 

정적 초기화자(static initializer)

  • 정적 초기화자는 static 변수들의 초기화에 사용한다. 일반 멤버변수는 생성자에서 초기화하지만 static 변수는 객체 생성 없이도 사용해야하므로 생성자를 통해 초기화할 수 없다.
  • 그래서 static 변수는 정적초기화자를 통해 초기화를 한다.
  • 정적 초기화자는 클래스가 로딩될 때 생성자와 main() 메서드에 앞서 오직 단 한 번만 실행되기 때문에 애플리케이션 실행 중 반드시 한번만 실행되어야 할 로직이 있다면 이곳에 기술하여 사용될 수 있다.
static {
	클래스 내부에서 스태틱 변수를 초기화 시키는 코드들...
}