【问题标题】:Static variables in non-static inner classes非静态内部类中的静态变量
【发布时间】:2011-02-12 07:16:02
【问题描述】:

首先我想问Why does Java prohibit static fields in inner classes?,但问题已经出现了。 Bozho的回答消除了我需要它们的原因(serialVersionUID)。不过,我还是很好奇:

是只在源代码中还是在类文件中禁止静态字段?

顺便说一句,还有一个令人信服的理由来禁止这样做。在 C 中,即使在函数内部也允许使用静态变量。它们的生命周期与任何其他静态变量相同,只是它们的可见性不同。这同样适用于 Java。

【问题讨论】:

  • 一般来说,序列化内部类(而不是静态嵌套类)是个坏主意,因为它们也有对外部类的引用并且也会被序列化。这通常不能满足您的需求。
  • @Peter:当它们被序列化为外部类对象的一部分时,通常需要这样做。
  • @Peter:我认为那里没有问题。内部实例中有一个隐藏的引用,所以外部实例也必须序列化。引用是隐式的,这使得它不明显,但是一旦你知道它......

标签: java static-members inner-classes


【解决方案1】:

内部类可以定义静态字段:

内部类不得声明静态成员,除非它们是编译时常量字段(第 15.28 节)。

因此您可以定义一个序列号。

当静态字段不是常量时,逻辑上不允许 - 静态字段不需要类的实例 - 它们是每个类的,而内部类需要拥有类的实例 - 没有它们就不能存在一个实例。虽然静态字段可能是内部类,但它们被定义为就好像它们在所属类中一样,但这会更加混乱。

【讨论】:

  • 确实!这一定已经改变了——我确定我自己也遇到了问题。
  • 为此,内部类的 Class 对象也应该是 per-outer-object。
  • @Paŭlo Ebermann 类对象也有自己的类,由 callign 获得 class.getDeclaringClass
  • @Bozho,我需要一个工作示例来证明这个陈述 :: "Inner classes may not declare static members, unless they are compile-time constant fields"
  • @Bozho:是的,拥有类,但不是拥有对象——所有用不同外部对象创建的内部对象实际上都具有相同的类对象。 (getDeclaringClass() 也适用于静态嵌套类。)
【解决方案2】:

如果它们被设计成允许静态的东西,就不会发生真正的坏事。类文件级别没有问题,我认为字节码没有内部类的概念。

这会令人困惑:

class X
    class Y
        static int z;

X x1 = new X();
X.Y y1 = x1.new Y();    

X x2 = new X();
X.Y y2 = x2.new Y();    
X.Y y3 = x2.new Y();    

直观地说,y2 和 y3 应该共享同一个 z,但它应该是 y1 看到的同一个 z 吗?


从概念上讲,内部类仅在外部实例中有效。甚至可以想象,当外部实例被 GC'ed 时,JVM 会卸载它; [1] 中给出的反对类卸载的论点不适用,因为内部类没有静态变量或静态初始化器。

然而现实是,所有内部实例共享一个类,而不管外部实例如何。这当然是真的:y1.getClass()==y2.getClass()==y3.getClass()。

可以说语言规范规定这是真的:[2]

如果...由同一个类加载器定义,两个引用类型是相同的运行时类型,并且具有相同的二进制名称

y1 的类和 y2 的类具有相同的类加载器,X.Y 的二进制名称定义明确且独立于外部实例。所以 y1 和 y2 必须有相同的运行时类。

如果语言规范实际上暗示内部类独立于外部实例,则普遍接受的针对内部类中的静态状态的解释被削弱。


[1]http://java.sun.com/docs/books/jls/third_edition/html/execution.html#12.7

[2]http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.3.4

【讨论】:

  • 不,这根本不会令人困惑。每当我写y3.z 时,我都会收到警告“静态字段......应该以静态方式访问”。我将其更改为X.Y.z,任何混乱都消失了。
  • 今天你得到的是一个错误。如果我们允许它,我们有两种可能的语义,你可能认为X.Y.z 是明智的,其他人可能认为x.Y.z 是明智的。
  • 但是其他的明显错了,编译器说的很清楚。其他语义是不可能的,它就是行不通。
  • 当前编译器都不允许。如果我们想在内部类中允许静态字段,那么两者都是可行的候选者。
  • 当“静态”表示“独立于实例”时,它也意味着“独立于 封闭 实例”,不是吗?当“静态”意味着“只存在一次”时,就像在 C 中一样,这也很清楚。您需要一个非常奇怪的“静态”定义才能解决任何问题。
【解决方案3】:

静态成员只在非静态内部类的情况下是不允许的,bcz非静态内部类也作为外部类的方法,所以方法的所有规则都适用于内部类..我们可以在静态内部声明静态成员上课.....

基本规则

  1. 非静态内部类不允许静态方法静态内部类
  2. 静态内部类允许从静态到非静态的一切

【讨论】:

    猜你喜欢
    • 2011-09-01
    • 1970-01-01
    • 2014-01-22
    • 2012-10-16
    • 1970-01-01
    • 2013-07-05
    • 2021-11-02
    • 2021-11-28
    • 1970-01-01
    相关资源
    最近更新 更多