접근 제어자는 클래스, 메서드, 필드의 가시성을 제어합니다 — 누가 접근할 수 있는가를 결정합니다. 이는 캡슐화의 기반이 되는 메커니즘입니다. Java에는 가장 제한적인 것부터 가장 덜 제한적인 것까지 네 가지 수준이 있습니다.
네 가지 수준
{
a;
b;
c;
d;
}
제어자 같은 클래스 같은 패키지 하위 클래스(다른 pkg) 어디서나
────────────────────────────────────────────────────────────────────────
public ✓ ✓ ✓ ✓
protected ✓ ✓ ✓ ✗
(default) ✓ ✓ ✗ ✗
private ✓ ✗ ✗ ✗
참고: 제어자를 생략하면 package-private(기본값)가 되어 같은 패키지 내에서만 보입니다. 이는 public과 같지 않은 별개의 수준입니다.
public class BankAccount {
private double balance; // 숨겨짐 — 데이터 보호
public void deposit(double amt) { // public API — 통제된 접근
if (amt > 0) balance += amt;
}
public double getBalance() { // private 데이터에 대한 읽기 전용 접근
return balance;
}
}
// 외부 코드는 account.balance = -1000 을 할 수 없음 (private 이므로)
표준 패턴: 필드를 **private**으로 만들고 통제된 public 메서드를 노출합니다. 이는 불변식을 보호하고 호출자를 깨뜨리지 않고 내부 표현을 변경할 수 있게 합니다 — 캡슐화의 본질입니다.
✓ 필드 → private (거의 항상); 필요하면 메서드를 통해 노출
✓ Public API 메서드 → public
✓ 내부 헬퍼 → private
✓ 하위 클래스가 접근/오버라이드하게 하려면 → protected
✓ 클래스 → public (어디서나 사용 가능) 또는 package-private (모듈 내부)
원칙: 여전히 동작하는 가장 제한적인 제어자를 사용하십시오(최소 권한) — private으로 시작하고 필요할 때만 개방합니다.
접근 제어자는 Java가 캡슐화 — 내부 세부 사항을 숨기고 통제된 인터페이스를 노출하는 근본적인 OOP 원칙 — 를 구현하는 방법입니다.
올바른 제어자를 선택하는 것(필드는 기본적으로 private, 의도된 API에만 public)은 데이터 무결성을 보호하고, 외부 코드가 내부에 의존하지 못하게 하며(따라서 자유롭게 리팩터링 가능), 클래스의 의도된 사용법을 명확히 합니다.
네 가지 수준 모두 — 특히 자주 잊히는 package-private 기본값과 하위 클래스에 걸친 protected — 를 이해하는 것은 잘 캡슐화되고 유지보수 가능한 클래스와 API를 설계하고, 코드가 시스템의 나머지 부분에 얼마나 노출되는지를 제어하는 데 필수적입니다.