Java 常数和内部类

Java 常数和内部类,java,constants,inner-classes,Java,Constants,Inner Classes,static内部类中的变量: 内部类不能包含静态字段。它不能包含静态成员,因为在哪里分配静态成员会有问题。内部类与外部类相连接。我理解为什么它不包含static成员,但内部类可以包含static常量。为什么?它经过特殊处理吗?它在特殊的堆上吗?它仍然是静态成员,但是是常量,所以它被特殊处理了吗 它可以包含:“最终静态int x”,但不能包含“静态int x” 我想知道为什么本地类中使用的方法变量应该是final。我的意思是: public void function1() { final i

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

它可以包含:“最终静态int x”,但不能包含“静态int x”

  • 我想知道为什么本地类中使用的方法变量应该是
    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
        }
    

    为什么没有同步问题?

    要回答第一个问题:

    就我个人而言,我还不明白为什么它不接受内部类中的非最终静态成员。但是,我可以告诉您编译时会发生什么。当您声明
    静态final
    基元成员时,可以将其编译为使用此成员的代码。但是,当您尝试创建
    静态最终对象o=new Object()时,它无法在编译时知道
    o
    将指向什么。显然,如果您在内部类中创建一个
    静态int
    (非final),则会产生相同的编译器错误

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


    x
    是一个局部变量,它被推送到堆栈上。当您在内部类中使用对
    x
    的引用时,您将遇到问题。因为内部类很可能比该函数的作用域活得更长。函数一结束,
    x
    就超出范围并从堆栈中删除。所以,现在,您的内部类仍然有一个对不再存在的变量的引用。因此,这是在编译器中实现的一个小技巧:如果您将
    x
    声明为
    final
    ,编译器知道它不会更改,因此没有必要保留对它的引用。这允许编译器将
    x
    作为新成员复制到内部类的实例中。因此,
    x
    将被复制到堆中。如果不将堆栈标记为final(当然不会编译,因为编译器会保护您避免犯此错误),请将其与对堆栈的无效引用进行比较。

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

  • 在complilation之后,内部类和顶级类并没有什么不同,只有它的所有构造函数获得额外的参数——对外部类的引用

    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不同于
    静态int x=1-区别在于前者不需要初始化—它是一个常量,而后者需要一个隐式静态初始化块来放置将分配1到x的代码

  • 最后一个变量作为构造函数参数访问匿名类
  • X类{ void x(){ 最终整数x=1; 新的Runnable(){ 公开募捐{ int y=x; } }; } }

    实际匿名类

    class X$1 {
       private final Integer x;
       X$1(Integer x) {
          this.x = x;
       }
       ...
    
    外部变量必须是final的唯一原因是,否则看起来我们可以从内部类代码更改它

    void x() {
        Integer x = 1;
        new Runnable() {
          public void run() {
              x = 2;
          }
    ...
    
    但事实并非如此,因为内部类与副本一起工作

  • 内部类背后的思想是它们属于包含类的实例。因此,如果我们忽略作用域和类似的细节,内部类的静态成员将等同于包含类的非静态成员

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

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

  • 一旦变量超出范围,局部变量的地址就毫无用处,例如当方法返回时。如果读取或写入变量,会发生什么情况?该地址现在指向一个非法的内存位置,甚至更糟的是:指向一个完全不相关的变量


  • 所以,若我把变量标记为final,这个变量用另一种方式处理?内存中的不同位置?关于第二个问题,是的:它被复制到内部类的实例中(不是类,而是真实对象本身!)。常量被复制到实例中。如果我们有一个对象数组,每个对象都有常数?我们使用了这么大的内存?是的,每个内存都保持不变。每个实例占用4个额外字节,这不是