디폴트 메서드의 문제 자바 8 전에는 기존 구현체를 깨뜨리지 않고는 인터페이스에 메서드를 추가할 방법이 없었다. 인터페이스에 메서드를 추가하면 컴파일 오류가 발생한다. 인터페이스에 메서드를 추가할 수 있도록 디폴트 메서드가 자바 8이후로 출현했지만 위험이 완전히 사라진건 아니다. 디폴트 메서드를 선언하면, 그 인터페이스를 구현한 후 디폴트 메서드를 재정의하지 않은 모든 클래스에서 디폴트 구현이 쓰이게 된다. 모든 기존 구현체들과 매끄럽게 연동되진 않는다. 디폴트 메서드는 구현 클래스에 대해 아무것도 모른채 합의 없이 무작정 삽입될 뿐이다. 문제상황 자바 8에서 컬렉션 인터페이스들에 다수의 디폴트 메서드가 추가됬지만, 모든 상황에서 불변식을 해치지 않는 디폴트 메서드를 작성하긴 어려웠다. Collectio..
다중 구현 메커니즘 자바가 제공하는 다중 구현 메커니즘은 인터페이스, 추상클래스 2가지다. 자바 8부터 인터페이스도 디폴트 메서드를 제공할 수 있게되었다. 디폴트 메서드란? https://devfunny.tistory.com/350 자바8의 default 메서드 등장 디폴트 메서드의 등장 자바 8에서는 기본 구현을 포함하는 인터페이스를 정의하는 2가지 방법을 제공한다. 만약 인터페이스를 바꾸게 되었을때, 해당 인터페이스를 구현한 모든 클래스의 구현 devfunny.tistory.com 추상클래스 추상 클래스와 인터페이스의 가장 큰 차이는 추상 클래스가 정의한 타입을 구현하는 클래스는 반드시 추상 클래스의 하위 클래스가 되어야한다는 점이다. 자바는 단일 상속만 가능하므로, 추상 클래스 방식은 새로운 타입을..
들어가기전 아이템 19를 공부하기 전, 아이템 18 포스팅을 먼저 읽어보자. https://devfunny.tistory.com/544 [교재 EffectiveJava] 아이템 18. 상속보다는 컴포지션을 사용하라 상속 상속은 코드를 재사용하는 강력한 수단이지만, 항상 최선은 아니다. 잘못 사용하면 오류를 내기 쉬운 소프트웨어를 만들게된다. 안전한 상속 상위 클래스와 하위 클래스를 모두 같은 프로 devfunny.tistory.com 상속을 고려한 설계와 문서화 우선, 메서드를 재정의하면 어떤 일이 일어나는지를 정확히 정리하여 문서로 남겨야한다. 즉, 상속용 클래스는 재정의할 수 있는 메서드들을 내부적으로 어떻게 이용하는지 문서로 남겨야한다. 1) 클래스의 API 로 공개된 메서드에서 클래스 자신이 또다..
상속 상속은 코드를 재사용하는 강력한 수단이지만, 항상 최선은 아니다. 잘못 사용하면 오류를 내기 쉬운 소프트웨어를 만들게된다. 안전한 상속 상위 클래스와 하위 클래스를 모두 같은 프로그래머가 통제하는 패키지 안에서의 상속일 경우 확장할 목적으로 설계되었고, 문서화도 잘 된 클래스의 경우 위험한 상속 구체 클래스를 패키지 경계를 넘어, 다른 패키지의 구체 클래스를 상속하는 경우 해당 아이템은 '위험한 상속'에 속하는 경우를 말하며, 클래스-인터페이스 사이의 구현 및 확장하는 인터페이스 상속과는 무관하다. 상속의 캡슐화 저하 상속은 캡슐화를 깨뜨린다. 상위 클래스가 어떻게 구현되느냐에 따라 하위 클래스의 동작에 이상이 생길 수 있다. 확장이 충분히 고려되지않은 상속에서는 상위 클래스의 수정에 따라 하위 클..
불변 클래스 불변 클래스란, 그 인스턴스의 내부 값을 수정할 수 없는 클래스이다. 불변 인스턴스에 간직된 정보는 고정되어 절대 달라지지 않는다. 자바 플랫폼 라이브러리에서 불변 클래스로 예를 든다면, String, 기본 타입의 박싱된 클래스들, BigInteger, BigDecimal 등이 존재한다. 불변 클래스를 설계한 이유는 상태가 바뀌지 않는 특성 덕분에, 가변 클래스보다 설계 및 구현과 사용이 쉽고 오류가 생길 여지가 적고 훨씬 안전하기 때문이다. 불변 클래스로 만들기 1) 객체의 상태를 변경하는 메서드 (setter) 를 제공하지 않는다. 2) 클래스를 확장할 수 없도록 한다. 예를 들면 클래스를 final 로 선언하여 상속을 막아서 하위 클래스에서 변경할 수 없도록 한다. 3) 모든 필드를 f..
public 클래스의 public 필드의 사용(하지마라) public class Point { public double x; public double y; public static void main(String[] args) { Point point = new Point(); // 외부 클래스에서 아래와같이 직접 접근 가능 point.x = 10; point.y = 20; System.out.println(point.x); System.out.println(point.y); } } 위 예제의 public 필드는 아주 위험하다. 이런 클래스는 데이터 필드에 직접 접근이 가능하게되면서, API를 수정하지 않고는 내부 표현을 바꿀 수 없고, 불변식을 보장할 수 없고, 외부에서 필드에 접근할때 부수 작업을 수행..
길이가 0 이상일 경우 변경 가능한 public static final array public class ArrayTest { public static final int[] VALUES = {1, 2, 3, 4}; } 값을 변경해보자 public class Main { public static void main(String[] args) { System.out.println(ArrayTest.VALUES[0]); // 1 ArrayTest.VALUES[0] = 5; /* 변경이 된다 */ System.out.println(ArrayTest.VALUES[0]); // 5 } } 해결방안 1 import java.util.Arrays; import java.util.Collections; import jav..
정보은닉 컴포넌트를 설계를 잘하기 위해서는 클래스 내부 데이터와 내부 구현 정보를 외부 컴포넌트로부터 잘 숨겨야한다. 잘 설계된 컴포넌트는 모든 내부 구현을 완벽히 숨겨, 구현과 API를 깔끔히 분리한다. 오직 API 를 통해서만 다른 컴포넌트와 소통하며 서로의 내부 동작에는 전혀 개의치 않는다. 이것을 정보은닉 또는 캡슐화라고 한다. 정보은닉의 장점 1. 시스템 개발 속도를 높인다. 여러 컴포넌트를 병렬로 개발할 수 있다. 인터페이스를 개발하면 이에 맞춰서 개발하고, 구현하면된다. 인터페이스를 사용하는 쪽과 지원하는 쪽이 동시에 개발이 가능하다. 2. 시스템 관리 비용을 낮춘다. 각 컴포넌트를 더 빨리 파악하여 디버깅할 수 있다. 다른 컴포넌트로 교체하는 부담도 적다. 인터페이스 기준으로 캡슐화가 잘 ..