jvm通过IO流读取class文件,并加载到内存中。类的实例对象都是依靠相应的class文件载体生成的,而反射修改的其实是实例对象,并没有动运行时加进来内存的字节码文件。
Class cl = Demo.class;// 字节码文件
Field f3 = cl.getDeclaredField("sex");//拿到Demo类中的sex字段
f3.setAccessible(true);//允许暴力设置属性
Object o = cl.newInstance();//实例化Demo类
Demo d2 = (Demo) o;//强转
//System.out.println(d2.getSex().getName());//打印空指针
Object bean = new Dog("123");//实例Dog类
f3.set(o,bean);//赋予o中的sex字段bean对象
Demo d3 = (Demo) o;//强转
System.out.println(d3.getSex().getName());//打印123
Object bean1 = new Dog("234");//实例Dog类
f3.set(o,bean1);//赋予o中的sex字段bean1对象
Demo d4 = (Demo) o;//强转
System.out.println(d4.getSex().getName());//打印234
package com;
public class Demo {
static {
System.out.println("ok");
}
private Dog sex;
public Dog getSex() {
return sex;
}
public void setSex(Dog sex) {
this.sex = sex;
}
}
//Demo类
package com;
public class Dog {
private String name;
public Dog(){}
public Dog(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
//Dog类
上面我用反射给o这个Demo类实例对象中的sex赋值,打印出数字内容说明反射成功调用。接下来就只需在new一个新对象就能验证反射改没改字节码。
Object z = o.getclass().newInstance();
Demo d5 = (Demo) z;
System.out.println(d5.getSex().getName());//还是跟d2一样报空指针
这里用o.getclass()而不是用cl,更加严谨的证明了运行中class没有发生变化。
java中实例化一个类肯定要有对应的class文件,要修改一个类信息要么在实例化前,要么在实例化后,显然反射就是在类实例化后修改实例对象的。