java - リフレクションを使用して 2 + 2 = 5 をオーバーライドする

okwaves2024-01-25  7

少々お待ちください。これは奇妙な問題であることは理解しています。

私はちょうど Java のリフレクション ライブラリ、特に 2 + 2 = 5 をオーバーライドする Lex Fridman のビデオからのコードを見つけました。

import java.lang.reflect.Field;

public class Main {
    public static void main(String[] args) throws Exception {
        Class cache = Integer.class.getDeclaredClasses()[0];
        Field c = cache.getDeclaredField("cache");
        c.setAccessible(true);
        Integer[] array = (Integer[]) c.get(cache);
        array[132] = array[133];

        System.out.printf("%d",2 + 2);
    }
}

同等の Scala 形式に変換して、その動作を理解しようとしていますが、Int.getClass.getDeclaredClasses が空の配列を返すため、コンパイルできません。

import java.lang.reflect.Field

val cache: Class[_] = Int.getClass.getDeclaredClasses.head
// above line throws java.util.NoSuchElementException: next on empty iterator

val c: Field = cache.getDeclaredField("cache")
c.setAccessible(true)
val array = c.get(cache).asInstanceOf[Array[Int]]
array(132) = 5

println(2+2)

私がそれを使用しようとしたとき、class も getClass も Integer の下のメソッドではなかったので、代わりに Int を使用してみました。 Scala の Int は Java の Integer の単なるラッパーであるという印象を受けていましたが、そうではありませんか?

私も試してみました:

new Integer() (「代替メソッドを備えたオーバーロードされたメソッド コンストラクター Integer」に関する苦情) new Int() ("クラス Int は抽象クラスです。インスタンス化できません」) クラス T で Int と Integer の両方を拡張すると、Int ... new T.getClass.... (最終クラスからの不正な継承) が拡張されます。

これが Scala でコンパイルできない Java で機能するのはなぜですか? Scala で 2 + 2 = 5 という愚かな目標を達成するにはどうすればよいでしょうか?

2

関連 (および重複の可能性あり): stackoverflow.com/questions/63733340/…

– VGR

2020 年 9 月 5 日 1:35

@VGR 良いリンクです。問題は Scala で再現する方法だったため、おそらく重複ではありません。

– ドミトロ・ミティン

2020 年 9 月 5 日 7:37

@VGR Dmytro の言うとおり、私は特にこの Java コードの Scala 翻訳に興味があるので、私の質問には答えられませんが、内部で何が起こっているかについての説明は非常に興味深いものです。関係なく役に立ちます。有益なリンクをありがとうございます!

– ジェームズ・ホワイトリー

2020 年 9 月 5 日 19:31



------------------------

scala.Int の代わりに java.lang.Integer を使用する必要があります。

Int.getClass は、クラス Int のコンパニオン オブジェクトに対して呼び出される getClass ですが、これは間違っています。

コードの Scala への翻訳は次のとおりです

val cache = classOf[Integer].getDeclaredClasses.apply(0)
val c = cache.getDeclaredField("cache")
c.setAccessible(true)
val array = c.get(cache).asInstanceOf[Array[Integer]]
array(132) = array(133)
println(2 + 2) // 5

Scala の Int は Java の Integer の単なるラッパーであるという印象を受けていましたが、そうではありませんか?

そうではありません。通常、scala.Int は Java int に対応します。

https://github.com/scala/scala/blob/2.13.x/src/library/scala/Int.scala

----------------------------------

Integer クラス内の IntegerCache 内部クラスをチェックした場合。実装の一部は次のとおりです。

        high = h;

        cache = new Integer[(high - low) + 1];
        int j = low;
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);

デフォルトでは、-128 (低) から 127 (高) までの整数です (おそらく、これらが一般的なアプリケーションで最もよく使用されるため選択されます)。キャッシュ サイズは 256 です (そのため、- と + の値は一緒に保持されます)

アプリケーションでは、「キャッシュ」を取得します。 -128 から 127 までの値である Integer クラスのフィールド。ただし、配列内ではこれらが一緒に保持されるため、値 0 のインデックスは実際には 128 (最初に -128 の値があるため) + 0 になります。

0 -> 128
1 -> 129
2 -> 130
3 -> 131
4 -> 132
5 -> 133

そして、配列[132] = 配列[133];式はキャッシュ内で 4 = 5 を作成します。したがって、アプリケーションがキャッシュからインデックス 4 を呼び出すたびに、整数 5 が返されます。

Scala 部分については、私は持っていません。Scala の経験はありますが、バイト コードにコンパイルするためだけに JVM を使用するのではありませんか?したがって、おそらく Scala は JDK を使用しておらず、その Int 実装が異なるため、エラーが発生します (@Dmytro Mitin の回答に基づいて JDK から Integer を使用できるようです)。

総合生活情報サイト - OKWAVES
総合生活情報サイト - OKWAVES
生活総合情報サイトokwaves(オールアバウト)。その道のプロ(専門家)が、日常生活をより豊かに快適にするノウハウから業界の最新動向、読み物コラムまで、多彩なコンテンツを発信。