为什么Java包装类是不可变的?

shr*_*000 20 java mutable immutability primitive-types

我知道适用于一般不可变类的通常原因,即

  1. 不能改变作为副作用
  2. 很容易理解他们的状态
  3. 固有的线程安全
  4. 无需提供克隆/复制构造函数/工厂复制方法
  5. 实例缓存
  6. 不需要防御性副本.

但是,包装类表示基本类型,基本类型是可变的.那么为什么封装类不可变?

Jon*_*eet 29

但是,包装类表示基本类型,基本类型(String除外)是可变的.

首先,String不是原始类型.

其次,谈论可变的原始类型是没有意义的.如果您更改变量的值,如下所示:

int x = 5;
x = 6;
Run Code Online (Sandbox Code Playgroud)

这并没有改变数字5 - 它正在改变它的价值x.

虽然包装器类型可能已经变得可变,但在我看来,这样做会很烦人.我经常使用这些类型的只读集合,并且不希望它们可以更改.偶尔我想要一个可变的等价物,但在这种情况下,很容易想出一个,或使用Atomic*类.

我发现自己希望这一点Date并且Calendar变得更加频繁,而不是我发现自己想要Integer变得多变......(当然我通常会选择Joda Time,但Joda Time的一个好处就是不变性.)

  • @ shrini1000:你同意字符串是不可变的,对吧?但如果你写了'String x ="hello"; x ="那里";`这不会让他们变得可变,不是吗?改变变量的值与使该值自身改变不同. (7认同)
  • @ shrini1000,你有权利进行内存分配.但在Java中,您无法直接从/向内存读/写.因此,正如Jon Skeet所写的那样,由于你必须使用它们的方式,因此不能将原语称为可变或不可变. (3认同)

Pet*_*rey 10

对于某些类型,还有可变的,线程安全的包装器.

AtomicBoolean
AtomicInteger
AtomicIntegerArray
AtomicLong
AtomicLongArray
AtomicReference - can wrap a String.
AtomicReferenceArray
Run Code Online (Sandbox Code Playgroud)

还有一些异国情调的包装纸

AtomicMarkableReference - A reference and boolean
AtomicStampedReference - A reference and int
Run Code Online (Sandbox Code Playgroud)


Sea*_*oyd 6

对于您的信息:如果您想要可变的持有者类,您可以使用java.util.concurrent包中的Atomic*类,例如AtomicInteger,AtomicLong


Phi*_*ipp 5

这是一个示例,其中Integer可变时会很糟糕

class Foo{
    private Integer value;
    public set(Integer value) { this.value = value; }
}

/* ... */

Foo foo1 = new Foo();
Foo foo2 = new Foo();
Foo foo3 = new Foo();
Integer i = new Integer(1);
foo1.set(i);
++i;
foo2.set(i);
++i;
foo3.set(i);
Run Code Online (Sandbox Code Playgroud)

现在foo1,foo2和foo3的值是什么?您可能希望它们是1、2和3。但是当Integer可变时,它们现在都将是3,因为它们Foo.value都指向同一个Integer对象。