简单易懂。深度理解String 。新手利器。

 对于java的学习者而言,无论是初学者,还是java大师,String对于大家而言,也绝对不会陌生。下面就从

自己学习的角度大致分析一下String,StringBuffer和StringBuilder这三者的区别和联系。如有不足,欢迎补充说

明~谢谢

    1 String类

    String类在java的java.lang.String包下面,需要特别说明的是String类是final关键字修饰的,也就是说String类是不能够被继承的,String中的内容一旦被创建后是不能被修改的。Stirng是对象也不是8种基本数据类型

   1) 具体的讲解请看下面的例子:

  

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

package com.yonyou.test;

 

 

class Test{

  public static void main(String[] args) {

    String str=new String("龙不吟");

    str=new String("虎不啸");//原始String对象中str的内容到底变了没有?

        System.out.println(str);

     

    //下面也是一个String的例子

    String str2="天下太平";

    str2=str2+"国泰民安";//原始String对象中的str2到底变了没有?

    System.out.println(str2);

      

}

 }

    首先说明上述原始String对象中的内容都没有改变!

       对于这个问题大家可以这样理解:

       如果大家看过String的源码可以发现,String字符串中的内容存储在char数组中的。

       在判断原始String对象str和str2的是否改变了,这里需要明白一个问题,在java中相关对象的引用变量一般都存在栈中,而相关的对象都是存在堆中的,栈中的值指向了它所引用的对象(堆中相应的对象的地址)。

     栈 :由JVM分配区域,用于保存线程执行的动作和数据引用。栈是一个运行的单位,Java中一个线程就会相应有一个线程栈与之对应。

 

 一般是用于存储的基本数据类型的局部变量(注意这里仅仅是局部的,对于全局变量不能这样定义哦?)

            

     堆 :由JVM分配的,用于存储对象等数据的区域。一般用于存储我们new出来的对象。

 

     常量池 :在堆中分配出来的一块存储区域,用于存储显式 的String,float或者integer.例如String str="abc"; abc这个字符串是显式声明,所以存储在常量池。

 

      对于java内存的更详细的讲解请参考:http://www.cnblogs.com/xiohao/p/4278173.html 这里不再累述。

      例如:

      创建一个对象String str=new String("Hello World");

      对于变量str而言,它代表的是引用变量,它的值是存储在栈中的,而new String("Hello World")会创建一个新的对象,而对象的值是存储在堆中的。而引用

      变量str指向对中的对象new String("Hello World"); 这样看来视乎上面的问题就很好解释了。

       由于是String修饰的str和str2而言,它们的引用变量的本身是不能够改变,但是它们指向的对象,比如说指向的堆中地址却是可以改变的。

       所以说上面String对象str和str2所对应的原始对象都没有改变,仅仅是str和str2所对应的引用变量的指向发生的改变。这段话有一些绕,理解起来不是那么容易,请多读几遍,反复思考一下。

       

      2) 接下来大家可以来理解一下

1

2

3

4

5

6

7

8

9

10

11

12

13

package com.yonyou.test;

 

 

class Test{

  public static void main(String[] args) {

     String str=new String("Hello World");

     String str2="Hello World";

     System.out.println("str和str2的equals值相同吗?"+str.equals(str2));

     System.out.println("str和str2的==值相同吗?"+(str==str2));

   }

//注意此处的str==str2必须用括号括起来,

                                                                 // 否//否则的话 字符连接符号 +的优先级高于==,实际上进行的比较是

                                                                 //str//("str和str2的==值相同吗?"+str)和str2的==值相同吗?而不是Hello World和Hello World是否相同

 

}

  

 输出结果为:

 str和str2的equals值相同吗?true
 str和str2的==值相同吗?false

 这些结果右是怎么输出来的呢?

 首先我们需要明白equals和==的区别和联系

 对于equals而言,它是 Object类中方法如下:

 ...

     * @param   obj   the reference object with which to compare.
     * @return  <code>true</code> if this object is the same as the obj
     *          argument; <code>false</code> otherwise.
     * @see     #hashCode()
     * @see     java.util.Hashtable
     */

 public boolean equals(Object obj) {
 return (this == obj);
    }

   通过在这里查看Object类中equals的方法我们知道,如果一个类没有重写Object类中的equals方法的话,那么它的作用和==的作用是一样的。说白了是没有任何区别的。但是如果用户可以根据自己的需求进行重写equals方法那样的话,equals比较的返回值就和相关的需求相关了。

   如在jdk中的String类中的equals方法是这样重写的:

   
   

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

/**

     * Compares this string to the specified object.  The result is {@code

     * true} if and only if the argument is not {@code null} and is a {@code

     * String} object that represents the same sequence of characters as this

     * object.

     *

     * @param  anObject

     *         The object to compare this {@code String} against

     *

     * @return  {@code true} if the given object represents a {@code String}

     *          equivalent to this string, {@code false} otherwise

     *

     * @see  #compareTo(String)

     * @see  #equalsIgnoreCase(String)

     */

    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;

    }

  这样我们就可以发现,对于String对象中的equals方法而言,它的目的是比较两个对象所对应的值是否相同,注意仅仅是两个对象的值,跟这两个对象的引用(地址没有任何关系)。

    而对于==而言,它在java中的主要作用则是用来比较java中一些基本类型(如int,long,float等)的值是否相同以及比较两个对象是否有相同(即两个对象的引用地址是否相同)。

    这也就明白了为什么上面的对象equals的值相同而==的值不同。

 

      3)对于下面声明的这个变量创建了几个对象?

          String str=new Stirng("xyz"); //创建了几个对象

          String str2="abc";//创建了几个对象

          首先说“String str=new Stirng("xyz");”创建了一个或者两个

           对于“xyz”这个对象而言,它是存放在字符串的缓冲区中的,不管出现多少遍,都是缓冲区中的那一个。而new String()每次都会创建一个新的对象。所以如果之前创建过“xyz”这个对象的话,那么久创建一个对象,而如果之前要是没有创建过这个字符串的话,那么就会创建两个对象。

          其次说String str2=“abc”会创建零个或者一个。

          这个是为什么我就不哆嗦了。

         需要注意str和str2是变量名不是对象。

         

         请看下面的这条语句创建了几个对象?

          String str="a"+"b"+"c"+"d"+"e"+"f"+"g"+"h"+"i"+"j"+"k";

         没错这里仅仅创建了一个对象即str=”abcdefghijk“;

          为了更好的说明这个问题我们来看下面的例子:

1

2

3

4

5

6

7

8

9

10

11

12

13

package com.xiaohao.test;

 

public class Test{

    public static void main(String[] args) {

      String str1="ab";

      String str2="a"+"b";

      String str3="b";

      String str4="a"+str3;

      System.out.println("str1和str2相等吗?"+(str1==str2));

      System.out.println("str1和str4相等吗?"+(str1==str4));

    }

 

}

  上面程序的输出结果为:

       str1和str2相等吗?true
       str1和str4相等吗?false

      这说明javac编译的时候可以对字符串常量直接相加的表达式进行优化,不必等到运行期在进行加法处理,而是在编译的时候直接去掉加号,直接将其编译成这些常量相连的结果。

而对于str4而言由于str3是变量,不是字符串常量,所以最终的结果为false。

     

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值