適切なツール

献身の代わりに



常に...いいえ。 吹雪には決して入らず、そのような楽しみ以外の何かのためにそのようなコードを書いてください
画像
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つの事実を知る必要があります。
  1. 小さな(最も一般的な)値のキャッシュがあります
  2. オートボクシング中に、このキャッシュが使用されます(たとえば、コンストラクターではキャッシュは使用されません)

また、このキャッシュ名とその場所を知る必要がありますが、rt.jarソースのおかげでこれは問題ではありません。 どう思いますか? このキャッシュは、プライベート内部クラスのプライベートフィールドです。 やった!

これを行います:
  1. クラスIntegerのクラスオブジェクトを取得します
  2. その内部クラスのリストを引き出します
  3. それらの中から正しいものを見つけます(ここでは幸運です-それは1つだけです。本当です。そうすべきではないところを掘り下げているので、将来のバージョンで1つだけになるという保証はありません。)
  4. キャッシュフィールドを取得する
  5. プライベートなので、値を取得するためにアクセス可能にします
  6. これは配列です。 目的のセルの値を「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は動的言語であるという事実により、ソリューションは完全に異なります。 知っておくべきことは次のとおりです。
  1. Groovyは常にオブジェクトでのみ動作します(自動ボクシングはありません)
  2. Groovyはメソッドを使用してステートメントを実装します。 具体的には、「+」演算子はメソッドによって実装されます(サプライズ:)「plus()」
  3. GroovyのMetaClassを使用すると、任意のメソッドをクロージャーに簡単に置き換えることができます

ここに私たちがやることがあります:
  1. MetaClass整数を取る
  2. plus()メソッドを、常に60を返す実装に置き換えます

そしてそれだけです! コードは次のとおりです。
 Integer.metaClass.plus = {int i -> 60 } 

ここで、彼らが言うように-コメントなし。

正確に2つの出力があります。


  1. このコードでそのようなナンセンスに関与しないでください。
  2. 目標に合った適切なツールを使用してください。

シヴケル!


habrahabr.ru/post/144407

Source: https://habr.com/ru/post/J144297/


All Articles