[JAVA] J'ai lu la source de Long

D'une manière ou d'une autre, j'ai décidé de lire également la source JDK. Cela dit, je n'ai pas le temps de lire attentivement chaque ligne, alors je l'ai lu brièvement et j'ai trouvé ce code. La dernière fois j'ai lu la source d'Integer, la prochaine sera donc Long.

Classe longue

La classe Long est une classe wrapper pour le type primitif long. Premièrement, les champs et les constructeurs. Eh bien, c'est une source que tout le monde peut imaginer.

Long.java


    private final long value;

    public Long(long value) {
        this.value = value;
    }

Classe LongCache

En fait, il existe une classe LongCache qui ne peut pas être vue dans javadoc.

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);
        }
    }

Si je pense que Long est également un paramètre externe comme Integer, il a été fixé de -128 à 127. Je n'ai rien écrit dans l'original, pas sans commentaire ni cité. C'est le cas depuis le JDK 1.5, donc Oracle ne semble pas pertinent.

C'est un cache de LongCache, mais il est référencé par valueOf.

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);
    }

Je pensais que je le comparerais avec l'opérateur de comparaison ==, mais c'est la même chose que Byte, Short et Integer.

Source Hacker's Delight

Il est également en Integer. Les fonctionnels étaient les mêmes quand je pensais qu'ils étaient ensemble, mais la mise en œuvre était légèrement différente. C'est naturel parce que c'est différent de 32 bits et 64 bits.

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;
     }

La largeur de bits étant différente, la constante changera. Eh bien, Figure 5-2 et Figure 5-14. L'un ou l'autre a tort. Si vous payiez 2,56 $ Typo comme M. Knoose, je le chercherais à fond.

méthode sum, méthode max, méthode min

Il y avait sum, max, min ajouté à partir de JDK 1.8 qui ne ressentent pas la même valeur d'existence que Integer. Je ne pensais pas avoir sauté Byte et Short.

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);
    }

Je l'ai écrit en Integer, mais si sum est une méthode avec une fonction de détection de débordement, cela a toujours du sens. Par exemple, j'ai pensé que ce serait professionnel s'il y avait une longue détection de dépassement avec multiplication multiple au lieu de somme. La détection de débordement peut être calculée avec long en multipliant int, mais la détection de débordement en multipliant long est gênante.

Je suis désolé qu'il dise avec désinvolture @see java.util.function.BinaryOperator. Je ne sais pas comment ils sont liés.

Constant

Les constantes sont définies pour Byte, Short, Integer et Long. Il y en a cinq, MIN_VALUE, MAX_VALUE, TYPE, SIZE, BYTES, et les trois premiers datent des temps anciens, avec SIZE ajouté à partir du JDK 1.5 et BYTES à partir du JDK 1.8. Eh bien, je n'utilise que MIN_VALUE et 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;

C'est une source qui permet aux humains de comprendre facilement où un grand nombre est reconnu. J'aurais aimé avoir tous les nombres hexadécimaux. Cependant, quand j'ai regardé la source, j'ai pensé que int et long devraient être la valeur maximale en décimal, et il s'est avéré être Ghan. En regardant le javadoc, il y a des valeurs de champ constantes, mais ce sont 2147483647 et 9223372036854775807L.

méthode hashCode

La logique de calcul de hachage a été implémentée dans les méthodes statiques depuis JDK 1.8. Jusqu'au JDK 1.7, la logique était écrite selon une méthode normale.

Long.java


    public int hashCode() {
        return Long.hashCode(value);
    }

    public static int hashCode(long value) {
        return (int)(value ^ (value >>> 32));
    }

Lorsque l'on réfléchit à la façon de traiter 64 bits en 32 bits, il s'agissait d'une somme logique exclusive (XOR) entre les 32 bits supérieurs et inférieurs.

méthode toString

C'est une vieille méthode.

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);
    }

Le traitement au moment de Long.MIN_VALUE est assez difficile. Eh bien, si elle est négative, la valeur absolue sera plus grande de 1, donc ce sera gênant. En fait, je crée une chaîne de caractères avec getChars, mais c'est un chemin car il est difficile de regarder la source.

Si vous pensez à Integer.toString,

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);
    }

Que fais-tu aussi? Alors qu'en est-il de Short and 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);
    }

Comme prévu, ils appelaient Integer.toString.

méthode parseLong

C'est une vieille méthode.

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;
    }

Vérifier NumberFormatException est très bien. Il existe également un contrôle + uniquement.

Si vous pensez que vous pouvez jeter un coup d'œil rapide, tirez-vous avec result- = digit;? Si vous pensez que c'est une addition, retournez un résultat négatif? Résultat: -résultat; et le signe est opposé. Je me demande si le moins est dû au fait que la valeur absolue est 1 plus grande.

