✔ 클래스, 변수, 메서드에 접근할 수 있는 범위를 지정하는 키워드.
✔ 허용되지 않은 외부 접근을 막아 데이터 보호 및 보안 강화 역할.
자바에서는 클래스, 변수, 메서드에 접근할 수 있는 범위를 접근제한자(Access Modifier)로 조절할 수 있다.
| 같은 클래스 | 같은패키지 | 자식클래스 | 외부클래스 | |
|---|---|---|---|---|
| private | ✅ 가능 | ❌ 불가능 | ❌ 불가능 | ❌ 불가능 |
| default | ✅ 가능 | ✅ 가능 | ❌ 불가능 | ❌ 불가능 |
| protected | ✅ 가능 | ✅ 가능 | ✅ 가능 | ❌ 불가능 |
| public | ✅ 가능 | ✅ 가능 | ✅ 가능 | ✅ 가능 |
getter/setter를 사용해야한다.class Person {
private String name = "홍길동"; // private 변수 (외부 접근 불가)
public String getName() { // public 메서드를 통해 접근 가능
return name;
}
}
public class Main {
public static void main(String[] args) {
Person p = new Person();
// System.out.println(p.name); // ❌ 오류 (private 변수 직접 접근 불가)
System.out.println(p.getName()); // ✅ getter 사용해서 접근 (출력: 홍길동)
}
}
class DefaultExample { // default 클래스 (같은 패키지 내에서만 접근 가능)
int number = 10; // default 변수
}
public class Main {
public static void main(String[] args) {
DefaultExample ex = new DefaultExample();
System.out.println(ex.number); // ✅ 같은 패키지 내라서 접근 가능
}
}
class Parent {
protected String message = "Hello from Parent";
}
class Child extends Parent {
public void printMessage() {
System.out.println(message); // ✅ 부모 클래스의 protected 변수 사용 가능
}
}
public class Main {
public static void main(String[] args) {
Child c = new Child();
c.printMessage(); // 출력: Hello from Parent
}
}
class PublicExample {
public String message = "공개 데이터";
}
public class Main {
public static void main(String[] args) {
PublicExample ex = new PublicExample();
System.out.println(ex.message); // ✅ 어디서든 접근 가능 (출력: 공개 데이터)
}
}
처음 공부할때.. 왜 굳이 private를 써서 getter/setter를 번거롭게 써야하지..? 라는 생각이 있었기에 나와 같은 코린이에게 도움이 되길 바라며 추가로 정리해보자면..
1️⃣ 데이터 보호 (정보 은닉)
🔴 public 필드를 그대로 사용하면?
class BankAccount {
public int balance = 10000; // public → 외부에서 직접 접근 가능!
}
public class Main {
public static void main(String[] args) {
BankAccount account = new BankAccount();
account.balance = -5000; // ❌ 오류 발생! (마이너스 잔액이 가능해짐)
System.out.println("잔액: " + account.balance);
}
}
public 때문에 외부에서 잘못된 갑이 들어가도 막을 방법이 없음!
🟢 private을 사용하고, Getter/Setter를 통해 접근을 제어한다.
class BankAccount {
private int balance = 10000; // private → 직접 접근 불가
public void setBalance(int amount) {
if (amount >= 0) {
this.balance = amount;
} else {
System.out.println("잘못된 금액입니다.");
}
}
public int getBalance() {
return balance;
}
}
이제 setBalance(-5000) 같은 잘못된 입력을 방어할 수 있음!
2️⃣ 유지보수성과 확장성 향상
🔴 예시: public 필드 사용 시 유지보수 문제
class User {
public String username; // public → 직접 접근 가능
}
public class Main {
public static void main(String[] args) {
User user = new User();
user.username = "hyerin"; // 여기까지는 문제없음
}
}
✅ 하지만 이후에 username을 대문자로 저장하고 싶다면?→ 모든 user.username을 수정해야 함
🟢 해결: private + setter 사용
class User {
private String username;
public void setUsername(String username) {
this.username = username.toUpperCase(); // 자동으로 대문자로 변환
}
public String getUsername() {
return username;
}
}
✔ 이제 setUsername("heyrin")을 호출하면 자동으로 "heyrin" → "heyrin".toUpperCase()로 변환됨.
✔ 외부 코드는 수정할 필요 없이, 내부 로직만 변경하면 됨!
3️⃣ 코드의 안정성과 가독성 향상
🔴 문제: 직접 필드 변경 시 추적 어려움
class Order {
public int quantity;
}
public class Main {
public static void main(String[] args) {
Order order = new Order();
order.quantity = 10; // 여기서는 10
order.quantity = 5; // 어디서 바뀌었는지 추적 어려움
}
}
→ order.quantity가 변경될 때, 어떤 조건으로 바뀌었는지 알 수 없음.
🟢 해결: private + setter 사용
class Order {
private int quantity;
public void setQuantity(int quantity) {
System.out.println("수량 변경: " + this.quantity + " → " + quantity);
this.quantity = quantity;
}
}
public class Main {
public static void main(String[] args) {
Order order = new Order();
order.setQuantity(10); // 값 변경 (초기값 0 → 10)
order.setQuantity(5); // 값 변경 (10 → 5)
}
}
✔ 이제 값이 변경될 때 로그가 남아, 어디서 바뀌었는지 추적 가능!
초창기 자바 개발에서는 getter/setter 없이 public 필드를 직접 사용하는 경우가 많았지만 코드가 복잡해지고 유지보수성이 중요해지면서, 캡슐화의 필요성이 강조되었다.
현재는 데이터 보호와 유효성 검사를 위해 private 필드와 getter/setter를 사용하는 것이 일반적이다!
하지만, Getter/Setter를 사용하는 것에도 문제점이 있을 수 있다.
➡ 이 부분은 "Getter/Setter" 글에서 더 자세히 다룬다.