Java中String作参数传递问题

本文详细探讨了Java中使用String作为参数时的行为,解释了为何改变String参数值在函数内部不会影响外部调用者看到的原始值。通过分析参数传递机制,揭示了Java中String对象的副本特性及其对程序行为的影响。

大家都知道参数的传递有传值和传引用(C++传址),String在Java里作参数也算是传引用,但是有一些问题让人费解,先看个简单的程序;

public class StringParameter {
	public static void test(String str){
		str="world";// 2
	}
	public static void main(String[] args) {
		String str="hello";// 1
		test(str);
		System.out.println(str);
	}
}

输出结果:hello;

也就是test函数并没有改变str的值,按理说String也是引用,那为什么它作为参数时无法改变它的值呢?

关于这个问题很多人都给出了自己的解释,但是很多的解释都不是很令人满意(也是我能力有限,看不懂大牛们写的东西);

以下是我看了一些资料所理解的,如果有什么不妥的还望多多指点:

1.首先要明白java中参数的传递都是传递的副本,就是说将参数复制一份,将副本传进去,无论传值还是引用都会复制,在执行main函数第1句话时情况如下图:


str指向常量池中的hello,将str作参数传递到函数时情况如下,


执行test函数第2句话时情况如下,


既是在执行str="world"语句时,是把str的副本指向了新的字符串,因为String类是final类,无法改变长度的,所以当test函数

执行结束时str副本消亡,而str的所指向的字符串没有改变,最后输出为hello.



### Java 参数传递机制 在Java中,参数传递主要分为按值调用(Pass by Value)和按引用调用(Pass by Reference),但实际上Java只支持按值调用。对于基本数据类型的参数传递,传入的是实际数值的一个副本;而对于引用数据类型,则是传递对象引用的副本。 #### 基本数据类型传递 当函数接收一个基本数据类型为参数时,会创建该原始值的一份拷贝并将其赋给形参。因此,在方法内部对该参数所做的任何修改都不会影响到外部的实际变量[^1]。 ```java public void changeValue(int value){ value = 10; } int num = 5; changeValue(num); System.out.println(num); // 输出仍然是5,因为只是改变了value这个局部变量 ``` #### 引用数据类型传递 对于像`StringBuffer`, `ArrayList`这样的复杂对象或是自定义类实例来说,情况有所不同。虽然形式上还是按照值来传递,但是这里所谓的“值”是指向堆内存中某个特定位置的对象引用地址。所以如果我们在方法体内通过此引用来改变对象的状态(比如增加列表项或更改字符串缓冲区的内容),这些变化是可以被外界感知到的。 然而需要注意的是,即使能够操同一个对象状态,也无法让两个不同的引用指向完全新的不同对象: ```java public static void tryChangeObjectReference(StringBuilder sbuilder) { sbuilder.append(" world"); } StringBuilder strBldr = new StringBuilder("hello "); tryChangeObjectReference(strBldr); System.out.println(strBldr.toString()); // hello world // 下面的例子则不会成功替换strBldr所指代的对象本身 public static void failToReplaceObjectReference(StringBuilder paramSb) { paramSb = new StringBuilder("new content"); } failToReplaceObjectReference(strBldr); System.out.println(strBldr.toString()); // 还是原来的 "hello world" ``` ### String 类型详解 `String` 是一种特殊的引用类型,在Java里它实际上是不可变(immutable)的字符序列容器。一旦创建了一个`String`对象之后就不能再对其内容做任何形式上的修改了——每次涉及对原字符串的操都会返回一个新的`String`对象而不是直接改动现有的那个。 这意味着当你试图在一个方法内修改传入的`String`参数时,实际上是在构建另一个全新的字符串而非更新原有的那一个。这同样适用于其他所有尝试去变更已存在字符串的行为,无论是追加、截取还是大小写转换等等[^3]。 ```java public static void appendString(String s) { s += " extra"; } String originalStr = "initial "; appendString(originalStr ); System.out.println(originalStr ); // initial ,并没有受到影响 ``` 尽管如此,由于`String`常量池的存在使得相同字面量会被共享存储空间从而节省资源消耗,并且编译期优化也可能导致某些看似会产生新对象的地方其实并未真正发生分配动
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值