【问题标题】:Avoid creating multiple Class Objects in a for loop- Performance避免在 for 循环中创建多个类对象 - 性能
【发布时间】:2016-01-25 20:30:39
【问题描述】:

假设我有一个名为 Song 的类,其中包含很多信息,例如

  • 歌曲名称
  • 歌曲艺术家
  • 歌曲文件扩展名
  • 其他歌曲信息...

此类中的 setter 设置歌曲标题。

public class Song {
    private String title;
    private String artist;
    ...

    public Song(String songTitle, String songArtist, ...) {
        this.title=songTitle;
        this.artist=songArtist;
        ...
    }

    public void setTitle(String Songname){
        this.title = Songname;
    }

    public String getTitle(){return title;}
    public String getArtist(){return artist;}
    ...
}

我有一个 字符串 列表,其中包含不同的歌曲标题,但没有关于歌曲的其他信息。现在我想填充一个 Songs 列表,并在 setter 的帮助下将这些 Songs 类的标题设置为列表 Strings 中的标题。我在 for 语句中执行此操作,但如果我检查列表条目,我只会得到最后添加的歌曲的标题。

int index = 0;
Song songClass = new LocalSong(null, null, ...);
for (final String song : Songs) {
    try {
        songClass.setTitle(song);
        //Set Titles for Local Song Objects
        AnotherList.add(index, null);
        AnotherList.set(index, songClass);
        System.out.println("Title of Song number " + index + " is " + AnotherList.get(index).getTitle());
        index++;
    } catch (Exception e) {e.printStackTrace();}
}

我发现,当我不使用 Song 类中的 setter 并在 for 语句中为每个 List of Strings 条目创建一个新的 Song 对象时,它可以工作。像这样:

int index = 0;
for (final String songname : Songs) {
    try {
        Song songClass = new LocalSong(songname, null, ...);
        //Set Titles for Local Song Objects
        AnotherList.add(index, null);
        AnotherList.set(index, songClass);
        System.out.println("Title of Song number " + index + " is " + AnotherList.get(index).getTitle());
        index++;
    } catch (Exception e) {e.printStackTrace();}
}

但该解决方案不是性能要求高吗?例如,如果我在 Strings 列表中有数百个条目,我会创建数百个我不使用的歌曲类,或者垃圾收集器是否处理得很好?

另外,有没有更好的方法来创建带有我从 Strings 列表中获得的标题的歌曲类。

【问题讨论】:

  • 如果您只需要标题,为什么还要Song 实例?
  • 是的,您正在创建所有这些歌曲对象。但是物品很便宜。但是,您在什么意义上不使用这些歌曲对象?您将它们全部放入列表中是有原因的。无论如何,这不是性能好坏的问题,而是工作与否的问题。
  • Songs 是一个字段/变量/参数,应该以小写开头,如songs。 --- 为什么打电话给add(index, null); set(index, songClass); 而不仅仅是add(songClass)? --- songClass 应该只是 song
  • @DaveNewton 我在可扩展的列表视图中使用这些歌曲对象,我有一些包含更多信息的歌曲和一些只有标题的歌曲。我根据其在 exp 中的分组位置对对象进行不同的处理。列表视图。
  • 另外,请不要永远捕获这样的异常并继续处理,就好像没有出现任何问题一样。

标签: java android performance for-loop garbage-collection


【解决方案1】:

您指的是Song 类的instances,而不是很多类,而面向对象编程所有关于只要您有可识别的不同就创建实例对象。现代 Java 框架中的单个 HTTP 请求通常会创建然后丢弃 数千个 对象,而 JVM 被设计为可以很好地处理它。

更广泛地说,除非您有已证实的性能问题,否则不要针对性能进行优化——它实际上很慢,并且调查(例如分析)会告诉您问题出在哪里。

