JavaRush /Java 博客 /Random-ZH /Java 中的 charAt() 方法

Java 中的 charAt() 方法

已在 Random-ZH 群组中发布
有许多基本技术我们经常使用,甚至不假思索。那么,如果你想一想,看看一些看似简单的方法是如何实现的呢?我认为这将帮助我们更接近Java一步) Java 中的 charAt() - 1让我们想象一种情况,我们需要提取某个字符串中的某个字符。我们如何在 Java 中做到这一点?例如,通过调用Java String charAt. charAt()我们将在今天的文章中讨论该方法。

句法

char charAt(int index)返回指定索引处的 char 值。索引范围从 0 到length()-1。也就是说,char序列的第一个值是 in index 0,下一个值是 in ,index 1等等,就像数组索引的情况一样。

例子

public static void main(String[] args) {
   System.out.print("JavaRush".charAt(0));
   System.out.print("JavaRush".charAt(1));
   System.out.print("JavaRush".charAt(2));
   System.out.print("JavaRush".charAt(3));
}
第一行采用第一个字符,第二行采用第二个字符,依此类推。由于这里使用了 not println, but print,没有换行,我们将在控制台得到以下输出:

Java
如果char给定索引表示为 Unicode,则该方法的结果java charAt()将是表示该 Unicode 的字符:
System.out.println("J\u0061vaRush".charAt(1));
控制台输出:

a

什么是“引擎盖下”

你问它是如何运作的?Java 中的 charAt() - 2事实上,每个对象都String包含一个数组byte,其中包含给定行元素的字节:
private final byte[] value;
这是方法本身chatAt
public char charAt(int index) {
   if (isLatin1()) {
       return StringLatin1.charAt(value, index);
   } else {
       return StringUTF16.charAt(value, index);
   }
}
isLatin1- 一个标志,指示我们的字符串是否仅包含拉丁字符。这决定了接下来将调用哪个方法。

isLatin1 = true

如果字符串仅包含拉丁字符,则调用静态charAt类方法StringLatin1
public static char charAt(byte[] value, int index) {
   if (index < 0 || index >= value.length) {
       throw new StringIndexOutOfBoundsException(index);
   }
   return (char)(value[index] & 0xff);
}
第一步是检查传入的索引是否大于或等于0,并且没有超出内部字节数组,如果不是这种情况,则抛出异常new StringIndexOutOfBoundsException(index)。如果检查通过,那么我们需要的元素就会被获取。最后我们看到:
  • &将二进制运算扩展为byte按位运算
  • 0xff什么都不做,但&需要一个参数
  • (char)将数据从 ASCII 表转换为char

isLatin1 = false

如果我们不仅有拉丁字符,则将使用该类StringUTF16并调用其静态方法:
public static char charAt(byte[] value, int index) {
   checkIndex(index, value);
   return getChar(value, index);
}
这又调用:
public static void checkIndex(int off, byte[] val) {
   String.checkIndex(off, length(val));
}
他委托给静态方法String
static void checkIndex(int index, int length) {
   if (index < 0 || index >= length) {
       throw new StringIndexOutOfBoundsException("index " + index +
                                                 ", length " + length);
   }
}
实际上,这里会检查索引是否有效:再次检查它是正数还是零,以及它是否没有超出数组的限制。但在类中StringUTF16的一个方法中,charAt调用第二个方法会更有趣:
static char getChar(byte[] val, int index) {
   assert index >= 0 && index < length(val) : "Trusted caller missed bounds check";
   index <<= 1;
   return (char)(((val[index++] & 0xff) << HI_BYTE_SHIFT) |
                 ((val[index]   & 0xff) << LO_BYTE_SHIFT));
}
让我们开始分析这里实际发生的情况。该方法开始的第一步是再次检查索引的有效性。要了解接下来会发生什么,您需要了解:当非拉丁字符进入数组时value,它由两个字节(两个数组单元)表示。如果我们有一个由两个西里尔字母“av”组成的字符串,那么:
  • 对于“a”,这是一对字节 - 48 和 4;
  • 对于 'in' - 50 和 4。
也就是说,如果我们创建字符串“av”,它将有一个数组value- {48, 4, 50, 4} 实际上,此方法适用于两个数组单元value。因此,下一步是index <<= 1;直接获取数组中所需字符的第一个字节的索引value。现在假设我们有一个字符串"абвг"。那么值数组将如下所示:{48, 4, 49, 4, 50, 4, 51, 4}。我们要求字符串的第三个元素,那么二进制表示为 00000000 00000011。移位 1 后,我们得到 00000000 00000110,即index = 6。要刷新您有关按位运算的知识,您可以阅读这篇文章Java 中的 charAt() - 4我们还看到一些变量: HI_BYTE_SHIFT 在本例中为 0。 LO_BYTE_SHIFT在本例中为 8。在此方法的最后一行中:
  1. 从值数组中取出一个元素,按位移动HI_BYTE_SHIFT,即 0,同时增加index +1

    在字符串 的示例中"абвг",第六个字节 - 51 - 将保持不变,但同时索引增加到 7。

  2. 此后,以相同的方式获取数组的下一个元素并按位移位,但移位量为 LO_BYTE_SHIFT,即 8 位。

    如果我们有字节 4,它具有二进制表示形式 - 00000000 00000100,那么移位 8 位后我们将得到 00000100 00000000。如果它是整数 - 1024。

  3. 接下来,对于这两个值,进行操作| (OR)

    如果我们有字节 51 和 1024,在二进制表示中看起来像 00000000 00110011 和 00000100 00000000,那么在运算之后OR我们将得到 00000100 00110011,这意味着十进制中的数字 1075。

    好吧,最后,数字1075被转换为char类型,而在转换int -> char时,使用了ASCII表,在其中,数字1075的下面,有字符'g'。

实际上,这就是我们在 Java 编程中获得“g”作为方法结果的方式charAt()
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION