2016-03-29 5 views
1

Ich versuche, Generika in Java zu verstehen, und dieses einfache Beispiel versuchen, aber es kann nicht funktionieren; es kommt mit Fehler zurückJava-Generics, Methode base() ist nicht definiert für den Typ T

Exception in thread "main" java.lang.Error: Unresolved compilation problem: The method base() is undefined for the type T at javaTest.Main.testShape(Main.java:21) at javaTest.Main.main(Main.java:25)

Unten ist der Code

class Shape{ 
    int id=1; 
    void base(){ 
     System.out.println("Shape.base()"); 
    } 
} 

// unrelated class, but same func name 
class OtherShape{ 
    float id=1.1f; 
    void base(){ 
     System.out.println("OtherShape.base()"); 
    } 
} 

public class Main { 

    static <T>void testShape(T shape){ 
     shape.base(); 
    } 

    public static void main(String[] args) {   
     testShape(new Shape()); 
     testShape(new OtherShape());   
    } 
} 

eine Idee, wie ich es Arbeit machen?

+0

@Dijkgraaf: der ersten Zeile in gleichem Code oben: Exception in thread "main" java.lang.Error: Ungelöste compilation Problem: Verfahren base() ist nicht definiert für den Typ T bei javaTest.Main.testShape (Main.java:21) bei javaTest.Main.main (Main.java:25) – user57754

Antwort

7

In Java werden Generika ohne externen Kontext kompiliert, daher muss der Code gültig sein, ohne zu wissen, wie er am Ende aufgerufen wird.

etwas Deklarieren <T> bedeutet, dass Sie etwas passieren kann, das Objekt ist, so bedeutet T var, dass bei der Kompilierung var soll nur java.lang.Object sein. Daher macht var.base() keinen Sinn, da java.lang.Object keine Methode namens base() bietet.

Man kann sagen, dass T mindestens Shape zum Beispiel ist <T extends Shape>, indem er erklärt, dann können Sie alles passieren, die von Shape erbt. Ihr zweites Beispiel funktioniert jedoch immer noch nicht, da OtherShape nicht von Shape erbt, d. H. Es erfüllt nicht die Bedingung <T extends Shape>.

es zu beheben völlig es soll wie folgt aussehen:

class Shape{ 
    int id=1; 
    void base(){ 
     System.out.println("Shape.base()"); 
    } 
} 

// unrelated class, but same func name 
class OtherShape extends Shape{ 
    float id=1.1f; 
    @Override 
    void base(){ 
     System.out.println("OtherShape.base()"); 
    } 
} 

public class Main { 

    static <T extends Shape> void testShape(T shape){ 
     shape.base(); 
    } 
    ... 
} 

Ein Schritt nach vorn wäre Shape eine Schnittstelle zu bilden und schafft vielmehr jede Form Klasse (TriangleShape, OtherShape, ...), die eine Schnittstelle zu implementieren.

Hinweis trotzdem, dass Sie in Ihrem Beispiel nicht wirklich Generika erfordern, sind sie sehr nützlich, wenn Sie auf die gleiche Art zum Beispiel später, wie verweisen müssen sie wieder aus dem Verfahren zurückkehrt:

static <T extends Shape> T testShape(T shape){ 
     shape.base(); 
     return shape; 
    } 

Im obigen Beispiel können Sie das Ergebnis einer solchen Methode immer noch dem gleichen Typ zuordnen, den Sie im Parameter übergeben haben, da Parametertyp und Rückgabetyp identisch sind (T).

1

Ich glaube, Sie bekommen dieses Problem, weil Sie T auf keinen Objekttyp anwenden. Versuchen Sie es so.

class Shape{ 
    int id=1; 
    void base(){ 
     System.out.println("Shape.base()"); 
    } 
} 

// unrelated class, but same func name 
class OtherShape extends Shape{ 
    float id=1.1f; 
    void base(){ 
     System.out.println("OtherShape.base()"); 
    } 
} 

public class Test { 

    static void testShape(Shape shape){ 
     shape.base(); 
    } 

    public static void main(String[] args) {   
     testShape(new Shape()); 
     testShape(new OtherShape());   
    } 
} 
0

Es gibt keine Möglichkeit, dies nur zu tun, wenn Sie dieselbe Schnittstelle für die Klassen implementieren.

interface S { 
    void base(); 
} 

static void testShape(S shape){ 
    shape.base(); 
} 
1

Die tatsächliche Fehlermeldung Sie bekommen ist:

The method base() is undefined for the type T 

Und das ist genau das Problem: Ihre Methode entwickelt, ist auf eine Art arbeiten T und Sie haben gesagt, dass T sein buchstäblich jeden Objekttyp. Da TString oder Number oder ein anderes zufälliges Objekt sein kann, das jemand anderes erstellt hat, können Sie nicht davon ausgehen, dass es bestimmte Methoden für das Objekt haben wird.Daher ist das Verfahren base()undefined für den Typ T, da T nicht unbedingt ein Typ ist, der eine base() Methode hat. Ist das sinnvoll?

Wenn das, was Sie wollen auf jede Art zu arbeiten, die eine base() Methode hat, das ist ein Ding namens structural typing die Java leider nicht unterstützt. (Java-Typsystem ist nominative statt.)

Die nächste beste Sache ist, eine Schnittstelle zu definieren Ihre base() Methode zu halten, und implementieren diese Schnittstelle in beiden Klassen:

interface ShapeInterface { 
    void base(); 
} 

class Shape implements ShapeInterface { 
    ... 
} 

class OtherShape implements ShapeInterface { 
    ... 
} 

Aber dann Sie nicht mehr benötigen parametrischer Polymorphismus (das heißt, Generika), da Sie nur alte verwenden können subtype polymorphism statt: seit Shape und OtherShape sowohl ein unterstützen ist-eine Beziehung mit ShapeInterface, Ihren testShape Verfahren können nur ein ShapeInterface akzeptieren und mit ihm interagieren direkt:

static void testShape(ShapeInterface shape) { 
    shape.base(); 
} 
Verwandte Themen