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

时间:2017-06-17 01:45:44

标签: android string kotlin immutability

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

var str: String

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

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

所以请澄清矛盾......

6 个答案:

答案 0 :(得分:8)

我不喜欢写文档的方式,但实际上并没有矛盾。他们使用 mutable 这个词,其方式是邀请程序符号对象之间的比较,但这并不是很有帮助。

var关键字声明的变量是可重新分配的,而使用val关键字声明的变量不是。

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

变量是否可重新分配以及它指向的对象是 immutable 是两回事。

以下是一个例子:

class Person(var name: String)

val fred = Person("Fred")

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

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

因此,要以文档的方式使用mutable,只是因为声明符号val不会使对象指向不可变。

答案 1 :(得分:6)

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

  

赞赏@ cricket_007

让我深入描述当您声明变量时背后发生的事情。

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

enter image description here

如上图所示和声明。

-String pool是堆内存中的特殊存储区域。

- 当string is created和池中的字符串already exists时,existing string will be returned的引用,而不是创建新对象并返回其引用。

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

现在我们可以使用此变量,现在我们的示例值分配给变量 String1

我们也可以更改值

string1.renameTo("Hi This Is Test")

那么在记忆中会发生什么呢? - >是,
如果 "嗨这是测试" 此字符串可用,它将返回对" string1 &#34的引用;
其他它创建新空间并提供参考" string1 "

实际上,这就是为什么String称为不可变的。

参考 - Link

答案 2 :(得分:4)

@Frank的excellent example。它让我更清楚,文档说的是什么。

文档的第一部分说:

  

Kotlin中的类可以具有属性。 这些可以声明为   可变,使用var关键字或使用val关键字进行只读。

现在,第二部分说:

  

字符串由String类型表示。 字符串是不可变的。

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

根据弗兰克的例子,我们再举一个例子。

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声明的。并且User对象也分配给它。

user2属性是不可变的。您无法将指定的对象更改为它。但是Object本身具有可变属性。因此,属性可以按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)

正如弗兰克所说,

  

只是因为声明了一个符号val并不会使它指向不可变的对象。

我的最后一分钱:

  

String对象是不可变的,因为它无法更改。但那   不可变的String对象可以分配给可变的属性,其中   可以使用不同的String对象重新分配。那是什么   var关键字确实如此。使财产变得可变。但对象呢   指向可以是可变的或不可变的。

答案 3 :(得分:3)

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

的功能

var和val之间的差异可以与Java中的final变量相关联。您可以设置final String常量,也可以设置常规String对象

答案 4 :(得分:0)

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

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

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

b = "World"

答案 5 :(得分:0)

就个人而言,我发现在Java方面考虑List<Main> mainList = ... var flatList = ( from main in mainList from owner in main.Owners select new FlatList { Id = main.Id, Name = main.Name, OwnerId = owner.Id, OwnerName = owner.Name }).ToList(); val之间的区别更容易。 var将对应于具有val修饰符的变量,这意味着它只能分配一次,而final只是缺少该修饰符,因此可以重新分配。

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