美文网首页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