Java 嵌套获取性能

Java 嵌套获取性能,java,Java,在Java中,如果我继续使用嵌套get来检索值,是否会影响性能?例如: String firstname = getOffice().getDepartment().getEmployee().getFirstName(); String lastname = getOffice().getDepartment().getEmployee().getLastName(); String address = getOffice().getDepartment().getEmployee().get

在Java中,如果我继续使用嵌套get来检索值,是否会影响性能?例如:

String firstname = getOffice().getDepartment().getEmployee().getFirstName();
String lastname = getOffice().getDepartment().getEmployee().getLastName();
String address = getOffice().getDepartment().getEmployee().getAddress();
VS:


第二个版本会因为“跳跃”更少而更快吗?

而不是性能我认为第二个版本是更好的人类理解代码。您不应该担心微优化,而应该编写一个好的、干净的代码。

这完全取决于
getXYZ
调用做什么。如果它们是对底层字段的简单访问器,那么不,不是在HotSpot(Oracle的JVM)上,因为如果有任何需要,它们将得到优化。另一方面,如果他们做任何类型的复杂工作(遍历btree,等等),那么他们当然必须重复做这些工作(除非hospot可以向自己证明调用是幂等的,如果代码有任何复杂性,这是不可能的)。(他们重复工作是否重要是另一个问题;除非你看到实际的性能问题,否则不要担心。)


但第二个更具可读性和可维护性。这是使用它的更有力的理由。

可能是的。但是假设吸气剂在内部看起来像普通吸气剂,它可能会非常小,以至于几乎无法测量

此外,如果您经常运行此代码,使其变得重要,那么Hotspot编译器的魔力会将字节码踢进并弄乱,可能会再次使这两种变体相同


最后,很难说到底会发生什么。如果性能对您很重要,请设置测试。如果性能不足以证明测试成本的合理性。。。好吧,那就不用担心了。

您正在考虑的优化被称为。你不应该去想这些,除非你真的不得不去想

我同意@AmitD的答案,认为这是第二个更具可读性的答案。当像这样链接方法调用时,您还可以用以下方式编写它们-

Employee e = getOffice()
              .getDepartment()
              .getEmployee();
String firstname = e.getFirstName();
String lastname = e.getLastName();
String address = e.getAddress();

进一步提高可读性。

可以使用字节码分析,也可以使用
System.nanoTime
对这两种方法进行计时。我认为第二个更快。以下是我的结论:

我写了三节课,如下所示:

public static class A {
    public B b = new B();
}

public static class B {
    public E e = new E();
}

public static class E {
    public String name = "s";
    public int age = 1;
}
然后我编写了两个简单的方法,并使用
javap-c CLASS\u NAME
获取它们的java字节码

public static void Test1() {
    A a = new A();
    String str = a.b.e.name;
    int age = a.b.e.age;
}
上述方法的字节码为:

public static void Test1();
    Code:
       // new A();
       0: new           #15
       3: dup           
       4: invokespecial #17                 
       7: astore_0      
       8: aload_0

       // a.b (it accesses the field and put it on operand stack)
       9: getfield      #18

      // b.e
      12: getfield      #22

      // b.name
      15: getfield      #28

      // pop 'name' from stack
      18: astore_1      
      19: aload_0  

      // cyle continues     
      20: getfield      #18
      23: getfield      #22
      26: getfield      #34 
      29: istore_2      
      30: return
public static void Test2();
    Code:
       // new A();
       0: new           #15 
       3: dup           
       4: invokespecial #17
       7: astore_0      
       8: aload_0       

       // store a.b.e on operand stack once
       9: getfield      #18
      12: getfield      #22
      15: astore_1      
      16: aload_1

      // get 'name' field
      17: getfield      #28
      20: astore_2      
      21: aload_1       
      // get 'age' field
      22: getfield      #34
      25: istore_3      
      26: return        
您可以清楚地看到,在字节码级别,每次尝试访问字段时,它都会将该字段的值放在堆栈上,然后这个循环继续。因此,
a.a1.a2….
将是
n
指令,前提是堆栈将有足够的空间容纳所有
n
。编译器并没有优化同一周期的再次调用,以访问
name
age
字段

下面是第二种方法:

public static void Test2() {
        A a = new A();
        E e = a.b.e;
        String str = e.name;
        int age = e.age;
    }
上述方法的字节码为:

public static void Test1();
    Code:
       // new A();
       0: new           #15
       3: dup           
       4: invokespecial #17                 
       7: astore_0      
       8: aload_0

       // a.b (it accesses the field and put it on operand stack)
       9: getfield      #18

      // b.e
      12: getfield      #22

      // b.name
      15: getfield      #28

      // pop 'name' from stack
      18: astore_1      
      19: aload_0  

      // cyle continues     
      20: getfield      #18
      23: getfield      #22
      26: getfield      #34 
      29: istore_2      
      30: return
public static void Test2();
    Code:
       // new A();
       0: new           #15 
       3: dup           
       4: invokespecial #17
       7: astore_0      
       8: aload_0       

       // store a.b.e on operand stack once
       9: getfield      #18
      12: getfield      #22
      15: astore_1      
      16: aload_1

      // get 'name' field
      17: getfield      #28
      20: astore_2      
      21: aload_1       
      // get 'age' field
      22: getfield      #34
      25: istore_3      
      26: return        

上面的4条指令比前面的代码短,因为它阻止执行
getfield
。因此,我认为这应该比上一个更快。

您要查找的单词是
chained
get。嵌套意味着一个get是在另一个get的上下文中发生的。哇,谢谢你的努力。不过,请记住,字节码只是故事的一部分。JVM可以并且将在运行时改变它。Oracle的JVM(热点)将识别经常使用的部件(热点),并积极优化它们。it要做的最简单和最容易的事情之一就是内联简单的访问器。