2017-08-14 3 views
3

Vorbereitung für OCPJP 6 Prüfung (deshalb verwende ich Java 1.6 Compiler) Ich habe etwas Unklares über Java Generics bemerkt. Betrachten Sie den folgenden Code ein:Java generischer Typparameter nicht innerhalb seiner Grenzen

class A<K extends Number> { 

    public <V> V useMe1(A<? super V> a) { // OK 
     return null; 
    } 

    public <V> V useMe2(A<? extends V> a) { // OK 
     return null; 
    } 

    public <V> V useMe3(A<V> a) { // ERROR, but why, since 2 above were ok 
     return null; 
    } 

} 

Wenn ich versuche, den Code (mit 1,6-Compiler) zu kompilieren, erhalte ich die Fehlermeldung:

type parameter V is not within its bound

Trotz Unbrauchbarkeit des Codes oben, ich frage mich, warum Compiler denken, dass die Typen <? super V> und <? extends V> die Klassengebundenheit übereinstimmen, aber <V> ist nicht (da V diese beiden Grenzen übereinstimmt).

Ich werde diesen Code nicht ändern, ich will es verstehen. Der Code wird von der Beispiel-OCPJP 6-Prüfungsfrage genommen, die fragt: "Welche Zeile wird kompiliert?"

+1

'useMe2' kompiliert nicht mit Java 8. – assylias

+0

Der zweite kompiliert nicht entweder: / –

Antwort

1

Die dritte, useMe3, schlägt fehl, da V nicht extend Number angesichts der fehlenden Grenzen auf seiner Erklärung <V> garantiert ist. Und da das Argument als A<V> deklariert ist, gibt es keine Scape, V muss Number erweitern und die Java-Sprache fordert den Programmierer auf, dies in diesem Fall explizit anzugeben.

Das ist in der Tat die einfache und vielleicht weniger offensichtlich, warum die anderen beiden funktionieren können. Durch die Verwendung von ? in ihrer Argumenttypdefinition geben Sie die Möglichkeit, dass diese mit extend Number kompatibel ist, selbst wenn V selbst ein Priorat ist, das nicht durch eine bestimmte Grenze in Bezug auf Number eingeschränkt ist.

Sie müssen feststellen, dass extend Number keinen Einfluss mehr auf V hat, aber ? was auch immer das ist. Ein anderer Weg, um es zu sagen, gibt es eine unbekannte Klasse, die durch diese ? dargestellt wird und muss extend Number und darüber hinaus für die Methode useMe1, zum Beispiel, es muss ein Super von V sein, wobei V durch den Code bestimmt werden würde, der das anruft Methode.

Dies ist vielleicht interessanter im Fall von useMe2, wo V effektiv alles sein könnte, was nichts mit Number zusammenhängt. ZB:

interface FooInterface { ... } 
class MyNumber extends Number implements FooInterface { ... } 

A<?> subject = ...; 
A<MyNumber> param = ...; 
FooInterface foo = subject.useMe2(param); 

Im useMe2 Aufruf oben V ist FooInterface, die nichts mit Number zu tun hat, und die ? in in diesem Fall MyNumber. MyNumber ist durch A type-Parameter beschränkt auf erweitert Number begrenzt und durch die Typ-Parameter-Definition des Arguments in useMe2 zu erweitern FooInterface aber V selbst ist völlig uneingeschränkt.

Verwandte Themen