Die Nachteile der Reflexion sind wie folgt.
Es gibt hochentwickelte Anwendungen, die die Reflexion nutzen, wie z. B. Analysewerkzeuge und Frameworks für die Abhängigkeitsinjektion, aber sie entfernen sich von der Reflexion, wenn die Nachteile der Reflexion offensichtlich werden. Wenn Sie sich fragen, ob Sie Reflexion verwenden sollten, sollten Sie dies wahrscheinlich nicht tun.
Reflexion wird in sehr begrenzten Fällen verwendet.
Viele Programme, die eine Klasse verwenden müssen, die zur Kompilierungszeit nicht abgerufen werden kann, haben einen geeigneten Typ und eine geeignete Oberklasse als Typ, um die Klasse zur Kompilierungszeit zu setzen (Item64).
In diesem Fall erstellen wir Instanzen reflektierend und greifen über Schnittstellen und Oberklassen auf diese erstellten Instanzen zu.
Im folgenden Programm wird beispielsweise eine Instanz der durch das erste Argument angegebenen Unterklasse von `` Set <String>
`erstellt, und andere Befehlszeilenargumente werden in Set gepackt und standardmäßig ausgegeben.
Wenn HashSet als erstes Argument verwendet wird, wird es zufällig angezeigt. Wenn TreeSet als erstes Argument verwendet wird, wird es in alphabetischer Reihenfolge angezeigt.
package tryAny.effectiveJava;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.Set;
public class Reflection {
// Reflective instantiation with interface access
public static void main(String[] args) {
// Translate the class name into a Class object
Class<? extends Set<String>> cl = null;
try {
cl = (Class<? extends Set<String>>) // Unchecked cast!
Class.forName(args[0]);
} catch (ClassNotFoundException e) {
fatalError("Class not found.");
}
// Get the constructor
Constructor<? extends Set<String>> cons = null;
try {
cons = cl.getDeclaredConstructor();
} catch (NoSuchMethodException e) {
fatalError("No parameterless constructor");
}
// Instantiate the set
Set<String> s = null;
try {
s = cons.newInstance();
} catch (IllegalAccessException e) {
fatalError("Constructor not accessible");
} catch (InstantiationException e) {
fatalError("Class not instantiable.");
} catch (InvocationTargetException e) {
fatalError("Constructor threw " + e.getCause());
} catch (ClassCastException e) {
fatalError("Class doesn't implement Set");
}
// Exercise the set
s.addAll(Arrays.asList(args).subList(1, args.length));
System.out.println(s);
}
private static void fatalError(String msg) {
System.err.println(msg);
System.exit(1);
}
}
Die oben verwendete Technik ist leistungsfähig genug, um in einem vollwertigen Service Provider-Framework (? Item1) verwendet zu werden. Diese Technik ist fast alles, was Sie zum Nachdenken benötigen.
Das Obige hat zwei Nachteile.
Im obigen Code gibt es beim Casting eine Warnung.
Diese Warnung ist gültig, da die Umwandlung in `` Class <? Extends Set <String >>
`erfolgreich ist, auch wenn der als erstes Argument verwendete Name nicht die Implementierungsklasse von Set ist.
Siehe Punkt 27 zur Unterdrückung von Warnungen.
Ein sehr seltener Fall der Verwendung von Reflection ist die dynamische Verwendung mehrerer Versionen eines Pakets. Kompilieren Sie die älteste Version und rufen Sie die Methode der neuen Klasse dynamisch auf. (Es kommt überhaupt nicht)
Recommended Posts