✅ 기본형과 참조형의 공유
🔎 도입
프로그래밍에서 변수는 데이터를 저장하는 기본 단위입니다. 하지만 변수의 타입에 따라 데이터의 저장 방식과 공유 방식이 달라집니다. 특히 기본형(Primitive Type) 과 참조형(Reference Type) 은 메모리 관리 방식이 다르며, 이에 따라 값의 변경 및 공유 방식도 차이가 있습니다. 이러한 차이를 이해하는 것은 부수효과(Side Effect)와 불변성(Immutability)의 개념을 파악하는 데 중요한 요소가 됩니다.
🔎 기본형과 참조형의 차이
- 기본형(Primitive Type)
- 변수에 값 자체를 저장합니다.
- 다른 변수에 값을 복사하면 별도의 값이 생성됩니다.
- 변경해도 다른 변수에는 영향을 주지 않습니다.
- 참조형(Reference Type)
- 변수에 객체의 메모리 주소(참조값) 를 저장합니다.
- 같은 객체를 참조하는 변수를 통해 값을 변경하면, 모든 참조 변수에 영향을 미칩니다.
📝 예제: 기본형과 참조형의 차이 (Java)
public class ReferenceTypeExample {
public static void main(String[] args) {
// 기본형 변수
int a = 10;
int b = a; // 값이 복사됨
b = 20;
System.out.println("a: " + a); // 10
System.out.println("b: " + b); // 20
// 참조형 변수
int[] arr1 = {1, 2, 3};
int[] arr2 = arr1; // 참조값(주소)이 복사됨
arr2[0] = 100;
System.out.println("arr1[0]: " + arr1[0]); // 100 (같은 객체를 참조)
System.out.println("arr2[0]: " + arr2[0]); // 100
}
}
💡 기본형 변수는 값이 복사되지만, 참조형 변수는 객체의 주소를 복사하므로 값 변경이 서로 영향을 줍니다.
✅ 공유참조와 부수효과
🔎 부수효과(Side Effect)란?
- 부수효과란 함수나 메서드가 주된 작업 외에 추가적인 변경을 일으키는 것을 의미합니다.
- 대표적인 예로 공유참조(Shared Reference)를 통한 데이터 변경이 있습니다.
- 부수효과는 예측하지 못한 동작을 초래할 수 있어 디버깅을 어렵게 만듭니다.
📝 예제: 공유참조로 인한 부수효과
class Person {
String name;
Person(String name) {
this.name = name;
}
}
public class SideEffectExample {
public static void main(String[] args) {
Person p1 = new Person("Alice");
Person p2 = p1; // p1과 p2가 같은 객체를 참조
p2.name = "Bob"; // p2를 변경했지만 p1도 영향을 받음
System.out.println(p1.name); // Bob
}
}
💡 같은 객체를 참조하는 변수에서 값이 변경되면, 원치 않는 곳에서도 값이 변경되는 문제가 발생할 수 있습니다.
✅ 부수효과의 해결방안
🔎 공유참조 해제
- 공유참조된 객체의 복사본을 만들어 사용하면, 원본 객체를 보호할 수 있습니다.
- 하지만 이는 단기적인 해결책이며, 완전한 해결책은 불변객체(Immutable Object)를 활용하는 것입니다.
📝 예제: 객체 복사로 공유참조 해제
class Person {
String name;
Person(String name) {
this.name = name;
}
// 복사 생성자 사용
Person(Person other) {
this.name = other.name;
}
}
public class CopyExample {
public static void main(String[] args) {
Person p1 = new Person("Alice");
Person p2 = new Person(p1); // 새로운 객체 생성
p2.name = "Bob";
System.out.println(p1.name); // Alice (영향받지 않음)
}
}
💡 복사 생성자를 사용하면 공유참조 문제를 완화할 수 있지만, 이는 근본적인 해결책이 아닙니다.
✅ 불변객체(Immutable Object)로 해결
🔎 불변객체란?
- 한 번 생성되면 내부 상태가 변하지 않는 객체를 의미합니다.
- Java에서는 final 키워드를 활용하여 불변성을 보장할 수 있습니다.
- 불변객체는 값이 변경될 때 새로운 객체를 생성하여 반환해야 합니다.
📝 예제: 불변객체 만들기
final class ImmutablePerson {
private final String name;
public ImmutablePerson(String name) {
this.name = name;
}
public String getName() {
return name;
}
// 새로운 객체 반환 (with 패턴 적용)
public ImmutablePerson withName(String newName) {
return new ImmutablePerson(newName);
}
}
public class ImmutableExample {
public static void main(String[] args) {
ImmutablePerson p1 = new ImmutablePerson("Alice");
ImmutablePerson p2 = p1.withName("Bob"); // 새로운 객체 생성
System.out.println(p1.getName()); // Alice (원본 객체는 유지)
System.out.println(p2.getName()); // Bob (새로운 객체)
}
}
💡 불변객체를 사용하면 원본 객체가 변경되지 않으며, 부수효과를 방지할 수 있습니다.
✅ 불변객체 활용과 관례
🔎 set 대신 with 사용
- 일반적으로 객체의 속성을 변경할 때 set 메서드를 사용하지만, 불변객체에서는 with를 사용하는 것이 관례입니다.
- setName(String name) 대신 withName(String name)을 사용하면 새로운 객체를 반환하는 방식임을 명확히 나타낼 수 있습니다.
✅ 결론
- 기본형과 참조형의 차이를 이해해야 합니다.
- 공유참조로 인한 부수효과는 디버깅을 어렵게 만듭니다.
- 불변객체를 활용하면 부수효과를 원천적으로 방지할 수 있습니다.
- 불변객체에서는 set 대신 with를 사용하여 새로운 객체를 생성하는 방식으로 값을 변경합니다.
💡 객체의 상태를 불변으로 유지하면 코드의 예측 가능성이 높아지고, 유지보수성이 향상됩니다.