Es gibt viele grundlegende Techniken, die wir regelmäßig anwenden, ohne darüber nachzudenken. Was wäre, wenn Sie darüber nachdenken und sich ansehen, wie einige scheinbar einfache Methoden umgesetzt werden? Ich denke, das wird uns helfen, Java einen Schritt näher zu kommen.) Stellen wir uns eine Situation vor, in der wir ein bestimmtes Zeichen aus einer Zeichenfolge extrahieren müssen. Wie können wir das in Java machen? Zum Beispiel durch den Aufruf von
Java String charAt
. Wir werden im heutigen Artikel über die Methode charAt()
sprechen .
Syntax
char charAt(int index)
gibt den char-Wert am angegebenen Index zurück. Der Index reicht von 0 bis length()-1
. Das heißt, der erste char
Wert der Sequenz liegt in index 0
, der nächste in index 1
usw., wie es bei der Array-Indizierung der Fall ist.
Beispiel
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));
}
Die erste Zeile nimmt das erste Zeichen auf, die zweite Zeile das zweite und so weiter. Da dies nicht der Fall ist println
, sondern hier verwendet wird print
, ohne eine neue Zeile, erhalten wir die folgende Ausgabe auf der Konsole:
Java
Wenn der angegebene Index als Unicode dargestellt wird, ist char
das Ergebnis der Methode das Zeichen, das diesen Unicode darstellt:java charAt()
System.out.println("J\u0061vaRush".charAt(1));
Konsolenausgabe:
a
Was ist „unter der Haube“
Wie funktioniert es, fragen Sie? Tatsache ist, dass jedes ObjektString
ein Array byte
mit Bytes der Elemente einer bestimmten Zeichenfolge enthält:
private final byte[] value;
Und hier ist die Methode selbst chatAt
:
public char charAt(int index) {
if (isLatin1()) {
return StringLatin1.charAt(value, index);
} else {
return StringUTF16.charAt(value, index);
}
}
isLatin1
– ein Flag, das angibt, ob unsere Zeichenfolge nur lateinische Zeichen enthält oder nicht. Dadurch wird bestimmt, welche Methode als nächstes aufgerufen wird.
isLatin1 = wahr
Wenn die Zeichenfolge nur lateinische Zeichen enthält, wird eine statischecharAt
Klassenmethode aufgerufen StringLatin1
:
public static char charAt(byte[] value, int index) {
if (index < 0 || index >= value.length) {
throw new StringIndexOutOfBoundsException(index);
}
return (char)(value[index] & 0xff);
}
Der erste Schritt besteht darin, zu überprüfen, ob der eingehende Index größer oder gleich 0 ist und nicht über das interne Byte-Array hinausgeht. Ist dies nicht der Fall, wird eine Ausnahme ausgelöst new StringIndexOutOfBoundsException(index)
. Wenn die Prüfungen bestanden werden, wird das von uns benötigte Element übernommen. Am Ende sehen wir:
&
erweitert sich für binäre Operationen aufbyte
bitweise0xff
tut nichts,&
erfordert aber ein Argument(char)
Konvertiert Daten aus einer ASCII-Tabelle inchar
isLatin1 = false
Wenn wir nicht nur lateinische Zeichen hätten, wird die Klasse verwendetStringUTF16
und ihre statische Methode wird aufgerufen:
public static char charAt(byte[] value, int index) {
checkIndex(index, value);
return getChar(value, index);
}
Was wiederum heißt:
public static void checkIndex(int off, byte[] val) {
String.checkIndex(off, length(val));
}
Und er delegiert an eine statische Methode String
:
static void checkIndex(int index, int length) {
if (index < 0 || index >= length) {
throw new StringIndexOutOfBoundsException("index " + index +
", length " + length);
}
}
Hier wird tatsächlich geprüft, ob der Index gültig ist: wiederum ob er positiv oder Null ist und ob er nicht über die Grenzen des Arrays hinausgegangen ist. Aber in einer Klasse StringUTF16
in einer Methode charAt
wird der Aufruf der zweiten Methode interessanter sein:
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));
}
Beginnen wir mit der Analyse, was hier tatsächlich passiert. Der erste Schritt zu Beginn der Methode ist eine erneute Prüfung der Gültigkeit des Index. Um zu verstehen, was als nächstes passiert, müssen Sie verstehen: Wenn ein nicht-lateinisches Zeichen in das Array eintritt value
, wird es durch zwei Bytes (zwei Array-Zellen) dargestellt. Wenn wir eine Zeichenfolge aus zwei kyrillischen Zeichen haben – „av“, dann:
- für „a“ ist dies ein Bytepaar – 48 und 4;
- für 'in' - 50 und 4.
value
– {48, 4, 50, 4}. Tatsächlich funktioniert diese Methode mit zwei Array-Zellen value
. Daher ist der nächste Schritt eine Verschiebung index <<= 1;
, um direkt zum Index des ersten Bytes des gewünschten Zeichens im Array zu gelangen value
. Nehmen wir nun an, wir haben eine Zeichenfolge "абвг"
. Dann sieht das Wertearray so aus: {48, 4, 49, 4, 50, 4, 51, 4}. Wir fragen nach dem dritten Element der Zeichenfolge, und dann ist die binäre Darstellung 00000000 00000011. Bei einer Verschiebung um 1 erhalten wir 00000000 00000110, also index = 6
. Um Ihr Wissen über bitweise Operationen aufzufrischen, können Sie diesen Artikel lesen . Wir sehen auch einige Variablen: HI_BYTE_SHIFT
In diesem Fall ist es 0. LO_BYTE_SHIFT
In diesem Fall ist es 8. In der letzten Zeile dieser Methode:
- Ein Element wird aus dem Wertearray entnommen und bitweise um
HI_BYTE_SHIFT
, also 0, verschoben, während zunehmen wirdindex +1
.Im Beispiel mit dem String
"абвг"
würde das sechste Byte – 51 – so bleiben, gleichzeitig erhöht sich aber der Index auf 7. - Danach wird das nächste Element des Arrays genommen und auf die gleiche Weise bitweise verschoben, jedoch um LO_BYTE_SHIFT, also um 8 Bit.
Und wenn wir Byte 4 hätten, das eine binäre Darstellung hat – 00000000 00000100, dann hätten wir nach der Verschiebung um 8 Bits 00000100 00000000. Wenn es eine ganze Zahl ist – 1024.
- Als nächstes folgt für diese beiden Werte die Operation
| (OR)
.Und wenn wir die Bytes 51 und 1024 hätten, die in binärer Darstellung wie 00000000 00110011 und 00000100 00000000 aussehen, dann
OR
erhalten wir nach der Operation 00000100 00110011, was im Dezimalsystem die Zahl 1075 bedeutet.Nun, am Ende wird die Zahl 1075 in den Typ char umgewandelt, und bei der Konvertierung int -> char wird die ASCII-Tabelle verwendet, und darin steht unter der Zahl 1075 das Zeichen „r“.
charAt()
in der Java-Programmierung.
GO TO FULL VERSION