Java/강의
[📙 Java 문법 종합반] 2-7. 객체지향 PART 1 - 캡슐화(접근제어자)
가지코딩
2025. 4. 15. 19:36
📙 목차
🧡 학습 목표
- 캡슐화가 무엇인지 학습한다.
- 접근제어자가 무엇인지 학습한다.
- 무분별한 세터가 무엇인지 학습한다.
객체지향의 4가지 특징
- 캡슐화 - 데이터의 보호
- 상속 - 재사용성과 확장
- 추상화 - 데이터의 계층적 표현
- 다형성 - 객체지향의 꽃
1. 캡슐화(Encapsulation)란?
캡슐화란?
- 객체의 정보를 외부에서 직접 접근하지 못하게 보호하는 개념이다.
- 캡슐처럼 감싸서 내부를 보호하고 외부로부터 내용물을 숨기고 있는 모습에서 유래됐다.
- 클래스 혹은 객체의 캡슐화는 접근제어자 를 통해서 구현할 수 있다.
캡슐화가 왜 필요할까?
- 외부에 노출하고 싶지 않은 정보를 보호하고 필요한 경우에만 안전하게 접근할 수 있도록 한다.
- 캡슐화를 구현하기 위해서는 접근제어자 를 이해해야 한다.
2. 접근제어자(Access Modifier)
접근 제어자
- 접근제어자는 클래스, 변수, 메서드, 생성자의 접근 범위를 제한하는 키워드이다.
- 캡슐화 구현을 위해 사용된다.
접근제어자 | 클래스 내부 | 패키지 내부 | 상속한 클래스 | 전체 공개 |
public | ✅ | ✅ | ✅ | ✅ |
protected | ✅ | ✅ | ✅ | ❌ |
default | ✅ | ✅ | ❌ | ❌ |
private | ✅ | ❌ | ❌ | ❌ |
접근제어자 활용 예시(public, private)
public class Person { // ✅ 외부에서 접근 불가
public String name; // ✅ 외부에서 접근 불가
private String secret; // ❌ 외부에서 접근 불가
public Person() {} // ✅ 외부에서 접근 불가
public void methodA() {} // ✅ 외부에서 접근 가능
private void methodB() {} // ❌ 외부에서 접근 불가
}
Person person = new Person(); // ✅ 접근가능 생성자가 public
person.name; // ✅ 접근가능 변수가 public
person.secret; // ❌ 접근불가능 변수가 private
person.methodA(); // ✅ 접근가능 메서드가 public
person.methodB(); // ❌ 접근불가능 메서드가 private
3. 데이터 접근 - 게터(Getter)와 세터(Setter)
캡슐화가 된 데이터에 접근 방법
- 캡슐화가 잘 적용된 클래스는 내부 데이터를 private 으로 보호하고 있기 때문에, 데이터 조회나 변경이 필요한 경우 안전한 접근방법이 필요하다.
- 그 역할을 수행하는 메서드가 바로 게터(Getter)와 세터(Setter) 이다.
게터(Getter) 활용법
데이터를 안전하게 접근하기 위해 사용된다.
public class Person {
private String secret;
public String getSecret() {
return this.secret; // ✅ 객체의 secret 속성 반환
}
}
public class Main {
public static void main(String[] args) {
Person p1 = new Person();
p1.secret; // ❌ 직접 접근 불가능
String newSecret = p1.getSecret(); // ✅ 게터를 활용해 접근가능
}
}
세터(Setter) 활용법
데이터를 안전하게 설정/변경하기 위해 사용된다.
public class Person {
private String secret;
public void setSecret(String secret) {
this.secret = secret; // ✅ secret 속성 설정 및 변경
}
}
public class Main {
public static void main(String[] args) {
Person p1 = new Person();
p1.secret = "password"; // ❌ 직접접근, 변경 불가능
p1.setSecret("newPassword"); // ✅ 세터를 활용해 접근, 변경가능
}
}
4. 무분별한 세터가 무엇일까?
사례 1
public class DataStore {
private String store;
public void setStore(String data) {
this.store = data;
}
}
문제점
- 접근을 막아 놓고 다시 세터로 외부에 노출한다면, 접근제어를 하는 의미가 사라진다.
- 이런 경우 무조건 세터를 만드는 것이 아니라 올바른 데이터만 저장될 수 있도록 제한해야 한다.
해결책: 안전한 데이터 설정 로직 추가
public class DataStore {
private String store;
public void setStore(String data) {
if ("B".equals(data)) {
System.out.println("❌ 'B'는 입력할 수 없습니다!");
} else {
this.store = data;
}
}
}
- 데이터는 안전하게 저장되고 원하지 않는 값이 들어오는 것도 막을 수 있다.
사례 2
public class Robot {
private boolean leftLeg;
private boolean rightLeg;
public void setLeftLeg(boolean power) {
this.leftLeg = power;
}
public void setRightLeg(boolean power) {
this.rightLeg = power;
}
}
문제점
public class Robot {
private boolean leftLeg; // 세터필요
private boolean rightLeg;// 세터필요
private boolean leftArm; // 세터필요
private boolean rightArm;// 세터필요
private boolean leftEye; // 세터필요
private boolean rightEye;// 세터필요
}
Robot robot = new Robot();
robot.setLeftLeg(true); // ✅ 왼쪽 다리 움직임
robot.setLeftArm(true); // ⚠️ 왼쪽 팔을 먼저 움직이면 균형이 깨짐
robot.setRightLeg(true); // ✅ 오른쪽 다리 움직임
...
- 속성이 많아질수록 세터를 호출하는 코드가 점점 복잡해지고 유지보수가 어려워진다.
해결책: 동작을 직접 제공하기
public class Robot {
private boolean leftLeg;
private boolean rightLeg;
private boolean leftArm;
...
public void walk(boolean power) {
System.out.println("🚶 왼쪽 다리 앞으로!");
leftLeg = power;
System.out.println("🚶 오른쪽 다리 앞으로!");
rightLeg = true;
...
}
}
- 걷는 동작을 하나의 메서드로 정의한다.
- 모든 요소를 조작하는 순서가 walks() 안에서 관리되면서 사용이 간단해졌다.