Java是否将新的HashSet(someHashSet).contains()优化为O(1)?

时间:2013-02-14 14:18:17

标签: performance complexity-theory java

此类是出现问题的示例:

public class ContainsSet {
    private static HashSet<E> myHashSet;

    [...]

    public static Set<E> getMyHashSet() {
        return new HashSet<E>(myHashSet);
    }

    public static boolean doesMyHashSetContain(E e) {
        return myHashSet.contains(e);
    }
}

现在想象两个可能的功能:

boolean method1() {
    return ContainsSet.getMyHashSet().contains(someE);
}
boolean method2() {
    return ContainsSet.doesMyHashSetContain(someE);
}

现在我的问题是,方法1在Java优化之后是否具有与方法2相同的时间复杂度。 (我使用HashSet而非Set来强调myHashSet.contains(someE)具有复杂性O(1)。)

没有优化就不会。虽然.contains()具有复杂性O(1),但new HashSet<E>(myHashSet)具有复杂性O(n),这会使方法1的复杂度为O(n) + O(1) = O(n),这与心爱的{{}}相比非常糟糕O(1) {1}}。

我导入此问题的原因是因为如果您不允许外部类更改其内容,我会被教导不返回列表或集合。返回副本是一个显而易见的解决方案,但它可能非常耗时。

3 个答案:

答案 0 :(得分:7)

不,javac没有(也不能)优化这一点。需要将源中描述的字节代码发送到此级别。并且JVM几乎不够智能,无法优化它。它太可能有副作用来证明。

如果您想要不变,请不要返回HashSet的副本。将其包装在不可修改的包装器中:Collections.unmodifiableSet(myHashSet)

答案 1 :(得分:0)

我可以在这里说什么,但是创建一个新的HashSet并通过构造函数填充它是很昂贵的!

Java不会&#34;优化掉&#34;这项工作:即使你和我知道它会产生与#34相同的结果;通过&#34; contains()调用,java无法知道这一点。

答案 2 :(得分:0)

没有。这超出了优化范围。你返回了一个新对象,你可以在其他地方使用它,Java不应该省略它。将创建一个新的HashSet。

返回副本不是一个好习惯。这不仅耗费时间,而且耗费空间。正如Sean所说,你可以用unmodifiableSet包装,或者你可以将它包装在你自己的类中。

你可以试试这个:

public static Set<E> getMyHashSet() {
    return Collection.unmodifiableSortedSet(myHashSet);
}

注意:使用该方法将返回您的集合的视图,而不是副本。