我已经阅读了很多关于这个主题的问题,其中很多人都说静态内容(static methods
和variables
)属于java.lang.Class
对象(也称为类级别对象)永久代)及其背后的原因是
如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所述:
对于类(静态)方法,与类关联的监视器 使用方法类的对象。
从以上几点可以得出结论,静态内容属于java.lang.Class
个实例,但为什么在任何规范中都没有写清楚?
如果class A { static int b; }
为什么b
无法通过A.class.b
访问?
那么如何证明静态变量和方法属于Class
对象?
如果静态内容不属于Class对象,那么它究竟属于哪个?为什么许多答案,博客和教程都提到它?
答案 0 :(得分:0)
§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.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
? 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()
就是所谓的String
在class
类上定义的实例方法;实例方法和类方法的区别在这里是无关紧要的。)
那么如何证明静态变量和方法属于Class对象?
从上面的1)开始,即从它们只能通过类型名称(即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
。允许(尽管不鼓励)通过定义它们的类的实例访问静态成员。而且,由于# 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语言规范,因此它确实符合规范要求。
但请注意,如果您使用了该类型的定义类型或实例,它将获取静态字段的完全相同的值,并将在运行时调用完全相同的静态方法。这足以证明静态成员确实是定义它们的类型(或类)的特征。