일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- Java
- FLUTTER
- flutter firestore
- Flutter TextField
- RxAndroid
- Python
- 코틀린
- NDK
- 안드로이드 구글맵
- UWP
- C
- Rxjava2
- mfc
- 알고리즘
- android push
- Django REST Android
- C/C++
- Android
- RxJava
- Django REST
- android architecture component
- Kotlin
- Android P
- 프로그래머스
- dart
- 안드로이드
- Django REST framework
- C++
- kodility
- livedata
- Today
- Total
개발하는 두더지
[Effective Java 규칙11] clone을 재정의할 때는 신중하라 본문
[Effective Java 규칙11] clone을 재정의할 때는 신중하라
Effective Java 2/E 책과 구글링을 통해 내용을 정리하고 개인적인 견해가 포함된 글입니다.
어떤 클래스가 Cloneable 인터페이스를 구현하면 Object의 protected 인 clone 메서드가 어떻게 동작할지를 정하게된다.
먼저 clone 메서드의 규약은 느슨한 편인데 아래 규약을 살펴보자
객체의 필드단위까지 복사하여 반환하는데 다음의 조건이 일반적으로 충족되야 한다
x.clone() != x 이 조건은 참이어야 한다
x.clone().getClass() == x.getClass() 이 조건은 참이겠지만 반드시 그래야하는 것은 아니다
x.clone().equals(x) 이 조건도 참이겠지만 반드시 그래야하는 것은 아니다
객체를 복사하면 보통 같은 클래스의 새로운 객체가 만들어지는데, 어떤 생성자도 호출되지 않는다.
음. 무슨 내용을 알려주고싶은건지 확실히 이해가 안간다.
final이 아닌 클래스에 clone을 재정의할 때는 클래스에 Cloneable 인터페이스를 구현하고(메소드가 하나도 없기때문에 구현할 건 없다. 클래스에 Cloneable 인터페이스를 사용하겠다고 선언하는 것 뿐) clone 메소드를 오버라이드하고 반드시 super.clone을 호출해 얻은 객체를 반환해야 한다. 이렇게 안한다면 CloneNotSupportedException에 걸리게 된다.
@Override
protected PhoneNumber clone(){
try {
return (PhoneNumber) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
clone할 경우에 주의해야할 점이있는데 복제할 객체가 변경가능한 객체의 참조 필드를 가지고 있다면 문제가 생긴다. 기본자료형 필드의 경우 그대로 복사가되지만 배열의 경우 원래 객체의 배열을 참조하게 되는 문제가 발생한다. 배열의 경우 super.clone()을 통해서 얻은 객체에 배열의 clone을 다시 set 해줘야 한다.
clone은 또다른 형태의 생성자이므로 원래 객체를 손상시키는 일이 없어야 하며 복사본의 불변식을 만족시켜야 한다.
배열객체.clone을 하면 자바 1.5부터 반환되는 배열의 컴파일 시점 자료형으로 복사가되므로 따로 형변환 할 필요가 없다.
@Override public Stack clone() {
try {
Stack result = (Stack) super.clone();
result.elements = elements.clone();
return result;
} catch( CloneNotSupportedException e) {
throw new AssertionError();
}
}
( 규칙 6에서 사용한 Stack 클래스의 clone 재정의 )
생각보다 cloneable 인터페이스를 구현하고 clone 메서드를 재정의하는 작업은 복사하기위해 많은 코드들이 필요하며 신경써야할 부분들이 많다.
그래서 객체 복제를 지원하는 좋은 방법은 복사 생성자나 복사 팩터리를 제공하는 것이다.
Cloneable/clone보다 장점들이 많다. 객체 생성 수단에 의존하지 않고, 어려운 규약을 지킬 필요도 없고, final 과 충돌이 일어나지 않으며, 불필요한 예외 검사를 할 필요가 없고, 형 변환도 필요없다. 이러한 인터페이스 기반의 생성자와 팩터리는 변환 생성자 (conversion constructor)로 더 잘 알려져 있으며 예를들면
HashSet객체 s가 있고, 이것을 TreeSet으로 복제하고 싶을 때 변환 생성자를 사용하면 new TreeSet(s)로 만들면 된다.
결론적으로,
Cloneable을 구현하는 인터페이스를 만들지 말아야 하며, 상속을 목적으로 설계하는 클래스는 Cloneable을 구현하지말고
변환 생성자를 이용하여 복사하는 것이 더 좋은 방법이다.
'Java,Android' 카테고리의 다른 글
[Effective Java 규칙13] 클래스와 멤버의 접근 권한은 최소화하라 (0) | 2018.09.14 |
---|---|
[Effective Java 규칙12] Comparable 구현을 고려하라 (0) | 2018.09.14 |
[Effective Java 규칙9] equals를 재정의할 때는 반드시 hashCode도 재정의하라 (0) | 2018.09.14 |
[Effective Java 규칙8] equals를 재정의할 때는 일반 규약을 따르라 (0) | 2018.09.14 |
Effective Java로 Java를 효과적으로 사용해보자 (0) | 2018.09.04 |