static 클래스 변수 (참고: 변수, 상수, 리터럴 - 3. 종류)
"static" = "공통적인", "클래스의"
static 키워드를 붙이면, Java 가 메모리 할당을 딱 한번만 하도록 만듦
정적 멤버는 객체(인스턴스)에 소속된 멤버가 아니라 클래스에 고정된 멤버
→ 따라서, 클래스 로더가 클래스를 로딩해서 메소드 메모리 영역에 적재할때 클래스별로 관리된다.
→ 따라서, 클래스의 로딩이 끝나는 즉시 바로 사용 가능
Static 키워드를 통해 생성된 정적 멤버들은 Heap영역이 아닌 Static영역에 할당된다.
(new 연산을 통해 생성한 객체는 Heap영역에 생성된다.)
장점
Static 영역에 할당된 메모리는 모든 객체가 공유하여, 하나의 멤버를 어디서든지 참조할 수 있다.
단점
Garbage Collector의 관리 영역 밖에 존재하므로, Static영역에 있는 멤버들은 프로그램의 종료 시까지 메모리가 할당된 채로 존재
→ Static을 남발할 시, 시스템 성능 ↓
Static영역을 활용하고자 한다면,
객체 생성을 위해 생성자보다는 정적 팩토리 메서드를 사용해야한다.
// 정적 필드
// 타입 필드 = 초기값
static int num = 0;
// 정적 메소드
// static 리턴 타입 메소드 {}
public static void static_method(){}
필드/메소드 생성 시, 인스턴스로 생성할것인지 정적으로 생성할것인지에 대한 판단 기준은 공용으로 사용하느냐 아니냐
로 내리면 된다.
그냥 생성한다면, 자동으로 인스턴스로 생성되며
정적으로 생성하려면, 필드와 메소드 선언 시 static이라는 키워들를 추가적으로 붙이면 된다.
// 1. Number 클래스 안에 클래스 변수 num1, 인스턴스 변수 num2 를 생성
class Number{
static int num1 = 0; // 클래스 필드
int num2 = 0; // 인스턴스 필드
}
public class Static_ex {
// 2. Number인스턴스인 number1, number2 를 생성했을 때,
public static void main(String[] args) {
Number number1 = new Number(); // 첫번째 number
Number number2 = new Number(); // 두번쨰 number
// 3. number1에서 num1과 num2를 각각 1씩 증가
number1.num1++; // 클래스 필드 num 을 1증가시킴
number1.num2++; // 인스턴스 필드 num 을 1증가시킴
// 4. number2 에서 num1, num2 를 각각 출력시켰을 때, num1 은 1, num2 는 0 을 출력
System.out.println(number2.num1); // 두번째 number의 클래스 필드 출력
System.out.println(number2.num2); // 두번째 number의 인스턴스 필드 출력
}
}
num1 은 1, num2 는 0 을 출력된 이유
인스턴스 변수는 인스턴스가 생성될 때마다 생성되므로, 인스턴스마다 각기 다른 값을 가지지만(num2)
정적 변수는 모든 인스턴스가 하나의 저장공간을 공유하기에 항상 같은 값을 가지기 때문이다.(num1)
클래스 메서드라고도 부른다
인스턴스 멤버(인스턴스 변수, 인스턴스 메서드) 와 관련없는 작업을 하는 메서드
메서드 내에서 인스턴스 변수 사용 불가능
객체 생성 없이 '클래스이름.메서드이름()'으로 호출
ex) Math.random()
class Name{
// 클래스 메소드
static void print1() {
System.out.println("내 이름은 홍길동입니다.");
}
// 인스턴스 메소드
void print2() {
System.out.println("내 이름은 이순신입니다.");
}
}
public class Static_ex {
public static void main(String[] args) {
Name.print1(); // 인스턴스를 생성하지 않아도 호출이 가능
Name name = new Name(); // 인스턴스 생성
name.print2(); // 인스턴스를 생성하여야만 호출이 가능
}
}
/* 출력결과
내 이름은 홍길동입니다.
내 이름은 이순신입니다.
*/
// 인스턴스 변수의 경우
class StaticMethod7_1 {
int num1, num2; // 인스턴스 변수 선언
static int add(int num1, int num2) { // 메서드 반환타입 앞에 static 이 붙었기 때문에 static 메서드가 됩니다.
System.out.println();
System.out.println("매개변수로 입력 받은 num1, num2 확인");
System.out.println("num1 = " + num1);
System.out.println("num2 = " + num2);
// 여기서 매개 변수에 있는 num1, num2 와 위에 인스턴스 변수로 선언한 num1, num2 는 같은 걸까요?
// 기본형 매개변수에서 배웠듯이 같지 않습니다. 서로 영향을 받지 않습니다.
// 여기서의 num1 과 num2 는 단지 인스턴스 변수와 이름만 같은 지역변수일 뿐 메서드가 종료되면 사라집니다.
// 인스턴스 변수는 클래스 메서드에서 사용하지 못합니다.
}
}
// 클래스 변수의 경우
class StaticMethod7_1 {
// 클래스 변수 선언
static int num1 = 10, num2 = 20;
static int add(int num1, int num2) { // 메서드 반환타입 앞에 static 이 붙었기 때문에 static 메서드가 됩니다.
System.out.println();
System.out.println("매개변수로 입력 받은 num1, num2 확인");
System.out.println("num1 = " + num1);
System.out.println("num2 = " + num2);
// 추가로 StaticMethod7_1 에 선언한 변수를 사용하고 싶다면?
// 인스턴스 변수가 아닌 클래스 변수를 선언해야합니다. static 타입 변수이름;
// 자 그럼 이제 클래스 변수로 선언을 했으니까
// 매개 변수에 있는 num1, num2 와 위에 클래스 변수로 선언한 num1, num2 는 같은 걸까요?
// 그렇지 않습니다. 위에서 말씀드렸듯이 num1, num2는 매개변수이자 클래스 변수와 이름만 같습니다.
// 또한 클래스 변수 를 사용하려면 클래스명.클래스변수 로 만 접근 가능합니다.
// 이렇게 클래스 메서드에서 클래스 변수를 사용할 수 있다.
System.out.println("클래스변수 확인");
System.out.println("StaticMethod7_1.num1 = " + StaticMethod7_1.num1);
System.out.println("StaticMethod7_1.num2 = " + StaticMethod7_1.num2);
System.out.println("num1 + num2 = " + (num1 + num2));
return num1 + num2;
}
}
class StaticMethod7_1Main {
public static void main(String[] args) {
StaticMethod7_1 methodTest = new StaticMethod7_1(); // 객체 생성
methodTest.num1 = 10;
methodTest.num2 = 20;
// methodTest.add(methodTest.num1, methodTest.num2); // add 는 static 메서드 이기 때문에 객체로 생성된 참조변수로는 접근할 수 없습니다.
// 클래스이름.메서드이름() 방식으로 static 메서드를 호출
StaticMethod7_1.add(methodTest.num1, methodTest.num2);
}
}
class Singleton {
private static Singleton one; // static 변수인 one
private Singleton() {
}
// getInstance() 메서드에서 one 값이 null 인 경우에만 객체를 생성하도록 하여, one 객체가 딱 한 번만 만들어지도록 했다.
public static Singleton getInstance() {
if(one==null) {
one = new Singleton();
}
return one;
}
}
public class Sample {
public static void main(String[] args) {
Singleton singleton1 = Singleton.getInstance();
Singleton singleton2 = Singleton.getInstance();
System.out.println(singleton1 == singleton2); // true 출력
}
}