String s1=new String("a");

String s2="a";
的区别???????

解决方案 »

  1.   

    1.开辟一个内存空间储存字符串“a”2.在常量池里使用字符串“a”如果没有“a”则把该字符串添加到常量池
      

  2.   

    String s2="a"; 在栈区String s1=new String("a"); 在堆区
    所以要s1==s2为false
      

  3.   

    那就是说如果再有一个String s3=="a"那么s3取刚才s2在常量池里边创建的"a",s3==s2为true吧?
      

  4.   

    如果只有String s1=new String("a"); 这一句,则先在String池里面创建字符串“a”,接着在堆内创建“a”,这句就创建了两个对象;
    如果接着再写一个String s2="a";因为在上一句已经在String池里面创建了字符串“a”,所有这句不会创建对象了,直接把s2指向上一句在String池里面创建了字符串“a”。如果这两句反过来写,效果又是不一样的
      

  5.   

    Integer i1=new Integer(1);
    Integer i4=1;System.out.println(i1==i4);
    System.out.println(i1==1);那这个为什么两次输出结果不一样?????
      

  6.   

    参考参考【转】
    String类是Java中很重要的一个类,在此总结一下这个类的特别之处。下面的相关资料翻译自《java语言规范》(第三版)和《java虚拟机规范》(第二版),有的直接摘引了原文。下面的代码都是用SUN jdk1.6 javac来编译。 1.String literal,这里将它翻译为字面常量,它由双引号包围的0个或多个字符组成,比如"abc","Hello World"等等。一个String字面常量总是引用相同的String实例,比如"abc","abc"两个常量引用的是同一个对象。 程序测试: 
    package testPackage; 
    class Test { 
            public static void main(String[] args) { 
                    String hello = "Hello", lo = "lo"; 
                    System.out.print((hello == "Hello") + " "); 
                    System.out.print((Other.hello == hello) + " "); 
                    System.out.print((other.Other.hello == hello) + " "); 
                    System.out.print((hello == ("Hel"+"lo")) + " "); 
                    System.out.print((hello == ("Hel"+lo)) + " "); 
                    System.out.println(hello == ("Hel"+lo).intern()); 
            } 

    class Other { static String hello = "Hello"; } 
    另一个包:
    package other; 
    public class Other { static String hello = "Hello"; } 
    输出: 
    true true true true false true 
    结论有六点: 
    1)  同一个包下,同一个类中的相同的String字面常量表示对同一个String对象的引用。 
    2)  同一个包下,不同的类中的相同的String字面常量表示对同一个String对象的引用。 
    3)  不同包下,不同类中的相同String字面常量同样表示对同一个String对象的引用。 
    4)  通过常量表达式计算的String,计算在编译时进行,并将它作为String字面常量对待。 
    5)  通过连接操作得到的String(非常量表达式),连接操作是运行时进行的,会新创建对象,所以它们是不同的。 
    6)  显式的对一个计算得到的String调用intern操作,得到的结果是已经存在的相同内容的String字面常量。 
    补充说明: 
    1)像这样的问题,String str = "a"+"b"+"c"+"d"; 
    运行这条语句会产生几个String对象?1个。参考上面第5条,通过常量表达式得到的String 是编译时计算的,因此执行这句话时只有"abcd"着一个String对象存在。 
    常量表达是的定义可以参考java语言规范。另例: 
          final String str1 = "a"; 
          String str2 = str1+"b"; 
    执行第二句话会有几个String对象产生?1个。因为str1是常量,所以str1+"b"也是常量表达式,在编译时计算。 
        遇到这种问题时,不要说它依赖于具体的编译器或者虚拟机实现,因为这就是规范里有的。一般的说,java的编译器实现应该遵守《java语言规范》,而java虚拟机实现应该遵守《java虚拟机规范》。 
    2)不要这样使用字符串: 
    String str = new String("abc"); 
        参考文档中的说明: 
    String 
    public String(String original) 
        初始化一个新创建的 String 对象,使其表示一个与参数相同的字符序列;换句话说,新创建的字符串是该参数字符串的副本。由于 String 是不可变的,所以无需使用此构造方法,除非需要 original 的显式副本。 
    参数: 
    original - 一个 String。 
    注意:无需使用此构造方法!!! 
    3)单独的说明第6点: 
    String str = new String("abc"); 
    str = str.intern(); 
        当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(用 equals(Object) 方法确定),则返回池中的字符串引用。否则,将此 String 对象添加到池中,并返回此 String 对象的引用。 
        很明显,在这个例子中"abc"引用的对象已经在字符串池中了,再调用intern返回的是已经存在池中内容为"abc"的字符换对象的引用。在上面的例子中也说明了这个问题。 
    2. String类的实例表示表示Unicode字符序列。String字面常量是指向String实例的引用。(字面常量是“引用”!) 
    3.String转换 
        对于基本类型先转换为引用类型;引用类型调用toString()方法得到String,如果该引用类型为null,转换得到的字符串为"null"。 
    4. String链接操作“+” 
        如果“+”操作的结果不是编译期常量,将会隐式创建一个新的对象。为了提高性能,具体的实现可以采用 StringBuffer,StringBuilder类对多个部分进行连接,最后再转换为String,从而避免生成再丢弃中间的String对象。为了达到共享实例的目的,编译期常量总是“interned”的。 
    例子: 
    String a = "hello "; 
    String b = a+1+2+"world!"; 
    反汇编结果: 
    0:  ldc #2; //String hello 
      2:  astore_1 
      3:  new #3; //class java/lang/StringBuilder 
      6:  dup 
      7:  invokespecial #4; //Method java/lang/StringBuilder." <init>":()V 
      10: aload_1 
      11: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 
      14: iconst_1 
      15: invokevirtual #6; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder; 
      18: iconst_2 
      19: invokevirtual #6; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder; 
      22: ldc #7; //String world! 
      24: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 
      27: invokevirtual #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String; 
      30: astore_2 
    实际就是 
    String b = new StringBuilder().append(a).append(1).append(2).append("world").toString(); 
    这里就使用StringBuilder来避免中间临时String对象的产生而导致性能下降。 
        补充例子,下面的两个例子主要是对编译时常量做一个说明: 
    1) 
    String c = "c"; 
    String str = "a"+"b"+c; 
    和 
    2) 
    String c = "c"; 
    String str = c+"a"+"b"; 
    1)中,str="a"+"b"+c;编译器分析是会把"a"+"b"作为编译时常量,生成字面常量"ab",所以实际执行这句话时,链接的是"ab"和c。实际相当于执行了 
    String str = new StringBuilder().append("ab").append(c).toString(); 
    2)中,String str = c+"a"+"b"; 
    编译器分析到c为变量,后面的"a"+"b"就不会作为编译时常量来运算了。 
    实际运行时相当于执行 
    String str = new StringBuilder().append(c).append("a").append("b").toString(); 
    5.String对象的创建: 
    1)  包含String字面常量的类或者接口在加载时创建表示该字面常量的String对象。以下两种情况下不会创建新String对象。 
    a)  一个相同的字面常量已经出现过。 
    b)  一个相同内容的字符串已经调用了intern操作(比如经过运算产生的字符串调用intern的情形)。 
    2)  非常量表达式的字符串连接操作有时会产生表示结果的String对象。 
    3)  String字面常量来自类或接口的二进制表示中(也就是class文件中)的CONSTANT_String_info 结构。CONSTANT_String_info结构给出了构成字符串字面常量的Unicode字符序列。 
    4)  为了生成字符串字面常量,java虚拟机检查 CONSTANT_String_info结构给出的字符序列: 
    a)  如果与CONSTANT_String_info结构中给出的字符换内容相同的串实例已经调用过String.intern,得到的字符串字面常量就来自该串的同一实例。 
    b)  否则,根据CONSTANT_String_info 中的字符序列创建一个新的字符串实例,然后调用intern方法。 
    例子:一个SCJP题目 
    11. public String makinStrings() { 
    12. String s = “Fred”; 
    13. s = s + “47”; 
    14. s = s.substring(2, 5); 
    15. s = s.toUpperCase(); 
    16. return s.toString(); 
    17. } 
    How many String objects will be created when this method is invoked? 
    答案是3个。上面已经说明,"Fred","47"是字符串字面常量,它们在在类加载时创建的。这里题目问,方法调用时(!)有多少个String对象被创建,两个字面常量自然不包括在内。3个是:"Fred47","ed4","ED4"。 
    6.String与基本类型的包装类比较 
        相同点,它们都是不变类,使用"=="判断时可能会有类似的性质。 
        在java 5之后,java增加了自动装箱和拆箱功能。因此,就有了这样的性质: 
    Integer i = 5; 
    Integer j = 5; 
    System.out.println(i == j); 
    结果:true. 
      这表面上看来是和String相同点,但其实现是极为不同的。这里作为一个不同点来介绍。 
        众所周知,自动装箱是这样实现的: 
    Integer i = 5; 
    相当于 
    Integer i = Integer.valueOf(5);//注意不是new Integer(5),这就无法满足java语言规范中的约定了,约定见本文最后 
        而在Integer中,静态的创建了表示从-128~+127之间数据的Integer对象,这个范围之内的数进行装箱操作,只要返回相应的对象即可。因此 
    Integer i = 5; 
    Integer j = 5; 
    我们得到的是同一个对象。这是通过类库的设计来实现的。而String的共享是通过java虚拟机的直接支持来实现的,这是它们本质的不同。 
        这是Integer类中的部分代码: 
    private static class IntegerCache { 
      private IntegerCache(){} 
      static final Integer cache[] = new Integer[-(-128) + 127 + 1]; 
      static { 
          for(int i = 0; i < cache.length; i++) 
          cache[i] = new Integer(i - 128); 
      } 

    public static Integer valueOf(int i) { 
      final int offset = 128; 
      if (i >= -128 && i <= 127) { // must cache 
          return IntegerCache.cache[i + offset]; 
      } 
        return new Integer(i); 
        } 
    关于基本类型的装箱,Java语言规范中有如下说明: 
        如果被装箱的变量p为true,false,一个处于\u0000~\u007f之间的byte/char,或一个处于-128~+127之间的int /short,令r1和r2为对p的任何两个装箱操作的结果,则r1==r2总是成立的。理想的情况下,对一个基本类型变量执行装箱操作,应该总是得到一个相同的引用。但在实践中,在现存的技术条件下,这是不现实的。上面的规则是一个注重实效的折衷。 
        最后一点,要理解java的方法调用时的传参模型:java中只有pass by value。(不明确这一点,就有乱七八糟的解释,比如典型的Java既有传值,又有传引用,String很特殊……) 
    //改变参数的值? 
    public void test(String str){ 
        str = "Hello"; 

    //改变参数的值? 
    public void test(StringBuffer buffer){ 
        buffer = new StringBuffer("Hello"); 
    }
    交换两个Integer?  
    public void swap(Integer a,Integer b){ 
        Integer temp = a; 
        a = b; 
        b = temp; 
      

  7.   

    String是特殊情况,这不能相提并论
      

  8.   

    基本类型和其包装器以及String类型在JAVA里都是特殊的存在
    例:
    String strA = "a";//strA的“指针”指向常量池中的字符串"a";
    String strB = new String("a");//strB的“指针”指向堆,而它指向的堆中的对象,才真正指向常量池中的"a"String strC = "c";
    String strD = "d";
    String strCD1 = "cd";
    String strCD2 = strC+strD;
    strCD1==strCD2 这个也是成立的,具体为什么,你自己琢磨一下吧。
      

  9.   

    那在如:String s1=new String("a")
    那么 System.out.println(s1=="a");依照常量池的说法也为true喽。。但是实际却是false啊 。不理解
      

  10.   

    《Agile Java 测试驱动开发》书上是这样说的:"String a = "abc" ;
    String b = new String("abc") ; //Don't Do this避免使用第二种方式。第二种方式创建了两个String对象,这样降低了性能:首先,java虚拟机
    创建了String对象"abc"。然后,java虚拟机创建一个新的String对象,并把字符串"abc"传入
    构造函数,使得您的代码阅读起来更加困难.
      

  11.   

    我试过了 不成立。结果为false