『On Java 8』读书笔记 (五) : 类型信息、泛型

类型信息

RTTI(RunTime Type Information,运行时类型信息)能够在程序运行时发现和使用类型信息。

Java在运行时,识别对象和类信息,主要有两种方式:

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

Class 对象

运行时的类型信息,由Class对象表示。每一个类都有一个Class对象。

当生成类对象时,JVM会先调用类加载器,将类加载到内存中。

所有的类都是第一次使用时,动态加载到 JVM 中的。当程序创建第一个对类的静态成员的引用时,就会加载这个类。

类加载器首先会检查这个类的 Class 对象是否已经加载,如果尚未加载,默认的类加载器就会根据类名查找 .class 文件。这个类的字节码被加载后,JVM 会对其进行验证,确保它没有损坏,并且不包含不良的 Java 代码。

想在运行时使用类型信息,必须先得到Class引用。Class.forName(全限定类名) 或者 对象.getClass()

另外一种获取类对象引用的方法是,类字面常量。例如Status.calss。当使用.calss时,不会自动初始化该Class对象。直到第一次引用static方法或非常量(非final)的static字段,才会进行类初始化。

一般类的初始化分三个步骤:

  1. 加载。类加载器,查找字节码,从字节码中创建Class对象。
  2. 链接。验证字节码,为static字段分配存储空间,并且解析类中创建的对其他类的引用。
  3. 初始化。如果有超类,先初始化超类。

Class 泛型

Class intClass = int.class;
Class<Integer> genericIntClass = int.class;
 
// 为了使用Class对象时,放松限制,可使用通配符。通配符就是 ?,表示“任何事物”。
Class<?> intClass = int.class;
复制代码

反射

Class 支持反射操作, java.lang.reflect 库中包含类 FieldMethodConstructor。这些类型的对象由 JVM 在运行时创建,以表示未知类中的对应成员。

Constructor 用于创建新对象,get()set() 方法读取和修改与 Field 对象关联的字段,invoke() 方法调用与 Method 对象关联的方法。

此外,还可以调用便利方法 getFields()getMethods()getConstructors() 等,以返回表示字段、方法和构造函数的对象数组。因此,匿名对象的类信息可以在运行时完全确定,编译时不需要知道任何信息。

泛型

多态是一种面向对象思想的泛化机制。

简单泛型

促成泛型出现的最主要的动机之一是为了创建集合类。约定集合要存储什么类型的对象,并且通过编译器确保规约得以满足。避免了手动类型转化。

List<String> list = new ArrayList<>();
list.add("abc");
复制代码

泛型也同样适用于接口方法

泛型擦除

编译后,泛型就会被擦除掉,例如List<String>编译后会变为List。所以实际上,Java编译后,是没有泛型这一概念的。

Class c1 = new ArrayList<String>().getClass();
Class c2 = new ArrayList<Integer>().getClass();
System.out.println(c1 == c2); // true
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享