| 제어자 | 같은 클래스 | 같은 패키지 | 상속(자식) | 전체 (외부) |
| Private | ⭕ | ❌ | ❌ | ❌ |
| Default | ⭕ | ⭕ | ❌ | ❌ |
| Protected | ⭕ | ⭕ | ⭕ | ❌ |
| Public | ⭕ | ⭕ | ⭕ | ⭕ |
공개 범위는 public> protected> default> private
여담으로 스프링 JPA에서
package com.kindtail.adoptmate.animal.domain;
import com.kindtail.adoptmate.adoption.domain.Adoption;
import com.kindtail.adoptmate.animal.dto.AnimalCreateRequest;
import com.kindtail.adoptmate.animal.dto.AnimalStatusUpdateRequest;
import com.kindtail.adoptmate.member.domain.Member;
import jakarta.persistence.*;
import lombok.*;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@Entity
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name = "tbl_animal")
public class Animal {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "animal_id")
private Long id;
private String species;
@Enumerated(EnumType.STRING)
private Gender gender;
private String breed;
private String color;
@Enumerated(EnumType.STRING)
private Status status=Status.PROTECTED;
private Long age;
@Lob
private String image;
@ManyToOne(fetch = FetchType.LAZY ) // @manyToOne 일때 cascade = CascadeType.ALL 필요없음
@JoinColumn(name = "member_id", nullable = false) // 외래 키 컬럼명 지정
private Member member;
@CreationTimestamp
private LocalDateTime createdAt;
@UpdateTimestamp
private LocalDateTime updatedAt;
public void updatestatus (AnimalStatusUpdateRequest request) {
this.status= request.status();
}
@OneToMany(mappedBy = "animal", cascade = CascadeType.REMOVE, orphanRemoval = true)
private List<Adoption> adoptions = new ArrayList<>();
}
1. "무분별한 객체 생성 방지" (객체의 무결성)
기본 생성자가 public으로 열려 있으면, **"데이터가 텅 빈 불완전한 객체"**를 누군가 실수로 생성할 수 있습니다.
- 예: Animal animal = new Animal(); (이름도, 주인도 없는 동물이 생성됨)
- 이런 객체는 나중에 NullPointerException 같은 치명적인 버그를 유발합니다.
- 따라서 protected로 막아두어, 외부에서는 반드시 **@Builder**나 파라미터가 있는 생성자를 통해서만 **"완전한 상태의 객체"**를 만들도록 강제하는 것입니다.
2. "JPA 프록시 객체의 상속 문제" (기술적 이유)
- 설명: "그럼 아예 private으로 막으면 안 되나요?"
- JPA는 **지연 로딩(Lazy Loading)**을 지원하기 위해, 실제 엔티티 대신 **가짜 객체(프록시)**를 만듭니다.
- 이 프록시는 우리 Animal 클래스를 **상속(extends)**받아서 만들어집니다.
- 자바 문법상 자식 클래스(프록시)는 부모(엔티티)의 생성자를 호출해야 하는데, private이면 호출할 수 없습니다.
- 결국 "외부 접근은 막으면서(Private 효과), JPA 프록시에게는 상속을 허용하는(Inheritance)" 최적의 단계가 **protected**인 것입니다.
'개발 공부 > Java-Spring' 카테고리의 다른 글
| [Java] final, static, static final 차이점 완벽 정리 (0) | 2026.05.09 |
|---|---|
| Spring의 핵심, IoC와 DI: 제어의 역전과 의존성 주입 완벽 가이드 (0) | 2026.01.23 |
| [JPA] N+1 문제, 원인과 결과로 완벽하게 이해하기 (0) | 2026.01.20 |
| 불변의 객체 의 정의 (0) | 2025.12.10 |
| spring ai 해보기 (0) | 2025.12.06 |