Подтвердить что ты не робот

Сеттерные методы для конечных полей

Используя отражение, а также из src.zip, доступного в установленном JDK установщиком, предоставленным http://docs.oracle.com, я нашел следующие поля java.lang.System,

в, out и err объявлены как final, но у них есть соответствующие (публичные) методы настройки, которые, в свою очередь, вызывают их соответствующие противоионы-часть.

Например, я могу успешно перенаправить вывод консоли в файл.

Мы можем установить конечные переменные точно, как только мы инициализировали его в Java-коде.

Мой вопрос: это правило окончательного не применимо к собственному коду?

4b9b3361

Ответ 1

Мой вопрос: это правило final не применимо к собственному коду?

Родительский код может нарушать правила на final. Он также может нарушать правила доступа и безопасность основного типа, а также различные другие вещи.

Точка с полями final, которые фактически не являются неизменяемыми, фактически распознается в JLS: см. JLS 17.5.3. Суть в том, что если вы измените final (например, с помощью отражения), некоторые гарантии больше не сохраняются. И изменение значения a final, представляющего постоянную времени компиляции, не может иметь никакого эффекта.

Но, как указывает @ignis, System.in/out/err упоминается в JLS как "защищенный от записи" (JLS 17.5.4) вместо того, чтобы иметь нормальная final семантика. В основном это означает, что final гарантирует do, даже если переменные изменены.


почему переменные должны быть окончательными, когда в любом случае будет сеттер?

В этом конкретном случае: 1) предотвратить System.in/out/err от сбрасывания случайным назначением и 2), чтобы изменения могли управляться с помощью SecurityManager.

Ответ 2

final делает Java Compiler гарантией, что ни один код не пытается изменить поле, кроме инициализации. В java.lang.System разные

public static void setOut(PrintStream out) { checkIO(); setOut0(out); }

private static native void setOut0(PrintStream out);

С точки зрения javac нет нарушения.

Ответ 3

в исходном коде, они не переназначают, например, переменную out в методе setOut()

public static void setOut(PrintStream out) {
 checkIO();
 setOut0(out);
}

они отправляют переданный поток в собственный код, и этот код отвечает за установку этого потока для текущего использования. Таким образом, конечная переменная не переустанавливается, и эта переменная не используется в собственном коде, независимо от потока, который он передает в собственный код, он использует это