[解決済み] Javaリフレクションを用いた静的なプライベートfinalフィールドの変更
質問
を持つクラスがあります。
private static final
フィールドがありますが、残念ながら実行時に変更する必要があります。
リフレクションを使うと、こんなエラーが出ます。
java.lang.IllegalAccessException: Can not set static final boolean field
値を変更する方法はありますか?
Field hack = WarpTransform2D.class.getDeclaredField("USE_HACK");
hack.setAccessible(true);
hack.set(null, true);
解決方法は?
ないものとします。
SecurityManager
が邪魔をしている場合は
setAccessible
を回避するために
private
を消すためにモディファイアをリセットし
final
を変更し、実際に
private static final
のフィールドを作成します。
以下はその例です。
import java.lang.reflect.*;
public class EverythingIsTrue {
static void setFinalStatic(Field field, Object newValue) throws Exception {
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, newValue);
}
public static void main(String args[]) throws Exception {
setFinalStatic(Boolean.class.getField("FALSE"), true);
System.out.format("Everything is %s", false); // "Everything is true"
}
}
がないと仮定した場合
SecurityException
がスローされた場合、上記のコードでは
"Everything is true"
.
ここで実際に行われているのは、次のようなことです。
-
プリミティブな
boolean
値true
とfalse
でmain
は参照型に自動変換されます。Boolean
"定数"Boolean.TRUE
とBoolean.FALSE
-
リフレクションは
public static final Boolean.FALSE
を参照するようにします。Boolean
が参照するBoolean.TRUE
-
その結果、以後は
false
にオートボックス化されます。Boolean.FALSE
の場合、同じBoolean
で参照されるものと同じです。Boolean.TRUE
-
であったものはすべて
"false"
現在では"true"
関連する質問
-
リフレクションを使った変更
static final File.separatorChar
ユニットテスト用 -
setAccessibleを「正当な」使用方法のみに制限するには?
-
をいじる例があります。
Integer
のキャッシュを変更したりString
など
-
をいじる例があります。
注意事項
このようなことを行う場合は、常に細心の注意を払う必要があります。というのも
SecurityManager
があるかもしれませんが、そうでなくても、使用パターンによって、うまくいったりいかなかったりします。
デシリアライゼーションなどの場合、システムが
final
フィールドを作成します。final
フィールドは、リフレクションや他の実装に依存した手段で変更することができます。これが合理的な意味を持つ唯一のパターンは、オブジェクトが構築され、その後にfinal
フィールドが更新されます。オブジェクトは他のスレッドから見えるようにしてはいけませんし、またfinal
への更新がすべて終了するまでfinal
のフィールドが完了する。のフリーズはfinal
フィールドはコンストラクタの終了時に発生します。final
フィールドが設定された直後、およびfinal
フィールドをリフレクションや他の特別なメカニズムで使用することができます。それでも、いろいろと複雑な問題がある。もし
final
フィールドの宣言でコンパイル時の定数に初期化されている場合、その定数を変更するとfinal
フィールドの使用は観察されないかもしれません。final
フィールドはコンパイル時にコンパイル時定数に置き換えられます。もう一つの問題は、仕様上、積極的な最適化が可能な
final
フィールドがあります。スレッド内でfinal
フィールドの変更と、コンストラクタで行われない最終フィールドの変更です。
こちらもご覧ください
-
JLS 15.28 定数式
-
このテクニックは、プリミティブな
private static final boolean
なぜなら、コンパイル時に定数としてインライン化されるため、 "new"の値が観測できない可能性があるからです。
-
このテクニックは、プリミティブな
付録 ビット単位の操作について
本質的に
field.getModifiers() & ~Modifier.FINAL
に対応するビットをオフにします。
Modifier.FINAL
から
field.getModifiers()
.
&
はビットワイズアンド、そして
~
はビット単位の補集合です。
こちらもご覧ください
定数表現を覚える
まだ解決できないのか、私のように落ち込んでいるのか?あなたのコードはこのように見えますか?
public class A {
private final String myVar = "Some Value";
}
この回答に対するコメント、特に @Pshemo さんのものを読んで、私は次のことを思い出しました。 定数表現 は扱いが異なるので 不可能 を修正することができます。したがって、次のようなコードに変更する必要があります。
public class A {
private final String myVar;
private A() {
myVar = "Some Value";
}
}
クラスの所有者でない場合は... 私はあなたを感じる!
なぜこのような動作になるのか、詳しくは これを読む ?
関連
-
Java Exceptionが発生しました エラー解決
-
[解決済み] リフレクションを使用して文字列からプロパティ値を取得する
-
Exception: java.util.NoSuchElementException: 行が見つかりません
-
[解決済み] Javaにおけるpublic、protected、package-private、privateの違いは何ですか?
-
[解決済み] Java内部クラスと静的ネストされたクラス
-
[解決済み] 整数の平方根が整数であるかどうかを判断する最速の方法
-
[解決済み] Pythonにはクラス内に「プライベート」変数がある?
-
[解決済み] Javaにおける "final class "の意味とは?
-
[解決済み】Javaで異なるクラスからプライベートフィールドの値を読み取る方法は?
-
[解決済み】静的定数文字列(クラスメンバ)
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
springboot project MIMEタイプ text/htmlで転送された静的ファイルを読み込む。
-
javaの実行中に「javaの例外が発生しました」と表示された場合はどうすればよいですか?
-
アクセス制限について アプリケーションの種類がAPIでない(必要なライブラリの制限)。
-
eclipse アクセス制限です。タイプ 'xxx' は API ではありません(必須ライブラリ '' の制限)。
-
サーブレットクラスのインスタンス化エラーの解決法
-
スレッド "main" での例外 java.lang.ArrayIndexOutOfBoundsException: 1
-
javaでよく使われる英単語
-
SocketTimeoutExceptionの解決方法です。読み込みがタイムアウトした
-
JSPで「リストが型解決できない!」の解決方法
-
ローカルリソースのロードが許可されていない場合の解決策