Si vous vous demandez ce que signifie si (résultat <limite + chiffre), faites-vous result -digit et amenez-le sur le côté droit pour vérifier la plage afin que la valeur absolue ne déborde pas? Si je l'écris, je vais le tirer pour le moment, et si la valeur qui devrait être négative devient positive, elle sera jugée comme dépassement.

Méthode parseUnsignedLong

Une méthode appelée parseUnsignedInt a été ajoutée à Integer depuis le JDK 1.8, mais elle a également été ajoutée à Long. Java n'est-il pas signé depuis longtemps? Qu'est-ce que cela signifie de l'analyser non signé?

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);
        }
    }

Quoi qu'il en soit, si vous le réduisez d'un chiffre et parseLong, et s'il diminue lorsque vous ajoutez le dernier chiffre, cela ressemble à un débordement. Il analyse les non-signés, mais cela peut être négatif. C'est une excellente spécification.

Essayons.

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);
    }

Quand tu cours ...

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)

Le résultat est comme prévu, mais êtes-vous heureux? cette. Si vous souhaitez utiliser la version 64 bits complète, vous pouvez utiliser BigInteger.

finalement

Dans le passé, 32 bits était la norme, il est donc compréhensible que les entiers 32 bits et 64 bits de long soient implémentés séparément. S'il est long, le traitement semble lourd. Cependant, dans le système d'exploitation 64 bits, la machine virtuelle 64 bits est généralement utilisée maintenant, et en termes de matériel, il semble que la longueur 64 bits fonctionne normalement. Par exemple, dans le cas d'Intel x64, le registre à usage général est Registre 8 bits: AH AL BH BL CH CL DH DL Registre 16 bits: AX BX CX DX Registre 32 bits: EAX EBX ECX EDX Registre 64 bits: RAX RBX RCX RDX R8 R9 R10 R11 R12 R13 R14 R15 Maintenant, le nombre de registres 64 bits augmente tellement!

Je pense que les spécifications de code d'octet de la JVM actuelle sont basées sur 32 bits, donc je pense que je peux la mettre à niveau en 64 bits et faire de longues 128 bits la prochaine fois.

Recommended Posts

J'ai lu la source de Long
J'ai lu la source de ArrayList que j'ai lu
J'ai lu la source d'Integer
J'ai lu la source de Short
J'ai lu la source de Byte
J'ai lu la source de String
J'ai lu le livre de démarrage de Kotlin
DrainTo de LinkedBlockingQueue est-il sûr? J'ai suivi la source
05. J'ai essayé de supprimer la source de Spring Boot
J'ai étudié le traitement interne de Retrofit
[jour: 5] J'ai résumé les bases de Java
J'ai compris les bases de la saisie de caractères
J'ai comparé les caractéristiques de Java et .NET
Je veux var_dump le contenu de l'intention
J'ai essayé d'utiliser le profileur d'IntelliJ IDEA
J'ai vérifié le nombre de taxis avec Ruby
Essayez Progate Free Edition [Java I]
[Java] Comment obtenir l'URL de la source de transition
J'ai essayé d'utiliser la fonction Server Push de Servlet 4.0
J'ai lu le code lisible, alors prends note
J'étais accro au record du modèle associé
J'ai vu la liste du développement Android collectivement
J'ai essayé de réduire la capacité de Spring Boot
Jugement du calendrier
J'ai essayé le nouveau profileur de fonctionnalités d'IntelliJ IDEA 2019.2.
Le monde de Clara-Rules (4)
Je veux connaître la réponse de l'application Janken
Traitement d'image: structure de base de l'image lue par le programme
Je souhaite afficher le nom de l'affiche du commentaire
J'ai résumé le format d'affichage de la réponse JSON de Rails
Le monde de Clara-Rules (1)
Le monde de Clara-Rules (3)
Lire la source Java HashMap
J'ai lu le "Guide pratique orienté objet", donc un mémorandum
Source des objets cellulaires
Relisez le guide des rails (vue d'ensemble du contrôleur d'action)
[Java] Lors de l'écriture du source ... Mémorandum ①
J'ai écrit un diagramme de séquence de l'exemple j.u.c.Flow
Le monde de Clara-Rules (5)
J'ai résumé les types et les bases des exceptions Java
L'idée du tri rapide
Je suis parfaitement conscient de la commodité de graphql-code-generator partie 2
Je ne peux pas sortir de l'écran de la console Rails db
Je veux retourner la position de défilement de UITableView!
L'idée de jQuery
J'ai créé le côté serveur du jeu de cartes en ligne ①
Je n'ai pas vraiment compris le comportement de Java Scanner et .nextLine ()
J'ai jeté un coup d'œil à l'intérieur du Java HashMap
J'ai essayé de résumer les bases de kotlin et java
[Android] Quittez l'activité de la source de transition au moment de la transition d'écran
Je souhaite modifier le paramètre de sortie du journal de UtilLoggingJdbcLogger