了解Java对象数组中对象的引用

时间:2014-12-07 15:24:05

标签: java arrays pointers memory

我编写了一些代码来理解如果我将一个基元,对象可变或不可变的混合存储到Array对象中会发生什么。我可以在存储后对它们进行修改,看看它是否正确解除引用这些内容并返回修改后的值。我没有得到我的预期代码要做的事情?我想我知道为什么,并想澄清这种理解是否正确。这是代码。

public class DriverApp3 {

private static String CYEAR = "2014" ;
private static StringBuffer CYEARFLG = new StringBuffer("1914") ;

public double money = 2.13 ;

public static void main(String args[])
{
    Integer j = 12 ;
    DriverApp3 d = new DriverApp3(); 
    StringBuffer sb = new StringBuffer("Unicorn");
    MutableInteger mi = new MutableInteger(67);
    int i = 76 ;

    Object[] parseXML = new Object[]{j,DriverApp3.CYEAR,d, d.money,DriverApp3.CYEAR, sb, mi, DriverApp3.CYEARFLG,i};

    //                               0           1      2      3        4             5   6           7          8
    System.out.println("======chng of all original values ==========");
    j = 13 ; 
    d.money = 3.14 ; 
    parseXML[4]="2015";
    DriverApp3.CYEAR = "2013"; 
    mi.set(9);
    sb.replace(3,5,"KO");
    DriverApp3.CYEARFLG.replace(0,4,"1939");
    i = 7 ;

    Object[] chngdO = new Object[]{j,DriverApp3.CYEAR,d, d.money,DriverApp3.CYEAR, sb, mi, DriverApp3.CYEARFLG,i};

    int cnt = 0 ;
    for (Object m : parseXML)
    {
        Integer s_objid = m.hashCode();
        String clsType = "Type="+m.getClass().getTypeName();
        String clsName = "SimplName="+m.getClass().getSimpleName();
        String canName = "CanonName="+m.getClass().getCanonicalName();

        Object n = chngdO[cnt];
        Integer ns_objid = n.hashCode();
        String nclsType = "Type="+n.getClass().getTypeName();
        String nclsName = "SimplName="+n.getClass().getSimpleName();
        String ncanName = "CanonName="+n.getClass().getCanonicalName();


        System.out.println(cnt + ": Hashcode=" + s_objid + ":" + clsType + ":" + m + "\n " + ": Hashcode=" + ns_objid + ":" + nclsType /*+ ":"+ clsName+ ":"+  canName*/+ ":" + n + "\n" );
        cnt++ ;
    }

}

@Override
public String toString()
{

    return "Hashcode="+this.hashCode() + "," + DriverApp3.CYEAR  ;
} 

}

可变类也在这里......

/ **  *  来自stackoverflow.com的@author代码片段  *不是线程安全的  * / 公共类MutableInteger {

private int value;
public MutableInteger(int value) {
    this.value = value;
}
public void set(int value) {
    this.value = value;
}
public int intValue() {
    return value;
}

public String toString()
{
    return "id="+this.hashCode()+" val=" + this.value ; 
}

}

我的申请表的输出是.....

======chng of all original values ==========

0:Hashcode = 12:Type = java.lang.Integer:12  :Hashcode = 13:Type = java.lang.Integer:13

1:Hashcode = 1537249:Type = java.lang.String:2014  :Hashcode = 1537248:Type = java.lang.String:2013

2:Hashcode = 366712642:Type = xander.DirRefOrCopy.DriverApp3:Hashcode = 366712642,2013  :Hashcode = 366712642:Type = xander.DirRefOrCopy.DriverApp3:Hashcode = 366712642,2013

3:Hashcode = 815979831:Type = java.lang.Double:2.13  :Hashcode = 300063655:Type = java.lang.Double:3.14

4:Hashcode = 1537250:Type = java.lang.String:2015  :Hashcode = 1537248:Type = java.lang.String:2013

5:Hashcode = 1829164700:Type = java.lang.StringBuffer:UniKOrn  :Hashcode = 1829164700:Type = java.lang.StringBuffer:UniKOrn

6:Hashcode = 2018699554:Type = xander.DirRefOrCopy.MutableInteger:id = 2018699554 val = 9  :Hashcode = 2018699554:Type = xander.DirRefOrCopy.MutableInteger:id = 2018699554 val = 9

7:Hashcode = 1311053135:Type = java.lang.StringBuffer:1939  :Hashcode = 1311053135:Type = java.lang.StringBuffer:1939

8:Hashcode = 76:Type = java.lang.Integer:76  :Hashcode = 7:Type = java.lang.Integer:7

1 个答案:

答案 0 :(得分:0)

指数0 对于Integer j,它是不可变的,所以一旦我在数组外部修改它,第0个仍然指向值为12的那个,因为它仍然存在于Java保持它的整个Integer的不可变单个副本的地方。这显然是一个保持每个类或接口的所有运行时常量的区域。在这种情况下,它是字符串文字区域。修正后的j指向一个值为13的新的不可变单个副本。参见Hashcodes也不同。

指数1 像上面一样的问题。仅仅因为它是DriverApp3的一个成员,你本来希望自己修改它,但它不会因为数组在java存储该不可变的单个副本的地方存储了旧的内存地址字符串值。因为,该地址仍然是“活着的”,它一直指向数组中的内存地址。非常非直观 - 不确定是否有其他模式或语言可以更好地处理这个问题。它可能是错误的来源。想要确保你反映你的变化 - 在其中使用MUTABLE obj而不是IMMUTABLE。或者,您还需要记住,Java可能会将您的基元(如果存储基元)Autobox Autobox放入Object文本中,具体取决于它是String,Integer,Double等。

指数2 一切都按预期工作 - 它指向数组。因此,它在更改时继续指向相同的可变对象地址。

指数3 Double再次将Autoboxed变为不可变的Double。因此,它与String和Integer是同一个问题,因为它是一个Object Array。当然,自Java 1以来就是这样 - 顺便说一句 - 我在这里使用Java 8编译器。

指数4 parseXML [4] = “2015”; 那么我们在这里直接用不可变的String literal 2015

的地址覆盖地址

指数5& 6 StringBuffer和MutableInteger正确反映修正,因为它们仍然指向相同的地址。 Java不会创建新副本,因为它们的定义本质上是可变的。

指数7 反映更改,因为它是一个可变的StringBuffer而不是共享的不可变文字!!

指数8 遭受同一个原语被自动装入不可变共享单拷贝文字的问题。

因此,如果您希望存储数组的内容反映数组之外的修改更改,请使用Mutable Objects。并且,要注意自动Autoboxing陷入不可变的Object文字的陷阱。