Java 反射机制:(十二)调用运行时类中指定的结构

一、调用构造器

  1、调用运行时类中的指定的构造器

     ① 调用 getDeclaredConstructor() 方法根据参数获取指定的构造器

    ② 保证此构造器是可以访问的(暴力反射,针对非 public 修饰)

    ③ 调用 newInstance(Object obj, initargs) 方法创建对象

 1     @Test
 2     public void testConstructor() throws Exception {
 3         Class clazz = Person.class;
 4 
 5         //private Person(String name)
 6         /*
 7         1.获取指定的构造器
 8         getDeclaredConstructor():参数:指明构造器的参数列表
 9          */
10 
11         Constructor constructor = clazz.getDeclaredConstructor(String.class);
12 
13         //2.保证此构造器是可访问的
14         constructor.setAccessible(true);
15 
16         //3.调用此构造器创建运行时类的对象
17         Person per = (Person) constructor.newInstance("Tom");
18         System.out.println(per);
19 
20     }

  2、

二、调用属性

  1、调用指定属性

    在反射机制中,可以直接通过Field类操作类中的属性,通过Field类提供的set()get()方法就可以完成设置和取得属性内容的操作

public Field getField(String name) 返回此Class对象表示的类或接口的指定的public的Field。

public Field getDeclaredField(String name)返回此Class对象表示的类或接口的指定的Field。

      在 Field 中:

public Object get(Object obj) 取得指定对象obj上此Field的属性内容

public void set(Object obj,Object value) 设置指定对象obj上此Field的属性内容

  

  2、操作运行时类的指定的 public 的属性

    ① 获取运行时的类;

    ② 获取指定的属性:要求运行时类中属性声明为public

    ③ 设置、获取当前属性的值

 1      @Test
 2      public void testField() throws Exception {
 3         Class clazz = Person.class;
 4 
 5         //创建运行时类的对象
 6         Person p = (Person) clazz.newInstance();
 7 
 8 
 9         //获取指定的属性:要求运行时类中属性声明为public
10         //通常不采用此方法
11         Field id = clazz.getField("id");
12 
13         /*
14         设置当前属性的值
15 
16         set():参数1:指明设置哪个对象的属性   参数2:将此属性值设置为多少
17          */
18 
19         id.set(p,1001);
20 
21         /*
22         获取当前属性的值
23         get():参数1:获取哪个对象的当前属性值
24          */
25         int pId = (int) id.get(p);
26         System.out.println(pId);
27 
28 
29     }

  3、操作运行时类中的指定的非public修饰属性

    ① 获取运行时的类;

    ② 获取运行时类中指定变量名的属性;

    ③ 保证当前属性是可访问的(暴力反射,防止非 public 修饰的)

setAccessible(true):暴力反射          // 忽略访问权限修饰符的安全检查

    ④ 获取、设置指定对象的此属性值

 1     @Test
 2     public void testField2() throws Exception {
 3         Class clazz = Person.class;
 4 
 5         //创建运行时类的对象
 6         Person p = (Person) clazz.newInstance();
 7 
 8         //1. getDeclaredField(String fieldName):获取运行时类中指定变量名的属性
 9         Field name = clazz.getDeclaredField("name");
10 
11         //2.保证当前属性是可访问的
12         name.setAccessible(true); //暴力反射
13         //3.获取、设置指定对象的此属性值
14         name.set(p,"Tom");
15 
16         System.out.println(name.get(p));
17     }

三、调用方法

  1、操作运行时类中的指定的方法

    

Object invoke(Object obj, Object … args) 执行方法

     说明:

      ① Object 对应原方法的返回值,若原方法无返回值,此时返回null;

      ② 若原方法若为静态方法,此时形参Object obj可为null;

      ③ 若原方法形参列表为空,则Object[] argsnull;

      ④ 若原方法声明为private,则需要在调用此invoke()方法前,显式调用方法对象的setAccessible(true)方法,将可访问private的方法。

    操作步骤:

    ① 根据运行时类对象获取指定的某个方法

    ② 保证当前方法是可访问的(暴力反射,防止非 public 修饰)

    ③ 调用invoke() 方法

 1     @Test
 2     public void testMethod() throws Exception {
 3 
 4         Class clazz = Person.class;
 5 
 6         //创建运行时类的对象
 7         Person p = (Person) clazz.newInstance();
 8 
 9         /*
10         1.获取指定的某个方法
11         getDeclaredMethod():参数1 :指明获取的方法的名称  参数2:指明获取的方法的形参列表
12          */
13         Method show = clazz.getDeclaredMethod("show", String.class);
14         //2.保证当前方法是可访问的
15         show.setAccessible(true);
16 
17         /*
18         3. 调用方法的invoke():参数1:方法的调用者  参数2:给方法形参赋值的实参
19         invoke()的返回值即为对应类中调用的方法的返回值。
20          */
21         Object returnValue = show.invoke(p,"CHN"); //String nation = p.show("CHN");
22         System.out.println(returnValue);
23 
24         System.out.println("*************如何调用静态方法*****************");
25 
26         // private static void showDesc()
27 
28         Method showDesc = clazz.getDeclaredMethod("showDesc");
29         showDesc.setAccessible(true);
30         //如果调用的运行时类中的方法没有返回值,则此invoke()返回null
31         //Object returnVal = showDesc.invoke(null);
32         Object returnVal = showDesc.invoke(Person.class);
33         System.out.println(returnVal);//null
34 
35     }

  2、

 

