现在的位置: 首页 > 综合 > 正文

学习笔记之RTTI

2018年02月07日 ⁄ 综合 ⁄ 共 7092字 ⁄ 字号 评论关闭

运行期类型鉴定(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);                    
     }                                                                     
    }                                                                             
   }                                                                                     

 

抱歉!评论已关闭.