Java反射

1. class文件

一个.java文件中可以看到的内容是未经编译过的,只有一部分自定义的内容。在IDEA中点开class文件查看,发现也只有一部分自定义的内容,因为这是编译器经过反编译处理后看到的,并不是class文件完全体。这容易误导以为一个class文件的内容也只有反编译后所看到的内容。

以下是class文件真正的ClassFile内容,存储类似C语言结构体。

ClassFile {
    u4magic; //Class 文件的标志,魔术
    u2minor_version;//Class 的附版本号
    u2major_version;//Class 的主版本号
    u2constant_pool_count;//常量池表项的数量
    cp_infoconstant_pool[constant_pool_count-1];//常量池表项,索引为1~constant_pool_count-1
    u2access_flags;//Class 的访问标志(类访问修饰符)
    u2this_class;//表示当前类的引用
    u2super_class;//表示父类的引用
    u2interfaces_count;//实现接口数量
    u2interfaces[interfaces_count];//接口索引数组
    u2fields_count;//此类的字段表中的字段数量
    field_infofields[fields_count];//一个类会可以有多个字段,字段表
    u2methods_count;//此类的方法表中的方法数量
    method_infomethods[methods_count];//一个类可以有个多个方法,方法表
    u2attributes_count;//此类的属性表中的属性数量
    attribute_infoattributes[attributes_count];//属性表集合
}

2. Class对象

2.1 Class和Object的区别

Object类是所有java类的父类,所有java类默认继承Object类,所有类都可以向上转型成Object对象,基于多态,一个Object形参可以接收任意对象,一些公共的方法只用写一份,方法内部只操作Object对象即可实现操作所有对象。基于这个特性,类模板编译时会把模板参数擦除成Object,类模板也只用一个即可,这个设计解决了C++中的类模板编译代码膨胀问题。

Class类是一个模板类,同样也会默认继承Object类,每个class文件都只有一个唯一的Class对象(ClassFile结构体),不同的Class对象结构体相同,提取共性,使用一个Class模板类就可以操作所有Class对象。

2.2 Class对象和实例化对象的区别

Class对象由类加载器从元数据区加载到堆中并创建一个唯一的Class对象。

实例化对象是Class对象存在后,基于Class对象在堆中申请一块内存并初始化成员变量。

3. ClassAPI

3.1 创建Class对象

3.1.1 类名.class

Class<Student> cls = Student.class;

3.1.2 类全路径

Class<?> cls = Class.forName("com.trustlife.pa.test.Student");

3.2 创建实例化对象

3.2.1 使用无参构造器创建

Student student = cls.getDeclaredConstructor().newInstance();

 3.2.2  简化版无参构造

Student student = cls.newInstance();

3.3 获取构造函数

3.3.1 获取public修饰的构造函数

Constructor<?>[] constructors = cls.getConstructors();

3.3.2  获取所有修饰符下的构造函数

Constructor<?>[] declaredConstructors = cls.getDeclaredConstructors();

3.4 获取成员变量

3.4.1 获取public修饰的成员变量

Field[] fields = cls.getFields();

3.4.2 获取所有修饰符下的成员变量

Field[] declaredFields = cls.getDeclaredFields(); 

3.5 获取成员方法

3.5.1 获取public修饰的成员方法

Method[] methods = cls.getMethods();

3.5.2 获取所有修饰符下的成员方法

Method[] declaredMethods = cls.getDeclaredMethods();

3.6 简单实现mapToBean

@Data
class Student {
    private String name;
    private Integer age;
}
public class Test {
    public static void main(String[] args) throws Exception {
        Map<String, Object> map = new HashMap<>();
        map.put("name", "rose");
        map.put("age", 18);
        Student student = mapToBean(map, Student.class);
        System.out.println(student);
    }

    private static <K, V, T> T mapToClass(Map<K, V> map, Class<T> cls) throws Exception {
        Constructor<T> constructor = (Constructor<T>) cls.getDeclaredConstructors()[0];
        T t = constructor.newInstance(new Object[constructor.getParameterCount()]);
        for (Method method : cls.getMethods()) {
            String name = method.getName();
            if (name.length() >= 4 && name.startsWith("set")) {
                if (name.length() > 4 && name.charAt(4) >= 'A' && name.charAt(4) <= 'Z')
                    name = name.substring(3);
                else
                    name = String.valueOf(name.charAt(3)).toLowerCase() + (name.length() > 4 ? name.substring(4) : "");
                method.invoke(t, map.get((K) name));
            }
        }
        return t;
    }
}

4. 反射特点

反射就是对Class对象的操作。

反射可以非常优雅的实现很多功能,但是反射破坏了对象的封装性,开发中除一些工具类外,使用反射的时候也要尽量确保不破坏对象的封装性,如果任意使用,任意破坏,也就不再是面向对象开发了。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值