关于setAccessible方法的使用
- Method和Field、Constructor对象都有setAccessible()方法。
- setAccessible是启动和禁用访问安全检查的开关。
- 参数值为true则指示反射的对象在使用时应该取消Java语言访问检查。
提高反射的效率。如果代码中必须用反射,而该句代码需要频繁的被调用,那么请设置为true。
使得原本无法访问的私有成员也可以访问
- 参数值为false则指示反射的对象应该实施Java语言访问检查。
调用指定属性
方式一
在反射机制中,可以直接通过Field类操作类中的属性,通过Field类提供的set()和 get()方法就可以完成设置和取得属性内容的操作。
public void testField() throws Exception {
Class clazz = Person.class;
//创建运行时类的对象
Person p = (Person) clazz.newInstance();
//获取指定的属性:要求运行时类中属性声明为public
//通常不采用此方法
Field id = clazz.getField("id");
/*
设置当前属性的值
set():参数1:指明设置哪个对象的属性 参数2:将此属性值设置为多少
*/
id.set(p,1001);
/*
获取当前属性的值
get():参数1:获取哪个对象的当前属性值
*/
int pId = (int) id.get(p);
System.out.println(pId);
}
方式二
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的属性内容
/*
如何操作运行时类中的指定的属性 -- 需要掌握
*/
@Test
public void testField1() throws Exception {
Class clazz = Person.class;
//创建运行时类的对象
Person p = (Person) clazz.newInstance();
//1. getDeclaredField(String fieldName):获取运行时类中指定变量名的属性
Field name = clazz.getDeclaredField("name");
//2.保证当前属性是可访问的
name.setAccessible(true);
//3.获取、设置指定对象的此属性值
name.set(p,"Tom");
System.out.println(name.get(p));
//3.获取、设置指定对象的静态属性值
// name.set(Person.class,"男");
//
// System.out.println(name.get(p));
}
调用指定方法
通过反射可以调用类中的方法,通过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的方法。
/*
如何操作运行时类中的指定的方法 -- 需要掌握
*/
@Test
public void testMethod() throws Exception {
Class clazz = Person.class;
//创建运行时类的对象
Person p = (Person) clazz.newInstance();
/*
1.获取指定的某个方法
getDeclaredMethod():参数1 :指明获取的方法的名称 参数2:指明获取的方法的形参列表
*/
Method show = clazz.getDeclaredMethod("show", String.class);
//2.保证当前方法是可访问的
show.setAccessible(true);
/*
3. 调用方法的invoke():参数1:方法的调用者(那个对象调用的) 参数2:给方法形参赋值的实参
invoke()的返回值即为对应类中调用的方法的返回值。
*/
Object returnValue = show.invoke(p,"CHN"); //String nation = p.show("CHN");
System.out.println(returnValue);
System.out.println("*************如何调用静态方法*****************");
// private static void showDesc()
Method showDesc = clazz.getDeclaredMethod("showDesc");
showDesc.setAccessible(true);
//如果调用的运行时类中的方法没有返回值,则此invoke()返回null
// Object returnVal = showDesc.invoke(null);
Object returnVal = showDesc.invoke(Person.class);
System.out.println(returnVal);//null
}
调用指定构造器
步骤如下:
- 通过Class类的
getDeclaredConstructor(Class … parameterTypes)
取得本类的指定形参类型的构造器 - 向构造器的形参中传递一个对象数组进去,里面包含了构造器中所需的各个参数。
通过Constructor实例化对象。
```java / 如何调用运行时类中的指定的构造器 / @Test public void testConstructor() throws Exception {Class clazz = Person.class;
//private Person(String name)
/*
1.获取指定的构造器
getDeclaredConstructor():参数:指明构造器的参数列表
*/
Constructor constructor = clazz.getDeclaredConstructor(String.class);
//2.保证此构造器是可访问的
constructor.setAccessible(true);
//3.调用此构造器创建运行时类的对象
Person per = (Person) constructor.newInstance("Tom");
System.out.println(per);
}
}
```