java内功提升-反射
在程序运行时,通过.class文件获得类中的内容(构造方法,成员方法,属性等),并且进行操作
初始化一个类需要哪些步骤?
1.加载.class文件,创建Class对象;
2.连接:校验Class对象的完整性和正确性
3.初始化
创建一个空白的对象实例(只有引用没有内容)
初始化父类对象(如果继承了父类)
添加成员变量,成员方法(静态变量在类被加载到jvm中的时候就已经创建)
运行实例程序
使用反射的步骤
1.创建Class对象
三种方式:
(1).调用Class.forName(“类的完整路径”)
(2).调用实例对象的getClass()方法
(3).通过.class文件赋值得到:Class clazz = Person.class
2.获取构造方法
Constructor constructor = clazz.getConstructor();
3.获得对象实例
Object obj = constructor.newInstance();
4.获得字段/获得方法
Field field = clazz.getFiled(name);
Method method = clazz.getMethod(methodName, paramTypeClass);
5.给字段赋值或得到字段的值/调用方法得到返回值
field.set(obj, value);
field.get(obj);
method.invoke(obj,params); //传入的是对象和参数
获取构造方法
//获取Test类的Class对象
Class<Test> clazz = Test.class;
//通过反射获取构造方法
Constructor<Test> constructor = clazz.getConstructor();
//获取Test类的私有构造方法
Field declaredField = clazz.getDeclaredField();
//通过反射获取Test类的实例
Test test = constructor.newInstance();
获取Field
//获取Test类的Class对象
Class<Test> clazz = Test.class;
//获取属性名为name的Filed属性对象,不包括私有属性
Field age = clazz.getField("age");
//获取Test的所有属性对象,包括父类中的公有属性,不包括私有属性
Field[] fields = clazz.getFields();
//获取Test的名为age的属性对象,包括私有属性
Field declaredField = clazz.getDeclaredField("age");
//获取Test中的所有属性,包括父类中的公有属性,包括私有属性
Field[] declaredFields = clazz.getDeclaredFields();
//给age属性赋值
age.set(18);
//得到age对象的名字
age.getName();
获取Method
Constructor<Test> constructor = clazz.getConstructor();
Test test = constructor.newInstance();
//获取名为eat()的方法,不包括私有方法
Method method = clazz.getMethod("eat");
//获取所有的方法,包括父类中的公有方法,不包括私有方法
Method[] methods = clazz.getMethods();
//获取名为eat的方法,包括私有方法
Method declaredMethod = clazz.getDeclaredMethod("eat");
//获取所有的方法,包括父类中的方法,包括私有方法
Method[] declaredMethods = clazz.getDeclaredMethods();
//调用执行该方法,并传入test实例和参数
method.invoke(test,"肉");
暴力访问
//获取Test类的Class对象
Class<Test> clazz = Test.class;
Test test = clazz.getConstructor().newInstance();
//获取名为name的私有字段
Field name = clazz.getDeclaredField("name");
//给属性赋值
name.set(test,"张三");
上面的代码有什么问题吗?
看似没有问题,其实私有字段是不能通过外部来进行赋值的,那么如何解决?
//获取Test类的Class对象
Class<Test> clazz = Test.class;
Test test = clazz.getConstructor().newInstance();
//获取名为name的私有字段
Field name = clazz.getDeclaredField("name");
//设置暴力访问
name.setAccessible(true);
//给属性赋值
name.set(test,"张三");
看出来了吗?对了,只要加上**setAccessible()**这个方法,并且将它设置为true就可以对私有的属性、方法等 进行操作了。