0

考虑以下代码作为该想法的完全简化示例:

public class Main {
    public static void foreach(int[] x, intVoid action) {
        for (int i = 0; i < x.length; ++i) {
            action.apply(x[i]);
        }
    }

    public static void main (String[] args) {
        int[] h = new int[] {2, 3, 5, 7, 11, 13};
        for (int i = 0; i < 10; ++i) {
            foreach(h, new intVoid() {
                public void apply(int x) {
                    System.out.println(x * 2);
                }
            });
        }
    }
}

interface intVoid {public void apply(int x);}

在 for 循环中foreach,从逻辑的角度来看,我们使用完全相同的参数进行调用,因为我们接口的匿名实现不依赖于上下文中的任何内容。问题是——它会被实例化 10 次还是只被实例化一次?或者,类似地,它是否等同于以下代码:

public class Main {
    public static void foreach(int[] x, intVoid action) {
        for (int i = 0; i < x.length; ++i) {
            action.apply(x[i]);
        }
    }

    public static void main (String[] args) {
        int[] h = new int[] {2, 3, 5, 7, 11, 13};
        intVoid action = new intVoid() {
            public void apply(int x) {
                System.out.println(x * 2);
            }
        };
        for (int i = 0; i < 10; ++i) {
            foreach(h, action);
        }
    }
}

interface intVoid {public void apply(int x);}

我有时会遇到这种情况,在需要的地方准确定义实现非常方便,但有时我还需要确保不会尝试多次创建同一个对象。如果运行时有优化,那么我对如何在不同的实现中进行处理很感兴趣,特别是如果我将这些代码转换为在 Android 的 Dalvik VM 中运行会发生什么。
我知道我可以自己测试这一切,但我想知道是否有人已经对这个问题有所了解。

4

2 回答 2

4

问题是——它会被实例化 10 次还是只被实例化一次?

10 次,因为这是你告诉它要做的。看到 JVM(或 Dalvik)注意到它apply没有副作用并且对象没有状态,我会感到惊讶,因此您不需要创建单独的实例。有可能——Hotspot 相当令人印象深刻——但对我来说这似乎是一个不太可能的优化。

当然,创建每个对象可能很便宜 - 但根据您的第二个代码片段创建一个对象仍然会更好。

于 2013-01-23T09:05:09.420 回答
3

每次new执行都会实例化一次。逃逸分析可能会在它被 JITed 之后消除它,例如在 10,000 次之后,但我不认为它确实如此。

如果它足够聪明地不创建单独的实例,那么它足够聪明地消除它,这是更好的。

于 2013-01-23T09:05:02.610 回答