rtti在java造型前的查抄
迄今为止,我们已知的RTTI形式包罗:
(1) 经典造型,如"(Shape)",它用RTTI确保造型的正确性,并在碰着一个失败的造型后发生一个ClassCastException违例。
(2) 代表工具范例的Class工具。可查询Class工具,获取有用的运行期资料。
在C++中,经典的"(Shape)"造型并不执行RTTI。它只是简朴地汇报编译器将工具看成新范例处理惩罚。而Java要执行范例查抄,这凡是叫作“范例安详”的下溯造型。之所以叫“下溯造型”,是由于类分层布局的汗青分列方法造成的。若将一个Circle(圆)造型到一个Shape(几许形状),就叫做上溯造型,因为圆只是几许形状的一个子集。反之,若将Shape造型至Circle,就叫做下溯造型。然而,尽量我们明晰知道Circle也是一个Shape,所以编译器可以或许自动上溯造型,但却不能担保一个Shape必定是一个Circle。因此,编译器不答允自动下溯造型,除非明晰指定一次这样的造型。
RTTI在Java中存在三种形式。要害字instanceof汇报我们工具是不是一个特定范例的实例(Instance即“实例”)。它会返回一个布尔值,以便以问题的形式利用,就象下面这样:
if(x instanceof Dog)
((Dog)x).bark();
将x造型至一个Dog前,上面的if语句会查抄工具x是否从属于Dog类。举办造型前,假如没有其他信息可以汇报本身工具的范例,那么instanceof的利用长短常重要的——不然会获得一个ClassCastException违例。
我们最一般的做法是查找一种范例(好比要酿成紫色的三角形),但下面这个措施却演示了如何用instanceof标志出所有工具。
//: PetCount.java // Using instanceof 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("c11.petcount.Dog"), Class.forName("c11.petcount.Pug"), Class.forName("c11.petcount.Cat"), Class.forName("c11.petcount.Rodent"), Class.forName("c11.petcount.Gerbil"), Class.forName("c11.petcount.Hamster"), }; for(int i = 0; i < 15; i++) pets.addElement( petTypes[ (int)(Math.random()*petTypes.length)] .newInstance()); } catch(InstantiationException e) {} catch(IllegalAccessException 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); } } ///:~
在Java 1.0中,对instanceof有一个较量小的限制:只可将其与一个已定名的范例较量,不能同Class工具作比拟。在上述例子中,各人大概以为将所有那些instanceof表达式写出来是件很贫苦的工作。实际环境正是这样。但在Java 1.0中,没有步伐让这一事情自动举办——不能建设Class的一个Vector,再将其与之较量。各人最终会心识到,如编写了数量浩瀚的instanceof表达式,整个设计都大概呈现问题。
虽然,这个例子只是一个构思——最亏得每个范例里添加一个static数据成员,然后在构建器中令其增值,以便跟踪计数。编写措施时,各人大概想象本身拥有类的源码节制权,可以或许自由窜改它。但由于实际环境并非老是这样,所以RTTI显得出格利便。
1. 利用类标志
PetCount.java示例可用Java 1.1的类标志重写一遍。获得的功效显得越发明晰易懂:
//: PetCount2.java // Using Java 1.1 class literals package c11.petcount2; 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 PetCount2 { public static void main(String[] args) { Vector pets = new Vector(); Class[] petTypes = { // Class literals work in Java 1.1+ only: Pet.class, Dog.class, Pug.class, Cat.class, Rodent.class, Gerbil.class, Hamster.class, }; try { for(int i = 0; i < 15; i++) { // Offset by one to eliminate Pet.class: int rnd = 1 + (int)( Math.random() * (petTypes.length - 1)); pets.addElement( petTypes[rnd].newInstance()); } } catch(InstantiationException e) {} catch(IllegalAccessException e) {} Hashtable h = new Hashtable(); for(int i = 0; i < petTypes.length; i++) h.put(petTypes[i].toString(), new Counter()); for(int i = 0; i < pets.size(); i++) { Object o = pets.elementAt(i); if(o instanceof Pet) ((Counter)h.get( "class c11.petcount2.Pet")).i++; if(o instanceof Dog) ((Counter)h.get( "class c11.petcount2.Dog")).i++; if(o instanceof Pug) ((Counter)h.get( "class c11.petcount2.Pug")).i++; if(o instanceof Cat) ((Counter)h.get( "class c11.petcount2.Cat")).i++; if(o instanceof Rodent) ((Counter)h.get( "class c11.petcount2.Rodent")).i++; if(o instanceof Gerbil) ((Counter)h.get( "class c11.petcount2.Gerbil")).i++; if(o instanceof Hamster) ((Counter)h.get( "class c11.petcount2.Hamster")).i++; } for(int i = 0; i < pets.size(); i++) System.out.println( pets.elementAt(i).getClass().toString()); Enumeration keys = h.keys(); while(keys.hasMoreElements()) { String nm = (String)keys.nextElement(); Counter cnt = (Counter)h.get(nm); System.out.println( nm.substring(nm.lastIndexOf('.') + 1) + " quantity: " + cnt.i); } } } ///:~
#p#分页标题#e#
在这里,typenames(范例名)数组已被删除,改为从Class工具里获取范例名称。留意为此而特别做的事情:譬喻,类名不是Getbil,而是c11.petcount2.Getbil,个中已包括了包的名字。也要留意系统是可以或许区分类和接口的。
也可以看到,petTypes的建设模块不需要用一个try块困绕起来,因为它会在编译期获得查抄,不会象Class.forName()那样“掷”出任何违例。
Pet动态建设好今后,可以看到随机数字已获得了限制,位于1和petTypes.length之间,并且不包罗零。那是由于零代表的是Pet.class,并且一个普通的Pet工具大概不会有人感乐趣。然而,由于Pet.class是petTypes的一部门,所以所有Pet(宠物)城市算入计数中。
2. 动态的instanceof
Java 1.1为Class类添加了isInstance要领。操作它可以动态挪用instanceof运算符。而在Java 1.0中,只能静态地挪用它(就象前面指出的那样)。因此,所有那些烦人的instanceof语句都可以从PetCount例子中删去了。如下所示:
//: PetCount3.java // Using Java 1.1 isInstance() package c11.petcount3; 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 PetCount3 { public static void main(String[] args) { Vector pets = new Vector(); Class[] petTypes = { Pet.class, Dog.class, Pug.class, Cat.class, Rodent.class, Gerbil.class, Hamster.class, }; try { for(int i = 0; i < 15; i++) { // Offset by one to eliminate Pet.class: int rnd = 1 + (int)( Math.random() * (petTypes.length - 1)); pets.addElement( petTypes[rnd].newInstance()); } } catch(InstantiationException e) {} catch(IllegalAccessException e) {} Hashtable h = new Hashtable(); for(int i = 0; i < petTypes.length; i++) h.put(petTypes[i].toString(), new Counter()); for(int i = 0; i < pets.size(); i++) { Object o = pets.elementAt(i); // Using isInstance to eliminate individual // instanceof expressions: for (int j = 0; j < petTypes.length; ++j) if (petTypes[j].isInstance(o)) { String key = petTypes[j].toString(); ((Counter)h.get(key)).i++; } } for(int i = 0; i < pets.size(); i++) System.out.println( pets.elementAt(i).getClass().toString()); Enumeration keys = h.keys(); while(keys.hasMoreElements()) { String nm = (String)keys.nextElement(); Counter cnt = (Counter)h.get(nm); System.out.println( nm.substring(nm.lastIndexOf('.') + 1) + " quantity: " + cnt.i); } } } ///:~
#p#分页标题#e#
可以看到,Java 1.1的isInstance()要领已打消了对instanceof表达式的需要。另外,这也意味着一旦要求添加新范例宠物,只需简朴地改变petTypes数组即可;毋需窜改措施剩余的部门(但在利用instanceof时却是必须的)。