新手String类

zcdabing 2014-06-10 10:19:58

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.temp = "456";
}

}

结果
123
456


public class MyClass
{
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";
}

}

结果
123
123


求解释这是为什么,为什么。。。。。
...全文
280 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
xlight2023 2014-06-11
  • 打赏
  • 举报
回复
String是一个特殊的引用类型,String是final class,不可被继承,String一旦赋值不可被改变,查看源码可知String里维护的是一个final char[],改变String的值其实是重新创建了一个String内存块,然后将原来的String对象的引用地址指向新创建的地址。 相信楼主明白了。
Yoara 2014-06-11
  • 打赏
  • 举报
回复
这是一个很基础但涉及知识面非常广的问题。 这里面有三个概念: 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";
    }
 
}
如此,看看打印的结果,理解了么?
Mime_mi 2014-06-11
  • 打赏
  • 举报
回复
第一个例子是引用传递,第二个例子是值传递。
lodamemory 2014-06-11
  • 打赏
  • 举报
回复
值传递和引用传递
  • 打赏
  • 举报
回复
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;
  • 打赏
  • 举报
回复
因为String 是不可变类。如果要想是可变的,那么就用可以使用StringBuffer。
zcdabing 2014-06-11
  • 打赏
  • 举报
回复
引用 1 楼 leizh007 的回复:
因为java函数是值传递
弄个这么蹩脚的称谓,值传递还叫引用,叫学C++过来的情何以堪
zcdabing 2014-06-11
  • 打赏
  • 举报
回复
引用 10 楼 Yoara 的回复:
这是一个很基础但涉及知识面非常广的问题。 这里面有三个概念: 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";
    }
 
}
如此,看看打印的结果,理解了么?
多谢啊,明白了。你说有个常量区我就明白了,原先看书上说,String不可变可是第一个明明是改变了,现在才发现还是没变,只是在常量区新建了空间,堆区并没改变
Mr-稻帅 2014-06-11
  • 打赏
  • 举报
回复
java当中值的引用传递问题,你好好看一下这方面的基础知识就可以的。。
2.wa 2014-06-10
  • 打赏
  • 举报
回复
那你想那个构造函数为什么写 成
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 吗?
_一场游戏 2014-06-10
  • 打赏
  • 举报
回复
自己画个图应该就明白了
姜小白- 2014-06-10
  • 打赏
  • 举报
回复
第一次的拷贝指向t1,将t1 的temp 修改为456 ,t1.temp 便为 456了 第二次的拷贝就是单纯的常量123,在方法内修改t值,相当于重新new了一个字符串456,并不影响main方法中的123。
leizh007 2014-06-10
  • 打赏
  • 举报
回复
因为java函数是值传递

62,615

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