Heim >Java >javaLernprogramm >Ausführliche Erläuterung des Java-Reflexionsmechanismus

Ausführliche Erläuterung des Java-Reflexionsmechanismus

巴扎黑
巴扎黑Original
2017-06-23 16:38:481287Durchsuche

1. Konzept

Reflection besteht darin, verschiedene Komponenten von Java in entsprechende Java-Klassen abzubilden.

Die Konstruktionsmethode der Class-Klasse ist privat und wird von der JVM erstellt.

Reflection ist eine Funktion der Java-Sprache, die es dem Programm ermöglicht, während der Laufzeit Selbstprüfungen durchzuführen und interne Mitglieder zu betreiben (beachten Sie, dass es nicht kompiliert wird). Beispielsweise ermöglicht es einer Java-Klasse, alle ihre Mitgliedsvariablen und -methoden abzurufen und anzuzeigen. Diese Fähigkeit von Java wird in praktischen Anwendungen möglicherweise nicht häufig 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. (Von Sun)

JavaBean ist eine der praktischen Anwendungen der Reflexion, die es einigen Tools ermöglicht, Softwarekomponenten visuell zu bedienen. Diese Tools laden und erhalten die Eigenschaften von Java-Komponenten (Klassen) dynamisch durch Reflektion.

Reflection gibt es seit 1.2. Die nächsten drei großen Frameworks werden alle den Reflection-Mechanismus verwenden. Wenn es um die Klasse „Class“ geht, ist ihr Objekt kein Bytecode im Speicher. 

 Instanzen der Class-Klasse 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. Die grundlegenden Java-Typen (boolean, byte, char, short, int, long, float und double) und das Schlüsselwort void werden ebenfalls als Klassenobjekte dargestellt. Die Klasse hat keinen öffentlichen Konstruktor. Klassenobjekte werden automatisch von der Java Virtual Machine erstellt, wenn eine Klasse geladen wird und indem die Methode defineClass im Klassenlader aufgerufen wird.

1 Person p1 = new Person();
2 //下面的这三种方式都可以得到字节码
3 CLass c1 = Date.class();
4 p1.getClass(); 
5 //若存在则加载,否则新建,往往使用第三种,类的名字在写源程序时不需要知道,到运行时再传递过来
6 Class.forName("java.lang.String");

Der Bytecode von CLass.forName() wurde in die Java Virtual Machine geladen, um den Bytecode abzurufen. Der Bytecode wurde nicht in der Java Virtual Machine generiert und ist mit Klassen geladen Der Loader wird geladen und der geladene Bytecode wird in der virtuellen Maschine zwischengespeichert.

Betrachten Sie das folgende einfache Beispiel, um zu sehen, wie Reflexion funktioniert.

import java.lang.reflect.*;  

public class DumpMethods {  
   public static void main(String args[]) {  
      try {  
           Class c = Class.forName("java.util.Stack");  

           Method m[] = c.getDeclaredMethods();  
             
           for (int i = 0; i < m.length; i++)  
               System.out.println(m[i].toString());  
      }  
      catch (Throwable e){  
            System.err.println(e);  
      }  
   }  
}

1 public synchronized java.lang.Object java.util.Stack.pop() 
2 public java.lang.Object java.util.Stack.push(java.lang.Object) 
3 public boolean java.util.Stack.empty() 
4 public synchronized java.lang.Object java.util.Stack.peek() 
5 public synchronized int java.util.Stack.search(java.lang.Object)

 

Dies listet die Methoden der java.util.Stack-Klassennamen und auf ihre Qualifizierer und Rückgabetypen. Dieses Programm verwendet Class.forName, um die angegebene Klasse zu laden, und ruft dann getDeclaredMethods auf, um die Liste der in der Klasse definierten Methoden abzurufen. java.lang.reflect.Methods ist eine Klasse, die zur Beschreibung einer einzelnen Methode in einer Klasse verwendet wird.

