개발 서적/EFFECTIVE JAVA

열거 타입의 확장은 불가능? 열거 타입은 활용하기 좋지만 확장할 수 없다는 단점이 있다. 쉽게 말해서 Enum 타입은 상속이 불가능하다. 사실 대부분의 상황에서 열거 타입을 확장하는 것은 좋지 않은 생각이다. 열거 타입은 원소들을 순회할 수 있는데 기반 타입과 확장 타입을 모두 순회하는 방법도 마땅치 않다. 열거 타입은 인터페이스를 구현할 수 있다. 열거 타입을 상속받는 것은 불가능하다. 하지만 열거 타입이 인터페이스를 구현하는 것은 가능하다. 상위 인터페이스를 정의하고 이를 확장한 여러 열거 타입으로 유연하게 여러 열거 타입 구현체를 사용할 수 있다. 아래는 체스 미션에서 사용한 인터페이스와 열거 타입을 사용한 예시이다. 체스 미션에서 활용한 방향 열거 타입 체스 기물인 킹, 퀸, 폰, 룩, 비숍, 나..
자바가 람다를 지원하면서 API를 작성하는 방법이 크게 바뀌었다. 특히 함수형 인터페이스를 사용해 메서드마다 다른 동작을 메서드를 사용하는 클라이언트에서 지정해줄 수 있다. 이런 방식을 동작 파라미터화라고 한다. 이를 이용하면 변화하는 요구사항에 효과적으로 대응할 수도 있고 클래스와 클래스 간의 의존을 맺을 때 의존을 끊어줄 수도 있다. 변하는 요구사항에 대응하기 회원들의 리스트에서 어떤 조건에 따라 필터링을 해야 한다고 가정하자. public class Member { private final String name; private final int age; public Member(String name, int age) { this.name = name; this.age = age; } } 회원은 이름..
상속은 코드 중복을 제거하는 강력한 수단이지만 잘못 사용하면 오류를 내기 쉬운 소프트웨어를 만들게 된다. 상속의 문제점 상속은 캡슐화를 깨뜨린다. 하위 클래스가 가지는 상위 클래스에 대한 강한 의존성 때문에 상위 클래스의 구현에 따라 하위 클래스 동작이 의도와는 다르게 동작할 수도 있다. 게다가 상위 클래스의 변화가 하위 클래스까지 전파되어 변화에 맞춰 수정도 계속해주어야 한다. 예를 들어 HashSet을 상속 받는다고 가정하자. 상속받은 하위 클래스는 처음 생성된 이후 몇 개의 원소가 더해졌는지 횟수를 알고 싶어서 횟수를 알 수 있는 기능을 추가했다. public class InstrumentedHashSet extends HashSet { private int addCount = 0; @Overrid..
용어 정리 클래스와 인터페이스 선언에 타입 매개변수가 쓰이면, 이를 제네릭 클래스 혹은 제네릭 인터페이스라 한다. public interface List extends Collection { List 인터페이스는 E라는 원소 타입 매개변수를 받고 이러한 제네릭 클래스와 인터페이스를 통틀어 제네릭 타입이라 한다. 제네릭 타입은 매개변수화 타입을 정의한다. 예를 들어 List라고 했을 때 Integer가 리스트가 받을 수 있는 타입을 정의한 매개변수화 타입이다. 제네릭 타입에는 로 타입이라는 것도 있다. 로 타입이란 타입 매개변수를 사용하지 않은 제네릭 타입을 의미한다. List list; 그렇다면 이 로 타입을 사용하지 말아야 하는 이유는 무엇일까? 로 타입은 타입 안정하지 않다. List rawList ..
자바가 열거 타입을 지원하기 전 로또의 등수를 표현한다고 가정해보자. 열거 타입을 쓸 수 없다면 다음과 같이 표현할 수 있을 것이다. public static final int LOTTO_RANK_FIRST = 1; public static final int LOTTO_RANK_SECOND = 2; public static final int LOTTO_RANK_THRID = 3; public static final int LOTTO_RANK_FOURTH = 4; public static final int LOTTO_RANK_FIFTH = 5; public static final int LOTTO_RANK_NOTHING = 0; 1등은 정수 1로, 5등은 5로, 꽝은 0으로 정수를 열거하여 작성했다. 이렇..
불변 클래스 클래스의 인스턴스 내부 값을 수정할 수 없는 클래스를 불변 클래스라고 한다. 인스턴스의 정보는 객체가 파괴되는 순간까지 절대 달라지지 않는다. 불변 객체의 특징 불변 객체는 단순하다. 인스턴스 내부가 달라지는 가변 객체와 달리 분변 객체는 생성된 뒤부터 값이 달라지지 않았음을 보장하여 믿고 쓸 수 있다. 불변 객체는 스레드 세이프하고 동기화할 필요가 없다. 여러 스레드가 동시에 사용해도 훼손되지 않는다. 불변 객체는 안심하고 공유할 수 있다. 스레드 세이프한 것과 이어지는 내용인데 값이 달라지지 않기 때문에 재활용할 수 있으면 재활용하면 좋다. 자주 쓰이는 인스턴스는 캐싱하여 같은 인스턴스를 중복 생성하지 않게 해 줄 수도 있다. 객체를 만들 때 다른 불변 객체들을 구성 요소로 사용하면 이점..
똑같은 객체를 매번 생성하기보다 하나를 재사용하는 편이 나을 때가 많다. 특히 불변 객체는 생성할 필요 없이 언제든 재사용할 수 있다. 예시1. String String newString = new String("string"); String string1 = "string"; String string2 = "string"; 첫 줄처럼 문자열을 생성하는 사람은 없을 것이나 예시를 들기 위해 가져왔다. 문자열(String)은 프로그램이 실행되는 동안 엄청 많이 생성되는 객체이다. String은 String pool에서 관리되기 때문에 단순히 2,3번째 줄처럼 생성하면 String pool에서 인스턴스를 가져오기 때문에 불필요한 생성은 하지 않는다. 하지만 new로 생성하게 되면 새로운 인스턴스로 생성하기 ..
중첩 클래스 중첩 클래스(nested class)란 다른 클래스 안에 정의된 클래스를 말한다. 메서드 밖에서 사용해야 하거나 메서드 안에 정의하기에 너무 길 때 만든다. public class OuterClass { // ... class InnerClass { // ... } } 정적 멤버 클래스 static이 붙어 정적으로 선언된 중첩 클래스를 정적 멤버 클래스라고 한다. 바깥 클래스의 private 멤버 변수에도 접근할 수 있다는 점만 제외하고 일반 클래스와 똑같다. 멤버 클래스일 뿐 다른 정적 멤버 변수와 같은 규칙을 적용받는다. 바깥 클래스가 생성되는 것과 상관없이 독립적으로 생성할 수 있다. public class OuterClass { static class StaticInnerClass {..
더즈
'개발 서적/EFFECTIVE JAVA' 카테고리의 글 목록