適切なツール

献身の代わりに





常に...いいえ。 吹雪には決して入らず、そのような楽しみ以外の何かのためにそのようなコードを書いてください

画像

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



All Articles