2017-03-13 7 views
3

Ich bin neu bei Generika und habe das folgende Problem festgestellt, als ich versuchte, sie in einem kleinen Programm zu verwenden, von dem ich versuchen werde, die notwendigen Informationen zu geben.Generische Typkonvertierung für Methodenargument nicht möglich, warum?

Ich werde versuchen, nur das Notwendige zu geben, aber wenn irgendetwas fehlt, lass es mich wissen und ich werde zur Verfügung stellen, was benötigt wird.

Das erste, was ist die folgende Schnittstelle:

1: public interface IPrice<T extends IPrice<T>> { 
2:  void setPriceToZero(); 
3:  T addPrice(T price); 
4:  T subtractPrice(T price); 
5:  T multiplyPriceByFactor(int factor); 
6:  String priceToString(); 
7: } 

Es wird von einer Klasse BnSPrice umgesetzt wird; hier die wahrscheinlich notwendig ein Teil davon:

1: public class BnSPrice implements IPrice<BnSPrice> { 
2:  public BnSPrice subtractPrice(BnSPrice price) {...} 
2: } 

Jetzt ist der Teil, der nicht kompiliert werden und die ich nicht wirklich verstehen:

1: public static void main(String[] args){ 
2:  [...] 
3:  IPrice<? extends BnSPrice> test = new BnSPrice(5); 
4:  test.subtractPrice(new BnSPrice(5)); 
5:  [...] 
6: } 

Was ich bekommen ist

"Error:(27, 28) java: incompatible types: main.bnsCalculatorModel.BnSPrice >cannot be converted to capture#1 of ? extends >main.bnsCalculatorModel.BnSPrice"

in der Zeile wo ich die Subtract-Methode anrufe.

Warum passiert das und wie kann ich das korrigieren, damit ich noch auf die Schnittstelle programmieren kann?

(Mein Ziel ist, dass es einfach sein sollte mein Programm mit anderen „Arten von Preisen“ in der Zukunft. Zu verlängern)

+0

Zeilennummern bitte hinzufügen! Ist der Fehler in der Zeile 'IPrice test = new BnSPrice (5); – Pyranja

+0

Mögliches Duplikat von [Warum der generische Typ für das Argument nicht anwendbar ist, erweitert die Superklasse für beide?] (Http://stackoverflow.com/questions/21452966/why-generic-type-isnot-applicable-for-argument-extends -super-class-for-both) –

+0

Zeilennummern hinzugefügt; Fehler war in Codeblock 3 Zeile 4. Sweeper hat einen guten Job bei der Erklärung. – Wolfone

Antwort

6

Lassen Sie uns zunächst sehen, wie diese Arbeit zu machen:

IPrice<BnSPrice> test = new BnSPrice(5); 
test.subtractPrice(new BnSPrice(5)); 

Okay, also das Wildcard-? extends ... Werke zu entfernen. Warum?

Sie müssen das Konzept der generischen Platzhalter verstehen. <? extends BnPrice> bedeutet, dass dies ein beliebiger Typ sein kann, der eine Unterklasse von BnPrice ist. Im Moment haben Sie keine, aber lassen Sie uns eine erstellen, um meinen Standpunkt zu demonstrieren.

class MyPrice extends BnPrice {} 

Beachten Sie, dass MyPrice ein BnPrice Objekt in eine Variable vom Typ nicht zuordnen können.

Großartig! Jetzt haben wir unser test Objekt. Mal sehen, wie die subtractPrice in der Art definiert ist IPrice<? extends BnPrice>:

T subtractPrice(T price); 

Da Sie <? extends BnPrice>T schrieb jede Unterklasse von BnPrice sein kann, das heißt, es BnPrice oder MyPrice sein kann.Wenn TBnPrice ist, dann wäre dies kompilieren:

test.subtractPrice(new BnSPrice(5)); 

Sie eine BnPrice in eine Methode übergeben, die ein BnPrice erwartet. Alles gut. Aber, T muss nicht unbedingt BnPrice sein. Es kann auch MyPrice sein! Was wäre wenn es MyPrice wäre? Dann würde die obige Zeile nicht kompiliert, weil Sie keinen BnPrice an einen MyPrice Parameter übergeben können.

Da der Parameter ein beliebiger Typ sein kann, der BnPrice erweitert, können Sie kein BnPrice daran übergeben.

+0

Ok, das macht für mich einen gewissen Sinn; zumindest der Punkt, den Sie über den Compiler gemacht haben, ohne zu wissen, ob der Typ in Ihrem Beispiel ein MyPrice oder ein BnSPrice war; Es ist ein bisschen schwer zu begreifen, warum der Vertrag, den wir über die Schnittstelle gemacht haben, nicht ausreicht, aber ich habe eine vage Vorstellung, dass es nur in meinem speziellen Fall ausreichen würde, aber nicht allgemein; Es könnte sein, dass ich Methoden aufrufen möchte, die in einem Subtyp existieren, aber nicht in dem anderen. Denke ich in die richtige Richtung? Oh, eine Follow-up-Frage: Ist dein erster Codeblock die allgemeinste Version, die ich bekommen kann? – Wolfone

+0

@Wolfone Ich denke, du denkst in die richtige Richtung, und ja, soweit es mich betrifft, ist das praktisch die allgemeinste Version, die du bekommen kannst. – Sweeper

+0

Ok, perfekt; Danke für Ihre Hilfe! – Wolfone

0

Da die Art von Test IPrice<? extends BnSPrice> ist, so dass der erwartete Typ des Arguments von subtrahieren ist ? extends BnSPrice, nicht BnSPrice.

wird diese kompilieren:

BnSPrice test = new BnSPrice(5); 
test.subtractPrice(new BnSPrice(5)); 
Verwandte Themen