JavaSE-14笔记【反射机制(+2024新)】

1.反射机制概述

反射机制是JDK中的一套类库,这套类库可以帮助我们操作/读取class文件,反射机制可以让程序更灵活,后期学习的大量java框架底层都是基于反射机制实现的,需要能够熟练地使用反射机制中的方法。

反射机制最核心的几个类:

  • java.lang.Class:Class类型的实例代表硬盘上的某个class文件,或者说代表一种类型,并且需要注意的是某种类型的class文件在内存中只有一份,无论以何种方式获取到的都是同一个;
  • java.lang.reflect.Field:Field类型的实例代表类中的属性/字段;
  • java.lang.reflect.Constructor:Constructor类型的实例代表类中的构造方法;
  • java.lang.refelct.Method: Method类型的实例代表类中的方法。

2.获取Class的四种方式

第一种方式: Class c = Class.forName("完整的全限定类名");
①全限定类名是带有包名的;
②如果是lang包下的,java.lang也不能省略;
③参数为字符串参数;
④如果类不存在,运行时会报异常:java.lang.ClassNotFoundException
⑤这个方法的执行会导致类加载。

第二种方式: 通过类的引用调用:Class c = 引用.getClass();

第三种方式: 在java中任何一种类型,包括基本数据类型,都有.class属性,用这个属性可以获取对应的Class实例:Class c = 类名.class;
第四种方式: 通过类加载器获取(具体见后9.1)

示例代码:
User类:

package reflecttest;

public class User {
   
}
package reflecttest;

public class ReflectTest01 {
   
    public static void main(String[] args) throws ClassNotFoundException {
   
        //第一种方式:Class.forName("完整的全限定类名")
        //stringClass代表String类型,代表硬盘上的String.class文件
        Class stringClass = Class.forName("java.lang.String");

        //获取User类型
        Class userClass = Class.forName("reflecttest.User");

        //第二种方式,obj.getClass()
        String s = "反射机制";
        Class stringClass2 = s.getClass();

        //某种类型的字节码文件在内存中只有一份
        //stringClass 和 stringClass2 都代表了同一种类型:String类型
        System.out.println(stringClass == stringClass2); //true

        User user = new User();
        Class userClass2 = user.getClass();
        System.out.println(userClass == userClass2); //true

        //第三种方式:类名.class
        Class intClass = int.class;
        Class stringClass3 = String.class;
        Class userClass3 = User.class;

        System.out.println(userClass3 == userClass); //true
    }
}

3.通过反射机制实例化对象*

假设userClass为获取到的User类型,则可以通过userClass.newInstance()实例化User对象,其底层是通过调用User类的无参构造方法完成对象的实例化。
注意: 要使用newInstance()方法的话,必须要保证对应类中存在无参构造方法,如果没有无参构造方法,则会出现异常:java.lang.InstantiationException

此外,newInstance()方法从java9开始已过时。

修改User类:

package reflecttest;

public class User {
   
    static {
   
        System.out.println("静态代码块调用了!");
    }
    public User(){
   
        System.out.println("无参构造方法调用了!");
    }
}

示例代码:

package reflecttest;

public class ReflectTest02 {
   
    public static void main(String[] args) throws Exception {
   
        //获取User类型,会进行类加载,类中若有静态代码块会执行
        Class userClass = Class.forName("reflecttest.User");

        //通过userClass创建User实例,返回Object类型,需要向下转型
        //必须保证User类中有无参构造方法
        User user = (User)userClass.newInstance();

        System.out.println(user);

        //每次调用创建的是不同的对象实例
        User user2 = (User)userClass.newInstance();
        System.out.println(user2);
        System.out.println(user == user2);

    }
}

运行结果:
在这里插入图片描述

4.反射机制结合配置文件灵活实例化对象*

通过此方式可以做到对象的动态创建,只需要修改属性配置文件就可以完成不同对象的实例化。

classInfo.properties配置文件:

className = reflecttest.User

测试代码(User同上):

package reflecttest;

import java.util.ResourceBundle;

public class ReflectTest03 {
   
    public static void main(String[] args) throws Exception {
   
        //资源绑定器
        ResourceBundle resourceBundle = ResourceBundle.getBundle("reflecttest.classInfo");

        //通过属性配置文件的key获取value
        String className = resourceBundle.getString("className");

        //通过反射机制实例化对象
        Class objClass = Class.forName(className);

        Object o = objClass.newInstance();

        System.out.println(o);
    }
}

运行结果:
在这里插入图片描述

classInfo.properties配置文件:

className = java.util.Date

测试代码不变,运行结果:
在这里插入图片描述

5.java.lang.reflect.Field

Vip类:

package reflecttest;

public class Vip {
   
    public String name;

    private int age;

    protected boolean sex;

    int accountId;

    public static String grade = "黄金Vip";

    public static final String dec = "描述";

}

测试代码:

package reflecttest;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

/**
 * java.lang.reflect.Field 代表的是一个类中的字段/属性
 */
public class ReflectTest04 {
   
    public static void main(String[] args) throws ClassNotFoundException {
   
        //获取Vip类
        Class vipClass = Class.forName("reflecttest.Vip");

        System.out.println("获取Vip类中所有public修饰的属性/字段:");

        //获取Vip类中所有public修饰的属性/字段
        Field[] fields = vipClass.getFields();

        //遍历
        for (Field field: fields) {
   
            //获取属性名
            System.out.println("属性名:"+field.getName());
        }
        System.out.println("===================================");

        System.out.println("获取Vip类中所有属性/字段,包括私有的:");

        //获取Vip类中所有属性/字段,包括私有的
        Field[] fields1 = vipClass.getDeclaredFields();

        //遍历
        for (Field field: fields1) {
   
            //获取属性名
            System.out.println("属性名:" + field.getName());

            //获取属性类型
            Class fieldType = field.getType();
            System.out.println("属性类型:" + fieldType);

            //通过属性类型获取其完整类名
            System.out.println("属性类型完整类名:" + fieldType.getName());
            //通过属性类型获取其简单类名
            System.out.println("属性类型简单类名:" + fieldType.getSimpleName());

            //获取属性修饰符
            System.out.println("属性修饰符:" + Modifier.toString(field.getModifiers()));
            System.out.println();
        }
    }
}

运行结果:
在这里插入图片描述

5.1反编译类中的所有字段/属性

package reflecttest;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class ReflectTest05 {
   
    public static void main(String[] args) throws Exception {
   
        //获取Vip类
//        Class stringClass = Class.forName("reflecttest.Vip");
                Class stringClass = Class.forName("java.util.Date");


        //字符串拼接
        StringBuilder sb = new StringBuilder();

        //获取String类的修饰符
        sb.append(Modifier.toString(stringClass.getModifiers()));

        sb.append(" class ");

        //获取简单类名
        sb.append(stringClass.getSimpleName());

        sb.append(" extends ");

        //获取父类简单类名
        sb.append(stringClass.getSuperclass().getSimpleName());

        //获取当前类实现的所有接口
        Class[] interfaces = stringClass.getInterfaces();

        if(interfaces.length > 0){
   
            sb.append(" implements ");
            for (int i = 0; i < interfaces.length; i++) {
   
                sb.append(interfaces[i].getSimpleName());
                if(i != interfaces.length-1){
   
                    sb.append(
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ED_Sunny小王

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值