자바 접근 제어자
자바에서 접근 제어자(Access Modifier)는 클래스, 메서드, 변수 등의 접근 범위를 결정하여 객체 지향 프로그래밍의 캡슐화(encapsulation)를 구현하는 데 사용됩니다. 자바는 네 가지 접근 제어자를 제공합니다: public
, private
, protected
, 그리고 default(접근 제어자를 명시하지 않을 때).
1. public
- 설명: 모든 클래스에서 접근 가능합니다. 패키지 내부 또는 외부 어디서든 해당 멤버에 접근할 수 있습니다.
- 접근 범위:
- 같은 클래스: O
- 같은 패키지: O
- 하위 클래스(다른 패키지): O
- 전체 외부 클래스: O
- 예시:
public class MyClass { public int myVariable; public void myMethod() { // 구현 코드 } }
- 사용 시기: 클래스의 인터페이스를 공개하여 다른 클래스나 패키지에서 자유롭게 사용할 수 있도록 할 때 사용합니다.
2. private
- 설명: 선언된 클래스 내에서만 접근 가능합니다. 다른 클래스에서는 접근할 수 없습니다.
- 접근 범위:
- 같은 클래스: O
- 같은 패키지: X
- 하위 클래스(다른 패키지): X
- 전체 외부 클래스: X
- 예시:
public class MyClass { private int myVariable; private void myMethod() { // 구현 코드 } }
- 사용 시기: 클래스 내부의 구현을 감추고 외부에서의 직접적인 접근을 막아 데이터의 무결성을 유지하고 싶을 때 사용합니다.
3. protected
- 설명: 동일한 패키지 내의 클래스 또는 다른 패키지에 있는 하위 클래스에서 접근 가능합니다.
- 접근 범위:
- 같은 클래스: O
- 같은 패키지: O
- 하위 클래스(다른 패키지): O
- 전체 외부 클래스: X
- 예시:
public class MyClass { protected int myVariable; protected void myMethod() { // 구현 코드 } }
- 사용 시기: 상속 관계에서 부모 클래스의 멤버를 하위 클래스에서 사용할 수 있도록 하면서도 외부 접근은 제한하고 싶을 때 사용합니다.
4. default (패키지 전용 접근 제어자)
- 설명: 접근 제어자를 명시하지 않을 때 적용되며, 동일한 패키지 내에서만 접근 가능합니다.
- 접근 범위:
- 같은 클래스: O
- 같은 패키지: O
- 하위 클래스(다른 패키지): X
- 전체 외부 클래스: X
- 예시:
public class MyClass { int myVariable; // 접근 제어자 없음 void myMethod() { // 구현 코드 } }
- 사용 시기: 패키지 내부에서만 사용되는 멤버를 정의할 때 사용합니다.
접근 제어자 선택 시 고려사항
- 캡슐화: 데이터의 무결성을 유지하기 위해 필드는 보통
private
으로 선언하고, 필요한 경우public
메서드를 통해 접근합니다. - 상속과 재사용성:
protected
는 상속 관계에서 하위 클래스가 부모 클래스의 멤버에 접근할 수 있도록 합니다.- 외부 패키지에서 클래스의 일부 기능만 노출하고 싶을 때 유용합니다.
- 패키지 구조:
default
접근 제어자는 같은 패키지 내에서만 접근이 가능하므로, 패키지 단위로 클래스를 묶어 관리할 때 유용합니다. - 보안과 유지보수:
- 불필요한 외부 접근을 막음으로써 코드의 보안을 높이고, 유지보수를 용이하게 합니다.
- 너무 많은 멤버를
public
으로 선언하면 오히려 코드의 복잡성이 증가하고 오류가 발생할 가능성이 높아집니다.
정리
- public: 어디서든 접근 가능 (전역 공개).
- private: 해당 클래스 내에서만 접근 가능 (완전 은닉).
- protected: 같은 패키지 또는 다른 패키지의 하위 클래스에서 접근 가능 (상속 관계에서 공개).
- default: 같은 패키지 내에서만 접근 가능 (패키지 공개).
접근 제어자는 객체 지향 프로그래밍에서 매우 중요한 개념으로, 올바른 사용을 통해 코드의 안정성과 재사용성을 높일 수 있습니다. 각 접근 제어자의 특성과 용도를 잘 이해하고 상황에 맞게 적용하는 것이 중요합니다.
@Embeddable와 protected 기본 생성자
1. @Embeddable
와 기본 생성자
@Embeddable
은 JPA에서 값 타입(Value Type)을 정의할 때 사용하는 어노테이션입니다. 값 타입 객체는 데이터베이스의 컬럼으로 매핑되며, 엔티티의 일부로 사용됩니다. 이때 JPA는 리플렉션(Reflection) 기술을 사용해 객체를 생성합니다.
리플렉션과 기본 생성자
- JPA는 리플렉션을 사용해 객체를 생성하고 데이터베이스에서 조회한 값을 객체에 주입합니다.
- 리플렉션은 기본 생성자가 반드시 필요합니다. JPA가
new Address()
처럼 기본 생성자를 호출해서 객체를 생성하기 때문입니다. - 기본 생성자는 직접 호출되지 않더라도, JPA의 내부 동작을 위해 꼭 필요합니다.
2. 왜 protected
접근제어자를 사용하는가?
JPA의 요구사항
- JPA에서는 기본 생성자를 반드시 제공해야 하지만, 이 생성자는 프레임워크 내부에서만 사용됩니다.
- 즉, 외부 코드에서 직접 호출하지 않도록 캡슐화해야 합니다.
protected
vs public
- public: 외부에서도 기본 생성자를 호출할 수 있게 됩니다. 이는 값 타입 객체의 불변성을 해칠 가능성을 열어줍니다.
- protected: JPA와 같은 프레임워크에서만 사용할 수 있도록 제한되며, 외부에서 호출할 수 없으므로 값 타입 객체의 불변성을 유지할 수 있습니다.
3. 객체지향 설계 관점
값 타입 객체는 불변 객체(Immutable Object)로 설계하는 것이 일반적입니다. 불변 객체는 객체 생성 이후 상태가 변하지 않도록 설계된 객체로, 다음과 같은 장점을 제공합니다:
- 안전성: 객체 상태가 변하지 않아 동시성 문제가 발생하지 않습니다.
- 신뢰성: 상태가 변하지 않으므로 데이터의 무결성을 유지할 수 있습니다.
Address 클래스의 불변성
private final
로 필드를 선언하고, setter를 제거하면 완벽한 불변 객체가 됩니다. 기본 생성자를 protected
로 제한하면 JPA 외부에서 호출할 수 없으므로 외부 코드로 인해 불변성이 깨지는 것을 방지합니다.
@Embeddable
@Getter
public class Address {
private final String city;
private final String street;
private final String zipcode;
protected Address() {
// JPA가 리플렉션을 통해 사용
this.city = null;
this.street = null;
this.zipcode = null;
}
public Address(String city, String street, String zipcode) {
this.city = city;
this.street = street;
this.zipcode = zipcode;
}
}
4. 결론
- 기본 생성자: JPA가 리플렉션 기술로 객체를 생성하기 위해 반드시 필요합니다.
protected
접근제어자: 외부에서 기본 생성자의 사용을 제한하여 불변성을 유지하고, JPA 프레임워크의 동작만 허용합니다.- 설계 원칙: 값 타입 객체는 불변 객체로 설계하는 것이 바람직하며, 이를 위해
protected
접근제어자를 사용합니다.
이러한 설계는 JPA의 동작 방식과 객체지향 원칙을 조화롭게 결합한 결과입니다.
'spring' 카테고리의 다른 글
@RequestBody @Valid Object obj, BindingResult br 타입에러가 br에 담기지 않는 이유 (0) | 2024.11.30 |
---|---|
도메인 모델 패턴 vs 트랜잭션 스크립트 패턴 (0) | 2024.11.25 |
JPA기초 @Entity & @Id & @GeneratedValue & 영속성 컨텍스트 (0) | 2024.11.23 |
[Spring] Spring Bean 과 Servlet에 관한 질의응답 (ChatGPT) (5) | 2024.09.02 |
[Spring] 서블릿 컨테이너와 스프링 컨테이너에 관한 질의응답 (ChatGPT) (0) | 2024.08.31 |
댓글