2018-6-2 Basic Generic

제네릭의 기본문법

  • 다중 매개변수 기반 제네릭 클래스의 정의
package yoon;

class DBox<L, R> {
    private L left; // 왼쪽 수납공간
    private R right;

    public void set(L o, R r) {
        left = o;
        right = r;
    }
gi
    @Override
    public String toString() {
        return left + " & " + right;
    }
}

public class MultiTypeParam {
    public static void main(String [] args) {
        DBox<String, Integer> box = new DBox<String, Integer>();
        box.set("Apple", 25);
        System.out.println(box);
    }
}
//result
Apple & 25

타입매개변수의 규칙

  1. 한 문자로 이름을 짓는다.
  2. 대문자로 이름을 짓는다.
  3. 기본자료형의 이름은 타입인자로 쓸 수 없다.
    • E : Element
    • K : Key
    • N : Number
    • T : Type
    • V : Value
  • 위와 같이 사용을 하는게 자바의 컨벤션이다.
Box<int> box = new Box<int>();
// 타입 인자로 기본 자료형이 올 수 없으므로 컴파일 오류가 발생
package yoon;

public class PrimitivesAndGeneric {
    public static void main(String [] args) {
        Box2<Integer> iBox = new Box2<Integer>();
        iBox.set(125); // 오토박싱 진행
        int num = iBox.get();
        System.out.println(num);
    }
}
//result
125

타입인자의생략: 다이아몬드기호

  • Box aBox = new Box();
  • Box aBox = new Box<>();
  • 위의 두 문장은 같은 의미이다. 참조 변수의 선언을 통해서 <> 안에 Apple이 생략이 되었다고 컴파일러가 판단을 한다.
package yoon;

public class BoxInBox {
    public static void main(String [] args) {
        Box2<String> sBox = new Box2<>();
        sBox.set("I am so happy.");

        Box2<Box2<String>> wBox = new Box2();
        wBox.set(sBox);

        Box2<Box2<Box2<String>>> zBox = new Box2();
        zBox.set(wBox);

        System.out.println(zBox.get().get().get());
    }
}
//result
I am so happy.
  • 위 코드를 통해 Box과 같은 '매개변수화 타입'이 '타입인자'로 사용될 수 있다는것을 알 수 있다.

타입인자의 제한

  • class Box {... } : 인스턴스 생성 시 타입인자로 Number 또는 이를 상속하는 클래스만 올 수 있다.
package yoon;

class Box<T extends Number> {
	private T ob;

    public void set(T o) {
    	ob = o;
    }

    public T get() {
    	return ob;
    }

}

public class BoundedBox {
    public static void main(String [] args) {
        Box2<Integer> iBox = new Box2<>(); // Integer는 Number를 상속
        iBox.set(24);

        Box2<Double> dBox = new Box2<>(); // Double은 Number를 상속
        dBox.set(5.97);

        System.out.println(iBox.get());
        System.out.println(dBox.get());
    }
}
//result
24
5.97

제네릭 클래스의 타입인자를 인터페이스로 제한하기

package yoon;

interface Eatable {
    public String eat();
}

class Apple2 implements Eatable {
    @Override
    public String toString() {
        return "I am an apple.";
    }

    @Override
    public String eat() {
        return "It's tastes so good";
    }
}

class Box3<T extends Eatable> {
    T ob;

    public void set(T o) {
        ob = o;
    }

    public T get() {
        System.out.println(ob.eat()); // Eatable로 제한해서 eat호출 가능
        return ob;
    }
}



public class BoundedInterfaceBox {
    public static void main(String [] args) {
        Box3<Apple2> box = new Box3<>();
        box.set(new Apple2()); // 사과 저장

        Apple2 ap = box.get(); // 사과 꺼내기
        System.out.println(ap);
    }
}
//result
It's tastes so good
I am an apple.
  • class Box<T extends Number & Eatable> { … } : Number를 상속하면서 동시에 Eatable인터페이스를 구현하는 클래스만이 타입인자로 올 수 있게 동시에 제한을 할 수 있다.

제네릭 메소드의 정의

  • public static Box makeBox(T o) { ... }
  • 메소드의 이름은 makeBox이고 반환형은 Box이다.
  • static과 Box사이의 는 T가 타입 매개변수임을 알려준다.
package yoon;

class BoxFactory {
    public static <T> Box2<T> makeBox(T o) {
        Box2<T> box = new Box2<>();
        box.set(o);
        return box;
    }
}

public class GenericMethodBoxMaker {
    public static void main(String [] args) {
        Box2<String> sBox = BoxFactory.makeBox("Sweet");
        System.out.println(sBox.get());

        Box2<Double> dBox = BoxFactory.makeBox(7.59);
        System.out.println(dBox.get());
    }
}
//result
Sweet
7.59
Written on June 2, 2018