`
zhxy0234
  • 浏览: 5632 次
  • 性别: Icon_minigender_1
  • 来自: 大连
最近访客 更多访客>>
社区版块
存档分类
最新评论

1.string及equals

阅读更多
看了一篇文章,对 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" 这样的表达是创建字符串的时候,程序首先会
在这个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 对象的值了
真是爽啊,又快又方便!
关于String
String 啊 String ,让我说你什么好呢?
你为我们 Java 程序员带来所有的困扰还不够吗?
看看 String 这一次又怎么闹事儿吧

1. 回顾一下坏脾气的 String 老弟

例程1:
class Str {
    public static void main(String[] args) {
        String s = "Hi!";
        String t = "Hi!";
        if (s == t)
            System.out.println("equals");
        else
            System.out.println("not equals");
    }
}

程序输出什么呢?
如果看客们看过我的《来自 String 的困惑》之一
相信你很快会做出正确的判断:
程序输出:equals

2. 哦,天哪,它又在搅混水了

例程2:
class Str {
    public static void main(String[] args) {
        String s = "HELLO";
        String t = s.toUpperCase();
        if (s == t)
            System.out.println("equals");
        else
            System.out.println("not equals");
    }
}
那么这个程序有输出什么呢?
慎重!再慎重!不要被 String 这个迷乱的家伙所迷惑!
它输出:equals
WHY!!!

把程序简单的更改一下:
class Str2 {
    public static void main(String[] args) {
        String s = "Hello";
        String t = s.toUpperCase();
        if (s == t)
            System.out.println("equals");
        else
            System.out.println("not equals");
    }
}
你可能会说:不是一样吗?
不!千真万确的,不一样!这一次输出:not equals

Oh MyGOD!!!
谁来教训一下这个 String 啊!

3. 你了解你的马吗?
“要驯服脱缰的野马,就要了解它的秉性”牛仔们说道。
你了解 String 吗?

解读 String 的 API ,可以看到:
toUpperCase() 和 toLowerCase() 方法返回一个新的String对象,
它将原字符串表示字符串的大写或小写形势;
但是要注意:如果原字符串本身就是大写形式或小写形式,那么返回原始对象。
这就是为什么第二个程序中 s 和 t 纠缠不清的缘故

对待这个淘气的、屡教不改的 String ,似乎没有更好的办法了
让我们解剖它,看看它到底有什么结构吧:

(1) charAt(int n) 返回字符串内n位置的字符,第一个字符位置为0,
最后一个字符的位置为length()-1,访问错误的位置会扔出一块大砖头:
StringIndexOutOfBoundsException 真够大的

(2) concat(String str) 在原对象之后连接一个 str ,但是返回一个新的 String 对象

(3) EqualsIgnoreCase(String str) 忽略大小写的 equals 方法
这个方法的实质是首先调用静态字符方法toUpperCase() 或者 toLowerCase()
将对比的两个字符转换,然后进行 == 运算

(4) trim() 返回一个新的对象,它将原对象的开头和结尾的空白字符切掉
同样的,如果结果与原对象没有差别,则返回原对象

(5) toString() String 类也有 toString() 方法吗?
真是一个有趣的问题,可是如果没有它,你的 String 对象说不定真的不能用在
System.out.println() 里面啊
小心,它返回对象自己

String 类还有很多其他方法,掌握他们会带来很多方便
也会有很多困惑,所以坚持原则,是最关键的

4. 我想买一匹更好的马
来购买更驯服温和的 String 的小弟 StringBuffer 吧
这时候会有人反对:它很好用,它效率很高,它怎么能够是小弟呢?
很简单,它的交互功能要比 String 少,如果你要编辑字符串
它并不方便,你会对它失望
但这不意味着它不强大
public final class String implements Serializable, Comparable, CharSequence
public final class StringBuffer implements Serializable, CharSequence
很明显的,小弟少了一些东东,不过这不会干扰它的前途

StringBuffer 不是由 String 继承来的
不过要注意兄弟它也是 final 啊,本是同根生

看看他的方法吧,这么多稳定可靠的方法,用起来比顽皮的 String 要有效率的多
?br /> Java 为需要改变的字符串对象提供了独立的 StringBuffer 类
它的实例不可变(final),之所以要把他们分开
是因为,字符串的修改要求系统的开销量增大,
占用更多的空间也更复杂,相信当有10000人挤在一个狭小的游泳池里游泳
而岸边又有10000人等待进入游泳池而焦急上火
又有10000人在旁边看热闹的时候,你这个 String 游泳池的管理员也会焦头烂额

在你无需改变字符串的情况下,简单的 String 类就足够你使唤的了,
而当要频繁的更改字符串的内容的时候,就要借助于宰相肚里能撑船的
StringBuffer 了

5. 宰相肚里能撑船
(1) length() 与 capacity()
String 中的 length() 返回字符串的长度
兄弟 StringBuffer 也是如此,他们都由对象包含的字符长度决定

capacity()呢?
public class TestCapacity {
    public static void main(String[] args){
        StringBuffer buf = new StringBuffer("it was the age of wisdom,");
        System.out.println("buf = " + buf);
        System.out.println("buf.length() = " + buf.length());
        System.out.println("buf.capacity() = " + buf.capacity());
        String str = buf.toString();
        System.out.println("str = " + str);
        System.out.println("str.length() = " + str.length());
        buf.append(" " + str.substring(0,18)).append("foolishness,");
        System.out.println("buf = " + buf);
        System.out.println("buf.length() = " + buf.length());
        System.out.println("buf.capacity() = " + buf.capacity());
        System.out.println("str = " + str);
    }
}
程序输出:
buf = it was the age of wisdom.
buf.length() = 25
buf.capacity() = 41
str = it was the age of wisdom
str.length() = 25
buf = it was the age of wisdom, it was the age of foolishness,
buf.length() = 56
buf.capacity() = 84
str = it was the age of wisdom,

可以看到,在内容更改之后,capacity也随之改变了
长度随着向字符串添加字符而增加
而容量只是在新的长度超过了现在的容量之后才增加
StringBuffer 的容量在操作系统需要的时候是自动改变的
程序员们对capacity所能够做的仅仅是可以在初始化 StringBuffer对象的时候
以上片断引用自http://bbs.blueidea.com/viewthread.php?tid=945875&page=###
解释得比较形象和经典。具体的比较,要亲自动手运行一下程序才行,如下为网上找到的专门研究equals和==的关系的程序,相信可从中体会出他们的深刻不同:
String s1 = null;
String s2 = null;
System.out.println(s1==s2);//true
//System.out.println(s1.equals(s2));//NullPointerException
s1 = s2;
System.out.println(s1==s2);//true
//System.out.println(s1.equals(s2));//NullPointerException
System.out.println("***1***");

s1 = null;
s2 = "";
System.out.println(s1==s2);//false
//System.out.println(s1.equals(s2));//NullPointerException
s1 = s2;
System.out.println(s1==s2);//true
System.out.println(s1.equals(s2));//true
System.out.println("***2***");

s1 = "";
s2 = null;
System.out.println(s1==s2);//false
System.out.println(s1.equals(s2));//false
s1 = s2;
System.out.println(s1==s2);//true
//System.out.println(s1.equals(s2));//NullPointerException
System.out.println("***3***");

s1 = "";
s2 = "";
System.out.println(s1==s2);//true
System.out.println(s1.equals(s2));//true
s1 = s2;
System.out.println(s1==s2);//true
System.out.println(s1.equals(s2));//true
System.out.println("***4***");
s1 = new String("");
s2 = new String("");
System.out.println(s1==s2);//false
System.out.println(s1.equals(s2));//true
s1 = s2;
System.out.println(s1==s2);//true
System.out.println(s1.equals(s2));//true
System.out.println("***5***");

s1 = "null";
s2 = "null";
System.out.println(s1==s2);//ture
System.out.println(s1.equals(s2));//true
s1 = s2;
System.out.println(s1==s2);//true
System.out.println(s1.equals(s2));//true
System.out.println("***6***");
s1 = new String("null");
s2 = new String("null");
System.out.println(s1==s2);//flase
System.out.println(s1.equals(s2));//true
s1 = s2;
System.out.println(s1==s2);//true
System.out.println(s1.equals(s2));//true
System.out.println("***7***");

s1 = "abc";
s2 = "abc";
System.out.println(s1==s2);//ture
System.out.println(s1.equals(s2));//true
s1 = s2;
System.out.println(s1==s2);//true
System.out.println(s1.equals(s2));//true
System.out.println("***8***");
s1 = new String("abc");
s2 = new String("abc");
System.out.println(s1==s2);//false
System.out.println(s1.equals(s2));//true
s1 = s2;
System.out.println(s1==s2);//true
System.out.println(s1.equals(s2));//true
System.out.println("***9***");

总结:   多数情况下这两者的区别就是究竟是对对象的引用进行比较还是对对象的值进行比较(其他特殊情况此处不予考虑)。==操作符是比较的对象的引用而不是对象的值。

但在最初的Object对象中的equals方法与==操作符完成功能是相同的。
源码:
java.lang.Object.equals()方法:
-------------------------------------------------------------
public boolean equalss(Object obj) {
return (this = = obj);
    }
在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类的equal方法是对对象的值进行比较。
根据以上的讨论可以得出结论:equal方法和==操作符是否存在区别要个别对待,要根据equal的每个实现情况。

文章来自以下链接:
http://www.blogjava.net/Sunspl/archive/2008/06/11/207230.html
分享到:
评论

相关推荐

    java 中String.equals和==的比较

    主要介绍了java 中String.equals和==的比较的相关资料,需要的朋友可以参考下

    Java中Object.equals和String.equals的区别详解

    主要给大家介绍了Java中Object.equals和String.equals的区别,文中通过一个小示例让大家轻松的明白这两者的区别,对大家具有一定的参考价值,需要的朋友们下面来一起看看吧。

    equals问题经典

    我想问stu1的String name="hck",这个"hck"存在常量池中,它和String s=new String("hck")有什么区别! String s1=new String("abc"); String s2=new String("abc"); s1.equals(s2);结果为true Student stu1=new ...

    String中==与equals区别验证

    String中==与equals区别验证

    StringAPI.java

    1.String和char[]之间的转换 toCharArray(); 2.String和byte[]之间的转换 getBytes() Arrays工具类 : Arrays.toString(names) String类 String replace(char oldChar, char newChar) String replace...

    String.txt

    //创建字符串方式1 String b =new String("abc"); //创建字符串方式2 System.out.println(a==b); //false,内存地址不相等 String c =new String("abc"); String d =new String("abc"); ...

    Java基础复习(内附String中equals与==区别的分析)

    NULL 博文链接:https://771816006-qq-com.iteye.com/blog/1394972

    跟我学Java-day13-String和StringBuilder.pdf

    1.String类 1.1字符串的比较【理解】 1.1.1==号的作用 比较基本数据类型:比较的是具体的值 比较引用数据类型:比较的是对象地址值 1.1.2equals方法的作用 方法介绍 示例代码 1.2用户登录案例【应用】 ...

    JDT生成代码实例

    StringLiteral stringLiteral = ast.newStringLiteral(); stringLiteral.setLiteralValue("中国"); //将其作为引用方法参数 methodInvocation.arguments().add(stringLiteral); //创建变量 ...

    ATM Program

    public static UserInfo loginCheck(String num,String passward) { UserInfo userInfo=null; for(int i=0;i<DataOS.customers.size();i++){ if(DataOS.customers.get(i).num.equals(num) && DataOS....

    java编的简单计算器

    //System.out.println(".".equals(String.valueOf(st.charAt(st.length()-1)))); } } else if(".".equals(e.getActionCommand())){ System.out.println(n); if(n==0&&g==0){ st = jt.getText()...

    autocad objectarx acmgd.dll 导出的.net类资料清单

    Equals(Object) AS System.Boolean GetHashCode() AS System.Int32 GetType() AS System.Type ToString() AS System.String 属性: CurrentMode AS Autodesk.AutoCAD.ApplicationServices.DocumentLockMode 可...

    C# 判断字符为空的6种方法的效率实测对比

    4. strTest.Equals(string.Empty) 5. strTest.Length == 0 6. string.IsNullOrEmpty(strTest) 为了对以上6种方法的效率,有个直观的感受,我特意编写了以下的测试代码: using System; namespace StrTest { class ...

    Android 文件读写源码

    Toast.makeText(getApplicationContext(), R.string.sdcarderror, 1).show(); } } catch (Exception e) { Toast.makeText(getApplicationContext(), R.string.fail, 1).show(); e....

    -互联网Java面试重点难点.rar

    1. JDK 和 JRE 有什么区别? 2. == 和 equals 的区别是什么? 3. 两个对象的 hashCode()相同,则 equals()也一定为 true,对吗? 4. final 在 java 中有什么作用? 5. java 中的 Math.round(-1.5) 等于多少? 6...

    java--scjp考题复习

    equals() B. toLowerCase() C. toUpperCase() D. equalsIgnoreCase() E. none of the above 正确答案: D 931. At the end of these two lines of code: String s="hypertext"; String t=s.substring(2,5); What ...

    Java 面试宝典

    11、"=="和 equals 方法究竟有什么区别? ................................................................. 12 12、静态变量和实例变量的区别? ...............................................................

    字符串完整版.pdf

    1. 字符串的定义:string str=”” string str=new string(new char[]{}); 2. 如果没有使用,系统不会为其编译生成 3. 字符是不可变的---字符串是静态文本值,如果对字符串值做修改,系统会重新为其分配一块空间,...

Global site tag (gtag.js) - Google Analytics