Set.of(E... elements) - 它使用的是哪个 Set 实现?它与 new HashSet<>() 有什么关系?
Set.of(E... elements) - which Set implementation is it using? and what is its relation to new HashSet<>()?
我想问一下 - 和
有什么区别
Set<CurrencyType> set1 = new HashSet<>() {{
add("a");
add("b");
add("c");
}}
和
Set<CurrencyType> set2 = Set.of(
"a",
"b",
"c"
)
在名为 MySillyTest
的 @Test 的调试模式下(这个名称很快就会恢复)我可以看到 set1
是 MySillyTest
的一个实例,但我假设它只是一个HashSet
。另一方面,set2
是 ImmutableCollections$SetN
的一个实例。这两者之间的真正区别是什么? Set.of()
使用的是 java.util.Set
的什么实现?这两者之间有 performance/memory usage/cpu 用法差异吗?
不保证 Set.of(...)
的实现 class。它可能会根据运行时实现或未来版本而改变。然而,它的一些特性——主要是不变性——是有保证的。
当您使用“double-brace 初始化”时,您正在定义一个从指定类型派生的新匿名 class。所以 MySillyTest
扩展 HashSet
因为那是你指定的。注意double-brace初始化has problems;我不允许,也不鼓励别人用
两者之间的重要区别在于 Set.of(...)
导致的不变性。如果您需要一个可变集,那不是一个选择。但是,如果您可以使用不可变集,它会提供卓越的可读性和性能。
即使您需要可变集,也不要将 double-brace 初始化视为 Set.of(...)
的替代方法;只需以常规方式使用 HashSet
。
不知道,不关心
Set.of
(and List.of
, Map.of
) 使用的具体 class 未记录。我们所知道的是对象 returned (a) 实现了接口,并且 (b) 是不可修改的。
这就是我们需要知道的全部内容。我们不应该关心幕后使用的具体具体 class。
作为未知的具体 class 为 of
方法的实施者提供了自由。
- 那些程序员可以根据你的论点性质自由优化。例如,如果您传递枚举参数,高度优化的
EnumSet
class 可能会在幕后使用。
- 那些程序员可以在 Java 的版本之间自由更改他们的具体 class。例如,Java 17 实施可能 return 一个具体 class 而 Java 18 return 是另一个。
所以你应该永远不要依赖于of
/copyOf
方法所使用的特定具体class。
你问过:
What is the real difference between those two?
在你的第一个中,我们知道了具体的 class。结果集是可修改的。
你的第二个,我们不知道具体的class,也不关心具体的class。结果集是不可修改的。
Code
Concrete Class
Modifiable
new HashSet<>() {{ add("a"); add("b"); add("c"); }}
known
modifiable
Set.of( "a", "b", "c"
unknown
unmodifiable
避免double-brace
正如其他人所说,一般最好避免double-brace初始化。
如果您想要紧凑 literals-style 初始化可修改集合的便利性,请结合使用 of
方法。您可以将现有集合传递给构造函数。
Set< String > set =
new HashSet<>(
Set.of( "a", "b", "c" ) // Pass a collection to constructor.
)
;
我想问一下 - 和
有什么区别Set<CurrencyType> set1 = new HashSet<>() {{
add("a");
add("b");
add("c");
}}
和
Set<CurrencyType> set2 = Set.of(
"a",
"b",
"c"
)
在名为 MySillyTest
的 @Test 的调试模式下(这个名称很快就会恢复)我可以看到 set1
是 MySillyTest
的一个实例,但我假设它只是一个HashSet
。另一方面,set2
是 ImmutableCollections$SetN
的一个实例。这两者之间的真正区别是什么? Set.of()
使用的是 java.util.Set
的什么实现?这两者之间有 performance/memory usage/cpu 用法差异吗?
不保证 Set.of(...)
的实现 class。它可能会根据运行时实现或未来版本而改变。然而,它的一些特性——主要是不变性——是有保证的。
当您使用“double-brace 初始化”时,您正在定义一个从指定类型派生的新匿名 class。所以 MySillyTest
扩展 HashSet
因为那是你指定的。注意double-brace初始化has problems;我不允许,也不鼓励别人用
两者之间的重要区别在于 Set.of(...)
导致的不变性。如果您需要一个可变集,那不是一个选择。但是,如果您可以使用不可变集,它会提供卓越的可读性和性能。
即使您需要可变集,也不要将 double-brace 初始化视为 Set.of(...)
的替代方法;只需以常规方式使用 HashSet
。
不知道,不关心
Set.of
(and List.of
, Map.of
) 使用的具体 class 未记录。我们所知道的是对象 returned (a) 实现了接口,并且 (b) 是不可修改的。
这就是我们需要知道的全部内容。我们不应该关心幕后使用的具体具体 class。
作为未知的具体 class 为 of
方法的实施者提供了自由。
- 那些程序员可以根据你的论点性质自由优化。例如,如果您传递枚举参数,高度优化的
EnumSet
class 可能会在幕后使用。 - 那些程序员可以在 Java 的版本之间自由更改他们的具体 class。例如,Java 17 实施可能 return 一个具体 class 而 Java 18 return 是另一个。
所以你应该永远不要依赖于of
/copyOf
方法所使用的特定具体class。
你问过:
What is the real difference between those two?
在你的第一个中,我们知道了具体的 class。结果集是可修改的。
你的第二个,我们不知道具体的class,也不关心具体的class。结果集是不可修改的。
Code | Concrete Class | Modifiable |
---|---|---|
new HashSet<>() {{ add("a"); add("b"); add("c"); }} | known | modifiable |
Set.of( "a", "b", "c" | unknown | unmodifiable |
避免double-brace
正如其他人所说,一般最好避免double-brace初始化。
如果您想要紧凑 literals-style 初始化可修改集合的便利性,请结合使用 of
方法。您可以将现有集合传递给构造函数。
Set< String > set =
new HashSet<>(
Set.of( "a", "b", "c" ) // Pass a collection to constructor.
)
;