跳转至

类型信息

运行时类型信息使得你可以在程序运行时发现个使用类型信息 主要有两种方式 1. 传统的RTTI:假定我们在编译时已经知道了所有的类型 2. 反射:允许我们在运行时发现和使用类的信息

为什么需要RTTI

  1. RTTI名字的含义:在运行时,识别一个对象的类型

Class对象

  • 它包含了与类有关的信息
  • 每一个类都有一个Class对象->Class对象是被保存在一个同名的.class文件
  • 为了生成这个类的对象,运行这个程序的JVM将使用被称为“类加载器“的子系统
  • 所有的类都是在对其第一次使用时,动态加载到JVM中
  • 当程序创建第一个对类的静态成员引用时,就会加载这个类

    构造器也是类的静态方法,即使在构造器前没有使用static关键字。因此,使用new操作符创建类的新对象也会被当作对类的静态成员引用。

  • 其余各个部分实在必需时才加载

  • 创建的过程:
    1. 首先检查这个类的Class对象是否已经加载
      1. 如果尚未加载,默认的类加载器就会根据类名查找.class文件
    2. 在这个类的字节码被加载时,他们会接受验证,确保其没有被破坏、并且不包含不良的java代码
    3. 一旦某个类的Class对象被载入内存,他就被用来创建这个类的所有对象
  • Class对象的基本操作:
    1. forName()
      1. 参数:String
      2. 返回值:一个Class对象的引用
      3. 如果找不到要加载的类,及抛出异常ClassNotFoundException
      4. 如果已经拥有了一个类型的对象,就可以通过调用getClass()方法来取得Class的引用,这个方法属于Object的一部分
      5. 在传递给forName()的字符串中,必须使用全限定名(包含包名)
    2. getName()
      1. 产生全限定的类名
      2. 分别使用getSimpleName()getCanonicalName()来产生是否完整的类名
    3. isInterface()
      1. 是否是一个接口
    4. getSUperclass()
      1. 查询其直接基类
      2. 可以在运行时发现一个对象完整的类继承结构
    5. newInstance()
      • 实现虚拟构造器的一种途径
      • 使用newInstance()来创建的类,必须带有默认的构造器 类的加载过程

类字面常量

  • 另一种生成对Class对象的引用:对象.class
  • 优势:
    1. 更简单
    2. 更安全
    3. 更高效
    4. 适用范围:
      1. 普通的类
      2. 接口、数组以及基本数据类型
      3. 对于基本数据类型的包装器类还有一个标准字段TYPE:TYPE字段是一个引用,指向对应的基本数据类型的Class对象

泛化的Class引用

  • Class<Integer> IntegerClass = int.class
  • 通过使用泛型语法,可以让编译器强制执行额外的类型检查
  • 可以使用通配符?来表示任何事物:Class<?> class = something.class
    1. Class<?>Class等价,但优于后者
    2. 表示你并非是碰巧或者由于疏忽,而使用了一个非具体的引用
  • 将通配符与extends结合,限定一个范围:Class<? extends SuperClass> class = something.class
  • newInstance()将返回对象的确切类型

新的转型语法:cast()

  • cast()方法接受参数对象,将其转型为Class引用的类型
  • 类 a = classname.cast(b)

instanceof与Class的等价性

  1. instanceof()isInstance()等价
  2. ==equals()等价
  3. instanceof()保持了类型的概念,指:你是这个类嘛?或你是这个类的派生类嘛?
  4. ==比较实际的对象,不考虑继承

反射:运行时的类信息

  • RTTI的限制:这个类型在编译时必须一致,这样才能使用RTTI识别它,并利用这些信息做一些有用的事
  • 运行时获得类的信息的另一个动机:远程方法调用(RMI)

  • java.lang.reflect

    1. Class类与java.lang.reflect类库一起对反射的概念进行了支持
    2. Field
      1. Class.getFields():返回字段的对象数组
        • 不能得到私有的属性
      2. 使用get() set()方法读取和修改与Field对象关联的字段
    3. Method
      1. Class.getMethod():返回方法的对象数组
      2. 使用invoke()方法对用与Method对象关联的方法
    4. Constructor
      1. Class.getConstructors():返回构造器的对象数组
      2. Class.getConstructor():在()可以指定构造器参数类型,空即返回无参构造器
      3. 使用Constructor创建新的对象
  • Class.forName()生成的结果在编译时是不可知的,因此所有方法特征签名信息都是在执行时被提取出来
  • 优点和缺点
    1. 优点:可以动态的创建和使用对象(也是框架底层核心)使用灵活
    2. 使用反射基本是解释执行,对执行速度有影响
  • 反射对用优化——关闭访问检查
    1. MethodFieldConstructor对象都有setAccessible()方法
      1. setAccessible():启动和禁用访问安全检查的开关
      2. 参数值为true表示反射的对象在使用时取消访问检查,提高反射的效率
    2. java反射真的很慢吗_哔哩哔哩_bilibili