String t0= new String("string");
String t1="strin"+"g";
String t2 = "string";
String t3 = new String("string");
String t4 = "string";
boolean five = t0==t2;
boolean six = t1==t2;
boolean seven = t0==t3;
boolean eight = t2==t4;
System.out.println(five);
System.out.println(six);
System.out.println(seven);
System.out.println(eight);
请各位演示下或许能得到与我相同的 困惑了
始终认为对象之间使用==比较的话为比较其内存地址(object.getClass()之间的比较除外,这种情况是不考虑继承关系比较实际的Class对象)
String 为一种对象类型 使用==比较应该为比较内存
String t1="strin"+"g";
String t2 = "string";
t1 t2内存地址相同?还是String *="*******";这时候的String *不是一个对象了?这种方式不申请新内存(以new为申请一块新的内存)
困惑 期待解答..........

解决方案 »

  1.   


    Code:
    String s= "Hello"; 
     s = s + "world!"; s所指向的对象是否改变了呢?我们来看看发生了什么事情。在这段代码中,s原先指向一个String对象,内容是"Hello",然后我们对s进行了+操作,那么s所指向的那个对象是否发生了改变呢?答案是没有。这时,s不指向原来那个对象了,而指向了另一个String对象,内容为"Helloworld!",原来那个对象还存在于内存之中,只是s这个引用变量不再指向它了。 通过上面的说明,我们很容易导出另一个结论,如果经常对字符串进行各种各样的修改,或者说,不可预见的修改,那么使用String来代表字符串的话会引起很大的内存开销。因为String对象建立之后不能再改变,所以对于每一个不同的字符串,都需要一个String对象来表示。这时,应该考虑使用StringBuffer类,它允许修改,而不是每个不同的字符串都要生成一个新的对象。并且,这两种类的对象转换十分容易。 同时,我们还可以知道,如果要使用内容相同的字符串,不必每次都new一个String。例如我们要在构造器中对一个名叫s的String引用变量进行初始化,把它设置为初始值,应当这样做: Code:
    public class Demo{ 
         private Strings; 
         ... 
        public Demo{ 
           s="Initialvalue"; 
        } 
         ... 
     } 
     而非 
     
     s=new String("Initialvalue"); 
    后者每次都会调用构造器,生成新对象,性能低下且内存开销大,并且没有意义,因为String对象不可改变,所以对于内容相同的字符串,只要一个String对象来表示就可以了。也就说,多次调用上面的构造器创建多个对象,他们的String类型属性s都指向同一个对象。 上面的结论还基于这样一个事实:对于字符串常量,如果内容相同,Java认为它们代表同一个String对象。而用关键字new调用构造器,总是会创建一个新的对象,无论内容是否相同。 至于为什么要把String类设计成不可变类,是它的用途决定的。其实不只String,很多Java标准类库中的类都是不可变的。在开发一个系统的时候,我们有时候也需要设计不可变类,来传递一组相关的值,这也是面向对象思想的体现。不可变类有一些优点,比如因为它的对象是只读的,所以多线程并发访问也不会有任何问题。当然也有一些缺点,比如每个不同的状态都要一个对象来代表,可能会造成性能上的问题。所以Java标准类库还提供了一个可变版本,即StringBuffer。
      

  2.   

    String t0= new String("string");
    String t1="strin"+"g";
    String t2 = "string";
    String t3 = new String("string");
    String t4 = "string";
    //t0-->内存1-->"string"
    //t1-->"string"
    //t2-->"string"
    //t3-->内存2-->"string"
    //t4-->"string"So:
    t0!=t2
    t1=t2
    t0!=t3
    t2=t4
      

  3.   

    不知道楼主有什么地方困惑,String类型是final类型的,并且其中重载+号的操作是重新份内配内存空间,新建一个对象,并不是改变原来的对象,String a = "abc" + "a" + "b" + "c";上面的表达式编译器在执行过程中共分配了三个String类型的对象空间,第一次是定义一个String类型的引用,指向"abc"这时候并没有分配内存,第一次分配内存是执行的"abc" + "a"操作,也就是说分配了一个String类型的对象空间,及new了一个String用来保存"abca",依次类推,共分配了3次空间,最后一次才是我们的String a 保存的"abcabc"
      

  4.   

    对于字符串常量,如果内容相同,Java认为它们代表同一个String对象。而用关键字new调用构造器,总是会创建一个新的对象,无论内容是否相同。
      

  5.   

    TO sureyor():
    对于字符串常量,如果内容相同,Java认为它们代表同一个String对象。而用关键字new调用构造器,总是会创建一个新的对象,无论内容是否相同。
    这样
    String t1= "strin";
    String t5=t1+"g";
    t5的值还是"string"  与T2内容还是相同可是已经不是一个String对象了。
      

  6.   

    bigcatzhou() 您根本没明白什么意思 您肯定没有运行我的代码
      

  7.   

    字符串池
    String str="asas"; ///用这种方式声明的字符串 会放到字符串池中
    如果下一次再用这种方式声明字符串 程序会先检测字符串池里有没有该字符串 如果有的话 就让引用直接指向它 如果没有  再新建一个字符串 放入字符串池中而用String str=new String() 这种方式声明的字符串不会放到池中。。每次都是新建一个字符串
    不知道这样说对不对
      

  8.   

    Java虚拟机常量池,保存着几乎所有的常量值。字符串表达式总是指向池中的一个对象。使用new操作创建的字符串对象不指向字符串池中的对象但是可以使用intern方法使其指向池中的对象(注:如果池中已经有相同的字符串--使用equals方法确定,则直接返回池中的字符串,否则先将字符串添加到池中,再返回)。池中两个相等的字符串如果使用“==”来比较将返回真。
    我困惑的就是 String 类型并不与基础类型相同  它是一个对象 也适用与这个道理吗??
      

  9.   

    。。  以前看的一本叫 java学习笔记的书上说的 字符串就是这样。
      

  10.   

    String t1= "strin";
    String t5=t1+"g";
    t5的值还是"string"  与T2内容还是相同可是已经不是一个String对象了。
    --------------------------------我的理解是,如果常量和常量通过运算符"+",就不重新分配内存;如果是变量和常量通过运算符"+",就会重新分配内存.由于内存不一样,所以t5和t4通过==比较是不相等的楼主如果有时间和精力,可以去研究一下String的"+"实现和"=="的实现,看看源码,就什么都明白啦
      

  11.   

    String t1="strin"+"g";
    String t2 = "string";
    这t1 == t2是由编译器去完成,而不是JVM完成的
    因为编译器在编译t1的时候会智能的判断这个地方都是常量,没有必要在运行期去计算,只要编译期完成就可以了所以它等同于:
    String t1="string";
    String t2 = "string";所以t1 == t2
      

  12.   

    另外to   sureyor() String没有重载 + 号的,Java不允许运算符重载,我们写String s = a + b也是由编译器完成的
    它等同于String s = new StringBuffer().appendChild(a).append(b).toString();== 就更加没有重载了,t1 == t2是由于字符串常量池的原因造成它们的地址相同
      

  13.   

    写错:
    String s = new StringBuffer().append(a).append(b).toString();
      

  14.   

    String t= "strin";
    String t4= "string";
    String t5= t+"g";to ChDw:
    你说t5==t4返回true还是false?
      

  15.   

    要理解 java中String的运作方式,必须明确一点:String是一个非可变类(immutable)。什么是非可变类呢?简单说来,非可变类的实例是不能被修改的,每个实例中包含的信息都必须在该实例创建的时候就提供出来,并且在对象的整个生存周期内固定不变。java为什么要把String设计为非可变类呢?你可以问问 james Gosling :)。但是非可变类确实有着自身的优势,如状态单一,对象简单,便于维护。其次,该类对象对象本质上是线程安全的,不要求同步。此外用户可以共享非可变对象,甚至可以共享它们的内部信息。(详见 《Effective java》item 13)。String类在java中被大量运用,甚至在class文件中都有其身影,因此将其设计为简单轻便的非可变类是比较合适的。 
    一、创建。
        好了,知道String是非可变类以后,我们可以进一步了解String的构造方式了。创建一个Stirng对象,主要就有以下两种方式:
    java 代码
    String str1 = new String("abc");    
    Stirng str2 = "abc";  
         虽然两个语句都是返回一个String对象的引用,但是jvm对两者的处理方式是不一样的。对于第一种,jvm会马上在heap中创建一个String对象,然后将该对象的引用返回给用户。对于第二种,jvm首先会在内部维护的strings pool中通过String的 equels 方法查找是对象池中是否存放有该String对象,如果有,则返回已有的String对象给用户,而不会在heap中重新创建一个新的String对象;如果对象池中没有该String对象,jvm则在heap中创建新的String对象,将其引用返回给用户,同时将该引用添加至strings pool中。注意:使用第一种方法创建对象时,jvm是不会主动把该对象放到strings pool里面的,除非程序调用 String的intern方法。看下面的例子:java 代码
    String str1 = new String("abc"); //jvm 在堆上创建一个String对象   
      
     //jvm 在strings pool中找不到值为“abc”的字符串,因此   
     //在堆上创建一个String对象,并将该对象的引用加入至strings pool中   
     //此时堆上有两个String对象   
    Stirng str2 = "abc";   
      
     if(str1 == str2){   
             System.out.println("str1 == str2");   
     }else{   
             System.out.println("str1 != str2");   
     }   
      //打印结果是 str1 != str2,因为它们是堆上两个不同的对象   
      
      String str3 = "abc";   
     //此时,jvm发现strings pool中已有“abc”对象了,因为“abc”equels “abc”   
     //因此直接返回str2指向的对象给str3,也就是说str2和str3是指向同一个对象的引用   
      if(str2 == str3){   
             System.out.println("str2 == str3");   
      }else{   
             System.out.println("str2 != str3");   
      }   
     //打印结果为 str2 == str3  
       再看下面的例子:
    java 代码
    String str1 = new String("abc"); //jvm 在堆上创建一个String对象   
      
    str1 = str1.intern();   
    //程序显式将str1放到strings pool中,intern运行过程是这样的:首先查看strings pool   
    //有没“abc”对象的引用,没有,则在堆中新建一个对象,然后将新对象的引用加入至   
    //strings pool中。执行完该语句后,str1原来指向的String对象已经成为垃圾对象了,随时会   
    //被GC收集。   
      
    //此时,jvm发现strings pool中已有“abc”对象了,因为“abc”equels “abc”   
    //因此直接返回str1指向的对象给str2,也就是说str2和str1引用着同一个对象,   
    //此时,堆上的有效对象只有一个。   
    Stirng str2 = "abc";   
      
     if(str1 == str2){   
             System.out.println("str1 == str2");   
     }else{   
             System.out.println("str1 != str2");   
     }   
      //打印结果是 str1 == str2   
          为什么jvm可以这样处理String对象呢?就是因为String的非可变性。既然所引用的对象一旦创建就永不更改,那么多个引用共用一个对象时互不影响。
    二、串接(Concatenation)。
         java程序员应该都知道滥用String的串接操作符是会影响程序的性能的。性能问题从何而来呢?归根结底就是String类的非可变性。既然String对象都是非可变的,也就是对象一旦创建了就不能够改变其内在状态了,但是串接操作明显是要增长字符串的,也就是要改变String的内部状态,两者出现了矛盾。怎么办呢?要维护String的非可变性,只好在串接完成后新建一个String 对象来表示新产生的字符串了。也就是说,每一次执行串接操作都会导致新对象的产生,如果串接操作执行很频繁,就会导致大量对象的创建,性能问题也就随之而来了。
        为了解决这个问题,jdk为String类提供了一个可变的配套类,StringBuffer。使用StringBuffer对象,由于该类是可变的,串接时仅仅时改变了内部数据结构,而不会创建新的对象,因此性能上有很大的提高。针对单线程,jdk 5.0还提供了StringBuilder类,在单线程环境下,由于不用考虑同步问题,使用该类使性能得到进一步的提高。三、String的长度
       我们可以使用串接操作符得到一个长度更长的字符串,那么,String对象最多能容纳多少字符呢?查看String的源代码我们可以得知类String中是使用域 count 来记录对象字符的数量,而count 的类型为 int,因此,我们可以推测最长的长度为 2^32,也就是4G。
        不过,我们在编写源代码的时候,如果使用 Sting str = "aaaa";的形式定义一个字符串,那么双引号里面的ASCII字符最多只能有 65534 个。为什么呢?因为在class文件的规范中, CONSTANT_Utf8_info表中使用一个16位的无符号整数来记录字符串的长度的,最多能表示 65536个字节,而java class 文件是使用一种变体UTF-8格式来存放字符的,null值使用两个字节来表示,因此只剩下 65536- 2 = 65534个字节。也正是变体UTF-8的原因,如果字符串中含有中文等非ASCII字符,那么双引号中字符的数量会更少(一个中文字符占用三个字节)。如果超出这个数量,在编译的时候编译器会报错。
      

  16.   

    JVM中没有关于String"+","=="等的实现?-_-,我孤陋寡闻啦...
      

  17.   

    to ChDw(米)如果是用编译器完成 那就说还是在加载时候存入常量池中了  我就是不理解这个
    String t1 = "string";被编译器理解为与基础类型一样的常量 而非一个对象了?并不是Runtime loading。
    to sureyor() String的原代码我已经看过了您说的都没有实现。
    这些运算应该是在 编译时候进行转型  我只知道char转为int吧 至于String不清楚 不过 米答了
      

  18.   

    java语言只允许非常有限的运算符重载。如果“+”运算符有两重含义:如果它的两个操作数都是数值型则表示算术加运算符;如果至少一个操作数是字符串实例时,表示字符连接符。下面三条语句描述了“+”运算符的三种不同用途: String string1 = "box"+(5+3);  //Result:"box 8"; String string2 = ("box"+5)+3;  //Reusult:"box 53"; String string3 = "box"+5+3;  //result:"box 53"; 第一条语句包含了一个字符串连接符和一个算术加法运算符;第二条语句包含了字符串连接符的两种用法;从第三条语句我们可以看出,如果要在一个语句行中同时使用“+”的两种用法,最好用括号显示地表示出它们之间的运算关系。
      

  19.   

    to sureyor()您说的关于String与ChDw(米)说的是一致的strings pool就是米所说的编译期完成
    (编译期完成 JVM加载时就是按照常量加载)jvm会马上在heap中创建一个String对象,就是运行器(JVM是动态加载对象的)。
      

  20.   


     String string1 = "box"+(5+3);  //Result:"box 8"; String string2 = ("box"+5)+3;  //Reusult:"box 53"; String string3 = "box"+5+3;  //result:"box 53";
    这3个举例 用thinking in java所说String+会把 5 3变成String处理
    3+"box"也是同理
    至于这是不是运算符重载我不清楚了。
      

  21.   

    to sureyor() 也是对什么问题比较  较真的 我们很象的 做个朋友吧 有问题一起探讨
    留个MSN OR Q的 我Q:8271132 MSN:[email protected]
      

  22.   

    String t= "strin";
    String t4= "string";
    String t5= t+"g";t4 != t5因为编译器在编译t5这行时候,它并不能肯定知道t的值是多少(当然从逻辑上说是一定为常量)
    所以编译器不会对它进行优化,也就是说它只能编译出
    String t5 = new StringBuffer().append(t).append("g").toString()这样的结果JVM对String的特殊处理并不在 + 与 ==, String特殊在Class文件中含有String常量这一概念,在JVM加载时,它会将这些常量加载到JVM内存的常量池中,类定义的常量字符串,如果内容相同会指向相同的常量池中对象
      

  23.   

    Object类中的boolean equals(Object o)方法是用来比较对象的内容是否相等,其返回值是boolean类型的值,相同为真,不同则为假。实际上还是比较对象地址是否相同。
    String类覆盖了equals()方法,他比较是对象中的内容是否相同。
      

  24.   

    my msn: [email protected]
      

  25.   

    ChDw(米)您也不在乎这几分 
    感谢个位哦
      

  26.   


    首先java不要与C混淆 java中没有指针的概念(并不是没有指针而是对指针进行了伪装:使用上泛化、强化和简单化,概念上淡化和弱化)。
    c++中有对象类型的变量和对象的指针类型,而java只有一种类型:对象类型。Java是一种真正的面向对象的语言,即使是开发简单的程序,也必须设计对象。String 类 顾名思义,String是串的意思,这个类是字符串常量的类。相信使用过C语言进行编程的人都知道字符串是怎么回事,这里就不再进行赘述了。但有一点要说明的是,Java中的字符串和C语言中的字符串是有区别的。在C语言中,并没有真正意义上的字符串,C语言中的字符串就是字符数组,使用起来非常的灵活。而在Java中,字符串常量是一个类即String类,它和字符数组是不同的。
    现在我们看楼主的问题:
    根据执行的结果我们知道System.out.println(six)为true;为什么?首先我们不要被"strin"+"g" 中的+号蒙骗了 其实+号只是一个连接符没有其他的任何的作用,(这和在c中是不一样的,c中应该是两个指针指向的位置,在堆栈中的位置"strin"+"g"和"string"是不一样的,不明白的去看看c。)如果你真正的了解java 你就很容易明白 
    Example:string 的构造函数
    public String()
            //这个构造函数用来创建一个空的字符串常量。
     
        如:String str=new String();    或:String str;
                    str=new String();
     public String(String value )
    这个构造函数用一个已经存在的字符串常量作为参数来创建一个新的字符串常量。无论"strin"+"g" 还是“string” 都是把“string”作为STRING对象的value值传递给public String(String value );看到这里应该明白为什么t1==t2;Continue downwards,if you Not understand.学习java的人都知道 Java会为每个用双引号"XXX"括起来的字符串常量创建一个String类的对象。如:String k="string"; Java会为"string" 创建一个String类的对象,然后把这个对象赋值给k。等同于:
        
        String temp=new String("string");    String k=temp;   这个构造函数的用法如:    String str=new String(k);   (注:k是一个String类的对象)    String str=new String("string");其实说道这里temp有点类似c++的指针,对java来说只是一个string对象的引用(有的说成句柄或者指针)。JAVA强调所有的对象赋值和传递都是引用,解释如下: Object a=new Object(); 并不是将新生成的对象赋给a,a是对新生成对象的引用。 Object a=new Object(); Object b; b=a; b并不是一个新对象,它是对a对象的引用,由此我们可以看出t1 t2都是对同一个对象的引用又都指向同一个字符串“string”因此我们不难理解t1=t2。同理t2=t4。
    go on....
    Java在对象对比时可以用符号"=="和方法 equals(); "=="符号只是单纯的比较对象引用的指针是否相等。我们知道在Java中,Object myObject 其中myObject是引用变量,是指向具体内存中对象的指针。也就是说Object a,b  若a == b 则说明a和b指向同一个对象,若a和b指向不同的对象,即使这两个对象完全相同,a != b java中所有类都会从Object类中继承equals()方法,一般情况下equals()方法判断对象(在对内存中的实体进行判断)是否相等,如果相等则返回true,不相等则返回false。当然,具体情况还要看类的创建者是怎么重写(Override) equals()的方法。t0和t3虽然值相等但是t0和t3的引用却不同所以t0!=t3 同理t0!=t2 但是如果使用equals()方法,我们就会发现System.out.println("t0equalst3:"+t0.equals(t3));结果为true.why?这是因为equals()方法是两个对象对内存中的实体进行的比较。有兴趣的去参看一下Object类的API Docs.月:java高级工程师