本人自学java两年,有幸初入这个行业,所以功力尚浅,本着学习与交流的态度写一些学习随笔,什么错误的地方,热烈地希望园友们提出来,我们共同进步!这是我入园写的第一篇文章,写得可能会很乱。

一、什么是String

  String是java中的一个类,位于java.lang包中,也就是我们平常所说的字符串。字符串是我们在编程的过程中用到最多的类,同时在面试中也经常会出现相关的面试题,所以掌握String字符串的特性是很有必要,不仅可以提高对java的理解,同时还能有助于提高编写程序的质量。

  从源码中我们可以看到,其实String内部维护的是一个char数组,对于字符串的操作,其实就是对内部数组的操作。值得注意的是,char数组是用final关键字修饰,也就是说每一次创建字符串的时候,都会创建一个对象(String不变性)

 /** The value is used for character storage. */
private final char value[];

二、String对象的创建

  最常用的字符串创建的方式有两种,第一种是直接用字面量的引用来创建,第二种是用new关键字来创建。两种创建方式存在很大的区别,上面有提到,字符串是不可变的,所以每次创建时都会创建一个新的对象,如果这样一直创建下去的话,势必会浪费很多的内存,java为了解决这个问题提高程序的性能,用第一种方式创建字符串的时候,首先,会先判断创建的字符串在常量池中是否已经存在,如果存在,则将引用指向它,否则创建新的字符串并在常量池中缓存起来,这样一来创建相同的字符串时只需要将引用指向常量池中已存在的字符串即可,无需再创建,从而节约内存;第二种用new关键字创建,这种方式无论常量池中是否已经创建都会创建一个新的对象,所以本人推荐在平常创建字符串的时候使用第一种方式。如下代码可验证:

     String a = "aaa";
        String b = "aaa";
        String c = new String("aaa");
        String d = new String("aaa");
        System.out.println(a == b);//发回true
        System.out.println(a == c);//返回false
        System.out.println(c == d);//返回false

三、String对象的使用

  String中有非常多的api,下面我将介绍一种常用的api:

  1、public char charAt(int index)

  获取指定位置的字符,index指定位置,源码如下:

    public char charAt(int index) {
if ((index < ) || (index >= value.length)) {
throw new StringIndexOutOfBoundsException(index);
}
return value[index];
}

这个方法非常简单,通过传入的数字来获取到数组中对应的下标位置的值,然后直接返回该值即可;

应用场景:获取字符串中指定位置的字符,但是一次只能获取一个字符。

  2、public boolean startsWith(String prefix, int toffset)

  这个方法可以用来判断字符串是否以指定的字符或字符串开始,如果是返回true,否则返回false。有两个重载的方法:

  (1)startsWith(String prefix, int toffset):prefix是指需要与原字符串匹配的字符串,toffset是指开始匹配的位置:

 public boolean startsWith(String prefix, int toffset) {
char ta[] = value;//原字符串
int to = toffset;
char pa[] = prefix.value;//匹配字符串
int po = ;
int pc = prefix.value.length;
// Note: toffset might be near -1>>>1.
if ((toffset < ) || (toffset > value.length - pc)) {
return false;
}
    //这里是主要的判断逻辑
while (--pc >= ) {
if (ta[to++] != pa[po++]) {
return false;
}
}
return true;
}

  (2)startsWith(String prefix):默认从第一个字符串开始匹配

 public boolean startsWith(String prefix) {
return startsWith(prefix, );
}

  3、public String substring(int beginIndex, int endIndex)

  这个方法是用来截取指定字符串长度方法,返回一个新的字符串。

    public String substring(int beginIndex, int endIndex) {
if (beginIndex < ) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
if (endIndex > value.length) {
throw new StringIndexOutOfBoundsException(endIndex);
}
     //截取字符串长度
int subLen = endIndex - beginIndex;
if (subLen < ) {
throw new StringIndexOutOfBoundsException(subLen);
}
    //调用构造方法
return ((beginIndex == ) && (endIndex == value.length)) ? this
: new String(value, beginIndex, subLen);
}

构造方法:

 public String(char value[], int offset, int count) {
if (offset < ) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count <= ) {
if (count < ) {
throw new StringIndexOutOfBoundsException(count);
}
if (offset <= value.length) {
this.value = "".value;
return;
}
}
// Note: offset or count might be near -1>>>1.
if (offset > value.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
this.value = Arrays.copyOfRange(value, offset, offset+count);
}

