【问题标题】:cheat with java final keyword用 java final 关键字作弊
【发布时间】:2016-08-14 09:09:35
【问题描述】:

我正在编写一些 java 代码,但有一次我在一件事上被阻止了。

final String action = "action1";
final Button otherAction = (findById....);
otherAction.setOnClickListener(new View.OnClickListener() {
    @Override
        public void onClick(View v) {
            if (action.equals("action1")) {
                action = "action2";
            } else if (action.equals("action2")) {
                action = "action3";
            } else if (action.equals("action3")) {
                action = "action1";
            }
        }
    });

显然这段代码不起作用,因为我无法为action 分配新值,因为它是最终变量,因此只能初始化一次。
要从 onClickListener 范围内访问变量,您必须将其声明为 final。

所以我做了什么来解决这个问题:

final Button otherAction = (findById....);
otherAction.setOnClickListener(new View.OnClickListener() {
    @Override
        public void onClick(View v) {
            if (t.action.equals("action1")) {
                t.action = "action2";
            } else if (t.action.equals("action2")) {
                t.action = "action3";
            } else if (t.action.equals("action3")) {
                t.action = "action1";
            }
        }
    });

Class t {
    public static String action = "action1";
}

我的问题是:为什么会这样?

【问题讨论】:

  • 原因很简单 - t.action 不是最终的
  • 匿名内部类只能访问有效的最终变量。一直是explained in detail here
  • @Raman Shrivastava 对,但我认为 OP 问题的要点是为什么 t.action 在定义为 public static 类变量时不需要是最终的,而它必须是final 当它只是一个局部变量时。
  • 你可以让action成为你外部类的实例变量。
  • 我已经看到“为什么这不起作用?”问题,但是这个“为什么这有效?”可能是同类中的第一个。 ;-)

标签: java asynchronous scope static final


【解决方案1】:

字段不必是 final 才能从匿名类访问,只需方法变量即可。

这是因为(其实体或类的)字段一直存在,直到不再需要(由 GC 确定),所以总有一个可以分配的地方。

但是,如果您在某处传递匿名类实例,则在包含方法退出时它可能仍然存在。想象一下 otherAction 在遥远的将来调用这个监听器。但是没有地方再分配这个变量了,因此它应该是最终的,并在任何类实例化时复制。

【讨论】:

    【解决方案2】:

    据我了解,第一个代码块不起作用。这里的“工作”是指:编译错误。

    第二个有效,因为 if 遵循 Java 语言规范。对非局部参数、形参没有限制。t.action是静态变量。

    Any local variable, formal parameter, or exception parameter used but not declared in an inner class must be declared final.
    
    Any local variable used but not declared in an inner class must be definitely assigned (§16) before the body of the inner class.
    

    http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.1.3

    还有一点需要注意的是,Java 8 之前。Java 8 引入了:有效 final 的概念,上面用于内部类的局部变量不需要正式声明为 final。更多详细信息,可以在以下位置查看: https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.1.3

    Any local variable, formal parameter, or exception parameter used but not declared in an inner class must either be declared final or be **effectively** final (§4.12.4), or a compile-time error occurs where the use is attempted.
    

    在此处查看有关 Effective-final 的更多说明: Difference between final and effectively final

    关于第二个代码块的工作原理,您可以在此处阅读: Why are only final variables accessible in anonymous class?

    它提供了我见过的关于这个问题的最合理的答案:)

    【讨论】:

      猜你喜欢
      • 2012-12-30
      • 1970-01-01
      • 2011-06-09
      • 1970-01-01
      • 2019-01-15
      • 1970-01-01
      • 2018-05-17
      • 1970-01-01
      • 2011-07-02
      相关资源
      最近更新 更多