美文网首页Java编程思想
Java编程思想——第十四章:类型信息

Java编程思想——第十四章:类型信息

作者: 代夫阿普曼 | 来源:发表于2019-06-06 22:14 被阅读0次

运行时类型信息使得你可以在程序运行时发现和使用类型信息。

Java让我们能在运行时识别对象和类的信息的两种方式:

  1. 传统的RTTI:它假定我们在编译时已经知道了所有的类型;
  2. 反射机制:它允许我们在运行时发现和使用类信息。

1.为什么需要RTTI

  • 当把 Shape 对象放入 List<Shape>的数组时会向上转型。但在向上转型为 Shape 的时候也丢失了 Shape对象 的具体类型。对于数组而言,它们只是 Shape 类的对象。

    当从数组中取出元素时,这种容器—实际上他将所有的事物当作 Object 持有—会自动将结果转型回 Shape 。这是RTTI最基本的使用形式,因为在Java中,所有类型转换都是在运行时进行正确性检查的。

    接下来就是多态机制的事情了,Shape 对象实际执行什么样的代码,是由引用所指向的具体对象 CircleSquareTriangle 而决定的。你希望大部分代码尽可能地了解对象的具体类型,而是只与对象家族的一个通用表示打交道。

2.Class对象

Class对象就是用来创建类的所有的常规对象。

类似程序的一部分,每一个类都有一个Class对象。为了生成这个类的对象,运行这个程序的Java虚拟机将使用被称为 类加载器 的子系统。

Class.forName() 可以获取Class对象的引用。getName()产生全限定的类名,并分别使用 getSimpleName()getCanonicalName() 来产生不含包名的类名和全限定名。isInterface() 可以告诉你这个Class对象是否表示某个接口。还可以使用 getSuperclass() 方法查询其直接基类。

2.1 类字面常量
  • 使用字面常量也可以生成对Class对象的引用

    FancyToy.class
    

    类字面常量不仅可以应用于普通的类,也可以应用于接口、数组以及基本数据类型。

    当使用 .class 来创建对Class对象的引用时,不会自动地初始化该Class对象。为使用类而做的准备工作实际包含三个步骤:

    1. 加载:这是由类加载器执行的;
    2. 链接:在链接阶段将验证类中的字节码,为静态域分配存储空间,并且如果必须的话,将解析这个类创建的对其他类的所有引用。
    3. 初始化:如果该类具有超类,则对其初始化,执行静态初始化其和静态初始化块。
  • Class.forName() 会立即执行初始化;

2.2 泛化的Class引用
  • Class引用总是指向某个Class对象,它可以制造类的示例,并包含可作用与这些实例的所有方法代码。它还包含该类的静态成员,因此,Class引用表示的就是它所指向的对象的确切类型。而该对象便是Class类的一个对象。

    尽管泛型类引用只能赋值为指向其声明的类型,但是普通类引用可以被重新赋值为指向任何其他的Class对象。通过泛型语法可以让编译器强制执行额外的类型检查。

  • 使用通配符 ? 放松限制,?代表任何事物。

    Class<?> intClass = int.class;
    

    限定创建Class引用的范围

    Class<? extends Numner> bounded = int.class;
    Class<? super FancyToy> up = ftClass.getSuperclass();
    
  • newInstance() 返回的不是精确类型,而只是Object。

2.3 新的转型语法
  • cast()用于Class引用的转型语法,新的转型语法对于无法使用普通转型的情况显得非常有用。

3.类型转换前先做检查

RTTI的第三种形式,就是关键字 instanceof。它返回一个布尔值,告诉我们对象是不是某个特定类型的实例。

3.1 使用类字面量
3.2 动态的 instanceof
  • Class.isInstance 方法提供了一种动态地测试对象的途径。
3.3 递归计数

4 注册工厂

  • 使用 工厂方法 设计模式,将对象的创建工作交给类自己去完成。

5.instanceof与Class的等价性

6.反射:运行时的类信息

  • 如果不知道某个对象的确切类型,RTTI可以告诉你。但这个类型在编译时必须已知。
  • 人们想要在运行时获取类的信息的另一动机,便是希望提供在跨网络的远程平台上创建和运行对象的能力。这种被称为远程方法调用,它允许一个Java程序将对象分布到多台机器上。
  • RTTI和反射之间真正的区别在于:对于RTTI来说,编译器在编译时打开和检查 .class 文件。而对于反射机制来说,在运行时打开和检查 .class 文件。

7.动态代理

  • Java的动态代理比代理的思想更向前迈进一步,因为它可以动态创建代理并动态地处理对所代理方法的调用。在动态代理上所做的所有调用都会被重定向到单一的调用处理器上,它的工作室揭示调用的类型并确定相应的对策。

8.空对象

空对象最有用支出在于它更靠近数据,因为对象表示的是问题空间内的实体。

8.1 模拟对象与桩
  • 空对象的逻辑变体是模拟对象和桩。与空对象一样,它们都表示在最终的程序中所使用的实际对象。

    模拟对象和桩之间的差异在于程度不同。模拟对象往往是轻量级和自测试的,通常很多模拟对象被创建出来是为了处理各种不同的测试情况。桩只是返回桩数据,它通常是重量级的。

9.接口与类型信息

  • interface关键字的一种重要目标就是允许程序员隔离构建,进而降低耦合性。如果你编写接口,那么就可以实现这一目标,但是通过类型信息,这种耦合性还是会传播出去——接口并非是对解耦的一种无懈可击的保障。最简单的解决方式是对实现使用包访问权限。


06/06/2019 :created

相关文章

网友评论

    本文标题:Java编程思想——第十四章:类型信息

    本文链接:https://www.haomeiwen.com/subject/ifdpxctx.html