【JAVA反射机制】

一、Class类

Java.lang.Object

         |-java.lang.Class<T>

构造方法:无。

常用方法:

static Class<?>

forName(String className)
          返回与带有给定字符串名的类或接口相关联的 Class 对象。

Constructor<T>

getConstructor(Class<?>... parameterTypes)
          
返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。

Constructor<?>[]

getConstructors()
          
返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。

 Constructor<T>

getDeclaredConstructor(Class<?>... parameterTypes)
          
返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法。

 Constructor<?>[]

getDeclaredConstructors()
          
返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法。

 Field

getDeclaredField(String name)
          
返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。

 Field[]

getDeclaredFields()
          
返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。

 Method

getDeclaredMethod(String name, Class<?>... parameterTypes)
          
返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。

 Method[]

getDeclaredMethods()
          
返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。

 Field

getField(String name)
          
返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。

 Field[]

getFields()
          
返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。

 Method

getMethod(String name, Class<?>... parameterTypes)
          
返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。

 Method[]

getMethods()
          
返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。

 T

newInstance()
          
创建此 Class 对象所表示的类的一个新实例。

二、Constructor

Java.lang.Object

         |-java.lang.reflect.AccessibleObject

                   |-java.lang.reflect.Constructor<T>

  1. 构造方法:无。
  2. 常用方法:

 T

newInstance(Object... initargs)
          使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。

 String

toString()
          
返回描述此 Constructor 的字符串。

三、Field

Java.lang.Object

         |-java.lang.reflect.AccessibleObject

                   |-java.lang.reflect.Field

  1. 构造方法:无
  2. 常用方法:

 Object

get(Object obj)
          返回指定对象上此 Field 表示的字段的值。

 String

getName()
          
返回此 Field 对象表示的字段的名称。

 void

set(Object obj, Object value)
          
将指定对象变量上此 Field 对象表示的字段设置为指定的新值。

还有诸如getInt与setInt等操作基本数据类型的方法。

四、Method

Java.lang.Object

         |-java.lang.reflect.AccessibleObject

                   |-java.lang.reflect.Method

1.构造方法:无

2.常用方法:

 String

getName()
          以 String 形式返回此 Method 对象表示的方法名称。

 Class<?>

getReturnType()
          
返回一个 Class 对象,该对象描述了此 Method 对象所表示的方法的正式返回类型。

 Object

invoke(Object obj, Object... args)
          
对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。

 String

toString()
          
返回描述此 Method 的字符串。

五、暴力访问

使用方法:Constructor、Field、Method三个类均为AccessibleObject类的子类,AccessibleObject类中有一个方法用于暴力访问类中私有的、受保护的构造方法、成员变量、普通方法。

static void

setAccessible(AccessibleObject[] array, boolean flag)
          使用单一安全性检查(为了提高效率)为一组对象设置 accessible 标志的便捷方法。

 void

setAccessible(boolean flag)
          
将此对象的 accessible 标志设置为指示的布尔值。

前者为静态方法,用于为一组对象设置可访问标记的方法,后者为非静态方法,用于为特定的对象设置可访问标记的方法。

六、示例:    

 1 package p09.ReflectDemo.p01.Demo01;
 2 
 3 /**
 4  * @author kuangdaoyizhimei
 5  *
 6  */
 7 public class Person {
 8     //两个字段
 9     private int age;
10     private String name;
11     public String id;
12     //带参数构造方法
13     public Person(int age, String name) {
14         super();
15         this.age = age;
16         this.name = name;
17         System.out.println("Person(int age,String name)run");
18     }
19     //无参构造方法
20     public Person() {
21         super();
22         System.out.println("Person()run");
23     }
24     //公有无参数show方法
25     public void show()
26     {
27         System.out.println(name+"-----is show runnig---"+age);
28     }
29     //私有无参数method方法
30     private void method()
31     {
32         System.out.println("method is running");
33     }
34     //私有带参数set方法
35     private void set(int age,String name)
36     {
37         this.age=age;
38         this.name=name;
39         System.out.println("set function is run,name is "+name+" ,age is "+age);
40     }
41     //公有静态无参数go方法。
42     public static void go()
43     {
44         System.out.println("static go function is running!");
45     }
46 }
Person.java

