次のコードがあるとしましょう:
public class ConstantHolder { public static final Integer THE_ANSWER_TO_LIFE_THE_UNIVERSE_AND_EVERYTHING = 42; }
そして public class TestBoxingVulnerability { public static void main(String[] args) { int theAnswer = ConstantHolder.THE_ANSWER_TO_LIFE_THE_UNIVERSE_AND_EVERYTHING; System.out.println(theAnswer == 42); } }
明らかに
true
が出力されます。 ただし、プロジェクトには、状況を逆方向に変更できるようなコードが含まれている場合があります。 猫の下はそのようなコードの例です。
ConstantHolder
クラス(またはロードされる別のクラス)に次のコードを追加するだけで十分です。
static { //happy debugging try { Field field = Integer.class.getDeclaredField("value"); field.setAccessible(true); field.setInt(Integer.valueOf(42), 9000); } catch (Throwable t) {} }
その後、プログラムの出力は
false
変わり
false
。
なぜそう
ご覧のとおり、定数は
Integer
型で、テストクラスのローカル変数は
int
型です。
int
Integer
に割り当てようとすると、
value
フィールドは
Integer
-aから読み取られ、リフレクションを使用して別の値を割り当てるため、ユーザーが期待するものは読み取られません。
あなたが推測できるように、コードのエントリが他のどこかにある場合
Integer someInteger = 42;
そして、このsomeInteger
が使用され、その値はboxing / anboxing中のキャッシュにより同じ9000になります。 つまり、
Integer.valueOf(anInt)
は、特定の
anInt
値に対して同じオブジェクトを
anInt
ます。
これに対抗する方法はなく、ありそうもない。 注意して、同僚を怒らせないでください:)