2016-11-05 58 views
0

我看了很多问题在这个题目,很多人说的静态内容(static methodsvariables)属于java.lang.Class对象(也称作为生活在永久代类级别对象),这背后的原因是静态变量和方法是否属于该类的java.lang.Class对象?

  1. 在Java规范中,我们可以发现这个“静态内容属于类的一些内部结构,这是所有对象共有的并且存在于对象外部”。

如Java语言规范

的§8.3.1.1提到如果字段声明为静态,存在的 只有一个化身领域,无论多少的情况下(可能是零)最终可能会创建类 。一个静态字段,有时称为类 变量,在类被初始化(§12.4)时体现出来。

  • java.lang.Class一类的对象表示的类的内部结构,存在的它恰好一个化身,它是常见的所有对象。

  • java.lang.Class当类加载并初始化时,对象在Perm Gen中创建。

  • java.lang.Class被称为类级对象,而静态变量被称为类变量,因为静态变量是类级别对象的状态。

  • 在同步一个静态方法时,我们需要获取类级别对象的锁,这个锁又是java.lang.Class实例。

  • 如§8.4.3.6提到说:

    对于类(静态)方法,用 Class对象方法的类相关联的监视器被使用。

    从以上几点可以看出,静态内容属于java.lang.Class实例,但为什么在任何规范的任何地方都没有写清楚?

    而且如果class A { static int b; }为什么b不能通过A.class.b访问?

    那么如何证明静态变量和方法属于Class对象?

    如果静态内容不属于Class对象,那么它究竟属于哪里?为什么很多答案,博客和教程都提到它?

    +0

    更多的是,他们只有一个单一的实例,他们不属于任何一个对象的“属于”类 – Rogue

    回答

    0

    Java语言规范的§8.3.1.1规定如下:

    如果某个字段声明static,存在的领域只有一个化身,不管类的多少实例(可能是零)最终可能创建。一个static字段,有时称为类变量,在类被初始化时(§12.4)被体现。

    而且§8.4.3.6说:

    对于类(静态)方法,用Class对象的方法的类相关联的监视器被使用。

    它们都没有指定一个对象,它应该包含static字段。

    至于你提到:

    静态内容属于一些内部结构的类,这是共同的所有对象,并存在外的对象的”

    这包括的实例。 Class。这些实例描述了部分内部结构,但不包含它们。

    因此,不幸的是,试图证明是错误的。

    +0

    这就是为什么我问这个问题,没有证据它在任何规范中(JVMS,JLS),但它看起来像静态内容属于类级别的对象。例如,如果静态内容不属于类级对象,那么为什么我们需要对Class对象进行锁定以使静态方法同步? –

    +0

    ,正如你从JLS引用的那样“一个静态字段,有时称为类变量,在类被初始化时(第12.4节)就体现了。”,一个类将被初始化意味着java.lang.Class的类级对象创建。 –

    +0

    不,他们不是。静态方法的'同步'使用'Class'对象的原因,只是一个方便的协议。对于每个加载的类,只有一个实例的任何其他对象都适合。幸运的是,JVM已经有了这种对象 - “Class”对象。 – kgeorgiy

    0

    你似乎在问一个看起来完全不同的问题作为一个问题。这可能是您混淆的主要来源。另外,在处理语言规范时,我们需要对名称进行精确定位,以便将混淆最小化。

    静态内容是一个在网站组织中使用的术语。当您参考静态内容时,您似乎隐含了Java类的静态字段和方法(统称为静态成员)。我们只需使用术语静态成员即可清楚。

    从以上几点我们可以得出结论:静态内容属于java.lang.Class实例,但为什么它在任何规范中的任何地方都没有写得清楚?

    §15.11试图指定静态成员经由PrimaryName和使用该表达Primary . Identifier一个标识符访问。

    在最简单的情况下,规范说:主节点的类型必须是引用类型T,否则会发生编译时错误。这意味着要通过定义成员类型的名称来访问静态成员。

    而且如果class A { static int b; }为什么b不能通过A.class.b访问?

    出于与上述同样的原因,A.class不是参考类型限定静态场b。类型为A,因此b只能以A.b访问。

    作为Java程序员,我们非常感谢Java的设计师,我们可以像Ab那样访问像A.b这样的静态成员,不是吗?

    稍长的解释必须处理Java的反射功能,特别是类java.lang.Class这是Java中唯一的实例类为的类。是的,java.lang.Class的实例是类。因此,java.lang.String实例java.lang.Class就像一个字符串String s = "foo";实例的类java.lang.String。该方案:

    public class Main { 
        public static void main(String[] args) { 
        String s = "foo"; 
        System.out.println(String.class instanceof Class); // statically 
        System.out.println(Class.class.isInstance(String.class)); // dynamically 
        System.out.println(s instanceof String); // statically 
        System.out.println(String.class.isInstance(s)); // dynamically 
        } 
    } 
    

    打印:

    true 
    true 
    true 
    true 
    

    一个问题可能会持续,这是究竟是什么A.class?所述spec defines it类常量

    类字面评估为Class对象为指定类型(或空隙)如通过定义类加载器定义(§12.2)的类的当前实例的的。

    的话,那上调用任何方法说String.class(记住,String.class接收机这里)都在其类,这是该类java.lang.Class定义的方法。因此,你可以这样做String.class.isInstance(str),就像你可以调用str.length()一样,其中strString的一个实例(而length()是在String类中定义的所谓的实例方法;实例方法和类方法的区别在这里是不相关的)。

    那么你如何证明静态变量和方法属于Class对象呢?

    从1)的上方,即从一个事实,即它们只能通过声明它们的类型(即classinterface)的名称访问。这里有一个小皱纹。静态成员也可以通过定义它们的类型的实例来访问,下面的示例可能会让你感到惊讶。这个程序做什么:

    public class Main { 
        static int foo = 22; 
    
        public static void main(String[] args) { 
         Main m = null; 
         System.out.println(m.foo); // ** Don't Do This ** 
        } 
    } 
    

    不,它不扔NullPointerException。通过定义的类实例允许(尽管不鼓励)访问静态成员。由于javac不像其他人那样了解Java语言规范,它确实符合spec的要求。

    但请注意,如果您使用定义类型或该类型的实例,它将获取完全相同的静态字段值,并且会在运行时调用完全相同的静态方法。这足以证明我们自己,静态成员确实是定义它们的类型(或类)的一个特征。

    +0

    Kedar感谢您的回答,我确实知道我们可以从一个实例访问静态成员,并且我知道您提到的其他内容,即String.class实际上是java.lang.Class的一个对象但以上所有解释都是不给我任何线索为什么静态成员不属于类级别的对象 –

    +0

    嗯,我试过了。也许它不够好。 –

    相关问题