Java 基础之String篇

Java 基础之String篇

这篇推文中基于JDK8来进行讲解,后版本的JDK部分改动会提出来。

JDK中的String

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
}

OK,我们下面看下String的Diagrams:


image

OK,我们先梳理一下String的继承关系。
String类实现了三个接口,分别是Serializable,Compareable,CharSequence。
对于Serializable接口中,并没有需要实现的方法,该接口只是用于表示可以序列化。
对于Compareable接口中,只有一个方法<b>public int compareTo(T o);</b>这个方法主要是用于比较的。
对于CharSequence,它是一个描述字符串结构的接口,里面定义了字符串的最基本的操作。比如获取长度,获取第几位的字符,截取字符。

不知道大家有没有注意到String类使用了final修饰,为什么String类要使用final修饰呢?请继续看下去哦。

String类重要成员变量

  /** The value is used for character storage. */
  // String 的底层便是 char数组。在这里提一下,在JDK9之后,我们String的底层是 byte数组,并且通过coder变量来代表编码格式。
  private final char value[];

  /** Cache the hash code for the string */
  // hash值,这个很重要哦。这个后面会讲到的。
  private int hash; // Default to 0

  // 序列版本号,这个很重要,后面会有一篇推文专门讲序列化的。大家可以期待下。
  /** use serialVersionUID from JDK 1.0.2 for interoperability */
  private static final long serialVersionUID = -6849794470754667710L;

  /**
   * Class String is special cased within the Serialization Stream Protocol.
   *
   * A String instance is written into an ObjectOutputStream according to
   * <a href="{@docRoot}/../platform/serialization/spec/output.html">
   * Object Serialization Specification, Section 6.2, "Stream Elements"</a>
   */
  // serialPersistentFields变量可以指定序列化的数据,在这里并没有指定。
  private static final ObjectStreamField[] serialPersistentFields =
      new ObjectStreamField[0];

不知道大家看到这里,是否注意到我们的char数组也使用了final修饰呢。在这里大家得回忆回忆我们final的作用哦(本推文后面也讲述到了)。注意不管是JDK8中的char数组,还是JDK9之后的byte数组,都是使用了final修饰哦,下面会揭晓为什么。

String类常用的成员方法

在这里只会列举方法名,方法的实现大家可以自行阅读源码。(这里只是列举一部分常用的方法,String因为使用太频繁了,常用方法太多了)

// 获取字符串的长度
public int length() {}
// 判断字符串是否为空
public boolean isEmpty() {}
// 获取索引为index下的字符
public char charAt(int index) {}
// 这个方法是继承自Object对象的,用来比较对象的,大家可以看看在String里面的重写,还是很有意思的。
public boolean equals(Object anObject) {}
// 判断字符串是否是以suffix结尾,比如 laochou.jpg 就可以采用了 endsWith("jpg");
public boolean endsWith(String suffix) {}
// 获取对应字符的索引,索引从0开始。很多人会好奇,为啥参数不是char,因为都一样 'a' = 97
public int indexOf(int ch) {}
// 跟上面一样,但是这个是获取最后一个字符的索引。
public int lastIndexOf(int ch) {}
// 将字符串中的旧字符,替换成我们新字符
public String replace(char oldChar, char newChar) {}
// 截取字符串
public String substring(int beginIndex) {}
public String substring(int beginIndex, int endIndex) {}
// 分割字符串
public String[] split(String regex) {}
// 去重字符串两端的空白字符
public String trim() {}
// 全部转小写
public String toLowerCase() {}
// 全部转大写
public String toUpperCase() {}
// 生成一个字符数组
public char[] toCharArray() {}

如何创建String对象呢

在这里,我只列举一些常见的用法。如果大家想看全部的,可以自行阅读源码。

// 通过字面量直接赋值的方式(字面量就是""里面的东西,比如String a = "laochou",那么laochou就是字面量。)
String a = "";
// 通过new的方式(但是注意参数不同)
// 什么都不传
String b = new String();
// 传空字符串
String c = new String("");
// 传字符数组
String d = new String(new char[]{});
// 传byte数组
String e = new String(new byte[]{});

String对象到底创建在哪里。

String对象创建在哪里,取决于你是通过何种方式来使用的。我前面也讲了一些创建String对象的方式。

<b>在这里我们就细讲一下。</b>

// 通过使用字面量来赋值的,会在String Pool创建String对象,并返回引用地址。
String a = "finger dance";
// 通过new关键字来创建的,分为两种情况
    // 1. 如果对应字面量在String Pool中没有,那么会先在String Pool创建一个对象。然后会在堆中也同样创建一个对象。
    // 2. 如果对应字面量在String Pool中已经存在,那么就只会在堆中创建一个对象。
    // 重点:只要是new关键字,那么就一定会在堆中创建。
