什么是 Java 反射

 2022-08-27
原文地址:https://my.oschina.net/u/3293292/blog/1305496

1 , 类初始化的时机

1 , 在使用一个类之前,需要先加载该类的class文件到内存,创建该类对象,通过该类的对象访问类中的成员变量, 成员方法. 那么问题是: 是谁加载类的class文件到内存中的呢? 并创建了该类的对象的是谁呢 ? 答案是 : 类加载器

2, 什么时候会加载一个类到内存中 ? 加载一个类的情形如下 :

创建类的实例, 访问类的静态变量, 调用类的静态方法, 初始化类的子类

2, 什么是反射 ?

通常情况下, 访问类中的成员变量, 构造方法, 成员方法 , 使用的是该类的Java文件 . 如果不通过该类的java文件, 而是只有class文件, class文件是java文件编译后的文件, 当一个类 ,处于运行状态时, 就会执行编译, java文件编译成class文件, 通过该类的class文件访问类中的成员变量, 成员方法, 构造方法, 即为反射 . 所以java反射机制是在运行状态中, 对于任意一个类 ,都能够知道这个类的所有属性和方法 .

要使用反射机制, 首先要获取该类的class文件对象

3, 反射定义

反射就是通过类class文件对象 , 去使用该文件中的成员变量,构造方法, 成员方法.

要使用反射, 首先要获取class文件对象, 也就是Class类对象,

Class类对象中, 又将成员变量, 构造方法, 成员方法 , 分别封装成单独的类 ,

成员变量 Field类

构造方法 Constructor类

成员方法 Method类

所以首先要获取class文件对象, 获取class文件对象有三种方法 :

1, 任意对象都有getClass()方法,

Person p = new Person();

Class c1 = p.getClass();

创建类的对象, 然后通过对象.getClass()方法

2, 数据类型的静态属性

Classc2 = Person.class;

3, Class类中的静态方法

Classc3 = Class.forName(“类的包类路径名”);

4, 通过反射获取类中的无参构造方法并使用

1, 获取该类的class字节码文件对象

Class<?> person = Class.forName(“Person类的包类路径名”);

2, 通过class字节码文件对象获取构造方法对象Constructor

Constructor[] cons =person. getConstructors(); //获取所有公共构造方法

Constructor[] cons =person. getDeclaredConstructors(); //获取所有构造方法包括私有

Constructor con =person. getConstructor(Class<?>... parameterTypes); //获取指定参数的公共构造方法

3, 通过Constructor对象创建该构造方法的声明类的新实例, 此处为Person类

Object obj = con. newInstance();

Obj即为Person类的对象

5, 反射获取类中私有内容

如果一个类中的成员变量,构造方法,成员方法是私有的, 那么在该类外部通过创建该类对象是无法访问该类中的私有元素的.

那么可以通过反射访问类中的私有内容 . 例如, 通过反射获取类中的私有的构造方法.

// 实体类

    Public class Person{
    
        …
    
        Private Person(String name){
    
               This.name = name;
    
    }
    
    }

// 测试类(通过反射获取类中的私有的构造方法)

    Public class demo{
    
        Public static void main(String[] args){
    
               //获取字节码文件对象
    
               Class c = Class.forName(“类的包类路径名”);
    
               //获取构造器对象 , Constructor类对象  
    
               Constructor con = c.getDeclaredConstructor(String.class);
    
               //用该私有构造方法创建对象
    
               Object obj = Con.newInstance();
    
    }
    
    }

6, 通过反射获取成员变量并赋值

    //实体类
    
    Public class Person{
    
        Private String name;
    
        … …
    
    }
    
    //测试类   给name赋值
    
    Public Class demo(){
    
        Public static void main(){
    
               //通过反射获取字节码文件对象
    
               Class c = Class.forName(“包类路径名称”);
    
               //通过字节码文件对象获取所有成员变量
    
               Field[] fields = c.getFields();
    
               Field[] fields = c.getDeclaredFields();
    
               // 获取单个的成员变量
    
               Field filed = c.getField(“成员变量名称”);  
    
               //给指定对象(Person)中的成员变量赋值
    
               Filed.set(Person,”莱昂纳多”) ; 
    
     }
    
    }

7, 通过反射获取带参带返回值成员方法并使用

    // 实体类
    
    Public class Person{
    
        //无参数 无返回值
    
        Public void show(){
    
               System.out.println(“show方法”);
    
         }
    
    //带参数, 带返回值
    
    Public StringgetString(String str){
    
        System.out.println(“getString”+str);
    
      }
    
    }
    
    //测试类
    
    Public class demo{
    
        Public static void main(){
    
               //通过反射获取类的字节码文件对象
    
               Classc = Class.forName(“类的包类路径名”);
    
               //通过类的class字节码文件对象获取类的构造方法
    
               Constructor con = c.getConstructor();
    
               Object obj = Con.newIntence();
    
               //通过类的字节码文件对象获取自己一级父类中的所有的公共的成员方法,
    
               Method[] methods = c.getMethods();
    
               //通过类的字节码文件对象获取自己类中的所有的成员方法,不包括父类
    
               Method[] methods = c.getDeclaredMethods();
    
     
    
               //获取单个方法并使用
    
               // public Method getMethod(Stringname,class<?> parameterTypes);
    
               // 第一个参数表示的是方法名,第二个参数表示的是方法的参数的class类型
    
               Method m1 = c.getMethod(“show”); // “show”代表方法名,该方法没有参数,第二个参数可以不填
    
               // 执行该方法
               //第一个参数表示对象是谁, 第二个参数表示调用该方法的实际参数
               // public Object invoke(Objectobj , object args);  
    
    
               m1.invoke(obj);   //标识调用obj对象的m1方法
    
               // 通过反射获取getString方法    
    
               Mehotd m2 = c.getMethod(“getString”,String.class);
    
               //调用obj对象的m2方法, 传递的参数为 ”hello”
               //此时的getString为执行该方法返回值, “hello”即表示调用m2方法传递的实际参数
               Object getString = m2.invoke(obj,”hello”);   
    
       }
    
    }

8 , 反射实用范例: 通过反射运行配置文件中的内容

Txt文件中配置如下内容:

className=类的包类路径名

methodName=方法名

1, 通过Properties类读取txt文件

    Properties prop =new Properties();
    
    FileReader fr = new FileReader(“xxx.txt”);
    
    Prop.load(fr);
    
    fr.close();

2, 获取txt文件中的数据

    StringclassName  = Prop.getProperty(“className”);  //此处的param_key为txt文件中的数据key值
    
    String methodName = Prop.getProperty(“methodName”);

3, 获取class字节码文件对象

    Class c = Class.forName(className);
    
    //获取空参数构造方法,并实例化
    
    Constructor con = c.getConstructor();
    
    Object obj = con.newInstance();  //即通过反射创建了类的对象
    
    //获取方法对象
    
    Method m1 = c.getMethod(methodName);// 此处默认没有参数
    
    //执行方法
    
    m1.invoke(obj);   //即执行obj类中的m1方法

展开阅读全文