Сеттерные методы для конечных полей
Используя отражение, а также из src.zip, доступного в установленном JDK установщиком, предоставленным http://docs.oracle.com, я нашел следующие поля java.lang.System
,
в, out и err объявлены как final, но у них есть соответствующие (публичные) методы настройки, которые, в свою очередь, вызывают их соответствующие противоионы-часть.
Например, я могу успешно перенаправить вывод консоли в файл.
Мы можем установить конечные переменные точно, как только мы инициализировали его в Java-коде.
Мой вопрос: это правило окончательного не применимо к собственному коду?
Ответы
Ответ 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);
}
они отправляют переданный поток в собственный код, и этот код отвечает за установку этого потока для текущего использования. Таким образом, конечная переменная не переустанавливается, и эта переменная не используется в собственном коде, независимо от потока, который он передает в собственный код, он использует это