关于setAccessible方法的使用

  • Method和Field、Constructor对象都有setAccessible()方法。
  • setAccessible是启动和禁用访问安全检查的开关。
  • 参数值为true则指示反射的对象在使用时应该取消Java语言访问检查。

提高反射的效率。如果代码中必须用反射,而该句代码需要频繁的被调用,那么请设置为true。
使得原本无法访问的私有成员也可以访问

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

调用指定属性

方式一

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

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

方式二

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的属性内容

  1. /*
  2. 如何操作运行时类中的指定的属性 -- 需要掌握
  3. */
  4. @Test
  5. public void testField1() throws Exception {
  6. Class clazz = Person.class;
  7. //创建运行时类的对象
  8. Person p = (Person) clazz.newInstance();
  9. //1. getDeclaredField(String fieldName):获取运行时类中指定变量名的属性
  10. Field name = clazz.getDeclaredField("name");
  11. //2.保证当前属性是可访问的
  12. name.setAccessible(true);
  13. //3.获取、设置指定对象的此属性值
  14. name.set(p,"Tom");
  15. System.out.println(name.get(p));
  16. //3.获取、设置指定对象的静态属性值
  17. // name.set(Person.class,"男");
  18. //
  19. // System.out.println(name.get(p));
  20. }

调用指定方法

通过反射可以调用类中的方法,通过Method类完成。

步骤:

  • 通过Class类的getMethod(String name,Class…parameterTypes)方法取得一个Method对象,并设置此方法操作时所需要的参数类型。
  • 之后使用Object invoke(Object obj, Object[] args)进行调用,并向方法中传递要设置的obj对象的参数信息。

invoke(Object obj, Object[] args)的说明:

  • Object 对应原方法的返回值,若原方法无返回值,此时返回null
  • 若原方法若为静态方法,此时形参Object obj可为null
  • 若原方法形参列表为空,则Object[] args为null
  • 若原方法声明为private,则需要在调用此invoke()方法前,显式调用方法对象的setAccessible(true)方法,将可访问private的方法。

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

调用指定构造器

步骤如下:

  1. 通过Class类的getDeclaredConstructor(Class … parameterTypes)取得本类的指定形参类型的构造器
  2. 向构造器的形参中传递一个对象数组进去,里面包含了构造器中所需的各个参数。
  3. 通过Constructor实例化对象。
    ```java / 如何调用运行时类中的指定的构造器 / @Test public void testConstructor() throws Exception {

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

    }

}

```