Das folgende Beispiel verwendet das Class-Objekt, um den Klassennamen des Objekts anzuzeigen:

1 void printClassName(Object obj) {
2          System.out.println("The class of " + obj +
3                             " is " + obj.getClass().getName());
4      }

Sie können auch ein Klassenliteral verwenden (JLS Abschnitt 15.8.2). ), um das angegebene Klassenobjekt vom Typ (oder void) zu erhalten. Beispiel:

1 System.out.println("The name of class Foo is: "+Foo.class.getName());

Wenn keine Objektinstanz vorhanden ist, gibt es zwei Hauptmethoden.

//获得类类型的两种方式        
Class cls1 = Role.class;        
Class cls2 = Class.forName("yui.Role");

Beachten Sie, dass in der zweiten Methode der Parameter in forName der vollständige Klassenname (Paketname + Klassenname) sein muss und diese Methode Ausnahmen abfangen muss. Da Sie nun cls1 haben, können Sie eine Instanz der Role-Klasse erstellen. Die Verwendung der newInstance-Methode von Class entspricht dem Aufruf des Standardkonstruktors der Klasse.

1 Object o = cls1.newInstance(); 
2 //创建一个实例        
3 //Object o1 = new Role();   //与上面的方法等价

2. Häufig verwendete Methoden

1. isPrimitive (bestimmen Sie, ob es sich um einen Basistyp von Bytecode handelt)

public class TestReflect {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        String str = "abc";
        Class cls1 = str.getClass();
        Class cls2 = String.class;
        Class cls3 = null;//必须要加上null
        try {
            cls3 = Class.forName("java.lang.String");
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println(cls1==cls2);
        System.out.println(cls1==cls3);
        
        System.out.println(cls1.isPrimitive());
        System.out.println(int.class.isPrimitive());//判定指定的 Class 对象是否表示一个基本类型。
        System.out.println(int.class == Integer.class);
        System.out.println(int.class == Integer.TYPE);
        System.out.println(int[].class.isPrimitive());
        System.out.println(int[].class.isArray());
    }
}
/*
 * true
true
false
true
false
true
false
true

 */
*/

2.getConstructor und getConstructors()

In Java gibt es keine Reihenfolge der Konstruktionsmethoden und sie werden nach Typ und Anzahl der Parameter unterschieden.

1 public class TestReflect {
2     public static void main(String[] args) throws SecurityException, NoSuchMethodException {
3         // TODO Auto-generated method stub
4         String str = "abc";
5         
6         System.out.println(String.class.getConstructor(StringBuffer.class));
7     }
8 }

3. Die Field-Klasse repräsentiert eine Mitgliedsvariable in einer bestimmten Klasse.

 1 import java.lang.reflect.Field;
 2 public class TestReflect {
 3     public static void main(String[] args) throws SecurityException, NoSuchMethodException, NoSuchFieldException, IllegalArgumentException, Exception {
 4         ReflectPointer rp1 = new ReflectPointer(3,4);
 5         Field fieldx = rp1.getClass().getField("x");//必须是x或者y
 6         System.out.println(fieldx.get(rp1));
 7         
 8         /*
 9          * private的成员变量必须使用getDeclaredField,并setAccessible(true),否则看得到拿不到
10          */
11         Field fieldy = rp1.getClass().getDeclaredField("y");
12         fieldy.setAccessible(true);//暴力反射
13         System.out.println(fieldy.get(rp1));
14         
15     }
16 }
17 
18 class ReflectPointer {
19     
20     public int x = 0;
21     private int y = 0;
22     
23     public ReflectPointer(int x,int y) {//alt + shift +s相当于右键source
24         super();
25         // TODO Auto-generated constructor stub
26         this.x = x;
27         this.y = y;
28     }
29 }

 4.