该类封装了一些成员变量和方法。

 1 package p09.ReflectDemo.p01.Demo01;
 2 
 3 import java.lang.reflect.Constructor;
 4 import java.lang.reflect.InvocationTargetException;
 5 
 6 /**
 7  * 该类为测试拿到字节码文件中的构造方法。
 8  * @author kuangdaoyizhimei
 9  *
10  */
11 public class GetConstructorDemo {
12 
13     public static void main(String[] args) throws Exception {
14         getAllConstructors();
15         getNoneParameterConstructor();
16         getParameterConstructor();
17     }
18 
19     /**
20      * 使用带参数构造方法创建本类实例
21      * @throws InstantiationException
22      * @throws IllegalAccessException
23      * @throws IllegalArgumentException
24      * @throws InvocationTargetException
25      * @throws NoSuchMethodException
26      * @throws SecurityException
27      * @throws ClassNotFoundException
28      */
29     private static void getParameterConstructor() throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, ClassNotFoundException {
30         Class<?> clazz=Class.forName("p09.ReflectDemo.p01.Demo01.Person");
31         Constructor<?> con=clazz.getConstructor(int.class,String.class);
32         Object obj=con.newInstance(24,"张三");
33     }
34  
35     /**
36      * 使用无参构造方法创建本类的实例。
37      * @throws NoSuchMethodException
38      * @throws SecurityException
39      * @throws ClassNotFoundException
40      * @throws InstantiationException
41      * @throws IllegalAccessException
42      * @throws IllegalArgumentException
43      * @throws InvocationTargetException
44      */
45     private static void getNoneParameterConstructor() throws NoSuchMethodException, SecurityException, ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
46         Class clazz=Class.forName("p09.ReflectDemo.p01.Demo01.Person");
47         Constructor con=clazz.getConstructor();
48         Object obj=con.newInstance();
49     }
50 
51     /**
52      * 得到字节码文件中定义的所有构造方法
53      * @throws ClassNotFoundException
54      * @throws NoSuchMethodException
55      * @throws SecurityException
56      * @throws InstantiationException
57      * @throws IllegalAccessException
58      * @throws IllegalArgumentException
59      * @throws InvocationTargetException
60      */
61     private static void getAllConstructors() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
62         Class clazz=Class.forName("p09.ReflectDemo.p01.Demo01.Person");
63         Constructor arr[]=clazz.getConstructors();
64         for(Constructor con:arr)
65         {
66             System.out.println(con);
67         }
68     }
69 
70 }
GetConstructorDemo.java

该类用于演示怎样使用反射机制获取Person.java中的构造方法,并使用获取到的构造方法创建对象(但参数构造方法与不带参数构造方法)。

 1 package p09.ReflectDemo.p01.Demo01;
 2 
 3 import java.lang.reflect.Field;
 4 import java.lang.reflect.Method;
 5 
 6 /**
 7  * 该类用于拿到字节码文件中的字段。
 8  * @author kuangdaoyizhimei
 9  *
10  */
11 public class GetFieldsDemo {
12     public static void main(String args[]) throws Exception
13     {
14 //        getPublicFields();
15 //        getPublicSpecialField();
16 //        getPrivateSpecialField();
17     }
18     private static void getPrivateSpecialField() throws ClassNotFoundException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, InstantiationException {
19         Class clazz=Class.forName("p09.ReflectDemo.p01.Demo01.Person");
20 //        Field name=clazz.getField("name");
21         Field name=clazz.getDeclaredField("name");
22         name.setAccessible(true);//暴力访问
23         Object obj=clazz.newInstance();
24         name.set(obj, "张三");
25         System.out.println(name.get(obj));
26     }
27 
28     private static void getPublicSpecialField() throws ClassNotFoundException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, InstantiationException {
29         Class clazz=Class.forName("p09.ReflectDemo.p01.Demo01.Person");
30         Field field=clazz.getField("id");
31 //        System.out.println(field);
32         Object obj=clazz.newInstance();
33         field.set(obj, "12345");
34         System.out.println(field.get(obj));
35     }
36 
37     private static void getPublicFields() throws ClassNotFoundException {
38         Class clazz=Class.forName("p09.ReflectDemo.p01.Demo01.Person");
39         Field f[]=clazz.getDeclaredFields();//得到所有的字段
40 //        Field f[]=clazz.getFields();//得到公有的字段
41         for(Field field :f)
42         {
43             System.out.println(field);
44         }
45     }
46 }
GetFieldsDemo.java

