6

を に変換する必要があるたびに、またはを選択intしました。ここで、どちらの方法が速いのか疑問に思ったので、function_1、function_2、および function_3 を 10000000 回呼び出し、関数の処理にかかる時間を出力する簡単なベンチマークを作成しました。関数は次のとおりです。String""+aInteger.toString(a)

public static String i="";
public static String j="";
public static String k="";

public static void function_1()
{
    i=Integer.toString(getOne());
}

public static void function_2()
{
    j=""+1;
}

public static void function_3()
{
    j=""+getOne();
}

public static int getOne()
{
    return 1;
}

出力は次のとおりです。

Benchmarking starting...
Executing function_1 10000000 time(s)...
Done executing function_1 in 476 ms.
Executing function_2 10000000 time(s)...
Done executing function_2 in 8 ms.
Executing function_3 10000000 time(s)...
Done executing function_3 in 634 ms.
Benchmarking complete!

function_2 は次のようにコンパイルされているため、非常に高速だと思います

public static void function_2()
{
    j="1";
}

それを避けるために、getOne()代わりに関数を使用しました。しかし、ここに興味深い部分があります(私にとって):元の方法をfunction_3使用せずにコンパイルする必要があります(この場合はプリミティブであるため)。私の質問は次のとおりです。コンパイラは実際にどのように脅威を与えるので、呼び出しよりも遅くなりますか?toStringObjectInteger.toString(1)int""+1Integer.toString(1)

4

3 に答える 3

5

""1コンパイル時に認識されます。これが、バイトコードへの変換で infunction_2 "" + 1が実際に while に置き換えられる理由です。"1"

getOne()結果はコンパイル時に不明であるため、連結は実行時に行われます。ただし、連結 (+) は効率的ではないため、コンパイラがこれをStringBuilder.append()ベース実装に変更する可能性があります。

信じられない?試してください: するとjavap -c ClassName.class、次のように表示されます。

public static void function_2();
Code:
   0: ldc           #39                 // String 1
   2: putstatic     #16                 // Field j:Ljava/lang/String;
   5: return        


public static void function_3();
Code:
   0: new           #42                 // class java/lang/StringBuilder
   3: dup           
   4: invokespecial #44                 // Method java/lang/StringBuilder."<init>":()V
   7: invokestatic  #28                 // Method getOne:()I
  10: invokevirtual #45                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
  13: invokevirtual #49                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
  16: putstatic     #16                 // Field j:Ljava/lang/String;
  19: return 

function_2()関数_3にはこれらすべてのメソッド呼び出しがあり、内部に追加のStringBuilderがあります:)

実行時に最適化が行われる場合がありますが、この動作は JVM であり、構成に依存することに注意してください。

于 2013-03-27T21:05:31.213 に答える
1

10,000,000 回の反復で次の関数をテストしました。

public static void no_func_maybe_constant()
{
    j= "" + 1;
}

public static void no_func_no_constant()
{
    j = "";
    j = j + 1;
}

public static void yes_func_maybe_constant()
{
    j = "" + getOne();
}

public static void yes_func_no_constant()
{
    j = "";
    j = j + getOne();
}

私の結果:

no_func_maybe_constant Took 0.028058674s
no_func_no_constant Took 1.449465242s
yes_func_maybe_constant Took 1.275561897s
yes_func_no_constant Took 1.263362257s

関数を呼び出さない場合と関数を呼び出す場合の違いは実際には無視できるほどのものだったので、"" + 1実際にコンパイル時の定数計算を行っていたようです。関数がないと時間がかからないことがあるのが興味深い...

于 2013-03-27T20:47:58.697 に答える
0

2 と 3 の違いは、整数を取得するためにメソッドを呼び出さなければならないことが原因である可能性があります。メソッドを呼び出すと、新しいアクティベーション レコードが作成され、コール スタックが複雑になるため、JVM の JIT がその静的関数呼び出しを単一の戻り値にインライン化できない限り、ここでさらに処理が行われます (ここではほぼ確実に発生しません)。

于 2013-03-27T20:50:37.440 に答える