第一次的拷贝指向t1,将t1 的temp 修改为456 ,t1.temp 便为 456了
第二次的拷贝就是单纯的常量123,在方法内修改t值,相当于重新new了一个字符串456,并不影响main方法中的123。

解决方案 »

  1.   

    那你想那个构造函数为什么写 成this.id=id;如果参数类型是原始类型,那么传过来的就是这个参数的一个副本,也就是这个原始参数的值,这个跟之前所谈的传值是一样的。如果在函数中改变了副本的 值不会改变原始的值.
        如果参数类型是引用类型,那么传过来的就是这个引用参数的副本,这个副本存放的是参数的地址。如果在函数中没有改变这个副本的地址,而是改变了地址中的 值,那么在函数内的改变会影响到传入的参数。如果在函数中改变了副本的地址,如new一个,那么副本就指向了一个新的地址,此时传入的参数还是指向原来的 地址,所以不会改变参数的值。你第一个是传一个对象的引用过去。
    还把这个对象的值改变了。
    第二个,String 自己new了个。
    只在方法内有效。比如下面代码:
    public class Test5 {    public static void main(String[] args) {        List<People> list = new ArrayList<People>();        People people = new People();        people.id = 1;
            list.add(people);        people.id = 2;
            list.add(people);        for (People p : list) {
                System.out.println(p.id);
            }
        }}class People {
        public int id;
    }
    你觉得会输出1,2 吗?
      

  2.   

    因为String 是不可变类。如果要想是可变的,那么就用可以使用StringBuffer。
      

  3.   

    String类里面的value
        private final char value[];public final class String
        implements java.io.Serializable, Comparable<String>, CharSequence {
        /** The value is used for character storage. */
        private final char value[];
    StringBuffer类里面的value public final class StringBuffer
        extends AbstractStringBuilder
        implements java.io.Serializable, CharSequence
    {
    ////////////////////////
    abstract class AbstractStringBuilder implements Appendable, CharSequence {
        /**
         * The value is used for character storage.
         */
        char[] value;
      

  4.   

    这是一个很基础但涉及知识面非常广的问题。这里面有三个概念:
    1.java的方法传递方式是值传递的。
    这句话什么含义呢?它是指针对基本类型boolean/byte/char/short/int/long/float/double则传递字面值,而针对其他Object类型,则传递该对象的引用的地址值(这里很容易让人以为是引用传递)。同时这还涉及到虚拟机对方法调用的局部变量表的使用机制,可以简单理解为,新开辟了一个内存区域用来保存方法中传入的参数值。基本类型的内存区域存着字面值,而对象存的是引用指向的地址值。2.String是不可变类。
    不可变类是指该类所有与状态相关的成员变量,都是声明为final型的,如楼上所描述,String里面用于描绘字符串值的private final char value[];是final的,即他有且只有在初始化始被赋值。3.方法区的常量池和堆区的对象变量概念。
    诸如String s = "123";这样的代码,实际上是java提供的语法糖,他表示的真实含义是String s = new String("123").intern();
    这句代码什么意思呢?他表示,先去方法区的常量池中搜索有没有字符串常量"123",如果有,则直接返回"123"在常量池中的引用地址;如果没有,则在方法区中扩展常量池增加"123"字符串的对象,并返回引用地址。
    而String ss = new String("123");则是显式的在堆区新建对象,返回引用。如下代码 String s = new String("123").intern();
    String ss = new String("123");
    String sss = "123";
    System.out.println(s==ss);
    System.out.println(s==sss);
    其中==操作符表示比较引用地址。自己尝试下结果。
    明确了以上三个概念。解释你的两段代码就很容易了。 public static void fun(Test t)
        {
            t.temp = "456";
        }
    这里的"456"在常量池中创建新的对象并返回引用,为t.temp赋了新的引用地址,指向常量区"456"。public static void main( String args[])
        {
            String s = "123";
            System.out.println(s);
            fun(s);
            System.out.println(s);
        }
        public static void fun(String t)
        {
            t = "456";
        }其中fun方法中的参数String t的生命周期只在这一次方法调用。方法载入时,传参将s指向的地址值赋给了t。
    fun方法同样在常量池中创建新的对象(称为c)并返回引用,但将引用地址赋给了我们这里的String t,也就是说,t的指向地址从s指向的地址值变为了c所指向的地址值。这并不影响s。所以发生了,你看到的现在这个现象。如果对第二段代码还不是很理解,可以把你第一段代码稍加改造,就能理解的非常透彻。
    class Test
    {
        String temp = "123";
    }
    public class MyClass
    {
        public static void main( String args[])
        {
            Test t1 = new Test();
            System.out.println(t1.temp);
            fun(t1);
            System.out.println(t1.temp);
        }
        public static void fun(Test t)
        {
            t. = new Test();      //仅增加这一行
            t.temp = "456";
        }
     
    }如此,看看打印的结果,理解了么?
      

  5.   

    String是一个特殊的引用类型,String是final class,不可被继承,String一旦赋值不可被改变,查看源码可知String里维护的是一个final char[],改变String的值其实是重新创建了一个String内存块,然后将原来的String对象的引用地址指向新创建的地址。
    相信楼主明白了。
      

  6.   

    java当中值的引用传递问题,你好好看一下这方面的基础知识就可以的。。
      

  7.   


    多谢啊,明白了。你说有个常量区我就明白了,原先看书上说,String不可变可是第一个明明是改变了,现在才发现还是没变,只是在常量区新建了空间,堆区并没改变