1、类型时类型识别(run-timetype identification,RTTI):当之有一个指向对象的引用时,RTTI可以让你找出这个对象的确切类型。
2、Java运行时识别对象和类的信息,主要有俩种方式:
1).一种是“传统“RTTI,它假定我们在运行时已经知道了所有的类型。
2).另一种是“放射“机制,它允许我们在运行时获得类的信息。
3、Class对象:每个类都有一个Class对象,保存在一个同名的.class文件中,它包含了与类相关的信息。
4、在运行时,当我们想生成这个类的对象时,运行这个程序的Java虚拟机(JVM)首先检查这个类的Class对象是否已经加载,就会根据类名查找.class文件,并将其载入。所以Java并非一开始执行就完全加载的,这一点与许多传统语言都不同。
5、Class.forName(“类名”)是获得Class引用的一种方法,该方法返回一个Class对象的引用。例如:Class.forName(“MyClass”);
在调用该方法时,若MyClass类被还没加载,则加载MyClass类。
6、类字面常量:另一种获得Class引用的方法,MyClass.class(类名.class)。
此方法,更安全,更高效。
7、类字面常量不仅应用于普通的类,也可以应用于接口、数组以及基本数据类型。
8、RTTI的形式包括:
1).传统的类型转化。如Base类是Subclass类基类。
Base base = new Subclass();
Subclass sub= (Subclass)base;//(Subclass),由RTTI确定类型转化正确性。在C++中,经典的类型转换“(Subclass)”并不使用RTTI。
2).代表对象的类型的Class对象。同过查询Class对象可以获取运行时所需的信息。
3).RTTI的第三种形式,使用关键字“instanceof”。如:
boolean yesOrNot = (base instanceof Subclass);
若base是Subclass类的实例,yesOrNot就为true。
9、instanceof与Class的等价性:
class Base{}
class Subclass extends Base{};
public class Test{
static void test(Object x){
System.out.println("Testing x of type: " + x.getClass());
System.out.println("x instanceof Base: " + (x instanceof Base));
System.out.println("x instanceof Subclass: " + (x instanceof Subclass));
System.out.println("Base.isInstance(x): " + (Base.class.isInstance(x)));
System.out.println("Subclass.isInstance(x):" + (Subclass.class.isInstance(x)));
System.out.println("x.getClass() == Base.class: " + (x.getClass() == Base.class));
System.out.println("x.getClass() == Subclass.class: " + (x.getClass() == Subclass.class));
System.out.println("x.getClass().equals(Base.class): " + (x.getClass().equals(Base.class)));
System.out.println("x.getClass().equals(Subclass.class): " + (x.getClass().equals(Subclass.class)));
}
public static void main(String[] args){
test(new Base());
System.out.println("---------------------------------------------------");
test(new Subclass());
}
}
运行结果:
1).instanceof 与 isInstance生成的结果完全一样,equal与==也一样。
2). Instanceof与isInstance保持了类型的概念,它指得是“你是这个类,或者是这个类的派生类吗?”
3).equal与==比较实际的Class对象,没有考虑继承。
10、Java是通过Class对象来实现RTTI机制的,即使我们只是做些诸如类型转换这类的事情。Class类提供的一些方法:
11、RTTI的限制:编译器必须已经知道所有用RTTI来处理的类型。但是,当你从网络连接中获得一串字节,并被告知这些字节代表一个类。可是编译器并不知道这个类的信息。这时你要使用这个类,那么就得使用反射机制。
12、RTTI与反射之间的区别:对RTTI来书,编译器在编译时打开和检查.class文件,而对于反射机制,.class文件在编译时是不可获取的,所以是在运行时打开和检查.class文件的。
13、获取关于类和对象的反射信息在java.lang.reflect库中,它包含了Field、Method以及Constructor类。
1).Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)字段或实例字段。
2). Method 提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)。
3). Constructor 提供关于类的单个构造方法的信息以及对它的访问权限。
Base类如下:
class Base{
private int number = 1;
public int otherNum = 100;
public Base(){
}
public Base(int number){
this.number = number;
}
public void func(){
number++;
}
public void otherFunc(){
otherNum--;
}
}
Test:
public class Test{
public static void main(String[] args){
Constructor[] constructors = null;
Method[] methods = null;
Field[] fields = null;
try {
Class c = Class.forName("Base");
constructors = c.getConstructors();//公有构造方法。
methods = c.getMethods();//公有方法。
fields = c.getFields();//公有字段。
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
System.out.println("Base含有的公有构造方法:");
for(int i = 0; i < constructors.length; i++){
System.out.println(constructors[i].getName());
}
System.out.println("Base含有的公有方法(有些是从Oject继承的):");
for(int i = 0; i < methods.length; i++){
System.out.println(methods[i].getName());
}
System.out.println("Base含有的公有字段:");
for(int i = 0; i < fields.length; i++){
System.out.println(fields[i].getName());
}
}
}
运行结果: