1
200
根据 Effective Java ,第4章,第73页,第2版:
同一章的其他要点:
|
2
99
至少有两个原因。 第一-安全 http://www.javafaq.nu/java-article1060.html
第二存储器效率 http://hikrish.blogspot.com/2006/07/why-string-class-is-immutable.html
|
3
57
实际上,原因字符串在Java中是不可变的,与安全性没有太大关系。两个主要原因如下: 广告安全:字符串是广泛使用的对象类型。因此,它或多或少地保证在多线程环境中使用。字符串是不可变的,以确保在线程之间共享字符串是安全的。拥有不变的字符串可以确保在将字符串从线程A传递到另一个线程B时,线程B不能意外地修改线程A的字符串。 这不仅有助于简化已经相当复杂的多线程编程任务,而且有助于提高多线程应用程序的性能。当可以从多个线程访问可变对象时,必须以某种方式同步对这些对象的访问,以确保一个线程在被另一个线程修改时不会尝试读取对象的值。正确的同步对于程序员来说既困难又昂贵。不能修改不可变对象,因此不需要同步。 性能:虽然已经提到了字符串交互,但它仅代表Java程序的内存效率的一个小增益。只有字符串文本被实习生。这意味着只有在 源代码 将共享同一个字符串对象。如果您的程序动态地创建相同的字符串,它们将在不同的对象中表示。 更重要的是,不可变的字符串允许它们共享内部数据。对于许多字符串操作,这意味着不需要复制底层的字符数组。例如,假设您想要取字符串的前五个字符。在爪哇中,您将调用MyStudio子字符串(0,5)。在这种情况下,substring()方法只需创建一个共享mystring的基础char[]的新string对象,但谁又知道它从索引0开始,到该char[]的索引5结束。要将其以图形形式显示,您将得到以下结果:
这使得这种操作非常便宜,O(1)因为操作既不依赖于原始字符串的长度,也不依赖于我们需要提取的子字符串的长度。此行为还具有一些内存优势,因为许多字符串可以共享其基础字符[]。 |
4
28
螺纹安全和性能。如果一个字符串不能被修改,那么在多个线程之间传递一个引用是安全和快速的。如果字符串是可变的,则必须将字符串的所有字节复制到新实例,或者提供同步。一个典型的应用程序每次需要修改一个字符串时,都会读取该字符串100次。参见维基百科 immutability . |
5
11
我们真的应该问,“为什么x应该是可变的?”最好是默认不变,因为前面已经提到了 Princess Fluff . 有些东西是可变的,这应该是个例外。 不幸的是,大多数当前的编程语言都默认为可变性,但希望将来的默认值更多地是不可变性的(请参见 A Wish List for the Next Mainstream Programming Language ) |
6
7
一个因素是,如果字符串是可变的,那么存储字符串的对象必须小心地存储副本,以免它们的内部数据在没有通知的情况下发生更改。考虑到字符串是一个相当原始的类型,比如数字,当我们可以将它们视为通过值传递的,即使它们是通过引用传递的(这也有助于节省内存),也是很好的。 |
7
7
字符串不是基元类型,但是您通常希望将它与值语义一起使用,即像值一样。
价值是你可以信任的东西,它不会在你背后改变。
如果你写:
字符串作为一个对象具有自然的指针语义,要获得值语义,它也需要是不可变的。 |
8
6
真的!我不能相信这里的错误信息。不可变的字符串与安全性无关。如果有人已经可以访问正在运行的应用程序中的对象(如果你试图防止有人在你的应用程序中“黑客”一个字符串,就必须假设这一点),那么他们肯定是黑客的很多其他机会。 字符串的不可变性正在解决线程问题,这是一个非常新颖的想法。六羟甲基三聚氰胺六甲醚。。。我有一个对象被两个不同的线程改变了。如何解决此问题?同步访问对象?Naawww…让我们不要让任何人更改对象——这将解决所有混乱的并发问题!事实上,让所有的对象都是不可变的,然后我们可以从Java语言中删除同步化的结构。 真正的原因(由上面的其他人指出)是内存优化。在任何应用程序中,重复使用相同的字符串文字都很常见。事实上,这是很常见的,几十年前,许多编译器对只存储字符串文本的单个实例进行了优化。这种优化的缺点是,修改字符串文字的运行时代码引入了一个问题,因为它正在修改共享它的所有其他代码的实例。例如,对于应用程序中的某个函数来说,将字符串“dog”更改为“cat”是不好的。printf(“dog”)将导致“cat”被写入stdout。因此,需要有一种方法来防止代码试图更改字符串文本(即使其不可变)。一些编译器(在操作系统的支持下)可以通过将字符串文字放入一个特殊的只读内存段来实现这一点,如果进行写入尝试,该段将导致内存错误。 在Java中,这就是所谓的交互。这里的Java编译器只是遵循编译器几十年来完成的标准内存优化。为了解决在运行时修改这些字符串文字的相同问题,Java只是使字符串类不可变(即,不给您设置任何允许更改字符串内容的设置)。如果没有出现字符串文本的interning,则字符串不必是不可变的。 |
9
6
我知道这是个肿块,但是… 它们真的是不变的吗? 考虑以下内容。
…
甚至可以将其作为扩展方法。
这使得下面的工作
结论:它们处于编译器已知的不变状态。上面的描述只适用于.NET字符串,因为Java没有指针。但是,使用C中的指针,字符串可以完全可变。这不是指针的用途、实际用途或安全使用的方式;但是,这是可能的,因此会改变整个“可变”规则。通常不能直接修改字符串的索引,这是唯一的方法。有一种方法可以防止这种情况的发生,即当字符串被指向时不允许使用字符串的指针实例或进行复制,但两者都不允许,这使得C中的字符串不是完全不可变的。 |
10
3
在大多数情况下,“字符串”是(使用/处理为/认为为/假定为)有意义的 原子单位, 就像一个数字 . 因此,询问一个字符串中的各个字符为何不可变就如同询问整数中的各个位为何不可变一样。你应该知道为什么。想想看。 我不想这么说,但不幸的是,我们在辩论这件事,因为我们的语言很烂,我们试图用一个词, 一串 描述一个复杂的、上下文相关的概念或对象类别。 我们使用“字符串”进行计算和比较,类似于使用数字的方式。如果字符串(或整数)是可变的,为了可靠地执行任何类型的计算,我们必须编写特殊的代码来将它们的值锁定到不可变的局部形式中。因此,最好将一个字符串看作一个数字标识符,而不是16、32或64位的长度,而是数百位的长度。
当有人说“弦”时,我们都会想到不同的东西。那些把它简单地看作一组人物,而没有特别的目的的人,当然会对某人感到震惊。
刚刚决定
他们不应该操纵那些角色。但是“字符串”类不仅仅是一个字符数组。这是一个
考虑一下,如果字符串是可变的,会是什么样子。如果 易变的 当此函数使用用户名字符串时,另一个线程有意或无意地修改了用户名字符串:
安全不仅仅是“访问控制”,还涉及“安全”和“保证正确性”。如果一个方法不能很容易地被编写出来并依赖于可靠地执行一个简单的计算或比较,那么调用它是不安全的,但是调用编程语言本身是安全的。 |
11
2
这是一种权衡。字符串进入字符串池,当您创建多个相同的字符串时,它们共享相同的内存。设计人员认为这种节省内存的技术在普通情况下可以很好地工作,因为程序往往会在相同的字符串上磨很多。 缺点是连接会产生很多额外的字符串,这些字符串只是过渡的,只是变成垃圾,实际上会损害内存性能。您有StringBuffer和StringBuilder(在爪哇,StringBuilder也在.NET中)用来保存这些情况下的内存。 |
12
2
在C++中有字符串可变的决定会引起很多问题,请参见Kelvin Henney的这篇优秀文章。 Mad COW Disease . COW=书面副本。 |
13
2
Java中的字符串不是真正不可变的,可以使用反射和类加载来改变它们的值。你不应该为了安全而依赖那个财产。 有关示例,请参见: Magic Trick In Java |
14
2
不变性与安全性没有那么紧密的联系。为此,至少在.NET中,您得到了SecureString类。 |
15
0
不变是好的。查看有效的Java。如果每次传递字符串时都必须复制它,那么这将是许多容易出错的代码。对于哪些修改会影响哪些引用,您也会感到困惑。正如整数必须是不可变的才能表现得像int一样,字符串必须表现得像不可变的才能表现得像基元一样。在C++中,按值传递字符串在源代码中没有明确提及。 |
16
0
几乎每一条规则都有例外:
|
17
-1
这主要是出于安全考虑。如果你不能相信你的字符串是防篡改的,那么保护系统就要困难得多。 |
Emopusta · 从后端到前端的图像路径不工作 2 年前 |
Asdrubal Hernandez · Linq查询特定数组索引出错 2 年前 |
Niyazi Babayev · 如何在表达式中动态应用表达式? 2 年前 |
Dansih · .Net核心自定义身份验证方案 2 年前 |
lolorekkk · 面板插入。NET WinForm 2 年前 |