3. Typische Beispiele

 1. Ändern Sie b in allen Elementvariablen vom Typ String in a.

 1 import java.lang.reflect.Field;
 2 public class TestReflect {
 3     public static void main(String[] args) throws SecurityException, NoSuchMethodException, NoSuchFieldException, IllegalArgumentException, Exception {
 4         ReflectPointer rp1 = new ReflectPointer(3,4);
 5         changeBtoA(rp1);
 6         System.out.println(rp1);
 7         
 8     }
 9     
10     private static void changeBtoA(Object obj) throws RuntimeException, Exception {
11         Field[] fields = obj.getClass().getFields();
12         
13         for(Field field : fields) {
14             //if(field.getType().equals(String.class))
15             //由于字节码只有一份,用equals语义不准确
16             if(field.getType()==String.class) {
17                 String oldValue = (String)field.get(obj);
18                 String newValue = oldValue.replace('b', 'a');
19                 field.set(obj,newValue);
20             }
21         }
22     }
23 }
24 
25 class ReflectPointer {
26     
27     private int x = 0;
28     public int y = 0;
29     public String str1 = "ball";
30     public String str2 = "basketball";
31     public String str3 = "itcat";
32     
33     public ReflectPointer(int x,int y) {//alt + shift +s相当于右键source
34         super();
35         // TODO Auto-generated constructor stub
36         this.x = x;
37         this.y = y;
38     }
39 
40     @Override
41     public String toString() {
42         return "ReflectPointer [str1=" + str1 + ", str2=" + str2 + ", str3="
43                 + str3 + "]";
44     }
45 }

 2. Schreiben Sie ein Programm, um die Hauptmethode in der Klasse basierend auf dem vom Benutzer bereitgestellten Klassennamen aufzurufen.

Warum Reflexion nutzen?

 1 import java.lang.reflect.Field;
 2 import java.lang.reflect.Method;
 3 
 4 public class TestReflect {
 5     public static void main(String[] args) throws SecurityException, NoSuchMethodException, NoSuchFieldException, IllegalArgumentException, Exception {
 6         String str = args[0];
 7         /*
 8          * 这样会数组角标越界,因为压根没有这个字符数组
 9          * 需要右键在run as-configurations-arguments里输入b.Inter(完整类名)
10          * 
11          */
12         Method m = Class.forName(str).getMethod("main",String[].class);
13         //下面这两种方式都可以,main方法需要一个参数
14         
15         m.invoke(null, new Object[]{new String[]{"111","222","333"}});
16         m.invoke(null, (Object)new String[]{"111","222","333"});//这个可以说明,数组也是Object
17         /*
18          * m.invoke(null, new String[]{"111","222","333"})
19          * 上面的不可以,因为java会自动拆包
20          */
21     }
22 }
23 
24 class Inter {
25     public static void main(String[] args) {
26         for(Object obj : args) {
27             System.out.println(obj);
28         }
29     }
30 }

 3. Instanz des Operators simulieren

class S {  
}   

public class IsInstance {  
   public static void main(String args[]) {  
      try {  
           Class cls = Class.forName("S");  
           boolean b1 = cls.isInstance(new Integer(37));  
           System.out.println(b1);  
           boolean b2 = cls.isInstance(new S());  
           System.out.println(b2);  
      }  
      catch (Throwable e) {  
           System.err.println(e);  
      }  
   }  
}

 

In diesem Beispiel wird ein S-Klassenobjekt erstellt der Klasse und prüft dann, ob ein Objekt eine Instanz von S ist. Integer(37) ist es nicht, aber new S() schon.

4. Methodenklasse

