码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • Java源码分析 | CharSequence


    本文基于 OracleJDK 11, HotSpot 虚拟机。

    CharSequence 定义

    CharSequence 是 java.lang 包下的一个接口,是 char 值的可读序列, 即其本身描述的就是字符串。因此我们可以直接使用如下:

    CharSequence cs1 = "朝雾轻寒";  // 默认实现为 String
    CharSequence cs2 = new StringBuilder("朝雾轻寒");
    CharSequence cs3 = new StringBuffer("朝雾轻寒");
    

    扩展

    char 数据类型是基于原始 Unicode 规范,Unicode 标准定义了合法代码点(code point)的范围是 U+0000 到 U+10FFFF,称为 Unicode scalar value。其中从 U+0000 到 U+FFFF 的字符集称为基本多语言平面 (BMP),码位大于 U+FFFF 的字符集称为补充平面。

    一个 char 值表示基本多语言平面(BMP)代码点,可以是代理代码点或 UTF-16 编码的代码单元。一个 int值表示所有 Unicode 代码点,包括补充代码点。低(最低有效)21 位int用于表示 Unicode 代码点,高(最高)11 位必须为零。

    只接受char值的方法不支持补充字符。

    CharSequence 提供了对多种不同类型的 char 序列的统一只读访问,它有如下的实现类,如 String、StringBuffer、StringBuilder、CharBuffer 类等。

    ![image-20220823114718245](/Users/charlie/Pictures/typora/Java源码分析 | CharSequence/image-20220823114718245.png)

    此接口不修改equals 和hashCode 方法的常规协定。因此,通常未定义比较实现 CharSequence 的两个对象的结果。每个对象都可以通过一个不同的类实现,而且不能保证每个类能够测试其实例与其他类的实例的相等性。因此,使用任意 CharSequence 实例作为集合中的元素或映射中的键是不合适的。

    方法

    length()

    该方法的作用是返回此字符序列的长度。长度是序列中 16 位 char 的个数。

    int length();
    

    charAt(int index)

    该方法的作用是返回指定索引处的 char 值。索引范围从零到length() - 1,与数组的索引一样。如果char索引指定的值是 surrogate,则返回代理值。

    char charAt(int index);
    

    注意:如果 index 超出索引范围,则会抛出 IndexOutOfBoundsException异常。

    subSequence(int start, int end)

    该方法的作用是返回一个 CharSequence 序列的子序列。该子序列以char指定索引处的值开始,以索引处的char值结束end - 1。返回序列的长度(以char为单位)为end - start,因此如果start == end 返回一个空序列。

    CharSequence subSequence(int start, int end);
    

    注意: 如果 start 或 end 超出索引范围,或者 start大于end,则会抛出 IndexOutOfBoundsException异常。

    toString()

    该方法是返回以与此序列相同的顺序返回包含此序列中字符的字符串。字符串的长度就是这个序列的长度。

    public String toString();
    

    这是重写了 Object 方法, Object 类不需要显示的继承。

    chars()

    该方法在 JDK1.8 中加入,其作用是返回此序列中int值的零扩展流。char任何映射到代理代码点的字符都会未经解释地传递。如果在读取流时发生了突变,则结果是未定义的。

    public default IntStream chars() {
       			// 实现了int原语迭代器
            class CharIterator implements PrimitiveIterator.OfInt {
                int cur = 0;
    						// 如果迭代器中还有元素,则返回true。
                public boolean hasNext() {
                    return cur < length();
                }
    						 // 返回迭代器中的下一个元素
                public int nextInt() {
                    if (hasNext()) {
                        return charAt(cur++);
                    } else {
                        throw new NoSuchElementException();
                    }
                }
    						 /* 对每个剩余元素执行指定的操作,直到所有元素。
                   已被处理或动作引发异常。行动是
                   按照迭代顺序执行,如果指定了该顺序。
                   由操作引发的异常会传递给调用者。*/
                @Override
                public void forEachRemaining(IntConsumer block) {
                    for (; cur < length(); cur++) {
                        block.accept(charAt(cur));
                    }
                }
            }
    				// 返回一个通过继承了 Spliterator.OfInt 的 Supplier 创建的新的顺序或并行 IntStream
            return StreamSupport.intStream(() ->
                    // 创建一个拆分器,以 CharIterator 作为元素的源,同时报告初始元素数量,源或者元素的特征
                    Spliterators.spliterator(
                            new CharIterator(),
                            length(),
                            Spliterator.ORDERED),
                    Spliterator.SUBSIZED | Spliterator.SIZED | Spliterator.ORDERED,
                    false);
    }
    

    很多情况下,我们可以直接使用包装类如 Integer 直接进行数据处理,得益于 JDK1.5 中添加了自动装箱功能。但如果在内部循环中进行装箱或拆箱操作, 会带来大量 CPU 和垃圾回收机制的开销。

    在 JDK1.8 中我们知道加入了 Stream 流支持,在设计 api 时充分考虑对原语支持,综合性能、开销、维护成本等,添加了对 int、long、double 的原语专门化,详细可见:传送门。

    codePoints()

    该方法在 JDK1.8 中加入,其作用是返回此序列的一个代码点值流。在序列中遇到的任何代理对都是按字符组合的。 toCodePoint 和结果被传递到流。任何其他代码单元,包括普通的BMP字符、未配对的代理和未定义的代码单元,都是零扩展到int值,然后将这些值传递给流。 如果在读取流时发生了突变,则结果是未定义的。

    public default IntStream codePoints() {
            class CodePointIterator implements PrimitiveIterator.OfInt {
                int cur = 0;
    						 /* 对每个剩余元素执行指定的操作,直到所有元素。
                   已被处理或动作引发异常。行动是
                   按照迭代顺序执行,如果指定了该顺序。
                   由操作引发的异常会传递给调用者。*/
                @Override
                public void forEachRemaining(IntConsumer block) {
                    final int length = length();
                    int i = cur;
                    try {
                        while (i < length) {
                            char c1 = charAt(i++);
                            if (!Character.isHighSurrogate(c1) || i >= length) {
                                block.accept(c1);
                            } else {
                                char c2 = charAt(i);
                                if (Character.isLowSurrogate(c2)) {
                                    i++;
                                    block.accept(Character.toCodePoint(c1, c2));
                                } else {
                                    block.accept(c1);
                                }
                            }
                        }
                    } finally {
                        cur = i;
                    }
                }
    						// 如果迭代器中还有元素,则返回true
                public boolean hasNext() {
                    return cur < length();
                }
    						// 返回迭代器中的下一个元素
                public int nextInt() {
                    final int length = length();
    
                    if (cur >= length) {
                        throw new NoSuchElementException();
                    }
                    char c1 = charAt(cur++);
                    if (Character.isHighSurrogate(c1) && cur < length) {
                        char c2 = charAt(cur);
                        if (Character.isLowSurrogate(c2)) {
                            cur++;
                            return Character.toCodePoint(c1, c2);
                        }
                    }
                    return c1;
                }
            }
    				// 返回一个通过继承了 Spliterator.OfInt 的 Supplier 创建的新的顺序或并行IntStream
            return StreamSupport.intStream(() ->
                    Spliterators.spliteratorUnknownSize(
                            new CodePointIterator(),
                            Spliterator.ORDERED),
                    Spliterator.ORDERED,
                    false);
    }
    

    compare(CharSequence cs1, CharSequence cs2)

    该方法在 JDK11 中加入,其作用是按字典顺序比较两个CharSequence实例。如果第一个序列按字典顺序分别小于、等于或大于第二个,则返回负值、零或正值。

    public static int compare(CharSequence cs1, CharSequence cs2) {
        if (Objects.requireNonNull(cs1) == Objects.requireNonNull(cs2)) {
            return 0;
        }
    
        if (cs1.getClass() == cs2.getClass() && cs1 instanceof Comparable) {
            return ((Comparable) cs1).compareTo(cs2);
        }
    
        for (int i = 0, len = Math.min(cs1.length(), cs2.length()); i < len; i++) {
            char a = cs1.charAt(i);
            char b = cs2.charAt(i);
            if (a != b) {
                return a - b;
            }
        }
    
        return cs1.length() - cs2.length();
    }
    
    

    将长度为len的CharSequence cs视为 char 值的序列,从cs[0]到cs[len-1]。假设 k 是每个序列中对应的 char 值不同的最低索引。序列的字典顺序由 char 值cs1[k]与cs2[k]的数值比较确定。如果没有这样的索引k,则较短的序列在字典上被认为小于另一个。如果序列具有相同的长度,则认为这些序列在字典上是相等的。

    更多源码分析

    • Java源码分析 | Object
  • 相关阅读:
    SpringCloud微服务实战——搭建企业级开发框架(四十六):【移动开发】整合uni-app搭建移动端快速开发框架-环境搭建
    布隆过滤器(Bloom Filter)初学习
    操作指南|如何通过Polkassembly参与Moonbeam治理 (2022年8月31日更新)
    985大学新增专业,考数据结构+自然语言处理!中央民族大学新增语言信息安全...
    使用LIMIT分页
    【论文阅读笔记】Deep learning for time series classification: a review
    针对 DNS 监控的 Grafana Dashboard面板DeepFlow
    Keil4打开单片机工程一片空白,cpu100%程序卡死的问题解决
    Andorid获取原生GPS定位信息
    mongodb简介、安装、搭建复制集以及切片
  • 原文地址:https://www.cnblogs.com/zwqh/p/16625101.html
    • 最新文章
    • 攻防演习之三天拿下官网站群
      数据安全治理学习——前期安全规划和安全管理体系建设
      企业安全 | 企业内一次钓鱼演练准备过程
      内网渗透测试 | Kerberos协议及其部分攻击手法
      0day的产生 | 不懂代码的"代码审计"
      安装scrcpy-client模块av模块异常,环境问题解决方案
      leetcode hot100【LeetCode 279. 完全平方数】java实现
      OpenWrt下安装Mosquitto
      AnatoMask论文汇总
      【AI日记】24.11.01 LangChain、openai api和github copilot
    • 热门文章
    • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
      奉劝各位学弟学妹们,该打造你的技术影响力了!
      五年了,我在 CSDN 的两个一百万。
      Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
      面试官都震惊,你这网络基础可以啊!
      你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
      心情不好的时候,用 Python 画棵樱花树送给自己吧
      通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
      13 万字 C 语言从入门到精通保姆级教程2021 年版
      10行代码集2000张美女图,Python爬虫120例,再上征途
    Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
    正则表达式工具 cron表达式工具 密码生成工具

    京公网安备 11010502049817号