Think in java(五)RTTI的的三种形式、类型信息、class.forname与.class的区别

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


猜你喜欢

转载自blog.csdn.net/duan_2018/article/details/79859354