14.1 为什么需要类型信息
- 当从List<Shape>中取出元素时,这种容器--实际上它将所有的元素都当做Object来持有的--会自动将结果转型会Shape.
- RTTI:在运行时,识别一个对象的类型.
- 使用RTTI可以查询某个Shape引用所指向的对象的确切类型.
14.2 Class对象
- Class对象包含了与类有关的信息,是用来创建类的所有的“常规”对象的.
- 每个类都有一个Class对象,每当编写并且编译了一个新类,就会产生一个Class对象(更恰当的说是被保存在了一个同名的.class文件中).
- 所有的类都是在第一次使用时被加载到JVM中的(没使用就没被加载).
- Class.forName(String ClassName)会加载名为ClassName的类(前提是这个类没有被加载过),static初始化会在这个时候进行,方法返回一个Class对象.
Class c = Class.forName("com.imdevl.Toy"); ///全限定名
c.getName();///返回全限定名
c.getSimpleName();///返回类名
c.getCanonicalName();///返回全限定名
c.isInterface();
Class up = c.getSuperClass();///返回父类的Class对象
Object obj = up.newInstance();////up这个类必须要有默认构造器;
obj.getClass();
c.getInterfaces();///返回的是Class对象,C类中的接口
-
关于向上向下转型
14.2.1 类字面常量
- 为了使用类而做的准备工作实际包含三个步骤:
1.加载
2.链接:为静态域分配空间,解析这个类创建的对其他类的引用
3.初始化:
14.2.2 泛型的Class引用
public class GenericClassReference {
public static void main(String[] args) throws Exception {
Class<Toy> c = Toy.class;
Toy toy = c.newInstance();
Class cc = Toy.class;
Object obj = cc.newInstance();
Class<FancyToy> ftClass = FancyToy.class;
Class<? super FancyToy> up = ftClass.getSuperclass();
///Class<Toy> up2 = ftClass.getSuperclass(); 无法通过编译
Toy toy2 = new FancyToy();
FancyToy fToy = ftClass.cast(toy2);
/**等同于这个 就是向下转型**/
fToy = (FancyToy) toy2;
}
}
class Toy{
}
class FancyToy extends Toy{
}
14.3 类型转换前先做检查
RTTI的三种形式:
- 传统的类型转换,如“Shape”,由RTTI确保类型转换的正确性,如果执行了一个错误的类型转换,就会抛出一个ClassCastException异常。
- 代表对象的类型的Class对象。通过查询Class对象可以获取运行时所需的信息。
- 关键字I instanceof.他返回一个布尔值,告诉我们对象是不是某个特定类型的实例。
instanceof有比较严格的限制:只可将其与命名类型进行比较,不可以与Class对象作比较
动态的instanceof
Shape s = new Shape();
Class c = Shape.class;
boolean b = c.isInstance(s);
14.4 注册工厂
14.5 instanceof和Class的等价性
shape instanceof Shape; /////true
shape instanceof Circle; /////false
Shape.class.isInstance(shape);////true
Circle.class.isInstance(shape);////false
shape.getClass == Shape.class;////true
shape.getClass == Circle.class;///false
shape.getClass.equals(Shape.class);////true
shape.getClass.equals(Circle.class);///false
circle instanceof Shape; ////true
circle instanceof Circle; /////true
Shape.class.isInstance(circle);////true
Circle.class.isInstance(circle);////true
circle.getClass == Shape.class;////false
circle.getClass == Circle.class;///true
circle.getClass.equals(Shape.class);///false
circle.getClass.equals(Circle.class);////true
14.6 反射:运行时的类信息
public class Reflection {
public static void main(String[] args) throws Exception {
String string = "com.imdevil.RTTI.Car";
Class c = Class.forName(string);
Method method[] = c.getMethods();
for(Method method2:method){
if (method2.toString().contains("draw")) {
System.out.println(method2.toString());
method2.invoke(c.newInstance(), 10);
}
}
Car car = new Car();
Method method3 = c.getMethod("draw", int.class);
method3.invoke(car, 100);
}
}
class Car{
public Car() {
}
public Car(int i) {
System.out.println(i);
}
public void draw(int i){
System.out.println("draw"+i);
}
public void color(){
}
}
14.7 动态代理
14.8 空对象
14.9接口与类型信息
看起来 没有任何方式可以阻止反射到达并且调用那些非公共访问权限的方法。对域来说,的确如此,即便是private域。