static 키워드를 사용하면 특정 클래스에서 공용으로 함께 사용할 수 있는 변수를 만들 수 있다.
public class Data3 {
public String name;
public static int count
public Data3(String name) {
this.name = name;
count ++;
}
}
public class DataCountMain {
public static void main(String[] args) {
Data3 data1 = new Data3("A");
System.out.prinln("A count" + Data3.count); // A count = 1
Data3 data2 = new Data3("B");
System.out.prinln("B count" + Data3.count); // B count = 2
Data3 data3 = new Data3("C");
System.out.prinln("C count" + Data3.count); // C count = 3
}
}
위 코드를 보면 count 정적 변수에 접근하는 방법이 조금 다르다. Data.count와 같이 클래스 명에 .을 사용한다. 클래스에 직접 접근하는 것 같이 느낄 수도 있다.
Java 코드의 메모리 영역에는 메서드 영역, 스택 영역, 힙 영역이 있는데, static 변수는 힙 영역에 생성되지 않고 메서드 영역에서 관리한다.

당신이 설명하신 비유를 조금 더 쉽게 풀어보겠습니다.
예를 들어 붕어빵 틀이 하나 있고, 이 틀을 이용해 10개의 붕어빵을 만든다고 가정해보자. 붕어빵 틀은 static 변수를 가지고 있으면 이 변수는 붕어빵 틀과 관련된 모든 붕어빵이 공유하는 값이다. 예를 들어, "현재 만들어진 붕어빵의 총 개수"라는 static 변수를 두면, 이 값은 10이 된다.
반면에 붕어빵 각각은 자신만의 특성을 가지고 있을 수 있다. 예를 들어, 붕어빵의 속에 어떤 재료가 들어있는지는 각 붕어빵마다 다를 수 있는데 이런 것이 바로 인스턴스 변수입니다.
다시 정리하면 static 변수는 붕어빵 틀(클래스)이 특별히 관리하는 변수이고, 이 변수는 클래스가 생성하는 모든 인스턴스(붕어빵)가 공유한다. 즉, 붕어빵 틀에 하나만 존재하는 정보입니다.
인스턴스 변수는 붕어빵(인스턴스)마다 고유하게 존재하는 정보로 각 붕어빵마다 다른 값을 가질 수 있다.
지역변수(매개변수 포함)
지역변수는 스택 영역 안에 있는 스택 프레임 안에 보관된다. 메서드가 종료되면 스택 프레임도 제거 되는데 이때 해당 스택 프레임에 포함된 지역 변수도 함께 제거된다.
인스턴스 변수
인스턴스에 있는 멤버 변수를 인스턴스 변수라고 하는데, 인스턴스 변수는 힙영역을 사용한다. 힙영역은 가비지 컬렉션이 발생하기 전까지는 생존하기 때문에 지역 변수보다 생존 주기가 길다.
클래스 변수
클래스 변수는 메서드 영역의 static 영역에 보관되는 변수로 메서드 영역은 프로그램 전체에서 사용하는 공용 공간이다. 클래스 변수는 해당 클래스가 JVM에 로딩 되는 순간 생성된다. 그리고 JVM이 종료될 때 까지 생명주기가 이어진다. 따라서 가장 긴 생명 주기를 가진다.
static이 정적이라는 이유에는 여기에 있는데, 힙 영역에 생성되는 인스턴스 변수는 동적으로 생성되고, 제거된다. 반면에 static 인 정적 변수는 거의 프로그램 실행 시점에 딱 만들어지고, 프로그램 종료 시점에 제거된다. 정적 변수는 이름 그대로 정적이다.
자바 가상 머신(JVM)에 의해 구동되는 자바 프로그램은 메모리 관리를 개발자가 직접 명시적으로 수행하지 않고, 자동 메모리 관리 기능을 지원한다. 가비지 컬렉션은 자바의 메모리 관리 방법 중 하나로 자바 가상 머신의 Heap영역에서 동적으로 할당했던 메모리 중 필요 없게 된 메모리 객체를 모아 주기적으로 제거하는 프로세스를 의미한다.
package memory;
public class DecoUtil1 {
public String deco (String str) {
return "*" + str + "*";
}
}
package memory;
public class DecoMain1 {
public static void main(String[] args) {
String s = "hello java";
DecoUtil1 decoUtil1 = new DecoUtil1();
String deco = decoUtil1.deco(s);
System.out.println(deco);
String deco2 = decoUtil1.deco(deco);
System.out.println(deco2);
}
}
deco 메서드를 사용하기 위해 인스턴스를 생성하고 있다. 굳이 생성하지 않고도 사용할 수 있게끔 하기 위해 static을 사용한다.public class DecoUtil1 {
public static String deco (String str) {
return "*" + str + "*";
}
}
public class DecoMain1 {
public static void main(String[] args) {
String s = "hello java";
String deco = DecoUtil1.deco(s);
System.out.println(deco);
}
}
static 메서드는 객체 생성 없이 메서드를 바로 호출할 수 있다는 장점이 있다. 하지만 제약없이 사용할 수 있진 않다.
static메서드는 static만 사용할 수 있다. static이 붙은 정적 메서드나 정적 변수만 사용할 수 있다.public class DecoData {
private int instanceValue;
private static int staticValue;
public static void staticCall() {
//instanceValue++; // 인스턴스 변수 접근, compile error
//instanceMethod(); // 인스턴스 메서드 접근, compile error
staticValue++;
staticMethod();
}
public void instanceCall() {
instanceValue++;
instanceMethod();
staticValue++;
staticMethod();
}
private void instanceMethod() {
System.out.println("instance method");
}
private void staticMethod() {
System.out.println("static method");
}
}
static메서드는static만 사용할 수 있으며 클래스 내부의 기능을 사용할 때, 정적 메서드는static이 붙은 정적 메서드나 정적 변수만 사용할 수 있 다.- 클래스 내부의 기능을 사용할 때, 정적 메서드는 인스턴스 변수나, 인스턴스 메서드를 사용할 수 없다. 반대로 모든 곳에서
static을 호출할 수 있다.
정적 메서드는 공용 기능이다. 따라서 접근 제어자만 허락한다면 클래스를 통해 모든 곳에서static을 호출할 수 있다.
정적 메서드가 인스턴스의 기능을 사용할 수 없는 이유
정적 메서드는 클래스의 이름을 통해 바로 호출할 수 있다. 그래서 인스턴스처럼 참조값의 개념이 없다.
특정 인스턴스의 기능을 사용하려면 참조값을 알아야 하는데, 정적 메서드는 참조값 없이 호출한다. 따라서 정적 메서드 내부에서 인스턴스 변수나 인스턴스 메서드를 사용할 수 없다.물론 당연한 이야기지만 다음과 같이 객체의 참조값을 직접 매개변수로 전달하면 정적 메서드도 인스턴스의 변수나 메서드를 호출할 수 있다.
public static void staticCall(DecoData data) {
data.instanceValue++;
data.instanceMethod();
}
김영한 - 실전 자바