静态变量和方法是否属于该类的java.lang.Class对象?

时间:2016-11-05 05:29:29

标签: java class oop static

我已经阅读了很多关于这个主题的问题,其中很多人都说静态内容(static methodsvariables)属于java.lang.Class对象(也称为类级别对象)永久代)及其背后的原因是

  1. 在Java规范中,我们可以发现这个“静态内容属于类的一些内部结构,它对所有对象都是通用的,并且存在于对象之外”。
  2. 如Java语言规范§8.3.1.1中所述

      

    如果一个字段被声明为静态,那么它只有一个化身   该字段,无论该类有多少个实例(可能为零)   最终可能会创建。静态字段,有时称为类   变量,在类初始化时体现(第12.4节)。

    1. java.lang.Class类的对象表示类的内部结构,它只存在一个化身,并且它对所有对象都是通用的。

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

    4. java.lang.Class称为类级别对象,静态变量称为类变量,因为静态变量位于类级别对象的状态。

    5. 在同步静态方法时,我们需要锁定类级别对象,这又是java.lang.Class实例。

    6. 如§8.4.3.6所述:

        

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

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

      如果class A { static int b; }为什么b无法通过A.class.b访问?

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

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

2 个答案:

答案 0 :(得分:0)

Java语言规范的

§8.3.1.1声明如下:

  

如果一个字段被声明为static,那么无论该类最终可以创建多少个实例(可能为零),都只存在该字段的一个化身。一个static字段,有时称为类变量,在初始化类时实现(第12.4节)。

§8.4.3.6说:

  

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

它们都没有指定应包含static字段的对象。

如你所说:

  

静态内容属于某些内部结构,这个类对所有对象都是通用的,并且在对象之外存在 “。

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

所以,不幸的是,你要证明的陈述是错误的。

答案 1 :(得分:0)

你好像在问一些看似完全不同的问题。这可能是您混淆的主要原因。此外,在处理语言规范时,我们需要对名称进行精确处理,以便最大限度地减少混淆。

静态内容是网站组织中使用的术语。当您引用静态内容时,您似乎暗示了Java类的静态字段和方法(一起称为静态成员)。我们只需使用术语静态成员即可。

  

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

§15.11尝试使用表达式Primary . Identifier指定通过 PrimaryName 标识符访问静态成员。

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

  

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

出于与上述相同的原因,A.class不是定义静态字段b的引用类型。类型为A,因此b只能作为A.b访问。

作为Java程序员,我们感谢Java的设计人员,我们可以像A b一样访问静态成员,不是我们吗?

稍微长一点的解释必须处理Java的反射功能,特别是类A.b这是Java中唯一一个实例为类的类。是的,java.lang.Class的实例是类。因此,java.lang.Classjava.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 spec defines it Class Literal

类文字计算指定类型(或void)的Class对象,由当前实例的类的定义类加载器(第12.2节)定义。

所以,任何可以调用A.class(请记住,String.class接收器)的方法都是在其类上定义的方法,班级String.class 。因此,您可以java.lang.Class执行String.class.isInstance(str),就像调用str.length() str String的实例一样{而length()就是所谓的Stringclass类上定义的实例方法;实例方法和类方法的区别在这里是无关紧要的。)

  

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

从上面的1)开始,即从它们只能通过类型名称(即interfacepublic 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。允许(尽管不鼓励)通过定义它们的类的实例访问静态成员。而且,由于# Perform an aggregate and merge it to your data.frame. TN_97_Lau_Cot_Agg <- merge( x = TN_97_Lau_Cot, y = aggregate(min_dist ~ YEAR + POLICY, data = TN_97_Lau_Cot, min), by = c("YEAR","POLICY"), all.x = TRUE ) # Subset the values that you want. TN_97_Lau_Cot_Final <- unique(subset(TN_97_Lau_Cot_Agg, min_dist.x == min_dist.y)) 像其他人一样理解Java语言规范,因此它确实符合规范要求。

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