java String 参数传递 按值与地址

           今天看erlang,看到一个最基本的问题,就是方法调用或函数调用时,参数传递的方式,大家都知道在Java中,基本类型是通过按值传递的方式,来实现参数传递,而对象类型则是通过按引用地址传递的,但是这个里面有一个Java里面被作为基本类型的对象,就是string,在其他语言中,基本上是没有String基本类型的,比如c++,erlang等,所以Java中,String这个对象比较特殊,他传递参数时候也比较特殊。

        下面一个例子:

       

public class StringTest {

	public static void main(String[] args) {
		String value = "Hello World";
		String newValue = new String("Hello World2");
		System.out.println("change before value is:"+value);
		System.out.println("change before new value is:"+newValue);
		change(value);
		change(newValue);
		System.out.println("====================================");
		System.out.println("change after value is:"+value);
		System.out.println("change after new value is:"+newValue);
	}
	
	
	public static void change(String value){
		value = value+" change";
	}
}

      上面的程序运行结果为:

         change before value is:Hello World

         change before new value is:value

         ====================================

        change after value is:Hello World

        change after new value is:value

 

     从上面的运行结果可以看出来,不管string是直接通过 “=”赋值,或者是通过new的方式赋值,方法调用之后,他的值都没有改变,也就是说,不管这个string是在常量池中或者堆内存中,他的值都不会改变,这样string的参数传递就和其他的基本类型不一样了,虽然Java中string类型是基本类型。

    为什么会有上面的结果呢,网上有人说,string的值是在常量池中,所以不会改变,但是我们用new的方式,他也是没有改变呢。其实解释这个原因很简单,简单到看一下源码就行了。以下是string的源码:

       

public final class String
    implements java.io.Serializable, Comparable, CharSequence
{
    /** The value is used for character storage. */
    private final char value[];

    /** The offset is the first index of the storage that is used. */
    private final int offset;

    /** The count is the number of characters in the String. */
    private final int count;

    /** Cache the hash code for the string */
    private int hash; // Default to 0

    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    private static final long serialVersionUID = -6849794470754667710L;

    /**
     * Class String is special cased within the Serialization Stream Protocol.
     *
     * A String instance is written initially into an ObjectOutputStream in the
     * following format:
     * 
     *      TC_STRING (utf String)
     * 
* The String is written by method DataOutput.writeUTF. * A new handle is generated to refer to all future references to the * string instance within the stream. */ private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0]; /** * Initializes a newly created {@code String} object so that it represents * an empty character sequence. Note that use of this constructor is * unnecessary since Strings are immutable. */ public String() { this.offset = 0; this.count = 0; this.value = new char[0]; }

    从源码中可以知道,string的实现是通过char[] 数组的形式,之所以String对象不管怎么整都不会改变是因为,String对象是一个final对象,就是不变的对象,里面的属性也是不变的对象,所以不管你怎么弄他都是不变的,这个就是String基本类型和其他基本类型不一样的地方,所以网上说各种原因的,看一下源码就知道为什么了。

   通过操作符 “+”,来实现string对象的相加,这个就是有点c++重的操作符重载的意思了,编译的时候,String的相加会有优化,这个优化就是如果常量池中有同样的string就会给他赋为这个变量的地址,如果没有就会通过new的方式创建一个char[],还有string中的所有有关两个string的操作比如concat这种方法,都是通过new String的方式返回新的String对象。

你可能感兴趣的:(java,闲谈一二)