值传递String

本文深入探讨Java中的值传递机制,包括基本类型与引用类型的传递差异,以及String对象作为特殊情况的处理方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载:http://www.cnblogs.com/myCodingSky/p/3902284.html

值传递:传递的是实际参数的一个副本,这个值可能是基本类型,也可能是引用类型的地址.

引用传递:传递的是实际参数的地址的一个副本.

在java中,只有值传递.

一.值传递

1.基本类型

复制代码
 1 public class ValueTest {
 2     
 3     public static void main(String[] args) {
 4         int a = 10;
 5         changeVal(a);
 6         System.out.println(a);
 7     }
 8     
 9     public static void changeVal(int a){
10         a += 10;
11     }
12     
13 }
复制代码

上面的demo输出的是10,而不是20。为什么?

①.程序运行时,main方法先入栈,然后给变量a分配内存。

②.当运行到changeVal(a);时,changeVal()方法入栈。当方法入栈时,会给局部变量和形参变量(a)分配内存.

   即在changeVal方法栈里面,也有一个名为a,值为10的变量。

③.由于a+=10;是在changeVal方法栈里面运行的,所以只会改变changeVal方法栈里面的a值,而不会改变main方法栈里面的a值。如下图

 

2.引用类型

引用类型也是值传递,不过这个"值"指的是对象的内存地址.

复制代码
 1 public class ValueTest {
 2     
 3     public static void main(String[] args) {
 4         StringBuilder builder = new StringBuilder("hello");
 5         changeVal(builder);
 6         System.out.println(builder);
 7     }
 8     
 9     public static void changeVal(StringBuilder builder){
10         builder.append(" world");
11     }
12     
13 }
复制代码

输出是hello world,可见builder的值是改变了.

与基本类型不一样,主要是StringBuilder是引用类型。因此new StringBuilder("hello")的内存是分配在堆区。而在栈区的变量(builder)只保存一个地址(假设为0x345),如下图:

因此,main和changeVal两个方法栈的builder变量都指向了同一块内存。故当changVal方法中改变builder的值,main中的builder也会变化。

 

3."特殊的"String

复制代码
 1 public class ValueTest {
 2     
 3     public static void main(String[] args) {
 4         String str = "hello";
 5         changeVal(str);
 6         System.out.println(str);
 7     }
 8     
 9     public static void changeVal(String str){
10         str+=" world";
11     }
12     
13 }
复制代码

上面的demo输出的是:hello,而不是hello world。str记录了对象的地址,那么str的值应该也被改变了才对?

这跟String的"特性"有关,String会被存放在字符串常量池,而且String是不可被改变的(final).

①.在第10行设个断点,当执行到这行的时候,由上面的分析可知,main()和changeVal()方法中的str都指向了常量池中的"hello"字符串。

②.执行str+=" world"时,由于String是不可变的,所以不可能直接在"hello"上做修改。这时会在常量池中新增一个"hello world"的字符串,并将地址传给changeVal()方法栈中的str.

③.因此changeVal()方法中的str指向了新增的"hello world"字符串,而main方法中的str还是指向原来的"hello"。所以输出"hello".

 

### Java 中 String 值传递机制与深拷贝、浅拷贝的关系 #### 1. **值传递的概念** 在 Java 中,无论是基本数据类型还是引用数据类型,参数传递本质上都是按值传递(pass-by-value)。对于基本数据类型,传入的是实际的数值副本;而对于引用数据类型,传入的是对象引用的一个副本[^2]。这意味着如果方法内部修改了该引用所指向的对象状态,则外部可见这一变化,但如果重新给这个局部变量赋值另一个对象,则不会影响原始引用。 #### 2. **String 的不可变性与值传递** 由于 `String` 是不可变类(immutable class),一旦创建就不能更改其内容。每次对字符串执行操作时实际上都会返回一个新的字符串实例[^1]。因此,在涉及 `String` 参数的方法调用过程中,尽管也是按照值传递的原则来进行处理,但由于 `String` 自身的设计特性——即它的 final 属性决定了无法对其内部字符数组做任何改动,所以无论是在形式上看起来像是“值传递”,还是从效果上看类似于“深拷贝”的行为,其实质均源于 `String` 的只读性质[^1]。 具体来说: - 当我们将一个 `String` 对象作为参数传递给某个函数时,实际上是把这个字符串对象的引用值复制了一份交给函数内的局部变量; - 函数体内对该局部变量所做的任何变更都不会反映回原来的那个 `String` 实例上去,因为不可能改变原有 `String` 的内容,只能基于它构建全新的其他 `String` 实例。 #### 3. **关于 String 在浅拷贝中的表现** 假设有一个包含非基础数据成员(比如 `String` 字段)的类实现了 `Cloneable` 接口并覆盖了 `clone()` 方法以提供浅拷贝能力。在这种情况下,当调用此类实例的 `clone()` 方法生成的新对象中,那些属于 `String` 类型的数据项虽然表面上看似乎也经历了一次所谓的“复制”动作,但实际上并没有真正意义上分配额外的空间去保存另一份完全独立的内容副本。原因就在于前面提到过的 `String` 不可变得特征使得即便两个不同的对象持有相同的字符串值,它们也可以放心大胆地共享底层表示而不用担心彼此干扰。 #### 4. **序列化实现深拷贝的应用场景** 为了达到真正的深拷贝目的,可以通过序列化的方式来完成整个对象图谱的彻底分离。这种方式不需要逐层手动指定哪些部分需要参与克隆过程,也不强制要求每一个组成单元都要单独具备 `Cloneable` 标记或者定义自己的 `clone()` 行为逻辑。只要目标类别及其所有子组件都支持标准的 Java 序列化协议即可自动获得一份完整的备份记录。这种方法尤其适用于像嵌套层次较为复杂的结构体当中包含了众多相互关联却又各自独立运作的部分的情形之下。 ```java public static void main(String[] args) throws Exception{ Person person = new Person(); person.setName(new String("John")); // 使用ObjectOutputStream/ObjectInputStream进行序列化反序列化的深拷贝方式 ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(person); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); Person clonedPerson = (Person)ois.readObject(); System.out.println(clonedPerson.getName() == person.getName()); // false, different objects } class Person implements Serializable { private transient String name; public void setName(String name){ this.name = name; } public String getName(){ return name; } } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值