【问题标题】:Java - Nested Level object assignmentJava - 嵌套级别对象分配
【发布时间】:2016-11-16 15:40:26
【问题描述】:

我目前正在处理大量嵌套的关卡对象,并且正在考虑性能。

假设我有以下课程:

class Address {
    private String doorNumber;
    private String street;
    ...
}

还有另一个类 Customer。

class Customer {
    private List<Address> addressList;
    private String firstName;
    .....
    .....
    .....
}

当我尝试像下面这样访问它时:

public static void main(String[] str) {
    Customer customer = new Customer();
    // ... and add addresses to this Customer object.

    // Set 1
    // And if I then do...
    customer.getAddressList().get(0).getHouseNumber();
    customer.getAddressList().get(0).getStreet();

    // OR
    // Set 2
    Address address = customer.getAddressList().get(0);
    address.getHouseNumber();
    address.getStreet()
}

我知道访问地址的第一组行不是干净的代码,我认为编译器会对此进行排序,但事实并非如此。因为当我反编译我的代码时,我得到了完全相同的东西,所以不确定编译器是否在那里进行了任何优化。所以我的第一个问题是为什么编译器不清理它并将其分配给临时变量?

我的下一个问题是,这与性能有关吗?除了第一个不是很干净的代码之外,哪个是两者中性能更好的代码。这是否意味着,我的第二组代码在编译期间会在内部被翻译成第一行?

最后一个问题,在一个类上调用变量是否比它的 getter 方法更优化?我只是在考虑性能,没有干净的编码。

【问题讨论】:

  • 第二个版本的性能会更好,特别是如果addressListLinkedList&lt;&gt; 或其他List&lt;&gt;,而get 不是O(1)。 (假设您将比第一个元素更深入地挖掘。)
  • 谢谢@bradimus。这个想法是我是否必须对变量分配保持勤奋,或者 Java 编译器是否进行了任何优化?不确定。
  • 您可以通过基准测试自己检查性能。在循环中运行代码数千次并使用System.nanoTime() 测量时间。
  • 如果您要进行基准测试,请确保正确执行:stackoverflow.com/questions/504103/…
  • 谢谢@AndréStannek。性能可能因 JVM 的不同实现而异。而且我可能无法访问不同类型的 JVM 实现。我只是想看看是否有人对此或编译器的内部工作有所了解。真的只是发人深省吗?这有意义吗?

标签: java variable-assignment


【解决方案1】:

副作用。

考虑这种情况,调用 get 方法不是返回一些文本,而是有一些内部副作用:

// This goes up each time getAddressList is called.
public int addressesRequested;

public List<Address> getAddressList(){
    addressesRequested++;
    return addressList;
}

当然,在这种方法中,这样的副作用没有多大意义,但是方法调用可以通过多种方式留下某种形式的剩余效果。

customer.getAddressList(); // addressesRequested is now 1.
customer.getAddressList(); // addressesRequested is now 2.
...

因此,编译器无法将多个方法调用优化为一个 - 它必须假设一个方法调用具有副作用。

还值得注意的是,方法也可以内联 - 即方法的主体被复制到调用站点以避免方法调用开销。这通常仅在 JVM 认为值得进行此类优化时才会发生;即因为它经常被调用。但是,它不会导致调用站点被进一步优化 - 它不会在那里触发某种临时变量。

字段呢?它们不会产生副作用……可以吗?

好的,所以你现在正在考虑这个:

// Assume addressList was public and could be accessed like so:
customer.addressList.get(0)..
customer.addressList.get(0)..
..

它们不会产生副作用,但编译器也不会将其放入临时变量中。这是因为副作用是双向的——其他方法可能会改变地址列表字段;很可能来自其他线程。

【讨论】:

  • 喜欢你的回答卢克,现在这很有意义。我不知道为什么我没有从这个角度考虑它,我一直在思考 getter 和 setter。
  • 是的,当我写这个问题时,我更多的是考虑内联替换的行
  • @VishalJumani 没问题!我有一种感觉可能正在考虑内联(getter/setter 通常是第一种内联的方法,因为它们被使用的频率很高)所以似乎也值得把额外的注释放在那里。
  • @VishalJumani 后续的想法也是 “字段怎么样?它们不会产生副作用?” 但假设也适用于它们 - 我会添加一些东西如果你愿意,也可以考虑。
猜你喜欢
  • 1970-01-01
  • 2021-12-23
  • 2021-01-19
  • 1970-01-01
  • 2022-01-26
  • 2019-05-22
  • 1970-01-01
  • 2023-01-12
  • 1970-01-01
相关资源
最近更新 更多