献身の代わりに
常に...いいえ。
Guillaume-Groovy言語開発のリード
悪への反省
私の友人の一人はパズルの大ファンです。 任意、およびプログラマーを含む。 これが彼の最後の楽しみです。
アサートがクラッシュを停止するように、静的初期化子に目的のコードを記述します。
public class Test { static { //Write some code here } public static void main(String[] args) { Integer a = 20; Integer b = 20; assert (a + b == 60); } }
試してみることにした場合は、アサーションを含めるようにしてください(-eaフラグ付き) 。
その後、トピックに関する決定といくつかの推論がありますので、すでにそれを扱っている場合、またはあなたが壊れている場合は、それをカットしてください。
ソリューションから始めましょう。 特に複雑なことはなく、Integerクラスに関するリフレクションと2つの事実を知る必要があります。
- 小さな(最も一般的な)値のキャッシュがあります
- オートボクシング中に、このキャッシュが使用されます(たとえば、コンストラクターではキャッシュは使用されません)
また、このキャッシュ名とその場所を知る必要がありますが、rt.jarソースのおかげでこれは問題ではありません。 どう思いますか? このキャッシュは、プライベート内部クラスのプライベートフィールドです。 やった!
これを行います:
- クラスIntegerのクラスオブジェクトを取得します
- その内部クラスのリストを引き出します
- それらの中から正しいものを見つけます(ここでは幸運です-それは1つだけです。本当です。そうすべきではないところを掘り下げているので、将来のバージョンで1つだけになるという保証はありません。)
- キャッシュフィールドを取得する
- プライベートなので、値を取得するためにアクセス可能にします
- これは配列です。 目的のセルの値を「20」から「30」に変更します
コードは次のとおりです。
static { try { Class<?>[] declaredClasses = Integer.class.getDeclaredClasses(); Field cacheField = declaredClasses[0].getDeclaredField("cache"); cacheField.setAccessible(true); ((Integer[]) cacheField.get(null))[20 + 128] = 30; } catch (Exception e) { e.printStackTrace(); } }
私はあなたのことは知りませんが、私に関しては、ホラーホラーです。 可視性とカプセル化の規則に違反するべきではない場所をクロールし、ハーフキックで中断するいコード(たとえば、オートボクシングではなく、コンストラクターで整数を作成する必要があります)。
とにかく、私たちはIntegerがこのキャッシュを持っているというだけで幸運でした。 それ以外の場合、プラスの変更でこのトリックを行うことはできません。
なぜそんなに簡単なことをするのが難しいのですか? そのようなもののためのJavaは研ぎ澄まされていないので(それは同じ女性ですよね?) 。 Javaは静的言語であり、それで問題ありません。 20 + 20 = 40であるという事実を常に当てにすることができます。 まあ、ほとんどいつも。 これはいい 。
しかし、まだそのようなトリックを打ち出す必要がある場合(もちろん、プラスの動作の再定義ではなく、同様の)。 このためのより良いツールがあります。 たとえば、Groovy。
私たちはそれを正しく壊します!
Groovyパズルバージョンは次のとおりです。
//Write some code here Integer a = 20 Integer b = 20 assert 60 == a + b
パズルではほとんど同じ(メイン()、愚かなセミコロン、および-eaの必要性に対する不名誉なし)が、Groovyは動的言語であるという事実により、ソリューションは完全に異なります。 知っておくべきことは次のとおりです。
- Groovyは常にオブジェクトでのみ動作します(自動ボクシングはありません)
- Groovyはメソッドを使用してステートメントを実装します。 具体的には、「+」演算子はメソッドによって実装されます(サプライズ:)「plus()」
- GroovyのMetaClassを使用すると、任意のメソッドをクロージャーに簡単に置き換えることができます
ここに私たちがやることがあります:
- MetaClass整数を取る
- plus()メソッドを、常に60を返す実装に置き換えます
そしてそれだけです! コードは次のとおりです。
Integer.metaClass.plus = {int i -> 60 }
ここで、彼らが言うように-コメントなし。
正確に2つの出力があります。
- このコードでそのようなナンセンスに関与しないでください。
- 目標に合った適切なツールを使用してください。
シヴケル!
habrahabr.ru/post/144407