JAVA

자바 캡슐화 — 필드를 숨기고 안전하게 다루는 법(PRIVATE·GETTER·SETTER)

PANCO_IT
#자바#JAVA#캡슐화#private#getter#setter

필드를 전부 공개했을 때와 private으로 숨기고 통로만 열었을 때를 비교한 그림

만지는 문을 하나로 좁히면, 잘못된 값이 들어오는 길도 하나로 좁혀집니다.

3편에서 생성자로 객체의 초기값을 한 번에 채웠습니다. 그런데 만든 뒤가 문제입니다. 지금 구조라면 아무 데서나 d.age = -5;라고 써도 막을 방법이 없습니다. 나이가 음수인 강아지가 생겨도 자바는 아무 말도 하지 않습니다. 이 문을 잠그는 것이 오늘의 주제, 캡슐화입니다.

캡슐화가 뭔가요?

캡슐화는 필드를 밖에서 직접 못 만지게 숨기고, 공식 통로(메서드)로만 다루게 묶는 것입니다. 알약 캡슐이 가루약을 감싸듯, 데이터를 클래스 안에 감춥니다.

쉽게 — 자판기와 같습니다. 우리는 동전을 넣고 버튼을 누를 뿐, 자판기 문을 열고 음료를 직접 꺼내지 않습니다. 내부는 잠겨 있고, 정해진 통로(투입구·버튼·배출구)만 열려 있죠. 그래서 돈을 안 넣고 가져가는 일을 기계가 막을 수 있습니다. 캡슐화가 클래스에 해 주는 일이 정확히 이것입니다.

private — 밖에서 못 만지게 잠그기

잠그는 방법은 간단합니다. 필드 앞에 잠금 키워드를 붙입니다. 바로 private입니다.

class Dog {
    private String name;   // 이 클래스 안에서만 접근 가능
    private int age;
}

private가 붙은 필드는 그 클래스 안에서만 쓸 수 있습니다. 밖에서 직접 만지려 하면 컴파일 오류가 납니다.

Dog d = new Dog("바둑이", 3);
d.age = -5;   // 오류: age has private access in Dog

지금까지 별말 없이 쓰던 d.age = 3 같은 코드가 이제 막히는 것입니다. 문이 잠겼으니, 다음은 공식 통로를 낼 차례입니다.

getter와 setter — 공식 통로 내기

잠근 필드를 읽고 쓸 수 있게, public 메서드 두 개를 만들어 줍니다. 읽는 쪽을 getter, 쓰는 쪽을 setter라고 부릅니다.

class Dog {
    private int age;

    public int getAge() {          // getter: 값을 읽는 통로
        return age;
    }
    public void setAge(int age) {  // setter: 값을 바꾸는 통로
        this.age = age;
    }
}

이름은 관례로 get / set 뒤에 필드명을 첫 글자만 대문자로 붙입니다(agegetAge, setAge). 자바 세계 어디서나 통하는 약속이라, 이 규칙대로 지어야 다른 코드·도구와 잘 맞물립니다.

캡슐화 3단계: private으로 잠그고, getter와 setter로 통로를 내고, 통로에서 검사한다

그림 1. 잠그고(private), 통로를 내고(getter·setter), 통로에서 검사합니다.

setter에서 검사하기 — 캡슐화의 진짜 힘

"직접 접근을 막고 메서드로 우회하는 게 무슨 이득이지?" 싶을 수 있습니다. 이득은 통로에서 값을 검사할 수 있다는 데 있습니다.

public void setAge(int age) {
    if (age < 0) {
        System.out.println("나이는 0보다 작을 수 없습니다");
        return;               // 잘못된 값은 거부
    }
    this.age = age;
}

이제 d.setAge(-5)를 불러도 나이는 바뀌지 않습니다. 필드로 들어오는 문이 setter 하나뿐이니, 여기 한 곳만 지키면 이상한 값이 아예 못 들어옵니다. 필드가 public이었다면 값을 바꾸는 코드가 백 군데여도 전부 믿어야 했을 것입니다.

직접 실행해 보기

아래 코드를 돌려 보세요. setAge(-5)가 거부되는 것을 확인한 뒤, 검사 조건을 age > 30 거부로 바꿔 보거나 name에도 getter를 만들어 보면 좋습니다.

캡슐화: private 필드와 검사하는 setter
class Dog {
  private String name;
  private int age;
  Dog(String name, int age) {
      this.name = name;
      setAge(age);              // 생성 시에도 같은 검사를 거침
  }
  public int getAge() {
      return age;
  }
  public void setAge(int age) {
      if (age < 0) {
          System.out.println("나이는 0보다 작을 수 없습니다");
          return;
      }
      this.age = age;
  }
  void info() {
      System.out.println(name + " (" + age + "살)");
  }
}

public class Main {
  public static void main(String[] args) {
      Dog d = new Dog("바둑이", 3);
      d.info();          // 바둑이 (3살)
      d.setAge(-5);      // 나이는 0보다 작을 수 없습니다
      d.info();          // 바둑이 (3살) — 값이 지켜짐
      d.setAge(4);
      d.info();          // 바둑이 (4살)
  }
}

📱 코드 실행(실습)은 태블릿·PC에서 이용할 수 있어요. 모바일에서는 위 코드를 눈으로 따라가며 확인하세요.

단골 함정 — private인데 직접 만지려 한다

private를 붙인 뒤에도 습관처럼 d.age = 5;라고 쓰면 컴파일 오류가 납니다. "age has private access"라는 메시지가 보이면, 필드를 직접 만진 곳을 찾아 d.setAge(5)처럼 통로로 바꾸면 됩니다.

하나 더. getter와 setter를 만들 때 이름을 age()changeAge()처럼 마음대로 지으면 문법 오류는 아니지만 관례가 깨져 다른 사람과 도구가 알아보지 못합니다. get·set + 첫 글자 대문자, 이 틀을 지키는 것이 좋습니다.

한 장 정리

항목내용
캡슐화필드를 숨기고 공식 통로(메서드)로만 다루게 묶는 것
private그 클래스 안에서만 접근 가능(밖에서 직접 접근 시 컴파일 오류)
getter값을 읽는 통로, 이름은 get필드명()
setter값을 바꾸는 통로, 이름은 set필드명(값) — 여기서 값 검사
public어디서나 접근 가능(통로 메서드에 붙임)

이것만 기억하면 됩니다. 캡슐화는 잠그고(private), 통로를 내고(getter·setter), 통로에서 검사하는 것입니다. 필드로 들어오는 문을 하나로 좁히면, 잘못된 값을 막는 일도 그 한 곳에서 끝납니다.

미니 퀴즈

개념을 제대로 잡았는지 직접 풀어 봅니다. 정답은 눌러야 나옵니다.

미니 퀴즈

OX 2문제 + 4지선다 3문제


포켓코딩(JAVA2) 4편 · 예제 출처: 강사 개인 GitHub 저장소. 다음 편: 배열 — 값 여러 개를 한 줄로 세우는 법.

PANCO_IT

IT 지식을 정리하는 개발자

관련 글