Java에서 정적 멤버(static member)란
static 키워드가 붙어 객체 생성 여부와 상관없이 클래스에 소속되는 멤버를 말한다.
즉, 객체(new)를 생성하지 않아도 사용할 수 있고
클래스 로딩 시점에 JVM에 의해 메모리의 Method 영역에 올라가고
프로그램 종료 시까지 유지된다.
정적 멤버에는 대표적으로 다음 두 가지가 있다.
class Example {
static int count; // 정적 필드
static void printCount() { // 정적 메서드
System.out.println(count);
}
}
이들은 모두 객체가 아닌 클래스에 속한다는 공통점을 가진다.
정적 필드는 나의 클래스에 대해 단 하나만 존재하며
해당 클래스에서 생성된 모든 인스턴스가 이 값을 공유한다.
따라서 객체를 여러 개 생성하더라도
정적 필드는 객체마다 새로 만들어지지 않고
클래스 기준으로 하나의 값이 유지된다.
다음 예제를 살펴보자.
public class A_StaticField {
// 정적 필드
// 정적 필드는 클래스가 로드될 때 생성되고 프로그램이 종료될 때 소멸된다.
public static int number = 101;
private static String message = "Hello World";
// 정적 필드에 대한 Getter, Setter 메서드도 static 키워드를 사용해서 접근한다.
public static String getMessage() {
return message;
}
public static void setMessage(String message) {
// 정적 필드는 객체를 생성하지 않고 접근하기 때문에 this로 접근할 수 없음
// this.message = message;
A_StaticField.message = message;
}
}
public class Application {
public static void main(String[] args) {
// 1. 정적 필드 테스트
// 1-1). 정적 필드 생성 및 출력
System.out.println(A_StaticField.number); // 101
System.out.println(A_StaticField.getMessage()); // "Hello World"
System.out.println();
// 1-2). 객체의 정적 필드 공유
A_StaticField a1 = new A_StaticField();
A_StaticField a2 = new A_StaticField();
// 객체 참조를 통한 접근 (컴파일 가능하지만 권장 X)
System.out.println(a1.number); // 101
System.out.println(a2.number); // 101
// 클래스 이름을 통한 접근 (권장)
System.out.println(A_StaticField.number); // 101
System.out.println();
// 1-3). 정적 필드의 Getter, Setter 메서드
A_StaticField.setMessage("Goodbye World");
System.out.println(A_StaticField.getMessage()); // "Goodbye World"
}
클래스 이름으로 접근 가능
System.out.println(A_StaticField.number); // 101
System.out.println(A_StaticField.getMessage()); // "Hello World"
객체를 생성하지 않아도 바로 사용할 수 있다.
객체 간 값 공유
A_StaticField a1 = new A_StaticField();
A_StaticField a2 = new A_StaticField();
// 객체 참조를 통한 접근 (컴파일 가능하지만 권장 X)
System.out.println(a1.number); // 101
System.out.println(a2.number); // 101
// 클래스 이름을 통한 접근 (권장)
System.out.println(A_StaticField.number); // 101
A_StaticField.number는 두 객체가 같은 값을 바라본다.
→ 정적 필드는 인스턴스별로 새로 생성되지 않는다.
정적 필드에 대한 Getter / Setter
// 정적 필드에 대한 Getter, Setter 메서드도 static 키워드를 사용해서 접근한다.
public static String getMessage() {
return message;
}
this 키워드 접근 불가 → 클래스 이름을 사용하여 접근
public static void setMessage(String message) {
// 정적 필드는 객체를 생성하지 않고 접근하기 때문에 this로 접근할 수 없음
// this.message = message;
A_StaticField.message = message;
}
정적 메서드는 객체를 생성하지 않고 클래스 이름으로 호출 가능한 메서드이다.
정적 메서드 역시 여러가지 특징을 가지고 있다.
다음 예제를 살펴보자.
public class B_StaticMethod {
// 정적 필드
private static int num1 = 10;
private static int num2 = 18;
// 인스턴스 필드
private int num3 = 30;
// 1. 매개 변수와 반환값이 없는 정적 메서드
public static void method01() {
System.out.println(num1 + num2++);
// 정적 메서드에서는 인스턴스 필드에 접근할 수 없다.
// 정적 메서드는 객체를 생성하지 않고 사용하므로 인스턴스 필드에 접근할 수 없다.
// System.out.println(num3);
}
// 2. 매개 변수가 없고 반환값이 있는 메서드
public static int method02() {
int num1 = 20;
int num2 = 30;
// 정적 메서드에서는 this 키워드를 사용할 수 없다.
// 따라서, B_StaticMethod.num1 형태로 접근한다.
return num1 + num2 + B_StaticMethod.num2;
}
// 3. 매개 변수가 있고 반환값이 없는 메서드
public static void method03(int number) {
// 정적 메서드 안에서 다른 정적 메서드를 호출할 수 있다.
// 단, 정적 메서드 안에서 일반 메서드는 호출할 수 없다.
// this와 마찬가지로 객체를 생성하지 않고 사용하기 때문이다.
// ex). sum(number);
System.out.println(B_StaticMethod.method02() + number);
}
private int sum(int number) {
return number + this.num3;
}
// 4. 매개 변수와 반환값이 있는 정적 메서드
public static int method04(int... numbers) {
return Arrays.stream(numbers).sum();
}
}
public class Application {
public static void main(String[] args) {
// 2.정적 메서드 테스트
// 2-1). 매개 변수와 반환값이 없는 정적 메서드 호출
B_StaticMethod.method01(); // 28
B_StaticMethod.method01(); // 29
System.out.println();
// 2-2). 매개 변수가 없고 반환값이 있는 정적 메서드 호출
System.out.println(B_StaticMethod.method02()); // 70
// 2-3). 매개 변수가 있고 반환값이 없는 정적 메서드 호출
B_StaticMethod.method03(100); // 170
System.out.println();
// 2-4). 매개 변수와 반환값이 있는 정적 메서드 호출
System.out.println(B_StaticMethod.method04());
System.out.println(B_StaticMethod.method04(4, 5, 15));
System.out.println(B_StaticMethod.method04(4, 5, 15, 25, 35));
System.out.println();
}
정적 메서드에서는 인스턴스 필드에 접근할 수 없다.
public class B_StaticMethod {
// 정적 필드
private static int num1 = 10;
private static int num2 = 18;
// 인스턴스 필드
private int num3 = 30;
public static void method01() {
System.out.println(num1 + num2++);
// 정적 메서드에서는 인스턴스 필드에 접근할 수 없다.
// 정적 메서드는 객체를 생성하지 않고 사용하므로 인스턴스 필드에 접근할 수 없다.
// System.out.println(num3);
}
}
정적 메서드에서는 this 키워드를 사용할 수 없다.
public class B_StaticMethod {
// 정적 필드
private static int num1 = 10;
private static int num2 = 18;
// 인스턴스 필드
private int num3 = 30;
public static int method02() {
int num1 = 20;
int num2 = 30;
// 정적 메서드에서는 this 키워드를 사용할 수 없다.
// 따라서, B_StaticMethod.num1 형태로 접근한다.
return num1 + num2 + B_StaticMethod.num2;
}
}
정적 메서드 안에서 일반 메서드는 호출할 수 없다.
public class B_StaticMethod {
public static void method03(int number) {
// 정적 메서드 안에서 다른 정적 메서드를 호출할 수 있다.
// 단, 정적 메서드 안에서 일반 메서드는 호출할 수 없다.
// this와 마찬가지로 객체를 생성하지 않고 사용하기 때문이다.
// ex). sum(number);
System.out.println(B_StaticMethod.method02() + number);
}
private int sum(int number) {
return number + this.num3;
}
}
// Java.lang.Math
public class Application {
public static void main(String[] args) {
// 객체 생성 없이 호출 가능
int max = Math.max(10, 20);
double sqrt = Math.sqrt(16);
System.out.println("최대값: " + max); // 최대값: 20
System.out.println("제곱근: " + sqrt); // 제곱근: 4.0
}
}