2012-02-22 2 views
8

은 (명확성을 위해 하지 일반적인 클래스) 클래스 Foo에 대해 다음 생성자를 고려일반 생성자의 사용 사례는 무엇입니까?

public <T> Foo(T obj) { } 

이 그냥 일반 generic methods와 같은 생성자에 대한 올바른 구문입니다.

하지만이 구문의 사용법은 무엇입니까? 일반적으로 제네릭 메서드는 반환 형식에 대해 형식 안정성을 제공하며 컴파일러에서 형식 유추를 활용할 수 있습니다. 예를 들면 :

Pair<String, Integer> stringInt = Pair.of("asfd", 1234); 

그러나 해당 유형의 매개 변수는 반환 형식에 영향을주지 않도록 생성자를 호출은 항상 그 선언 클래스의 인스턴스를 반환합니다. 위의 생성자는 그 erasure로 대체 할 수있다 : 물론 제네릭의

public Foo(Object obj) { } 

는 반환 형식에 안전한 형태에 대한뿐만 아니라입니다. 생성자는 전달되는 인수 (들)의 유형을 제한 할 수 있습니다 그러나, 위의 추론은 여전히 ​​제한된 유형의 매개 변수에 적용됩니다. 경계와

public <N extends Number> Foo(N number) { } 

public Foo(Number number) { } //same thing 

심지어 중첩 된 형식 매개 변수는 와일드 카드를 사용하여 처리됩니다

public <N extends Number, L extends List<N>> Foo(L numList) { } 

public Foo(List<? extends Number> numList) { } //same thing 

그렇다면 일반적인 생성자를 사용하기위한 합법적 인 사용 사례는 무엇입니까?

답변

6

기능 프로그래밍에서 채택 된 가능한 방법은 다음과 같습니다.을 반환 할 때까지 반복적으로 새로운 요소를 생성하는 내부 상태가있는 Stream 유형이 있다고 가정합니다. 외부 발신자가 스트림 형의 내부 상태 유형이 무엇인지 상관하지 않습니다, 그래서 당신은 내부 상태 유형이 무엇인지 알 필요받는없이

class Stream<E> { 
    <S> Stream(S initialState, StepFunction<E, S> stepFun) { 
    ... 
    } 
} 

같은 것을 얻을 수 있습니다.

+0

아하, 매우 흥미 롭다! +1 –

+0

+1, 이것은 훌륭한 예입니다. OP가 구체적으로 둘러싸인 유형이 일반 적이 지 않다고 말하기 때문에 약간은 속임수입니다. ('Stream '는 일반적인 것입니다.) –

+0

@JohnFeminella - 나는 단지 나의 구체적인 예제 인'Foo'가 일반적인 것이 아니며 단지 혼란을 피하기위한 것입니다. 나는 대답에 대한 제한으로 그것을 의미하지는 않았다. –

2

하나의 유스 케이스는 생성자 인수를 둘 이상의 유형으로 제한하려는 경우입니다.

난 내 머리 위로 떨어져 생각할 수
public <L extends List<? extends Number> & RandomAccess> Foo(L raNumList) { } 

... 

Foo f1 = new Foo(new ArrayList<Integer>()); 
Foo f2 = new Foo(new LinkedList<Integer>()); //compiler error 
+1

또는'Foo'가'Object'를 취한 사전 제네릭 코드와의 하위 호환성을 위해, 그러나 이제는 좀 더 특화된 것을 원합니다. '> Foo (T obj)'./정말이 모든 것이 일반적이라는 것을 확신하지 못합니다. –

5

한 가지는 당신이 경계가 성취되는 것을 보장 할 수 있다는 것입니다 : 만 일반 구문은 또한 RandomAccess 구현하는 ListNumber의의 복용 생성자를 선언 할 수 있습니다 여러 매개 변수에 걸쳐 같은 방식으로.

public <T> Foo (List<T> listA, List<T> listB) { 
    listA.addAll(listB); 
} 

사용하여 와일드 카드는 여기에 빠르게 꽤 불쾌한 될 것입니다 아마 당신은 어쨌든 원하는 일을하지 :

는 복사 대상 소스에서 목록은 분명히 바보 인위적인하지만 유효한 생성자를 가져 가라. 또한이를 허용하지 않는 것은 전적으로 임의의 제한 사항입니다. 그래서 그것은 언어 스펙이 허용하는 것은 나에게 의미가 있습니다.

+2

또는 body 내에'T'를 사용하십시오 : Foo (리스트 ts) {T t0 = ts.get (0); ts.set (0, ts.get (1)); ts.set (1, t0); }'. 좋아요, 설득력있는 예는 아닙니다. –

1

생성자 매개 변수에 특정 제약 조건을 적용 할 수 있습니다. 예 : 다음 코드는 InterfaceA와 InterfaceB 인터페이스를 구현하는 두 개의 매개 변수를 필요로합니다.

<T extends InterfaceA & InterfaceB > Foo(T t1, T t2) { 

} 
1

주된 용도는 유형 매개 변수가 여러 매개 변수 사이에서 충족되도록하는 것입니다. 다음은 올바른 순서로 조립 라인의 구성 요소의 무리를두고 예는 다음과 같습니다

public <T> AssemblyLine(T[] starting, List<T> components) { 
    T[] a = components.toArray(starting); 
    Arrays.sort(a); 
    this.conveyorBelt.add(a); 
} 

여기 <T>T[]List<T> 동일한 유형 T을 유지 보장, 그리고 (말), Integer[]List<string>.

+0

+1 일반 배열과 인스턴스 등을 전달해야하는 것을 잊어 버렸습니다. - 좋은 것 (나는 오타가 있다고 생각합니다. 이것은'components.toArray'이어야합니다) –

+0

고마워요! 나는 그것을 고쳤다. –

관련 문제