该类用于演示怎样使用反射机制获取Person.java中的字段,并对字段赋值与获取。

 1 package p09.ReflectDemo.p01.Demo01;
 2 
 3 import java.lang.reflect.InvocationTargetException;
 4 import java.lang.reflect.Method;
 5 
 6 /**
 7  * 该类用于测试拿到字节码文件对象中的普通方法
 8  * @author kuangdaoyizhimei
 9  *
10  */
11 public class GetMethodsDemo {
12 
13     public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
14 //        showAllMethods();
15 //        getSpecialMethod();
16 //        getSpecialPrivateParameterMethod();
17         getPublicStaticMethod();
18     }
19 
20     private static void getPublicStaticMethod() throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {
21         Class clazz=Class.forName("p09.ReflectDemo.p01.Demo01.Person");
22         Method method=clazz.getMethod("go", null);
23         Object obj=clazz.newInstance();
24         method.invoke(obj, null);
25     }
26     private static void getSpecialPrivateParameterMethod() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
27         Class clazz=Class.forName("p09.ReflectDemo.p01.Demo01.Person");
28         Method method=clazz.getDeclaredMethod("set", int.class,String.class);
29         method.setAccessible(true);//暴力访问,如果不是私有方法,这里可以不使用该语句
30         Object obj=clazz.newInstance();
31         method.invoke(obj, 23,"张三");
32     }
33 
34     private static void getSpecialMethod() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
35         Class clazz=Class.forName("p09.ReflectDemo.p01.Demo01.Person");
36         Method method=clazz.getMethod("show",null);
37         Object obj=clazz.newInstance();
38         method.invoke(obj, null);
39     }
40 
41     private static void showAllMethods() throws ClassNotFoundException {
42         Class clazz=Class.forName("p09.ReflectDemo.p01.Demo01.Person");
43 //        Method methods[]=clazz.getMethods();//得到所有的公有方法,包括父类的
44         Method methods[]=clazz.getDeclaredMethods();//得到所有本类中的方法
45         for(Method method:methods)
46         {
47             System.out.println(method);
48         }
49     }
50 
51 }
GetMethodsDemo

该类用于演示怎样使用反射机制获取Person.java中的普通方法,并调用特定的方法(带参数方法与不带参数方法)。

七、实例:模拟电脑运行过程

 1 package p10.ReflectDemo.p02.Demo01;
 2 
 3 /**
 4  * 模拟主板
 5  * 
 6  * @author kuangdaoyizhimei
 7  * 
 8  */
 9 public class MainBoard {
10     public void run() {
11         System.out.println("主板已经通电,即将运行!");
12     }
13 
14     public void usePCI(PCI pci) {
15         if (pci != null) {
16             pci.open();
17             pci.close();
18         }
19     }
20 }
MainBoard.java

该类用于模拟主板对象。

 1 package p10.ReflectDemo.p02.Demo01;
 2 
 3 /**
 4  * 模拟接口PCI
 5  * @author kuangdaoyizhimei
 6  *
 7  */
 8 public interface PCI {
 9     public void open();
10     public void close();
11 }
PCI.java

该接口模拟PCI接口。

 1 package p10.ReflectDemo.p02.Demo01;
 2 
 3 import java.io.File;
 4 import java.io.FileInputStream;
 5 import java.util.Properties;
 6 
 7 /**
 8  * 模拟电脑运行
 9  * @author kuangdaoyizhimei
10  *
11  */
12 public class Entry {
13 
14     public static void main(String[] args) throws Exception {
15         MainBoard mb=new MainBoard();
16         mb.run();
17         
18         //这种扩展方法烂透了,应当使用反射技术来完成,可以大大提高扩展性
19 //        mb.usePCI(new SoundCard());
20         
21         File file=new File("pci.conf");
22         FileInputStream fis=new FileInputStream(file);
23         Properties pro=new Properties();
24         pro.load(fis);
25         if(pro.size()>=4)
26         for(int i=0;i<4;i++)
27         {
28             String pciname=pro.getProperty("pci"+(i+1));
29             if(pciname.equals(""))
30             continue;
31             Class<?> clazz=Class.forName(pciname);
32             PCI pci=(PCI)clazz.newInstance();
33             mb.usePCI(pci);
34         }
35         fis.close();
36     }
37 }
Entry.java

该类模拟电脑运行过程。

1 pci1=p10.ReflectDemo.p02.Demo01.SoundCard
2 pci2=
3 pci3=
4 pci4=
pci.conf

该配置文件用于模拟给主板插上扩展硬件,如声卡、显卡等,默认有声卡

运行结果为:

如果想要添加一个显卡,则只需要改变配置文件为:

1 pci1=p10.ReflectDemo.p02.Demo01.SoundCard
2 pci2=p10.ReflectDemo.p02.Demo01.DisplayCard
3 pci3=
4 pci4=
pci.conf

同时需要在p10.ReflectDemo.p02.Demo01包下创建DisplayCard.java文件,该类实现了PCI接口。

 1 package p10.ReflectDemo.p02.Demo01;
 2 
 3 public class DisplayCard implements PCI {
 4 
 5     @Override
 6     public void open() {
 7         System.out.println("显卡已经打开!");
 8     }
 9 
10     @Override
11     public void close() {
12         System.out.println("显卡已经关闭!");
13     }
14 
15 }
DisplayCard.java

这样,就可以将该显卡安装到了主板上,电脑运行时就可以正常使用该显卡了。

运行结果是:

八、总结。

接口+配置文件是软件开发中非常有用的开发方式,使用这种开发范式可以极大扩展软件功能而不需要修改源代码。

原文地址:https://www.cnblogs.com/kuangdaoyizhimei/p/4241422.html