本人自学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. DDGScreenShot—图片擦除功能

    写在前面 图片擦除功能,也是运用图片的绘制功能, 将图片绘制后,拿到相应的图片.当然,有一涨底图更明显 实现代码如下 /** ** 用手势擦除图片 - imageView --传图片 - bgView ...

  2. DDGScreenShot — 复杂屏幕截屏(如view ScrollView webView wkwebView)

    写在前面 最近有这么一个需求,分享页面,分享的是web订单截图,既然是web 就会有超出屏幕的部分, 生成的图片还要加上我们的二维码,这就涉及到图片的合成了. 有了这样的需求,就是各种google.也 ...

  3. php中$_FILES应用实例

    允许用户从表单上传文件是非常有用的.先来看一段HTML表单代码 <html> <body> <form action="upload_file.php" ...

  4. ArcticCore重构-问题列表1

    基于官方arc-stable-9c57d86f66be,AUTOSAR版本3.1.5 基本问题 Arctic Core中的代码组织有很多有待改进的地方,这里先提出几点: 1. 头文件引用混乱,所有头文 ...

  5. nginx+php+mysql+wordpress搭建简单站点 安装及配置过程

    环境 阿里云ECS云服务器 CPU:1核 内存:2G 操作系统:Centos 7.3 x64 地域:华北 2(华北 2 可用区 A) 系统盘:40G 安装及配置 主要使用 nginx . php 和 ...

  6. 微信小程序-统一下单、微信支付(Java后台)

    1.首先分享 微信统一下单接口: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1   微信接口 签名 对比网址: https: ...

  7. Net Core动态加载webservice/WCF

    1.动态加载的目的 前端时间和顺丰对接了个项目(PS:顺丰的开发对外能力真的是掉粉),用的webservice 测试时用的无固定IP访问,正式版需要固定IP访问,我的理解是web服务都是全网络可以访问 ...

  8. PAT1004:Counting Leaves

    1004. Counting Leaves (30) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue A fam ...

  9. 重写equals时,遵守的规定

      0 正确的equals方法 public class MyClass { // 主要属性1 private int primaryAttr1; // 主要属性2 private int prima ...

  10. Spring Cloud Sleuth服务链路追踪(zipkin)(转)

    这篇文章主要讲述服务追踪组件zipkin,Spring Cloud Sleuth集成了zipkin组件. 一.简介 Spring Cloud Sleuth 主要功能就是在分布式系统中提供追踪解决方案, ...