私たちが普段何気なく使っている基本的なテクニックがたくさんあります。さて、考えてみて、一見単純なメソッドがどのように実装されているかに注目してみるとどうでしょうか? これは Java に一歩近づくのに役立つと思います) ある文字列内の特定の文字を抽出する必要がある状況を想像してみましょう。Java でこれを行うにはどうすればよいでしょうか? たとえば、 を呼び出します
Java String charAt
。今日の記事ではその方法についてcharAt()
説明します。
構文
char charAt(int index)
指定されたインデックスの char 値を返します。インデックスの範囲は 0 ~ ですlength()-1
。つまり、配列のインデックス付けの場合と同様に、char
シーケンスの最初の値は にありindex 0
、次の値は にあり、というようになります。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));
}
最初の行は最初の文字を取り、2 行目は 2 番目の文字を取り、以下同様となります。not ですがprintln
、ここではprint
改行なしで使用されているため、コンソールに次の出力が表示されます。
Java
指定されたインデックスが Unicode として表される場合char
、メソッドの結果は、java charAt()
この Unicode を表す文字になります。
System.out.println("J\u0061vaRush".charAt(1));
コンソール出力:
a
「ボンネットの下」とは何ですか
それはどのように機能するのですか? 実際、各オブジェクトには、指定された文字列の要素のバイトを含む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
2 番目のメソッドを呼び出す方が興味深いでしょう。
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
、2 バイト (2 つの配列セル) で表されることを理解する必要があります。2 つのキリル文字の文字列「av」がある場合、次のようになります。
- 「a」の場合、これは 48 と 4 のバイトのペアです。
- 「in」の場合 - 50 と 4。
value
{48, 4, 50, 4} が含まれることになります。実際、このメソッドは 2 つの配列セルで機能しますvalue
。したがって、次のステップは、index <<= 1;
配列内の目的の文字の最初のバイトのインデックスに直接アクセスすることですvalue
。ここで、 string があるとします"абвг"
。この場合、値の配列は次のようになります: {48, 4, 49, 4, 50, 4, 51, 4}。文字列の 3 番目の要素を要求すると、バイナリ表現は 00000000 00000011 になります。1 だけシフトすると、00000000 00000110、つまり が得られますindex = 6
。ビット単位の演算に関する知識を更新するには、この記事を読んでください。いくつかの変数も表示されます。 HI_BYTE_SHIFT
この場合は 0、 LO_BYTE_SHIFT
この場合は 8 です。このメソッドの最後の行では次のようになります。
- 要素が値配列から取得され、 を
HI_BYTE_SHIFT
増加させながら だけ、つまり 0 だけビット単位でシフトされますindex +1
。文字列 の例では
"абвг"
、6 番目のバイト (51) はそのままですが、同時にインデックスは 7 に増加します。 - この後、配列の次の要素が取得され、同じ方法でビット単位にシフトされますが、LO_BYTE_SHIFT、つまり 8 ビットだけシフトされます。
そして、バイナリ表現 - 00000000 00000100 を持つバイト 4 がある場合、8 ビットシフトすると、00000100 00000000 になります。整数の場合 - 1024。
- 次に、これら 2 つの値に対して、 の操作が続きます
| (OR)
。また、バイト 51 と 1024 があり、バイナリ表現では 00000000 00110011 と 00000100 00000000 のように見えた場合、演算後は
OR
00000100 00110011 が得られます。これは、10 進数で 1075 を意味します。さて、最終的には 1075 という数字が char 型に変換され、int -> char に変換するときに ASCII テーブルが使用され、その中で 1075 という数字の下に文字「r」が存在します。
charAt()
。
GO TO FULL VERSION