네트워크 캠퍼스/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 {
클래스 내부에서 스태틱 변수를 초기화 시키는 코드들...
}