前言
本周比较忙,没有学到泛型那一块,就先聊下java的类型信息。这一部分在搭建spring项目时经常会用到。
保持周更,加油。
类型信息
所谓类型信息,就是标识这个类的信息:类名是什么?类是怎么构造的?有哪些成员变量和成员函数?有没有继承关系?等等。我们经常会用到多态,java是如何知道一个父类的引用究竟是指向哪个类的呢?靠的就是类型信息。
类型信息放在哪儿?
- 类型信息均存放在类型为Class(注意是大写)的一个对象中。
- 每当生成一个类时,java会自动的生成一个Class对象,并将类与这个Class对象绑定。
- 当类被第一次使用时,jvm会把它加载进来(通过读取.class文件)。加载过程的第一步时检查这个类的Class对象是否已经加载,如果没有加载,就去读取.class文件。一旦jvm获取了类型的Class对象,他就能创建这个类的所有对象。
类型信息(Class对象)怎么用
获取Class对象
以类
public class Test() {}
为例
Class.forName("com.my.Test(完整类路径名)")
:此语句是Class的static函数,会让jvm加载某个具体的类(如果尚未加载),并返回该类的Class对象的引用。- 类的static初始化是类在第一次使用时使用的。这个描述不太准确,应该说static初始化发生在类的第一次加载时,使用以上语句会加载某个类并进行static初始化。
- 使用某个具体的对象:如
Test test = new Test()
,test.getClass()
获取该类Class对象的引用 - 直接使用类名:
Test.class
- 注意:使用这种方式不会触发类的static初始化
引用Class对象
如同
List<T>
一样,Class类型也是泛化的
- 使用
Class<T>
可以引用其类T的Class对象 - 使用
Class<? extends T>
可以引用类T及其子类的Class对象- 注意不是Class,这与List不用。后者可以用来存放T及其子类。
使用Class对象
以
Class<Interger> intClass = Integer.class
为例
intClass.newInstance()
, 使用默认构造函数(只能用无参的默认构造函数)创建一个Integer对象。intClass.cast(Long.valueof(1))
,将long强转为intintClass.isInstance("string"),
,判断入参是否是Integer或者其子类(Integer没有子类)
Class对象的
equals()
与instanceof
,都可以用来比较类型信息。但前者是严格相等的,后者包含了继承关系。比如:类A和类B(A继承自B),分别创建其对象a、b
Objects.equals(a.getClass(), A.class)
,结果为trueObjects.equals(a.getClass(), B.class)
,结果为false- a instanceof B, 结果为true
拓展应用:反射
所谓反射,就是在运行时能够获取某个类的所有成员变量和函数(包括私有方法)。依然以
Class<Interger> intClass = Integer.class
为例
- 可以看到,Class对象 + 返回类的所有成员变量和函数,就可以满足反射的需要了。而后者已经在Class对象中实现了。
- Class对象在运行中可以获取到,比如
Class.forName("路径")
,编译时并不知道"路径"对应的类型,但运行时根据Class对象就可以确认了。
- Class对象在运行中可以获取到,比如
intClass.getFields()
返回类型的所有(不含private)intClass.getMethods()
返回类型所有的成员函数(不含private)intClass.getCOnstructors()
返回类型所有的构造函数(不含private)
访问私有方法(建议不要使用):
Method m = Test.class.getDeclaredMethod("methodName")
m.setAccessible(true)
m.invoke(new Test())