简单聊聊String的一些源码……

简介: 简单聊聊String的一些源码……

简单聊聊String的一些源码……

1.1 不变性

先瞅瞅 String 在JDK源码中的定义:

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];

从源码中,我们可以看到不可变的原因:

1.String被final修饰,说明 String 类不能被继承,String 的方法都不会被覆盖;2.String 中保存数据的是一个 char 数组(value)。value 也是被final修饰的,也就是value一旦被赋值,内存地址是绝对无法修改的,而且 value 的权限是private的,String 也没有开放出可以对 value 进行赋值的方法,外部绝对无法访问,所以说 value 一旦产生,内存地址就根本无法被修改。

如果要自定义一个不可变类,可以借助 String 的这种操作,利用final关键字的特性。

String具有不可变行,所以 String 的大多数方法都会返回新的 String

String s = "abc";
// 替换失败
s.replace("b","d");
// 正确操作需要一个参数接收返回值
s = s.replace("b","d");

1.2 字符串乱码

字符串乱码往往是转换过程中,字符编码不统一造成的。

解决办法:所有用到编码的地方指定编码方式,使用 UTF-8。(ISO-8859-1对中文的支持有限,所以包含中文的时候不建议使用ISO-8859-1)

1.3 首字母大写

如果我要在让一个字符串的首字母小写,那么这时候该怎么办呢?

name.substring(0,1).toLowerCase() + name.substring(1);

主要使用Java的两个方法:

1.publice String substring(int beginIndex, int endIndex):beginIndex表示开始位置,endIndex表示结束位置。(这是左闭右开的操作)2.public String substring(int beginIndex):beginIndex表示开始位置,结束位置为文本末尾

如果要修改首字母大写,则

name.substring(0,1).toUpperCase + name.substring(1)

首字母小写的应用场景,比如反射的场景下类的属性名。

1.4 相等判断(equals)

判断相等有两种方法:equalsequalsIgnoreCase。后者判断时忽略大小写

如果让你判断两个String相等的逻辑,应该如何设计代码?

JDK源码

public boolean equals(Object anObject) {
    // 判断内存地址是否相等
    if (this == anObject) {
        return true;
    }
    // 判断待比较的对象是否是String,如果不是String,直接返回不相等
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        // 判断两个字符串的长度是否相等,不等则直接返回不相等
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            // 一次比较每个字符是否相等,若有一个不等,直接返回不相等
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

如果要设计代码判断两者是否相等时,我们可以参考String的方式,从两者的底层结构出发。先判断地址,再判断数据类型,最后就像 String 底层的数据结构是 char 的数组一样时,就挨个比较 char 数组中的字符是否相等即可

1.5 替换、删除(replace)

str.replace(char oldChar, char newChar) :替换所有匹配的字符。如果没有匹配的字符,返回的还是原来的对象,并不是新的对象。

JDK源码

public String replace(char oldChar, char newChar) {
    if (oldChar != newChar) {
        int len = value.length;
        int i = -1;
        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 = 0; j < i; j++) {
                buf[j] = val[j];
            }
            while (i < len) {
                char c = val[i];
                buf[i] = (c == oldChar) ? newChar : c;
                i++;
            }
            return new String(buf, true);
        }
    }
    return this;
}

replace(CharSequence target, CharSequence replacement) :替换所有的匹配的字符串。不支持正则表达式

JDK源码

// Pattern.compile(target.toString(), Pattern.LITERAL)匹配时把正则特殊字符转为普通字符。
// Matcher.quoteReplacement 匹配的结果特殊字符转为普通字符主要是$和\。
public String replace(CharSequence target, CharSequence replacement) {
    return Pattern.compile(target.toString(), Pattern.LITERAL).matcher(this).replaceAll(Matcher.quoteReplacement(replacement.toString()));
}

replaceAll(String regex, String replacement):替换所有的匹配的字符串。支持正则表达式。

JDK源码

public String replaceAll(String regex, String replacement) {
    return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}

replaceFirst(String regex, String replacement):替换匹配到的第一个字符串,支持正则。

JDK源码

public String replaceFirst(String regex, String replacement) {
    return Pattern.compile(regex).matcher(this).replaceFirst(replacement);
}

