Book/Effective Java 3E
-
Item 29. 이왕이면 제네릭 타입으로 만들라Book/Effective Java 3E 2022. 11. 12. 10:30
Item 7의 스택 코드는 제네릭 타입이어야 마땅합니다. 제네릭으로 바꾼다고 해도 현재 버전을 사용하는 클라이언트에는 아무런 해가 없습니다. 오히려 지금 상태에서의 클라이언트는 스택에서 꺼낸 객체를 형변환해야 하는데, 이때 런타임 오류가날 위험이 있습니다. 일반 클래스를 제네릭 클래스로 만드는 첫 단계는 클래스 선언에 타입 매개변수를 추가하는 일입니다. 이때 타입 이름으로는 보통 E를 사용합니다(Item 68). 그런 다음 Object를 적절한 타입 매개변수로 바꾸고 컴파일해봅시다. 이 단계에서 대체로 하나 이상의 오류나 경고가 발생합니다(Stack 클래스 생성자 부분: elements = new E[DEFAULT_INITIAL_CAPACITY];). E와 같은 실체화 불가 타입으로는 배열을 만들 수 없..
-
Item 28. 배열보다는 리스트를 사용하라Book/Effective Java 3E 2022. 11. 12. 09:10
배열과 제네릭 타입의 차이 배열은 공변(convariant)이다. Sub가 Super의 하위 타입이라면 배열 Sub[]는 배열 Super[]의 하위 타입이 된다(공변, 즉 함께 변한다는 뜻이다). 반면, 제네릭은 불공변(invariant)이다. 즉, List은 List의 하위 타입도 아니고 상위 타입도 아니다. 배열은 실체화(reify)된다. 배열은 런타임에도 자신이 담기로 한 원소의 타입을 인지하고 확인한다(아래 코드 28-1 런타임 실패). 반면, 제네릭은 타입 정보가 런타임에는 소거(erasure)된다. 원소 타입을 컴파일타임에만 검사한다. 소거는 제네릭이 지원되기 전의 레거시 코드와 제네릭 타입을 함께 사용할 수 있게 해주는 메커니즘이다. // 코드 28-1 런타임에 실패한다. Object[] o..
-
Item 27. 비검사 경고를 제거하라Book/Effective Java 3E 2022. 11. 8. 23:00
제네릭을 사용하기 시작하면 수많은 컴파일러 경고를 보게 될 것입니다. 비검사 형변환 경고, 비검사 메서드 호출 경고, 비검사 매개변수화 가변인수 타입 경고, 비검사 변환 경고 등입니다. 대부분의 비검사 경고는 쉽게 제거할 수 있습니다. 할 수 있는 한 모든 비검사 경고를 제거하라 // warning 발생(javac 명령줄 인수에 -Xlint:uncheck 옵션 추가) Set exaltation = new HashSet(); // 비검사 경고 제거 Set exaltation = new HashSet(); 모두 제거한다면 그 코드는 타입 안정성이 보장됩니다. 즉, 런타임에 ClassCastException이 발생할 일이 없고, 잘 동작하리라 확신할 수 있습니다. @SuppressWarnings("unchec..
-
Item 26. 로 타입은 사용하지 말라Book/Effective Java 3E 2022. 11. 8. 22:00
클래스와 인터페이스 선언에 타입 매개변수(type parameter)가 쓰이면, 이를 제네릭 클래스 혹은 제네릭 인터페이스라 합니다.[JLS, 8.1.2, 9.1.2] 예컨대 List 인터페이스는 원소의 타입을 나타내는 타입 매개변수 E를 받습니다. 그래서 이 인터페이스의 완전한 이름은 List지만, 짧게 List라고도 자주 씁니다. 제네릭 클래스와 제네릭 인스턴스를 통틀어 제네릭 타입(generic type)이라 합니다. 각각의 제네릭 타입은 일련의 매개변수화 타입(parameterized type)을 정의합니다.[JLS, 4.5] 예컨대 List은 원소의 타입이 String인 리스트를 뜻하는 매개변수화 타입입니다. 여기서 String이 정규(formal) 타입 매개변수 E에 해당하는 실제(actual..
-
Item 25. 톱레벨 클래스는 한 파일에 하나만 담으라Book/Effective Java 3E 2022. 11. 6. 09:42
소스 파일 하나에 톱레벨 클래스를 여러 개 선언하면 어느 소스 파일을 먼저 컴파일하느냐에 따라 결과가 달라집니다. 다음 소스 파일은 Main 클래스 하나를 담고 있고, Main 클래스는 다른 톱레벨 클래스 2개(Utensil과 Dessert)를 참조합니다. package effectivejava.chapter4.item25; public class Main { public static void main(String[] args) { System.out.println(Utensil.NAME + Dessert.NAME); } } Utensil와 Dessert 클래스가 Utensil.java라는 파일과 Dessert.java라는 파일에 동시 정의되어 있다고 가정해 봅시다. package effectivejav..
-
Item 24. 멤버 클래스는 되도록 static으로 만들라Book/Effective Java 3E 2022. 11. 6. 09:25
중첩 클래스(nested class)란 다른 클래스 안에 정의된 클래스를 말합니다. 중첩 클래스는 자신을 감싼 바깥 클래스에서만 쓰여야 하며, 그 외의 쓰임새가 있다면 톱레벨 클래스로 만들어야 합니다. 중첩 클래스의 종류 정적 멤버 클래스 (비정적) 멤버 클래스 익명 클래스 지역 클래스 이 중 첫번째를 제외한 나머지는 내부 클래스(inner class)에 해당합니다. 정적 멤버 클래스 정적 멤버 클래스는 다른 클래스 안에 선언되고, 바깥 클래스의 private 멤버에도 접근할 수 있다는 점만 제외하고는 일반 클래스와 똑같습니다. 정적 멤버 클래스는 흔히 바깥 클래스와 함께 쓰일 때만 유용한 public 도우미 클래스로 쓰입니다. public class OuterClass { private int x = ..
-
Item 23. 태그 달린 클래스보다는 클래스 계층구조를 활용하라Book/Effective Java 3E 2022. 11. 2. 21:30
다음 코드는 원과 사각형을 표현할 수 있는 클래스입니다. package effectivejava.chapter4.item23.taggedclass; // 코드 23-1 태그 달린 클래스 - 클래스 계층구조보다 훨씬 나쁘다! class Figure { enum Shape { RECTANGLE, CIRCLE }; // 태그 필드 - 현재 모양을 나타낸다. final Shape shape; // 다음 필드들은 모양이 사각형(RECTANGLE)일 때만 쓰인다. double length; double width; // 다음 필드는 모양이 원(CIRCLE)일 때만 쓰인다. double radius; // 원용 생성자 Figure(double radius) { shape = Shape.CIRCLE; this.radi..
-
Item 22. 인터페이스는 타입을 정의하는 용도로만 사용하라Book/Effective Java 3E 2022. 11. 2. 21:00
인터페이스는 자신을 구현한 클래스의 인스턴스를 참조할 수 있는 타입 역할을 합니다. 인터페이스는 오직 이 용도로만 사용해야 합니다. 아래 상수 인터페이스 안티패턴은 인터페이스를 잘못 사용한 예입니다. package effectivejava.chapter4.item22.constantinterface; // 코드 22-1 상수 인터페이스 안티패턴 - 사용금지! public interface PhysicalConstants { // 아보가드로 수 (1/몰) static final double AVOGADROS_NUMBER = 6.022_140_857e23; // 볼츠만 상수 (J/K) static final double BOLTZMANN_CONSTANT = 1.380_648_52e-23; // 전자 질량 (..