在Java中声明内联数组更快(或更好)吗?

时间:2013-12-03 10:39:06

标签: java arrays inline

考虑以下两个几乎相同的方法调用。记下在两者上声明和分配字节数组的方式。

void Method1()
{
    byte [] bytearray = new byte[16];

    /* some code */

}

void Method2()
{
    byte [] bytearray = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

    /* some code */    
}

在这两种情况下,假设当Method1和Method2返回时,“bytearray”是垃圾收集的候选者,因为操作bytearray变量的代码都不会持有超出方法本身末尾的引用。

Method2是否通过避免调用“new”来更快地(或不同地)运行?或者上述两种实现是否相同?在任何一种情况下,Java编译器或运行时都可以进行优化以避免为这个短暂的临时缓冲区命中内存分配器的开销吗?

7 个答案:

答案 0 :(得分:11)

哪种形式最快?取决于JIT - 它们可能是相同的。很少(如果有的话)程序会注意到差异,如果有的话。

哪种形式最好?几乎总是让您的程序更具可读性。

但是,无论我们是否会注意到,是否存在实际的差异?我们来看看吧!

class ArrayTest {

    public int[] withNew() {
        int[] arr = new int[4];
        return arr;
    }

    public int[] withInitializer() {
        int[] arr = {0, 0, 0, 0};
        return arr;
    }

}

我们用javap -c ArrayTest

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

  public int[] withNew();
    Code:
       0: iconst_4      
       1: newarray       int
       3: astore_1      
       4: aload_1       
       5: areturn       

  public int[] withInitializer();
    Code:
       0: iconst_4      
       1: newarray       int
       3: dup           
       4: iconst_0      
       5: iconst_0      
       6: iastore       
       7: dup           
       8: iconst_1      
       9: iconst_0      
      10: iastore       
      11: dup           
      12: iconst_2      
      13: iconst_0      
      14: iastore       
      15: dup           
      16: iconst_3      
      17: iconst_0      
      18: iastore       
      19: astore_1      
      20: aload_1       
      21: areturn       
}

不,在这种情况下它们不一样 - 使用初始化器形式会使插槽单独设置为0,这有点无意义,因为它们已经被数组分配归零。所以,它基本上等同于:

public int[] withNewAndSettingExplicitly() {
    int[] arr = new int[4];
    arr[0] = 0;
    arr[1] = 0;
    arr[2] = 0;
    arr[3] = 0;
    return arr;
}

虽然它编译为另一组字节代码,但大致相同但不完全相同:

  public int[] withNewAndSettingExplicitly();
    Code:
       0: iconst_4      
       1: newarray       int
       3: astore_1      
       4: aload_1       
       5: iconst_0      
       6: iconst_0      
       7: iastore       
       8: aload_1       
       9: iconst_1      
      10: iconst_0      
      11: iastore       
      12: aload_1       
      13: iconst_2      
      14: iconst_0      
      15: iastore       
      16: aload_1       
      17: iconst_3      
      18: iconst_0      
      19: iastore       
      20: aload_1       
      21: areturn 

因此,故事的寓意是这样的:如果你想要将所有元素设置为0,那么你使用new int[size]生成的字节码更少(可能更快或更快),但是你也必须打字少(这是一个很大的胜利)。如果要在分配数组时直接设置数组中的值,请使用代码中最佳的代码,因为无论您选择何种形式,生成的代码都将完全相同。

现在,回答你的实际问题:

  

Method2是否通过避免调用“new”来更快地(或不同地)运行?

正如我们所看到的,new隐藏在初始化语法后面(查找newarray操作码)。顺便说一句,JVM中的分配非常便宜(世代垃圾收集器具有令人愉快的副作用)。

  

或者上述两种实现是否相同?

正如我们所看到的那样 - 并不完全,但不太可能有人会注意到差异。

  

在任何一种情况下,Java编译器或运行时都可以进行优化,以避免为这个短暂的临时缓冲区命中内存分配器的开销吗?

再次 - 分配很便宜,所以不用担心。尽管如此,最近的JVM有一个名为escape analysis的小功能,这可能导致数组被分配堆栈而不是堆分配。

答案 1 :(得分:5)

两种方式之间没有区别。语法只是'Syntactic sugar'

答案 2 :(得分:3)

他们是一样的。

new关键字会创建对象。但在Java中,数组是.. 对象。见Chapter 10. Arrays

  

在Java编程语言中,数组是对象(§4.3.1),是   动态创建,可以分配给Object类型的变量   (§4.3.2)。可以在数组上调用Object类的所有方法   ..
  数组由数组创建表达式§15.10或数组初始值设定项§10.6)创建。

答案 3 :(得分:2)

这两种方法完全相同。但是,对于较长的数组或者如果要修改数组长度,第二种方法更冗长,更不方便。

答案 4 :(得分:0)

最好使用第一种风格。

在第二种风格上我试图找到一个非0。它保证更无错误,因此更易读。

这个速记有充分的理由存在!

答案 5 :(得分:0)

两者都是相同的......因为两者都将占用堆上的相同空间......并且字节码将是研究它的选项

答案 6 :(得分:0)

两者都是相同的但我不推荐第二个,因为它很难读写和调试。想象一下,你发现了这个:

byte [] bytearray = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

你能判断出阵列的大小是否正确吗?是的,但想象一下是:

byte [] bytearray = new byte[25];

这要容易得多。

想象一下数组长度为100的情况!