• 推荐!搬瓦工官方代理,自动更换被封IPJust My Socks

ad

第14章 类型信息

RTTI(Runtime Type Information),运行时类型信息使得你可以在程序运行时发现和使用类型信息。

  • 14.2 Class对象

类是程序的一部分,每个类都有一个Class对象。换言之,每当编写并且编译了一个新类,就会产生一个Class对象(更恰当地说,是被保存在一个同名的.class文件中)。为了生成这个类的对象,运行这个程序的Java虚拟机(JVM)将使用被称为“类加载器”的子系统。

Java程序在它开始运行之前并非被完全加载,其各个部分是在必需时才加载的。所有的类都是在对其第一次使用时,动态加载到JVM中的。当程序创建第一个对类的静态成员的引用时,就会加载这个类。(这个证明构造器也是类的静态方法)

获得Class对象的引用的几种方法

  1. Class.forName(“typeinfo.toys.FancyToy”)。—传递给forName()的字符串中,必须使用全限定名(包含包名),并且注意大小写。
  2. 类字面常量:FancyToy.class。—这样做不仅更简单,而且更安全,因为它在编译时就会收到检查(不需要放在try语句中)。==注意,当使用“.class”来创建对Class对象的引用时,不会自动地初始化改Class对象。==类字面常量不仅可以应用于普通的类,还可以应用于接口、数据以及基本数据类型。另外,对于基本数据类型的包装器类,还有一个标准字段TYPE,TYPE字段是一个引用,指向对应的基本数据类型的Class对象,如:boolean.class等价于Boolean.TYPE.
  3. obj.getClass()

为了使用类而做的准备工作实际包含以下三个步骤:

  1. 加载。这是由类加载器执行的。该步骤将查找字节码(通常在classpath所指定的路径中茶盅,但这并非是必须的),并从这些字节码中创建一个Class对象。
  2. 链接。在链接阶段将验证类中的字节码,为静态域分配存储空间,并且如果必需的话,将解析这个类创建的对其他类的所有引用。
  3. 初始化。如果该类具有超类,则对其初始化,执行静态初始化器和静态初始化块。

初始化被延迟到了对静态方法(构造器隐式的是静态的)或者非常数静态域进行首次引用时才执行:

static void callHiddenMethod(Object a, Strign methodName) throws Exception{
    Method g = a.getClass().getDeclaredMethod(methodName);
    g.setAccessible(true);
    g.invoke(a);
}

不管是将接口实现为一个私有内部类:

//InnerA$C
class InnerA{
    private static class C implements A{
        //...
    }
    
    public static A makeA(){
        return new C();
    }
}

还是匿名类:

//AnonymousA$1
class AnonymousA(){
    public static A makeA(){
        return new A(){
            //....
        }
    }
}

都无法阻止反射到达并调用那些非公共访问权限的方法,对于域来说,即便是private域。

但是,final域在遭遇修改时是安全的,运行时系统会在不抛异常的情况下接受任何修改尝试,但是实际上不会发生任何修改。

class WithPrivateFinlaField{
    private final String s = "I'm totally safe";//用反射无法修改
}
点赞