Объявление параметра функции как окончательного: зачем и когда это нужно? - PullRequest
4 голосов
/ 18 ноября 2011

Проходя учебник для Android (связанный с многопоточностью, луперами и обработчиками), я наткнулся на это:

public synchronized void enqueueDownload(final DownloadTask task)

Мои вопросы:

  1. Когда и почему необходимо объявить параметр функции как конечный?
  2. Это специфично для Java или что-то подобное существует в других языках, таких как C / C ++?

Ответы [ 4 ]

10 голосов
/ 18 ноября 2011

В 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
}
2 голосов
/ 18 ноября 2011

В вашем контексте последнее ключевое слово для этого параметра означает, что переменная задача не может быть переназначена внутри тела метода, и это указано в целях безопасности.

Подобное поведение может быть достигнуто в C ++ спостоянные параметры функции:

Если вы пишете функцию и не собираетесь изменять параметр, вы можете объявить, что это постоянный ссылочный параметр.

1 голос
/ 18 ноября 2011

Последнее ключевое слово используется в нескольких различных контекстах в качестве модификатора, означающего, что то, что оно изменяет, не может быть изменено в некотором смысле.

выпускные занятия

Вы заметите, что ряд классов в библиотеке Java объявлен как final, например,

публичный финальный класс String Это означает, что этот класс не будет разделен на подклассы, и информирует компилятор, что он может выполнить определенные оптимизации, которые он не мог бы сделать иначе. Это также дает некоторые преимущества в отношении безопасности и безопасности потоков.

Компилятор не позволит вам создать подкласс для любого класса, который объявлен как final. Вы, вероятно, не хотите или не должны объявлять свои собственные классы окончательными.

окончательные методы

Вы также можете объявить, что методы являются окончательными. Метод, объявленный как final, не может быть переопределен в подклассе. Синтаксис простой, просто поместите ключевое слово final после спецификатора доступа и перед возвращаемым типом, например так:

public final String convertCurrency()

Финальные поля

Вы также можете объявить поля окончательными. Это не то же самое, что объявить метод или класс финальным. Когда поле объявляется как final, это константа, которая не будет и не может измениться. Его можно установить один раз (например, когда объект создается, но после этого его нельзя изменить.) Попытки изменить его приведут либо к ошибке времени компиляции, либо к исключению (в зависимости от того, насколько хитрой является попытка).

Поля, которые являются как окончательными, так и статическими, и общедоступными, фактически называются константами. Например, физическая программа может определить Physics.c, скорость света как

public class Physics {

  public static final double c = 2.998E8;


}

В классе SlowCar поле speedLimit может быть как окончательным, так и статическим, хотя оно является приватным.

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;    

  }

}

окончательные аргументы

Наконец, вы можете объявить, что аргументы метода являются окончательными. Это означает, что метод не изменит их напрямую. Поскольку все аргументы передаются по значению, это не обязательно, но иногда полезно.

1 голос
/ 18 ноября 2011

Вы объявляете что-то как окончательное, если знаете , что оно никогда не должно быть переназначено.Вы часто хотите сделать это для параметров метода, поскольку редко имеет смысл переназначать параметр метода.

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

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

C и C ++ используют const вместо final, но я не могу утверждать, чтознать подробности от руки.

...