0

XMLファイルから読み取るこのコードがあります。5つの文字列(groupId、groupType、filePath、author、lineNo)を取得し、最初にそれらを文字列配列に保存します。次に、文字列配列がArrayListに保存されます。最後に、最後の「for」はArrayListの内容を表示します。

コンテンツを表示したいときに、最後に追加された文字列配列だけを取得するという問題。以下はコードと出力です。誰かが問題が何であるかを理解できますか?

ArrayList<String[]> developerTypes = new ArrayList<String[]>();
String[] developerInfo = {null, null, null, null, null};
String[] developerInfoR = {null, null, null, null, null};

String groupId;
String groupType;
String filePath;
String author;
String lineNo;


SAXBuilder builder = new SAXBuilder();
Document doc = (Document) builder.build("A.xml");
Element clones = doc.getRootElement();

// Loop of clones' children (clone_group)
List<Element> parentElements = clones.getChildren();
for(Element parentElement:parentElements){


    // Loop of clone_group's children (clone_fragment)
    List<Element> elements = parentElement.getChildren();
    for(Element element:elements){

        // Loop of clone_fragment's children (blameInfo)
        List<Element> childelements = element.getChildren();
        for(Element childElement:childelements){

            groupId = parentElement.getAttributeValue("groupid");
            groupType = parentElement.getAttributeValue("type");
            filePath = element.getAttributeValue("file");
            author = childElement.getAttributeValue("author");
            lineNo = childElement.getAttributeValue("lineNo");
            //System.out.print(groupId + " - ");
            //System.out.print(groupType + " - ");
            //System.out.print(file + " - ");
            //System.out.println(author);
            developerInfo[0] = groupId;
            developerInfo[1] = groupType;
            developerInfo[2] = filePath.substring(1, filePath.lastIndexOf("."));;
            developerInfo[3] = author;
            developerInfo[4] = lineNo;
            developerTypes.add(developerInfo);

        }// for (blameInfo)    
    }// for (clone_fragment)
}// for (clone_group)

// Display the content of the Arraylist    
for(int i = 0; i< developerTypes.size(); ++i){

    developerInfoR = developerTypes.get(i);

    for(int j = 0; j< developerInfoR.length; ++j){

        System.out.print(developerInfoR[j] + " ");

    }
    System.out.print("\n");

}

出力:

309 Type-3 builtin/update-index.c Jonathan Nieder 704 
309 Type-3 builtin/update-index.c Jonathan Nieder 704 
309 Type-3 builtin/update-index.c Jonathan Nieder 704 
309 Type-3 builtin/update-index.c Jonathan Nieder 704 
309 Type-3 builtin/update-index.c Jonathan Nieder 704 
309 Type-3 builtin/update-index.c Jonathan Nieder 704 
309 Type-3 builtin/update-index.c Jonathan Nieder 704 
309 Type-3 builtin/update-index.c Jonathan Nieder 704 
309 Type-3 builtin/update-index.c Jonathan Nieder 704 
309 Type-3 builtin/update-index.c Jonathan Nieder 704 
309 Type-3 builtin/update-index.c Jonathan Nieder 704 
309 Type-3 builtin/update-index.c Jonathan Nieder 704 
...
4

3 に答える 3

3

コンテンツを表示したいときに、最後に追加された文字列配列だけを取得するという問題。

いいえ、同じ文字列配列への参照が多数あることがわかります...それはあなたが追加したものだからです。文字列配列オブジェクトは 1 つしかありません。その配列への単なる参照です。を呼び出すと、参照が にコピーされるため、同じ参照が何度も取得されます。developerInfodeveloperTypes.add(developerInfo)ArrayList

の宣言とインスタンス化をdeveloperInfoループに入れる必要があります。

String[] developerInfo = {
    groupId,
    groupType,
    filePath.substring(1, filePath.lastIndexOf(".")),
    author,
    lineNo
};
developerTypes.add(developerInfo);

developerInfoR同様に、使用するまで宣言しなかった場合、コードはよりクリーンになります。

for(int i = 0; i< developerTypes.size(); ++i){
    String[] developerInfoR = developerTypes.get(i);
    for(int j = 0; j< developerInfoR.length; ++j){
        System.out.print(developerInfoR[j] + " ");
    }
    System.out.print("\n");
}

または、さらに良いことに、強化された for ループを使用します。

for (String[] developerInfoR : developerTypes) {
    for (String info : developerInfoR) {
        System.out.print(info + " ");
    }
    System.out.print("\n");
}

一般に、できるだけ遅く、理想的には宣言の時点で値を割り当てて、回避できる最小のスコープでローカル変数を宣言する必要があります。メソッドの先頭ですべての変数を宣言すると、可読性が大幅に低下します。

于 2012-06-27T20:09:50.163 に答える
2

developerInfoループ内で何度も追加し続ける配列のインスタンスは 1 つだけです。各ループ ステップで新しい配列を作成する必要があります。

使用しているコンストラクトのセマンティクスについて誤解しているようです。前もって初期化している方法から推測していますがdeveloperInfoR、その値を使用することはありません。配列変数には配列への参照のみが含まれているため、それに割り当てるたびに、以前に参照されていた配列は忘れられて破棄されます。したがって、前もって初期化しないでくださいdeveloperInfo。実際、使用する場所まで宣言する必要さえありません。

配列の内容を出力する簡単な方法もあります: を呼び出すだけSystem.out.println(Arrays.toString(developerInfoR))です。そうすれば、印刷コードの内側のループさえ必要ありません。

変数 groupId、groupType、filePath、author、lineNo は必要ありません。例などを書くだけdeveloperInfo[0] = parentElement.getAttributeValue("groupid");です。これにより、より明白なコードが作成されます。しかし、String[] の代わりに完全なオブジェクトを使用することはおそらく理にかなっています。多くのフィールドがあり、それぞれの意味は整数インデックスの背後にあります。

全体として、これらの提案に加えていくつかの追加提案を行うと、コードは次のように書き直すことができます。

final String path = filePath.substring(1, filePath.lastIndexOf("."));
final Document doc = (Document) new SAXBuilder().build("A.xml");
final List<DeveloperInfo> developers = new ArrayList<String[]>();
for (Element parentElement : doc.getRootElement().getChildren())
  for (Element element : parentElement.getChildren())
    for (Element childElement : element.getChildren())
      developers.add(new DeveloperInfo(
          parentElement.getAttributeValue("groupid"),
          parentElement.getAttributeValue("type"),
          element.getAttributeValue("file"),
          path,
          childElement.getAttributeValue("author"),
          childElement.getAttributeValue("lineNo"),
      ));
for (DeveloperInfo d : developerTypes) System.out.println(d);

DeveloperInfo クラス:

class DeveloperInfo {
  public final String groupId, groupType, filePath, author, lineNo;
  public DeveloperInfo(
      String groupId, String groupType, String filePath, 
      String author, String lineNo)
  {
    this.groupId = groupId; this.groupType = groupType; this.filePath = filePath;
    this.author = author; this.lineNo = lineNo;
  }
  public String toString() {
    return "DeveloperInfo [groupId=" + groupId + ", groupType=" + groupType + 
      ", filePath=" + filePath + ", author=" + author + ", lineNo=" + lineNo + "]";
  }
于 2012-06-27T20:09:40.280 に答える
0

に追加するたびに、同じ配列を参照していますArrayList

これを宣言する代わりにString[] developerInfo = {null, null, null, null, null};

最初に。ループするたびに新しい配列を作成します。

String[] developerInfo = new String[5];

于 2012-06-27T20:10:22.067 に答える