什么是反射,反射原理

  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对象

    

java反射怎么debug java反射的步骤原理_java

 

 

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

    

java反射怎么debug java反射的步骤原理_构造方法_02

 

   

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

       

java反射怎么debug java反射的步骤原理_java反射怎么debug_03

 

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

  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()

 

作 者:一支会记忆的笔

---------------------

个性 签名:真正的学习不是记住知识,而是学会如何提出问题,研究问题,解决问题。