Paŭ*_*ann 90
标准API中的一些着名的不可变类:
大多数枚举类都是不可变的,但实际上这取决于具体情况.(不要实现可变的枚举,这会让你搞砸了.)我认为至少标准API中的所有枚举类实际上都是不可变的.
java.math.BigInteger和java.math.BigDecimal(至少这些类本身的对象,子类可能会引入可变性,尽管这不是一个好主意)
java.io.File中.请注意,这表示VM外部的对象(本地系统上的文件),可能存在也可能不存在,并且有一些方法可以修改和查询此外部对象的状态.但File对象本身保持不变.(java.io中的所有其他类都是可变的.)
java.awt.Font - 表示在屏幕上绘制文本的字体(可能有一些可变的子类,但这肯定没用)
java.awt.Cursor - 表示鼠标光标的位图(这里也有一些子类可能是可变的或取决于外部因素)
java.util.Locale - 表示特定的地理,政治或文化区域.
虽然大多数集合都是可变的,但java.util.Collections类中有一些包装器方法,它们在集合上返回一个不可修改的视图.如果你传递一个在任何地方都不知道的集合,这些集合实际上是不可变的集合.此外,Collections.singletonMap()
,.singletonList
,.singleton
返回不可变的一个元素的集合,并且也有不可变空的.
java.net.URL和java.net.URI - 表示资源(在互联网或其他地方)
java.time
除外DateTimeException
都是不可变的.大多数子类的类java.time
也是不可变的.可以说原始类型也是不可变的 - 你不能改变42的值,是吗?
Class AccessControlContext是一个不可变的类
AccessControlContext没有任何变异方法.它的状态包含一个ProtectionDomains列表(它是一个不可变类)和一个DomainCombiner.DomainCombiner是一个接口,因此原则上实现可以在每次调用时执行不同的操作.
实际上,ProtectionDomain的行为也可能取决于当前有效的策略 - 是否将这样的对象称为不可变是有争议的.
和AccessController?
没有AccessController类型的对象,因为这是一个没有可访问构造函数的final类.所有方法都是静态的.可以说AccessController既不可变也不可变,或两者兼而有之.
这对于所有其他没有对象(实例)的类都有效,最着名的是:
in
,)out
err
chr*_*ann 22
构建后不能更改不可变类.因此,例如,Java String
是不可变的.
要使类不可变,您必须使它final
和所有字段private
和final
.例如,以下类是不可变的:
public final class Person {
private final String name;
private final int age;
private final Collection<String> friends;
public Person(String name, int age, Collection<String> friends) {
this.name = name;
this.age = age;
this.friends = new ArrayList(friends);
}
public String getName() {
return this.name;
}
public int getAge() {
return this.age;
}
public Collection<String> getFriends() {
return Collections.unmodifiableCollection(this.friends);
}
}
Run Code Online (Sandbox Code Playgroud)
我在代码示例中添加了一个方法,展示了如何处理集合,这一点非常重要.
在可能的情况下,您应该使类不可变,因为那样您就不必担心线程安全等问题.
小智 13
重要的是要记住,将一个类声明为final并不意味着它是"不可变的",这基本上意味着这个类不能被扩展(或专门化).
不可变类必须具有私有和最终字段(没有setter),因此在构造之后,它的字段值不能更改.
LocalDate,LocalTime和LocalDateTime类(从1.8开始)也是不可变的.事实上,这个主题是在OCAJSE8(1Z0-808)考试中,这正是我决定将其视为仅仅是评论的原因.
所有原始包装类(如Boolean,Character,Byte,Short,Integer,Long,Float和Double)都是不可变的.
Money和Currency API(定义为Java9)也应该是不可变的.
顺便提一下,阵列支持的Lists(由其创建Arrays.asList(myArray)
)在结构上是可更改的.
此外,还有一些边界线情况,例如java.util.Optional(在OCP考试中有特色,1Z0-809),如果包含的元素本身是不可变的,它是不可变的.
String
是不可变类的一个很好的“现实世界”示例。您可以将它与可变StringBuilder
类进行对比。
大多数用于反射的 Java 类都是不可变的。其他一些是“几乎不可变的”:例如,实现的类Accessible
只有一个setAccessible
改变实例状态的方法Accessible
。
我确信标准类库中还有更多内容。