这个构造方法主要看Arrays.copyOfRange复制数组的方法,其中value是原数组,offset是开始复制的位置,offset+count是需要复制的长度,该方法返回一个新的数组存放在String维护的数组中,完成字符串的截取。

  4、public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin)

  该方法是将当前字符串从 srcBegin 位置到 srcEnd 结束为长度截取字符串放入到 dst 中,从 dstBegin 位置开始放

 public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
if (srcBegin < ) {
throw new StringIndexOutOfBoundsException(srcBegin);
}
if (srcEnd > value.length) {
throw new StringIndexOutOfBoundsException(srcEnd);
}
if (srcBegin > srcEnd) {
throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
}
System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
}

从源码中可以看到,该方法调用了数组复制的方法 System.arraycopy ,其实看了String源码都知道 该类中大量使用了arraycopy这个方法,原因是String内部维护的是一个不可变的数组,所以在对数组进行操作的时候都是要创建新的数组(新的字符串)进行操作。所以非常有必要说一下System.arraycopy这个方法,源码如下:

     /*
   * @param src the source array.
* @param srcPos starting position in the source array.
* @param dest the destination array.
* @param destPos starting position in the destination data.
* @param length the number of array elements to be copied.
* @exception IndexOutOfBoundsException if copying would cause
* access of data outside array bounds.
* @exception ArrayStoreException if an element in the <code>src</code>
* array could not be stored into the <code>dest</code> array
* because of a type mismatch.
* @exception NullPointerException if either <code>src</code> or
* <code>dest</code> is <code>null</code>.
*/
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);

这是一个本地静态方法,没有返回值

  src:原数组

  srcPos:原数组开始被复制的位置

  dest:目标数组

  destPos:开始放复制字符的地方

  length:复制的长度

  5、public String concat(String str)

  连接两个字符串,这个方法比较少用到,在写代码时基本没有用过:

public String concat(String str) {
int otherLen = str.length();
if (otherLen == ) {
return this;
}
     //当前字符串长度
int len = value.length;
      //复制当前字符串维护的数组到 buf中,长度为当前字符串长度加拼接字符串长度
char buf[] = Arrays.copyOf(value, len + otherLen);
     //将 str 的字符放到 buf 中
str.getChars(buf, len);
return new String(buf, true);
}

步骤:创建一个两个拼接字符串长度之和大小的数组,然后将两个字符串放入改数组中即可

  6、public static String valueOf(char c)

  这个方法是将指定数据类型转换成字符串类型,有非常多重载的方法,8个基本数据类型基本都有,比较简单,就不用多说了。

  7、public String replace(char oldChar, char newChar)

  该方法将字符串中出现的字符 oldChar 全部替换成 newChar

public String replace(char oldChar, char newChar) {
if (oldChar != newChar) {
int len = value.length;
int i = -;
char[] val = value; /* avoid getfield opcode */
       //获取到需要替换字符第一次出现的地方
while (++i < len) {
if (val[i] == oldChar) {
break;
}
}
if (i < len) {
         //临时字符数组
char buf[] = new char[len];
         //将第一次出现替换字符之前的所有字符放到临时字符数组中
for (int j = ; j < i; j++) {
buf[j] = val[j];
}
         //替换字符
while (i < len) {
char c = val[i];
            //将oldChar替换成newChar
buf[i] = (c == oldChar) ? newChar : c;
i++;
}
return new String(buf, true);
}
}
return this;
}

  8、public String replaceAll(String regex, String replacement)

  将当前字符串中出现的regex替换成replacement

  9、public String trim()

  去掉字符串前后的空格(不能去除中间部分)

public String trim() {
int len = value.length;
int st = ;
char[] val = value; /* avoid getfield opcode */ while ((st < len) && (val[st] <= ' ')) {
st++;
}
while ((st < len) && (val[len - ] <= ' ')) {
len--;
}
return ((st > ) || (len < value.length)) ? substring(st, len) : this;
}

  9、public String[] split(String regex, int limit)

  将字符串按照regex规则分割成若干字符串数组,并返回。limit:如果大于0,最多返回limit大小的数组,如果为0,则返回全部可能存在的字符串数组,该方法还有个重载方法,就是不用传入limit参数,与limit等于0的情况是一样的。

  结语:

  1、第一次写东西,所以写得很乱

     2、可能因为自己功力不行,所以感觉整片文章都是粘贴源码的,没有太多实质性的东西

     3、喜欢java的同学,欢迎一起讨论,我们共同进步

