首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 .NET Java 游戏 视频 人才 外包 培训 数据库 书店 程序员
中国软件网
欢迎您:游客 | 登录 注册 帮助
  • string三问:Java中如何给字符串分配内存
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • zrd
    • 等级:
    • 可用分等级:
    • 总技术专家分:
    • 总技术专家分排名:
    • 揭帖率:
    发表于:2008-08-20 18:05:38 楼主
    今天研究了一下Java中字符串内存分配的问题,但仍然没有弄清楚,希望有高手指教一下

    String是一个特殊的包装类数据。可以用:
    String str = new String("abc");
    String str = "abc";
    两种的形式来创建,第一种是用new()来新建对象的,它会在存放于堆中。每调用一次就会创建一个新的对象。而第二种是先在栈中创建一个对String类的对象引用

    变量str,然后查找栈中有没有存放"abc",如果没有,则将"abc"存放进栈,并令str指向”abc”,如果已经有”abc” 则直接令str指向“abc”。

      比较类里面的数值是否相等时,用equals()方法;当测试两个包装类的引用是否指向同一个对象时,用==,下面用例子说明上面的理论。
    代码片段(一)
            String str1 = "abc";
            String str2 = "abc";
            System.out.println(str1==str2); //true 这里
            System.out.println(str1.equals(str2)); //true too.
    可以看出str1和str2是指向同一个对象的。
    代码片段(二)
            String str1 =new String ("abc");
            String str2 =new String ("abc");
            System.out.println(str1.equals(str2)); //true 毫无疑问,这里证明他们是堆中的两个对象。
            System.out.println(str1==str2); // false
    用new的方式是生成不同的对象。每一次生成一个。
    因此用第二种方式创建多个”abc”字符串,在内存中其实只存在一个对象而已. 这种写法有利与节省内存空间. 同时它可以在一定程度上提高程序的运行速度,因

    为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。而对于String str = new String("abc");的代码,则一概在堆中创建新对象,而不管其字符

    串值是否相等,是否有必要创建新对象,从而加重了程序的负担。

    以上转自网络

    疑问1:
    String str1 = "abc";这样创建的 字符串 str1和str2,适用 ==可以理解为指向栈中的同一块内存,适用equals()方法又可以理解为堆中的对象。那么它到底是

    在堆中的呢,还是在栈中的呢。难道这就是他的特殊之处吗?
    代码片段(三)
            Integer str1 =  new Integer(12345);
            Integer str2 =  new Integer(12345);
            if(str1.equals(str2))
              System.out.println("equals right"); //这里输出正确
            if(str1==str2)
              System.out.println("== right");    //这里没有输出

    当测试两个包装类的引用是否指向同一个对象时,应用equals()方法而非==,可见包装类创建的是堆中的对象。

    疑问2:
    代码片段(四)
              String str1 =  "string";
              String str3 =  "str";
              String str4 = "ing";
              String str2 = str3+str4;
            if(str1.equals(str2))
                System.out.println("equals right"); //这里输出正确
              if(str1==str2)
                System.out.println("== right");    //这里没有输出
    由此可见,(一)中虽然定义了两个字符串str1 and str2,但实际上在栈中只有一个"abc",而str1 和 str2两个引用变量同时指向这个字符串,所以可以用“==”

    来判断是否相等。而(四)中的str1和str2并不是指向共同的字符串,所以不能用“==”来判断。那么为什么可以用equals()方法判断呢,如果理解为String

    str1 ="string"; 就是在堆里面创建的,就可以了,但是堆里的对象又不能用“==”判断,所以还是解释不清楚。

    疑问3:
    代码片段(五)
              String str1 = new String( "string");
              String str3 =  "str";
              String str4 = "ing";
              String str2 = str3+str4;
            if(str1.equals(str2))
                System.out.println("equals right"); //这里输出正确
              if(str1==str2)
                System.out.println("== right");    //这里没有输出

        两种不同方式创建的字符串竟然存在着某种联系!看来问题越来越复杂了!

    补充一个问题:
    equals方法,默认实现就是用"=="来直接比较内存地址:
    Object.equals:
    public boolean equals(Object obj) {
    return (this == obj);
        }
    那么str1==str2 与str1.equals(str2) 的不同之处又是什么呢?

    请高手指教!
    120  修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • lixiurui
    • 等级:
    • 可用分等级:
    • 总技术专家分:
    • 总技术专家分排名:
    发表于:2008-08-20 18:34:391楼 得分:0
    1.==表示引用自同一对象,equals()表示值相等。
    String str1 = "abc";引用的对象在栈(或者叫String池)中。
    String str1 =new String ("abc"); 引用的对象在内存/堆中。

    2.String str1 =  "string";在栈中
      String str3 =  "str";在栈中
      String str4 = "ing";在栈中
      String str2 = str3+str4; 在堆中,因为+号的作用是返回另外一个新建的String对象,而不是在栈中找string这个值。如果是String str2 = "str"+"ing";那最后的结果就在栈中。str1==str2为true。

    3.当然有联系了,值相同啊。

    4.String的equals方法是重写过的,和Object的不一样。下面是jdk1.6里的源码
    public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = count;
        if (n == anotherString.count) {
    char v1[] = value;
    char v2[] = anotherString.value;
    int i = offset;
    int j = anotherString.offset;
    while (n-- != 0) {
        if (v1[i++] != v2[j++])
    return false;
    }
    return true;
        }
    }
    return false;
        }
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • bianmazi
    • 等级:
    • 可用分等级:
    • 总技术专家分:
    • 总技术专家分排名:
    发表于:2008-08-20 19:27:072楼 得分:0
    csdn类似的帖子:http://topic.csdn.net/t/20021025/11/1124320.html

    equals 方法(是String类从它的超类Object中继承的)被用来检测两个对象是否相等,即两个对象的内容是否相等。
    ==用于比较引用和比较基本数据类型时具有不同的功能:
    比较基本数据类型,如果两个值相同,则结果为true
    而在比较引用时,如果引用指向内存中的同一对象,结果为true
    Eg:s1 = new String("sony"); //创建的是字符串对象
    s1.equals("sony"); //返回
    trues1 == "sony" //返回false
    //如果
    s1 = "sony";
    s1 == "sony" //返回true

    很简单的事情嘛.
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • hanzsim
    • 等级:
    • 可用分等级:
    • 总技术专家分:
    • 总技术专家分排名:
    发表于:2008-08-21 10:53:003楼 得分:0
    你问的问题根本是在常量字符串和构造字符串的存储问题。解决了这个问题,你的三个疑问都解决了。
    关键在哪?new关键字!
    String str1="abc"这里没有new,那么str1是引用已经存在的字符串对象,引用的就是已存放好的"abc",java把字符串常量也使用String类处理的,这是自动的,所以,你用这种方式创建10000个引用,引用的还是同一个,就是原来存储好的"abc",就像下面的代码一样:
    String strObj=new String("abc");
    String str1=strObj;
    String str2=strObj;
    ......
    只不过,字符串常量是自动创建的,这几行代码是手动创建的,仅仅是对对象的引用而已。
    而明确使用new 关键字则是要新建对象,那么每new一次,对象必然是新的一个,所以,equals(比较内容)是相同的,而==不同,不是同一对象!
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • zrd
    • 等级:
    • 可用分等级:
    • 总技术专家分:
    • 总技术专家分排名:
    发表于:2008-08-26 18:39:304楼 得分:0
    的确,最让我不解的是字符串在内存中是如何存储的。

    String s1 = "string";
    String s2 = "string";
    if(s1==s2)
      System.out.println("1 true");
    if (s1.equals(s2))
      System.out.println("2 true");

    两个语句都输出,这说明s1和s2是两个存储在栈(stack)中的引用,而且他们指向同一个字符串,对吗.那么这个字符串是对象还是常量,是存放在堆(heap)中,还是在栈(stack)中,还是其他什么地方呢?
                            String str1 = new String("string");
                            String str2 = "string";
    if(str1==str2)
    System.out.println("1 true");
    if (str1.equals(str2))
    System.out.println("2 true");
    为什么 1 没输出而 2 有输出,说明str1 和 str2 内容相同而地址不同,对吗

    如果他们在内存的同一块区域内,那么str2 就会自动指向str1,而实际上却没有。所以我认为这两种方式创建的字符串并不是存储在内存中在同一块区域,不知道对不对。那么他们又是分别怎样存储的呢?

    String str1 = new String("string");
    这样创建的对象应该在堆内存中,有人说这一条语句创建了两个对象,那么这两个分别是什么样的呢,存储在哪呢?

    请高人赐教!
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • zrd
    • 等级:
    • 可用分等级:
    • 总技术专家分:
    • 总技术专家分排名:
    发表于:2008-08-27 12:16:135楼 得分:0
    String s1 = "string";
    毕竟String并不是基本类型也不是包装类,既然s1能调用equals()方法,那么我就认为创建了一个对象,而不是一个简单的常量。既然是对象就应该是存储在堆heap中,而不是stack里。

    而且下面的代码输出false,也说明str2没有直接指向已经存在的、s1指向的堆里的字符串
    String str1 = new String("string");
    String str2 = "string";
    System.out.println(str1==str2);

    那么,是不是说这两种方式创建的对象不在内存的同一块区域,那到底是在哪里呢,这让我很迷惑,请高人指教。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • yanhan0615
    • 等级:
    • 可用分等级:
    • 总技术专家分:
    • 总技术专家分排名:
    发表于:2008-08-27 16:53:466楼 得分:0
    String s1 = "string"; 是作为静态变量在栈中;
    其他但凡是new出来的,都在堆里
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • marf_cn
    • 等级:
    • 可用分等级:
    • 总技术专家分:
    • 总技术专家分排名:
    发表于:2008-08-27 16:59:457楼 得分:0
    建议lz仔细找找stack、heap的区别,一句简单的话:变量存在stack里,对象存在heap里
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • marf_cn
    • 等级:
    • 可用分等级:
    • 总技术专家分:
    • 总技术专家分排名:
    发表于:2008-08-27 17:07:058楼 得分:0
    引用 6 楼 yanhan0615 的回复:
    String s1 = "string"; 是作为静态变量在栈中;
    其他但凡是new出来的,都在堆里

    不完全同意。实际上如果内存中没有“string”这个串的话,这条语句会new一个在heap中,而是s1作为变量在stack中
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • marf_cn
    • 等级:
    • 可用分等级:
    • 总技术专家分:
    • 总技术专家分排名:
    发表于:2008-08-27 17:09:249楼 得分:0
    引用 5 楼 zrd 的回复:
    String s1 = "string"; 
    毕竟String并不是基本类型也不是包装类,既然s1能调用equals()方法,那么我就认为创建了一个对象,而不是一个简单的常量。既然是对象就应该是存储在堆heap中,而不是stack里。
     
    而且下面的代码输出false,也说明str2没有直接指向已经存在的、s1指向的堆里的字符串
    String str1 = new String("string");
    String str2 = "string";
    System.out.println(str1==str2); 
     
    那么,是不是说这两种…

    这个结果当然是false,因为==操作符要比较的不仅仅是是否是同一个对象,还要比较hashcode
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • zhangdsh
    • 等级:
    • 可用分等级:
    • 总技术专家分:
    • 总技术专家分排名:
    发表于:2008-08-27 17:23:1610楼 得分:0
    有一点很重要 String 是一个常量 
    String s = "ssss";//可以简单理解是值 值和值之间可以通过 == 判读
    String s = new String("ssss");//这个就是对象,对象之间不能通过 == 判断。

    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • yanhan0615
    • 等级:
    • 可用分等级:
    • 总技术专家分:
    • 总技术专家分排名:
    发表于:2008-08-27 17:26:2111楼 得分:0
    楼上的,我当然是说String s1 = "string"; 这一整条语句的情况下是作为静态变量存储在栈中的,你别断章取义行么?

    另:你说的“因为==操作符要比较的不仅仅是是否是同一个对象,还要比较hashcode”就错了,==只是比较内存地址,equals()方法才是判断对象是否相等!!
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • yanhan0615
    • 等级:
    • 可用分等级:
    • 总技术专家分:
    • 总技术专家分排名:
    发表于:2008-08-27 17:28:0112楼 得分:0
    错了,是楼上的楼上
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • zrd
    • 等级:
    • 可用分等级:
    • 总技术专家分:
    • 总技术专家分排名:
    发表于:2008-08-29 08:56:3713楼 得分:0
    String s1 = "string";
    为什么说它是在栈中的呢,既然它能调用各种方法,它应该是对象而不是简单的常量啊,既然是对象就应该是在堆中才对啊。那么s1作为对象的引用存储在栈中倒是可以接受。

    String毕竟不是基本类型也不是包装类,不能用8种基本类型的思路来看待吧
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • wenjunsu
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-11-02 23:50:2614楼 得分:0

    学习了。。。。

    mark。。。

    up
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • wangmao2008
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-11-03 13:36:0415楼 得分:0
    该回复于2008-11-11 22:37:13被管理员删除
    修改 删除 举报 引用 回复

    网站简介广告服务网站地图帮助联系方式诚聘英才English 问题报告
    北京创新乐知广告有限公司 版权所有 京 ICP 证 070598 号
    世纪乐知(北京)网络技术有限公司 提供技术支持
    Copyright © 2000-2008, CSDN.NET, All Rights Reserved