我正在尝试一些事情,我遇到了这个有趣的场景。我只是想了解这两个片段的主要区别。
最初,我拿了两套,初始化了一套并将参考分配给其他。当我清除A组时,我注意到Set B大小也变为零
Set<String> A = new HashSet<String>();
A.add("hello");
A.add("HEY");
A.add("hey");
Set<String > B = A;
System.out.println("initial sizes :" + A.size() + " " + B.size());
A.clear();
System.out.println("final sizes :" + A.size() + " " + B.size());
这个输出是这样的:
initial sizes :3 3
final sizes :0 0
现在,我尝试按如下方式描述对象的相同行为:
Object a1 = new Object();
Object b1 = a1;
System.out.println("initial sizes :" + b1.toString() + " " + a1.toString());
a1 = null;
System.out.println("initial sizes :" + b1.toString() + " " + a1);
此输出类似于:
initial sizes :java.lang.Object@54182d86 java.lang.Object@54182d86
initial sizes :java.lang.Object@54182d86 null
这里有什么确切的区别,当我试图打印b1.toString()
答案 0 :(得分:4)
对于原语,例如int
,double
,float
等,会生成值的副本,即通过值传递: -
int x = 10;
public void foo(int k){
}
foo(x)
此处k
会获得x
中存储的值的副本,因此k
现在的值为10.但是,{{1} }和x
位于两个不同的内存位置。更改y
的值不会更改x
的值。
对于对象引用,引用的副本将通过值传递(引用只不过是某些内存的地址)。所以本质上两个引用现在都指向同一个对象(即相同的内存位置)。
k
将生成参考Myobject m = new Myobject();
public void bar (Myobject j){
}
bar(m)
的值的副本并将其分配给m
。 j
和m
现在都指向同一个对象。
答案 1 :(得分:3)
这里的区别在于a1
和b1
不是对象本身,而是对这些对象的引用。因此,如果修改a1
引用的对象,b1
引用的对象(同一个对象)也会改变。但是,如果您指示a1
指向另一个实例(或在这种情况下为null
),则它将不再引用相同的对象,因此更改为不会影响b1
。< / p>
进一步详细说明:Java 按值传递。但是,当您尝试传递对象(而不是原始值)时,您实际上传递了引用的值(有时也称为句柄)。这就是为什么在尝试确定Java是通过句柄传递还是通过引用传递时,它有时会有点混乱。
答案 2 :(得分:2)
检查此图片。 A2 / A3是对项目的参考。在第一种情况下,这些是对Set(图像上的a1)的引用。当一个引用修改对象时,第二个引用会看到相同的更改
另一方面,如果您只是设置reference = null
,那么您可以删除一个箭头&#34;从图片。引用停止指向对象,但另一个引用仍然指向它。
答案 3 :(得分:0)
您刚刚注意到java完全按值传递,其中甚至对其他对象的引用也作为值传递。
如果使对象无效,则实际上不对对象进行归零,将在同一对象上执行哪些方法。您只是将对象的引用值归零。
检查此示例,您只是使列表1上的引用值为空,而您仍然可以在原始列表上执行方法。
ArrayList<Integer> list1 = new ArrayList<Integer>(0);
list1.add(1);
list1.add(2);
ArrayList<Integer> list2 = list1;
list1.clear();
list1 = null;
System.out.println(list2.size());
System.out.println(list1.size()); // will cause an nullpointerexception
list1上方法的调用也会影响list2,但是将对象list1归零不会影响列表1
答案 4 :(得分:0)
我的答案是@ I.K的另一个要素。回答。基元(值的副本)和非基元(参考值的副本) - 这是关键的理解。
请查看我已放置注释的代码(托管在IDEONE上):
import java.io。*;
/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
public static void main (String[] args) throws java.lang.Exception
{
String a1 = "blablabla";
String b1 = a1;
System.out.println(b1);
System.out.println(a1);
System.out.println(b1.hashCode());
System.out.println(a1.hashCode());
a1 = "wow";
System.out.println(b1.hashCode());
System.out.println(a1.hashCode());
System.out.println(b1);
System.out.println(a1);
Set<String> a = new HashSet<String>();
Set<String> b = a;
a.add("hey");
a.add("HellO");
System.out.println(b.size());
System.out.println(b.hashCode()); // e.g. 69712814
System.out.println(a.hashCode()); // same - 69712814 (It's important to know)
a.clear();
System.out.println(a.size()); // same hashcode i.e. gets affected by the change.
System.out.println(b.size());
您可以看到使用相同的代码对它们进行有效散列。
String
类在Java中有点特殊,因为您可能知道它们使用字符串池来“实习”值。如果您运行上面的代码,您可以看到,只要执行a1 = "wow";
,它就会在池中创建一个新值“哇”,因此,hashCode()会发生变化。