学习日志11 java

加加油(ง •_•)ง加油(ง •_•)ง加油(ง •_•)ง

1 有关char和String

在 Java 中,char 和 String 都是用于处理文本的类型,但它们有本质区别。以下是两者的核心差异和对比:

1. 基本定义

char(字符类型)
  • 基本数据类型:存储单个 Unicode 字符,占用 16 位(2 字节)。
  • 表示方式:用单引号 ' ' 包裹,例如 'A''中''\n'
  • 范围\u0000(0)到 \uFFFF(65,535),涵盖所有基本 Unicode 字符。
String(字符串类型)
  • 引用数据类型:存储多个字符组成的序列,是 java.lang.String 类的实例。
  • 表示方式:用双引号 " " 包裹,例如 "Hello""123"
  • 不可变性:String 对象创建后不可修改,任何修改都会生成新的 String 对象。

2. 核心区别对比表

特性charString
类型基本数据类型(Primitive)引用数据类型(Object)
存储内容单个字符多个字符的序列(字符数组)
语法示例char c = 'A';String s = "Hello";
长度固定为 1 个字符可变长度,可空(""
常用操作字符比较、算术运算(如 'A'+1拼接(+)、截取、查找、替换
空值表示不能直接赋值为 null可以赋值为 null 或空字符串 ""

3. 关键差异详解

3.1 存储方式
  • char:直接存储字符的 Unicode 编码值(整数)。

    java

    char c = 'A'; // 存储的是65('A'的Unicode值)
    
  • String:内部用 char[] 数组存储字符序列,并提供各种操作方法。

    java

    String s = "ABC"; // 等价于存储 ['A', 'B', 'C']
    
3.2 不可变性
  • String 不可变:任何修改操作都会生成新的 String 对象。

    java

    String s = "Hello";
    s = s + " World"; // 实际上创建了新的String对象 "Hello World"
    
  • char:作为基本类型,赋值后直接修改值。

    java

    char c = 'A';
    c = 'B'; // 直接修改值,不涉及对象创建
    
3.3 常用操作对比
操作**char** 示例**String** 示例
获取字符char c = 'A';char c = "Hello".charAt(0);
拼接需通过 String 拼接String s = "A" + "B";
长度固定为 1(无需计算)int len = "Hello".length();
比较c == 'A's.equals("Hello")
转换为数字int num = c - '0';(字符 '0'-'9')int num = Integer.parseInt("123");

4. 相互转换

char → String

java

char c = 'A';
String s1 = String.valueOf(c);    // 方法1:推荐方式
String s2 = Character.toString(c); // 方法2:等效于valueOf
String s3 = c + "";               // 方法3:拼接空字符串(不推荐,效率低)
String → char

java

String s = "Hello";
char first = s.charAt(0);         // 获取第一个字符 'H'
char[] chars = s.toCharArray();   // 转换为字符数组 ['H', 'e', 'l', 'l', 'o']

5. 常见应用场景

char 的场景
  • 遍历字符串中的每个字符。

    java

    String s = "Hello";
    for (int i = 0; i < s.length(); i++) {
        char c = s.charAt(i); // 逐个获取字符 'H', 'e', 'l', 'l', 'o'
    }
    
  • 字符判断(如是否为数字、字母)。

    java

    char c = '5';
    boolean isDigit = Character.isDigit(c); // true
    
String 的场景
  • 文本处理(如拼接、分割、替换)。

    java

    String s = "Hello";
    String upper = s.toUpperCase(); // "HELLO"
    String replaced = s.replace('l', 'x'); // "Hexxo"
    
  • 输入输出(如读取用户输入、文件内容)。

    java

    Scanner scanner = new Scanner(System.in);
    String input = scanner.nextLine(); // 读取整行文本
    

6. 常见错误与注意事项

  1. 单引号 vs 双引号~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    java

    char c = 'A';   // 正确
    // char error = "A"; // 错误:双引号用于String,不能赋值给char
    
  2. 空字符串 vs null

    java

    String s1 = "";     // 空字符串(长度为0)
    String s2 = null;   // 空引用(未指向任何对象)
    
  3. 字符串拼接性能

    • 频繁拼接时,使用 StringBuilder 代替 +

    java

    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < 1000; i++) {
        sb.append(i); // 比 "s = s + i" 效率高得多
    }
    String result = sb.toString();
    

总结

  • char 是基本类型,用于存储单个字符,操作简单高效。
  • String 是对象类型,用于处理文本序列,提供丰富的方法但需注意不可变性和性能问题。

理解两者区别是 Java 文本处理的基础,建议通过练习加深记忆(例如:遍历字符串统计字符出现次数、反转字符串等)。

2 charAt()

1. charAt() 方法概述

  • 所属类java.lang.String(所有字符串对象都可直接调用)
  • 作用:返回字符串中指定索引位置的 char 类型字符。
  • 语法

    java

    char c = str.charAt(index);
    

    str:字符串对象

    • index:索引位置(从 0 开始,即第一个字符的索引为 0)
    • 返回值:指定位置的字符

2. 示例代码

java

String s = "Hello";
char firstChar = s.charAt(0);    // 获取第一个字符 'H'
char lastChar = s.charAt(4);     // 获取第五个字符 'o'(索引为4)
// char error = s.charAt(5);    // 报错:索引越界(字符串长度为5,最大索引为4)

3. 方法的内部实现(简化版)

String 类内部用 char[] 数组存储字符,charAt() 直接返回对应索引的字符:

java

// String类的部分源码(简化)
public final class String {
    private final char[] value; // 存储字符串的字符数组
    
    public char charAt(int index) {
        if ((index < 0) || (index >= value.length)) {
            throw new StringIndexOutOfBoundsException(index);
        }
        return value[index]; // 返回数组中指定位置的字符
    }
}

4. 常见应用场景

  1. 获取字符串的第一个字符

    java

    String name = "Alice";
    char firstInitial = name.charAt(0); // 'A'
    
  2. 遍历字符串中的每个字符

    java

    String s = "Java";
    for (int i = 0; i < s.length(); i++) {
        char c = s.charAt(i);
        System.out.print(c + " "); // 输出:J a v a
    }
    
  3. 检查字符串是否以特定字符开头

    java

    String url = "https://example.com";
    if (url.charAt(0) == 'h') {
        System.out.println("以 h 开头");
    }
    

5. 注意事项

  1. 索引范围

    • 合法索引范围是 0 到 length() - 1
    • 若索引越界,会抛出 StringIndexOutOfBoundsException
  2. 空字符串检查

    • 空字符串("")没有字符,调用 charAt(0) 会报错。

    java

    String empty = "";
    // char c = empty.charAt(0); // 报错:StringIndexOutOfBoundsException
    
  3. 与 toCharArray() 的区别:

    • charAt() 返回单个字符,适用于随机访问。
    • toCharArray() 返回整个字符数组,适用于需要频繁遍历或修改字符的场景。

总结

charAt() 是 Java 中处理字符串的核心方法之一,属于 Java 标准库的内置功能,无需额外导入即可使用。熟练掌握该方法对于字符串操作(如解析文本、验证格式等)非常重要。

3 char currentChar = (char) ('A' + i - 1);的解释 

这行代码用于生成字母序列中的当前字符,是构建空心字母金字塔的关键逻辑。我来详细拆解它的工作原理:

代码拆解

java

char currentChar = (char) ('A' + i - 1);
1. 核心逻辑
  • 'A':字符 A 的 Unicode 值是 65(十进制)。
  • i:循环变量,表示当前行数(从 0 开始)。
  • i - 1:调整偏移量,使字母序列从 A 开始递增。
2. 类型转换
  • ('A' + i - 1):计算结果是一个 int 类型的数值(例如 65 + 1 - 1 = 65)。
  • (char):强制将 int 类型转换为 char 类型,将数值映射为对应的 Unicode 字符。

示例演示

假设输入为 E(金字塔有 5 层),i 从 0 递增到 4,计算过程如下:

i(行数)计算过程结果(数值)转换为字符对应行的字母
0'A' + 0 - 164(非法值)@错误!
1'A' + 1 - 165A第 1 行字母
2'A' + 2 - 166B第 2 行字母
3'A' + 3 - 167C第 3 行字母
4'A' + 4 - 168D第 4 行字母

问题发现

这里存在一个 逻辑错误:当 i = 0 时,计算结果为 64,对应字符 @,而不是预期的 A。这会导致金字塔的第一层显示错误字符。

修正方案

正确的公式应该是 'A' + i,无需减 1:

java

char currentChar = (char) ('A' + i); // 修正后
修正后的示例
i(行数)计算过程结果(数值)转换为字符对应行的字母
0'A' + 065A第 1 行字母
1'A' + 166B第 2 行字母
2'A' + 267C第 3 行字母
3'A' + 368D第 4 行字母
4'A' + 469E第 5 行字母

完整修正后的代码片段

java

for (int i = 0; i < n; i++) {
    char currentChar = (char) ('A' + i); // 修正:直接用 'A' + i
    int leadingSpaces = 39 - i;
    
    // 生成当前行...
}

总结

  • 原始代码错误:减 1 导致第一层字符错误(显示 @ 而非 A)。
  • 正确逻辑:直接用 'A' + i 生成从 A 开始的字母序列。
  • 关键点:字符在 Java 中可作为数值参与运算,通过 Unicode 值映射到对应字符。

4 修正后的正确代码进行详细对比,指出存在问题的部分

我的代码

java

package PTA_training;

import java.util.Scanner;

public class Demo5_4 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        // 读取数组元素个数
        int n = scanner.nextInt();
        int[] arrays = new int[n];
        // 录入初始数据
        if (n >= 1 && n <= 100) {
            for (int i = 0; i < n; i++) {
                arrays[i] = scanner.nextInt();
            }
        } else {
            System.out.println("无效的输入!");
        }
        int w = scanner.nextInt();
        for (int j = 0; j < w; j++) {
            int temp = arrays[scanner.nextInt() - 1];
            for (int q = 0; q < temp; q++) {
                arrays[q] = arrays[q + 1];
            }
            arrays[n - 1] = temp;
        }
        for (int k = 0; k < n; k++) {
            if (k > 0) {
                System.out.print(" ");
            }
            System.out.print(arrays[k]);
        }
        scanner.close();
    }
}

