相关基础知识的博文: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的新特性基本上没有任何用处。