反射之对象创建与属性操作
如何获取运行时类的完整结构
先获取一个类的Class类对象,再通过这个对象的方法来获取,可以获取的结构有Field,Method,Constructor等
方法如下:
获取类的名字
c1.getName(): 包名+类名
c1.getSimpleName(): 类名
获取类的属性
c1.getFields():只能找到public属性
c1.getDeclaredFields():获取全部属性,包括private
获取指定属性的值
c1.getField("name"):因为该属性被private修饰,所以无法获取会报错
c1.getDeclaredField("name")
其他Method,Constructor类似,方法中含有Declared的可以获取全部属性包括private
代码测试
//获取类的信息
public class Test08 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
Class c1 = Class.forName("com.reflection.User");
//获得类的名字
System.out.println(c1.getName());//com.reflection.User 包名+类名
System.out.println(c1.getSimpleName());//User 类名
//获得类的属性
System.out.println("=============================");
Field[] fields = c1.getFields();//只能找到public属性
for (Field field : fields) {
System.out.println(field);//所以没有输出
}
fields = c1.getDeclaredFields();//获取全部属性,包括private
for (Field field : fields) {
System.out.println(field);
}
//获取指定属性的值
// Field field = c1.getField("name");//报错,因为属性name为private,无法获取,需要使用getDeclaredField()
Field field = c1.getDeclaredField("name");
System.out.println(field);
//获取类的方法
System.out.println("=============================");
Method[] methods = c1.getMethods();
for (Method method : methods) {
System.out.println("正常的"+method);//输出了所有public方法,包括父类的public方法(Object的)
}
methods = c1.getDeclaredMethods();//获得本类的所有方法,包括私有的
for (Method method : methods) {
System.out.println("getDeclaredMethods"+method);
}
//获得指定方法
//因为可能有重载方法,所以需要传参数
System.out.println("=============================");
Method getName = c1.getMethod("getName", null);
Method setName = c1.getMethod("setName", String.class);
System.out.println(getName);
System.out.println(setName);
//获得构造器
System.out.println("=============================");
Constructor[] constructors = c1.getConstructors();//获得所有public方法
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
constructors = c1.getDeclaredConstructors();//获得所有方法包括private
for (Constructor constructor : constructors) {
System.out.println("#"+constructor);
}
//获取指定构造器
System.out.println("=============================");
Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
System.out.println(declaredConstructor);
}
}
动态创建对象的执行方法
通过反射创建对象
/**
- 1.调用Class对象的newInstance()方法
- 1)类必须有一个无参构造器
- 2)类的构造器访问权限需要足够
- 2.通过构造器创建对象
- User user2 = (User)constructor.newInstance(“yuan”, 001, 21);
*/
通过Class对象的newInstance()方法来创建的对象是一个Object类型,需要强转为目标对象类型,如下代码案例中的User
并且其本质是调用目标对象类的无参构造器,如果没有无参构造器或者无参构造器权限不够将会报错
如果目标对象类型没有无参构造,则通过构造器来创建对象,先获取有参构造器的对象,再通过此对象的方法newInstance()传入参数,如下代码:
Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
User user2 = (User)constructor.newInstance("yuan", 001, 21);
通过反射操作方法或属性
操作方法:
获取到的方法需要使用invoke方法来激活(也可以理解为在某个对象的某个方法中传参),invoke(对象名,参数),例如代码:
setName.invoke(user3,"boss");
操作属性:
因为属性一般情况下都是私有的,不能直接操作私有属性,需要关闭权限检测,使用属性的方法setAccessible(true)取消Java语言访问检查,如下代码
name.setAccessible(true);
name.set(user4,"boss_yuan");
setAccessible的使用
Method、Field、Constructor对象都有setAccessible()方法。
setAccessible作用是启动和禁用访问安全检查的开关
参数值为true则指示反射的对象在使用时应该取消Java语言访问检查
设置setAccessible(true)可以提高反射效率,如果代码中必须使用反射,而该句代码要频繁的被调用,那么就需要 setAccessible(true)
设置setAccessible(true)使得原本无法访问的私有成员也可以访问
参数为false则指示反射的对象应该实施Java语言访问检查
测试代码
//动态的创建对象,通过反射
/**
* 1.调用Class对象的newInstance()方法
* 1)类必须有一个无参构造器
* 2)类的构造器访问权限需要足够
* 2.通过构造器创建对象
* User user2 = (User)constructor.newInstance("yuan", 001, 21);
*/
public class Test09 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
//获得Class对象
Class c1 = Class.forName("com.reflection.User");
//构造一个对象
User user = (User)c1.newInstance();//本质上是调用User类的无参构造器,如果没有无参构造器将会报错
System.out.println(user);
//通过构造器创建对象
Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
User user2 = (User)constructor.newInstance("yuan", 001, 21);
System.out.println(user2);
//通过反射调用普通方法
User user3 = (User)c1.newInstance();
Method setName = c1.getDeclaredMethod("setName", String.class);
//invoke激活的意思
//(对象,"方法的参数")
setName.invoke(user3,"boss");
System.out.println(user3.getName());
//通过反射操作属性
User user4 = (User)c1.newInstance();
Field name = c1.getDeclaredField("name");
//不能直接操作私有属性,需要关闭权限检测,属性或方法的setAccessible(true)
name.setAccessible(true);
name.set(user4,"boss_yuan");
System.out.println(user4.getName());
}
}