0

次のコードを検討してください。

final String str = "1-2-3";

for (int idx = 0; idx < str.split("\\D").length; idx++) {
    // do something
}

コードのこの部分は何回str.split("\\D")実行されますか? 3回?strまたは、 が として宣言されているように、コンパイラは をfinal1 回呼び出すだけstr.split("\\D")で十分であることがわかりますか?

4

6 に答える 6

6

これはあなたにとって興味深いかもしれません。このコードの場合:

class Foo {
  public static void main(String args[]) {
    final String str = "1-2-3";

    for (int idx = 0; idx < str.split("\\D").length; idx++) {
    }
  }
}

バイトコードは次のとおりです。

Compiled from "Foo.java"
class Foo {
  Foo();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return        

  public static void main(java.lang.String[]);
    Code:
       0: iconst_0      
       1: istore_2      
       2: iload_2       
       3: ldc           #2                  // String 1-2-3
       5: ldc           #3                  // String \D
       7: invokevirtual #4                  // Method java/lang/String.split:(Ljava/lang/String;)[Ljava/lang/String;
      10: arraylength   
      11: if_icmpge     20
      14: iinc          2, 1
      17: goto          2
      20: return        
}

のファイナリティと の不変性に関係なく、 が3split回 4 回実行されることは明らかです。strsplit

于 2013-09-05T08:34:20.457 に答える
3

JLS 14.14.1.2 の状態 (ここではステートメントExpressionの中間ビット):for

次に、以下のように反復ステップが実行される。Expression が存在する場合は、評価されます。

つまり、反復ステップでそれを行うことを意味し、仕様には最適化の余地はありません。

次のコードでも同様のことがわかります。

class Test {
    public static int getSeven () {
        System.out.println ("called getSeven()");
        return 7;
    }
    public static void main (String[] args){
        for (int i = 1; i <= getSeven(); i++) {
            System.out.println ("i = " + i);
        }
    }
}

それを実行すると、次のようになります。

called getSeven()
i = 1
called getSeven()
i = 2
called getSeven()
i = 3
called getSeven()
i = 4
called getSeven()
i = 5
called getSeven()
i = 6
called getSeven()
i = 7
called getSeven()

関数がループのたびに呼び出されることを示しています (終了条件を含む)。

つまり、特定のケースでは 1 回または3 回呼び出されるのではなく、実際には4回呼び出され、idxそれぞれが01に設定され2、最終チェックが に設定され3ます。

于 2013-09-05T08:34:38.423 に答える
1

編集

splitメソッドは長さを決定するために 3 回実行されますが、これは文字列が最終的であるかどうかとは関係ありません。strign が final でない場合でも、同じように実行されます。

このを参照してください:

/* package whatever; // don't place package name! */

import java.util.*;
import java.lang.*;
import java.io.*;

/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
    public static void main (String[] args) throws java.lang.Exception
    {
        String g = "bla bla";
        for (int i = 0; i < index(g); i++)
        {
            System.out.println("Round");
        }
    }

    public static int index(String input)
    {
        System.out.println("index Called");
        return input.length();
    }
}

各ラウンドの出力が表示されます: index Called

于 2013-09-05T08:23:17.350 に答える
1

コンパイラが何かを最適化するかどうかを確認する 100% 確実な方法があります。コンパイル結果を見てください。私は応答にバイトコードを含めましたが、それはかなり明白だと思います-分割メソッドは、最後のキーワードに関係なく、最初のケースで複数回実行されます(invoke virtual 行は分割メソッド呼び出しです。 goto ステートメントによってループされます)。

ただし、異なるコンパイラは異なる方法で動作する場合があります。ご希望の環境で自由に再テストしてください ('javap -c classname' でバイトコードを表示できます)

public class gti {
    public static void main ( String[] args ) {
        final String str = "1-2-3";

        for (int idx = 0; idx < str.split("\\D").length; idx++) {
            // do something
        }
    }
}

結果:

public class gti {
  public gti();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: iconst_0
       1: istore_2
       2: iload_2
       3: ldc           #2                  // String 1-2-3
       5: ldc           #3                  // String \D
       7: invokevirtual #4                  // Method java/lang/String.split:(Ljava/lang/String;)[Ljava/lang/String;
      10: arraylength
      11: if_icmpge     20
      14: iinc          2, 1
      17: goto          2
      20: return
}

その間

public class gti {
    public static void main ( String[] args ) {
        final String str = "1-2-3";
        int length = str.split("\\D").length;
        for (int idx = 0; idx < length; idx++) {
            // do something
        }
    }
}

結果:

public class gti {
  public gti();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #2                  // String 1-2-3
       2: ldc           #3                  // String \D
       4: invokevirtual #4                  // Method java/lang/String.split:(Ljava/lang/String;)[Ljava/lang/String;
       7: arraylength
       8: istore_2
       9: iconst_0
      10: istore_3
      11: iload_3
      12: iload_2
      13: if_icmpge     22
      16: iinc          3, 1
      19: goto          11
      22: return
}
于 2013-09-05T08:38:28.337 に答える
1

どのように機能しfor loopますか

  1. 初期化 --->int idx = 0
  2. コンディションチェック --->str.split("\\D").length;
  3. ループ本体の実行
  4. インクリメント インデックスidx++
  5. 状態確認 str.split("\\D").length;
  6. ループ本体の実行
  7. idx < str.split("\\D").length()失敗するまで手順 4 ~ 6 を繰り返します

idx < str.split("\\D").length()したがって、あなたの意志が実行されるたびに。条件一致の場合は 3 回実行され、条件失敗の場合は最後に 1 回実行されると思います。

于 2013-09-05T08:31:16.050 に答える
0

str.split("\D") は str 文字列を分割せず、String[] 配列の新しいインスタンスを返します。答えは 3 回 str.split("\D") が実行されます。

于 2013-09-05T08:28:35.240 に答える