String b = new String("laochou");

<b>有一个很重要的方法是intern。</b>。我们通过这个方法可以从String Pool中获取我们需要的字面量对应的对象引用,若有就返回。若无便在String Pool创建对象,并返回引用。因此我们可以通过intern方法后期动态添加对象到String Pool。

String Pool是?

是的,我们在这里,说一下,为什么要考虑使用到String Pool。在这里在提一下,String Pool 和 运行时常量池是不同的哈,后面会有专门一篇推文来讲。

因为在程序编写的过程中,会大量地用到String对象,如果每次声明一个String都要新建一个String对象,那么会造成空间的极大浪费。于是Java的堆中开辟了一块存储空间String Pool,用于存储String对象。当有多个String引用指向同样的String字符串时(New出来的除外),实际上是指向的是同一个String Pool中的对象,而不需要额外的创建对象。

也正是因为如此,String Pool的特性也需要我们String不可变。如果可变的话,那么指向就全会乱。

String是不可变的。

首先,大家得知道被final的作用,下面给大家分享下

  • final 修饰类,代表类不可被继承。那么其成员方法也无法被重写。
  • final 修饰变量,代表变量不可变。对于基本类型,那么值是不可变的。对于引用类型,那么对象是不可变的,但是对象的内容是可以变的。
  • final 修饰方法,代表方法不可重写。

OK,那我们现在就来理一理 String为什么是不可变的。

  • 首先我们String类是被final修饰的,那么String类是不可被继承的,那么它的成员方法就没有机会被重写。
  • 其次我们String类的底层char数组是被final修饰的,那么char数组的地址是无法改变的
  • 最后我们String类中并没有提供修改char数组内容的方法,因此String是不可变的。

看下面的代码

String i = "laochou";
String j = "FingerDance";
// 字符串使用+来拼接的底层其实是使用StringBuilder来操作的。(后面也会有一篇推文来讲String的扩展)
i = j + "_" + i;
System.out.println(i);

这就有人问了,这个i不是变了吗。其实原来i的引用地址所指向的内容并没发生改变,只是i这个引用地址改变了,改成了指向 "FingerDance_laochou" 这个字符串对象的地址。这里我画一个图方便大家理解。


image

String设计不可变有哪些好处

知道String设计成不可变有哪些好处,在面试的过程中如何被问到String,如果提及的话,也是加分项。

String设计成不可变的好处:

  1. 安全问题。在这里解释下,为什么安全?比如在网络传输过程中,字符串的值是不能被改变的。如果可以改变,那么无法保证安全,因为我们可以讲值改为我们任意的。
  2. 线程安全问题。不可变就天生具备线程安全。我们一般提的线程安全都是相对线程安全。
  3. 可以缓存hash值。因为String的hash值经常被使用,比如String作为HashMap的key。不可变的特性可以使得hash值可以进行缓存,因为是不变的。这也是为什么String类中有hash这个成员变量。

String对象如何判断是否相等

有两种方式可以用来判断对象是否相等。:

  • ==,使用等等操作符的时候,不仅会比较对象的内容,也会比较对象的引用地址。只有两者都满足,才相等。
  • equals,使用equals方法,只会比较对象的内容。如果内容相等就是相等。

因此我们需要根据我们的场景来使用这两者来判断String对象是否相等。

Demo:

String f = "laochou";
String g = "laochou";
String h = new String("laochou");
System.out.println(f == g);
System.out.println(f == h);
System.out.println(f.equals(h));

大家可以先小试牛刀看看哦。如果做完了,就可以编写代码试下校对。

关于String的一些面试题。

<b>String 的底层数据结构(根据不同的JDK,说法不同)。</b>
<b>String 为什么设计成不可变,是如何保证不可变的</b>
<b>讲一讲final关键字(这里虽然不是String的面试题,但是由于String被final修饰了,很容易被引出来问)</b>
<b>String是如何比较对象的</b>

这些面试题的答案都可以从推文中找到,这里只是帮大家回忆下推文中的知识。FingerDance后期会整理面试题给大家(专题,大杂烩都会有的呢,大家敬请期待)

最后

以上就是本期的内容了,希望看到这里的小伙伴,能收获一些知识。未来可期!!!

<b><font color="red">创作不易,如果觉得写的不错,还请点赞,关注,转发!!!</font></b>

<b>我是Laochou,一位又老又丑的前行者!!!下期见。</b>

<b>往期推荐:</b>

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,047评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,807评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,501评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,839评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,951评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,117评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,188评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,929评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,372评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,679评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,837评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,536评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,168评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,886评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,129评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,665评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,739评论 2 351

推荐阅读更多精彩内容