2017-03-24 4 views
11

Ich möchte so etwas wie dies in Java erreichen, aber immer kompilieren Zeitfehler:mit abstrakten Klasse Methode

The method onMessage(TextMessage, Class) in the type AbstractTestLoader is not applicable for the arguments (TextMessage, Class)

ich den Grund des Fehlers zu verstehen, aber ich fühle mich auch sollte es sein eine Möglichkeit, dies mit Casting zu erreichen oder auf andere Weise.

+0

Warum fühlst du * so? Vielleicht möchten Sie Ihr Verständnis des zugrunde liegenden Problems hinzufügen, um sicherzustellen, dass alle auf der gleichen Seite sind. Da wir uns beim Erkunden des Lösungsraums auf die Ursache einigen müssen. – GhostCat

+0

Hallo @GhostCat, ich habe bereits versucht, mein zugrunde liegendes Problem mit der Kommentarzeile zu erkunden 'Ich möchte diese Zeile so korrigieren, dass ich unten Methode mit der tatsächlichen Klasse von {T extends abstractEntity } aufrufen kann, auch Sie können Verweisen Sie auf die von mir gepostete Lösung, um eine bessere Lösung zu finden, wenn Sie antworten möchten. –

+0

Wird 'AbstractTestLoader' die direkte Superklasse? – glee8e

Antwort

4

Endlich, nach ein paar Versuchen bekomme ich einfach einfache und funktionierende Lösung, aber ich bin offen für andere beste Antworten, wenn möglich. Dank

public abstract class AbstractTestLoader<T extends AbstractEntity<T>> { 

    abstract Class<T> getEntityType(); 

    public void onMessage(TextMessage message) throws Exception { 
     onMessage(message, getEntityType()); 
    } 

    public void onMessage(TextMessage message, Class<T> clazz) throws Exception { 
     //here my original logic will go 
    } 
} 
2

Java implements generics via type erasure, was bedeutet, dass es nur ein Kompilierung-Konzept ist. Wenn das Programm läuft, gibt es keinen Unterschied zwischen AbstractTestLoader<Foo> und AbstractTestLoader<Bar>.

Es gibt einige Problemumgehungen, wie die, die Sie entdeckt haben, bei denen eine Klasse, die den Typ T zur Kompilierzeit kennt, einen tatsächlichen Klassentyp bereitstellen kann. Aber es gibt keine Möglichkeit, reine Generika zu verwenden, um zu ermitteln, was der generische Typ zur Laufzeit ist.

+0

Eigentlich gibt es einen Weg.Bitte beachte @ glee8es Antwort –

+0

@FedericoPeraltaSchaffner danke, dass du mich erwähnt hast, aber diese @ -Markierung löst keine Systembenachrichtigung aus, weil das nachstehende "s" das System glauben lässt, dass du jemanden namens "glee8e's" anrufst. nur eine nette Erinnerung :) – glee8e

+0

@FedericoPeraltaSchaffner: glee8e's Antwort ist eine gute und wird wahrscheinlich in vielen Fällen gut funktionieren. Ich glaube aber nicht, dass es meine Antwort ungültig macht: in meinen Augen ist es eine der Workarounds, die ich erwähnte, "wo eine Klasse, die den Typ von' T' zur Kompilierungszeit kennt, gemacht werden kann, um einen tatsächlichen Klassentyp bereitzustellen . " In Vishals Antwort geschieht dies über eine abstrakte Methode; Im Falle von Glee8e geschieht dies, indem die Verbrauchsklassen auf eine bestimmte Weise deklariert werden müssen. – StriplingWarrior

5

Es sollte beachtet werden, dass während Java Generic zur Laufzeit gelöscht wurde, es begrenzte Reflektionsapis gibt, um sie abzurufen, wenn sie in der Klassendatei vorhanden sind.

Hier ist eine schnelle Lösung mit dieser Annahme:

  1. AbstractTestLoader die direkte Superklasse ist.
  2. Unterklassen verwenden keinen Wildcardtyp, wenn eine Superklasse deklariert wird, z. Sub-Klassen wie diese class GenericLoader<T extends SubclassAbstractEntity<T>> extends AbstractTestLoader<T> existiert nicht. Hier

ist der Code:

public class AbstractTestLoader<T extends AbstractEntity<T>> { 

    private static final ClassValue<Class<?>> TYPE_PARAMETER_CACHE = new ClassValue<Class<?>>() { 
     @Override 
     protected Class<?> computeValue(Class<?> type) { 
      assert AbstractTestLoader.class.isAssignableFrom(type); 
      assert type.getSuperclass() == AbstractTestLoader.class; 
      Type genericSuperclass = type.getGenericSuperclass(); 
      assert genericSuperclass instanceof ParameterizedType; 
      Type entityType = ((ParameterizedType) genericSuperclass).getActualTypeArguments()[0]; 
      assert entityType instanceof Class<?>; 
      return (Class<?>) entityType; 
     } 
    }; 

    @SuppressWarnings("unchecked") 
    protected Class<T> getEntityType() { 
     return (Class<T>) TYPE_PARAMETER_CACHE.get(this.getClass()); 
    } 

    public void onMessage(Object message) throws Exception { 
     onMessage(message, getEntityType()); // getting compile time error here 
    } 

    public void onMessage(Object message, Class<T> clazz) throws Exception { 
     //here my original logic will go 
    } 
} 

Die getEntityType kann in Unterklassen außer Kraft gesetzt werden, in denen diese beiden Annahmen scheitern.

Verwandte Themen