Java类型信息

Java编程思想学习笔记

类型信息

面向对象编程的基本目的是:让代码只操纵对基类的引用。这样,如果需要添加一个新类来扩展程序,就不会影响到原来的代码。因此我们一般都会利用动态绑定(多态):创建一个具体对象,然后将它向上转型为基类(接口),然后统一操作基类(接口)的引用。

但有时确实需要知道某个泛化引用的确切类型,这时就需要用到RTTI。在Java中使用RTTI可以有三种形式:

  • 强制类型转换(Shape)obj
  • 关键字instanceof
  • class对象

Class对象

在java中使用被称为“Class对象”的特殊对象来保存与类有关的信息。每个类都有一个Class对象,每当编写并编译了一个新类时,就会产生一个Class对象(保存在同名的.class文件中)。在运行时,JVM使用“类加载器”子系统加载这个类的Class对象,一旦该类的Class对象被载入内存,它就会被用来创建这个类的所有对象。

获取Class对象的引用

无论何时,只要想在运行时使用类型信息,就必须首先获得对该类的Class对象的引用。Class对象引用的获取方法有三种:

  • obj.getClass()方法

    如果已经有了一个感兴趣的类型的对象,可以调用obj.getClass()方法来获取Class对象的引用。

  • Class.forName()

    使用obj.getClass必须首先持有一个感兴趣的类型的对象,而使用Class.forName不需要持有对象。该函数接收一个字符串,该字符串是感兴趣的类型的全限定名(包括包名)。

  • 类字面常量

    Java还提供了类字面常量来生成对Class对象的引用:Class.class。使用类字面常量会在编译时就收到检查,因而会更安全,不需要置于try块中。另外,它根除了对forName()方法的调用,效率也更高。一般会直接使用类字面常量。

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

Class对象的方法

Class包含很多有用的方法,下面列举几个:

newInstance() 用于制造一个该类的实例,注意,这个方法只能调用该类的无参构造器,因此该类也必须有一个无参构造器

getName() 产生该类型的全限定类名

getInterfaces() 返回Class对象,表示在感兴趣的Class对象中包含的接口

isInterface() 返回这个Class对象是否表示某个接口

泛化的Class引用

所有的Class对象是Class类(区别于class关键字)的某个实例,在Java SE5后,允许使用泛型语法对Class引用所指向的Class对象的类型进行限定。如下:

public class GenericClassReferences {
	public static void main(String[] args) {
		Class intClass = int.class;
		Class<Integer> genericIntClass = int.class;
		intClass = double.class;
		// genericIntClass = double.class // Illegal
	}
}

如上所示,通过泛型可以让编译器强制执行额外的类型检查。向Class引用添加泛型语法的原因就是为了提供编译期的类型检查。

若要在使用泛化的Class引用时放宽限制,可以使用通配符,如下:

public class WildcardClassReferences {
	public static void main(String[] args) {
		Class<?> intClass = int.class;
		intClass = double.class;
	}
}

Class<?>与普通的Class作用是等价的,但是好处是:表示并非是碰巧或由于疏忽,而使用了一个非具体的类的引用。

注意,放宽限制时不可以使用如下方法:

Class<Number> genericNumberClass = int.class;

尽管Integer继承自Number,但是Class Integer并非继承自Class Number,因此这种方法不可行。若需要为Class引用加以限定,限定为某种类型或该类型的任何子类型,可以使用通配符与extends关键字结合,如:

Class<? extends Number> genericNumberClass = int.class;

猜你喜欢

转载自my.oschina.net/u/2561528/blog/1793513