بسیاری از تکنیک های اساسی وجود دارد که ما به طور مرتب از آنها استفاده می کنیم بدون اینکه حتی به آن فکر کنیم. خوب، اگر در مورد آن فکر کنید و به نحوه پیاده سازی برخی روش های به ظاهر ساده نگاه کنید، چه؟ فکر میکنم این به ما کمک میکند یک قدم به جاوا نزدیکتر شویم) بیایید موقعیتی را تصور کنیم که در آن باید یک کاراکتر خاص را در یک رشته استخراج کنیم. چگونه می توانیم این کار را در جاوا انجام دهیم؟ برای مثال، با تماس با
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));
}
خط اول کاراکتر اول را می گیرد، خط دوم کاراکتر دوم را می گیرد و غیره. از آنجایی که نه println
، اما در اینجا استفاده می شود 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);
}
}
در اینجا، در واقع، بررسی می شود که آیا شاخص معتبر است یا خیر: دوباره مثبت است یا صفر، و اینکه آیا از محدوده های آرایه فراتر نرفته است. اما در یک کلاس 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.
value
- {48، 4، 50، 4} در واقع، این روش با دو سلول آرایه کار می کند value
. بنابراین، گام بعدی تغییر index <<= 1;
جهت رسیدن مستقیم به شاخص اولین بایت کاراکتر مورد نظر در آرایه است value
. حالا فرض کنید یک رشته داریم "абвг"
. سپس آرایه مقادیر به این صورت خواهد بود: {48, 4, 49, 4, 50, 4, 51, 4}. ما عنصر سوم رشته را درخواست می کنیم، و سپس نمایش باینری 00000000 000000011 است. وقتی با 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 خواهیم داشت. اگر یک عدد صحیح باشد - 1024.
- بعد، برای این دو مقدار، عملیات را دنبال می کند
| (OR)
.و اگر بایت های 51 و 1024 را داشتیم که در نمایش باینری مانند 00000000 00110011 و 00000100 00000000 بود، پس از عملیات به
OR
00000100 00110011 خواهیم رسید که در سیستم عدد 107 به معنای 5 است.خب در نهایت عدد 1075 به نوع char تبدیل می شود و هنگام تبدیل int -> char از جدول ASCII استفاده می شود و در آن زیر عدد 1075 کاراکتر 'g' وجود دارد.
charAt()
در برنامه نویسی جاوا، 'g' را دریافت می کنیم.
GO TO FULL VERSION