목록분류 전체보기 (115)
도당탕탕
하나이상의 타입 파라미터를 가지고 있는 클래스 또는 인터페이스를 제너릭 클래스 또는 인터페이스 라고 한다. 모든 제너릭 타입은 타입 파라미터가 없는 제너릭 타입의 이름인 raw type을 정의한다. 예를 들어, List에 대응하는 raw type은 List이다. Raw type은 제너릭 타입 정보가 삭제된 것처럼 동작한다. 주로 제너릭이 생기기 이전의 코드와 호환성을 위해서 존재한다. 자바에 제너릭이 추가되기 이전에는, 전형적인 컬렉션 선언방법이었다. private final Collection stamps = ...; 만약 위처럼 선언한 뒤에 stamps.add(new Coin(...));를 호출하게 되면, 컴파일, 런타임 에러가 나지 않는다. 하지만 결국 다음과 같이 객체를 읽어 들일 때 런타임 에러..
소스 파일 하나에 톱레벨 클래스를 여러 개 선언하더라도 자바 컴파일러는 에러를 내지 않는다. 하지만 이러한 행위는 정말 위험하고 아무런 득이 없는 행위이다. 그 이유는 한 클래스를 여러 가지로 정의할 수 있으며, 그중 어느 것을 사용할지는 어느 소스 파일을 먼저 컴파일하냐에 따라 달라지기 때문이다. 다음 예를 보자. Main.java class Main { public static void main(String[] args) { System.out.println(Utensil.NAME + Dessert.NAME); } } Utensil.java class Utensil { static final String NAME = "pan"; } class Dessert { static final String NA..
Nested class(이하 중첩 클래스)는 오직 Enclosing class(이하 동봉 클래스)를 돕기 위해서만 사용되어야 한다. 만약 그렇지 않으면 top level 클래스로 정의해야 한다. 4가지 종류의 중첩 클래스가 존재한다. static member class nonstatic member class anonymous class local class 여기서 2,3,4 번을 inner 클래스라고도 부른다. 1. Static member class 가장 흔한 사용은 오직 동봉 클래스와 연계해서 사용되는 public helper class이다. public class Calculator { // ... public static enum Operation { PLUS,MINUS; } } private ..
태그 값으로 알려주는 클래스는 단점이 많다. 다음 코드를 보면 알 수 있을 것이다. 태그 달린 클래스 class Figure { enum Shape { RECTANGLE, CIRCLE }; // tag 기능 final Shape shape; double length; double width; double radius; Figure(double radius) { shape = Shape.CIRCLE; this.radius = radius; } Figure(double length, double width) { shape = Shape.RECTANGLE; this.length = length; this.width = width; } double area() { switch(shape) { case RECTA..
인터페이스를 만들 때는 클라이언트에게 어떤 일을 할 수 있는지 정보를 제공해야 한다. 이러한 규칙에 위배되는 것 중에 소위 constant interface라고 하는 것이 있다. 보통 아래와 같이 정의되고, 상수에 접근할 필요가 있는 클래스에서 인터페이스를 구현해서 사용한다. 이렇게 인터페이스에 상수를 정의하는 이유는 클래스 이름을 사용해서 지칭해야 할 필요가 없기 때문이다. public interface PhysicalConstants { static final double AVOGADROS_NUMBER = 6.022_140_857e23; static final double BOLTZMANN_CONSTANT = 1.380_648_52e-23; static final double ELECTRON_MASS..
현재 자바 8 이전 버전에서는 기존 구현체를 깨트리지 않고는 인터페이스에 메서드를 추가할 방법이 없었다. 그래서 자바 8 이후에 디폴트 메서드를 통해 기존 인터페이스에 추가할 수 있도록 했다. 디폴트 메소드가 추가되면서 자바에서도 기존 인터페이스에 메서드를 추가하는 방법이 생겼지만 기존 구현체와 매끄럽게 연동이 되긴 힘들다. 그 이유는 구현 클래스에 대해 아무것도 모른 채 합의 없이 무작정 삽입시킬 수 있기 때문이다. 자바 8에서 핵심 컬렉션 인터페이스들에 다수의 디폴트 메소드가 추가되었다. 주로 람다를 활용하기 위해서다. 자바 라이브러리의 디폴트 메서드는 코드 품질이 높고 범용적이라 대부분 상황에서 잘 작동하지만 생각할 수 있는 모든 상황에서 불변식을 해치지 않는 디폴트 메소드를 작성하기에는 어렵다. ..
먼저 추상화 클래스의 문제점부터 보자. 추상화 클래스를 상속하는 클래스는 다른 클래스를 상속받을 수 없다. 즉, 한 가지 타입에 종속되어 버린다. //TypeA.java public abstract class TypeA {} //TypeB.java public abstract class TypeB {} //TypeTest.java => 컴파일에러!! public class TypeTest extends TypeA,TypeB { } 반면 인터페이스는 mixin 을 정의하는데 이상적이다. 여기서 말하는 mixin 이란 Mixed In의 약자로 어느 한 인터페이스를 이미 구현하고 있는 클래스에서 새로운 인터페이스를 구현하여 새로운 선택적인 기능을 얻게 된다는 뜻이다. 추상 클래스는 두 개 이상 상속할 수 없기..
상속을 고려한 설계와 문서화란 정확히 말하면 다음과 같다. 상속을 고려한 설계와 문서화 메서드를 재정의하면 어떤 일이 일어나는지를 정확히 정리하여 문서로 남겨야 한다. 달리 말하면 상속용 클래스는 재정의할 수 있는 메서드들을 내부적으로 어떻게 이용하는지 문서로 남겨야 한다. 클래스의 API로 공개된 메소드에서 클래스 자신의 또 다른 메서드를 호출할 수 있다. 그런데 마침 호출되는 메서드가 재정의 가능 메서드라면 그 사실을 호출하는 메서드의 API 설명에 적시해야 한다. 덧붙여서 어떤 순서로 호출하는지, 각각의 호출 결과가 이어지는 처리에 어떤 영향을 주는지도 담아야 한다. 즉 재정의 가능 메소드를 호출할 수 있는 모든 상황을 문서로 남겨야 한다. 대표적인 예로 @implSpec를 들 수 있다. Imple..