Set.of(E... elements) - 它使用哪个 Set 实现?它与 new HashSet<>() 有何关系?

问题描述 投票:0回答:2

我想问 - 有什么区别

Set<CurrencyType> set1 = new HashSet<>() {{
    add("a");
    add("b");
    add("c");
}}

Set<CurrencyType> set2 = Set.of(
    "a",
    "b",
    "c"
)

在名为

MySillyTest
的@Test调试模式下(这个名称很快就会回来),我可以看到
set1
MySillyTest$1
的一个实例,但我认为它只是一个
HashSet
。另一方面,
set2
ImmutableCollections$SetN
的一个实例。这两者之间真正的区别是什么?
java.util.Set
使用什么
Set.of()
实现?这两者之间有性能/内存使用/CPU 使用差异吗?

java collections set hashset
2个回答
8
投票

不知道,不关心

Set.of
(和
List.of
Map.of
)使用的具体类没有记录。我们所知道的是返回的对象 (a) 实现了接口,并且 (b) 是不可修改的。

这就是我们需要知道的一切。我们不应该关心幕后使用的特定具体类。

未知的具体类为

of
方法的实现者提供了自由。

  • 那些程序员可以根据你的论点的性质自由地进行优化。例如,如果您传递枚举参数,则可能会在幕后使用高度优化的
    EnumSet
    类。
  • 这些程序员可以在 Java 版本之间自由更改他们的具体类。例如,Java 17 实现可能返回一个具体类,而 Java 18 返回另一个具体类。

因此,您应该永远不要依赖于of

/
copyOf
方法使用的特定具体类。

你问:

这两者之间的真正区别是什么?

在你的第一个中,我们知道具体的类。并且结果集是可以修改的。

在你的第二个中,我们不知道具体的类,也不关心具体的类。并且结果集是不可修改的。

代码具体类可修改new HashSet<>() {{ add("a");添加(“b”);添加(“c”); }}已知可修改Set.of(“a”,“b”,“c”未知不可修改
避免双括号

正如其他人所说,通常

最好避免双括号初始化

如果您想要方便地对可修改集合进行紧凑的文字样式初始化,请与

of

 方法结合使用。您可以将现有集合传递给构造函数。

Set< String > set = new HashSet<>( Set.of( "a", "b", "c" ) // Pass a collection to constructor. ) ;
“但我

确实关心……”

如果您确实关心实现的具体细节,那么您不应该使用

Set.of

。如上所述,实现细节可能会有所不同,因此您不应依赖于 
Set.of
 的特定实现。

当您的项目有特定需求时,您应该明确选择满足这些需求的特定实现。您可以选择其中一种捆绑实现,从第三方库(例如

Eclipse CollectionsGoogle Guava)获取一种实现,或者编写您自己的实现。

提示:您可以通过将其结果传递给所选实现的构造函数来利用

Set.of

 的便捷语法。请参阅上面的代码示例:

new HashSet<>( Set.of( … ) )
    

2
投票
不保证由

Set.of(...)

 产生的实现类。它可能会根据运行时实现或未来版本而改变。然而,它的一些特性——主要是不变性——是得到保证的。

当您使用“双括号初始化”时,您正在定义一个从指定类型派生的新匿名类。所以

MySillyTest$1

 扩展了 
HashSet
 因为这就是您指定的。请注意,双括号初始化
有问题;我不允许它,并且我不鼓励其他人使用它。

两者之间的重要区别是

Set.of(...)

带来的不变性。如果您需要一个可变集,那么这不是一个选择。但如果您可以使用不可变集,它会提供卓越的可读性和性能。

但是,即使您需要可变集,也不要将双括号初始化视为

Set.of(...)

 的替代方案;只需按照常规方式使用 
HashSet
 即可。

© www.soinside.com 2019 - 2024. All rights reserved.