相关基础知识的博文:Java语言程序设计-进阶篇(二)泛型
一、什么是RTTI,为什么需要RTTI
RTTI全称为Run-Time Type Identification,运行阶段类型识别,含义就是在运行时,识别一个对象的类型。他使得从只能从编译期执行面向对象类型的操作的禁锢中解脱出来,并且可以使用某些非常强大的程序。RTTI有三种形式。
- 传统的类型转换,由RTTI确保类型转换的正确性,如果执行了错误的类型转换,会抛出一个ClassCastException的异常。
- 代表对象类型的Class对象,通过查询Class对象获取所需要的信息
- 类型转换前用instanceof检查
二、传统类型转换
package classtest; import java.util.Arrays; import java.util.List; abstract class Shape { void drow(){ 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> list = Arrays.asList( new Circle(), new Square(), new Triangle()); for(Shape s:list){ s.drow(); } } }
//输出结果: circle draw() Square draw() Triangle draw()
基类中通过this将类型参数传递给print,然后调用对应的toString方法,这也是多态的含义。
三、通过Class对象来执行RTTI
1.class对象
Class对象包含了与类型有关的信息,Java使用Class对象来执行RTTI。每个类都有一个Class对象,所有的Class对象都属于Class这个类。这个类有一些常用的方法如下:
- Class.forName("classname"),获取classname类对应的Class对象的引用,try/catch环绕
- getName()
- getSimpleName()
- getCanonicalName()
- getInterfaces()
- getSuperclass()
- newInstance(),try/catch环绕,通过对应的Class对象的引用获取一个classname类的实例
- getclass(),通过classname类的实例获取Class对象的引用
2.类字面常量.class以及与class.forname的区别
获取一个Class对象的引用,出了上面提到两种方法外,还可以通过classname.class来获取。这种获取方法称为类字面常量。这样做不仅简单,而且更加安全,因为他在编译期就得到了检查。所以也不用try/catch来环绕。
另外,还有一点区别就是使用.class来创建Class对象的引用时,不会自动地初始化该Class对象。
3.泛型与Class对象
传统创建一个引用的方法是
- Class intClass = int.class
这样没有泛型的限制,后面intClass=double.class也会通过编译。所以应该使用下面的语法
- Class<Integer> intClass = int.class
- Class<? extends Number> intClass = int.class
- Class<?> intClass = int.class //该方法与传统方法的区别是,你告诉别人你是故意这么做的。
4.泛型类的语法
package classtest; import java.util.*; class Counter{ private static int count; private final int id = count++; public String toString(){ return Integer.toString(id); } } public class FilledList<T> { private Class<T> type; public FilledList(Class<T> type){this.type=type;}//这里不能写成public FilledList<T> public List<T> create(int n){ List<T> list = new ArrayList<T>(); try{ for(int i=0;i<n;i++){ list.add(type.newInstance()); } }catch(Exception e){throw new RuntimeException(e);} return list; } public static void main(String[] args){ FilledList<Counter> f =new FilledList<Counter>(Counter.class); System.out.println(f.create(15)); } }
该语法实现了存储了一个类引用,然后又产生了一个List,填充这个List的对象是使用的newInstance()的方法。
//输出结果: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
四、instanceof与新转型语法
RTTI的第三种形式是用关键字instanceof,在强制向下转型前使用instanceof是很有用的
if(x instanceof Dog) (Dog)x.bark();此外。Class类的cast()方法和asSubclass()两个SE5的新特性基本上没有任何用处。