var str: String 是可变的还是不可变的?

Is var str: String mutable or immutable?

我已经在 Kotlin 中声明了一个 String 变量。

var str: String

Kotlin 文档与可变性概念相矛盾。 根据文档... var 是可变的。

但是对于String,它定义为不可变的。

所以请澄清矛盾...

我也不喜欢文档的编写方式,但实际上并不矛盾。他们使用 mutable 这个词的方式是在程序 symbolsobjects 之间进行比较不是很有帮助。

var 关键字声明的变量是可重新赋值的,而用 val 关键字声明的变量则不可。

字符串是不可变的对象类型,一旦创建就无法更改。

一个变量是否可重新赋值和它指向的对象是否不可变是两个不同的东西。

这是一个例子:

class Person(var name: String)

val fred = Person("Fred")

fred.name = "Barry" // fred is not immutable

fred = Person("Barry") // ERROR Val cannot be reassigned

所以按照文档的方式使用可变的,只是因为 symbol 被声明为 val 不会使 object 它指向不可变。

矛盾是什么?字符串是只读的。正如Java,你不能设置a[i] = 'x',任何字符串替换方法return 新字符串等。因此,不可变。这一点是为了阐明 var 字符串类型

的功能

var 和 val 之间的差异可以与 final 中的一个变量相关联 Java。你可以创建一个 final String 常量,或者你可以有一个常规的 String 对象

@Frank 的 。这让我更清楚了文档所说的内容。

文档的第一部分说:

Classes in Kotlin can have properties. These can be declared as mutable, using the var keyword or read-only using the val keyword.

现在,第二部分说:

Strings are represented by the type String. Strings are immutable.

在我看来,这些都是正确的。

基于弗兰克的例子,我们再举一个例子。

data class User(var name: String, var email:String)

var user1 = User("Foo","foo@bar.com")  
// user1 is mutable and object properties as well

val user2 = User("Bar","bar@foo.com")
// user2 is immutable but object's properties are mutable

现在,考虑 属性 user1。它是可变的,因为它是用关键字 var 声明的。以及分配给它的用户对象。

但是 user2 属性 是不可变的。您不能更改分配给它的对象。但是对象本身具有可变属性。因此可以通过 user2.name = "Foo".

更改属性

现在稍微更改示例并使用户属性不可变。

data class User(val name: String, val email:String)

var user1 = User("Foo","foo@bar.com")  
// user1 is mutable and object properties are not

val user2 = User("Bar","bar@foo.com")
// user2 is immutable and object's properties are also immutable

在这里,用户的属性是不可变的。所以,user1 是可变的,你可以给它赋值另一个对象。但是属性是不可变的。所以 user1 = User("New Foo","newfoo@bar.com") 会起作用。但是在分配对象 User 之后,您不能更改它的属性,因为它们是不可变的。

现在,让我们以String类型为例。

var str1 = "Bar"
// Here str1 (property) is mutable. So you can assign a different string to it. 
// But you can not modify the String object directly.
str1 = "Foo"  // This will work
str1[0] = 'B' // This will NOT work as The string object assigned to str1 is immutable

val str2 = "Foo"
// Here both str2 and the assigned object are immutable. (Just like Java final)

正如弗兰克所说,

just because a symbol is declared a val does not make the object it points to immutable.

我的最后一分:

String object is immutable, as it can not be changed. But that immutable String object can be assigned to a mutable property, which can be re-assigned with the different String Object. That is what var keyword does. Making the property mutable. But the object it points to can be mutable or immutable.

在 Kotlin/Java 中,对象的行为 而不是 取决于您用来访问它的引用类型。一切都(可能)在堆中,所以任何 属性 只是对象的引用(a.k.a。link)。

val str = "Hello"
val a = str
var b = str

在上面的代码片段中,只有一个不可变字符串 strab 都引用了它。无论您使用什么引用,可变的或不可变的,您都无法更改字符串。但是您可以更改可变引用本身以指向另一个(不可变)字符串:

b = "World"

实际上,String variable是可变的,而String Value是不可变的。

Appreciate with @cricket_007

让我深入描述当你声明变量时发生了什么。

val string1 = "abcd"  
val string2 = "abcd"

如上图和声明。

-字符串池是堆内存中的一个特殊存储区。

-当一个string is created并且如果字符串already exists在池中时,existing string will be returned的引用,而不是创建一个新对象并returning它参考。

-如果字符串不是不可变的,更改一个引用的字符串将导致其他引用的值错误。

-现在我们的示例值分配给变量 String1 现在我们可以使用这个变量了。

我们也可以更改值

string1.renameTo("Hi This Is Test")

那么内存后面发生了什么?
->是的,
if "Hi This Is Test" 这个字符串可用它将 return 引用 "string1
else 它创建新的 space 并引用“string1

实际上,这就是 String 称为不可变的原因。

参考 - Link

就我个人而言,我发现用 Java 来思考 valvar 之间的区别更容易。 val 将对应于带有 final 修饰符的变量,这意味着它只能被赋值一次,而 var 只是没有该修饰符,因此可以重新赋值。

对象本身仍然可以是可变的或不可变的。这里的可变性是指变量本身。