접근 제어자(access modifier)
접근제어자란?
- 클래스와 클래스의 멤버(생성자, 필드, 메서드)를 사용할 때 접근할 수 있는 범위를 지정하는 역할
1. 클래스의 접근 제어자
- 클래스에 지정할 수 있는 접근 제어자는 public과 default로 두 가지가 있다.
- public : 패키지와 상관 없이 모든 클래스에서 접근 가능
- default(생략) : 같은 패키지에 있는 클래스에서만 접근 가능
2. 클래스 멤버의 접근 제어자
- 클래스 멤버에 지정할 수 있는 접근제어자는 public, private, protected와 default로 네 가지가 있다.
- public : 패키지와 상관 없이 모든 클래스에서 접근 가능
- private(비공개) : 동일 클래스의 멤버들만 접근 가능
- protected : 같은 패키지 내 모든 클래스와 상속 관계인 경우, 다른 패키지의 자식 클래스에서 접근 가능
- default(생략) : 같은 패키지에 있는 클래스에서만 접근 가능
| 접근제어자 | 동일 클래스 | 동일 패키지 | 자손 클래스 | 전체 |
| public | O | O | O | O |
| protected | O | O | O | X |
| default | O | O | X | X |
| private | O | X | X | X |
캡슐화
캡슐화란?
- private 접근제어자를 활용해서 데이터는 숨기고, 의도된 동작으로만 외부에 공개하는 것이다
- 외부에서 private 멤버에 접근하기 위해서는 public 메서드를 활용해야 한다.
필요성
- 외부의 잘못된 접근으로 인한 멤버의 변화나 의도치 않은 동작을 방지한다.
- 유효하지 않은 값으로 직접 필드를 변경하려는 시도를 내부에서 valid 로직을 통해 필터링 할 수 있다.
활용법
- 은닉하려는 필드나 메서드의 접근제어자를 private로 정의한다.
- 다른 클래스에서 해당 필드나 메서드로 접근할 수 있는 public 메서드를 생성한다.
- ex) getter, setter 메서드
예제
//캡슐화 예제 class MotorBike
public class MotorBike {
//캡슐화
private int speed;
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
if (speed > 0) {
this.speed = speed;
}
}
public void increaseSpeed(int howMuch) {
setSpeed(this.speed + howMuch);
}
public void decreaseSpeed(int howMuch) {
if (this.speed - howMuch < 0) {
setSpeed(0);
} else {
setSpeed(this.speed - howMuch);
}
}
void start() {
System.out.println("Bike started");
}
}
MotorBike 객체의 speed라는 필드 값 private 접근제어자를 사용해 캡슐화 해서 외부 클래스에서 직접 접근하지 못 하도록 설정했다.
외부 클래스에서는 public으로 공개된 메서드를 통해서만 speed 값에 접근할 수 있다.
이를 메인 메서드를 가지고 있는 Runner 클래스 코드로 보여주면
//접근 실패 예제
public class MotorBikeRunner {
public static void main(String[] args) {
MotorBike ducati = new MotorBike();
MotorBike honda = new MotorBike();
ducati.speed = 100;
}

외부 클래스에서 직접 ducati 객체의 speed 필드 값에 접근을 하니 오류가 뜬 모습이다.
오류 메시지에 MotorBike.speed is not visible 은 private 접근제어자에 의해 speed라는 필드 값이 가려져 있기 때문에 보이지 않는다는 의미이다.
다음은 MotorBike 클래스의 public 메서드를 호출해 접근한 예제이다
//접근 성공 예제
public class MotorBikeRunner {
public static void main(String[] args) {
MotorBike ducati = new MotorBike();
MotorBike honda = new MotorBike();
ducati.start();
honda.start();
System.out.println("==============");
ducati.setSpeed(100);
honda.setSpeed(80);
System.out.println(ducati.getSpeed());
System.out.println(honda.getSpeed());
System.out.println("==============");
ducati.increaseSpeed(50);
honda.increaseSpeed(120);
System.out.println(ducati.getSpeed());
System.out.println(honda.getSpeed());
System.out.println("==============");
ducati.decreaseSpeed(25);
honda.decreaseSpeed(23);
System.out.println(ducati.getSpeed());
System.out.println(honda.getSpeed());
System.out.println("==============");
}
}

동일 클래스의 public 메서드를 호출하여 성공적으로 캡슐화 되어 있는 멤버에 접근한 것을 확인할 수 있다.
느낀점
다 알고 있는 개념이라 생각했는데도 다시 회상하여 적으려고 하니 각 접근제어자의 공개범위 등 정확하게 생각나지 않은 것들도 있고, 실제로 외부 클래스에서 캡슐화된 멤버에 접근하면 어떻게 오류가 뜨는지 확인해 본 건 처음이라 좋은 경험이 된 것 같다.
내가 머리 속으로 이해하고 넘어가는 것과 내가 누군가에게 보여주고 설명하기 위해 이해하는 것은 많이 다르다는 걸 느꼈다.
'AIBE5 TIL' 카테고리의 다른 글
| [TIL 26/02/10](Java) 인터페이스 (0) | 2026.02.10 |
|---|---|
| [TIL 26/02/09](Java) 상속 (0) | 2026.02.09 |
| [TIL 26/02/05](Java) 배열(Array)과 Wrapper Class (0) | 2026.02.05 |
| [TIL 26/02/04] (Java)(2) 데이터타입(기본형, String) (0) | 2026.02.04 |
| [TIL 26/02/04] (Java) (1) 무한 반복문 (0) | 2026.02.04 |