字符串的删除可以通过替换,把需要删除的字符替换成 "" 即可。

1.6 拆分(split)

split方法,该方法有两个参数,第一个参数是我们拆分的标准字符,第二个参数是一个 int 值(limit),用来限制我们需要拆分几个元素。如果 limit 比实际能拆分的个数小,按照 limit 的个数进行拆分。

String  s = "abb:dce:fbb";
// 默认情况下limit为0,结果:[abb, dce, fbb]
System.out.println(Arrays.toString(s.split(":")));
// 结果:[abb, dce:fbb]
System.out.println(Arrays.toString(s.split(":",2)));
// 结果:[abb, dce, fbb]
System.out.println(Arrays.toString(s.split(":",-1)));

如果字符串中存在空值,空值也会被拆分出来,但是最后的空值不管出现几个都不会出现。

String  s = "abb:dce:fbbb";
// 输出:[a, , :dce:f]
System.out.println(Arrays.toString(s.split("b")));

1.7 合并(join)

public static String join(CharSequence delimiter, CharSequence... elements) ,此方法是静态的,我们可以直接使用。第一个参数是合并的分隔符,第二个是合并的数据源,可变参数支持数组和 List 集合。

两个缺点:

1.不支持依次 join 多个字符串。String.join("," s1).join(",",s2),最后得到的是s1的值,第一次 join 的值s1会被第二次 join 的s2覆盖了;2.如果 join 的是一个 List ,无法自动过滤掉 null 值。

谷歌的 Guava 正好提供了 API 可以解决上述问题。

目录
相关文章
|
2月前
|
Kubernetes jenkins 持续交付
从代码到k8s部署应有尽有系列-java源码之String详解
本文详细介绍了一个基于 `gitlab + jenkins + harbor + k8s` 的自动化部署环境搭建流程。其中,`gitlab` 用于代码托管和 CI,`jenkins` 负责 CD 发布,`harbor` 作为镜像仓库,而 `k8s` 则用于运行服务。文章具体介绍了每项工具的部署步骤,并提供了详细的配置信息和示例代码。此外,还特别指出中间件(如 MySQL、Redis 等)应部署在 K8s 之外,以确保服务稳定性和独立性。通过本文,读者可以学习如何在本地环境中搭建一套完整的自动化部署系统。
58 0
|
2月前
|
存储 编译器 C语言
C++ --> string类模拟实现(附源码)
C++ --> string类模拟实现(附源码)
61 4
|
5月前
|
存储 Java
Java基础复习(DayThree):字符串基础与StringBuffer、StringBuilder源码研究
Java基础复习(DayThree):字符串基础与StringBuffer、StringBuilder源码研究
Java基础复习(DayThree):字符串基础与StringBuffer、StringBuilder源码研究
|
4月前
|
存储 缓存 安全
java源码之String详解
java源码之String详解
25 0
|
4月前
|
安全 Java 数据安全/隐私保护
Java基础4-一文搞懂String常见面试题,从基础到实战,更有原理分析和源码解析!(二)
Java基础4-一文搞懂String常见面试题,从基础到实战,更有原理分析和源码解析!(二)
40 0
|
4月前
|
JSON 安全 Java
Java基础4-一文搞懂String常见面试题,从基础到实战,更有原理分析和源码解析!(一)
Java基础4-一文搞懂String常见面试题,从基础到实战,更有原理分析和源码解析!(一)
58 0
|
5月前
qt初入门0:结构体中QString用memset导致崩溃分析及QLatin1String简单查看源码
qt初入门0:结构体中QString用memset导致崩溃分析及QLatin1String简单查看源码
225 0
|
5月前
|
安全 API
详解StringBuilder和StringBuffer(区别,使用方法,含源码讲解)
详解StringBuilder和StringBuffer(区别,使用方法,含源码讲解)
102 0
|
存储 消息中间件 缓存
从源码上聊聊Redis-String、List的结构实现
本文的数据类型只讲底层结构和部分机制,不讲具体的使用,使用的话自行bing,但是会提一些应用场景
166 1
从源码上聊聊Redis-String、List的结构实现
|
12月前
|
存储 安全 编译器
Go语言源码剖析-String和unsafe包
Go语言源码剖析-String和unsafe包
66 0