简体   繁体   English

Java可变和不可变概念

[英]Java Mutable and Immutable concepts

Can we create an Immutable object, that contains a mutable object? 我们可以创建一个包含可变对象的不可变对象吗? Is is possible? 有可能吗? please make me more clear about this. 请让我对此更加清楚。

Thanks in advance. 提前致谢。

Yes we can. 我们可以。

Take for example the code from java.lang.String : java.lang.String的代码为例:

/** The value is used for character storage. **/
private final char value[];

Obviously arrays are mutable because we can easily change their content like this: 显然,数组是可变的,因为我们可以像这样轻松地更改其内容:

value[0] = '&';

However String is still immutable. 但是String仍然是不变的。 That is, once created, its contents will never change. 也就是说,一旦创建,其内容将永远不会改变。 How does that happen? 怎么发生的?

Because even though value is mutable, there's no "regular" way for the user of String to modify it: 因为即使value是可变的, String的用户也没有“常规”方式来修改它:

  1. value is declared private final . value宣布为private final And String itself is final , meaning no subclass. 而且String本身是final ,意味着没有子类。
  2. There's no setter methods. 没有设置方法。 Nor any methods that modifies value . 也没有任何修改value方法。
  3. We can create a string from a char array, but the char array is copied inside the constructor, so modifying the original array would have no effect to the newly created string. 我们可以从char数组创建一个字符串,但是char数组会在构造函数内部复制,因此修改原始数组不会对新创建的字符串产生影响。
  4. The value field could also be shared by multiple String instances, but as long as it's not leaked, it's safe. value字段也可以由多个String实例共享,但是只要不泄漏就可以了。
  5. We can convert a string back to a char array, but again, its a copy. 我们可以将字符串转换回char数组,但同样可以将其复制。

So the answer is yes, if we follow a design strategy carefully. 因此,如果我们认真遵循设计策略 ,答案是肯定的。

In Java (and as far as I know all other mainstream languages with a const / final / readyonly / val etc keyword) an "immutable" object can contain references to mutable objects. 在Java中(据我所知,其他所有主流语言都带有const / final / readyonly / val etc关键字),“不可变”对象可以包含对可变对象的引用。 For a deeper dive into immutability see this paper - the quick takeaway is that there are unofficial Java extensions that allow you to specify that eg an immutable object can only contain references to immutable objects, eg Javari or Joe3 or OIGJ 要更深入地了解不变性,请参阅本文 -快速了解一下 ,有非官方的Java扩展允许您指定例如不可变对象只能包含对不可变对象的引用,例如JavariJoe3OIGJ

Objects in Java never really contain other objects--not like in C or in some other programming languages. Java中的对象从不真正包含其他对象-不像C或某些其他编程语言那样。 Even the so-called "container" classes really just contain references to other objects. 甚至所谓的“容器”类实际上只包含对其他对象的引用

An immutable object can refer to any other objects, mutable or immutable. 不可变的对象可以引用任何其他可变或不可变的对象。

You can't change which other objects an immutable object refers to, but you can change the other objects if they are mutable. 您不能更改不可变对象所引用的其他对象,但是可以更改其他对象的可变对象。

Edit : This depends somewhat on what you mean by "immutable." 编辑 :这在某种程度上取决于您所说的“不变”。 As another person pointed out, sometimes "immutable" is defined as a form of "shallow" immutability - ie constant references to mutable objects are allowed. 正如另一个人指出的那样,有时将“不变”定义为“浅”不变性的一种形式,即允许对可变对象的不变引用。 I'm not fond of this definition myself. 我自己不喜欢这个定义。 Some people might disagree with me here (and hopefully no one will downvote b/c of a difference of opinion), I think it's much clearer to define "immutability" as "having no mutable state of any kind." 这里有些人可能不同意我的观点(希望没有人会反对意见分歧),我认为将“不变性”定义为“没有任何可变的状态”更为明确。

Under this definition, the answer to your question is **no* because if it refers to mutable objects that gives it mutable state, which would make the object itself mutable. 在此定义下,您的问题的答案为“否”,因为如果它引用的可变对象具有可变的状态,则该可变的对象本身就是可变的。

I think it's important at this point to distinguish between a constant reference or pointer and an immutable object . 我认为在这一点上区分常量引用指针与不可变对象很重要 For example, the following code is a constant reference to a constant object: 例如,以下代码是对常量对象的常量引用:

private final string abc = "John";

Note that you can't modify the state of "abc" (ie that particular string will always be "John" - you can't change it to "Johnny" later, you'd need to create a new string. Also, you can't replace "John" with a new string (ie the variable "abc" itself will always refer to that string). 请注意,您无法修改“ abc”的状态(即该特定字符串始终为“ John”-您以后无法将其更改为“ Johnny”,则需要创建一个新字符串。此外,您也可以不能用新字符串替换“ John”(即变量“ abc”本身将始终引用该字符串)。

The following code is a mutable reference to an immutable object: 以下代码是对不可变对象的可变引用:

public string abc = "John";

(By the way, I do realize you should use a property here instead). (顺便说一句,我确实意识到您应该在此处使用属性)。

If you were to later do: 如果您以后要执行以下操作:

abc = "Johnny";

you'd be allowed to do that. 您将被允许这样做。 In this case, you're changing the object that the variable "abc" is referring to, not the original string. 在这种情况下,您要更改变量“ abc”所引用的对象,而不是原始字符串。 The string "John" will always have that value as long as it exists. 只要存在,字符串“ John”将始终具有该值。

However, consider the following object: 但是,请考虑以下对象:

public class Defg
{
    public int Count;

    public Defg(int Count)
    {
       this.Count = Count;
    }
}

Clearly, this is a mutable class (because you can change the value of "Count"). 显然,这是一个可变的类(因为您可以更改“ Count”的值)。

You can do the following: 您可以执行以下操作:

// Mutable reference to a mutable object. Note: "Count: 1" is a bit of C# syntax that just means that the "Count" parameter is set to 1. It's not strictly necessary here, I just added it for clarity.
public Defg Mutable = new Defg(Count: 1);

// Constant reference to a mutable object
public final Defg ConstReference = new Defg(Count: 1);

Note that the following is all perfectly valid: 请注意,以下全部完全正确:

Mutable = new Defg(Count: 10);
Mutable.Count = 4;
ConstReference.Count = 3;

However, you cannot do the following: 但是,您不能执行以下操作:

ConstReference = new Defg(Count: 3);

Note, in particular, that Defg can't possibly be an immutable object because you can change its state. 请特别注意,Defg 不可能是不可变的对象,因为可以更改其状态。

To summarize: 总结一下:
a) It's perfectly possible to have either a mutable reference to a constant object or a constant reference to a mutable object - the mutability of the reference to the object has nothing to do with whether the object itself is mutable and vice versa . a)完全可以使用对常量对象的可变引用或对可变对象的常量引用-对该对象的引用的可变性与对象本身是否可变无关, 反之亦然
b) Whether an object that refers to mutable objects can still be considered immutable depends on your definition of "immutable." b)引用可变对象的对象是否仍然可以视为不可变取决于您对“不可变”的定义。 In my opinion it can't because referring to a mutable object gives it mutable state; 在我看来,这不是因为引用可变对象会导致其可变状态。 it would be confusing/misleading at best to describe that as immutable. 将其描述为不可变的充其量只能是令人困惑/误导。

I think that it's possible. 我认为这是可能的。 But access modifier of variable which refers to mutable object must be final. 但是引用可变对象的变量的访问修饰符必须是最终的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM