มีเทคนิคพื้นฐานมากมายที่เราใช้เป็นประจำโดยไม่ต้องคิดเลย แล้วถ้าคุณคิดเกี่ยวกับมันและดูว่าวิธีการบางอย่างที่ดูเหมือนง่าย ๆ นั้นถูกนำไปใช้อย่างไร? ฉันคิดว่านี่จะช่วยให้เราเข้าใกล้ Java มากขึ้นอีกขั้นหนึ่ง)
ลองจินตนาการถึงสถานการณ์ที่เราจำเป็นต้องแยกอักขระบางตัวออกจากสตริงบางตัว เราจะทำสิ่งนี้ใน Java ได้อย่างไร? เช่น โดยการเรียก
ความจริงก็คือแต่ละวัตถุ
เรายังเห็นตัวแปรบางตัวด้วย:
Java String charAt
. charAt()
เราจะพูดถึงวิธีการ ในบทความของวันนี้
ไวยากรณ์
char charAt(int index)
ส่งกลับค่าถ่านที่ดัชนีที่ระบุ ดัชนีมีตั้งแต่ 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));
}
บรรทัดแรกใช้อักขระตัวแรก บรรทัดที่สองใช้อักขระตัวที่สอง และต่อๆ ไป เนื่องจากไม่ใช่println
แต่ ถูกใช้ที่นี่ print
หากไม่มีบรรทัดใหม่ เราจะได้ผลลัพธ์ต่อไปนี้ไปยังคอนโซล:
Java
หากchar
ดัชนีที่กำหนดแสดงเป็น Unicode ผลลัพธ์ของวิธีการ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 = จริง
หากสตริงมีเพียงอักขระละติน วิธี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);
}
}
ที่จริงแล้ว มีการตรวจสอบเพื่อดูว่าดัชนีนั้นถูกต้องหรือไม่ อีกครั้ง ไม่ว่าจะเป็นค่าบวกหรือศูนย์ และไม่เกินขีดจำกัดของอาร์เรย์หรือไม่ แต่ในคลาส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;
- สำหรับ 'ใน' - 50 และ 4
value
- {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
ขึ้นในตัวอย่างที่มีสตริง ไบต์
"абвг"
ที่หก - 51 - จะยังคงเป็นเช่นนั้น แต่ในขณะเดียวกันดัชนีก็จะเพิ่มขึ้นเป็น 7 - หลังจากนี้ องค์ประกอบถัดไปของอาร์เรย์จะถูกรับและเลื่อนระดับบิตในลักษณะเดียวกัน แต่โดย LO_BYTE_SHIFT นั่นคือ 8 บิต
และถ้าเรามีไบต์ 4 ซึ่งมีการแทนค่าไบนารี่ - 00000000 00000100 จากนั้นหลังจากเลื่อนไป 8 บิตเราจะได้ 00000100 00000000 ถ้าเป็นจำนวนเต็ม - 1,024
- ถัดไป สำหรับสองค่านี้ ให้ปฏิบัติตามการดำเนิน
| (OR)
การและถ้าเรามีไบต์ 51 และ 1,024 ซึ่งในการเป็นตัวแทนไบนารีดูเหมือน 00000000 00110011 และ 00000100 00000000 หลังจากการดำเนินการ
OR
เราจะได้รับ 00000100 00110011 ซึ่งหมายถึงตัวเลข 1,075 ในระบบทศนิยมในที่สุดหมายเลข 1,075 จะถูกแปลงเป็นประเภทถ่านและเมื่อแปลง int -> char จะใช้ตาราง ASCII และในนั้นภายใต้หมายเลข 1,075 จะมีอักขระ 'g'
charAt()
ในการเขียนโปรแกรม Java
GO TO FULL VERSION