4

浏览 android 教程(与多线程、loopers 和处理程序相关),我遇到了这个:

public synchronized void enqueueDownload(final DownloadTask task)

我的问题是:

  1. 何时以及为什么需要将函数的参数声明为 final?
  2. 它是 Java 特有的还是其他语言(如 C/C++)中存在类似的东西?
4

4 回答 4

10

在 Java 中,这通常是为了让您可以访问匿名内部类中的参数——这通常在 Android 中用于事件处理程序等。

真正的意思是参数的值不能在方法内改变,但目的通常是为了匿名内部类......

public synchronized void enqueueDownload(final DownloadTask task) {
    SomethingHandler handler = new SomethingHandler() {
        @Override public void handleSomething() {
            // This would not compile if task were not final
            task.doSomething();
        }
    };
    // Use handler
}
于 2011-11-18T19:20:13.373 回答
2

在您的上下文中,该参数上的 final 关键字意味着变量 task 不能在方法主体内重新分配,并且出于安全原因指定它。

可以在 C++ 中使用常量函数参数实现类似的行为:

如果你正在编写一个函数并且你不打算修改一个参数,你可以声明它是一个常量引用参数。

于 2011-11-18T19:25:37.330 回答
1

如果你知道它永远不应该被重新分配,你就声明它是最终的。您经常希望对方法参数执行此操作,因为重新分配方法参数几乎没有意义。

void foo(String str) { // no final
    str = "hijacked"; // perfectly fine
}

void foo(final String str) { // final
    str = "hijacked"; // compile error
}

C 和 C++ 使用const代替final,但我不能声称自己知道细节。

于 2011-11-18T19:18:23.320 回答
1

final 关键字在几种不同的上下文中用作修饰符,这意味着它修饰的内容在某种意义上不能更改。

最后的课程

您会注意到 Java 库中的一些类被声明为 final,例如

public final class String 这意味着这个类不会被子类化,并通知编译器它可以执行某些优化,否则它不能。它还在安全性和线程安全方面提供了一些好处。

编译器不会让您子类化任何声明为 final 的类。不过,您可能不希望或不需要将自己的类声明为 final。

最终方法

您还可以声明方法是最终的。声明为 final 的方法不能在子类中被覆盖。语法很简单,只需将关键字 final 放在访问说明符之后和返回类型之前,如下所示:

public final String convertCurrency()

最终字段

您也可以将字段声明为最终字段。这与将方法或类声明为 final 不同。当一个字段被声明为 final 时,它是一个不会也不能改变的常量。它可以设置一次(例如在构造对象时,但之后无法更改。)尝试更改它会生成编译时错误或异常(取决于尝试的偷偷摸摸程度)。

既是 final、static 和 public 的字段实际上是命名的常量。例如,一个物理程序可能定义 Physics.c,光速为

public class Physics {

  public static final double c = 2.998E8;


}

在 SlowCar 类中,speedLimit 字段可能既是 final 也是静态的,尽管它是私有的。

public class SlowCar extends Car {

  private final static double speedLimit = 112.65408; // kph == 70 mph

  public SlowCar(String licensePlate, double speed, double maxSpeed,
   String make, String model, int year, int numberOfPassengers, int numDoors) {
    super(licensePlate, 
     (speed < speedLimit) ? speed : speedLimit, 
     maxSpeed, make, model, year, numberOfPassengers, numDoors);
  }

  public void accelerate(double deltaV) {

     double speed = this.speed + deltaV;

     if (speed > this.maxSpeed) {
       speed = this.maxSpeed; 
     }

     if (speed > speedLimit) {
       speed = speedLimit;
     }

     if (speed < 0.0) {
       speed = 0.0; 
     } 

     this.speed = speed;    

  }

}

最后的论点

最后,您可以声明方法参数是最终的。这意味着该方法不会直接更改它们。由于所有参数都是按值传递的,因此这不是绝对必需的,但它有时会有所帮助。

于 2011-11-18T19:21:00.790 回答