Понимание Java "финал" для перевода на C#

Я не программист на Java. Я прочитал документацию по "final" и понимаю, что это означает, что "значение переменной может быть установлено один раз и только один раз".

Я перевожу Java на C#. Код не выполняется должным образом. Я попытался выяснить, почему, и нашел некоторые варианты использования final, которые не имеют смысла.

Фрагмент кода 1:

final int[] PRED = { 0, 0, 0 };
...
PRED[1] = 3;

PRED[1] будет 0 или 3?

Фрагмент кода 2:

final int[] PRED = new int[this.Nf];
for (int nComponent = 0; nComponent < this.Nf; nComponent++) {
    PRED[nComponent] = 0;
}
...
PRED[1] = 3;

Конечно, PRED[0] останется как 0?

6 ответов

Решение

Я думаю, у вас есть неправильное понимание final ключевое слово семантическое, когда оно применяется к массивам в Java.

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

final int[] PRED = new int[this.Nf];
// some other code
PRED = new int[123]; // <<== Compile error

вы увидите ошибку компиляции.

При переводе вашего кода на C# вам может потребоваться перевести final либо как sealed (когда он применяется к class) или как readonly (когда он применяется к члену). Семантика readonly массивы в C# и final Массивы в Java одинаковы: ваша программа не может переназначить массив, но может свободно изменять его элементы.

Наконец, есть специфичный для Java случай, когда final используется там, где он вообще не нужен в C#: когда вам нужно использовать переменную внутри метода анонимного локального класса в Java, вы должны сделать эту переменную final, Поскольку C# не имеет анонимных локальных классов, вам нужно будет перевести этот фрагмент кода с чем-то другим, возможно, с анонимными делегатами. Такие делегаты не ограничиваются использованием переменных только для чтения.

Слово, которое вы ищете в C#, это "const":

const int SOMETHING = 10;

Обратите внимание, что РАЗМЕР также должен быть постоянным.

Кроме того, константы могут быть только типа int, bool, string, char и т. Д. (Только базовые типы).

Поэтому, если вы хотите что-то еще, например, массив или класс, вы можете сделать:

static readonly int[] PRED = new int[this.Nf];

Статический Readonly означает точно const, логически, за исключением того, что он определен немного иначе за кулисами, что позволяет вам играть с ним более свободно. (Когда вы МОЖЕТЕ - вы ДОЛЖНЫ определять константы вместо статических только для чтения)

Сам массив не изменится во время выполнения, поэтому вы не сможете сделать это:

PRED = new int[3]; // Error
PRED = null; // Error
PRED = PRED; // Error

Но вы МОЖЕТЕ изменить значения ВНУТРИ массива PRED:

PRED[0] = 123;

Если вы хотите иметь коллекцию только для чтения, вы можете использовать объект ReadOnlyCollection! Если вы также хотите, чтобы этот объект был постоянным, вы можете использовать комбинацию static-readonly (вы не можете использовать константу, потому что это класс), и вы получите:

static readonly ReadOnlyCollection<int> PRED = new ReadOnlyCollection<int>(new[] {1, 2, 5, 6});

И тогда PRED всегда будет PRED, и всегда будет иметь размер 4, и всегда будет содержать 1, 2, 5, 6.

PRED = PRED; // Error (static readonly)
PRED = null; // Error (static readonly)
PRED[1] = 0; // Error (ReadOnlyCollection enforces readonly on the elements)

int i = PRED[1]; // Still works, since you aren't changing the collection.

final проверяется компилятором, а не во время выполнения. Так что если назначение PRED[1] = 3 был недействителен, он будет перехвачен компилятором, и код даже не скомпилируется.

Это присваивание допустимо, потому что последнее означает: вы не можете переназначить другое значение переменной. Это не значит: вы не можете изменить объект, на который ссылается переменная.

Приведенное выше назначение не изменяет значение PRED, Это изменяет значение PRED[1], Если бы PRED был списком, эквивалент был бы PRED.set(1, 3), Что в порядке. Что было бы неправильно, было бы PRED = new ArrayList<Integer>(),

Как вы уже заявили final переменная может быть установлена только один раз. Но законно ли менять свои ценности.

Ключевое слово Java final используется в языке программирования Java в разных условиях и имеет разные значения. Например:

  1. Чтобы объявить постоянную переменную,
  2. Объявить постоянный параметр метода.

    1. Переменная, объявленная как final, должна иметь инициализацию перед использованием. Этой переменной не может быть присвоено новое значение, например (a = b). Но если переменная не имеет примитивного типа, то ее свойства могут быть установлены с использованием методов set или любых других открытых полей. Это означает, что ссылка на экземпляр объекта не может быть изменена, но свойства экземпляра объекта могут быть изменены, если они сами не объявлены как окончательные.

    2. Запретить изменение параметра в методе, в котором он используется.

Если вы хотите, чтобы значение устанавливалось только один раз, хотя вместо final в java используйте readonly в C#, или const, или в некоторых случаях следует использовать sealed, хотя readonly, вероятно, лучше, если вы хотите только читать;)

Другие вопросы по тегам