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

dzi*_*iki 2 java collections set hashset

我想问 - 有什么区别

Set<CurrencyType> set1 = new HashSet<>() {{
    add("a");
    add("b");
    add("c");
}}
Run Code Online (Sandbox Code Playgroud)

Set<CurrencyType> set2 = Set.of(
    "a",
    "b",
    "c"
)
Run Code Online (Sandbox Code Playgroud)

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

Bas*_*que 7

不\xe2\x80\x99不知道,不\xe2\x80\x99不关心

\n

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

\n

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

\n

未知的具体类为of方法的实现者提供了自由。

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

因此,您永远不应该依赖of/方法使用的特定具体类copyOf

\n

你问:

\n
\n

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

\n
\n

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

\n

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

\n
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
代码具体类可修改
新的 HashSet<>() {{ add("a"); 添加(“b”);添加(“c”);}}已知的可修改的
Set.of(“a”,“b”,“c”未知不可修改的
\n

避免双括号

\n

正如其他人所说,\xe2\x80\x99s 通常最好避免双括号初始化。

\n

如果您想要方便地对可修改集合进行紧凑的文字样式初始化,请与这些of方法结合使用。您可以将现有集合传递给构造函数。

\n
Set< String > set =\n    new HashSet<>(\n        Set.of( "a", "b", "c" )  // Pass a collection to constructor. \n    )\n;\n
Run Code Online (Sandbox Code Playgroud)\n

\xe2\x80\x9c但我确实关心 \xe2\x80\xa6\xe2\x80\x9d

\n

如果您确实关心实现的具体细节,那么您不应该使用Set.of. 如上所述,实现细节可能会有所不同,因此您不应依赖特定的实现Set.of.

\n

当您的项目有特定需求时,您应该明确选择满足这些需求的特定实现。您可以选择其中一种捆绑实现,从第三方库(例如Eclipse CollectionsGoogle Guava )获取一种实现,或者编写您自己的实现。

\n

提示:您可以利用方便的语法,Set.of将其结果传递给所选实现的构造函数。请参阅上面的代码示例:

\n
new HashSet<>( Set.of( \xe2\x80\xa6 ) )\n
Run Code Online (Sandbox Code Playgroud)\n