四、关于 setAccessible 方法

  1、MethodFieldConstructor对象都有setAccessible()方法。

  2、setAccessible启动和禁用访问安全检查的开关。

  3、参数值为true则指示反射的对象在使用时应该取消Java语言访问检查。

    ① 提高反射的效率。 如果代码中必须用反射, 而该句代码需要频繁的被调用, 那么请设置为true

    ② 使得原本无法访问的私有成员也可以访问;

  4、参数值为 false 则指示反射的对象应该实施Java语言访问检查。

五、操作数组

  在java.lang.reflect包下还提供了一个Array类,Array对象可以代表所有的数组。程序可以通过使用Array类来动态的创建数组,操作数组元素等。

  Array 类提供了如下几个方法:

public static Object newInstance(Class<?> componentType, int... dimensions):创建一个具有指定的组件类型和维度的新数组
public static void setXxx(Object array,int index,xxx value):将array数组中[index]元素的值修改为value。
public static xxx getXxx(Object array,int index,xxx value):将array数组中[index]元素的值返回。

  此处的 Xxx 对应 8 种基本数据类型,如果该属性的类型是引用数据类型,则直接使用 set(object arr,int index, Object value)方法或get(Object array, int index) 方法。

  Demo:

 1 import java.lang.reflect.Array;
 2 
 3 public class TestArray {
 4     public static void main(String[] args) {
 5         Object arr = Array.newInstance(String.class, 5);
 6         Array.set(arr, 0, "Hello");
 7         Array.set(arr, 1, "World");
 8         System.out.println(Array.get(arr, 0));
 9         System.out.println(Array.get(arr, 1));
10         System.out.println(Array.get(arr, 2));
11     }
12 }

五、案例

  需求:写一个"框架",不能改变该类的任何代码的前提下,可以帮我们创建任意类的对象,并且执行其中任意方法

  实现步骤:

  实现技术
    ① 配置文件
    ② 反射
  实现步骤:
    ① 将需要创建的对象的全类名和需要执行的方法定义在配置文件中
    ② 在程序中加载读取配置文件
    ③ 使用反射技术来加载类文件进内存
    ④ 创建对象
    ⑤ 执行方法

   代码实现:

1 // 定义的配置文件 pro.properties
2 className=cn.java.domain.Student
3 methodName=sleep

  程序:

 1 // 框架类
 2 public class ReflectTest {
 3      public static void main(String[] args) throws Exception {
 4          //可以创建任意类的对象,可以执行任意方法
 5  
 6          /*
 7              前提:不能改变该类的任何代码。可以创建任意类的对象,可以执行任意方法
 8           */
 9  
10          //1.加载配置文件
11          //1.1创建Properties对象
12          Properties pro = new Properties();
13          //1.2加载配置文件,转换为一个集合
14          //1.2.1获取class目录下的配置文件
15          ClassLoader classLoader = ReflectTest.class.getClassLoader();
16          InputStream is = classLoader.getResourceAsStream("pro.properties");
17          pro.load(is);
18  
19          //2.获取配置文件中定义的数据
20          String className = pro.getProperty("className");
21          String methodName = pro.getProperty("methodName");
22  
23  
24          //3.加载该类进内存
25          Class cls = Class.forName(className);
26          //4.创建对象
27          Object obj = cls.newInstance();
28          //5.获取方法对象
29          Method method = cls.getMethod(methodName);
30          //6.执行方法
31          method.invoke(obj);
32  
33  
34      }
35 }
原文地址:https://www.cnblogs.com/niujifei/p/14902690.html