Java 字符串参数传递和修改(个人见解)

39 篇文章 1 订阅

                                   参考博文:https://blog.csdn.net/baidu_28997655/article/details/83992954

首先贴出一道面试题

public class Example{
    String str = new String("good");
    char[ ] ch = { 'a' , 'b' , 'c' };
    public static void main(String args[]){
        Example ex = new Example();
        ex.change(ex.str,ex.ch);
        System.out.print(ex.str + " and ");
        System.out.print(ex.ch);
    }
    public void change(String str,char ch[ ]){
        str = "test ok";
        ch[0] = 'g';
    }
}

当然答案也先贴出:

good and gbc

解析

1.首先按照正常的思路来思考

这里的change方法的参数,传递的是str和ch数组的地址,而在方法体内修改了str的值答案应该是:test ok and gbc。

2.问题1:字符串传参是值传递还是地址传递?

自己思考的答案和运行结果不同肯定是有问题的。
我们先打印一下各个代码块中的地址:

public class Test {
    String str = new String("good");
    char[ ] ch = { 'a' , 'b' , 'c' };
    public static void main(String args[]){
        Test ex = new Test();
        // 方法运行前,成员变量str的地址
        System.out.println("1-" + System.identityHashCode(ex.str));
        
        ex.change(ex.str,ex.ch);
        // 方法运行后,成员变量str的地址
        System.out.println("2-" + System.identityHashCode(ex.str));
        
        System.out.print(ex.str + " and ");
        System.out.print(ex.ch);
    }
    public void change(String str,char ch[ ]){
        // 方法体修改局部变量str的值之前的地址
        System.out.println("3-" + System.identityHashCode(str));
        
        str = "test ok";
        
        // 方法体修改局部变量str的值之后的地址
        System.out.println("4-" + System.identityHashCode(str));
        
        ch[0] = 'g';
    }
}

运行结果:

1-1872034366
3-1872034366
4-1581781576
2-1872034366
good and gbc

从上面可以看到,在传递字符串参数的时候,传递的是字符串的指针的一个副本,是属于值传递,在修改之前地址和成员变量str的地址相同,但是修改之后就不同了,由于字符串常量是在编译时期就已经创建的内存空间,既然创建了就有地址,当在传递字符串参数时,由于没有修改,所以传递的副本指针指向的内存和成员变量指针指向的内存的地址相同,但是修改之后,就是将新字符串的地址传递给了副本指针str,使得副本指针地址改变,但是没有改变原指针的指向。

2.问题2:字符串改变到底是内存地址改变还是内存中的值改变

首先在上面代码进行一些修改:

public class Test {
    String str = new String("good");
    char[ ] ch = { 'a' , 'b' , 'c' };
    public static void main(String args[]){
        Test ex = new Test();
        ex.change(ex.str,ex.ch);
        System.out.print(ex.str + " and ");
        System.out.print(ex.ch);
    }
    public void change(String str,char ch[ ]){
        System.out.println("1-" + System.identityHashCode(str));
        str = "test ok";
        System.out.println("2-" + System.identityHashCode(str));
        str = "test oj";
        System.out.println("3-" + System.identityHashCode(str));

        ch[0] = 'g';
    }
}

运行结果

1-1872034366
2-1581781576
3-1725154839
good and gbc

由上可知,参数传递过来指针指向的地址是1-1872034366,修改之后指向2-1581781576,再次修改之后指向3-1725154839,所以,字符串改变实际上是将指针指向了另一块内存,并不是将指向内存中的值改变。.

结论

  • 字符串传参是值传递,是将原来变量的指针(引用)复制一份传递给方法,但是他们指向的内存是同一个。
  • 字符串常量是在编译时期就已经创建了内存空间,改变字符串常量其实就是改变指针的指向地址,从指向一个常量变为指向另一个常量。

String在JVM层次的解析

有关字符串的在JVM底层实现的方式可以参考本篇博文JVM – StringTable(大师,我悟了)

        首先,我们要知道的是System类下的静态方法identityHashCode会返回一个变量的实际地址经过计算得到的值,所以只有指向同一块内存的变量,该方法返回的值才是相同的。

        字面量在编译后就存放在Class文件中,程序运行1,将字节码加载到方法区,当程序第一次因不用这个字面量的时候,该字面量就会被加载到字符串常量池中,而他的位置是经过hash后得出的,每一个相同的字面量都有一个唯一的地址,所以在运行时,你改变str指向的字符串,也只是将字符串常量池中不同元素的地址赋给了这个局部str变量,并不会对main方法的str造成任何影响。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值