2018-2-28 TIL 클래스변수와 클래스메소드
클래스변수와 클래스메소드
- 인스턴스변수는 인스턴스가 생성될 때, 생성된 인스턴스 안에 존재하는 변수이다. 그러나 ‘클래스변수’는 인스턴스의 생성과 상관없이 존재하는 변수이다.
package yoon;
class InstCnt{
static int instNum = 0; // class varable
InstCnt(){ // Constructor
instNum++;
System.out.println("인스턴스 생성 : " + instNum);
}
}
public class ClassVar {
public static void main(String [] args){
InstCnt ctn1 = new InstCnt();
InstCnt ctn2 = new InstCnt();
InstCnt ctn3 = new InstCnt();
}
}
//result
인스턴스 생성 : 1
인스턴스 생성 : 2
인스턴스 생성 : 3
- 클래스변수는 인스턴스 내에 존재하는 변수가 아니라 ‘어떠한 인스턴스에도 속하지 않는 상태로 메모리 공간에 딱 하나만 존재하는 변수’ 이다.
클래스 변수의 접근 방법
- 클래스 내부 접근 : 변수의 이름을 통해 직접 접근
- 클래스 외부 접근 : 클래스 또는 인스턴스의 이름을 통해 접근
package yoon;
class AccessWay{
static int num = 0;
AccessWay(){
incrCnt();
}
void incrCnt() {
num++; // 클래스 내부에서 이름을 통한 접근
}
}
public class ClassVarAccess {
public static void main(String [] args){
AccessWay way = new AccessWay();
way.num++; // 외부에서 인스턴스의 이름을 통한 접근
AccessWay.num++; // 외부에서 클래스 이름을 통한 접근
System.out.println("num = " + AccessWay.num);
}
}
//result
num = 3
- 클래스 변수 num은 default로 선언이 되어있다. 따라서 클래스 내부는 물론 클래스 외부이더라도 동일 패키지로 묶여 있으면 접근이 가능하다!!
클래스 변수의 초기화 시점과 초기화 방법
package yoon;
class InstCnt2 {
static int instNum = 100;
InstCnt2(){
instNum++;
System.out.println("인스턴스 생성 : " + instNum);
}
}
public class OnlyClassNoInstance {
public static void main(String [] args){
InstCnt2.instNum -= 15; // 인스턴스 생성없이 instNum에 접근
System.out.println(InstCnt2.instNum);
}
}
//result
85
- 위의 코드를 통해 클래스 변수는 인스턴스 생성 이전에 메모리 공간에 존재하는것을 알 수 있다.
- 클래스 변수는 해당 클래스 정보가 가상머신에 의해 읽히는 순간 메모리 공간에 할당되고 초기화 된다.
클래스 메소드
- 클래스 내에 정의된 메소드에 static을 선언하면, ‘클래스메소드’가 된다. 접근방법도 클래스변수와 동일하며, 인스턴스 생성이전부터 호출이 가능하고 어느 인스턴스에도 속해있지 않다.
package yoon;
class NumberPrinter {
private int myNum = 0;
static void showInt(int n){ // class method
System.out.println(n);
}
static void showDouble(double n){
System.out.println(n);
}
void setMyNum(int n){
myNum = n;
}
void showMyNumber(){ // instance method
showInt(myNum);
}
}
public class ClassMethod {
public static void main(String [] args){
NumberPrinter.showInt(20);
// 클래스 이름을 통한 클래스 메소드 호출
NumberPrinter np = new NumberPrinter();
np.showDouble(3.15); // 인스턴스 이름을 통한 클래스 메소드 호출
np.setMyNum(75);
np.showMyNumber();
}
}
//result
20
3.15
75
Q. 클래스 메소드에서 같은 클래스에 선언된 인스턴스 변수에 접근이 가능한가?
class AAA {
int num = 0;
static void addNum(int n) {
num += n; // 이 문장이 유효한가?
}
}
- A. 클래스 메소드는 인스턴스에 속하지 않으므로 인스턴스 변수에 접근이 불가능하다.
- A. 같은 이유로 클래스 메소드는 인스턴스 메소드의 호출도 불가능하다.
System.out.println() 그리고 public static void main()
- System은 java.lang패키지에 묶여있는 기본클래스이다. 원칙적으로는 Java.lang.System.out.println(…);으로 호출을 해야한다. 그러나 컴파일러가 다음 문장을 삽입해주기 때문에 패키지의 이름부분을 생략할 수 있다.
import Java.lang *;
// 컴파일러가 삽입하는 import선언
- out은 Systme.out으로 접근을 하니, static으로 선언된 클래스 변수라고 추측이 가능하다.
public final class System extends Object {
public static final PrintStream out;
// 참조변수 out
}
- println은 PrintStream의 인스턴스 메소드이다.
Systme.out.println(...);
- System에 위치한 클래스 변수 out이 참조하는 인스턴스의 println 메소드를 호출하는 문장
main메소드가 public이고 staitc인 이유는?
- main메소드 다음과 같은 구성이다
public static void main(String [] args){
...
}
- main메소드의 호출이 이뤄지는 영역은 클래스 외부이다. 따라서 public으로 선언이 되어한다.
- main메소드는 인스턴스가 생성되기 전에 호출된다. 따라서 static선언이 당연하다.
static의 또 다른 용도
static 초기화 블록(Static Initialization Block)
- static 초기화 블록은 가상머신이 클래스의 정보를 읽어 들일 때, 실행이 된다.
package yoon;
import java.time.LocalDate;
public class DateOfExecution {
static String date;
static { // 클래스 로딩 시 단 한번 실행이 되는 영역
LocalDate nDate = LocalDate.now();
date = nDate.toString();
}
public static void main(String [] args){
System.out.println(date);
}
}
//result
2018-02-26
Written on February 28, 2018