【讨论】:

    【解决方案2】:

    您似乎对创建新对象实例的关键字 new 存在根本性的误解。如果你只新建一个对象一次,那么列表中的所有对象引用都指向同一个对象,因此它是最后一个设置器,它指示无论访问哪个引用都可以看到值。

    您还尝试进行所谓的“过早优化”。请注意这一点,因为您经常会过度复杂化,从而通过关注这一点对代码的可维护性产生不利影响。可以做一些简单的小优化或选择同样容易或容易重构的替代方案,但要注意你没有解决不存在的问题。

    【讨论】:

      【解决方案3】:

      第二种解决方案有效的原因是因为您在 for 循环的每次迭代中都创建了 Song 类的 NEW 实例并将其添加到列表中。

      在第一个解决方案中,您在 for 循环 songClass 的每次迭代中都添加了 SAME 实例。您在这里所做的是更改songClass 的标题,并将其添加到列表中。

      至于垃圾收集,在代码的这个阶段创建一个包含很多对象的列表是完全可以的。当您不再使用对象时,垃圾收集器将释放它们。

      【讨论】:

        【解决方案4】:

        这里没有什么不寻常的,在第一个示例中,您重用了同一个对象,您的列表包含对同一个对象的相同引用。由于您修改它,因此您也在修改整个列表。

        但该解决方案的性能不是很重吗?

        不,至少在您测量到它需要太多内存或循环执行需要太多时间之前。如果发生这种情况,那么您应该重新设计您的代码,即。分块处理您的歌曲列表,仅处理用户在屏幕上看到的内容。也许重新设计您的 UI,让您的用户按字母顺序查看歌曲 - 仅在后面的 A、B、C ...... - 任何适合您的应用程序。

        【讨论】:

          【解决方案5】:

          限制多个实例的最简单方法

          import java.awt.event.WindowEvent;
          import java.awt.event.WindowListener;
          import java.io.*;
          
          import javax.swing.JFrame;
          
          
          public class SingleWindow {
              static String str;
              
              private SingleWindow() {
                  
              }
              
              private static void single() {
                  readFile();
                  System.out.println("Single str =" + str);
                  if (str.equals("false")) {
                      gui();
                      writeFile("true");
                  }
              }
                  
              private static void writeFile(String str){
                  try {
                      PrintWriter pw = new PrintWriter("E:\\Temp.txt");
                      pw.print(str);
                      pw.close();
                  } catch (IOException e) {
                      // TODO Auto-generated catch block
                      e.printStackTrace();
                  }   
              }
              
              static void readFile() {
                  String status = null;
                  System.out.println("readFile() entered \n");
                  try {
                      FileReader fr = new FileReader("E:\\temp.txt");
                      BufferedReader br = new BufferedReader(fr);
                      while((status = br.readLine())!=null){
                          str = status;
                          System.out.println("Status " + status);
                      }
                      br.close();
                  } catch (IOException e) {
                      // TODO Auto-generated catch block
                      e.printStackTrace();
                  }
              }
              
              static void gui() {
                  System.out.println("Entered GUI method \n");
                  JFrame frame = new JFrame();
                  frame.setVisible(true);
                  frame.setSize(300,300);
                  frame.addWindowListener(new WindowListener() {
                      @Override
                      public void windowOpened(WindowEvent arg0) {}
                      
                      @Override
                      public void windowIconified(WindowEvent arg0) {}
                      
                      @Override
                      public void windowDeiconified(WindowEvent arg0) {}
                      
                      @Override
                      public void windowDeactivated(WindowEvent arg0) {}
                      
                      @Override
                      public void windowClosing(WindowEvent arg0) {
                          System.out.println("Windows Closing \n");
                          writeFile("false");
                      }
                      
                      @Override
                      public void windowClosed(WindowEvent arg0) {
                          System.out.println("Windows Closed \n");
                      }
                      
                      @Override
                      public void windowActivated(WindowEvent arg0) {
                          //writeFile("false");
                          System.out.println("Windows Activate \n");
                      }
                  });
              }
              
              
              public static void main(String args[]) {
                  single();
                  System.out.println(str + "main method \n");
              }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-06-28
            相关资源
            最近更新 更多