Java 关键字final的用途是什么?

Java 关键字final的用途是什么?,java,android,final,Java,Android,Final,在下面的代码中,如果我从EditText中删除关键字final,我将在第(6)行中出现获取错误,在该行中我将EditText对象(et)传递给intent…我必须在此处了解final关键字的重要性 final EditText et=(EditText)findViewById(R.id.t); Button b=(Button)findViewById(R.id.b1); b.setOnClickListener(new Button.OnClickListen

在下面的代码中,如果我从EditText中删除关键字final,我将在第(6)行中出现获取错误,在该行中我将EditText对象(et)传递给intent…我必须在此处了解final关键字的重要性

final EditText et=(EditText)findViewById(R.id.t);
        Button b=(Button)findViewById(R.id.b1);
        b.setOnClickListener(new Button.OnClickListener(){
            public void onClick(View v)<br>
            {
            Intent on=new Intent(Intent.ACTION_CALL,Uri.parse("tel:"+et.getText()));
            startActivity(on);
            }
        });
final EditText et=(EditText)findViewById(R.id.t);
按钮b=(按钮)findViewById(R.id.b1);
b、 setOnClickListener(新建按钮。OnClickListener(){
单击“公共无效”(视图v)
{ Intent on=newintent(Intent.ACTION_调用,Uri.parse(“tel:+et.getText())); 星触觉(on); } });
这是因为您在这里使用闭包。这意味着内部类使用内置类的上下文。要使用它,变量应该声明为final,以便不被更改


请参阅更多。

Final使变量et只允许分配一次。它还改变了变量的范围,并允许函数onClick对et的可见性。如果没有final,et在函数onClick中不可见。

final本质上意味着变量
et
在任何时候都不会被重新分配,并且会保留在附近。这意味着内部类,如侦听器,可以相信它不会被其他线程重新分配,这可能会导致各种各样的问题

final还可用于修改方法或类定义,这意味着该方法不能被子类重写,或者该类不能扩展。

其中讨论了
final
关键字。根据(第4.12.4节):

变量可以声明为final。最后一个变量只能指定一次。如果将最终变量赋值给,则为编译时错误,除非在赋值之前明确未赋值(§16)

阅读以了解所涉及的实施细节:

这项限制的原因是什么 如果我们能弄清楚的话 关于如何实现本地类。 匿名本地类可以使用本地 因为编译器 自动给班级a 保存副本的专用实例字段 类使用的每个局部变量的。 编译器还添加了隐藏的 每个构造函数的参数 初始化这些自动创建的 私人领域。因此,本地类 实际上不访问本地 变量,但仅仅是它自己的私有 它们的副本。只有这样才能 正确工作是如果本地 变量被声明为final,因此 他们保证不会改变。 有了这一保证 本地类确信其 变量的内部副本 准确反映当地的实际情况 变量

编辑:


Berlin Brown说:“我发布了一个 匿名的内部类。但是 老实说,我还是不明白为什么 编译器必须有这些信息。 即使该字段被宣布为最终字段, 该字段仍然可以为空。我认为 你知道,这是Java的怪癖之一 必须声明该字段 最后…因为这就是它的方式。 没有一个明确的理由来解释为什么”

原因是要确保用户意识到闭包“关闭”变量而不是值。让我们假设不需要有最终的局部变量。然后我们可以编写如下代码:

public void doIt() {
    for(int i = 0; i < 3; ++i) {
        runnables.add(new Runnable() {
            @Override
            public void run() {
                System.out.println(i);
            }
        });
    }
    run(runnables); // run each runnable
}
public void doIt(){
对于(int i=0;i<3;++i){
添加(新的Runnable(){
@凌驾
公开募捐{
系统输出打印LN(i);
}
});
}
运行(可运行);//运行每个可运行
}
你认为结果会是什么?如果您认为它是“0 1 2”,那么您就错了,因为Runnable在该时间点关闭“变量”i而不是i的“值”,因此输出将是“2 2”。在这里可以做些什么来实现预期的行为?两种解决方案:要么依靠用户了解闭包是如何工作的,要么以某种方式在语言级别实施闭包。这是语言设计师们的第二个选择

public void doIt() {
    for(int i = 0; i < 3; ++i) {
        final int j = i; // notice the final local variable
        runnables.add(new Runnable() {
            @Override
            public void run() {
                System.out.println(j);
            }
        });
    }
    run(runnables);
}
public void doIt(){
对于(int i=0;i<3;++i){
final int j=i;//注意最后一个局部变量
添加(新的Runnable(){
@凌驾
公开募捐{
系统输出println(j);
}
});
}
运行(可运行);
}

JFTR,我并不是说第二种选择是“正确的”方法,只是在匿名内部类中使用局部变量之前将其标记为final对我来说是一个大问题。当然,YMMV.:-)

它还有助于理解Java如何创建匿名内部类。Java如何实现该特定类

Java需要该变量为final,因为编译器必须在编译时知道该对象的类型。然后,编译器将在匿名内部类实现中生成一个字段(在本例中为“et”)

如果类型不是final,编译器将如何确定如何构建内部类实现。基本上,通过声明字段final,您为Java编译器提供了更多信息

对编译器没有帮助的代码不会编译匿名内部类:

Object et;
et = a ? new Object() : new EditText();

使用上面的代码,Java编译器无法真正构建匿名内部类

您的代码:

Object et;
et = a ? new Object() : new EditText();
最终编辑文本et=(编辑文本)findViewById(R.id.t)

new按钮。OnClickListener$1(){
单击“公共无效”(视图v)
{ Intent on=newintent(Intent.ACTION_调用,Uri.parse(“tel:+et.getText())); 星触觉(on); } });
。。。 java编译器将创建一个字节码类,这是您提供的内部类块的一个实现,可能如下所示

public class OnClickListener$1 {

 private final EditText et ; <---- this is important
 public OnClickListener$1(final et) {
    this.et = et;
 }
 public void onClick(View v)<br>
                {
                Intent on=new Intent(Intent.ACTION_CALL,Uri.parse("tel:"+et.getText()));
                startActivity(on);
                }
}
公共类OnClickListener$1{
私人最终编辑文本et;的目的
Java final variable: If you make any variable as final, you cannot change the value of final variable (It will be constant).

Java final method: If you make any method as final, you cannot override it.

Java final class: If you make any class as final, you cannot extend it.