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 프로그래밍