Java类型信息
package RTTI; public class SweetShop { public static void main(String[] args) { System.out.println("inside main"); new Candy(); System.out.println("After creating Candy"); try { Class.forName("RTTI.Gum"); }catch (ClassNotFoundException e){ System.out.println(e); } System.out.println("After Class.forName(\"Gum\")"); new CooKie(); System.out.println("After creating Cookie"); } } class Candy{ static { System.out.println("Loading Candy"); } } class CooKie{ static { System.out.println("Loading Cookie"); } } class Gum { static { System.out.println("Loading Gum"); } }
static子句,static初始化是在类加载时进行的。
Class.forName();取得Class对象的引用的一种方法,它是用一个包含目标类的文本名的String作输入参数,返回一个Class对象的引用。如果类还没有被加载就加载它。在传递给forNam()的字符串中,你必须使用权限定名(包含包名)
Class对象使用getName()来产生全限定的类名,并分别使用getSimpleName()和getCanonicalName()来产生不含包名的类名和全限定的类名。isInterface()方法如同其名,可以告诉你这个Class对象是否表示某个接口。因此,通过Class对象,你可以发现你想要了解的类型的所有信息。
在main()中调用的Class.getInterfaces()方法返回的是Class对象,它们表示在感兴趣的Class对象中所包含的接口。
如果你有一个Class对象,还可以使用getSuperclass()方法查询其直接基类,这将返回你可以用来进一步查询的Class对象。因此,你可以在运行时发现一个对象完整的类继承结构。
Class的newInstance()方法是实现“虚拟构造器”的一种途径,虚拟构造器允许你声明:“我不知道你的确切类型,但是无论如何要正确地创建你自己。”在前面的示例中,up仅仅是一个Class引用,在编译期不具备任何更近一步的类型信息,当你创建新实例时,会得到Object引用,但是这个引用指向的是Toy对象。当然,在你可以发送Object能够接收的消息之外的任何消息之前,你必须更多地了解它,并执行某种转型。另外,使用newInstance()来创建的类,必须带有默认的构造器。
package RTTI; interface HasBatteries{} interface Waterproof{} interface Shoots{} class Toy{ Toy(){} Toy(int i){} } class FancyToy extends Toy implements HasBatteries,Waterproof,Shoots{ FancyToy(){super(1);} } public class ToyTest { static void printInfo(Class cc){ System.out.println("Class name:"+cc.getName()+" is interface?["+cc.isInterface()+"]"); System.out.println("Simple name: "+cc.getSimpleName()); System.out.println("Canonical name: "+cc.getCanonicalName()); } public static void main(String[] args) { Class c=null; try{ c=Class.forName("RTTI.FancyToy"); }catch (ClassNotFoundException e){ System.out.println("Can't find FancyToy"); System.exit(1); } printInfo(c); for(Class face:c.getInterfaces()) printInfo(face); Class up=c.getSuperclass(); Object obj=null; try{ obj=up.newInstance(); }catch (InstantiationException e){ System.out.println("Cannot instantiate"); System.exit(1); }catch (IllegalAccessException e){ System.out.println("Cannot access"); System.exit(1); } printInfo(obj.getClass()); } }
在ToyTest.java中,将Toy的默认构造器注释掉,并解释发生的现象
up.newInstance()发生异常,异常类型InstantiationException,输出:Cannot instantiate
将新的interface加到ToyTest.java中,看看这个程序是够能够正确检测出来并加以显示
不能,不知道为啥
将Rhomboid加入Shapes.java中。创建一个Rhomboid,将其向上转型为Shape,然后向下转型回Rhomboid。试着将其向下转型成Circle,看看会发生什么。
package RTTI;
import java.util.Arrays;
import java.util.List;
abstract class Shape {
void draw(){
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> shapeList= Arrays.asList(
new Circle(),new Square(),new Triangle()
);
for(Shape shape:shapeList){
shape.draw();
}
}
}
如果某个对象出现在字符串表达式中(涉及“+”和字符串对象的表达式),toString()方法就会被自动调用,以生成表示该对象的String。
如果不重写toString()的话,就会输出对象的地址
toString()被声明为abstract,以此强制继承者覆写该方法,并可以防止对无格式的SHape的实例化。
在本例中,当把Shape对象放入List<Shape>的数组时会向上转型。但在向上转型为Shape的时候也丢失了Shape对象的具体类型。对于数组而言,他们知识Shape类的对象。
当从数组中取出元素时,这种容器--实际上他将所有的事物都当做Object持有-----会自动将结果转型回Shape。这是TRRI最基本的使用形式,因为在java中,所有的类型转换都是在运行时进行正确性检查的。这也是RTTI名字的含义:在运行时,识别一个对象的类型。
我们希望尽可能少地了解对象的具体类型,而是只与对象家族中的一个通用表示打交道。
本文来自博客园,作者:北征愚人,转载请注明原文链接:https://www.cnblogs.com/xukd/p/15329081.html