Irgendwie habe ich beschlossen, auch die JDK-Quelle zu lesen. Trotzdem habe ich keine Zeit, jede Zeile sorgfältig zu lesen, also habe ich sie kurz gelesen und diesen Code gefunden. Das letzte Mal ich habe die Quelle von Integer gelesen, also wird das nächste Long sein.
Die Long-Klasse ist eine Wrapper-Klasse für den primitiven Typ long. Erstens Felder und Konstruktoren. Nun, es ist eine Quelle, die sich jeder vorstellen kann.
Long.java
private final long value;
public Long(long value) {
this.value = value;
}
Tatsächlich gibt es eine LongCache-Klasse, die in Javadoc nicht angezeigt wird.
Long.java
private static class LongCache {
private LongCache(){}
static final Long cache[] = new Long[-(-128) + 127 + 1];
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Long(i - 128);
}
}
Wenn ich denke, dass Long auch ein externer Parameter wie Integer ist, wurde er von -128 auf 127 festgelegt. Ich habe nichts im Original geschrieben, nicht unkommentiert und zitiert. Dies ist seit JDK 1.5 der Fall, daher scheint Oracle nicht relevant zu sein.
Es ist ein Cache von LongCache, auf den jedoch von valueOf verwiesen wird.
Long.java
public static Long valueOf(long l) {
final int offset = 128;
if (l >= -128 && l <= 127) { // will cache
return LongCache.cache[(int)l + offset];
}
return new Long(l);
}
Ich dachte, ich würde es mit dem Vergleichsoperator == vergleichen, aber es ist dasselbe wie Byte, Short und Integer.
Es ist auch in Integer. Die funktionalen waren die gleichen, als ich dachte, sie wären zusammen, aber die Implementierung war etwas anders. Es ist natürlich, weil es sich von 32-Bit und 64-Bit unterscheidet.
Integer.java
public static int bitCount(int i) {
// HD, Figure 5-2
i = i - ((i >>> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
i = (i + (i >>> 4)) & 0x0f0f0f0f;
i = i + (i >>> 8);
i = i + (i >>> 16);
return i & 0x3f;
}
Long.java
public static int bitCount(long i) {
// HD, Figure 5-14
i = i - ((i >>> 1) & 0x5555555555555555L);
i = (i & 0x3333333333333333L) + ((i >>> 2) & 0x3333333333333333L);
i = (i + (i >>> 4)) & 0x0f0f0f0f0f0f0f0fL;
i = i + (i >>> 8);
i = i + (i >>> 16);
i = i + (i >>> 32);
return (int)i & 0x7f;
}
Da die Bitbreite unterschiedlich ist, ändert sich die Konstante. Nun, Abbildung 5-2 und Abbildung 5-14. Entweder ist einer falsch. Wenn Sie wie Mr. Knoose Typo $ 2,56 bezahlen würden, würde ich gründlich danach suchen.
Ab JDK 1.8 wurden sum, max, min hinzugefügt, die nicht den gleichen Wert wie Integer haben. Ich dachte nicht, dass ich Byte und Short übersprungen hätte.
Long.java
public static long sum(long a, long b) {
return a + b;
}
public static long max(long a, long b) {
return Math.max(a, b);
}
public static long min(long a, long b) {
return Math.min(a, b);
}
Ich habe es in Integer geschrieben, aber wenn sum eine Methode mit Überlauferkennungsfunktion ist, ist es immer noch sinnvoll. Zum Beispiel dachte ich, es wäre professionell, wenn es eine lange Überlauferkennung mit Mehrfachmultiplikation anstelle von Summe gäbe. Die Überlauferkennung kann mit long durch Multiplikation von int berechnet werden, die Überlauferkennung durch Multiplikation mit long ist jedoch problematisch.
Es tut mir leid, dass beiläufig @see java.util.function.BinaryOperator steht. Ich weiß nicht, wie sie zusammenhängen.
Konstanten werden für Byte, Short, Integer und Long definiert. Es gibt fünf MIN_VALUE, MAX_VALUE, TYPE, SIZE, BYTES, und die vorherigen drei stammen aus der Antike, wobei SIZE ab JDK 1.5 und BYTES ab JDK 1.8 hinzugefügt wurden. Nun, ich benutze nur MIN_VALUE und MAX_VALUE.
Byte.java
public static final byte MIN_VALUE = -128;
public static final byte MAX_VALUE = 127;
Short.java
public static final short MIN_VALUE = -32768;
public static final short MAX_VALUE = 32767;
Integer.java
@Native public static final int MIN_VALUE = 0x80000000;
@Native public static final int MAX_VALUE = 0x7fffffff;
Long.java
@Native public static final long MIN_VALUE = 0x8000000000000000L;
@Native public static final long MAX_VALUE = 0x7fffffffffffffffL;
Es ist eine Quelle, die es dem Menschen leicht macht zu verstehen, wo eine große Anzahl erkannt wird. Ich wünschte, ich hätte alle Hexadezimalzahlen. Als ich mir jedoch die Quelle ansah, dachte ich, dass int und long der Maximalwert in Dezimalzahl sein sollten, und es stellte sich heraus, dass es Ghan war. Im Javadoc gibt es konstante Feldwerte, aber sie sind 2147483647 und 9223372036854775807L.
Die Hash-Berechnungslogik wurde seit JDK 1.8 in statischen Methoden implementiert. Bis JDK 1.7 wurde die Logik in einer normalen Methode geschrieben.
Long.java
public int hashCode() {
return Long.hashCode(value);
}
public static int hashCode(long value) {
return (int)(value ^ (value >>> 32));
}
Bei der Überlegung, wie 64 Bit zu 32 Bit verarbeitet werden sollen, war dies eine exklusive logische Summe (XOR) zwischen den oberen und unteren 32 Bit.
Dies ist eine alte Methode.
Long.java
public static String toString(long i) {
if (i == Long.MIN_VALUE)
return "-9223372036854775808";
int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
char[] buf = new char[size];
getChars(i, size, buf);
return new String(buf, true);
}
Die Verarbeitung zum Zeitpunkt von Long.MIN_VALUE ist ziemlich schwierig. Wenn es negativ ist, ist der Absolutwert um 1 größer, was auf verschiedene Weise problematisch ist. Eigentlich mache ich mit getChars eine Zeichenkette, aber es ist ein Pfad, weil es schwierig ist, die Quelle zu betrachten.
Wenn Sie an Integer.toString denken,
Integer.java
public static String toString(int i) {
if (i == Integer.MIN_VALUE)
return "-2147483648";
int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
char[] buf = new char[size];
getChars(i, size, buf);
return new String(buf, true);
}
Was machst du auch Was ist also mit Short und Byte?
Short.java
public static String toString(short s) {
return Integer.toString((int)s, 10);
}
Byte.java
public static String toString(byte b) {
return Integer.toString((int)b, 10);
}
Wie erwartet riefen diese Integer.toString auf.
Dies ist eine alte Methode.
Long.java
public static long parseLong(String s, int radix)
throws NumberFormatException
{
if (s == null) {
throw new NumberFormatException("null");
}
if (radix < Character.MIN_RADIX) {
throw new NumberFormatException("radix " + radix +
" less than Character.MIN_RADIX");
}
if (radix > Character.MAX_RADIX) {
throw new NumberFormatException("radix " + radix +
" greater than Character.MAX_RADIX");
}
long result = 0;
boolean negative = false;
int i = 0, len = s.length();
long limit = -Long.MAX_VALUE;
long multmin;
int digit;
if (len > 0) {
char firstChar = s.charAt(0);
if (firstChar < '0') { // Possible leading "+" or "-"
if (firstChar == '-') {
negative = true;
limit = Long.MIN_VALUE;
} else if (firstChar != '+')
throw NumberFormatException.forInputString(s);
if (len == 1) // Cannot have lone "+" or "-"
throw NumberFormatException.forInputString(s);
i++;
}
multmin = limit / radix;
while (i < len) {
// Accumulating negatively avoids surprises near MAX_VALUE
digit = Character.digit(s.charAt(i++),radix);
if (digit < 0) {
throw NumberFormatException.forInputString(s);
}
if (result < multmin) {
throw NumberFormatException.forInputString(s);
}
result *= radix;
if (result < limit + digit) {
throw NumberFormatException.forInputString(s);
}
result -= digit;
}
} else {
throw NumberFormatException.forInputString(s);
}
return negative ? result : -result;
}
Das Überprüfen von NumberFormatException ist in Ordnung. Es gibt auch einen Nur-Nur-Scheck.
Wenn Sie denken, dass es in Ordnung ist, einen kurzen Blick darauf zu werfen, ziehen Sie mit result- = digit; Wenn Sie denken, dass es sich um eine Addition handelt, geben Sie ein negatives Ergebnis zurück: -Ergebnis: und das Vorzeichen ist entgegengesetzt. Ich frage mich, ob das Minus ist, weil der absolute Wert 1 größer ist.
Wenn Sie sich fragen, was ist, wenn (Ergebnis <Grenze + Ziffer) ist, führen Sie Ergebnis -digit aus und bringen Sie es auf die rechte Seite, um den Bereich zu überprüfen, damit der Absolutwert nicht überläuft? Wenn ich es schreibe, ziehe ich es vorerst heraus, und wenn der Wert, der negativ sein sollte, positiv wird, wird es als Überlauf beurteilt.
Eine Methode namens parseUnsignedInt wurde seit JDK 1.8 zu Integer hinzugefügt, aber auch zu Long. Ist Java nicht lange signiert? Was bedeutet es, es ohne Vorzeichen zu analysieren?
Long.java
public static long parseUnsignedLong(String s, int radix)
throws NumberFormatException {
if (s == null) {
throw new NumberFormatException("null");
}
int len = s.length();
if (len > 0) {
char firstChar = s.charAt(0);
if (firstChar == '-') {
throw new
NumberFormatException(String.format("Illegal leading minus sign " +
"on unsigned string %s.", s));
} else {
if (len <= 12 || // Long.MAX_VALUE in Character.MAX_RADIX is 13 digits
(radix == 10 && len <= 18) ) { // Long.MAX_VALUE in base 10 is 19 digits
return parseLong(s, radix);
}
// No need for range checks on len due to testing above.
long first = parseLong(s.substring(0, len - 1), radix);
int second = Character.digit(s.charAt(len - 1), radix);
if (second < 0) {
throw new NumberFormatException("Bad digit at end of " + s);
}
long result = first * radix + second;
if (compareUnsigned(result, first) < 0) {
/*
* The maximum unsigned value, (2^64)-1, takes at
* most one more digit to represent than the
* maximum signed value, (2^63)-1. Therefore,
* parsing (len - 1) digits will be appropriately
* in-range of the signed parsing. In other
* words, if parsing (len -1) digits overflows
* signed parsing, parsing len digits will
* certainly overflow unsigned parsing.
*
* The compareUnsigned check above catches
* situations where an unsigned overflow occurs
* incorporating the contribution of the final
* digit.
*/
throw new NumberFormatException(String.format("String value %s exceeds " +
"range of unsigned long.", s));
}
return result;
}
} else {
throw NumberFormatException.forInputString(s);
}
}
Wenn Sie es um eine Ziffer reduzieren und analysieren und es beim Hinzufügen der letzten Ziffer verringert, fühlt es sich wie ein Überlauf an. Es analysiert unsigniert, kann aber negativ sein. Es ist eine großartige Spezifikation.
Lass es uns versuchen.
Main.java
public static void main(String[] args) {
long l01 = Long.parseUnsignedLong("9223372036854775807");
System.out.println(l01);
long l02 = Long.parseUnsignedLong("9223372036854775808");
System.out.println(l02);
long l03 = Long.parseUnsignedLong("18446744073709551615");
System.out.println(l03);
long l04 = Long.parseUnsignedLong("18446744073709551616");
System.out.println(l04);
}
Wenn du rennst ...
9223372036854775807
-9223372036854775808
-1
Exception in thread "main" java.lang.NumberFormatException: String value 18446744073709551616 exceeds range of unsigned long.
at java.lang.Long.parseUnsignedLong(Long.java:719)
at java.lang.Long.parseUnsignedLong(Long.java:746)
at Main.main(Main.java:28)
Das Ergebnis ist wie erwartet, aber sind Sie glücklich? Dies. Wenn Sie 64-Bit voll verwenden möchten, können Sie BigInteger verwenden.
In der Vergangenheit war 32-Bit der Standard, sodass Sie sehen können, dass 32-Bit-Int und 64-Bit-Länge separat implementiert werden. Wenn es lang ist, scheint die Verarbeitung schwer zu sein. In 64-Bit-Betriebssystemen wird derzeit im Allgemeinen eine 64-Bit-VM verwendet, und in Bezug auf die Hardware scheint 64-Bit-Länge normal zu funktionieren. Im Fall von Intel x64 ist das Allzweckregister beispielsweise 8-Bit-Register: AH AL BH BL CH CL DH DL 16-Bit-Register: AX BX CX DX 32-Bit-Register: EAX EBX ECX EDX 64-Bit-Register: RAX RBX RCX RDX R8 R9 R10 R11 R12 R13 R14 R15 Jetzt nimmt die Anzahl der 64-Bit-Register so stark zu!
Ich bin der Meinung, dass die Bytecode-Spezifikationen der aktuellen JVM auf 32 Bit basieren, daher denke ich, dass ich sie beim nächsten Mal auf 64 Bit aktualisieren und lange, lange 128 Bit erstellen kann.
Recommended Posts