代码之家  ›  专栏  ›  技术社区  ›  Phil

Java匿名类的效率含义

  •  25
  • Phil  · 技术社区  · 14 年前

    这两种方法在效率(例如执行时间、代码大小等)上有什么区别吗?

    下面是创建对象而不做任何事情的人为示例,但是我的实际场景可能是创建新的线程、侦听器等。假设以下代码在循环中发生,这样可能会有所不同。

    使用匿名对象:

    void doSomething() {
        for (/* Assume some loop */) {
            final Object obj1, obj2; // some free variables
    
            IWorker anonymousWorker = new IWorker() {
                doWork() {
                    // do things that refer to obj1 and obj2
                }
            };
        }
    }
    

    先定义类:

    void doSomething() {
        for (/* Assume some loop */) {
            Object obj1, obj2;
            IWorker worker = new Worker(obj1, obj2);
        }
    }
    
    static class Worker implements IWorker {
        private Object obj1, obj2;
        public CustomObject(Object obj1, Object obj2) {/* blah blah */}
    
        @Override
        public void doWork() {}
    };
    
    6 回复  |  直到 9 年前
        1
  •  39
  •   Brian Agnew    14 年前

    这个 只有 匿名类和顶级类的实际区别在于匿名类将隐式引用外部类。

    这不会在性能中表现出来,但会影响到您是否序列化这些类。

        2
  •  19
  •   Stephen C    14 年前

    即使有任何性能差异,也应该很少。如果存在差异,它将处于一个不值得担心的水平。

    IMO,您应该专注于编写可读和可维护的代码,并忽略“微”性能问题,直到 清楚的 有证据表明它们很重要…基于分析应用程序。

    (对于记录,当匿名内部类引用 final 在封闭范围中,这是通过隐藏的构造函数参数和隐藏的实例属性在字节码级别实现的。字节码将几乎与从其他实现中获得的字节码相同。)

        3
  •  18
  •   polygenelubricants    14 年前

    重要的是要认识到匿名类仍然是已知的类,并且 完全编译 在编译时。比如说,你在定义一个匿名的类体,也许在一个循环中有许多方法和字段等,这并不意味着运行时必须 编译 每次迭代都是这样。

    因此,两种方法之间的性能差异可以忽略不计。需要考虑的重要因素包括可读性、可重用性、可测试性等。

        4
  •  4
  •   PeterVermont    11 年前

    实际上,在实例化匿名类的许多实例时,我注意到了一个重要的性能问题。

    考虑到可能是由于局部类是静态的,我删除了它,没有任何区别。

    在我的例子中,我做了1000次选择3次,即499500次。本地类的版本(不管是静态的还是非静态的)花费了26秒,匿名功能相同类的版本花费了2分钟20秒。

        5
  •  4
  •   Det    10 年前

    关于性能,您应该考虑是否应该创建一个内部类。

    坏做法的一个例子是:

    public List<String> someMethod() {
           return new ArrayList<String>() {{
                          add("Item one");
                          add("Item two");
                  }};
    }
    

    虽然乍一看,这种语法上的便利看起来很聪明,但它(通常不被注意)创建了一个匿名的内部类,其对象保持对外部实例的引用。 由于这个对象也是作为somemethod的结果值提供给外部的,所以您不能确定调用方对这个列表做了什么。 如果他将生成的arraylist实例放入某个静态变量中,则当前对象也将永远保留!

        6
  •  0
  •   JesperE    14 年前

    思考代码性能是浪费时间的一种很好的方式。没有什么能比得上对代码进行实际基准测试。如果你担心表现, 测量代码 . 如果你怀疑你的代码是次优的, 分析代码 为了找出时间花在哪里,然后尝试改进那些部分。此时,实际研究字节代码可能是合适的,以查看这是否会提示您哪种实现更有效。

    当你这样做的时候, 再次测量代码 以确保不会使事情变得更糟,例如使代码变得更难看和更难维护。