우리가 생각조차 하지 않고 정기적으로 사용하는 기본 기술이 많이 있습니다. 글쎄, 그것에 대해 생각하고 겉보기에 간단해 보이는 몇 가지 방법이 어떻게 구현되는지 살펴보면 어떨까요? 이것이 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));
}
첫 번째 줄은 첫 번째 문자를 사용하고, 두 번째 줄은 두 번째 문자를 사용하는 식으로 진행됩니다. 여기서는 not println
, but 을 사용하므로 print
새 줄 없이 콘솔에 다음과 같은 출력이 표시됩니다.
Java
주어진 인덱스가 유니코드로 표시되는 경우 char
메서드의 결과는 java charAt()
이 유니코드를 나타내는 문자가 됩니다.
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 = 참
문자열에 라틴 문자만 포함되어 있으면 정적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 = 거짓
라틴 문자만 있는 경우 클래스가 사용되고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);
}
}
실제로 여기서는 인덱스가 유효한지 확인하기 위한 검사가 이루어집니다. 다시 한번 인덱스가 양수인지 0인지, 배열의 한계를 벗어나지 않았는지 확인합니다. 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
2바이트(2개의 배열 셀)로 표시됩니다. 두 개의 키릴 문자(“av”)로 구성된 문자열이 있는 경우:
- 'a'의 경우 이는 바이트 쌍(48과 4)입니다.
- 'in'의 경우 - 50과 4입니다.
value
즉, 문자열 “av”를 생성하면 배열 ({48, 4, 50, 4})을 갖게 됩니다 . 실제로 이 방법은 두 개의 배열 셀에서 작동합니다 value
. 따라서 다음 단계는 index <<= 1;
배열에서 원하는 문자의 첫 번째 바이트 인덱스로 직접 이동하는 것 입니다 value
. 이제 문자열이 있다고 가정해 보겠습니다 "абвг"
. 그러면 값 배열은 다음과 같습니다: {48, 4, 49, 4, 50, 4, 51, 4}. 문자열의 세 번째 요소를 요청하면 이진수 표현은 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입니다.
- 다음으로 이 두 값에 대해 다음과 같은 작업을 수행합니다
| (OR)
.그리고 이진 표현으로 00000000 00110011 및 00000100 00000000처럼 보이는 바이트 51과 1024가 있는 경우 작업 후
OR
00000100 00110011을 얻게 되며 이는 10진수 체계에서 숫자 1075를 의미합니다.자, 결국 숫자 1075를 char형으로 변환하고, int -> char로 변환할 때 ASCII 테이블을 사용하는데, 그 안에 숫자 1075 아래에 문자 'g'가 들어있습니다.
charAt()
.
GO TO FULL VERSION