Java的String详解(反复研究)

来源:互联网 发布:java角色权限设计 编辑:程序博客网 时间:2024/04/20 21:56

JAVA中的equals和==的区别

 

==比较的是2个对象的地址,而equals比较的是2个对象的内容。显然,当equals为true时,==不一定为true。

 

折腾了一阵子又查了查书,终于对 String 这个特殊的对象有了点感悟

public class TestString {

    public static void main(String[] args) {

        String s1 = "Monday";

        String s2 = "Monday";

    }

}

有什么问题呢?

1. 来自 String 的忧虑

上面这段程序中,到底有几个对象呢?

可能很多人脱口而出:两个,s1 和 s2

为什么?

String 是 final 类,它的值不可变。

看起来似乎很有道理,那么来检测一下吧,稍微改动一下程序

就可以看到结果了:

public class TestString {

    public static void main(String[] args) {

        String s1 = "Monday";

        String s2 = "Monday";

        if (s1 == s2)

            System.out.println("s1 == s2");

        else

            System.out.println("s1 != s2");

    }

}

编译并运行程序,输出:s1 == s2

为什么 s1 == s2 ?

== 分明是在说:s1 与 s2 引用同一个 String 对象 -- "Monday"!

2. 千变万化的 String

再稍微改动一下程序,会有更奇怪的发现:

public class TestString {

    public static void main(String[] args) {

        String s1 = "Monday";

        String s2 = new String("Monday");

        if (s1 == s2)

            System.out.println("s1 == s2");

        else

            System.out.println("s1 != s2");

        if (s1.equals(s2))

            System.out.println("s1 equals s2");

        else

            System.out.println("s1 not equals s2");

    }

}

我们将 s2 用 new 操作符创建

程序输出:

s1 != s2

s1 equals s2

嗯,很明显嘛

s1 s2分别引用了两个"Monday"String对象

可是为什么两段程序不一样呢?

3. 在 String 的游泳池中游泳

哈哈,翻了翻书终于找到了答案:

原来,程序在运行的时候会创建一个字符串缓冲池

当使用 s2 = "Monday" 这样的表达式创建字符串的时候,JAVA首先会

在这个String缓冲池中寻找相同值的对象,在第一个程序中,s1先被

放到了池中,所以在s2被创建的时候,程序找到了具有相同值的 s1

将 s2 引用 s1 所引用的对象"Monday"

第二段程序中,使用了 new 操作符,他明白的告诉程序:

“我要一个新的!不要旧的!”与是一个新的"Monday"Sting对象被创

建在内存中。他们的值相同,但是位置不同,一个在池中游泳

一个在岸边休息。哎呀,真是资源浪费,明明是一样的非要分开做什么呢?

4. 继续潜水

再次更改程序:

public class TestString {

    public static void main(String[] args) {

        String s1 = "Monday";

        String s2 = new String("Monday");

        s2 = s2.intern();

        if (s1 == s2)

            System.out.println("s1 == s2");

        else

            System.out.println("s1 != s2");

        if (s1.equals(s2))

            System.out.println("s1 equals s2");

        else

            System.out.println("s1 not equals s2");

    }

}

这次加入:s2 = s2.intern();

哇!程序输出:

s1 == s2

s1 equals s2

原来,程序新建了 s2 之后,又用intern()把他打翻在了池里

哈哈,这次 s2 和 s1 有引用了同样的对象了

我们成功的减少了内存的占用

5. == 与 equals() 的争斗

String 是个对象,要对比两个不同的String对象的值是否相同

明显的要用到 equals() 这个方法

可是如果程序里面有那么多的String对象,有那么多次的要用到 equals ,

更好的办法:

把所有的String都intern()到缓冲池去吧

最好在用到new的时候就进行这个操作

String s2 = new String("Monday").intern();

现在我可以无所顾忌的用 == 来比较 String 对象的值了

真是爽啊,又快又方便!

 

测试代码:

public class StringAddress {

 public static void main(String[] args) {
  String a = "hehe";
  String b = "hehe";
  String c = new String("hehe");
  String d = a;
  String e = c.intern();
  if (a == b)
   System.out.println("a==b---使用 a='hehe'创建字符串的时候,JAVA首先在String缓冲池中寻找相同值,若找到则不新建对象");
  if (a == c)
   System.out.println("a==c---使用new操作符,重新申请内存");
  if (a.equals(c))
   System.out.println("a.equals(c)---值相同,内存地址不同");
  if (a == d)
   System.out.println("a==d---a==d ==> a.equals(d)");
  if (a.equals(d))
   System.out.println("a.equals(d)");
  if (a == e)
   System.out.println("a==e---intern()后都到String池中");
  System.out.println(System.getProperty("user.dir"));
 }
}

-------------------------------------------------------------------------------------------- 

 

String和StringBuffer的区别

