Java의 접근 제어자는 클래스, 멤버 변수(필드), 메서드, 생성자에 대한 접근 수준을 제어하여 캡슐화(Encapsulation)를 구현하는 핵심적인 문법입니다. 접근 제어자를 통해 불필요한 정보 노출을 막고, 외부로부터의 무단 변경을 방지하여 객체의 무결성을 보장할 수 있습니다.
Java는 네 가지 종류의 접근 제어자를 제공하며, 허용 범위가 넓은 순서는 다음과 같습니다.
(가장 좁음)----------------------------------------------->(가장 넓음)
private → default (package-private) → protected → public
| 제어자 | 동일 클래스 | 동일 패키지 | 하위 클래스 (다른 패키지) | 전체 (모든 패키지) |
|---|---|---|---|---|
private | O | X | X | X |
default | O | O | X | X |
protected | O | O | O | X |
public | O | O | O | O |
privateprivate으로 선언된 멤버는 해당 클래스 내부에서만 접근할 수 있습니다.default (Package-Private)package-private라는 용어가 그 역할을 더 명확하게 설명해줍니다. 특정 패키지 내에서만 공유되어야 하는 유틸리티 클래스나 헬퍼(Helper) 메서드에 주로 사용됩니다.protecteddefault 접근 제어자의 특징을 모두 가집니다. (같은 패키지 내 접근 허용)publicpublic으로 선언된 멤버는 어디서든 (패키지, 상속 관계 무관) 자유롭게 접근할 수 있습니다.접근 제어자는 다음과 같은 곳에 사용할 수 있습니다.
public 또는 default만 가능합니다.public class MyClass {} : 모든 패키지에서 이 클래스를 사용할 수 있습니다.class MyClass {} : 같은 패키지 내에서만 이 클래스를 사용할 수 있습니다.// Speaker.java
public class Speaker {
// 필드는 외부에서 직접 수정하지 못하도록 private으로 보호
private int volume;
// 생성자는 외부에서 호출하여 객체를 생성해야 하므로 public으로 지정
public Speaker(int initialVolume) {
if (initialVolume >= 0 && initialVolume <= 100) {
this.volume = initialVolume;
}
}
// 볼륨을 올리는 메서드 (public API)
public void volumeUp() {
if (volume < 100) {
volume++;
}
}
// 볼륨을 내리는 메서드 (public API)
public void volumeDown() {
if (volume > 0) {
volume--;
}
}
// 현재 볼륨을 보여주는 메서드 (public API)
public void showVolume() {
System.out.println("현재 볼륨: " + volume);
}
}
위 예시에서 volume 필드는 private으로 선언되어 외부에서 직접 speaker.volume = 1000;과 같이 값을 변경할 수 없습니다. 대신 public으로 공개된 volumeUp(), volumeDown() 메서드를 통해서만 안전하게 상태를 변경할 수 있습니다. 이것이 바로 캡슐화의 핵심 원리입니다.
접근 제어자의 가장 중요한 목적은 속성(데이터)과 기능(메서드)을 외부로부터 적절히 숨기는 것(정보 은닉, Information Hiding)입니다.
private: 클래스의 내부 구현을 완전히 숨깁니다. 외부에서는 해당 멤버의 존재조차 알 필요가 없습니다.default: 패키지 단위의 모듈화를 지원합니다. 특정 패키지 내에서만 공유할 기능을 만들 때 유용합니다.protected: 상속을 통한 기능 확장 및 재정의를 유도합니다. 부모 클래스가 특정 기능을 자식 클래스에게만 제공하고 싶을 때 사용합니다.public: 클래스의 공식적인 외부 인터페이스(API)를 정의합니다. 이 클래스를 사용하는 모든 외부 코드와의 소통 창구 역할을 합니다.