2016-03-19 19 views
2

Ich habe ein Problem mit einem generischen Framework, das ich schreibe. Kann mir jemand erklären, warum mein Code nicht kompiliert? Ich habe versucht, es mit diesem einfachen Beispiel zu zeigen. (AKTUALISIERT Beispiel)Java Generics nicht anwendbar für die Argumente Ausgabe

import java.lang.annotation.ElementType; 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 
import java.lang.annotation.Target; 
import java.lang.reflect.Field; 

public class TestGeneric { 

    public static void main(String... sss) throws Exception { 

     Dao dao = new Dao("Hello"); 
     dao.extend(); 

     System.out.println(dao.getHelloWorld()); 
    } 
} 

@Target(ElementType.FIELD) 
@Retention(RetentionPolicy.RUNTIME) 
@interface TestAnnotation { 

    public Class<? extends AbstractCommand<? extends AbstractDao>>[] commands() default {}; 
} 

abstract class AbstractDao { 

    public void extend() throws Exception { 

     for (Field field : this.getClass().getDeclaredFields()) { 

      if (field.isAnnotationPresent(TestAnnotation.class)) { 

       TestAnnotation annotation = field.getAnnotation(TestAnnotation.class); 

       for (Class<? extends AbstractCommand<? extends AbstractDao>> commandClass : annotation.commands()) { 

        AbstractCommand<? extends AbstractDao> command = commandClass.newInstance(); 
        command.doSomething(this); 
       } 
      } 
     } 
    } 
} 

class Dao extends AbstractDao { 

    @TestAnnotation(commands = { Command.class }) 
    private String hello; 

    private String world; 

    public Dao(String hello) { 
     this.hello = hello; 
    } 

    public String getHello() { 
     return this.hello; 
    } 

    public void setWorld(String world) { 
     this.world = world; 
    } 

    public String getHelloWorld() { 
     return this.hello + " " + this.world; 
    } 
} 

abstract class AbstractCommand<T extends AbstractDao> { 
    public abstract void doSomething(T t); 
} 

class Command extends AbstractCommand<Dao> { 

    @Override 
    public void doSomething(Dao t) { 

     if (t.getHello().equals("Hello")) { 
      t.setWorld("World"); 
     } 
    } 
} 

Sobald ich folgende Änderungen vornehmen ...

abstract class AbstractCommand<T extends AbstractDao> { 
    public abstract void print(AbstractDao t); 
} 

class Command extends AbstractCommand<Dao> { 

    @Override 
    public void doSomething(AbstractDao t) { 

     Dao dao = (Dao) t; 

     if (dao.getHello().equals("Hello")) { 
      dao.setWorld("World"); 
     } 
    } 
} 

... alles funktioniert gut, aber dann muss ich AbstractDao die ganze Zeit werfen.

Soweit ich sagen kann, sollte alles sicher sein, aber ich bekomme diesen Fehler immer wieder.

Die Methode print (capture # 3-of? Erweitert AbstractDao) in der Art AbstractCommand nicht anwendbar für die Argumente ist (Dao)

Aber Dao erstreckt AbstractDao, also wo genau ist das Problem?

Ich habe diese Frage bereits gefunden generics error: not applicable for the arguments, aber ich bin mir nicht sicher, ob es das gleiche Problem ist, das ich habe.

Meine Vermutung ist, dass es etwas mit ‚Because the Java compiler erases all type parameters in generic code, you cannot verify which parameterized type for a generic type is being used at runtime

Hat jemand eine Lösung für dieses Problem zu tun?

Danke!

+5

Was möchten Sie tun? 'AbstractCommand 'bedeutet, dass es ein' AbstractCommand' von ** irgendeinem ** unbekannten Typ ist, der 'AbstractDao' erweitert. Das könnte oder könnte nicht 'Dao' sein, der Compiler kann es nicht wissen. – Tunaki

+0

Mögliches Duplikat http://stackoverflow.com/q/2723397/2891664. "AbstractCommand" ist ein Verbraucher, kein Produzent. – Radiodef

+0

Ich habe mein Beispiel aktualisiert, um es klarer zu machen, was ich versuche zu erreichen. Gibt es eine Möglichkeit, wie Dao AbstractDao nicht erweitern kann? – BenGe89

Antwort

3

Sie verwenden eine AbstractCommand Referenz.

Versuchen Sie, diese

((Command)command).print(new Dao("Hello World")); 
+0

Ich weiß nicht, ob es eine Instanz von Command oder von etwas anderem ist, das den AbstractCommand verlängert, wenn ich die Methode anrufe. – BenGe89

+0

@ BenGe89 In diesem Fall kennen Sie seinen Befehl, da Sie 'Command.class' verwenden. –

+0

@ BenGe89 Versuchen Sie stattdessen' Command command = clazz.newInstance(); 'zu schreiben. Dann tritt der Typenkonfliktfehler an diesem Punkt auf und kann aufschlussreicher sein. Sie wissen, dass es sich um einen "Befehl" handelt, aber der statische Typ von "clazz" ist "AbstractCommand", so dass eine Instanziierung einen Downcast erfordern würde. –