修正后的正确代码

java

package PTA_training;

import java.util.Scanner;

public class Demo5_4 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        // 读取数组元素个数
        int n = scanner.nextInt();
        int[] arrays = new int[n];
        // 录入初始数据
        if (n >= 1 && n <= 100) {
            for (int i = 0; i < n; i++) {
                arrays[i] = scanner.nextInt();
            }
        } else {
            System.out.println("无效的输入!");
            return;
        }
        int k = scanner.nextInt();
        for (int j = 0; j < k; j++) {
            int x = scanner.nextInt() - 1; // 要移动的元素的索引
            int temp = arrays[x]; // 保存要移动的元素
            // 将x+1到n的元素依次往前移一位
            for (int q = x; q < n - 1; q++) {
                arrays[q] = arrays[q + 1];
            }
            arrays[n - 1] = temp; // 将原来的第x个位置的元素放在数组的最后
        }
        for (int m = 0; m < n; m++) {
            if (m > 0) {
                System.out.print(" ");
            }
            System.out.print(arrays[m]);
        }
        scanner.close();
    }
}

详细对比与问题分析

1. 输入验证部分
  • 你的代码:当输入的 n 不在 1 到 100 这个有效范围内时,仅输出 "无效的输入!",程序会继续执行后续代码,可能导致后续操作出现异常。
  • 修正后代码:在输入无效时,除了输出错误信息,还添加了 return 语句,直接终止 main 方法,避免程序继续执行后续可能出错的代码。
2. 移动元素的内层循环部分
  • 你的代码

java

int temp = arrays[scanner.nextInt() - 1];
for (int q = 0; q < temp; q++) {
    arrays[q] = arrays[q + 1];
}

这里存在两个问题:

  • temp 存储的是要移动的元素的值,而不是要移动的元素的位置,使用 q < temp 作为循环条件是错误的逻辑。
  • 当 q 达到数组的倒数第二个元素时,q + 1 会超出数组的边界,导致数组越界异常。
  • 修正后代码
int x = scanner.nextInt() - 1; // 要移动的元素的索引
int temp = arrays[x]; // 保存要移动的元素
for (int q = x; q < n - 1; q++) {
    arrays[q] = arrays[q + 1];
}
  • 引入变量 x 来保存要移动元素的索引,逻辑更加清晰。
  • 内层循环从 x 开始,到 n - 1 结束,将 x + 1 到 n 的元素依次往前移一位,避免了数组越界的问题。
3. 变量命名部分
  • 你的代码:使用 w 表示要进行的移动次数,变量名不够直观。
  • 修正后代码:使用 k 表示要进行的移动次数,虽然只是一个小细节,但遵循了题目描述中的变量名,更符合习惯。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值