Java String、StringBuffer参数传递

java数据类型与参数传递  

2011-06-05 17:02:39|  分类: Java |  标签: |字号 订阅

在Java中,引用类型的变量非常类似于C/C++的指针。
基本类型与引用类型:
基本类型
java中int,float等属于基本类型,创建时存储于栈中。

引用类型

引用类型的引用存储于栈中,而对象则是存储与堆中。下面进行详细的阐述:

假设我们在函数中写了如下这个简单的语句:

StringBuffer str = new StringBuffer("Hello world"); 

别看这个语句简单,其实包含了如下三个步骤:

首先,new StringBuffer("Hello world")在堆里申请了一块内存,把要创建的StringBuffer对象放进去。

其次,StringBuffer str声明了一个指针。这个指针本身是存储在栈上的(因为语句写在函数中),可以用来指向某个StringBuffer类型的对象。或者换一种说法,这个指针可以用来保存某个StringBuffer对象的地址。

最后,当中这个等于号(赋值符号)把两者关联起来,也就是把刚申请的那一块内存的地址保存为栈中的str变量的值。

◆引用对象之间的赋值、判相等

通过上述的图解,大伙儿应该明白指针变量和该指针变量指向的对象是一个什么关系了吧。

还是接着刚才的例子,再来看赋值的问题。对于如下语句:

StringBuffer str2 = str;

这个赋值语句是啥意思?实际上就是把str的地址复制给str2,记住,是地址的复制,StringBuffer对象本身并没有复制。所以两个指针指向的是同一块堆区域。

再搞一张示意图,如下:

明白了赋值,判断相等的问题(就是==操作符)也就简单了。当我们写如下语句“if(str2 == str)”时,只是判断两个指针的值(也就是对象的地址)是否相等,并不是判断被指向的对象是否内容相同。

实际上两个指针的值相同,则肯定是指向同一个对象(所以对象内容必定相同)。但是两个内容相同的对象,它们的地址可能不一样(比如克隆出来的多个对象之间,地址就不同)。

参数传递:

这里我将会详细的介绍java中参数调用的时候,参数是如何传递的。这对于解决很多bt的面试题和平时的编程会有很大的帮助。

参数传递机制
call-by-value 值调用:将实际参数的内容拷贝到被调用方法

call-by-reference 引用调用:将实际参数的地址作为形式参数的值被传递到被调用方法。

(注意:一定要深刻理解上面的两种参数传递机制的真正含义。)
在java中,对于不管是基本类型还是引用类型,采用的都是值调用
存在一个方法method(RefParameter1,RefParameter2)。
此时,调用此方法,method(parameter1,parameter2);
执行的具体操作是:对实参parameter1,parameter2,采用值调用,即将实际参数的内容(对基本类型,会将其值copy;对于引用类型,其值不是堆中的某个对象,而是对象的地址,那才是实参的内容)拷贝到被调用方法的栈中。然后方法method根据传过来的参数进行方法的执行。

举例如下:
public static void change(String a){
        a = "changed" ;
    }
        public static void changeSB(StringBuffer a){
        a.append( "changed" );
    }

public static void changeSB2(StringBuffer a){
StringBuffer b= new  StringBuffer(“b”);       
a=b;
a.append( "changed" );
    }
   
    public static void changeInt(int a){
        int b=100;
        a=b;
    }

        int a=10;
        Test.changeInt(a);
        System.out.println(a);      //输出10
(这个应该容易理解。把a的内容,即10copy到方法中,无论如何改变都跟a无关。)
        String aa="111";
        String bb=new String("111");
        Test.change(bb);
        System.out.println(bb);      //输出为111
( 不管是采用aa创建的方式还是bb结果都一样。把对bb在堆中的对象的引用复制到change方法中,因为string为不可变量,a = "changed" ;会创建一个新的变量。对bb对象没有任何影响。)
        StringBuffer cc= new StringBuffer("111") ;
        Test.changeSB(cc);
        System.out.println(cc);     //输出为111changed
(这个是一个类对象的典型的例子。方法调用时会把参数cc的内容(StringBuffer("111") 对象的地址)复制到changeSB方法中,这时候方法中形参便也指向了对象StringBuffer("111") ,因此对他的修改会影响cc。)
StringBuffer dd= new StringBuffer("111") ;
        Test.changeSB2(dd);
        System.out.println(dd);     //输出为111
(这个理由很简单。方法changeSB2中,对引用a进行了重定向,指向了b。因此不会影响dd引用指向的内容)
### 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、付费专栏及课程。

余额充值