jdk源码阅读笔记-String的更多相关文章

  1. jdk源码阅读笔记-LinkedHashMap

    Map是Java collection framework 中重要的组成部分,特别是HashMap是在我们在日常的开发的过程中使用的最多的一个集合.但是遗憾的是,存放在HashMap中元素都是无序的, ...

  2. jdk源码阅读笔记-ArrayList

    一.ArrayList概述 首先我们来说一下ArrayList是什么?它解决了什么问题?ArrayList其实是一个数组,但是有区别于一般的数组,它是一个可以动态改变大小的动态数组.ArrayList ...

  3. jdk源码阅读笔记-HashSet

    通过阅读源码发现,HashSet底层的实现源码其实就是调用HashMap的方法实现的,所以如果你阅读过HashMap或对HashMap比较熟悉的话,那么阅读HashSet就很轻松,也很容易理解了.我之 ...

  4. JDK源码学习笔记——String

    1.学习jdk源码,从以下几个方面入手: 类定义(继承,实现接口等) 全局变量 方法 内部类 2.hashCode private int hash; public int hashCode() { ...

  5. jdk源码阅读笔记

    1.环境搭建 http://www.komorebishao.com/2020/idea-java-jdk-funyard/ 2. 好的源码阅读资源 https://zhuanlan.zhihu.co ...

  6. jdk源码阅读笔记-Integer

    public final class Integer extends Number implements Comparable<Integer> Integer 由final修饰了,所以该 ...

  7. jdk源码阅读笔记-HashMap

    文章出处:[noblogs-it技术博客网站]的博客:jdk1.8源码分析 在Java语言中使用的最多的数据结构大概右两种,第一种是数组,比如Array,ArrayList,第二种链表,比如Array ...

  8. jdk源码阅读笔记-LinkedList

    一.LinkedList概述 LinkedList的底层数据结构为双向链表结构,与ArrayList相同的是LinkedList也可以存储相同或null的元素.相对于ArrayList来说,Linke ...

  9. jdk源码阅读笔记-AbstractStringBuilder

    AbstractStringBuilder 在java.lang 包中,是一个抽象类,实现 Appendable 接口和 CharSequence 接口,这个类的诞生是为了解决 String 类在创建 ...

随机推荐

  1. Scala编程入门---面向对象编程之对象

    对象 Object,相当于class单个实例,通常在里面放一些静态的filed或method 第一次调用object方法时候,就会执行object的constructor,也就是Object中不在me ...

  2. Python flask中的配置

    当你开始学习Flask时,配置看上去是小菜一碟.你仅仅需要在config.py定义几个变量,然后万事大吉. 然而当你不得不管理一个生产上的应用的配置时,这一切将变得棘手万分. 你不得不设法保护API密 ...

  3. java 字符串池【转】

    java 字符串池 java运行环境有一个字符串池.比如String str="abc"时,会首先查看字符串池中是否存在字符串"abc",如果存在则直接将&qu ...

  4. WEB自动化(Python+selenium)的API

    在做Web自动化过程中,汇总了Python+selenium的API相关方法,给公司里的同事做了第二次培训,分享给大家                                         ...

  5. [CVPR2017] Deep Self-Taught Learning for Weakly Supervised Object Localization 论文笔记

    http://openaccess.thecvf.com/content_cvpr_2017/papers/Jie_Deep_Self-Taught_Learning_CVPR_2017_paper. ...

  6. cmd连接Oracle数据库成功后输入sql语句返回 2

    解决办法 : sql语句后一定要跟分号  .

  7. MAMP环境下为Mac OSX安装设置PHP开发环境

    一.简单介绍: PHP 页需要通过 Web 服务器处理.因此,要在 PHP 进行开发,您需要访问支持 PHP 的 Web 服务器和 MySQL 数据库.phpMyAdmin 也很实用,它是 MySQL ...

  8. 关于new date()获取服务器时间与linux系统时间不一致的解决办法 2017.12.6

    在catalina.sh  第一行添加一下脚本JAVA_OPTS="$JAVA_OPTS -Dfile.encoding=UTF8 -Duser.timezone=GMT+08"

  9. Linux上配置使用iSCSI详细说明

    本文详细介绍iSCSI相关的内容,以及在Linux上如何实现iSCSI. 第1章 iSCSI简介 1.1 scsi和iscsi 传统的SCSI技术是存储设备最基本的标准协议,但通常需要设备互相靠近并用 ...

  10. Oracle解锁scott账号

    在安装Oracle的最后一步,有一个口令管理的操作,当时忘了给scott账号解锁了(Oracle为程序测试提供的一个普通账户,口令管理中可以对数据库用户设置密码,默认是锁定的).现在想给scott这个 ...