4
  1. static内部类中的变量:内部类不能包含static字段。它不能包含static成员,因为在哪里分配成员会有问题static。内部类与外部类相连。我明白为什么它不包含static成员,但内部类可以包含static常量。为什么?是不是经过特殊处理?它在特殊堆上吗?仍然是静态成员,但是常量,所以要特殊处理?

    它可以包含:“final static int x”,但不能包含“static int x”。

  2. 我想知道为什么本地类中使用的方法的变量应该是final. 我是说:

    public void function1() {
      final int x; // value of x, which is used in class A have to be final
    
      class A {
        void function2() {
          //body of function
        }
      }
    }
    

    答案是:变量x id 复制到A 类中。不能更改,因为这样就出现了不一致。那么为什么 Java 的架构师没有创建不复制变量 x 的语言呢?变量的地址将被传递,然后变量 x 将被更改而不会出现不一致。有人可以举个例子并解释一下吗?

    或与同步有关的问题。两个变量应该相同,但是如果我们超出范围怎么办?其中一个变量不存在,那么同步呢?

编辑:为什么会这样:

interface In
{
    void f1();
}

class A
{
    int variable = 3;

    In g()
    {
        return new In()
        {
            @Override
            public void f1()
            {
                variable = 6;

                System.out.println(variable);
            }
        };
    }
}

public static void main(String[] args)
    {
        In in1;
        {
            A a = new A();
            in1 = a.g();
        }

        in1.f1(); //class A does not exists any more, field 'variable' is changed, despite it does not exist
    }

为什么没有同步问题?

4

3 回答 3

3

要回答您的第一个问题:

就个人而言,我还不明白为什么它不接受内部类中的非最终静态成员。但是,我可以告诉你编译时会发生什么。当你声明一个static final 原始成员时,它可以被编译成使用这个成员的代码。但是,当您尝试创建 a 时static final Object o = new Object();,它无法在编译时知道o将指向什么。static int并且显然给出了与您在内部类中创建(非最终)相同的编译器错误。

要回答第二个问题,原因如下:

x是一个局部变量,它被压入堆栈。当您在内部类中使用引用时x,您会遇到问题。因为内部类很可能会比该函数的范围更长寿。一旦函数结束,x就会超出范围并从堆栈中删除。所以,现在,你的内部类仍然有一个对不再存在的变量的引用。所以,这是在编译器中实现的一个小技巧:如果你声明你xfinal编译器知道它不会改变,那么保持对它的引用是没有意义的。这允许编译器复制x内部类的实例中作为新成员。因此,x将被复制到堆中。如果您没有将其标记为最终的,则将此与对堆栈的无效引用进行比较(当然不会编译,因为编译器会保护您不犯此错误)。

于 2013-08-09T22:35:13.607 回答
1

在我看来,没有无法解决的问题,因为内部类不能有静态成员,并且匿名类中使用的 var 只能是最终的。我认为这只是语言设计师的决定。

  1. 编译后的内部类与顶级类没有什么不同,只是它的所有构造函数都获得了额外的参数——对外部类的引用。

    X 类 { Y 类 { } }

编译器把它变成这个

class X {
}

class X$Y {
    private final X x;
    X$Y(X x) {
       this.x = x;
    }
}

没有理由 X$Y 不能有静态成员。语法也不是问题

class X {
    class Y {
        static int x = 1;
    }

    void x() {
         Y.x = 2;
    }
}

至于有什么static final int x = 1;不同static int x = 1;- 不同之处在于前者不需要初始化它是一个常量,而后者需要一个隐式静态初始化块来放置将分配 1 给 x 的代码。

  1. final var 获取匿名类作为构造函数参数

类 X { void x() { 最终整数 x = 1; 新的 Runnable() { public void run() { int y = x; } }; } }

实际的匿名类

class X$1 {
   private final Integer x;
   X$1(Integer x) {
      this.x = x;
   }
   ...

外部变量必须是最终变量的唯一原因是因为否则看起来我们可以从内部类代码中更改它

void x() {
    Integer x = 1;
    new Runnable() {
      public void run() {
          x = 2;
      }
...

但这不是真的,因为内部类使用副本

于 2013-08-10T03:38:06.487 回答
1
  1. 内部类背后的想法是它们属于包含类的一个实例。因此,如果我们忽略范围和类似的细节,内部类的静态成员将等同于包含类的非静态成员。

    然而,通过内部类的实现方式,这是不可能实现的:内部类被编译成一个独立的类,如果它有静态成员,它们将在包含类的所有实例之间共享。这打破了语言试图创造的错觉。因此静态成员是完全被禁止的。

    此规则的唯一例外是声明为static final并使用编译时常量初始化的字段,例如整数或字符串文字。这些是允许的,因为编译时常量将在包含类的所有实例之间共享。

  2. 一旦变量超出范围,例如当方法返回时,局部变量的地址就没有用了。如果变量被读取或写入,会发生什么?该地址现在指向一个非法的内存位置,或者更糟:指向一个完全不相关的变量。

于 2013-08-10T08:25:43.890 回答