类型信息
运行时类型信息使得你可以在程序运行时发现个使用类型信息 主要有两种方式 1. 传统的RTTI:假定我们在编译时已经知道了所有的类型 2. 反射:允许我们在运行时发现和使用类的信息
为什么需要RTTI
- RTTI名字的含义:在运行时,识别一个对象的类型
Class对象
- 它包含了与类有关的信息
- 每一个类都有一个Class对象->Class对象是被保存在一个同名的.class文件中
- 为了生成这个类的对象,运行这个程序的JVM将使用被称为“类加载器“的子系统
- 所有的类都是在对其第一次使用时,动态加载到JVM中
-
当程序创建第一个对类的静态成员引用时,就会加载这个类
构造器也是类的静态方法,即使在构造器前没有使用static关键字。因此,使用new操作符创建类的新对象也会被当作对类的静态成员引用。
-
其余各个部分实在必需时才加载
- 创建的过程:
- 首先检查这个类的Class对象是否已经加载
- 如果尚未加载,默认的类加载器就会根据类名查找
.class
文件
- 如果尚未加载,默认的类加载器就会根据类名查找
- 在这个类的字节码被加载时,他们会接受验证,确保其没有被破坏、并且不包含不良的java代码
- 一旦某个类的Class对象被载入内存,他就被用来创建这个类的所有对象
- 首先检查这个类的Class对象是否已经加载
- Class对象的基本操作:
forName()
- 参数:String
- 返回值:一个Class对象的引用
- 如果找不到要加载的类,及抛出异常
ClassNotFoundException
- 如果已经拥有了一个类型的对象,就可以通过调用
getClass()
方法来取得Class的引用,这个方法属于Object
的一部分 - 在传递给
forName()
的字符串中,必须使用全限定名(包含包名)
getName()
- 产生全限定的类名
- 分别使用
getSimpleName()
和getCanonicalName()
来产生是否完整的类名
isInterface()
- 是否是一个接口
getSUperclass()
- 查询其直接基类
- 可以在运行时发现一个对象完整的类继承结构
newInstance()
- 实现虚拟构造器的一种途径
- 使用
newInstance()
来创建的类,必须带有默认的构造器
类字面常量
- 另一种生成对Class对象的引用:
对象.class
- 优势:
- 更简单
- 更安全
- 更高效
- 适用范围:
- 普通的类
- 接口、数组以及基本数据类型
- 对于基本数据类型的包装器类还有一个标准字段
TYPE
:TYPE字段是一个引用,指向对应的基本数据类型的Class对象
泛化的Class引用
Class<Integer> IntegerClass = int.class
- 通过使用泛型语法,可以让编译器强制执行额外的类型检查
- 可以使用通配符
?
来表示任何事物:Class<?> class = something.class
Class<?>
与Class
等价,但优于后者- 表示你并非是碰巧或者由于疏忽,而使用了一个非具体的引用
- 将通配符与
extends
结合,限定一个范围:Class<? extends SuperClass> class = something.class
newInstance()
将返回对象的确切类型
新的转型语法:cast()
cast()
方法接受参数对象,将其转型为Class引用的类型类 a = classname.cast(b)
instanceof与Class的等价性
instanceof()
与isInstance()
等价==
与equals()
等价instanceof()
保持了类型的概念,指:你是这个类嘛?或你是这个类的派生类嘛?==
比较实际的对象,不考虑继承
反射:运行时的类信息
- RTTI的限制:这个类型在编译时必须一致,这样才能使用RTTI识别它,并利用这些信息做一些有用的事
-
运行时获得类的信息的另一个动机:远程方法调用(RMI)
-
java.lang.reflect
- Class类与java.lang.reflect类库一起对反射的概念进行了支持
Field
类Class.getFields()
:返回字段的对象数组- 不能得到私有的属性
- 使用
get()
set()
方法读取和修改与Field对象关联的字段
Method
类Class.getMethod()
:返回方法的对象数组- 使用
invoke()
方法对用与Method对象关联的方法
Constructor
类Class.getConstructors()
:返回构造器的对象数组Class.getConstructor()
:在()可以指定构造器参数类型,空即返回无参构造器- 使用Constructor创建新的对象
Class.forName()
生成的结果在编译时是不可知的,因此所有方法特征签名信息都是在执行时被提取出来- 优点和缺点
- 优点:可以动态的创建和使用对象(也是框架底层核心)使用灵活
- 使用反射基本是解释执行,对执行速度有影响
- 反射对用优化——关闭访问检查
Method
、Field
、Constructor
对象都有setAccessible()
方法setAccessible()
:启动和禁用访问安全检查的开关- 参数值为true表示反射的对象在使用时取消访问检查,提高反射的效率
- java反射真的很慢吗_哔哩哔哩_bilibili