Java 对象赋值
Posted
技术标签:
【中文标题】Java 对象赋值【英文标题】:Java Object Assignment 【发布时间】:2012-06-16 05:23:20 【问题描述】:我是 Java 新手,我有一些关于对象分配的问题。例如,
Test t1 = new Test();
Test t2 = t1;
t1.i=1;
假设变量 i
在 Test 类中定义,我是否正确假设 t1 和 t2 都指向同一个对象,其中修改 t1.i=1
会影响 t1
和 t2
?实际上我测试了它,似乎我是对的。但是,当我在String
上尝试相同的操作时,修改只发生在另一侧不受影响的一侧。这背后的原因是什么?
编辑:我用 String 尝试过的情况。
String s1 = "0";
String s2 = s1;
s1 = "1";
System.out.println(s1);
System.out.println(s2);
我通过在 String 上测试案例来意识到我的错误,因为它是不可变的。我以为s1="1"
修改字符串的情况,其实就是将“1”的引用返回给s1。尽管如此,我的问题仍然存在。 Test t2 = t1;
是否导致 t2 和 t1 都指向同一个对象,或者现在每个都有自己的对象?这种情况是否适用于 Java 上的所有对象?
【问题讨论】:
“在字符串上尝试相同的东西”是什么意思? String 对象中没有修改字符串本身的方法。请仔细阅读文档。 如果您在 String 上发布您正在执行的测试代码,我们可以更具体地说明您做错了什么 【参考方案1】:你是对的,但是字符串是一个特例;在这种情况下,它们是不可变的并且表现得像原语。
@newacct
我引用http://docs.oracle.com/javase/tutorial/java/data/strings.html:
注意:String 类是不可变的,因此一旦创建了 字符串对象不能更改。 String 类有一个数字 的方法,其中一些将在下面讨论,似乎 修改字符串。既然字符串是不可变的,那么这些方法究竟是什么 do 是创建并返回一个包含结果的新字符串 操作。
这就是使字符串成为特殊情况的原因。如果您不知道这一点,您可能会认为引用中讨论的方法不会返回新字符串,这会导致意外结果。
@user1238193
考虑您的以下问题:“Test t2 = t1; 是否导致 t2 和 t1 都指向同一个对象,或者现在每个对象都有自己的对象?这种情况是否适用于 Java 上的所有对象?”
t1 和 t2 将指向同一个对象。这适用于任何 java 对象(包括不可变对象)
【讨论】:
没有“特殊情况”。对任何类型的引用赋值都会改变它指向的对象,而不会影响它曾经指向的对象。 字符串是一种特殊情况;它们是对象,但它们是不可变的,这意味着如果您尝试通过例如 String.replace 来更改它们,您将获得一个新对象而不是相同的对象变异。 不,String
只是碰巧没有任何方法可以改变它。 “尝试改变它们”没有意义;你不能“尝试”做一些不存在的事情。 String.replace
给你一个新对象——你的意思是什么?这就是它的文档所说的。 Integer
和许多其他类是不可变的。通过将字段设为私有并且不提供更改其字段的方法,您可以轻松地编写一个不可变的类。而且无论如何,可变性与问题无关,最初是关于更改Test
上的字段,但String
上没有公共字段
然后你如何处理字符串池,所有类都有类似的东西?
字符串实习池与这个问题或可变性完全无关。任何类都可能有也可能没有像 String 这样的实习池【参考方案2】:
您的第一个假设是正确的。使用以下代码行:
Test t1 = new Test();
您创建一个新的 Test 对象,同时创建一个名为 t1 的 Test 引用来引用它。
在您发布的代码的第二行:
Test t2 = t1;
您实际上是在创建另一个 Test 引用,并将其分配给 t1 引用的同一对象。
所以t1.i = 1;
会影响t2.i
因为它毕竟是同一个对象。
对于字符串,字符串是不可变的,实例化后不能修改。
关于您的编辑:
String s1 = "0";
String s2 = s1;
s1 = "1";
System.out.println(s1);
System.out.println(s2);
他们会打印出不同的结果,因为当你真正说出来时
s1 = "1";
您实际上将 s1 绑定到另一个 String 对象,但 s2 仍将引用值为“0”的对象。
【讨论】:
【参考方案3】:在这两种情况下,您正在做完全不同的事情。在第一种情况下,使用t1.i = 1;
,您正在修改t1
指向的对象。在第二种情况下,使用t1 = "1";
,您正在更改引用以指向另一个对象(类似于您在t2 = t1;
时所做的。
如果您对Test
执行与第二种情况相同的操作,您将得到相同的结果(假设Test
有一个采用整数的构造函数):
Test t1 = new Test(5);
Test t2 = t1;
t2 = new Test(1); // Here we are assigning to the variable, just like your 2nd example
System.out.println(t1);
System.out.println(t2);
人们提到String
是不可变的。但这无关紧要,语言中没有“可变性”的概念,“可变”和“不可变”类的工作方式没有区别。如果一个类碰巧没有您可以设置的任何字段或任何可以更改其内部内容的方法,我们非正式地说它是“不可变的”。 String
就是这种情况。但是,如果您根本不做任何改变它,可变类的工作方式完全相同。
【讨论】:
在否决和评论其他答案之前,请先查看问题编辑历史记录。这会给你一个暗示,为什么许多答案,说同样的事情,被赞成。【参考方案4】:你是绝对正确的,因为 t1 和 t2 都引用同一个对象,对象状态的任何通道都会影响两者。
String 是一个不可变的对象。所以根本无法修改。 see this 了解更多关于 java 中不可变对象的信息。
【讨论】:
这并不能解释问题。Test
也是如此:Test s1 = new Test(2); Test s2 = s1; s1 = new Test(1);
【参考方案5】:
String objects are immutable.
编辑
Test t2 = t1;
是否导致 t2 和 t1 都指向同一个对象,或者现在每个都有自己的对象?
是的。虽然t2
是一个新的引用,但它会指向同一个对象,因为你告诉它这样做。创建一个Test
类型的新引用t2
并让它指向t1
指向的同一个对象。
但是,当您使用String
s 执行此操作,然后执行s1 = "1" ;
之类的操作时,您正在使 s1 指向另一个 String 对象。你可以用s1 = new String(1);
来理解它。
【讨论】:
这并不能解释问题。Test
也是如此:Test s1 = new Test(2); Test s2 = s1; s1 = new Test(1);
@newacct OP 稍后编辑了该帖子。最初的帖子只能用这几句话来回答。我现在将编辑我的帖子。感谢您指出这一点。
即使在编辑之前,“字符串是不可变的”也不是正确的答案。他说“当我在 String 上尝试同样的事情时”;答案应该是“你说的不可能。不可能对String做同样的事情”【参考方案6】:
字符串和其他对象一样是对象。因此,您分配给它们的任何变量都指向对象的同一个实例,就像您对测试对象所做的那样。
但请记住,String 没有您可以像在 Test 上那样设置的字段,因此您基本上无法进行相同的测试,因此无法将您的代码从 Test 对象移植到 String 对象。
使用原始类型(如 long、int 等)会得到相反的行为。 它们被“按值”分配给变量,所以如果你这样做
int t1 = 12;
int t2 = t1;
t1=15;
t2 的值仍然是 12
【讨论】:
【参考方案7】:以 StringBuilder 为例会更清楚一点。以下示例显示了仅使用引用而不是值的对象分配。
StringBuilder str = new StringBuilder();
str.append("GFG");
StringBuilder str1 = str;
str.append("tail");
// output: str1 = GFGtail str = GFGtail
System.out.println("str1 = " + str1.toString() + " str = " + str.toString());
【讨论】:
【参考方案8】:因为java使用了字符串字面量的概念。假设有5个引用变量,都引用一个对象“0”。如果一个引用变量改变了对象的值,就会影响到所有的引用变量。这就是为什么字符串对象在 java 中是不可变的。
【讨论】:
以上是关于Java 对象赋值的主要内容,如果未能解决你的问题,请参考以下文章