类型信息在运行时如何表示?
类是程序的一部分,每个类都有一个Class对象。每当编写并编译了一个新类,就会产生一个Class对象(同名的.class文件中)。
为了生成这个类的对象,运行这个程序的JVM,会使用“类加载器”的子系统。
所有的类在对其第一次使用时,就会动态加载到JVM中。比如程序创建第一个对类的静态成员的引用时,就会加载这个类。这个证明构造器也是类的静态方法,即使构造器没有使用static关键词。因此,使用new操作符创建类的新对象也会被当作对类的静态成员的引用。
java程序在它开始运行之前并非完全加载,其各个部分是必需时才加载的。
类加载器首先检查这个类的Class对象是否已经加载。如果尚未加载,默认的类加载器就会根据类名查找.class文件。
一旦某个类的Class对象被载入内存,它就被用来创建这个类的所有对象。
代码如下:
public class RTTI {
public static void main(String[] args) {
new Candy();
try {
Class.forName("com.test.Gum");
} catch (Exception e) {
System.out.println("loading gum fail");
}
new Cookie();
}
}
class Candy{
static{
System.out.println("loading candy");
}
}
class Gum{
static{
System.out.println("loading gum");
}
}
class Cookie{
static{
System.out.println("loading cookie");
}
}
output:
loading candy
loading gum
loading cookie
从代码可以总结出:
Class对象仅在需要的时候才被加载,static初始化是在类加载时进行的。
Class.forName(“com.test.Gum”);
forName()方法是Class类的一个static成员。
还可以通过getClass()方法来获取Class对象的引用。
java还可以通过类字面常量来生成Class对象的引用。例如:
Cookie.class
这样做简单、而且更安全,因为它在编译时就会受到检查,并且根除了对forName()方法的调用,更高效。
类字面常量不仅可以应用于普通的类,也可以应用于接口、数组以及基本数据类型。
对于基本类型的包装器类,还有一个标准字段TYPE。TYPE字段是一个引用,指向对应基本数据类型的Class对象。
建议使用.class形式,用.class创建对Class对象的引用时,不会自动地初始化该Class对象。
Class intClass = int.class;
Class genericIntClass = int.class;
intClass = double.class;
//编译错误 Type mismatch: cannot convert from Class to Class
//genericIntClass = double.class;
如上代码所示:通过使用泛型语法,可以让编译器强制执行额外的类型检查。
//编译报错
Class genericIntClass = int.class;
Integer继承自Number,但是编译错误,因为Integer Class对象不是Numner Class对象的子类。
为了在使用泛化的Class引用时放松限制,可以使用通配符,它是java泛型的一部分。通配符“?”表示“任何事物”。如下代码所示:
Class> genericIntClass = int.class;
genericIntClass = double.class;
在java SE5中,Class>优于平凡的Class,即便他们是等价的,Class>不会产生编译器警告信息。Class>的好处是它表示你并非是碰巧或由于疏忽,而使用了一个非具体的类引用,选择了非具体的版本。
为了创建一个Class引用,它被限定为某种类型,或该类型的任何子类型,你需要将通配符与extends关键字相结合,创建一个范围。
Class extends Number> genericIntClass = int.class;
genericIntClass = double.class;
Class引用添加泛型语法的原因仅仅是为了提供编译期类型检查,可以在编译期间发现错误,而不是在运行期间。
public class GenericToyTest {
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
Class ftClass = FancyToy.class;
FancyToy fancyToy = ftClass.newInstance();
Class super FancyToy> up = ftClass.getSuperclass();
//Class up2 = ftClass.getSuperclass();编译错误
Object obj = up.newInstance();//只接受Object
}
}
class Toy{}
class FancyToy extends Toy{}
RTTI形式包括:
if(x instanceof Dog){
((Dog)x).bark();
}
编译器允许自用地做向上转型的赋值操作,而不需要任何显式操作;向下转型赋值,必须使用显式的类型转换。