你似乎在问一个看起来完全不同的问题作为一个问题。这可能是您混淆的主要来源。另外,在处理语言规范时,我们需要对名称进行精确定位,以便将混淆最小化。
静态内容是一个在网站组织中使用的术语。当您参考静态内容时,您似乎隐含了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的设计师,我们可以像A
的b
那样访问像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()
一样,其中str
是String
的一个实例(而length()
是在String
类中定义的所谓的实例方法;实例方法和类方法的区别在这里是不相关的)。
那么你如何证明静态变量和方法属于Class对象呢?
从1)的上方,即从一个事实,即它们只能通过声明它们的类型(即class
或interface
)的名称访问。这里有一个小皱纹。静态成员也可以通过定义它们的类型的实例来访问,下面的示例可能会让你感到惊讶。这个程序做什么:
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的要求。
但请注意,如果您使用定义类型或该类型的实例,它将获取完全相同的静态字段值,并且会在运行时调用完全相同的静态方法。这足以证明我们自己,静态成员确实是定义它们的类型(或类)的一个特征。
更多的是,他们只有一个单一的实例,他们不属于任何一个对象的“属于”类 – Rogue