기본 패턴
java
public class BankAccount {
private double balance; // 외부 직접 접근 차단
private String ownerId;
public void deposit(double amount) { // 공개 API
if (amount > 0) balance += amount;
}
public double getBalance() {
return balance;
}
private boolean isValid(double amount) { // 내부 구현
return amount > 0 && amount <= balance;
}
}설명
네 가지 접근 제한자와 적용 범위
Java에는 키워드가 세 개(public, protected, private)이고 아무것도 안 쓰면 package-private이 됩니다.
| 제한자 | 같은 클래스 | 같은 패키지 | 서브클래스 | 어디서든 |
|---|---|---|---|---|
private | ✅ | ❌ | ❌ | ❌ |
| package-private | ✅ | ✅ | ❌ | ❌ |
protected | ✅ | ✅ | ✅ | ❌ |
public | ✅ | ✅ | ✅ | ✅ |
java
package com.example;
public class Foo {
private int a; // Foo 내부에서만
int b; // com.example 패키지 안에서만 (package-private)
protected int c; // 패키지 + 서브클래스에서
public int d; // 어디서든
}package-private — 모듈 내부 API의 기본 선택
키워드 없이 선언된 package-private은 Java에서 과소평가되는 접근 제한자입니다. 같은 패키지 안에서만 접근 가능하므로 패키지를 하나의 모듈로 설계할 때 내부 구현을 숨기는 데 씁니다. 외부에 노출할 이유가 없는 클래스나 메서드의 기본 선택입니다.
java
// 외부 노출이 필요 없는 유틸리티 클래스
class InternalParser { // package-private — public 아님
String parse(String raw) { ... }
}
// 같은 패키지 내에서만 사용
public class DataService {
private final InternalParser parser = new InternalParser(); // ✅
}캡슐화 설계 원칙 — 가능한 한 좁게
접근 제한자 선택의 원칙은 필요한 최소 범위만 열기입니다. 처음부터 public으로 만들면 나중에 좁히기 어렵습니다(다른 코드가 이미 의존하고 있으므로). 좁게 시작하고 필요할 때 넓히는 것이 안전합니다.
java
public class OrderService {
// ✅ 필드는 private — 직접 접근 차단
private final OrderRepository repository;
private double discountRate;
// ✅ 핵심 API만 public
public Order placeOrder(Cart cart) { ... }
// ✅ 내부 로직은 private
private double calculateTotal(Cart cart) { ... }
// ✅ 서브클래스에서 재정의해야 한다면 protected
protected void sendConfirmation(Order order) { ... }
}빠른 정리
| 상황 | 선택 |
|---|---|
| 클래스 내부 구현 | private |
| 패키지 내부 공유 | package-private (키워드 없음) |
| 상속 계층에서 재정의 허용 | protected |
| 라이브러리 공개 API | public |
| 기본 시작점 | private부터 시작, 필요 시 넓힘 |
주의할 점
public 필드는 캡슐화를 무너뜨립니다. 외부에서 직접 수정하면 클래스 내부의 불변식을 보장할 수 없습니다. 필드는 항상 private으로, 접근이 필요하면 메서드로 노출하세요.
java
// ❌ public 필드 — 외부에서 직접 수정 가능
public class Circle {
public double radius; // 음수 값도 막을 수 없음
}
Circle c = new Circle();
c.radius = -5; // 잘못된 상태지만 막을 수 없음
// ✅ private 필드 + 검증 메서드
public class Circle {
private double radius;
public void setRadius(double r) {
if (r < 0) throw new IllegalArgumentException("반지름은 0 이상");
this.radius = r;
}
public double getRadius() { return radius; }
}참고 링크
1 sources