『스프링입문을 위한 자바 객체지향의 원리와 이해』로 공부한 내용을 정리한 글입니다.
접근 제어자: 정보 은닉의 핵심 원리
객체지향 프로그래밍에서 "캡슐화(encapsulation)"란, 객체의 내부 상태(데이터)를 외부에서 직접 접근하지 못하도록 감추고, 허용된 방식으로만 접근할 수 있게 만드는 정보 은닉(information hiding) 기법입니다.
자바에서는 이 캡슐화를 접근 제어자(access modifier)를 통해 구현합니다. 클래스 멤버(필드와 메서드)에 접근을 제한함으로써, 외부로부터의 불필요하거나 위험한 접근을 방지하고, 소프트웨어의 유지보수성과 안정성을 높입니다.
자바의 4가지 접근 제어자
접근 제어자 | 클래스 내부 | 같은 패키지 | 다른 패키지의 자식 클래스 | 외부 클래스 |
private | ✅ | ❌ | ❌ | ❌ |
(default) | ✅ | ✅ | ❌ | ❌ |
protected | ✅ | ✅ | ✅ | ❌ |
public | ✅ | ✅ | ✅ | ✅ |
private
가장 제한적인 접근 제어자입니다. 같은 클래스 내부에서만 접근 가능합니다. 다른 클래스, 자식 클래스, 심지어 같은 패키지에 있어도 접근할 수 없습니다.
(default) (아무것도 쓰지 않음)
접근 제한자가 생략되었을 경우입니다. 같은 패키지 내에서는 접근 가능하지만, 다른 패키지에서는 접근할 수 없습니다.
protected
같은 패키지 + 다른 패키지의 자식 클래스에서 접근 가능합니다. 외부 클래스에서는 접근 불가입니다.
public
가장 개방적인 접근 제어자입니다. 어디서든 접근이 가능합니다.
코드와 UML로 이해하는 접근 제어
예시 클래스: ClassA
package encapsulation01.packageOne;
public class ClassA {
private int pri;
int def;
protected int pro;
public int pub;
void runSomething() {
// 클래스 내부이므로 모든 멤버 접근 가능
}
static void runStaticThing() { }
}
클래스 구조도
클래스 다이어그램과 함께 보면 다음과 같이 구성되어 있습니다:
- ClassA 클래스는 같은 패키지인 ClassB, ClassAA, 다른 패키지의 ClassAB, ClassC와 관계를 맺고 있습니다.
- 각각의 클래스가 ClassA의 멤버에 접근할 수 있는지 여부는 제어자의 종류에 따라 달라집니다.
예를 들어, 같은 패키지인 ClassB에서는 def, pro, pub 멤버에 접근할 수 있지만 pri는 접근할 수 없습니다.
캡슐화를 적용한 설계 예시
- 내부 변수 pri, def, pro 등은 외부에서 직접 접근을 막고,
- 외부에서는 runSomething() 같은 메서드를 통해서만 내부 데이터를 조작하거나 확인할 수 있도록 제한합니다.
- 특히 메서드 내에서 클래스 자신(this)의 멤버에 접근하는 경우에는 모든 접근 제어자가 허용됩니다.
이런 방식으로 외부로부터 내부 구현을 보호하고, 유지보수를 편하게 할 수 있습니다.
접근 제어자 정리 팁
- 무조건 public이 좋지 않다! → 설계 의도에 따라 정보 은닉 수준을 조절해야 합니다.
- 자식 클래스에서 접근하게 하려면 protected를 고려하라
- 패키지 간 분리 여부를 고려하라 → default는 다른 패키지에서는 못 씀
자바에서 변수 전달 방식: Call By Value vs Call By Reference
Java를 공부하다 보면 가장 많이 헷갈리는 개념 중 하나가 바로 변수의 전달 방식입니다. 함수나 메서드에 변수를 넘길 때, 값 자체를 넘기는지, 아니면 주소를 넘기는지에 따라 프로그램의 동작이 완전히 달라질 수 있기 때문입니다.
자바는 모든 변수 전달을 Call By Value(값에 의한 호출) 방식으로 처리하지만, 객체를 다룰 때는 마치 참조(Call By Reference) 방식처럼 보이는 경우도 있어 혼란을 줍니다. 예제를 통해 명확하게 이해해 봅시다.
예제 1: 기본형 변수의 복사 – CallByValue.java
public class CallByValue {
public static void main(String[] args) {
int a = 10;
int b = a;
b = 20;
System.out.println(a); // 10
System.out.println(b); // 20
}
}
- a의 값을 b에 복사했기 때문에 a와 b는 서로 독립적인 변수입니다.
- b의 값을 변경해도 a에는 영향이 없습니다.
👉 기본형 데이터는 값 그 자체가 복사됩니다.
예제 2: 참조형 변수의 복사 – CallByReference.java
public class CallByReference {
public static void main(String[] args) {
Animal ref_a = new Animal();
Animal ref_b = ref_a;
ref_a.age = 10;
ref_b.age = 20;
System.out.println(ref_a.age); // 20
System.out.println(ref_b.age); // 20
}
}
class Animal {
public int age;
}
- ref_a와 ref_b는 같은 객체(주소)를 참조하고 있습니다.
- ref_b.age = 20으로 값을 바꾸면 ref_a.age도 20이 됩니다.
- 둘 다 같은 객체 인스턴스를 가리키고 있기 때문입니다.
👉 참조형은 값(객체의 주소)을 복사하지만, 실제 객체는 하나입니다.
정리: 자바의 변수 전달 방식은?
기본형 (int, double 등) | 값 자체를 복사 (진짜 Call By Value) |
참조형 (객체) | 참조값(주소)을 복사 (주소에 의한 Call By Value처럼 보임) |
- 객체를 넘기면 주소값이 복사되므로 실제 객체는 공유됩니다.
- 그러나 자바는 근본적으로 Call By Reference를 지원하지 않습니다.
요약
- 자바는 항상 Call By Value입니다.
- 객체도 주소 값만 복사되기 때문에 객체는 공유됩니다.
- 혼동을 줄이려면 “기본형은 값 복사, 참조형은 주소 복사”로 이해하면 됩니다.
'Spring > 스프링입문을 위한 자바객체지향의 원리와 이해' 카테고리의 다른 글
final 키워드 (0) | 2025.07.01 |
---|---|
static 블록 (0) | 2025.07.01 |
다형성 (0) | 2025.06.30 |
is-a 관계, 진짜 맞는 말일까? 상속과 인터페이스의 차이 (0) | 2025.06.30 |
객체지향에서의 상속 (0) | 2025.06.30 |