而在某些特别情况下, String 对象的字符串拼接其实是被 JVM 解释成了 StringBuffer 对象的拼接,所以这些时候 String 对象的速度并不会比 StringBuffer 对象慢,而特别是以下的字符串对象生成中, String 效率是远要比 StringBuffer 快的: String S1 = “This is only a” + “ simple” + “ test”; StringBuffer Sb = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”); 你会很惊讶的发现,生成 String S1 对象的速度简直太快了,而这个时候 StringBuffer 居然速度上根本一点都不占优势。其实这是 JVM 的一个把戏,在 JVM 眼里,这个 String S1 = “This is only a” + “ simple” + “test”; 其实就是: String S1 = “This is only a simple test”; 所以当然不需要太多的时间了。但大家这里要注意的是,如果你的字符串是来自另外的 String 对象的话,速度就没那么快了,譬如: String S2 = “This is only a”; String S3 = “ simple”; String S4 = “ test”; String S1 = S2 +S3 + S4; 这时候 JVM 会规规矩矩的按照原来的方式去做

// String+String
  String tempstr = "abcdefghijklmnopqrstuvwxyz";
  int times = 3500;
  long lstart1 = System.currentTimeMillis();
  String str = "";
  for (int i = 0; i < times; i++) {
   str += tempstr;
  }
  long lend1 = System.currentTimeMillis();
  long time1 = (lend1 - lstart1) / 1000;
  System.out.println("String+String时间为: " + time1 + "毫秒");
  
  // "abcdefghijklmnopqrstuvwxyz"+"abcdefghijklmnopqrstuvwxyz"
  long lstart2 = System.currentTimeMillis();
  for (int i = 0; i < times; i++) {
   str = "abcdefghijklmnopqrstuvwxyz"+"abcdefghijklmnopqrstuvwxyz";
  }
  long lend2 = System.currentTimeMillis();
  long time2 = (lend2 - lstart2) / 1000;
  System.out.println("abcdefghijklmnopqrstuvwxyz+abcdefghijklmnopqrstuvwxyz时间为: " + time2 + "毫秒");

  // StringBuffer.append()
  long lstart3 = System.currentTimeMillis();
  StringBuffer sb = new StringBuffer();
  for (int i = 0; i < times; i++) {
   sb.append(tempstr);
  }
  long lend3 = System.currentTimeMillis();
  long time3 = (lend3 - lstart3) / 1000;
  System.out.println("StringBuffer.append()时间为: " + time3 + "毫秒");

 

 

---------------------------------------------------------------------------------------------

创建了几个对象

String   s   =   new   String( "xyz ");
这个语句创建了几个对象?
可能是一个,因为常量池中可能已经存在“xyz”这个对象了,所以这个语句不会再在常量池中创建了,只在堆里创建一个对象。如果常量池中不存在“xyz”,则会创建两个。

 

String s = "a" + "b";创建了几个对象

下面简单证明我的推断,首先编译这个类:

 

public class Test { private String s = "ab"; }

复制class文件备用,然后修改为

 

public class Test { private String s = "a" + "b"; }

再次编译,用ue之类的文本编辑器打开,察看二进制内容,可以发现,两个class文件完全一致,连一个字节都不差.

ok,真相大白了.根本不存在运行期的处理String b = "a" + "b";这样的代码的问题,编译时就直接优化掉了。

 

只有使用""和+创建的String对象才会加入String池中,其他用new或者String变量+""的形势均在用于存储对象的堆中。

栈(Stack):用于保存基本类型(byte,int,char)和对象引用,速度仅次于寄存器

堆(heap):用于存储复杂对象。String中有一个Value属性,由char[]型数组存储

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 壁纸颜色选深了怎么办 客厅壁纸太暗了怎么办 别人说你衣服丑怎么办 高楼热水器风大熄火怎么办 1楼独立下水2楼怎么办 宜家家具不会装怎么办 服务行业遇到低素质客户怎么办 服务类没有进项票怎么办 教师对学生缺乏耐心怎么办 买了竹料烂尾楼怎么办 刚毕业想换工作怎么办 客厅灯变不了光怎么办 塑料镀铝浸底漆咬底怎么办 标志408钥匙掉了怎么办 房本测绘页丢了怎么办 房本测绘页信息有误怎么办 税务登记证办完没有年检怎么办 建筑施工升降机司机证怎么办 北京建筑施工证怎么办呢 模拟城市5水抽干了怎么办 ip地址错误网络无法接通怎么办 rhino模型太大打开半天怎么办 日本新干线车票丢了怎么办 房间太干燥怎么办又热 薄荷叶子全干了怎么办 水培栀子花叶子蔫了怎么办 薄荷叶叶边干了怎么办 碗莲叶子发黑腐烂怎么办 龟背叶叶子蔫了怎么办 夏天龟背竹蔫了怎么办 春羽叶子长黄斑怎么办 百合竹叶子发黄掉落怎么办 凤尾蕨叶子蔫了怎么办 绿地珊瑚蕨干了怎么办 翠云草叶子蔫了怎么办 珊瑚蕨叶子烂了怎么办 黑骨茶叶子黑斑怎么办 外场主持没有人互动怎么办 企业年报填错了怎么办 手机忘了放哪了怎么办 燃气卡车没气了怎么办