什么是反射,反射原理
java类的执行需要经历以下过程
编译:.java文件编译后生成.class字节码文件
加载:类加载器负责根据一个类的全限定名来读取此类的二进制字节流到JVM内部,并存储在运行时内存区的方法区,然后将其转换为一个与目标类型对应的java.lang.Class对象实例
连接:细分三步
验证:格式(class文件规范) 语义(final类是否有子类) 操作
准备:静态变量赋初值和内存空间,final修饰的内存空间直接赋原值,此处不是用户指定的初值。
解析:符号引用转化为直接引用,分配地址
初始化:有父类先初始化父类,然后初始化自己;将static修饰代码执行一遍,如果是静态变量,则用用户指定值覆盖原有初值;如果是代码块,则执行一遍操作。
什么是反射:
Java的反射就是利用上面第二步加载到jvm中的.class文件来进行操作的。.class文件中包含java类的所有信息,当你不知道某个类具体信息时,可以使用反射获取class,然后进行各种操作。
Java反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性
要想解剖一个类,必须先要获取到该类的字节码文件对象(class)。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.)
关于class对象和这个Class类
- Class对象的由来是将class文件读入内存,并为之创建一个Class对象
Class类
class类 :代表一个类,是Java反射机制的起源和入口
用于获取与类相关的各种信息, 提供了获取类信息的相关方法
Class类继承自Object类
Class类是所有类的共同的图纸
每个类有自己的对象,同时每个类也看做是一个对象,有共同的图纸Class,存放类的结构信息,能够通过相应方法取出相应的信息:类的名字、属性、方法、构造方法、父类和接口。
获取class对象(反射入口)的三种方式
要想操作反射,必须先拿到反射的入口
1,通过通过Class.forName("全类名") 静态方法来获取,用的最多
Class c3 = Class.forName("reflect_fanshe.Person");
Class<?> perClazz = Class.forName("reflect_fanshe.Person");
2,类名.class
/2、类名.class 的方式得到,该方法最为安全可靠,程序性能更高
// 这说明任何一个类都有一个隐含的静态成员变量 class
Class c2 = Person.class;
Class<?> perClazz2 = Person.class;
3,对象.getClass()
Person person = new Person(); Class<?> perClazz3 = person.getClass();
Class具有的部分方法如下:
getName():获得类的完整名字。
getFields():获得类的public类型的属性。
getDeclaredFields():获得类的所有属性。包括private 声明的和继承类
getMethods():获得类的public类型的方法。
getDeclaredMethods():获得类的所有方法。包括private 声明的和继承类
getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes 参数指定方法的参数类型。
getConstructors():获得类的public类型的构造方法。
getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes 参数指定构造方法的参数类型。
newInstance():通过类的不带参数的构造方法创建这个类的一个对象。
通过反射获取对象的实例,并操作对象
1,class.newInstance() ,并强转类型,然后就可以操作对象了,主要是调用方法。
2,操作属性,可以操作类里面的public属性和private属性 如果属性是private,正常情况下是不允许外界操作属性值,这里可以用Field类的setAccessible(true)方法,暂时打开操作的权限
反射方法的使用之---通过反射运行配置文件内容
student类:
public class Student { public void show(){ System.out.println("is show()"); } }
配置文件以txt文件为例子(pro.txt):
className = cn.fanshe.Student
methodName = show
测试类:
import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.lang.reflect.Method; import java.util.Properties; /* * 我们利用反射和配置文件,可以使:应用程序更新时,对源码无需进行任何修改 * 我们只需要将新类发送给客户端,并修改配置文件即可 */ public class Demo { public static void main(String[] args) throws Exception { //通过反射获取Class对象 Class stuClass = Class.forName(getValue("className"));//"cn.fanshe.Student" //2获取show()方法 Method m = stuClass.getMethod(getValue("methodName"));//show //3.调用show()方法 m.invoke(stuClass.getConstructor().newInstance()); } //此方法接收一个key,在配置文件中获取相应的value public static String getValue(String key) throws IOException{ Properties pro = new Properties();//获取配置文件的对象 FileReader in = new FileReader("pro.txt");//获取输入流 pro.load(in);//将流加载到配置文件对象中 in.close(); return pro.getProperty(key);//返回根据key获取的value值 } }
需求:
当我们升级这个系统时,不要Student类,而需要新写一个Student2的类时,这时只需要更改pro.txt的文件内容就可以了。代码就一点不用改动
新写一个student2的类:
public class Student2 { public void show2(){ System.out.println("is show2()"); } }
配置文件更改为:
className = cn.fanshe.Student2
methodName = show2
控制台输出:is show2()