是否真的在加载Java类时创建java.lang.Class对象,甚至在实例化之前?

时间:2012-02-24 14:25:08

标签: java reflection static jvm instantiation

假设类具有如下代码:

class C {
    public static void show() {
    }
}

class CTest {
    public static void main (String[] args) {
        C.show();
    }
}

然后,在引用类C来访问静态方法show()时,完全合法的是,在场景后面Java实际上是通过Java反射调用show()方法?

即。它实际上是在做这样的事吗

Class test = Class.forName(C);
test.show();

调用静态方法?

如果没有,那么如何在不创建对象的情况下实际调用静态方法?

如果上面的解释是正确的,那么当我们实际通过java.lang.Class对象调用方法时,我们如何证明“静态成员只与类相关联,而不是对象”的语句?

4 个答案:

答案 0 :(得分:3)

  1. 在调用静态方法时,JVM不需要执行Class.forName()之类的任何操作,因为当调用方法的类被初始化时(或者当方法时)第一次运行,具体取决于静态方法调用的位置),查找其他类,并将静态方法代码的引用安装到与该调用类关联的数据池中。但是在初始化期间的某个时刻,是的,执行Class.forName()相当于找到另一个类。

  2. 这是一个似是而非的语义论证。您可以很容易地说,这加强了静态方法与相关联的标准行,而不是类的任何实例。

答案 1 :(得分:1)

JVM将可以使用的内存划分为不同的部分:存储类的一部分和对象的一部分。 (我想可能有第三部分,但我现在不太确定)。

无论如何,当创建一个对象时,java会查找相应的类(如蓝图)并创建它的副本 - >瞧,我们有一个对象。当调用静态方法时,执行内存的第一部分中的类的方法,而不执行第二部分中的对象的方法。 (因此不需要实例化对象)。

此外,反射需要大量资源,因此使用它来调用静态方法会对性能产生很大影响。

答案 2 :(得分:1)

了解更多信息:

当调用代码首次引用时,被调用的类将被加载。 即JVM只解析并在最初需要它的特定代码行加载该类。 您可以使用JVM arg“-verbose:class”并使用调试器逐步验证这一点。

它将调用ClassLoader.loadClass(String name)来加载类。

答案 3 :(得分:1)

您可以将println语句放入ctor,以验证它是否被调用:

class C {
    public static void show () {
        System.out.println ("static: C.show ();");
    }

    public C () {
        System.out.println ("C.ctor ();");
    }

    public void view () {
        System.out.println ("c.view ();");
    }

}

public class CTest
{
    public static void main (String args[])
    {
        System.out.println ("static: ");
            C.show ();
        System.out.println ("object: ");
            C c = new C ();
            c.view ();
            c.show (); // bad style, should be avoided
    }
}