了解Java中的引用行为

时间:2015-02-05 14:40:41

标签: java object reference

我正在尝试一些事情,我遇到了这个有趣的场景。我只是想了解这两个片段的主要区别。

最初,我拿了两套,初始化了一套并将参考分配给其他。当我清除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()

时,我希望得到一个NullPointerException

5 个答案:

答案 0 :(得分:4)

对于原语,例如intdoublefloat等,会生成的副本,即通过传递: -

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) 的值的副本并将其分配给mjm现在都指向同一个对象。

答案 1 :(得分:3)

这里的区别在于a1b1不是对象本身,而是对这些对象的引用。因此,如果修改a1引用的对象,b1引用的对象(同一个对象)也会改变。但是,如果您指示a1指向另一个实例(或在这种情况下为null),则它将不再引用相同的对象,因此更改为不会影响b1。< / p>

进一步详细说明:Java 按值传递。但是,当您尝试传递对象(而不是原始值)时,您实际上传递了引用的值(有时也称为句柄)。这就是为什么在尝试确定Java是通过句柄传递还是通过引用传递时,它有时会有点混乱。

答案 2 :(得分:2)

检查此图片。 A2 / A3是对项目的参考。在第一种情况下,这些是对Set(图像上的a1)的引用。当一个引用修改对象时,第二个引用会看到相同的更改

另一方面,如果您只是设置reference = null,那么您可以删除一个箭头&#34;从图片。引用停止指向对象,但另一个引用仍然指向它。

enter image description here

答案 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()会发生变化。