1️⃣ 정적 멤버 선언
정적 멤버(static)는 클래스에 속하는 멤버로 인스턴스가 아닌 클래스 자체에 소속된다.
- 정적 변수 : static으로 선언된 변수는 클래스의 모든 인스턴스가 공유하며, 프로그램 종료 시까지 유지된다.
- 정적 메서드 : static으로 선언된 메서드는 클래스 이름으로 호출하며, 객체 생성 없이 사용할 수 있다.
public class 클래스 {
// 정적 필드
static 타입 필드 [= 초기값];
// 정적 메소드
static 리턴 타입 메소드(매개변수 선언, ...) [...]
}
🔍 정적 변수 사용 판단 기준 :
- 객체마다 개별적으로 관리해야 하는 데이터라면 인스턴스 필드로 선언
- 모든 객체가 공유해야 하는 데이터라면 정적 필드로 선언
🔍 정적 메서드 사용 판단 기준 :
- 인스턴스 필드를 사용해야 작업이 수행된다면, 인스턴스 메서드로 선언
- 인스턴스 필드를 사용하지 않고, 클래스 차원에서 작업을 수행하기 충분하다면, 정적 메서드로 선언
2️⃣ 정적 멤버 사용
- 정적 멤버는 객체를 생성하지 않고도 클래스 이름을 통해 직접 접근 가능
- 클래스가 메모리에 로딩되면 정적 멤버 사용 가능
클래스.필드;
클래스.메소드(매개값, ...);
🛠 Example
public class Calculator {
String color; // 계산기별로 색깔이 다를 수 있다. (인스턴스 필드)
static double pi = 3.14159; // 계산기에서 사용하는 파이 값은 동일
// 인스턴스 필드
void setColor(String color) {
this.color = color;
}
// 정적 메소드
static int plus(int x, int y) {
return x + y;
}
// 정적 메소드
static int minus(int x, int y) {
return x - y;
}
}
public class CalculationExample {
public static void main(String[] args) {
double result1 = 10 * 10 * Calculator.pi;
int result2 = Calculator.plus(10, 5);
int result3 = Calculator.minus(10, 5);
System.out.println(result1);
System.out.println(result2);
System.out.println(result3);
}
}
⚠️ 주의사항
- 모든 인스턴스가 정적 멤버를 공유한다.
- 정적 멤버는 클래스 단위로 관리되므로, 한 객체에서 수정하면 다른 모든 객체에서도 영향을 미친다.
- 객체 참조 변수로 접근이 가능하지만 권장하지 않는다.
- 정적 필드와 정적 메소드는 원칙적으로 클래스 이름으로 접근해야 한다.
- 객체 참조 변수로 접근하면 코드의 의도가 불명확해질 수 있다.
3️⃣ 정적 초기화 블록
- 정적 변수의 초기화가 복잡한 로직을 포함하거나, 선언과 동시에 초기화할 수 없는 경우 사용하는 블록
- 정적 초기화 블록은 클래스 로딩 시 단 한 번만 실행되며, 주로 정적 필드의 초기화를 위해 사용
🤔 왜 사용하나요?
- 정적 필드는 객체 생성과 상관없이 사용해야 하므로 생성자에서 초기화할 수 없다.
- 대신, 클래스가 메모리에 로드될 때 한 번만 실행되는 정적 초기화 블록에서 초기화를 수행
- 예를 들어, 복잡한 계산이나 외부 리소스를 초기화해야 할 때 적합하다.
🛠 Example
public class Television {
static String company = "Samsung";
static String model = "LCD";
static String info;
static {
info = company + "-" + model;
}
}
public class TelevisionExample {
public static void main(String[] args) {
System.out.println(Television.info);
}
}
4️⃣ 정적 메소드와 블록 선언 시 주의할 점
✅ 특징
- 객체 없이 실행 가능
- 정적 메서드와 정적 블록은 클래스 로딩 시점에 사용 가능하며, 객체 생성 없이 실행된다.
- 인스턴스 멤버 사용 불가
- 정적 메서드와 정적 블록 내부에서는 인스턴스 필드나 인스턴스 메서드를 직접 사용할 수 없다.
- 이는 정적 멤버는 클래스 단위로 관리되기 때문에, 객체가 생성되지 않은 상태에서도 실행될 수 있기 때문
- this 키워드 사용 불가
- 정적 메서드와 정적 블록은 특정 객체에 종속되지 않으므로, this 키워드를 사용할 수 없다.
🛠 Example
public class ClassName {
// 인스턴스 필드와 메소드
int field1;
void method1() {
}
// 정적 필드와 메소드
static int field2;
static void method2() {
}
// 정적 블록
static {
// 컴파일 에러
// field1 = 10;
// method1();
// 에러 x
field2 = 10;
method2();
}
// 정적 메소드
static void Method3() {
// 컴파일 에러
// this.field1 = 10;
// this.method1();
field2 = 10;
method2();
}
// 변경된 정적 메소드
static void Method3_() {
ClassName obj = new ClassName();
obj.field1 = 10;
obj.method1();
}
}
- 겍체를 생성하여 해당 객체의 참조 변수를 통해 인스턴스 멤버에 접근해야 한다.
public class Car {
int speed;
void run() {
System.out.println(speed + "으로 달립니다.");
}
public static void main(String[] args) {
Car myCar = new Car();
myCar.speed = 60;
myCar.run();
}
}
- main() 메서드도 정적 메서드로 정의되므로 정적 메서드의 규칙도 동일하게 적용된다.
- main() 내부에서도 인스턴스 멤버를 사용하려면 객체를 생성한 뒤 참조 변수로 접근해야 한다.
⚠️ 주의사항
- 정적 메소드와 블록은 객체 생성과 무관
- 따라서, 클래스 로딩 시점에 존재하지 않는 인스턴스 멤버에는 접근할 수 없다.
- 정적 멤버는 클래스 이름으로 호출 권장
- 정적 메서드나 필드는 객체 참조 변수로도 호출할 수 있지만, 클래스 이름으로 호출하는 것이 권장
- 객체 참조 변수로 호출 시 혼란을 줄 수 있으니 주의!
- 정적 메서드나 필드는 객체 참조 변수로도 호출할 수 있지만, 클래스 이름으로 호출하는 것이 권장
5️⃣ 싱글톤 (Singleton)
- 전체 프로그램에서 단 하나의 객체만 생성되도록 보장하는 디자인 패턴
- 싱글톤 패턴은 객체 생성 비용을 줄이거나, 상태를 공유해야 하는 경우에 주로 사용
🔍 싱글톤 구현 방법
- 생성자 제한
- 클래스 외부에서 객체 생성을 제한하려면, 생성자에 private 접근 제한자를 붙인다.
- 이렇게 하면 외부에서 new 연산자를 사용해 객체를 생성할 수 없게 된다.
- 정적 필드로 객체 저장
- 클래스 내부에 자신의 타입으로 된 정적 필드를 선언
- 이 필드에 단 하나의 객체를 생성하여 저장
- 객체 변환 메서드
- 외부에서 객체를 얻기 위해 정적 메서드인 getInstance() 를 정의
- 이 메서드에서 이미 생성된 객체를 반환
🛠 Example
public class Singleton {
private static Singleton singleton = new Singleton();
private Singleton() {
}
static Singleton getInstance() {
return singleton;
}
}
public class SingletonExample {
public static void main(String[] args) {
// Singleton obj1 = new Singleton(); // 컴파일 에러
// Singleton obj2 = new Singleton(); // 컴파일 에러
Singleton obj1 = Singleton.getInstance();
Singleton obj2 = Singleton.getInstance();
if(obj1 == obj2) {
System.out.println("같은 Singleton 객체");
} else {
System.out.println("다른 Singleton 객체");
}
}
}
📌 특징 및 동작 원리
- 단 하나의 객체만 생성
- Singleton.getInstance() 가 호출될 때마다 동일한 객체가 반환
- 객체가 이미 생성된 경우에는 새로 생성하지 않고 기존 객체를 반환한다.
- 객체 접근의 유일한 경로
- 외부에서는 getInstace() 메서드를 통해서만 객체를 얻을 수 있다.
- 이는 외부에서 객체 생성을 차단함으로써 객체가 단 하나만 존재함을 보장한다.
📚 Reference
책 - 이것이 자바다
'Java' 카테고리의 다른 글
[TIL] 해시테이블 (Hash Table) 이란, Hash Table과 Hash Map의 차이 점 (7) | 2024.12.11 |
---|---|
[TIL] IntelliJ IDEA에서 DB 연결 (0) | 2023.05.23 |