面朝大海,春暖花开

IN IT && WIN IT

String和基本包装类作为参数在传递问题

String和基本包装类作为参数在传递问题

public class ReferenceDemo {

    public static void StringReference(){
        String a = new String("abc");
        String b = a;
        changeString(b);
        System.out.println("a: "+a);
        System.out.println("b: "+ b);
    }

    public static void changeString(String str){
        // str = "23232"; 同样的结果
        str = new String("abcd");
    }

    public static void IntegerReference(){
        Integer c = new Integer("1");
        Integer d = c;
        changeInteger(d);
        System.out.println("c: "+c);
        System.out.println("d: "+ d);
    }

    public static void changeInteger(Integer d){
        d = new Integer("12");
    }

    public static void main(String[] args) {
        StringReference();
        IntegerReference();
    }

}

结果:

a: abc
b: abc
c: 1
d: 1

可以发现b没有变成abcd,而且d也没有变成12, 明明是引用类型,什么变化,网上说String类型和基本包装类作为参数传递时会变成值传递,还有一种说法是String和基本包装类构造函数里的value是final类型的,我们知道,被final修饰的变量一旦初始化后就不能被修改。

//Integer.java源码
public final class Integer extends Number implements Comparable<Integer> {
    private final int value;
    public Integer(String s) throws NumberFormatException {
            this.value = parseInt(s, 10);
    }
}

//String源码
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
    private final char value[];
    public String() {
           this.value = new char[0];
    }
 }

自己实现一个实体类PlainString:

public class PlainString {

    private String value;

    public PlainString(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    @Override
    public String toString() {
        return this.value;
    }
}

测试:

public class ReferenceDemo {

    public static void plainString(){
        PlainString ps = new PlainString("aaa");
        PlainString pls = ps;
        changePlainString(pls);
        System.out.println("ps: "+ps);
        System.out.println("pls: "+pls);
    }

    public static void changePlainString(PlainString ps){
//        ps = new PlainString("bbb"); //注释1
        ps.setValue("bbb");    //注释2
    }


    public static void main(String[] args) {
        plainString();
    }

}

结果:

//打开注释1
ps: aaa
pls: aaa

//打开注释2
ps: bbb
pls: bbb

如果将PlainString中变成value用final修饰,那么就不能有setter方法了

public class PlainString {

    private final String value;

    public PlainString(String value) {
        this.value = value;
    }


    @Override
    public String toString() {
        return this.value;
    }
}

结果:

ps: aaa
pls: aaa

猜测: 刚开始初始对象时在堆上分配内存地址A,在非setter方法赋值的change*方法,实际上是在堆上分配了一块不同于初始化对象的内在地址B,当出change*方法体后,GC会回收B的内存地址,相当于没有改变;但使用setter方法的change*方法,实际上是在同一块内存地址A上修改了value,因此会对指向该内存地址的句柄产生影响

阅读更多
个人分类: java基础知识
上一篇kafka初探
下一篇java中的自动装箱和自动折箱
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