【发布时间】:2017-06-17 01:45:43
【问题描述】:
我已经在 Kotlin 中声明了一个字符串变量。
var str: String
Kotlin 文档与可变性概念相矛盾。 根据文件... var 是可变的。
但是对于 String 它定义为不可变的。
所以请澄清矛盾...
【问题讨论】:
标签: android string kotlin immutability
我已经在 Kotlin 中声明了一个字符串变量。
var str: String
Kotlin 文档与可变性概念相矛盾。 根据文件... var 是可变的。
但是对于 String 它定义为不可变的。
所以请澄清矛盾...
【问题讨论】:
标签: android string kotlin immutability
其实字符串variable是可变的,而字符串Value是不可变的。
欣赏@cricket_007
让我深入描述一下当你声明变量时发生的事情。
val string1 = "abcd"
val string2 = "abcd"
如上图和声明所示。
-字符串池是堆内存中的一个特殊存储区域。
-当一个string is created和already exists在池中时,引用existing string will be returned,而不是创建一个新对象并返回它的引用。
-如果字符串不是不可变的,用一个引用改变字符串会导致其他引用的值错误。
-现在我们将上面的示例值赋值给变量String1,现在我们可以使用这个变量了。
我们也可以改变值
string1.renameTo("Hi This Is Test")
那么在内存后面发生了什么?
->是的,
如果 “Hi This Is Test”这个字符串可用,它将返回对“string1”的引用
else 它创建新空间并引用“string1”
实际上,这就是为什么 String 被称为不可变的原因。
参考 - Link
【讨论】:
我也不喜欢文档的编写方式,但实际上并没有矛盾。他们使用 mutable 这个词的方式会引起程序 symbols 和 objects 之间的比较,这不是很有帮助。
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
所以要以文档的方式使用 mutable,仅仅因为 symbol 被声明为 val 并不会使其指向的 object 不可变。 p>
【讨论】:
@Frank 的excellent example。它让我更清楚,文件所说的。
文档的第一部分说:
Kotlin 中的类可以具有属性。 这些可以声明为 可变,使用 var 关键字或只读使用 val 关键字。
现在,第二部分说:
字符串由字符串类型表示。 字符串是不可变的。
在我看来,这两个都是真的。
基于弗兰克的例子,我们再举一个例子。
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") 会起作用。但是在分配一个对象用户之后,你不能改变它的属性,因为它们是不可变的。
现在,我们举一个字符串类型的例子。
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 对象可以分配给可变的 property,它 可以用不同的字符串对象重新分配。那是什么
var关键字可以。使属性可变。但它的对象 指向可以是可变的或不可变的。
【讨论】:
有什么矛盾?字符串是只读的。就像Java一样,不能设置a[i] = 'x',任何字符串替换方法都返回新字符串等。因此,不可变。这一点是为了阐明var String 类型的功能
var 和 val 之间的区别可以与 Java 中的 final 变量相关联。你可以创建一个final String 常量,或者你可以有一个普通的String 对象
【讨论】:
就我个人而言,我发现在 Java 方面考虑 val 和 var 之间的区别更容易。 val 将对应于带有 final 修饰符的变量,这意味着它只能分配一次,而 var 只是没有该修饰符,因此可以重新分配。
对象本身仍然可以是可变的或不可变的。这里的可变性是指变量本身。
【讨论】:
在 Kotlin/Java 中,对象的行为不取决于您用来访问它的引用类型。一切都(可能)在堆中,因此任何属性都只是对对象的引用(也称为链接)。
val str = "Hello"
val a = str
var b = str
上面的sn-p中只有一个不可变字符串str,a和b都引用了它。无论您使用什么引用,可变的或不可变的,您都无法更改字符串。但是您可以更改可变引用本身以指向另一个(不可变)字符串:
b = "World"
【讨论】: