Java反射的原理,作用

什么是反射,反射原理

java类的执行需要经历以下过程

  1. 编译:.java文件编译后生成.class字节码文件

  2. 加载:类加载器负责根据一个类的全限定名来读取此类的二进制字节流到JVM内部,并存储在运行时内存区的方法区,然后将其转换为一个与目标类型对应的java.lang.Class对象实例

  3. 连接:细分三步
    验证:格式(class文件规范) 语义(final类是否有子类) 操作
    准备:静态变量赋初值和内存空间,final修饰的内存空间直接赋原值,此处不是用户指定的初值。
    解析:符号引用转化为直接引用,分配地址

  4. 初始化:有父类先初始化父类,然后初始化自己;将static修饰代码执行一遍,如果是静态变量,则用用户指定值覆盖原有初值;如果是代码块,则执行一遍操作。

什么是反射:

  Java的反射就是利用上面第二步加载到jvm中的.class文件来进行操作的。.class文件中包含java类的所有信息,当你不知道某个类具体信息时,可以使用反射获取class,然后进行各种操作。

Java反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性

要想解剖一个类,必须先要获取到该类的字节码文件对象(class)。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.)

关于class对象和这个Class类

  • Class对象的由来是将class文件读入内存,并为之创建一个Class对象

image

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
类名.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() ,并强转类型,然后就可以操作对象了,主要是调用方法。

image

2,操作属性,可以操作类里面的public属性和private属性 如果属性是private,正常情况下是不允许外界操作属性值,这里可以用Field类的setAccessible(true)方法,暂时打开操作的权限

image

反射方法的使用之---通过反射运行配置文件内容

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值
    }
}

 控制台输出:is show()

需求:

当我们升级这个系统时,不要Student类而需要新写一个Student2的类时,这时只需要更改pro.txt的文件内容就可以了。代码就一点不用改动

新写一个student2的类:

public class Student2 { 
    public void show2() {
        System.out.println("is show2()");
    }
}

配置文件更改为:

className = cn.fanshe.Student2
methodName = show2

控制台输出:is show2()

你可能感兴趣的:(Java反射的原理,作用)