不可变类的示例

2022-08-31 20:21:55

我已经知道不可变类的定义,但我需要一些例子。


答案 1

标准 API 中一些著名的不可变类:

  • java.lang.String (已经提到)
  • 基元类型的包装类:java.lang.Integer, java.lang.Byte, java.lang.Character, java.lang.Short, java.lang.Boolean, java.lang.Long, java.lang.Double, java.lang.Float
  • java.lang.StackTraceElement(用于构建异常堆栈跟踪)
  • 大多数枚举类都是不可变的,但这实际上取决于具体情况。(不要实现可变枚举,这会在某个时候搞砸你。我认为至少标准API中的所有枚举类实际上是不可变的。

  • java.math.BigInteger 和 java.math.BigDecimal(至少这些类本身的对象,子类可以引入可变性,尽管这不是一个好主意)

  • java.io.File.请注意,这表示 VM 外部的对象(本地系统上的文件),该对象可能存在也可能不存在,并且有一些方法可以修改和查询此外部对象的状态。但 File 对象本身保持不可变。(java.io 中的所有其他类都是可变的。

  • java.awt.Font - 表示用于在屏幕上绘制文本的字体(可能有一些可变的子类,但这肯定没有用)

  • java.awt.BasicStroke - 用于在图形上下文上绘制线条的帮助器对象
  • java.awt.Color - (至少是这个类的对象,一些子类可能是可变的或取决于一些外部因素(如系统颜色)),以及java.awt.Paint的大多数其他实现,如
    • java.awt.GradientPaint,
    • java.awt.LinearGradientPaint
    • java.awt.RadialGradientPaint,
    • (我不确定java.awt.TexturePaint)
  • java.awt.Cursor - 表示鼠标光标的位图(在这里,一些子类也可能是可变的或取决于外部因素)

  • java.util.Locale - 表示特定的地理、政治或文化区域

  • java.util.UUID - 一个尽可能全局唯一的标识符
  • 虽然大多数集合都是可变的,但 java.util.Collections 类中有一些包装方法,它们返回集合上的不可修改视图。如果您向它们传递一个在任何地方都不知道的集合,则这些集合实际上是不可变的集合。此外,, 、返回不可变的单元素集合,并且还有不可变的空集合。Collections.singletonMap().singletonList.singleton

  • java.net.URL 和 java.net.URI - 表示资源(在互联网上或其他地方)

  • java.net.Inet4Address and java.net.Inet6Address, java.net.InetSocketAddress
  • java.security.Permission的大多数子类(表示某些操作所需的权限或赋予某些代码的权限),但不是java.security.PermissionCollection和子类。
  • 除 的所有类都是不可变的。子包的大多数类也是不可变的。java.timeDateTimeExceptionjava.time

可以说基元类型也是不可变的 - 你不能改变42的值,对吧?


类访问控件上下文是一个不可变的类

AccessControlContext 没有任何变异方法。它的状态由一个保护域列表(这是一个不可变的类)和一个DomainCombiner组成。DomainCombiner是一个接口,因此原则上实现可以在每次调用时执行不同的操作。

事实上,保护域的行为也可能取决于当前有效的政策 - 是否将此类对象称为不可变是有争议的。

和访问控制器?

没有 AccessController 类型的对象,因为这是没有可访问构造函数的最终类。所有方法都是静态的。可以说AccessController既不是可变的,也不是不可变的,或者两者兼而有之。

这同样适用于所有其他不能有对象(实例)的类,最著名的是:

  • java.lang.Void
  • java.lang.System(但这有一些可变的静态状态 - , ,inouterr)
  • java.lang.Math(这也是随机数生成器)
  • java.lang.reflect.Array
  • java.util.Collections
  • java.util.Arrays

答案 2

构造后无法更改不可变类。因此,例如,Java是不可变的。String

要使类不可变,必须使类以及所有字段和 .例如,以下类是不可变的:finalprivatefinal

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);
     }
}

我在代码示例中添加了一个方法,演示如何处理集合,这是一个要点。

在可能的情况下,你应该使类不可变,因为这样你就不必担心线程安全之类的事情。