✔ static 선언을 붙여서 선언하는 클래스 변수
클래스 변수(static 변수)란?
- 인스턴스가 생성되었을 때, 생성된 인스턴스 안에 존재하는 변수인 인스턴스 변수와 달리,
클래스 변수는 인스턴스의 생성과 상관없이 존재하는 변수 - 클래스 내에서 선언된 변수 앞에 static 선언을 붙이면 클래스 변수가 됨
- 클래스 변수는 인스턴스 내에 존재하는 변수가 아니라,
어떠한 인스턴스에도 속하지 않는 상태로 메모리 공간에 딱 하나만 존재하는 변수 - 이렇게 static으로 선언된 변수는 변수가 선언된 클래스의 모든 인스턴스가 공유하는 변수가 됨
- 클래스 변수는 인스턴스 내에 존재하는 변수가 아니라,
class InstCnt {
static int instNum = 0;
InstCnt() {
instNum++;
System.out.println("인스턴스 생성: " + instNum);
}
}
class ClassVar {
public static void main(String args[]) {
InstCnt cnt1 = new InstCnt(); // 1
InstCnt cnt2 = new InstCnt(); // 2
InstCnt cnt3 = new InstCnt(); // 3
}
}
- 인스턴스 간에 데이터 공유가 필요한 상황에서 클래스 변수를 선언
- 또는 참조를 목적으로 존재하는 값은 final 선언이 된 클래스 변수에 담아 사용
- 예) 원주율을 값을 가진 PI
클래스 변수의 접근 방법
- 클래스 내부에서 접근할 경우에는 변수의 이름을 통해 직접 접근함
- 클래스 외부에서 접근할 경우에는 클래스 또는 인스턴스의 이름을 통해 접근함
class AccessWay {
static int num = 0;
AccessWay() {
increCnt();
}
// 클래스 내부 : 변수의 이름을 통해 직접 접근
void incrCnt() {
num++;
}
}
class ClassVarAccess {
public static void main(String args[]) {
AccessWay way = new AccessWay();
// 클래스 외부 : 인스턴스의 이름을 통해 접근
way.num++;
// 클래스 외부 : 클래스의 이름을 통해 접근
AccessWay.num++;
}
}
클래스 변수의 초기화 시점과 초기화 방법
- 클래스 변수는 인스턴스 생성 이전에 메모리 공간에 존재하므로
인스턴스의 생성과 무관하게 해당 클래스 정보가 가상머신에 의해 읽히는 순간 메모리 공간에 할당되고 초기화됨- 그러므로 생성자를 통한 클래스 변수의 초기화를 진행하지 않도록 주의해야 함
✔ static 선언을 붙여서 선언하는 클래스 메소드
클래스 메소드(static 메소드)란?
- 클래스 내에 정의된 메소드에 static 선언을 붙이면 클래스 메소드가 됨
- 인스턴스 생성 이전부터 접근이 가능하므로 불필요한 인스턴스의 생성 과정을 생략할 수 있음
- 어느 인스턴스에도 속하지 않는 메소드
- 클래스 변수와 동일한 접근 방법을 가짐
class NumberPrinter {
private int myNum = 0;
static void showInt(int n) {
System.out.println(n);
}
// 클래스 내부 : 메소드의 이름을 통해 직접 접근
void showMyNumber() {
showInt();
}
}
class ClassMethod {
public static void main(String args[]) {
// 클래스 외부 : 클래스의 이름을 통해 접근
NumberPrinter.showInt(20);
// 클래스 외부 : 인스턴스의 이름을 통해 접근
NumberPrinter np = new NumberPrinter();
np.showInt(20);
}
}
- 클래스 메소드는 인스턴스에 속하지 않으므로 인스턴스 변수에 접근이 불가능하며, 인스턴스 메소드의 호출도 불가능
- 하지만 같은 클래스에 정의되어 있는 다른 클래스 메소드나 클래스 변수에는 접근이 가능함
✔ System.out.println() 그리고 public static void main()
out과 println의 정체는?
- System은 자바에서 제공하는 클래스로 java.lang 패키지에 묶여 있음
- 원칙적으로는 java.lang.System.out.println이 되어야 하지만 컴파일러가 java.lang.* 패키지를 import 선언해주게 됨
- 그리고 out은 System.out으로 접근을 하니 static으로 선언된 클래스 변수
- 마지막으로 println은 PrintStream 클래스의 인스턴스 메소드
- 즉, 이는 System에 위치한 클래스 변수 out이 참조하는 인스턴스의 println 메소드를 호출하는 문장임을 알 수 있음
public final class System extends Object {
public static final PrintStream out;
...
}
main 메소드가 public이고 static인 이유는?
- main 메소드의 호출이 이뤄지는 영역은 클래스 외부이므로 public으로 선언해야 함
- 그리고 main 메소드는 인스턴스가 생성되기 이전에 호출되므로 static으로 선언해야 함
- 이러한 main 메소드는 main 메소드를 담기 위한 별도의 클래스를 정의하는 것이 일반적
- 그러나 상황과 프로그래머의 성향에 따라서 다양한 형태로 어디든 존재할 수 있음
✔ 또 다른 용도의 static 선언
static 초기화 블록
- 클래스 변수에 대해서 선언과 동시에 초기화를 하고 싶다면 생성자는 적절하지 않음
- 이러한 상황을 고려하여 자바는 static 초기화 블록을 제공
- 이는 클래스 변수와 마찬가지로 가상머신이 클래스의 정보를 읽어 들일 때 실행이 되어
클래스 변수를 선언과 동시에 초기화할 수 있음
- 이는 클래스 변수와 마찬가지로 가상머신이 클래스의 정보를 읽어 들일 때 실행이 되어
class DateofExecution {
static String date;
static {
LocalDate nDate = LocalDate.now();
date = nDate.toString();
}
public static void main(String args[]) {
System.out.println(date);
}
}
static import 선언
- 클래스 변수에 접근할 때 클래스 이름이 아닌, 클래스 변수의 이름만으로 접근하기 위해서는 static import를 선언함
- 최소한으로 사용할 경우 도움이 되지만,
빈번히 사용할 경우 해당 메소드 또는 변수가 어디에 정의되고 선언된 것인지 구분이 힘들어져 오히려 방해가 될 수 있음
System.out.println(Math.PI);
import static java.lng.Math.PI;
System.out.println(PI);
'Java-Spring > 열혈 Java 프로그래밍' 카테고리의 다른 글
[Java] 콘솔 입력과 출력 (0) | 2023.08.03 |
---|---|
[Java] 메소드 오버로딩과 String 클래스 (0) | 2023.08.03 |
[Java] 정보 은닉 그리고 캡슐화 (0) | 2023.08.02 |
[Java] 패키지와 클래스 패스 (0) | 2023.08.01 |
[Java] 클래스와 인스턴스 (0) | 2023.08.01 |