Groovyの暗黙的な型キャストの機能

少し前に、Groovyのメールリストで質問しました-高性能なGroovyを書くときに避けるべき安定したリストはありますか。 他のヒントの中でも、Groovyの主要な開発者の1人であるJochen "blackdrag" Theodorouは、一般に、変数を宣言するときに特定の型を使用することが多いことを指摘しました(たとえば、def var = ...の代わりにMyType var = ...)型チェックおよび必要に応じて変換するためのオーバーヘッドコスト。



Groovy開発者によると、この領域の問題の多くは1.7までのバージョンで観察され、バージョン1.9で行われたランタイムの一般的な最適化に関する多くの作業中に修正されました。 ただし、以下は、Groovy 1.8.3でもこれらのオーバーヘッドが示す小さな実験です。



この実験の前に、次の記事groovy.codehaus.org/From+source+code+to+bytecodeを確認すると役立ちます。これは、GroovyのソースコードがJVMバイトコードに変換される方法と、入力を読み取る方法を示しています。実際のバイトコード内の記事、たとえば次の記事-www.ibm.com/developerworks/ibm/library/it-haggar_bytecode







したがって、最も単純なコードは次のとおりです。



class NoStrictType { void myMethod1() { def a = 4.2 } } class StrictType { void myMethod1() { int a = 4.2 } }
      
      







唯一の違いは、2番目のクラスでは、ローカル変数の型が明示的に定義されていることです。 両方のクラスをコンパイルし、これらのメソッドのバイトコードを調べます。

最初の場合(特定のタイプなし):



画像



したがって、コードは非常に明白です。 最初の行を省略します。これは、キャッシュされたCallSiteの配列を取得するもので、タイプ操作に直接関係しません。 次に、BigDecimal型の新しいオブジェクトを作成します(Groovyではデフォルトですべての非整数値がBidDecimalとして表されることを誰もが覚えていますか?)、オペランドスタックの最上部で現在の値を複製し、定数プールから値4.2を取得し、BigDecimalオブジェクトを初期化し、この作成されたオブジェクトへのリンクを保存します現在のフレームのローカル変数の配列の2番目のセルで、そこからスタックの最上部にロードし、最後にpopを使用して、メソッドからこのリンクを返します。 繰り返しになりますが、Groovyでは、明示的なreturnステートメントがなくても、計算で使用された最後の変数(より正確には、メソッド終了時にオペランドスタックの最上部に保存された最後のリンク)が返されます。



現在、2番目のクラスのバイトコードはStrictTypeです。



画像



最初のケースと比較した違いは何ですか? 静的メソッドDefaultTypeTransformation.intUnbox()の呼び出しが追加されました。 それが何をするのかについて、このメソッドのドキュメントを見てみましょう。

groovy.codehaus.org/api/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.html

このメソッドは、リンクオブジェクトを単純にNumber型のオブジェクトに変換し、プリミティブを返すことがわかります。



 public static int intUnbox(Object value) { Number n = castToNumber(value, int.class); return n.intValue(); }
      
      







この型変換がどのように実行されるかを見てみましょう。



  public static Number castToNumber(Object object, Class type) { if (object instanceof Number) return (Number) object; if (object instanceof Character) { return Integer.valueOf(((Character) object).charValue()); } if (object instanceof GString) { String c = ((GString) object).toString(); if (c.length() == 1) { return Integer.valueOf(c.charAt(0)); } else { throw new GroovyCastException(c, type); } } if (object instanceof String) { String c = (String) object; if (c.length() == 1) { return Integer.valueOf(c.charAt(0)); } else { throw new GroovyCastException(c, type); } } throw new GroovyCastException(object, type); }
      
      







最も安価ではないいくつかのinstanceof演算子、いくつかの明示的な型変換、条件演算子は、例外を処理します。 これが実際のアプリケーションの作業速度にどのように影響するかは測定しませんでしたが、事実から判断すると、この場合、型キャストのために追加のバイトコードをいくつ実行する必要があるかが印象的です。 覚えておいてください-元のメソッド自体-10バイトコードのみ。



All Articles