Android性能 - '避免内部吸气/安装者'

时间:2011-07-16 09:12:33

标签: java android performance optimization

请在开发网站上阅读:

Avoid Internal Getters/Setters

  

在像C ++这样的本地语言中,通常的做法是使用getter(例如i = getCount())而不是直接访问字段(i = mCount)。这是C ++的一个很好的习惯,因为编译器通常可以内联访问,如果你需要限制或调试字段访问,你可以随时添加代码。

     

在Android上,这是一个坏主意。虚拟方法调用比实例字段查找要昂贵得多。遵循常见的面向对象编程实践并在公共接口中使用getter和setter是合理的,但在类中,您应该始终直接访问字段。

     

没有JIT,直接字段访问速度比调用一个简单的getter快约3倍。使用JIT(直接字段访问与访问本地一样便宜),直接字段访问比调用一个简单的getter快约7倍。在Froyo中也是如此,但是当JIT内联getter方法时,将会有所改进。

2019/05更新:在当前版本中,上述材料已从文档中删除!

所以它说你会在课堂上使用字段访问:

 public class MyObject {

    public Object innerObject; // This would be private if I was using a getter

    public void doSomeStuff(){
          if(innerObject){        // Within class access like this
                 // ....
          }
    }

    public Object getInnerObject(){  // This would be removed if I was using field access
         return innerObject;
    }
 }

但是从另一个对象访问?:

 public class SecondObject {

      public void doSecondSomething(){
                MyObject ob = new MyObject();
                Object inner;

                //This is my question basically (from an Android performance perspective)   
                inner = ob.getInnerObject();
                // OR 
                inner = b.innerObject

       }

 }

7 个答案:

答案 0 :(得分:31)

使用内部getter和setter的性能影响也适用于外部getter和setter。

然而,在外部情况下,吸气剂和制定者在其他方面具有显着的益处;例如保持封装,减少有害耦合,使代码更易于维护,等等。因此,尽管可能会产生性能损失,但通常将其视为使用getter和setter的最佳实践

性能损失是旧版Android JIT编译器限制的结果。使用Gingerbread可以显着改善这种情况(参见 - https://stackoverflow.com/a/4930538/139985 ...并注意谁写了这个答案!)并继续改进。实际上,在Performance Tips的当前(2019)版本中,关于内部吸气剂和定位器的整个部分已被删除。

一般来说,为一个劣质平台“调整”你的代码是一个坏主意,特别是如果有一个合理的机会,一个更好的一个即将到来。

答案 1 :(得分:4)

尽管b.innerObject更快,但随着技术的进步(更好的cpus,JIT等),两个选项之间的差异会变小。

唯一可能重要的一点是在一直执行的密集循环中完成。例如,在游戏的onDraw方法中,当你循环遍历数百个对象时。

答案 2 :(得分:3)

// this is faster
inner = b.innerObject

// but this won't hurt performance much because
// it's assumed that it will be rare
inner = ob.getInnerObject();

答案 3 :(得分:3)

请注意,只有当相关成员每秒访问数千次时,这些性能注意事项才有意义。

直接访问可能是一个好主意的一个很好的例子是游戏的场景图(libgdx

public abstract class Actor {
    public Group parent;
    public final String name;
    public boolean touchable = true;

    public float x;
    public float y;
    public float width;
    public float height;
    public float originX;
    public float originY;
    public float scaleX = 1;
    public float scaleY = 1;
    public float rotation;
    public final Color color = new Color(1, 1, 1, 1);

答案 4 :(得分:2)

Getters和Setter总是有一个开销,因为它们是函数调用。当您在同一个对象中时,可以通过不使用它们来优化代码,因为您知道它们的用途,并且您不需要从它自己的对象中抽象/封装它们。

我认为您还需要从不同的角度来看待它:

  1. 没有getter / setter会破坏常见的oops做法吗?如果您正在制作其他人将使用的对象/模块,您将不希望有直接引用。

  2. 你真的不想在最后使用getter / setter太多次,除非sh!*优化了它的函数调用会产生开销。

  3. 你真的需要在percase的基础上进行优化,如果我构建两个模块,其中一些组件只能彼此访问,我可能会创建一个静态字段,否则我会坚持getter / setters

答案 5 :(得分:2)

性能方面,访问this.fieldthat.field没有区别。

托管它的对象更容易访问实例字段的感觉只是一种语法错觉。

OO明智地,认真地说,Android应用程序有多复杂?许多OO咒语来自构建怪物应用程序。如果你的小应用程序使用像结构这样的对象,那有什么大不了的呢?

即使在一个巨大的应用程序中,只要它在内部,并且所有访问字段的源代码都可用于重构,所以暴露字段完全没有问题。

答案 6 :(得分:0)

对于记录,setter和getter(在Java中)的另一个问题是它们使用起来很难看。

让我们说下一个练习,我们需要修改一个字段内部的字段

在java中是:

   object.getField().getSubField().setField3("hello"); // ugly

在C#中,相同的代码(即使使用封装)

   object.Field.SubField.Field3="hello";  // fine

因此,在Java(或android)中使用公共字段要清晰得多:

  object.field.subfield.field3="hello"; // fine too