Anu*_*lan 194 java string immutability
我在不可变字符串上编写了以下代码.
public class ImmutableStrings {
public static void main(String[] args) {
testmethod();
}
private static void testmethod() {
String a = "a";
System.out.println("a 1-->" + a);
a = "ty";
System.out.println("a 2-->" + a);
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
a 1-->a
a 2-->ty
Run Code Online (Sandbox Code Playgroud)
这里变量的值a已经改变(许多人说不可变对象的内容不能改变).但究竟是什么意思说String是不可改变的?你能否为我澄清一下这个话题?
来源:https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
rog*_*hat 397
在继续进行不可变性的大惊小怪之前,让我们先看看String课程及其功能,然后再得出任何结论.
这是如何String工作:
String str = "knowledge";
Run Code Online (Sandbox Code Playgroud)
像往常一样,这会创建一个包含"knowledge"并为其指定引用的字符串str.够简单吗?让我们执行更多功能:
String s = str; // assigns a new reference to the same string "knowledge"
Run Code Online (Sandbox Code Playgroud)
让我们看看以下声明如何工作:
str = str.concat(" base");
Run Code Online (Sandbox Code Playgroud)
这将一个字符串追加" base"到str.但是等等,这怎么可能,因为String对象是不可变的?令你惊讶的是,它是.
执行上述语句时,VM将获取值String str,即"knowledge"并附加" base",为我们提供值"knowledge base".现在,由于Strings是不可变的,因此VM无法将此值赋给str,因此它会创建一个新String对象,为其赋值"knowledge base",并为其提供引用str.
这里需要注意的一点是,虽然String对象是不可变的,但它的引用变量却不是.因此,在上面的例子中,引用是为了引用新形成的String对象.
在上面的例子中,我们有两个String对象:第一个是我们使用value创建的"knowledge",指向的s,第二个是"knowledge base"指向的str.但是,从技术上讲,我们有三个String目标,第三个是字面"base"的concat声明.
如果我们没有什么其他的参考s来"knowledge"?我们会失去这一点String.但是,它仍然存在,但由于没有引用而被视为丢失.再看下面的一个例子
String s1 = "java";
s1.concat(" rules");
System.out.println("s1 refers to "+s1); // Yes, s1 still refers to "java"
Run Code Online (Sandbox Code Playgroud)
发生了什么:
String "java"并引用s1它.String "java rules",但没有任何引用它.所以,第二个String瞬间就会丢失.我们无法达到它.引用变量s1仍然指原始变量String "java".
几乎每个应用于String对象以便修改它的方法都会创建新String对象.那么,这些String物体去哪儿了?嗯,这些存在于内存中,任何编程语言的关键目标之一就是有效利用内存.
随着应用程序的增长,文字占据大面积内存是非常常见的String,这甚至会导致冗余.因此,为了提高Java的效率,JVM预留了一个称为"字符串常量池"的特殊内存区域.
当编译器看到String文字时,它会String在池中查找.如果找到匹配项,则对新文本的引用将定向到现有文本,String并且不会String创建任何新对象.现有的String还有一个参考.以下是使String对象不可变的观点:
在String常量池中,String对象可能具有一个或多个引用.如果多个引用指向同一个引用,String甚至不知道它,如果其中一个引用修改了该String值,则会很糟糕.这就是String对象不可变的原因.
那么,现在你可以说,如果有人改写了String类的功能会怎么样?就是这样的原因的String类被标记final,这样没有人可以凌驾于其方法的行为.
Eng*_*uad 171
String是不可变的意味着您无法更改对象本身,但您可以更改对象的引用.
执行时a = "ty",实际上是在更改a由String文本创建的新对象的引用"ty".
更改对象意味着使用其方法更改其中一个字段(或者字段是公共字段而不是最终字段,以便可以从外部更新它们而无需通过方法访问它们),例如:
Foo x = new Foo("the field");
x.setField("a new field");
System.out.println(x.getField()); // prints "a new field"
Run Code Online (Sandbox Code Playgroud)
在一个不可变的类中(声明为final,以防止通过继承进行修改)(它的方法不能修改它的字段,而且字段总是私有的并且建议是最终的),例如String,你不能改变当前的String但是你可以返回一个新的String,即:
String s = "some text";
s.substring(0,4);
System.out.println(s); // still printing "some text"
String a = s.substring(0,4);
System.out.println(a); // prints "some"
Run Code Online (Sandbox Code Playgroud)
Gre*_*ill 18
你改变什么a 指.试试这个:
String a="a";
System.out.println("a 1-->"+a);
String b=a;
a="ty";
System.out.println("a 2-->"+a);
System.out.println("b -->"+b);
Run Code Online (Sandbox Code Playgroud)
您将看到物体到a,然后b是指没有改变.
如果要防止代码更改哪个对象a引用,请尝试:
final String a="a";
Run Code Online (Sandbox Code Playgroud)
字符串是char[]包含一系列UTF-16代码单元,int该数组的偏移量和int长度.
例如.
String s
Run Code Online (Sandbox Code Playgroud)
它为字符串引用创建空间.分配副本引用,但不修改这些引用引用的对象.
你也应该意识到这一点
new String(s)
Run Code Online (Sandbox Code Playgroud)
并没有真正做任何有用的事情.它只创建另一个由相同数组,偏移量和长度支持的实例s.很少有理由这样做,因此被大多数Java程序员认为是不好的做法.
Java的双引号的字符串像"my string"真的来引用实习 String情况下,这样"bar"是相同的字符串实例的引用,不管它有多少次出现在你的代码.
"hello"创建一个池化的实例,并new String(...)创建一个非池化的实例.尝试System.out.println(("hello" == "hello") + "," + (new String("hello") == "hello") + "," + (new String("hello") == new String("hello")));,你应该看到true,false,false