0

先看一段代码:

public class JavaTest {
 
    public static void changeStr(String str){
        str="welcome";
    }
    public static void main(String[] args) {
 
        String str="1234";
        changeStr(str);
        System.out.println(str);
    }
}

String不是引用类型吗?为什么输出来的还是1234?

针对 @喵了个咪 的回答,贴段代码:

    public static void change(List list){
        list.add("welcome");
    }
    public static void main(String[] args) {
        String str="1234";
        List<String >list = new ArrayList<>();
        list.add(str);
        change(list);
        assert  list.size() == 2;
    }

查看全部 9 个回答

0

首先关于String,在java语言规范里面规定了除了8种基础类型外其他的都是引用类型。
关于造成题主的这个问题是String这个类是一个不可变的类,也就是说String构造的字符串在常量池中是不可以修改的。
假设在main方法里面的那个str的内存地址是0x01;
传入方法之后:形参指向内存地址 0x01 ,赋值语句执行后修改方法体的str的引用;但是从头到尾并没有修改main方法体中的引用,方法体的str只是拷贝了一份main中str,而修改是在拷贝这里再加上string的不可变,自然就不会改变了。

图片写错了,是执行赋值语句之后指向内存地址0x01的引用不存在了


稍微改下题主的代码:
测试代码:

public class String_Refer_Test {
    public static void ChangeStr(String str){
        str="WelcomeChangeStr";
    }
    public static void ChangeStr_1(AnotherClass ano){
        ano.str="WelcomeChangeStr_1";
    }
    public static void ChangeStr_2(String str){
        str="WelcomeChanger_2";
    }
    public static void main(String[] args){
        String str="1234";
        ChangeStr(str);
        System.out.println(str);
        AnotherClass anotherClass =new AnotherClass("1234");
        ChangeStr_1(anotherClass);
        System.out.println(anotherClass.str);
        ChangeStr_2(anotherClass.str);
        System.out.println(anotherClass.str);
    }
}
class AnotherClass{
    public  String str;
    public AnotherClass(String str){
        this.str=str;
    }
}

输出结果:
1234
WelcomeChangeStr_1
WelcomeChangeStr_1

可以发现第二个方法和第三个方法中,第二个方法改变了String的值,但是第三个方法却没有改变,是因为第二个方法提供了修改了自身的引用的语句,anotherclass存在方法区的str变量被修改了,但是anotherclass是可以变的类,所以修改在堆中分配的内存地址没改变,不过方法区的str引用变了而已

其次其实编译下ChangeStr()方法发现也就三句:

0 ldc #2 <WelcomeChangeStr>
2 astore_0
3 return

根本没有提供改变自身值的字节码,也就不可能修改本身的值

推荐答案

1

String 是不可变的,所以你在函数体内部做的改变不可能修改这个变量本身地址的值,而是在另一个地址新建了一个String 类型的变量,而你获取不到这个新建的变量的地址,函数执行完毕这个变量就可能会被回收。