2011-01-04 2 views
1

EDIT : 큰 차이를 만들어내는 데 놓친 또 다른 주름이 여기에 있습니다.이 인터페이스와 메소드에서 Java generics에 대한 잘못된 점은 무엇입니까?

<T extends Bar> T doAnotherThing(List<Foo<T>> foo) { 
    return foo.get(0).doSomething(); 
} 

무시 그냥 List가 제네릭 클래스/인터페이스는 사실에 주목하는 List 사실 : doAnotherThing의 메소드 서명은 다음 대신합니다. 그래서 같은 메서드를 호출하고 있습니다 :

abstract class Bar { 
    // some neat stuff 
} 

class BarImpl extends Bar { 
    // some cool stuff 
} 

interface Foo<T extends Bar> { 
    T doSomething(); 
} 

class FooImpl implements Foo<BarImpl> { 
    BarImpl doSomething() { 
     // Does something awesome 
    } 
} 

이 모든 벌금과 멋쟁이이고 잘 작동 :

doAnotherThing(new ArrayList<FooImpl>); 

그래서, 난과 같이 정의 된 클래스 및 인터페이스를 가지고있다.

는 지금, 나는 방법과 같이 있습니다

<T extends Bar> T doAnotherThing(List<Foo<T>> foo) { 
    return foo.get(0).doSomething(); 
} 

이 방법은 완전히 다른 클래스의 일반적인 방법이며, 상기와 같이 체인의 일부가 아닙니다. 그러나

, 나는 다음과 같은 방법으로이 방법을 사용하려고 할 때, 나는 유형이 일치하지 않다는 오류 받고 있어요 :

doAnotherThing(new FooImpl()); 

FooImplFoo<T>를 구현을, 그래서하지 않습니다 이것이 어떻게 오류인지 확인하십시오. 어쩌면 내가 뭔가를 오해하고있는 것일까 요? 감사합니다

+2

예제에서 BarImpl은 막대를 확장하지 않습니다. – AniDev

+2

그것은 나를 위해 작동합니다. 'BarImpl extends Bar'를 잊었다는 사실 외에도 – Bozho

+0

컴파일러 오류 메시지를 공유 할 수 있습니까? –

답변

3

대답은 실제로 완벽하게 올바른 질문

complilation 오류 (유형 불일치)의 설명을 반영하도록 변경. 메서드 정의는 매개 변수가 List<Foo<T>>이라고 말합니다. 즉, 목록에 이 포함될 수 있으며Foo<T>의 메서드는 을 추가 할 수도 있습니다. Foo<T>을 구현하는 모든 개체는입니다. 그리고 FooImpl 인스턴스 만 포함 할 수 있기 때문에 List<FooImpl>으로 지정하면 해당되지 않습니다. 이 작품 :

doAnotherThing(new ArrayList<Foo<BarImpl>>()); 

혼합 제네릭 및 다형성을 신속 매우 복잡한 시나리오에 리드, 그래서 드물게 수행해야합니다.

+0

Michael, 해결되어야합니다. 다시 질문을 참조하십시오. 감사. – Polaris878

+0

@ Polaris878 : 변경된 대답, 지금 생각합니다. –

1

BarImpl extends Bar라고 가정 해 봅시다. 처음부터 당신이 생각한 것 같습니다.

확대 된 Foo 인터페이스는 어떻게 보이나요?

interface Foo<T extends Bar> { 
    T doSomething(); 
    T doAnotherThing(Foo<T> foo); 
} 

:

가 있습니까?당신이 그렇지 않으면 정의 경우

class FooImpl implements Foo<BarImpl> { 

public BarImpl doSomething() { 
    return null; 
} 

public BarImpl doAnotherThing(Foo<BarImpl> foo) { 
    return null; 
} 

} 
이제

가, 문제가있을 수 있습니다 : 이러한 경우 모든 것을에서

은 다음 IMPL와 함께 작동

interface Foo<T extends Bar> { 
    T doSomething(); 
    <T extends Bar> T doAnotherThing(Foo<T> foo); 
} 

하는 방식의 때문에 doAnotherThing을 정의하면 다른 generics 매개 변수가 도입됩니다. 인터페이스의 매개 변수와 메소드에서 오는 매개 변수를 혼동시키는 것은 무엇입니까? 예 : T. public BarImpl doAnotherThing(Foo<BarImpl> foo)가의 최우선의 적절한 방법이 아닌 이유가 더 명확하게

interface Foo<T extends Bar> { 
    T doSomething(); 
    <Y extends Bar> Y doAnotherThing(Foo<Y> foo); 
} 

: 는

마지막 정의가 대체 될 수있다 (BTW, 나는 자바는 혼란 이름 충돌을 허용 배울 놀랐습니다) 이 방법.

+0

'doAnotherThing'은'Foo '의 일부가 아니며 다른 클래스 – Polaris878

+0

의 일부입니다. 내 대답은 맹목적인 추측이었다. –

2

저에게 맞습니다. 나는 그 오류를 일으키는 것이 무엇이든 의심 스럽지만, 당신이 위에 올라간 버전에서는 그렇지 않습니다. 아래의 코드 (모두 하나의 파일, FooBarBaz.java)가 컴파일됩니까? 코드를 수정해야하는 유일한 변경 사항은 FooImpl.doSomething()을 공개하는 것이 었습니다. (아, 뭔가를 반환하고. :))

public class FooBarBaz { 

    <T extends Bar> T doAnotherThing(Foo<T> foo) { 
     return foo.doSomething(); 
    } 

    public static void main(String[] args) { 
     new FooBarBaz().doAnotherThing(new FooImpl()); 
    } 
} 

abstract class Bar { 
    // some neat stuff 
} 

class BarImpl extends Bar { 
    // some cool stuff 
} 

interface Foo<T extends Bar> { 
    T doSomething(); 
} 

class FooImpl implements Foo<BarImpl> { 
    public BarImpl doSomething() { 
     return null; 
    } 
} 

작품의 벌금을 내게 IDEA 9, JDK 1.6 맥 OS 10.6.5에.

+0

정확합니다. 실제로 작동합니다. 그러나 나는 위에서 강조한 (주요) 세부 사항을 놓쳤다. – Polaris878

1

원본 답변이 잘못되었다고 생각합니다. 다음은 잘 작동하는 것 같습니다. 그냥 doSomething 메서드를 public으로 만들고 Java6에서 괜찮게 컴파일합니다.

abstract class Bar { 
    // some neat stuff 
} 

class BarImpl extends Bar { 
    // some cool stuff 
} 

interface Foo<T extends Bar> { 
    public T doSomething(); 
} 

class FooImpl implements Foo<BarImpl> { 
    public BarImpl doSomething() { 
     return null; 
    } 
} 


public class Test { 
<T extends Bar> T doAnotherThing(Foo<T> foo) { 
    return foo.doSomething(); 
} 

} 
관련 문제