정의
클래스 레벨에서 변수를 선언하거나 메서드를 정의할 때 사용되는 키워드
클래스 자체에 속하는 고유한 멤버를 나타냄
즉, 특정 객체에 속하지 않고 클래스에 속하므로 모든 객체가 해당 멤버를 공유함
- 메모리 효율성과 성능 면에서 이점이 있으며, 객체 생성 없이 활용할 수 있는 장점이 있음
- 공유 데이터나 유틸리티 메서드에 적합
- 그러나 무분별하게 사용 시, 캡슐화와 데이터 은닉을 위반할 수 있고 코드의 유연성을 해칠 수 있음
Static 변수 / 메서드 / 클래스
Static 변수 메서드 클래스 요약 클래스가 공유하는 변수 객체 없이 호출 가능한 클래스 메서드 외부 클래스 인스턴스 없이 사용할 수 있는 중첩 클래스 정의 클래스가 메모리에 로드될 때 한 번만 생성되며, 클래스에 속하는 모든 객체가 공유 객체가 아닌 클래스 자체에서 호출할 수 있는 메서드 일반적으로 클래스는 static으로 선언하지 않지만, 내부 클래스는 static으로 선언 가능 특징 개별 인스턴스마다 복사되는 인스턴스 변수와 달리, 모든 객체에서 하나의 static 변수를 공유 인스턴스 변수나 인스턴스 메서드를 사용할 수 없음
대신 static 변수나 다른 static 메서드만 호출할 수 있음
this 키워드 사용 불가외부 클래스에 속하면서도 외부 클래스의 인스턴스에 독립적
외부 클래스의 인스턴스를 만들지 않고도 static 내부 클래스의 인스턴스를 생성할 수 있음사용 모든 인스턴스에서 공유되어야 하는 데이터를 관리하거나, 특정 값이 오직 하나만 존재해야 할 때 사용 객체를 생성하지 않고도 호출할 수 있어야 하는 유틸리티 메서드(예: Math.pow() 등)에 유용 특정 클래스에만 종속된 클래스를 만들고, 해당 클래스의 인스턴스를 만들 필요 없이 사용하고자 할 때 유용 예시 private final static int fixedRate; Collections.sort()
String.join()OuterClass.NestedStaticClass nested = new OuterClass.NestedStaticClass();
예시 코드
// Static 변수 (클래스 변수) public class Counter { public static int count = 0; public Counter() { count++; } } // 사용 예시 Counter a = new Counter(); Counter b = new Counter(); System.out.println(Counter.count); // 출력: 2, 두 객체가 같은 count 변수를 공유// Static 메서드 (클래스 메서드) public class MathUtils { public static int add(int a, int b) { return a + b; } } // 사용 예시 int result = MathUtils.add(5, 10); // 객체 생성 없이 클래스명으로 호출 가능// Static 클래스 (내부 클래스에서 사용) public class OuterClass { static class NestedStaticClass { public void display() { System.out.println("Static nested class method."); } } } // 사용 예시 OuterClass.NestedStaticClass nested = new OuterClass.NestedStaticClass(); nested.display(); // "Static nested class method." 출력
Static과 Non-static을 요소의 성격에 따라 구분하여 적용하는 예시 코드// Static과 Non-static 예시 public class BankAccount { // 모든 계좌에 공통된 금리를 위한 static 변수 private static double interestRate = 0.05; // 개별 계좌마다 고유한 잔액을 저장하는 non-static 변수 private double balance; // 생성자 public BankAccount(double balance) { this.balance = balance; } // 모든 계좌에 공통 금리를 반환하는 static 메서드 public static double getInterestRate() { return interestRate; } // 개별 계좌의 잔액을 반환하는 non-static 메서드 public double getBalance() { return balance; } // 개별 계좌에 이자를 계산하여 추가하는 non-static 메서드 public void applyInterest() { balance += balance * interestRate; // 모든 계좌에 동일한 interestRate 적용 } } public class Main { public static void main(String[] args) { // static 변수와 메서드는 클래스명으로 접근 System.out.println("Interest Rate: " + BankAccount.getInterestRate()); // 개별 계좌 생성 BankAccount account1 = new BankAccount(1000); BankAccount account2 = new BankAccount(2000); // 개별 계좌마다 다른 잔액 확인 System.out.println("Account 1 Balance: " + account1.getBalance()); // 1000 System.out.println("Account 2 Balance: " + account2.getBalance()); // 2000 // 이자 적용 후 잔액 확인 account1.applyInterest(); account2.applyInterest(); System.out.println("Account 1 Balance after interest: " + account1.getBalance()); System.out.println("Account 2 Balance after interest: " + account2.getBalance()); } }여기서 만약에 private static double interestRate = 0.05; 선언에서 static을 뺀다면, interetRate는 각 개별 BankAccount 객체에 종속된 인스턴스 변수가 된다.
즉, 각각의 객체가 고유의 interestRate 값을 가질 수 있게 된다. (= 개별 객체가 서로 다른 이율을 사용할 수 있음)
또한 클래스명으로 접근할 수 없고 인스턴스를 통해서만 접근할 수 있으며, 각 객체마다 별도로 메모리에 할당된다. -> 효율 저하
한편, Static을 사용하지 않는 이유
1. 객체 지향성 저해
static 멤버는 인스턴스가 아닌 클래스에 귀속되어 객체지향 프로그래밍에서 중요한 캡슐화와 데이터 은닉 원칙을 위반할 수 있음
2. 테스트와 유연성 저하
static으로 선언된 변수와 메서드는 모킹(mocking)이 어렵고, 다른 클래스와 유연하게 협력하기 어려움
3. 메모리 관리
static 멤버는 프로그램 종료 시까지 메모리에 남아 있어 메모리 누수나 성능 저하를 유발할 수 있음
전역 변수와 static 변수
static 변수는 전역 변수와 비슷한 개념처럼 보이지만, 자바에서 전역 변수는 없음
자바는 전역 변수 대신 static 변수를 사용하여 비슷한 역할을 수행하게 함. 다만 전역 변수와는 몇 가지 중요한 차이점이 있음:
차이점 전역변수 static 변수 소속 어떤 클래스에도 속하지 않고 프로그램 전체에서 사용할 수 있음 자바에서 모든 변수는 반드시 클래스에 속해야 함
static 변수가 전역변수의 역할을 대신함캡슐화 접근 제어가 어려움 private, protected, public 등 접근 제한자를 통해 캡슐화할 수 있음
불필요한 접근을 막고, 필요에 따라 클래스 내에서만 사용할 수 있게 하거나 제한된 외부 접근을 허용객체지향적 설계 프로그램 내 어디서든 직접 접근할 수 있어 유지보수가 어렵고 불안정 클래스 안에 속해 있어 특정 클래스와 논리적으로 연결된 상태로 유지 = 객체 지향적 설계 원칙 따름 // 전역 변수처럼 사용되지만 캡슐화와 객체 지향 원칙 유지하는 예시 public class GlobalCounter { // 전역 변수처럼 사용 가능한 static 변수 private static int count = 0; public static void increment() { count++; } public static int getCount() { return count; } } public class Main { public static void main(String[] args) { // 클래스명으로 접근, 객체 생성 없이 사용 GlobalCounter.increment(); System.out.println(GlobalCounter.getCount()); // 출력: 1 GlobalCounter.increment(); System.out.println(GlobalCounter.getCount()); // 출력: 2 } }
비고
1. 왜 private final static으로 선언하는지도 이제 명확한 근거를 들어 설명할 수 있다.
레퍼런스
1. 멘토링 강의, 도서관, 코드 예시의 경우 ChatGPT
'개발지식 조각 > Java' 카테고리의 다른 글
| 도메인과 서비스 (1) | 2024.11.29 |
|---|---|
| 일급 컬렉션(First-Class Collection) (1) | 2024.10.31 |
| 클린 코드의 정의 (0) | 2024.10.31 |
| List, Set, Map, Queue (0) | 2024.10.31 |
| 제너럴한 명명규칙 정리 (0) | 2024.10.31 |