Class clazz3 = instance.getClass();
System.out.println(“Class.forName() == SmallPineapple.class:” + (clazz1 == clazz2));
System.out.println(“Class.forName() == instance.getClass():” + (clazz1 == clazz3));
System.out.println(“instance.getClass() == SmallPineapple.class:” + (clazz2 == clazz3));
内存中只有一个 Class 对象的原因要牵扯到
JVM 类加载机制
的双亲委派模型
,它保证了程序运行时,加载类
时每个类在内存中仅会产生一个Class对象
。在这里我不打算详细展开说明,可以简单地理解为 JVM 帮我们保证了一个类在内存中至多存在一个 Class 对象。
构造类的实例化对象
通过反射构造一个类的实例方式有2
种:
- Class 对象调用
newInstance()
方法
Class clazz = Class.forName(“com.bean.SmallPineapple”);
SmallPineapple smallPineapple = (SmallPineapple) clazz.newInstance();
smallPineapple.getInfo();
// [null 的年龄是:0]
即使 SmallPineapple 已经显式定义了构造方法,通过 newInstance() 创建的实例中,所有属性值都是对应类型的初始值
,因为 newInstance() 构造实例会调用默认无参构造器。
- Constructor 构造器调用
newInstance()
方法
Class clazz = Class.forName(“com.bean.SmallPineapple”);
Constructor constructor = clazz.getConstructor(String.class, int.class);
constructor.setAccessible(true);
SmallPineapple smallPineapple2 = (SmallPineapple) constructor.newInstance(“小菠萝”, 21);
smallPineapple2.getInfo();
// [小菠萝 的年龄是:21]
通过 getConstructor(Object… paramTypes) 方法指定获取指定参数类型的 Constructor, Constructor 调用 newInstance(Object… paramValues) 时传入构造方法参数的值,同样可以构造一个实例,且内部属性已经被赋值。
通过Class
对象调用 newInstance() 会走默认无参构造方法,如果想通过显式构造方法构造实例,需要提前从Class中调用getConstructor()
方法获取对应的构造器,通过构造器去实例化对象。
这些 API 是在开发当中最常遇到的,当然还有非常多重载的方法,本文由于篇幅原因,且如果每个方法都一一讲解,我们也记不住,所以用到的时候去类里面查找就已经足够了。
获取一个类的所有信息
Class 对象中包含了该类的所有信息,在编译期我们能看到的信息就是该类的变量、方法、构造器,在运行时最常被获取的也是这些信息。
获取类中的变量(Field)
- Field 《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》无偿开源 威信搜索公众号【编程进阶路】 [] getFields():获取类中所有被
public
修饰的所有变量 - Field getField(String name):根据变量名获取类中的一个变量,该变量必须被public修饰
- Field[] getDeclaredFields():获取类中所有的变量,但无法获取继承下来的变量
- Field getDeclaredField(String name):根据姓名获取类中的某个变量,无法获取继承下来的变量
获取类中的方法(Method)
-
Method[] getMethods():获取类中被
public
修饰的所有方法 -
Method getMethod(String name, Class…<