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

被折叠的 条评论
为什么被折叠?



