
int a = 10;
int b = a;
System.out.println(a); // 10
System.out.println(b); // 10
기본타입은 항상 값을 복사한다.
a와 b는 다른 저장공간을 가진다.
Integer a = 10;
Integer b = a;
a.setValue(20); // (실제로 없는 메서드)
System.out.println(a); // 20
System.out.println(b); // 20
래퍼클래스는 주소가 공유가 된다.
따라서 값이 바뀐다면 같은 주소를 참조하고 있기 때문에 바뀐 값이 공유되어 출력된다.
하지만 래퍼클래스(참조형)은 불변객체이므로, 값이 바뀔 수가 없다!
String city, String street, String zipcode처럼 흩어져 있던 필드를 Address라는 클래스로 묶어서 재사용할 수 있다.@Embeddable
@NoArgsConstructor
public class Address {
private String city;
private String street;
private String zipcode;
}
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
private String name;
@Embedded
private Address address; // ✅ 임베디드 타입
}
JPA에서 임베디드 타입(Embeddable)을 공유할 때 생길 수 있는 부작용(side effect)은 주로 참조에 의한 변경(shared reference mutation)에서 발생한다.
임베디드 타입은 참조 타입이라, 여러 엔티티가 같은 임베디드 객체를 참조하면 한 곳의 변경이 다른 곳에도 영향을 줄 수 있다!
@Embeddable
public class Address {
private String city;
private String street;
public Address(String city, String street) {
this.city = city;
this.street = street;
}
public void setCity(String city) {
this.city = city;
}
}
Address address = new Address("Seoul", "Gangnam");
Member member1 = new Member("UserA", address); // 1차 공유
Member member2 = new Member("UserB", address); // 2차 공유
member1.getAddress().setCity("Busan"); // member1만 바꿨는데...
@Embeddable
@Getter // Getter만 설정
@NoArgsConstructor
@AllArgsConstructor // 필드 생성자
public class Address {
private String city;
private String street;
}
💡 Java에서 final 필드는 JPA에서 직접 지원하지 않으므로, 필드에 final을 쓰지 않고 setter만 제거하는 방식으로 한다.
Setter를 만들지 말자.김영한 자바 ORM 표준 JPA 프로그래밍