JDK源码阅读——java.lang.Character

本文详细探讨了`java.lang.Character`类,包括它的概述、UML类图、源码解析、内部类Subset和UnicodeBlock,以及枚举UnicodeScript的使用。通过实例展示了Character类在处理字符分类和转换上的功能。

Character

1.概述

public final class Characterextends Objectimplements Serializable, Comparable<Character>Character
类在对象中包装一个基本类型 char 的值。Character 类型的对象包含类型为 char 的单个字段。
此外,该类提供了几种方法,以确定字符的类别(小写字母,数字,等等),并将字符从大写转换成小写,反之亦然。

2.此类的UML类图

这里写图片描述
这里写图片描述
因为 UnicodeScript 是enum 类,所以继承抽象的Enum类。

3.源码解析

源码太多了,就捡几个不太常用的来讲。

/**
* 判断是否为BMP代码点
* 从 U+0000 到 U+FFFF 的字符集有时也称为 Basic Multilingual Plane (BMP)
*/
 public static boolean isBmpCodePoint(int codePoint) {
        return codePoint >>> 16 == 0;
        // Optimized form of:
        //     codePoint >= MIN_VALUE && codePoint <= MAX_VALUE
        // We consistently use logical shift (>>>) to facilitate
        // additional runtime optimizations.
    }
    /**
    * 确定使用指定基数的特定数字的字符表示形式。
    *
    */
    public static char forDigit(int digit, int radix) {
        // 只要一个为ture就为true
        if ((digit >= radix) || (digit < 0)) {
            return '\0';
        //    radix<2 或者 radix>36
        if ((radix < Character.MIN_RADIX) || (radix > Character.MAX_RADIX)) {
            return '\0';
        }
        if (digit < 10) {
            return (char)('0' + digit);
        }
        return (char)('a' - 10 + digit);
    }
    /**
    * 返回一个指示字符的常规类别的值。
    * 数字:9 字母:2 转义字符:24 转义序列:15 ……
    */
     public static int getType(char ch) {
        return getType((int)ch);
    }

       public static int getType(int codePoint) {
        // 调用了CharacterData.of(int ch)方法,这个方法返回 Character的子类
        return CharacterData.of(codePoint).getType(codePoint);
    }
    /**
    *  确定指定的代码点是否为从 0x0000 到 0x10FFFF 范围之内的有效 Unicode 代码点值。
    */
      public static boolean isValidCodePoint(int codePoint) {
        // Optimized form of:
        //     codePoint >= MIN_CODE_POINT && codePoint <= MAX_CODE_POINT
        int plane = codePoint >>> 16;
        return plane < ((MAX_CODE_POINT + 1) >>> 16);
    }
    /**
    *  确定指定字符是否为小写字母。
    */
  public static boolean isLowSurrogate(char ch) {
      // MIN_LOW_SURROGATE = '\uDC00' MAX_LOW_SURROGATE  = '\uDFFF'
        return ch >= MIN_LOW_SURROGATE && ch < (MAX_LOW_SURROGATE + 1);
    }

还有很多方法不……

4.Character内部类Subset 和UnicodeBlock

Subset源码:

public static class Subset  {
        private String name;
        protected Subset(String name) {
            if (name == null) {
                throw new NullPointerException("name");
            }
            this.name = name;
        }
        public final boolean equals(Object obj) {
            return (this == obj);
        }
        public final int hashCode() {
            return super.hashCode();
        }
        public final String toString() {
            return name;
        }
    }

UnicodeBlock

 public static final class UnicodeBlock extends Subset {

        private static Map<String, UnicodeBlock> map = new HashMap<>(256);
        private UnicodeBlock(String idName) {
            super(idName);
            map.put(idName, this);
        }

        private UnicodeBlock(String idName, String alias) {
            this(idName);
            map.put(alias, this);
        }
        //可变形参  构造方法
        private UnicodeBlock(String idName, String... aliases) {
            this(idName);
            for (String alias : aliases)
                map.put(alias, this);
        }
        public static final UnicodeBlock  BASIC_LATIN =
            new UnicodeBlock("BASIC_LATIN",
                             "BASIC LATIN",
                             "BASICLATIN");

      // 还有很多UnicodeBlock类型的常量省略。。。。。。。
        private static final UnicodeBlock[] blocks = {
            BASIC_LATIN,
            //省略很多UnicodeBlock实例
          }
    // 获取 c 所属的UnicodeBlock实例
       public static UnicodeBlock of(char c) {
            return of((int)c);
        }
        public static UnicodeBlock of(int codePoint) {
            //判断codePoint是否有效
            if (!isValidCodePoint(codePoint)) {
                throw new IllegalArgumentException();
            }
           // 二分查找UnicodeBlock
            int top, bottom, current;
            bottom = 0;
            top = blockStarts.length;
            current = top/2;

            // invariant: top > current >= bottom && codePoint >= unicodeBlockStarts[bottom]
            while (top - bottom > 1) {
                if (codePoint >= blockStarts[current]) {
                    bottom = current;
                } else {
                    top = current;
                }
                current = (top + bottom) / 2;
            }
            return blocks[current];
        }
        //  返回带有给定名称的 UnicodeBlock实例。
        public static final UnicodeBlock forName(String blockName) {
            UnicodeBlock block = map.get(blockName.toUpperCase(Locale.US));
            if (block == null) {
                throw new IllegalArgumentException();
            }
            return block;
        }
    }

5.枚举UnicodeScript

源码不贴上了
有2个方法 public static UnicodeScript of(int codePoint)和 public static final UnicodeScript forName(String scriptName)。
方法作用和UnicodeBlock一样。

6.Character 简单运用

  /**
     * 用 UnicodeBlock来判断中文字符
     */
    public boolean isChineseUBynicodeBlock(char c) {
        //
        Character.UnicodeBlock unicodeBlock = Character.UnicodeBlock.of(c);
        if (unicodeBlock == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
                || unicodeBlock == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
                || unicodeBlock == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B
                || unicodeBlock == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C
                || unicodeBlock == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D
                || unicodeBlock == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
                || unicodeBlock == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT
                )
            return true;
        else
            return false;
    }

    /**
     * 用 UnicodeScript 来判断中文字符
     * @param c
     * @return
     */
    public boolean isChineseByUnicodeScript(char c) {
        Character.UnicodeScript unicodeScript = Character.UnicodeScript.of(c);
        if (unicodeScript == Character.UnicodeScript.HAN)
            return true;
        else
            return false;
    }
    /**
     * 用 Character.getType()来判断中文字符
     * 不知道对不对
     */
    public boolean isGetType(char c){
        if (Character.getType(c) == 5)
            return true;
        else
            return false;
    }
<think> 我们正在解决Spring Boot升级到3.5.5和Spring升级到6.1.1时出现的`java.lang.NoSuchFieldError`错误。错误信息指出:`Class org.springframework.util.SystemPropertyUtils does not have member field 'java.lang.Character ESCAPE_CHARACTER'`。 ### 问题分析 1. **错误原因**:该错误通常发生在编译时存在某个类,但在运行时该类的版本发生了变化,导致字段不存在。具体来说,在`SystemPropertyUtils`类中,运行时环境找不到`ESCAPE_CHARACTER`这个字段。 2. **版本差异**:Spring Boot 3.5.5依赖于Spring 6.1.1。在Spring框架的早期版本中,`SystemPropertyUtils`类可能包含`ESCAPE_CHARACTER`字段,但在新版本中该字段可能已被移除或重命名。 ### 解决步骤 #### 1. 检查依赖关系 首先,确保项目中所有依赖的Spring相关库的版本与Spring Boot 3.5.5保持一致。使用Maven或Gradle的依赖树命令检查是否有旧版本的Spring库被引入。 - **Maven**: ```bash mvn dependency:tree ``` - **Gradle**: ```bash gradle dependencies ``` 在依赖树中搜索`spring-core`,确保其版本为6.1.1(与Spring Boot 3.5.5一致)。 #### 2. 排除旧版本依赖 如果发现其他依赖引入了旧版本的Spring库(如`spring-core`),需要排除这些传递依赖。 **Maven示例**: ```xml <dependency> <groupId>some.group</groupId> <artifactId>some-artifact</artifactId> <version>some-version</version> <exclusions> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> </exclusion> </exclusions> </dependency> ``` **Gradle示例**: ```groovy implementation('some.group:some-artifact:some-version') { exclude group: 'org.springframework', module: 'spring-core' } ``` #### 3. 检查自定义代码或第三方库 如果项目代码或第三方库直接引用了`SystemPropertyUtils.ESCAPE_CHARACTER`,需要更新这些引用。在Spring 6.1.1中,该字段可能已被移除。可以查看Spring Framework 6.1.1的官方文档或源码确认。 - **Spring Framework 6.1.1 源码**: 访问 [Spring Framework GitHub](https://github.com/spring-projects/spring-framework/tree/v6.1.1) 查看`SystemPropertyUtils`类。 #### 4. 替换已移除的字段 如果确认该字段已被移除,需要找到替代方案或修改代码逻辑。例如,在Spring 6.1.1中,处理属性占位符转义的方式可能已改变。 ### 替代方案建议 1. **查找新API**:在Spring 6.1.1中,属性占位符的处理可能使用了新的方法或常量。建议查阅最新版本文档。 2. **避免使用内部API**:`SystemPropertyUtils`是Spring内部工具类,不建议直接使用。如果必须使用,可考虑自行实现类似功能。 ### 示例修复 假设项目中有一段代码引用了`SystemPropertyUtils.ESCAPE_CHARACTER`: ```java import org.springframework.util.SystemPropertyUtils; public class MyClass { public void myMethod() { char escapeChar = SystemPropertyUtils.ESCAPE_CHARACTER; // 此行导致错误 } } ``` **修复方式**: - 如果该字段已移除,且无直接替代,可考虑硬编码转义字符(如`':'`)或使用其他Spring提供的工具方法。 ### 总结 升级过程中出现`NoSuchFieldError`通常是因为依赖冲突或API变动。解决步骤包括: 1. 统一依赖版本(确保所有Spring模块均为6.1.1)。 2. 排除旧版本传递依赖。 3. 修改代码以适应新版本的API变化。 > **注意**:Spring Boot 3.x要求Java 17+,请确保环境符合要求[^1]。 §§相关问题§§ 1. 如何解决Spring Boot升级后出现的`NoClassDefFoundError`错误? 2. Spring Boot 3.x有哪些重大变更需要注意? 3. 如何排查Maven或Gradle项目中的依赖冲突? </think>### 解决升级 Spring Boot 3.5.5 和 Spring 6.1.1 时出现的 `NoSuchFieldError` 错误 #### 问题原因分析 该错误表明在升级后,Spring 框架的 `SystemPropertyUtils` 类中缺少 `ESCAPE_CHARACTER` 字段。通常由以下原因导致: 1. **依赖冲突**:项目中存在多个不同版本的 `spring-core` 包(如同时存在 Spring 5.x 和 6.x) 2. **API 变更**:Spring 6.1.1 可能已移除或重命名此字段 3. **不兼容的第三方库**:某些依赖仍强制使用旧版 Spring API #### 解决方案步骤 ##### 1. 统一 Spring 依赖版本 在 `pom.xml` 或 `build.gradle` 中显式指定所有 Spring 组件的版本: ```xml <!-- Maven 示例 --> <properties> <spring.version>6.1.1</spring.version> <spring-boot.version>3.5.5</spring-boot.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-framework-bom</artifactId> <version>${spring.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> ``` ##### 2. 检查依赖冲突 使用以下命令分析依赖树: ```bash # Maven mvn dependency:tree -Dincludes=org.springframework # Gradle gradle dependencies --configuration runtimeClasspath | grep org.springframework ``` 重点关注是否存在旧版本 `spring-core`(如 5.x 版本)。 ##### 3. 排除冲突依赖 若发现旧版本传递依赖,手动排除: ```xml <dependency> <groupId>com.example</groupId> <artifactId>problematic-lib</artifactId> <exclusions> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> </exclusion> </exclusions> </dependency> ``` ##### 4. 更新代码适配新 API 检查代码中对 `SystemPropertyUtils.ESCAPE_CHARACTER` 的引用: - 在 Spring 6.1.1 中,该字段已被移除 - 替代方案:使用 `SystemPropertyUtils#resolvePlaceholders` 方法处理属性占位符 ```java // 替代旧版 ESCAPE_CHARACTER 的用法 String resolved = SystemPropertyUtils.resolvePlaceholders("${your.property}"); ``` ##### 5. 清理构建缓存 执行彻底的清理重建: ```bash # Maven mvn clean install -U # Gradle gradle clean build --refresh-dependencies ``` #### 验证修复 1. 启动应用检查是否抛出相同错误 2. 在 IDE 中验证类加载: ```java try { Class<?> clazz = Class.forName("org.springframework.util.SystemPropertyUtils"); Field field = clazz.getDeclaredField("ESCAPE_CHARACTER"); // 应抛出 NoSuchFieldException } catch (Exception e) { // 预期行为 } ``` > **重要提示**:Spring Boot 3.x 需要 JDK 17+,请确认环境符合要求[^1]。若仍存在问题,建议检查第三方库的兼容性列表。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值