php中文网 | cnphp.com

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 397|回复: 0

String类型函数传递问题

[复制链接]

3142

主题

3152

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

UID
1
威望
0
积分
7956
贡献
0
注册时间
2021-4-14
最后登录
2024-11-22
在线时间
763 小时
QQ
发表于 2022-7-17 12:39:41 | 显示全部楼层 |阅读模式
String类型函数传递问题
问题
以前没有注意过的一个问题, 最近在使用String类型作为函数入参的时候, 发现函数内对于String类型的改变并不会影响到外层调用对象本身;
结论 (先说结论)
这个问题根本不存在 (属于是自己把自己绕进去了);
String类型与普通的java对象一样, 只不过是用final修饰的不可变对象 (具体看String类型的源码与相关介绍);
测试数据(为什么会有这个问题, 来源于以下操作)
发现String (其实Integer, Long... 等等这些类型也会这样)函数传递修改后, 对象的值并没有被改变;
主要是因为String类型与Integer...等等这些类型的赋值方式迷惑了我们, 不需要通过"new"关键字和反射也可以构建对象;
比如: Integer a = 123; 这种操作, 让我们误当作基本类型赋值(实际上这个问题比较基础, 但有时候也会迷糊);
以下是对上述的操作案例;
package timer;

/**
* @author liwangcai E-mail:1252376504@qq.com
*/
public class StringDemo {
    public static void changeString(String tmp) {
        //此处操作具有一定的迷惑行为, 通常情况下只有基本数据类型才会这么操作;
        //但是对与String类型, 相当于新建了一个对象或者是拿到了常量池中的对象;
        tmp = "new";
        //打印通过函数传递进来的tmp参数的地址
        System.out.println(System.identityHashCode(tmp));
    }

    public static void changeInteger(Integer tmp) {
        //此处操作和String类型一样
        tmp = 199;
        //打印通过函数传递进来的tmp参数的地址
        System.out.println(System.identityHashCode(tmp));
    }

    public static void changeOther(StringDemo stringDemo) {
        System.out.println(System.identityHashCode(stringDemo));
    }


    public static void main(String[] args) {
        String tmp = "old";
        //打印原始的tmp
        System.out.println(tmp);      
        //打印原始的tmp对象地址
        System.out.println(System.identityHashCode(tmp));
        changeString(tmp);
        //打印函数调用后的tmp值
        System.out.println(tmp);


        //出于好奇也测试了一下Integer类型
        Integer iTmp = 1;
        //打印原始的iTmp的值
        System.out.println(iTmp);
        //打印原始的iTmp对象地址
        System.out.println(System.identityHashCode(iTmp));
        changeInteger(iTmp);
        //打印函数调用后iTmp的值
        System.out.println(iTmp);

        //对于普通的java对象
        StringDemo stringDemo = new StringDemo();
        //打印当前对象的地址
        System.out.println(System.identityHashCode(stringDemo));
        changeOther(stringDemo);
    }
}

//执行结果
old
685325104
685325104
460141958
old
1
1163157884
1163157884
1956725890
1
356573597
356573597

以上测试结果得到的结果分析
上面的这个操作实际上就是迷惑所在,在这里单独把它列出来看一下
Integer a;
//此处实际上是java的自动装箱, 相当于调用了valueOf函数
// 实际上是new了一个Integer对象出来,或者将另一个Integer对象直接赋值(可以去看一下Integer的源码)
a = 123;
//基础类型的直接赋值
int b;
b = 123;
//与Integer类似,String类型也有常量池, 相当于缓存, 此处不是重点;
// 相当于new了一个对象出来, 或将另一个String对象直接赋值;
String c;
c = "abc"

普通对象操作对比
/**
* @author liwangcai E-mail:1252376504@qq.com
*/
public class StringTest {
    public static void changeUser(User user) {
        user = new User("zhang san", 24);
    }


    public static void main(String[] args) {
        User user = new User("li si", 25);
        System.out.println(user);
        changeUser(user);
        System.out.println(user);
    }

    @Data
    @AllArgsConstructor
    @ToString
    static class User {
        private String name;

        private Integer age;
        
    }
}

//执行结果, 可以发现对象的值并没有改变
StringTest.User(name=li si, age=25)
StringTest.User(name=li si, age=25)
Process finished with exit code 0

为什么new一个对象并不会改对象值?
主要是因为在Java中函数传递只有值传递 (不是本博客重点, 不展开描述)
如果想要改变String的值正确的操作姿势?
String对象是普通的Java对象, 不过是被final修饰了;
实际上String对象的值存在其内部的char value[]数组中,如果想要改变String的值应该区修改这个数组的数据;
不过上述数组是使用final修饰的, 所以如果使用jdk中的String类, 那么String的值是无法被修改的;
如果要改变String的值应该怎么做?
实现自己的String类型, 内部存储char[]数组不设置为final类型就可以了;
/**
* @author liwangcai E-mail:1252376504@qq.com
*/
public class MyStringTest {
    public static void main(String[] args) {
        MyString myString = new MyString(new char[]{'a', 'b'});
        System.out.println(myString);
        changeMyString(myString);
        System.out.println(myString);
    }

    private static void changeMyString(MyString myString) {
        myString.setValue(new char[]{'c', 'd'});
    }


    @ToString
    @AllArgsConstructor
    @Data
    static class MyString {
        char[] value;
    }
}

//测试结果
//可以发现值改变了
MyStringTest.MyString(value=[a, b])
MyStringTest.MyString(value=[c, d])

Process finished with exit code 0

总结
对于String,Integer类型 "=" 操作符号迷惑了我们, 实际上一开始提出的问题并不存在;
如果要修改同一个对象, 需要修改其内的成员;





上一篇:httpdns是个什么技术,有什么用
下一篇:总结几个简单好用的Python人脸识别算法
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|php中文网 | cnphp.com ( 赣ICP备2021002321号-2 )

GMT+8, 2024-11-22 10:06 , Processed in 0.837798 second(s), 42 queries , Gzip On.

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2020, Tencent Cloud.

申明:本站所有资源皆搜集自网络,相关版权归版权持有人所有,如有侵权,请电邮(fiorkn@foxmail.com)告之,本站会尽快删除。

快速回复 返回顶部 返回列表