Java反射相关内容。
Class对象
Java中的反射最关键的一个类就是Class类,首先你要先得到这个类的对象,一般有两种方式,如果在编译时你知道那个类名,你可以直接Class cls = MyObject.class;
来得到Class对象。如果编译时不知道类名,那需要使用Class = Class.forname("com.mark.MyObject");
来得到Class对象,这里需要类的全限定名。
当得到Class对象后,那基本就能通过Class对象得到关于这个类的一切数据:字段、方法、构造函数等等信息都可以通过这个Class对象的相对应方法来获取到。
内部类
示例代码:
1 | package com.mark.reflection; |
我们知道内部类的类名是外部类+$+内部类名,所以,我门可以这样加载内部类:
1 | Class cls = Class.forName("com.mark.reflection.GenericClass$InnerClass"); |
这样我们得到了内部类的Class对象,但是如果想试用Class对象来创建内部类实例,则会遇到问题。
1 | GenericClass.InnerClass ic = (GenericClass.InnerClass) cls.getConstructor().newInstance(gc); |
上面的代码运行将会报NoSuchMethodException
的错误,也就是说没有找到无参构造函数。因为这个内部类并不是静态的,它需要一个外部类的实例引用。通过断点,可以发现在Class的getConstructor
方法调用了getConstructor0())
方法,在getConstructor0())
方法中通过得到类的所有构造函数,然后比较参数来得到指定的构造函数,而通过debug发现,这个类只有一个带有GenericClass参数的构造函数。
所以可以使用下面的方式来实例化一个内部类。
1 | Class outerCls = cls.getEnclosingClass(); |
getEnclosingClass
方法可以获得外部类的Class对象。
上面的方式实例化内部类略显麻烦,我们可以直接加载外部类的Class,然后实例化外部类对象再实例化内部类。
1 | Class cls = Class.forName("com.mark.reflection.GenericClass"); |
数组类型
1 | Class cls = int[].class; |
可以通过上面两种方式来得到int数组的Class对象,其他的基本类型数组也是类似的。如果不知道forName的参数是什么,可以System.out.println(boolean[].class);
看看就知道了。通过cls.getComponentType()
可以得到数组元素的类型。
数组实例无法直接cls.newInstance()
得到,需要借助java.lang.reflect.Array
类。
1 | int[] ints = (int[]) Array.newInstance(int.class, 2); |
创建一个长度为2的int数组。这也适用其他类型数组。
泛型信息
示例代码:
1 | package com.mark.reflection; |
对于泛型类,可以通过Class对象得到泛型相关的信息。
1 | Class cls = Class.forName("com.mark.reflection.GenericClass"); |