初学 Java 有段时间了,感觉似乎开始入了门,有了点儿感觉但是发现很多困惑和疑问而且均来自于最基础的知识折腾了一阵子又查了查书,终于对 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 != s2s1 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 ,让说你什么好呢?你为们 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 这个迷乱的家伙所迷惑! 
它输出:equalsWHY!!! 
把程序简单的更改一下: 
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 equalsOh 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, CharSequencepublic final class StringBuffer implements Serializable, CharSequence很明显的,小弟少了一些东东,不过这不会干扰它的前途StringBuffer 不是由 String 继承来的不过要注意兄弟它也是 final 啊,本是同根生看看他的方法吧,这么多稳定可靠的方法,用起来比顽皮的 String 要有效率的多? 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 wisdomstr.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对象的时候。
 

【Java】整理关于java的String类,equals函数和比较操作符的区别的更多相关文章

  1. string类find函数返回值判定

     string类find函数返回值判定 代码示例 #include<iostream> #include<cstring> using namespace std; int m ...

  2. C++string类常用函数

    C++string类常用函数 string类的构造函数:string(const char *s);    //用c字符串s初始化string(int n,char c);     //用n个字符c初 ...

  3. [Java初探04]__字符串(String类)相关

    前言 接下来将暂时将重心偏移向实际操作,不在将大量时间花费在详细的知识点整理上,将会简略知识总结笔记的记录,加强实际练习的时间,实例练习篇也不再同步进行,我会将部分我觉得重要的源码更新在每节知识点后面 ...

  4. Java学习笔记19(String类)

    String代表字符串,在Java中,所有的字符串字面值都作为此类的实例实现 字符串的特点以及简单的原理分析: package demo; /* * String类的特点: * 所有的"&q ...

  5. Java技术——你真的了解String类的intern()方法吗

    0.引言 什么都先不说,先看下面这个引入的例子:   String str1 = new String("SEU")+ new String("Calvin") ...

  6. java Vamei快速教程13 String类

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 之前的Java基础系列中讨论了Java最核心的概念,特别是面向对象的基础.在Jav ...

  7. java源码解析之String类(三)

    上一节我们主要讲了String类的一些不是很常用的方法,其中需要掌握的如下,我就不再赘述了 public int length() public boolean isEmpty() public by ...

  8. Java入门 - 语言基础 - 14.String类

    原文地址:http://www.work100.net/training/java-string.html 更多教程:光束云 - 免费课程 String类 序号 文内章节 视频 1 概述 2 创建字符 ...

  9. java基础源码 (1)--String类

    这个是String类上面的注释,我用谷歌翻译翻译的,虽然有点语法上的问题,但是大概都可以翻译出来 /** * The {@code String} class represents character ...

随机推荐

  1. TCP keepalive

      2. TCP keepalive overview In order to understand what TCP keepalive (which we will just call keepa ...

  2. spring入门之helloworld

    1.第一个spring例子 1.建立工程 建立一个java project就可以. 导包,helloworld包括下面两个最少的包: 到http://www.springsource.org/down ...

  3. LabVIEW系列——自定义错误

    1.自定义错误代码文本文件在labview中三处:      a).E:\Program Files\National Instruments\LabVIEW 8.6\project\errors   ...

  4. android开发之记录ListView滚动位置

    这个问题本身不难,但是由于项目中的需求太过于复杂,结果导致这个问题变得不是那么容易实现.在网上一搜,结果如下: 我不知道是who copy who?反正介绍的所谓的三种方法,第一种都是无法运行的,很明 ...

  5. 更多隐式Intent用法

    上几篇无论是显示的Intent或者隐式的Intent,都是要跳转的自己添加指定的页面,如果想要跳转到百度首页或者跳转到联系人面板等,前面的知识显然是很不实用的.这里,将要针对其它的一些Intent用法 ...

  6. Lucida Grande字体无法正常显示冒号的解决方案

    曾经贪图Mac OSX的UI漂亮,后来查到它用的是Lucida Grande字体,所以索性将win7也改成了那种字体,结果浏览器中的中文冒号全都显示为一个奇怪的符号.后来即使将字体设置回去也无法还原. ...

  7. JS获取页面上所有input

    for (var i = 0; i < document.getElementsByTagName("input").length; i++) { if (document. ...

  8. AUTOTRACE Statistics常用列解释

    AUTOTRACE Statistics常用列解释 序号 列名 解释 1 db block gets 从buffer cache中读取的block的数量 2 consistent gets 从buff ...

  9. SQL的数据类型

    Character 字符串: 数据类型 描述 存储 char(n) 固定长度的字符串.最多 8,000 个字符. N的范围1-8000 varchar(n) 可变长度的字符串.最多 8,000 个字符 ...

  10. 《转》15种CSS混合模式让图片产生令人惊艳的效果

    浏览器支持 按照现在情况来讲, 浏览器支持 CSSbackground-blend-mode属性还在不断的完善中.早期版本的浏览器目前还不支持,但caniuse.com报告说在Chrome,Firef ...