Có nhiều kỹ thuật cơ bản mà chúng ta sử dụng thường xuyên mà không hề nghĩ tới. Chà, điều gì sẽ xảy ra nếu bạn nghĩ về nó và xem xét cách thực hiện một số phương pháp tưởng chừng đơn giản? Tôi nghĩ điều này sẽ giúp chúng ta tiến gần hơn một bước đến Java) Hãy tưởng tượng một tình huống trong đó chúng ta cần trích xuất một ký tự nhất định trong một chuỗi nào đó. Làm thế nào chúng ta có thể làm điều này trong Java? Ví dụ: bằng cách gọi
Java String charAt
. charAt()
Chúng ta sẽ nói về phương pháp trong bài viết hôm nay.
Cú pháp
char charAt(int index)
trả về giá trị char tại chỉ mục đã chỉ định. Chỉ số nằm trong khoảng từ 0 đến length()-1
. Nghĩa là, char
giá trị đầu tiên của chuỗi là in index 0
, giá trị tiếp theo là in , index 1
v.v., như trường hợp lập chỉ mục mảng.
Ví dụ
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));
}
Dòng đầu tiên lấy ký tự đầu tiên, dòng thứ hai lấy ký tự thứ hai, v.v. Vì not println
, nhưng được sử dụng ở đây print
, không có dòng mới, nên chúng ta sẽ nhận được kết quả đầu ra sau cho bảng điều khiển:
Java
Nếu char
chỉ mục đã cho được biểu diễn dưới dạng Unicode, kết quả của phương thức java charAt()
sẽ là ký tự đại diện cho Unicode này:
System.out.println("J\u0061vaRush".charAt(1));
Đầu ra của bảng điều khiển:
a
"dưới mui xe" là gì
bạn hỏi nó thực hiện như thế nào ư? Thực tế là mỗi đối tượngString
chứa một mảng byte
với các byte của các phần tử của một dòng nhất định:
private final byte[] value;
Và đây là phương pháp của chính nó chatAt
:
public char charAt(int index) {
if (isLatin1()) {
return StringLatin1.charAt(value, index);
} else {
return StringUTF16.charAt(value, index);
}
}
isLatin1
- một lá cờ cho biết chuỗi của chúng ta có chỉ chứa các ký tự Latinh hay không. Điều này xác định phương thức nào sẽ được gọi tiếp theo.
isLatin1 = đúng
Nếu chuỗi chỉ chứa các ký tự Latinh, một phương thứccharAt
lớp tĩnh được gọi StringLatin1
:
public static char charAt(byte[] value, int index) {
if (index < 0 || index >= value.length) {
throw new StringIndexOutOfBoundsException(index);
}
return (char)(value[index] & 0xff);
}
Bước đầu tiên là kiểm tra xem chỉ mục đến có lớn hơn hoặc bằng 0 không và nó không vượt ra ngoài mảng byte bên trong và nếu không đúng thì một ngoại lệ sẽ được đưa ra new StringIndexOutOfBoundsException(index)
. Nếu quá trình kiểm tra được thông qua thì phần tử chúng ta cần sẽ được lấy. Cuối cùng chúng ta thấy:
&
mở rộng cho hoạt động nhị phân sangbyte
bitwise0xff
không làm gì ngoài&
việc yêu cầu một cuộc tranh luận(char)
chuyển đổi dữ liệu từ bảng ASCII sangchar
isLatin1 = sai
Nếu chúng ta có nhiều hơn các ký tự Latinh, lớp này sẽ được sử dụngStringUTF16
và phương thức tĩnh của nó sẽ được gọi:
public static char charAt(byte[] value, int index) {
checkIndex(index, value);
return getChar(value, index);
}
Đến lượt nó gọi:
public static void checkIndex(int off, byte[] val) {
String.checkIndex(off, length(val));
}
Và anh ta ủy quyền cho một phương thức tĩnh String
:
static void checkIndex(int index, int length) {
if (index < 0 || index >= length) {
throw new StringIndexOutOfBoundsException("index " + index +
", length " + length);
}
}
Trên thực tế, ở đây, một cuộc kiểm tra được thực hiện để xem liệu chỉ mục có hợp lệ hay không: một lần nữa, nó là dương hay bằng 0 và liệu nó có vượt quá giới hạn của mảng hay không. Nhưng trong một lớp StringUTF16
trong một phương thức, charAt
việc gọi phương thức thứ hai sẽ thú vị hơn:
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));
}
Hãy bắt đầu phân tích những gì đang thực sự xảy ra ở đây. Bước đầu tiên khi bắt đầu phương pháp là một bước kiểm tra khác về tính hợp lệ của chỉ mục. Để hiểu điều gì xảy ra tiếp theo, bạn cần hiểu: khi một ký tự không phải tiếng Latinh nhập vào mảng value
, nó được biểu thị bằng hai byte (hai ô mảng). Nếu chúng ta có một chuỗi gồm hai ký tự Cyrillic - “av”, thì:
- đối với 'a' đây là một cặp byte - 48 và 4;
- cho 'trong' - 50 và 4.
value
- {48, 4, 50, 4} Trên thực tế, phương thức này hoạt động với hai ô mảng value
. Do đó, bước tiếp theo là dịch chuyển index <<= 1;
để lấy trực tiếp chỉ mục của byte đầu tiên của ký tự mong muốn trong mảng value
. Bây giờ giả sử chúng ta có một chuỗi "абвг"
. Khi đó mảng giá trị sẽ có dạng như sau: {48, 4, 49, 4, 50, 4, 51, 4}. Chúng ta yêu cầu phần tử thứ ba của chuỗi và sau đó biểu diễn nhị phân là 00000000 00000011. Khi dịch chuyển đi 1, chúng ta nhận được 00000000 00000110, tức là index = 6
. Để làm mới kiến thức về các phép toán bitwise, bạn có thể đọc bài viết này . Chúng tôi cũng thấy một số biến: HI_BYTE_SHIFT
trong trường hợp này là 0. LO_BYTE_SHIFT
trong trường hợp này là 8. Ở dòng cuối cùng của phương thức này:
- Một phần tử được lấy từ mảng giá trị và được dịch chuyển theo bit bằng
HI_BYTE_SHIFT
0, nghĩa là 0, trong khi tăngindex +1
.Trong ví dụ với chuỗi
"абвг"
, byte thứ sáu - 51 - sẽ vẫn như vậy, nhưng đồng thời chỉ số sẽ tăng lên 7. - Sau đó, phần tử tiếp theo của mảng được lấy và dịch chuyển theo bit theo cách tương tự, nhưng bằng LO_BYTE_SHIFT, nghĩa là 8 bit.
Và nếu chúng ta có byte 4, có biểu diễn nhị phân - 00000000 00000100, thì sau khi dịch chuyển 8 bit, chúng ta sẽ có 00000100 00000000. Nếu đó là số nguyên - 1024.
- Tiếp theo, đối với hai giá trị này, hãy thực hiện thao tác
| (OR)
.Và nếu chúng ta có byte 51 và 1024, trong biểu diễn nhị phân trông giống như 00000000 00110011 và 00000100 00000000, thì sau thao tác
OR
chúng ta sẽ nhận được 00000100 00110011, nghĩa là số 1075 trong hệ thập phân.À, cuối cùng thì số 1075 được chuyển thành kiểu char, và khi chuyển đổi int -> char thì sử dụng bảng ASCII, và trong đó, dưới số 1075 có ký tự 'g'.
charAt()
trong lập trình Java.
GO TO FULL VERSION