运行期类型鉴定(RTTI)
概念:利用基类型的句柄判来断一个对象的真正类型
方法:
-- "传统"的RTTI,它假定我们已在编译和运行期拥有所有类型;
-- "反射"机制,利用它可在运行期独立查找类信息
对RTTI的需要
1、面向对象编程的基本目标是用大量代码控制基础类型的句柄
2、在Java中,所有造型都会在运行期间得到检查,以确保其正确性,那正是RTTI的意义所在:在运行期,对象的类型会得到鉴定
3、Class对象
作为程序一部分的每一个类,它们都有一个Class对象,换言之,每次写一个新类时,同时也会创建一个保存在完全同名的.class文件中的Class对
象
装载模块:
Class.forName(String name) -- 获取名字为name的目标类,返回一个Class对象句柄
类名.class -- 类标记方法,产生Class对象的句柄
PS:方法二会在编译期间得到检查,所以更安全些;同时它取消了对方法的调用,所以执行效率会更高
注意:类标记不仅可以应用于普通类,也可以应用于接口,数组以及基本数据类型
针对每种基本类型的封装器,还存在一个TYPE的标准字段,其作用是为相关的基本数据类型产生Class对象的句柄
对照表:
boolean.class Boolean.TYPE
char.class Character.TYPE
byte.class Byte.TYPE
short.class Short.TYPE
int.class Integer.TYPE
long.class Long.TYPE
float.class Float.TYPE
double.class Double.TYPE
void.class Void.TYPE
4、造型前的检查
instanceof -- 检验对象是否为一特定类型的实例,返回布尔值
ClassCastException -- 强制类型转换出错时跳出的异常
//package c11.petcount;
import java.util.*;
class Pet {}
class Dog extends Pet {}
class Pug extends Dog {}
class Cat extends Pet {}
class Rodent extends Pet {}
class Gerbil extends Rodent {}
class Hamster extends Rodent{}
class Counter {int i;}
public class PetCount {
static String[] typenames = {"Pet","Dog","Pug","Cat","Rodent","Gerbil","Hamster"};
public static void main(String[] args){
Vector pets = new Vector();
try{
Class[] petTypes = {
Class.forName("Dog"), //或采用标记法:Dog.class
Class.forName("Pug"), //或采用标记法:Pug.class
Class.forName("Cat"), //或采用标记法:Cat.class
Class.forName("Rodent"), //或采用标记法:Rodent.class
Class.forName("Gerbil"), //或采用标记法:Gerbil.class
Class.forName("Hamster"), //或采用标记法:Hamster.class 且不需要try语句
};
for (int i = 0; i < 15; i ++)
pets.addElement(petTypes[(int)(Math.random()*petTypes.length)].newInstance());
}catch(IllegalAccessException e){}
catch(InstantiationException e){}
catch(ClassNotFoundException e){}
Hashtable h = new Hashtable();
for (int i = 0; i < typenames.length; i ++)
h.put(typenames[i],new Counter());
for (int i = 0; i < pets.size(); i ++){
Object o = pets.elementAt(i);
if (o instanceof Pet)
((Counter)h.get("Pet")).i++;
if (o instanceof Dog)
((Counter)h.get("Dog")).i++;
if (o instanceof Pug)
((Counter)h.get("Pug")).i++;
if (o instanceof Cat)
((Counter)h.get("Cat")).i++;
if (o instanceof Rodent)
((Counter)h.get("Rodent")).i++;
if (o instanceof Gerbil)
((Counter)h.get("Gerbil")).i++;
if (o instanceof Hamster)
((Counter)h.get("Hamster")).i++;
}
for (int i = 0; i < pets.size(); i ++)
System.out.println(pets.elementAt(i).getClass().toString());
for (int i = 0; i < typenames.length; i ++){
System.out.println(typenames[i] + " Quantity :" + ((Counter)h.get(typenames[i])).i);
}
}
}
isInstance方法 -- 可动态调用instanceof运算符
RTTI语法
1、获取指向适当Class对象的一个句柄
Class.forName() -- 仅有类
getClass() -- 已有一个对象
2、Class.getInterfaces方法 -- 返回Class对象的一个数组,用于表示包含在Class对象内的接口
3、getSuperclass() -- 查询该对象的父类,返回一个Class句柄
4、Class的newInstance()方法
利用newInstance(),我们可以在没有现成对象供COPY的情况下新建一个对象,但创建的类必须有一个默认构造器
5、getName() -- 获取类名
6、isInterface -- 判断是否为接口
interface HasBatterires{}
interface Waterproof{}
interface ShootsThings{}
class Toy {
Toy(){}
Toy(int i){}
}
class FancyToy extends Toy implements HasBatterires,Waterproof,ShootsThings {
FancyToy(){
super(1);
}
}
public class ToyTest {
public static void main(String[] args){
Class c = null;
try{
c = Class.forName("FancyToy");
}catch(ClassNotFoundException e){}
printInfo(c);
Class[] faces = c.getInterfaces();
for (int i = 0; i < faces.length; i ++)
printInfo(faces[i]);
Class cy = c.getSuperclass();
Object o = null;
try{
o = cy.newInstance();
}catch(InstantiationException e){}
catch(IllegalAccessException e){}
printInfo(o.getClass());
}
static void printInfo(Class cc){
System.out.println("Class name:[" + cc.getName() + "] is interface :" + cc.isInterface());
}
}
反射:运行期类信息
1、在Java 1.1中,Class类得到了扩展,可以支持"反射"的概念,针对Field,Method以及Constructor类(每个类都实现了Memberinterface)
它们都新增了一个库:java.lang.reflect
2、方法getFields(),getMethods(),getConstructors(),分别返回用于表示字段、方法以及构造函数(Field,Method,Constructor)的对象数组
3、很少需要直接使用反射工具,之所以在语言中提供它们,仅仅是为了支持其他Java特性,比如对象序列化,Java Beans以及RMI
4、示例:一个类方法提取器
import java.lang.reflect.*;
public class ShowMethods {
static final String usage =
"usage: /n" +
"ShowMethods qualified.class.name/n" +
"To show all methods in class or: /n" +
"ShowMethods qualified.class.name word/n" +
"To search for methods involving 'word'";
public String test;
public static void main(String[] args){
if (args.length < 1){
System.out.println(usage);
System.exit(0);
}
try{
Class c = Class.forName(args[0]);
Method[] m = c.getMethods();
Field[] f = c.getFields();
Constructor[] ctor = c.getConstructors();
if (args.length == 1){
System.out.println("/nShow Methods:/n");
for (int i = 0; i < m.length; i ++)
System.out.println(m[i].toString());
System.out.println("/nShow Contructor:/n");
for (int i = 0; i < ctor.length; i ++)
System.out.println(ctor[i].toString());
System.out.println("/nShow Fields:/n");
for (int i = 0; i < f.length; i ++)
System.out.println(f[i].toString());
}
else{
for (int i = 0; i < m.length; i ++)
if (m[i].toString().indexOf(args[1]) != -1)
System.out.println(m[i].toString());
for (int i = 0; i < ctor.length; i ++)
if (ctor[i].toString().indexOf(args[1]) != -1)
System.out.println(ctor[i].toString());
for (int i = 0; i < f.length; i ++)
if (f[i].toString().indexOf(args[1]) != -1)
System.out.println(f[i].toString());
}
}catch(ClassNotFoundException e){
System.out.println("No such class: " + e);
}
}
}