arbeiten Das wird nie:
new MyService<clazz>()
wo clazz
ist eine Variable.
Die Typparameter in einem new
Aufruf können nur ein anderer Typparameter der umschließenden Methode oder Klasse sein (wenn die umschließende Methode nicht statisch ist) oder ein konkreter Klassenname.
Typparameter sind Entitäten, die sich nur auf die Kompilierungszeit auswirken, eingeführt werden, um den Typ des Parameters einzuschränken und Werte in generischen Klassen und Methoden zurückzugeben, und zum Kompilierungszeitpunkt fehlschlagen, wenn der Code möglicherweise den falschen Wert übergibt Laufzeit eingeben.
Der Wert von clazz
kann nur zur Laufzeit ermittelt werden, daher kann der Compiler nicht herausfinden, was die tatsächliche Klasse zur Kompilierungszeit ist. Aus diesem Grund ist dies weder legal noch macht es Sinn, Klassenreferenz zu verwenden, die Variablen als Typparameter enthält.
Die Wahrheit ist, dass es ziemlich unmöglich ist, zu beschränken, was die zugrunde liegenden Typ-Parameter MyService Instanz zurückgegeben wird und MyService<? extends MyAbstractClass>
ist so gut zurückzukehren, wie es nur geht.
Am allerwenigsten können Sie sicher, dass Ihre clazz
in der Tat erstreckt MyAbstractService anstatt einfach blind glauben, dass der Fall ist:
class ServiceClass {}
class MyService<T extends ServiceClass> {}
class Main {
public MyService<? extends ServiceClass> getMyService() throws Exception {
final String className = "com.my.project." + ConfigUtils.get(env, "mypackage");
@SuppressWarnings("unchecked")
final Class<? extends ServiceClass> clazz = (Class<? extends ServiceClass>) Class.forName(className);
if (!ServiceClass.class.isAssignableFrom(clazz))
throw new RuntimeException("bad configuration blah blah");
return new MyService<ServiceClass>();
}
}
Beachten Sie, dass new MyService<ServiceClass>()
nicht sehr ordentlich aussehen, als in der Tat clazz
wird in der Regel etwas anderes sein; ein Nachkomme von ServiceClass aber nicht ServiceClass selbst ...Der Grund dafür, dass dies ohne Fehler kompiliert wird, ist die Tatsache, dass es bei dem bisherigen Code irrelevant ist, welchen Typ-Parameter Sie zurückgeben, da sie in der Laufzeit alle in denselben Code übersetzt werden.
In einem komplexeren Kontext jedoch, wenn Sie einige Operationen mit Objekten ausführen möchten, die sich auf den gleichen Typparameter beziehen, stoßen Sie auf Probleme bei der Kompilierung. So ist immer ratsam, eine saubere Art-Parameter-basierte Lösung von dem zur Verwendung von On-Set:
class ServiceClass {}
class MyService<T extends ServiceClass> {}
class Main {
public <S extends ServiceClass> MyService<S> getMyService() throws Exception {
final String className = "com.my.project." + ConfigUtils.get(env, "mypackage");
@SuppressWarnings("unchecked")
final Class<S> clazz = (Class<S>) Class.forName(className);
if (!ServiceClass.class.isAssignableFrom(clazz))
throw new RuntimeException("bad configuration blah blah");
return new MyService<S>();
}
}
Jetzt denke ich, es ziemlich seltsam ist, dass man nicht einen Verweis auf die Serviceklasse halten müßte irgendwo in MyService ... vielleicht würden Sie schließlich brauchen so etwas wie die folgenden Code:
class ServiceClass {}
class MyService<S extends ServiceClass> {
private final Class<S> clazz;
MyService(Class<S> clazz) {
this.clazz = clazz;
}
Class<S> serviceClass() {
return clazz;
}
}
class Main {
public <S extends ServiceClass> MyService<S> getMyService() throws Exception {
final String className = "com.my.project." + ConfigUtils.get(env, "mypackage");
@SuppressWarnings("unchecked")
final Class<S> clazz = (Class<S>) Class.forName(className);
if (!ServiceClass.class.isAssignableFrom(clazz))
throw new RuntimeException("bad configuration blah blah");
return new MyService<S>(clazz);
}
}
an diesem Punkt der Typ-Parameter S
in getMyService
beginnt Art notwendig.
Durch die Art und Weise, da Java 7 (glaube ich) Sie nicht die S
in der neuen Anweisung angeben müssen, die vom Compiler abgeleitet werden:
return new MyService<>(clazz);
Sind Sie bequem mit der Idee, dass MyService und MyService sind zur Laufzeit nicht unterscheidbar? –
@OliverCharlesworth Ja, das bin ich, aber es ist eine Beschwerde, der ich ständig mit Java begegne, also lehnt es ein Teil von mir ab und zu ab, es zu akzeptieren. Ich versuche, alles nett und ordentlich zu machen, also muss ich nur die MyAbstractClass erweitern, ohne anderen Code oder unnötige Bedingungen hinzuzufügen. –
Eine Möglichkeit, darüber nachzudenken, ist zu überlegen, ob der Platzhalter in diesem Kontext einen Vorteil gegenüber einfach MyService hat. –