String类型作为方法参数时的相关问题

1,806 阅读4分钟

这是我参与更文挑战的第2天,活动详情查看: 更文挑战

在昨天做PTA的java作业时发现了一道题目,如下图:

image.png 这一题最开始的时候我觉得是选c的,输出为“AB.AB"。我想的是String作为引用数据类型,当做方法的参数时,应该是以引用传递的形式。所以对String类型的x和y进行操作时,会改变真实的值。

然而,实际运行的结果并不是我想的那样......

String类型

首先,String类型代表字符串。是一个final类,代表不可变的字符序列。字符串是常量,用双引号引起来表示。值在创建后不能更改。String对象的字符串内容是存储在一个字符数组value[]中的。

String的实例化方式

字面量定义的方式

String str=“hello”;

首先,字面量定义的数据在方法区中的字符串常量池中, 即相同字符串共用一个地址值。作为探究String在方法的参数的传递方式,先尝试着用字面量定义的Sring类型变量作为参数传递

public class Main{
    public static void main(String args[ ]){
        String a ="A";
        String b = "B";
        mb_operate(a,b);
        System.out.println(a + "." + b);
    }
    static void mb_operate(String x,String y){
        x=x.concat(y);
        y=x;
    }
}

image.png 通过答案可以知道,字面量定义的String类型作为方法参数时是以值传递的形式。

通过构造器

String s1=new String();

new构造器声明的数据,存储在堆空间中,这个时候声明两个相同字符串的变量,在堆空间里会开辟出两个空间,地址也不相同,然而这种情况正是题目中的情况,通过实践,可以知道构造器定义的String类型作为方法参数时也是以值传递的形式。

public class Main{
    public static void main(String args[ ]){
        String a = new String("A");
        String b = new String("B");
        mb_operate(a,b);
        System.out.println(a + "." + b);
    }
    static void mb_operate(String x,String y){
        x=x.concat(y);
        y=x;
    }
}

image.png

综上,String类型虽然是引用数据类型,但是其变量作为方法的参数时,与基本数据类型一样是以值传递的形式。

这里,我在网上搜到了一遍前辈的博客,大佬通过分析String构造器的源码,解释了String这种传递方式的特性缘由,大致意思是,String的底层是由char[]实现的,所以本质上是一种类似于Integer一样的包装类...下面的是他的原文:

String就相当于是char[]的包装类。包装类的特质之一就是在对其值进行操作时会体现出其对应的基本类型的性质。在参数传递时,包装类就是如此体现的。所以,对于String在这种情况下的展现结果的解释就自然而然得出了。同样的,Integer、Float等这些包装类和String在这种情况下的表现是相同的。

这里附上大佬博客的传送门

那么有没有办法让String类型的变量以引用传递的形式作为参数呢?

方法一: 使用StringBuffer可变字符串类型

public class Main{
    public static void main(String args[ ]){
        StringBuffer a = new StringBuffer("A");
        StringBuffer b = new StringBuffer("B");
        mb_operate(a,b);
        System.out.println(a + "." + b);
    }
    static void mb_operate(StringBuffer x,StringBuffer y){
        x=x.append(y);
        y=x;
        System.out.println(y);
    }
}

image.png

在这里注意的是StringBuffer中的增加为append,而y=x时,输出为AB.B,对数据的赋值操作没有影响到实际值。而对方法中的y使用StringBuffer中的方法时,可以发现b的值也受到了影响

public class Main{
    public static void main(String args[ ]){
        StringBuffer a = new StringBuffer("A");
        StringBuffer b = new StringBuffer("B");
        mb_operate(a,b);
        System.out.println(a + "." + b);
    }
    static void mb_operate(StringBuffer x,StringBuffer y){
        x.append(y);
        y.insert(1, "BBB");
    }
}

image.png

我猜测可能是因为StringBuffer中的方法时直接对引用进行操作,而一般的赋值操作却不影响值的变化或者地址的改变...

//更新2021/6/2 上午发的博客,下午继续做题的时候又发现了这种题型......

image.png

这一题可以说是更加直观的反映出了String类型的参数传递的问题,所以补充一下,目前我所了解的让String类型的变量实现以引用传递的形式作为参数相同作用的话,有两个办法:一是直接用StringBuffer类型,二是将String类型存入String数组中再以数组作为参数,从而实现引用传递的效果。

方法二:使用String[]数组

public class Main {
    public static void main(String[] args) {
        String a = new String("A");
        String b = new String("B");
        String[] s=new String[2];
        s[0] = a;
        s[1] = b;
        mb_operate(s);
        System.out.println(s[0] + "." + s[1]);
    }
    static void mb_operate(String[]s){
        s[0]=s[0].concat(s[1]);
        s[1]=s[0];
    }
}

image.png

有关更多的String的参数传递问题,在今后的学习中会不断去探究,会不断改善这篇文章的错误补充这篇文章的不足。