【java基础】浅析String

来源:互联网 发布:美国 二战 知乎 编辑:程序博客网 时间:2024/05/16 00:40

一、String类

  字符串广泛应用 在Java 编程中,在 Java 中字符串属于对象,Java 提供了 String 类来创建和操作字符串。String类的基本用法就不赘述了,请参考《Java String 类|菜鸟教程》。

二、String是不可变的

2.1 不可变对象

  不可变对象(immutable Object)就是那些一旦被创建,它们的状态就不能被改变的Objects,每次对他们的改变都是产生了新的immutable的对象。而mutable Objects就是那些创建后,状态可以被改变的Objects.
  如果一个类被设计成不可变的类 ,那么这个类的实例化对象是不可变的。

2.2 不可变类的特点

 不可变类有以下特点:

  • 这个类被声明为final类,以此来限制子类继承父类,以避免子类改变了父类的immutable特性;
  • 类的成员变量都是final并且是私有的;
  • 如果成员变量是一个引用类型,是可变的,那么在他的getter()方法中,返回的是对该对象的拷贝。

2.3 String类

在JDK1.7中,String类部分源码如下:

public final class String    implements java.io.Serializable, Comparable<String>, CharSequence {    /** The value is used for character storage. */    private final char value[];    /** Cache the hash code for the string */    private int hash; // Default to 0

  可以看出String类的定义是基本符合上面所说的不可变类的特点的,只有“hash”存在疑问。
  hash变量用于缓存字符串的哈希码(Cache the hash code for the string)。而hashCode()方法用于得到字符串对象的哈希码,源码及注释如下:

//计算字符串的哈希码public int hashCode() {        int h = hash;        //1.如果哈希码没有被计算过(hash==0),并且字符串不为空,则计算哈希码;        //2.如果被计算过(调用过hashCode()方法),则直接返回变量hash的值(第一次调用hashCode()时赋给hash的值).        if (h == 0 && value.length > 0) {            //hash的值有value计算得到            char val[] = value;            for (int i = 0; i < value.length; i++) {                h = 31 * h + val[i];            }            //将计算得到的哈希码值赋值给成员变量hash            hash = h;        }        return h;    }

  由上边源码及注释可以得出,hash虽然不是final,但它是通过计算final属性value得来的,并且能保证每次调用它的值都是一致的。所以String是不可变的。

三、为什么看起来变了?

  既然String是不可变的,那为什么在使用时总会遇见“变”的情况?下面分析一下几个常见的误区:

3.1 误区一:对象与对象的引用

 //1.误区一:引用 String str = "123"; System.out.println("str="+str); str = "456"; System.out.println("str="+str);

输出结果:str=123
     str=456
     
  从输出结果来看,str的值确实改变了,从“123”变成了“456”,这里就是存在的第一个误区。
  str其实是一个对象的引用,里面存放的是它所指向的对象的地址,并不是对象本身
  所以以上的代码可以解释为:str本来指向对象“123”(即str存放的是对象“123”的地址)。执行语句str=”456”;创建一个新的对象”456”,然后引用str重新指向这个新的对象。但是,原来的对象”123”仍然在内存中存在,并没有改变。

3.2误区二:字符串常量池

//2.常量池//字面量形式创建字符串对象String str1 = "abc";String str2 = "abc";System.out.println("str1==str2:"+(str1==str2)); //true//new创建字符串对象String str3 = new String("abc");String str4 = new String("abc");System.out.println("str3==str4:"+(str3==str4)); //false

输出结果:str1==str2:true
     str3==str4:false
     
  java中字符串对象创建有两种形式,一种是字面量形式,另一种是使用new这种标准的构造对象的方法。 
  字面量形式:当代码中出现字面量形式创建字符串对象时,JVM首先会对这个字面量进行检查。如果字符串常量池中存在相同内容的字符串对象的引用,则将这个引用返回,不创建新的对象;否则新的字符串对象被创建,然后将这个引用放入字符串常量池,并返回该引用。
  new创建:使用new来创建字符串对象,不管字符串常量池中有没有相同内容的对象的引用,新的字符串对象都会创建。

3.3误区三:调用String类的方法

//调用String类的方法String str5 = new String("abcdef");System.out.println("str5="+str5);str5 = str5.replace('c', 'Z');System.out.println("str5="+str5);str5 = str5.substring(2, 4);System.out.println("str5="+str5);

输出结果:str5=abcdef
     str5=abZdef
     str5=Zd

  在String中,调用某些方法(如replace、substring等)后可以得到改变后的值。那不是说明String对象能通过String类中的方法改变吗?这也是一个误区。
  避免这个误区其实只需要记住不可变对象的一个特点即可:immutable对象的状态在创建之后就不能发生改变,任何对它的改变都应该产生一个新的对象。
  为了验证,我们可以查看String类中replace、substring方法的源代码。这里省略掉方法实现的细节,直接查看在调用方法后的返回值。
  
replace方法中:

return new String(buf, true);

substring方法中:

return ((beginIndex == 0) && (endIndex == value.length))  ? this : new String(value, beginIndex, subLen);

  可以看出在调用replace、substring方法后都会产生一个新的String对象。其他类似的方法也是如此。

参考资料

如何创建不可变(Immutable)的Java类或对象
Java中的String为什么是不可变的? – String源码分析
为什么String要设计成不可变的?
Java中的字符串常量池
Java细节:字符串的拼接

1 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 哺乳期上火怎么办吃什么下火 前扣内衣有点紧怎么办 橱柜做了小10厘米怎么办 一个月宝宝体检胸围35怎么办 月经量少脸上长斑怎么办 下压100上压160怎么办 怎么办去台湾新的驻签 学生去韩国旅游签证怎么办 猪的眼睛赛肿了怎么办 纹眉没有修复霜怎么办 衣服搞到走珠露香水洗不掉怎么办 涂牙膏把脸烧伤怎么办 月经血排不出来怎么办 猫眼角膜掉了一块怎么办 腰酸痛直不起腰怎么办 白血病移植后复发了怎么办 斐讯k2红灯常亮怎么办 洗衣机把烟洗了怎么办 吸烟吸的恶心想吐怎么办 显示双方信息的明细怎么办 电脑关不了机了怎么办 xp系统关不了机怎么办 灯的开关闭不了怎么办 灯的开关按不动怎么办 灯开关按不动了怎么办 灯的开关摁不动怎么办 微信群500人满了怎么办 作业帮搜不到题目怎么办呢 金融社保卡密码忘了怎么办 工作未完想从国企辞职怎么办 宫腔粘连术后流血多怎么办 宫腔粘连术后一直流血怎么办? cad图框放不下图怎么办 简历假的入职怎么办 脱贫攻坚怎么看怎么办怎么干 吃的下没力气怎么办 恢复留查公示后怎么办 微语简报删了怎么办 小学生未完成作业作为老师怎么办 抽调人员想回原单位怎么办 扫码支付没成功怎么办