Lernen: Java-Prinzip – Reflexionsmechanismus
1. Was ist Reflexion:
Das Konzept der Reflexion wurde erstmals 1982 von Smith vorgeschlagen. Es bedeutet hauptsächlich, dass das Programm auf sich selbst zugreifen, es erkennen und ändern kann Ein Zustand oder Verhalten der Fähigkeit. Die Einführung dieses Konzepts löste schnell Forschungen zur angewandten Reflektivität im Bereich der Informatik aus. Es wurde erstmals im Bereich des Programmiersprachendesigns eingesetzt und hat Ergebnisse in Lisp und objektorientiert erzielt. Darunter sind LEAD/LEAD++, OpenC++, MetaXa und OpenJava Sprachen, die auf dem Reflexionsmechanismus basieren. Neuerdings werden Reflexionsmechanismen auch auf Fenstersysteme, Betriebssysteme und Dateisysteme angewendet.
Reflexion an sich ist kein neues Konzept, obwohl die Informatik dem Konzept der Reflexion eine neue Bedeutung gegeben hat. In der Informatik bezeichnet Reflexion eine Klasse von Anwendungen, die selbstbeschreibend und selbstkontrollierend sind. Mit anderen Worten, diese Art von Anwendung verwendet einen bestimmten Mechanismus, um die Beschreibung (Selbstdarstellung) und Überwachung (Untersuchung) ihres eigenen Verhaltens zu realisieren, und kann den Status und die Ergebnisse des von der Anwendung beschriebenen Verhaltens basierend auf diesen anpassen oder ändern Status und Ergebnisse des eigenen Verhaltens.
2. Was ist Klassenreflexion in Java?
Reflexion ist eine der Funktionen der Java-Programmentwicklungssprache. Sie ermöglicht es dem laufenden Java-Programm, sich selbst zu überprüfen und zu überprüfen Bedienen Sie direkt die internen Eigenschaften und Methoden des Programms. Diese Fähigkeit von Java wird in praktischen Anwendungen kaum genutzt, in anderen Programmiersprachen ist diese Funktion jedoch überhaupt nicht vorhanden. Beispielsweise gibt es in Pascal, C oder C++ keine Möglichkeit, Informationen über Funktionsdefinitionen in einem Programm zu erhalten.
Reflection ist der Schlüssel dazu, dass Java als dynamische (oder quasi-dynamische) Sprache betrachtet wird. Sie ermöglicht es dem Programm, während der Ausführung über die Reflection-APIs die internen Informationen jeder Klasse mit einem bekannten Namen abzurufen, einschließlich Paket- und Typparametern , Superklasse, implementierte Schnittstellen und innere Klassen, äußere Klassen, Felder, Konstruktoren, Methoden, Modifikatoren und können während der Ausführung Instanzen generieren, Feldinhalte ändern oder Methoden aufrufen.
3. Notwendige Klassen für die Java-Klassenreflexion:
Für die Java-Klassenreflexion sind nicht viele Klassen erforderlich. Sie sind: Feld, Konstruktor, Methode, Klasse, Objekt. Nachfolgend werde ich eine kurze Beschreibung geben dieser Klassen.
Feldklasse: Bietet Informationen über die Eigenschaften einer Klasse oder Schnittstelle sowie den dynamischen Zugriff darauf. Das reflektierte Feld kann ein (statisches) Klassenattribut oder ein Instanzattribut sein. Ein einfaches Verständnis kann als eine Klasse angesehen werden, die die Attribute der reflektierenden Klasse kapselt.
Konstruktorklasse: Bietet Informationen über eine einzelne Konstruktormethode einer Klasse und den Zugriff darauf. Diese Klasse unterscheidet sich von der Field-Klasse. Die Field-Klasse kapselt die Eigenschaften der Reflection-Klasse, während die Constructor-Klasse die Konstruktionsmethode der Reflection-Klasse kapselt.
Methodenklasse: Stellt Informationen zu einer einzelnen Methode in einer Klasse oder Schnittstelle bereit. Die reflektierten Methoden können Klassenmethoden oder Instanzmethoden (einschließlich abstrakter Methoden) sein. Diese Klasse ist nicht schwer zu verstehen. Sie wird zum Kapseln von Reflexionsklassenmethoden verwendet.
Klasse: Instanzen von Klassen repräsentieren Klassen und Schnittstellen in einer laufenden Java-Anwendung. Eine Aufzählung ist eine Klasse und eine Annotation ist eine Schnittstelle. Jedes Array gehört zu einer Klasse, die einem Klassenobjekt zugeordnet ist, das von allen Arrays mit demselben Elementtyp und derselben Dimension gemeinsam genutzt wird.
Object-Klasse: Jede Klasse verwendet Object als Superklasse. Alle Objekte (einschließlich Arrays) implementieren die Methoden dieser Klasse.
4. Was kann Javas Reflexionsklasse?
Nachdem ich so viel oben gelesen habe, denke ich, dass Sie ungeduldig sind, also okay! Im Folgenden werden wir dies anhand einiger einfacher Beispiele veranschaulichen.
Lassen Sie uns zunächst einen Blick darauf werfen, was wir durch den Reflexionsmechanismus von Java erreichen können.
Lass uns zuerst eine Klasse schreiben:
Java-Code
java.awt.event.ActionListener; import java.awt.event.ActionEvent; class A extends Object implements ActionListener{ private int a = 3; public Integer b = new Integer(4); public A(){} public A(int id,String name){} public int abc(int id,String name){return 0;} public void actionPerformed(ActionEvent e){} }
Sie sind möglicherweise durch meine Klasse verwirrt, Sie können nicht sehen, was ich tun möchte, dann Don Schauen Sie sich diese Klasse nicht an. Sie wissen, dass sie eine Schnittstelle namens ActionListener, zwei Konstruktoren und zwei Methoden hat.
Als nächstes verwenden wir Klasse A als Reflexionsklasse, um einige Informationen in Klasse A zu überprüfen. Schauen wir uns zunächst die Attribute und Attributwerte in der Reflexionsklasse an.
Java-Code
import java.lang.reflect.*; class B{ public static void main(String args[]){ A r = new A(); Class temp = r.getClass(); try{ System.out.println("反射类中所有公有的属性"); Field[] fb =temp.getFields(); for(int j=0;j<fb.length;j++){ Class cl = fb[j].getType(); System.out.println("fb:"+cl); } System.out.println("反射类中所有的属性"); Field[] fa = temp.getDeclaredFields(); for(int j=0;j<fa.length;j++){ Class cl = fa[j].getType(); System.out.println("fa:"+cl); } System.out.println("反射类中私有属性的值"); Field f = temp.getDeclaredField("a"); f.setAccessible(true); Integer i = (Integer)f.get(r); System.out.println(i); }catch(Exception e){ e.printStackTrace(); } } }
这里用到了两个方法,getFields()、getDeclaredFields(),它们分别是用来获取反射类中所有公有属性和反射类中所有的属性的方法。另外还有getField(String)和getDeclaredField(String)方法都是用来过去反射类中指定的属性的方法,要注意的是getField方法只能取到反射类中公有的属性,而getDeclaredField方法都能取到。
这里还用到了Field
类的setAccessible方法,它是用来设置是否有权限访问反射类中的私有属性的,只有设置为true时才可以访问,默认为false。另外
Field类还有set(Object AttributeName,Object
value)方法,可以改变指定属性的值。
下面我们来看一下如何获取反射类中的构造方法
java 代码
import java.lang.reflect.*; public class SampleConstructor { public static void main(String[] args) { A r = new A(); printConstructors(r); } public static void printConstructors(A r) { Class c = r.getClass(); //获取指定类的类名 String className = c.getName(); try { //获取指定类的构造方法 Constructor[] theConstructors = c.getConstructors(); for(int i=0; i<theConstructors.length; i++) { //获取指定构造方法的参数的集合 Class[] parameterTypes = theConstructors[i].getParameterTypes(); System.out.print(className + "("); for(int j=0; j<parameterTypes.length; j++) System.out.print(parameterTypes[j].getName() + " "); System.out.println(")"); } }catch(Exception e) { e.printStackTrace(); } } }
这个例子很简单,只是用getConstructors()方法获取了反射类的构造方法的集合,并用Constructor类的getParameterTypes()获取该构造方法的参数。
下面我们再来获取一下反射类的父类(超类)和接口
java 代码
import java.io.*; import java.lang.reflect.*; public class SampleInterface { public static void main(String[] args) throws Exception { A raf = new A(); printInterfaceNames(raf); } public static void printInterfaceNames(Object o) { Class c = o.getClass(); //获取反射类的接口 Class[] theInterfaces = c.getInterfaces(); for(int i=0; i<theInterfaces.length; i++) System.out.println(theInterfaces[i].getName()); //获取反射类的父类(超类) Class theSuperclass = c.getSuperclass(); System.out.println(theSuperclass.getName()); } }
这个例子也很简单,只是用Class类的getInterfaces()方法获取反射类的所有接口,由于接口可以有多个,所以它返回一个
Class数组。用getSuperclass()方法来获取反射类的父类(超类),由于一个类只能继承自一个类,所以它返回一个Class对象。
下面我们来获取一下反射类的方法
java 代码
import java.lang.reflect.*; public class SampleMethod { public static void main(String[] args) { A p = new A(); printMethods(p); } public static void printMethods(Object o) { Class c = o.getClass(); String className = c.getName(); Method[] m = c.getMethods(); for(int i=0; i<m.length; i++) { //输出方法的返回类型 System.out.print(m[i].getReturnType().getName()); //输出方法名 System.out.print(" "+m[i].getName()+"("); //获取方法的参数 Class[] parameterTypes = m[i].getParameterTypes(); for(int j=0; j<parameterTypes.length; j++){ System.out.print(parameterTypes[j].getName()); if(parameterTypes.length>j+1){ System.out.print(","); } } System.out.println(")"); } } }
这个例子并不难,它只是获得了反射类的所有方法,包括继承自它父类的方法。然后获取方法的返回类型、方法名和方法参数。
接下来让我们回过头来想一想,我们获取了反射类的属性、构造方法、父类、接口和方法,可这些东西能帮我们做些什么呢!!
下面我写一个比较完整的小例子,来说明Java的反射类能做些什么吧!!
java 代码
import java.lang.reflect.Constructor; import java.lang.reflect.Method; public class LoadMethod { public Object Load(String cName,String MethodName,String[] type,String[] param){ Object retobj = null; try { //加载指定的Java类 Class cls = Class.forName(cName); //获取指定对象的实例 Constructor ct = cls.getConstructor(null); Object obj = ct.newInstance(null); //构建方法参数的数据类型 Class partypes[] = this.getMethodClass(type); //在指定类中获取指定的方法 Method meth = cls.getMethod(MethodName, partypes); //构建方法的参数值 Object arglist[] = this.getMethodObject(type,param); //调用指定的方法并获取返回值为Object类型 retobj= meth.invoke(obj, arglist); } catch (Throwable e) { System.err.println(e); } return retobj; } //获取参数类型Class[]的方法 public Class[] getMethodClass(String[] type){ Class[] cs = new Class[type.length]; for (int i = 0; i < cs.length; i++) { if(!type[i].trim().equals("")||type[i]!=null){ if(type[i].equals("int")||type[i].equals("Integer")){ cs[i]=Integer.TYPE; }else if(type[i].equals("float")||type[i].equals("Float")){ cs[i]=Float.TYPE; }else if(type[i].equals("double")||type[i].equals("Double")){ cs[i]=Double.TYPE; }else if(type[i].equals("boolean")||type[i].equals("Boolean")){ cs[i]=Boolean.TYPE; }else{ cs[i]=String.class; } } } return cs; } //获取参数Object[]的方法 public Object[] getMethodObject(String[] type,String[] param){ Object[] obj = new Object[param.length]; for (int i = 0; i < obj.length; i++) { if(!param[i].trim().equals("")||param[i]!=null){ if(type[i].equals("int")||type[i].equals("Integer")){ obj[i]= new Integer(param[i]); }else if(type[i].equals("float")||type[i].equals("Float")){ obj[i]= new Float(param[i]); }else if(type[i].equals("double")||type[i].equals("Double")){ obj[i]= new Double(param[i]); }else if(type[i].equals("boolean")||type[i].equals("Boolean")){ obj[i]=new Boolean(param[i]); }else{ obj[i] = param[i]; } } } return obj; } }
这是我在工作中写的一个实现Java在运行时加载指定的类,并调用指定方法的一个小例子。这里没有main方法,你可以自己写一个。
Load方法接收的五个参数分别是,Java的类名,方法名,参数的类型和参数的值。
结束语:
Java
语言反射提供一种动态链接程序组件的多功能方法。它允许程序创建和控制任何类的对象,无需提前硬编码目标类。这些特性使得反射特别适用于创建以非常普通的方式与对象协作的库。Java
reflection 非常有用,它使类和数据结构能按名称动态检索相关信息,并允许在运行着的程序中操作这些信息。Java
的这一特性非常强大,并且是其它一些常用语言,如 C、C++、Fortran 或者 Pascal
等都不具备的。
但反射有两个缺点。第一个是性能问题。用于字段和方法接入时反射要远慢于直接代码。性能问题的程度取决于程序中是如何使用反射的。如果它作为程序运行中相对很少涉及的部分,缓慢的性能将不会是一个问题。即使测试中最坏情况下的计时图显示的反射操作只耗用几微秒。仅反射在性能关键的应用的核心逻辑中使用时性能问题才变得至关重要。