第14章 类型信息

基础知识

  • 运行时候的类型信息,使得你在程序运行时发现和使用类型信息
  • RTTI: Run-Time Type Information
  • java让我们在运行时候识别对象和类型信息的两种方式:
    • 一种是传统的RTTI,它假定我们在编译时已经知道了所有的类型
    • 另外的一种是反射机制,它允许我们在运行时发现和使用类的信息
  • 下面的代码很重要:
//: typeinfo/Shapes.java
import java.util.*;

abstract class Shape {
  void draw() { System.out.println(this + ".draw()"); }
  abstract public String toString();
}

class Circle extends Shape {
  public String toString() { return "Circle"; }
}

class Square extends Shape {
  public String toString() { return "Square"; }
}

class Triangle extends Shape {
  public String toString() { return "Triangle"; }
}   

public class Shapes {
  public static void main(String[] args) {
    List<Shape> shapeList = Arrays.asList(
      new Circle(), new Square(), new Triangle()
    );
    for(Shape shape : shapeList)
      shape.draw();
  }
} /* Output:
Circle.draw()
Square.draw()
Triangle.draw()
*///:~
  • 不通过new创建类的一种方式,这种方法是通过类字面常量的方法:
Class book = Class.getInstance(Book.class);
Book realBook = book.newInstance();
  • 生成class对象应用的方法: FancyToy.class 这样做会更加的安全,因为它在编译期就会得到检查。
  • 类字面常量可以作用于普通的类,也可以作用于接口,数组,以及基本的数据类型,如下所示:
    • int.class = int.TYPE
  • 注意当使用.class来创建对象的引用的时候,并不会初始化class对象。
  • 类使用前,编译器做的准备工作:
  • 这里写图片描述

  • 初始化被延迟到了对静态方法(构造器隐式地是静态的)或者非常数静态域进行首次调用时执行

  • 下面的代码很重要:
class Initable {
  static final int staticFinal = 47;
  static final int staticFinal2 =
    ClassInitialization.rand.nextInt(1000);
  static {
    System.out.println("Initializing Initable");
  }
}

class Initable2 {
  static int staticNonFinal = 147;
  static {
    System.out.println("Initializing Initable2");
  }
}

class Initable3 {
  static int staticNonFinal = 74;
  static {
    System.out.println("Initializing Initable3");
  }
}

public class ClassInitialization {
  public static Random rand = new Random(47);
  public static void main(String[] args) throws Exception {
    Class initable = Initable.class;
    System.out.println("After creating Initable ref");
    // 没有触发初始化:
    System.out.println(Initable.staticFinal);
    // 触发初始化:
    System.out.println(Initable.staticFinal2);
    // 触发初始化:
    System.out.println(Initable2.staticNonFinal);
    Class initable3 = Class.forName("Initable3");
    System.out.println("After creating Initable3 ref");
    System.out.println(Initable3.staticNonFinal);
  }
} /* Output:
After creating Initable ref
47
Initializing Initable
258
Initializing Initable2
147
Initializing Initable3
After creating Initable3 ref
74
*///:~
  • 注意下面的用法:
Class intClass = int.class;
intClass = double.class;  //正确

//上面的做法等价于,但是使用?更优:
Class<?> intClass = int.class;
intClass = double.class;

Class<Integer> intClass2 = int.class; //正确
intClass2 = double.class //错误
  • 想class引用添加泛型语法的原因仅仅是为了提供编译期的类型检查
  • 将泛型作用于Class对象的时候,newInstance()将返回该对象的确切类型,而不再是Object。
  • 代表对象类型的是Class对象。通过查询Class对象可以获得运行时所需要的信息。
  • 在进行对象类型转型前,使用下面的语句是非常安全的:
if (x instanceof Dog)
    ((Dog)x).bark();
  • **instanceof 与 ==
  • 在大多数情况下,instanceof 与==是等价的,但是instanceof 在比较两个对象的时候,是站在整个类的继承体系的角度去比较的,==只是单纯的比较两个对象
  • 反射
    -如果你不知道对象的确切类型,RTTI可以告诉你。但是有一些限制条件:这个类在编译时候已经知道,这样才能RTTI识别他,并利用这些信息做一些事情。

  • class与java.lang.reflect类库一起对反射的概念进行了支持。其中重要的类:Constructor, Method, 与Feild类。

  • RTTI和反射真正的区别在于:
    • RTTI:在编译时打开和检查.class文件
    • 反射机制: .class文件在编译时,是不可获取的,在运行时候打开和检查.class文件
    • Class.forName()生成的结果在编译的时候是不可知的。
    • 反射是一个强大的工具,可以改变方法属性的访问权限。
    • 代理:它是你为了加入额外的操作,而生成的用来代替实际对象的对象.
    • -
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值