정적인 멤버, 클래스의 멤버를 정의할 때 사용한다.
별도의 객체 생성 없이 클래스로 접근해 사용한다.
컴파일 후 자바 프로그램 실행 단계는 아래와 같다.
1. 클래스 로딩 - 클래스 정보(임포트, 상속관계 등 붕어빵 틀 정보)와 함께 이 시점에 static member가 메모리(meta space) 영역에 미리 적재
2. 코드 검증 (Byte Code Verifier)
3. 실행을 하는 Runtime 실행 단계 - main이 실행되면서 -> 객체 생성 (heap 메모리 영역에 객체가 적재)
순서1에서 static variable (or class variable)은 class loading 시점에 meta space 메모리 영역 하나의 공간에 저장된다는것을 알 수 있다.
이와는 다르게 instance variable(object member variable)은 runtime시 객체 생성 후 heap 메모리 영역에 각각의 객체의 공간에 저장된다.
Java Memory는 다음과 같다.
Stack 영역 : local variable 정보가 저장되는 영역, LIFO (Last In, First Out)
Heap 영역 : Object의 instance variable 정 보가 저장되는 영역
Meta space 영역 : class의 meta data(package, class, method ...)가 저장되는 영역으로 static member 정보가 저장된다.
package stpe1;
class StaticExam1{
int bonus; // instance variable (object member variable)
static int money; //static variable (class member variable)
public void test1() { //method
System.out.println("object member method");
}
public static void test2() { //static method
System.out.println("class member method == static method");
}
}
public class TestStatic1 {
public static void main(String[] args) {
StaticExam1 e = new StaticExam1();
System.out.println(e.bonus); //bonus에 접근하는법
// System.out.println(StaticExam1.bonus);
// non-static이기때문에 반드시 객체를 생성해야한다.
System.out.println(StaticExam1.money);
//static은 별도의 객체 생성없이 클래스이름.static멤버로 접근 가능
StaticExam1.test2(); //static method 이므로 클래스, 메소드로 호출 가능
// StaticExam1.test1();
// compile error, non-static method이므로 객체생성이 반드시 필요하다.
e.test1();
}
}
첫줄부터 살펴보면서 static의 특징을 알아보도록하자.
int bonus;
1.bonus 변수는 instance variable (object member variable)로 선언되었다. 위에 설명과 같이 자바 프로그램 순서3에서 실행을 하는 Runtime 실행 단계에 heap 메모리에 적재된다.
static int money;
2.money 변수는 static variable (class member variable)로 선언되었다. static member이기 때문에 클래스 로딩시(순서1)에 meta space 메모리에 적재된다.
public void test1() { //method
System.out.println("object member method");
}
public static void test2() { //static method
System.out.println("class member method == static method");
}
public static void main(String[] args) {
StaticExam1 e = new StaticExam1();
System.out.println(e.bonus);
// System.out.println(StaticExam1.bonus);
// non-static이기때문에 반드시 객체를 생성해야한다.
System.out.println(StaticExam1.money);
//static은 별도의 객체 생성없이 클래스이름.static멤버로 접근 가능
StaticExam1.test2(); //static method 이므로 클래스, 메소드로 호출 가능
// StaticExam1.test1();
// compile error, non-static method이므로 객체생성이 반드시 필요하다.
e.test1();
}
StaticExam1 e = new StaticExam1();
System.out.println(e.bonus);
e.bonus 코드를 통해 bonus 변수에 접근하고있다.
int는 0으로 초기화되기에 0을 출력할 것이다.
// System.out.println(StaticExam1.bonus);
주석처리된 코드를 살펴보자.
bonus의 값을 알기위해 클래스이름.변수 로 접근하고있다.
여기서 주의할 점이 있다. 왜 우리는 위에 코드처럼 e.bonus 로 접근하는 것일까?
이또한 실행 순서와 관련이 있다.
앞서 말한것처럼 instance 변수는 런타임시 heap 메모리 영역에 객체가 생성된 후 적재된다.
무조건 객체를 생성해야만 접근할 수 있다는 것이다.
때문에 객체를 생성하지않는 StaticExam1.bonus 코드로는 결과값을 알 수 없다.
System.out.println(StaticExam1.money);
static은 별도의 객체 생성없이 클래스이름.static멤버로 접근이 가능하다.
StaticExam1.test2();
test2()는 static member로 선언되었다.
클래스이름.메소드로 호출 가능하다.
e.test1();
e는 객체 생성된 참조 변수 이기때문에 instance method인 test1()을 객체를 생성하고 올바르게 호출한 것을 알 수 있다.
static과 non-static과의 접근 특성
package stpe1;
class StaticExam2{
int money1; //non-static, instance variable
static int money2; //static variable
public void test1() {
// non static method 내부에서 접근 여부를 테스트
System.out.println(money1); //같은 non-static이기때문에 접근 가능
System.out.println(money2); //static은 미리 메모리에 적재됨으로 접근 가능한 것이다.
}
public static void test2() { //클래스 로디잇점에 저장되기때문에 메타스페이스에 non-static i.v new로 객체 생성할때 메모리에 있다 없다 보장할수 없기때문에 객체 생성하고 접근해야
//
// static method 내부에서 접근 여부 테스트
System.out.println(money2); //같은 static 끼리이므로 접근 가능
// System.out.println(money1);
// static 에서 non-static으로 instance variable로 직접 접근은 불가
// 이유는 static은 객체 생성 없이 미리 클래스 로딩시에 메모리에 적재가되고 (meta space) ,
// i.v인 money1은 객체 생성을 할때만 메모리에 (heap) 적재되므로 직접 접근 불가능하고 접근을 위해서는 객체 생성 작업이 선행되어야 한다.
// 아래와같이 객체 생성해서 접근하면 된다.
StaticExam2 exam = new StaticExam2();
System.out.println(exam.money1);
}
}
public class TestStatic2 {
public static void main(String[] args) {
StaticExam2 exam = new StaticExam2();
exam.test1();
StaticExam2.test2(); //test2 메서드가 static 이므로 클래스로 접근해 객체 생성 없이 사용 가능
}
}
int money1; //non-static, instance variable
static int money2; //static variable
money는 non-static으로 instance variable이다. 객체 생성 후 사용할 수 있다.
money2는 static variable로 만들어졌다. 런타임 이전에 클래스 로딩시 생성된다.
2.
public void test1() {
System.out.println(money1);
System.out.println(money2);
}
non static method 내부에서 접근 여부를 테스트한다.
test1()은 non-static method이다.
money1은 같은 non-static이기때문에 접근이 가능하다.
money2는 static variable로 이의 특징은 미리 메모리에 적재됨으로 접근 가능한 것이다.
즉 test1()을 호출한다면 money2는 이전에 클래스 로딩시 메모리에 적재되어있기때문에 접근 가능하다.
3.
public static void test2() {
System.out.println(money2); //같은 static 끼리이므로 접근 가능
// System.out.println(money1);
// static 에서 non-static으로 instance variable로 직접 접근은 불가
// 이유는 static은 객체 생성 없이 미리 클래스 로딩시에 메모리에 적재가되고 (meta space),i.v인 money1은 객체 생성을 할때만 메모리에 (heap) 적재되므로 직접 접근 불가능하고 접근을 위해서는 객체 생성 작업이 선행되어야 한다.
// 아래와같이 객체 생성해서 접근하면 된다.
StaticExam2 exam = new StaticExam2();
System.out.println(exam.money1);
}
static method 내부에서 접근 여부 테스트이다.
test2()는 static method로 만들어졌다.클래스 로딩시점에 저장되기때문에 meta space에 non-static i.v new로 객체를 생성하는 시점에 메모리에 있는지 없는지 보장할 수 없기때문에 여기서 접근하려면 객체를 생성하고 접근해야한다.
public static void main(String[] args) {
StaticExam2 exam = new StaticExam2();
exam.test1();
StaticExam2.test2(); //test2 메서드가 static 이므로 클래스로 접근해 객체 생성 없이 사용 가능
}
instance member인 test1()은 객체를 생성하고 접근하고, class member(static)인 test2()는 클래스로 접근해 객체 생성 없이 사용가능하다.
static과 non-static 접근
:static에서 non-static으로 접근하기 위해서는 반드시 객체 생성이 필요하다.
:non-static에서 static으로 접근은 바로 가능
public class TestStatic7 {
public static void main(String[] args) {
System.out.println("main 실행");
}
static {
System.out.println("static 초기화 영역");
}
}
static 초기화 영역
main 실행
static 초기화 영역은 메인 메소드에 우선해서 실행된다는 것을 알 수 있다.