Stellt eine Methode in einer Klasse dar (kein Objekt).

 1 import java.lang.reflect.Field;
 2 import java.lang.reflect.Method;
 3 /*
 4  * 人在黑板上画圆,涉及三个对象,画圆需要圆心和半径,但是是私有的,画圆的方法
 5  * 分配给人不合适。
 6  * 
 7  * 司机踩刹车,司机只是给列车发出指令,刹车的动作还需要列车去完成。
 8  * 
 9  * 面试经常考面向对象的设计,比如人关门,人只是去推门。
10  * 
11  * 这就是专家模式:谁拥有数据,谁就是专家,方法就分配给谁
12  */
13 public class TestReflect {
14     public static void main(String[] args) throws SecurityException, NoSuchMethodException, NoSuchFieldException, IllegalArgumentException, Exception {
15         String str = "shfsfs";
16         //包开头是com表示是sun内部用的,java打头的才是用户的
17         Method mtCharAt = String.class.getMethod("charAt", int.class);
18         Object ch = mtCharAt.invoke(str,1);//若第一个参数是null,则肯定是静态方法
19         System.out.println(ch);
20         
21         System.out.println(mtCharAt.invoke(str, new Object[]{2}));//1.4语法
22         
23     }
24     
25 }

5. Array-Reflexion

Die Array-Toolklasse wird verwendet, um den Reflexionsvorgang des Arrays abzuschließen.

Der gleiche Typ und der gleiche Breitengrad haben den gleichen Bytecode.

int.class und Integer.class sind nicht derselbe Bytecode. Integer.TYPE, TYPE stellt den Bytecode der Basisklasse dar, der der Verpackungsklasse int.class==Integer.TYPE

entspricht
 1 import java.util.Arrays;
 2 
 3 /*
 4  * 从这个例子看出即便字节码相同但是对象也不一定相同,根本不是一回事
 5  * 
 6  */
 7 public class TestReflect {
 8     public static void main(String[] args) throws SecurityException, NoSuchMethodException, NoSuchFieldException, IllegalArgumentException, Exception {
 9         int[] a = new int[3];
10         int[] b = new int[]{4,5,5};//直接赋值后不可以指定长度,否则CE
11         int[][] c = new int[3][2];
12         String[] d = new String[]{"jjj","kkkk"};
13         System.out.println(a==b);//false
14         System.out.println(a.getClass()==b.getClass());//true
15         //System.out.println(a.getClass()==d.getClass());    //比较字节码a和cd也没法比
16         System.out.println(a.getClass());//输出class [I
17         System.out.println(a.getClass().getName());//输出[I,中括号表示数组,I表示整数
18         
19         System.out.println(a.getClass().getSuperclass());//输出class java.lang.Object
20         System.out.println(d.getClass().getSuperclass());//输出class java.lang.Object
21         
22         //由于父类都是Object,下面都是可以的
23         Object obj1 = a;//不可是Object[]
24         Object obj2 = b;
25         Object[] obj3 = c;//基本类型的一位数组只可以当做Object,非得还可以当做Object[]
26         Object obj4 = d;
27         
28         //注意asList处理int[]和String[]的区别
29         System.out.println(Arrays.asList(b));//1.4没有可变参数,使用的是数组,[[I@1bc4459]
30         System.out.println(Arrays.asList(d));//[jjj, kkkk]
31         
32     }
33 }

6. Fazit
Das Obige ist die einfache Verwendung des Reflexionsmechanismus. Offensichtlich müssen Freunde, die Spring studiert haben, verstehen, warum wir die angegebenen Methoden und Variablen über die Konfigurationsdatei erhalten können Wird durch Übergabe einer Zeichenfolge implementiert, genau wie Sie es benötigen. Wir erstellen es für Sie und verwenden Object, das die dynamischen Eigenschaften der Java-Sprache zeigt und die Abhängigkeit stark reduziert.

Achtung Studierende, die Java lernen! ! !
Wenn Sie während des Lernprozesses auf Probleme stoßen oder Lernressourcen erhalten möchten, können Sie gerne der Java-Lernaustauschgruppe beitreten: 159610322 Lassen Sie uns gemeinsam Java lernen!

Das obige ist der detaillierte Inhalt vonAusführliche Erläuterung des Java-Reflexionsmechanismus. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn