Интервью с исходным кодом java Integer обязательно

интервью Java задняя часть JVM исходный код

В интервью обычно спрашивают, видели ли вы исходный код, поэтому я написал эту интерпретацию исходного кода со ссылкой на онлайн-материалы и свое собственное мнение.

Обзор

Сначала введите разницу между Integer и int

1. Integer — это класс-оболочка для int, который является базовым типом данных в java.
2. Целочисленные переменные должны быть созданы до того, как их можно будет использовать, в то время как целые переменные не должны быть
3. Integer на самом деле является ссылкой на объект, при использовании нового Integer фактически генерируется указатель, указывающий на этот объект, а int предназначен для непосредственного хранения значения данных.

Переменная Integer, сгенерированная non-new, указывает на объект в пуле констант Java, а переменная, сгенерированная new Integer(), указывает на вновь созданный объект в куче, а адреса двух в памяти разные)

Integer a = new Integer(99);
Integer b = 99;
System.out.print(a== b); 
//false

4. Значение по умолчанию для Integer равно null, а значение по умолчанию для int равно 0.

Ingeter в Java — это класс-оболочка для int, и мы можем в основном приравнять их в разработке.

Класс Integer инкапсулирует int, который содержит методы для обработки типов int, такие как методы преобразования int-to-String или методы преобразования String-to-int, а также преобразования с другими типами, включая, конечно же, методы манипулирования битами.

главный атрибут

Ограниченный диапазон Integer равен0x7fffffff~0x80000000 这Границы типа int такие же.

Это объявлено в классе Integer.

//MIN_VALUE静态变量表示int能取的最小值,为-2的31次方,被final修饰说明不可变。
public static final int   MIN_VALUE = 0x80000000;
//类似的还有MAX_VALUE,表示int最大值为2的31次方减1。
public static final int   MAX_VALUE = 0x7fffffff;
public static final int SIZE = 32;


SIZE используется для представления количества битов значения int в форме дополнения до двух, и значение равно 32. Поскольку это статическая переменная, значение неизменяемо.

Поскольку дополнение до двух представляет отношение отрицательных чисел. Положительные числа всегда на единицу больше, чем отрицательные, поэтому:

MIN_VALUE представляет минимальное значение, которое может принимать int, равное -2 в 31-й степени.

MAX_VALUE указывает, что int может принимать максимальное значение, равное 2 в 31-й степени минус 1.

public static final Class<Integer>  TYPE = (Class<Integer>) Class.getPrimitiveClass("int");

Еще вот это, this должно относиться к типу, тип int.

final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
                                      99999999, 999999999, Integer.MAX_VALUE };
// Requires positive xstatic int stringSize(int x) {
    for (int i=0; ; i++)
        if (x <= sizeTable[i])
            return i+1;
}

stringSize в основном предназначен для определения длины строки, соответствующей числу int. Массив sizeTable хранит максимальное количество битов.

   final static char[] digits = {
        '0' , '1' , '2' , '3' , '4' , '5' ,
        '6' , '7' , '8' , '9' , 'a' , 'b' ,
        'c' , 'd' , 'e' , 'f' , 'g' , 'h' ,
        'i' , 'j' , 'k' , 'l' , 'm' , 'n' ,
        'o' , 'p' , 'q' , 'r' , 's' , 't' ,
        'u' , 'v' , 'w' , 'x' , 'y' , 'z'
    };

В массиве digits хранятся символы, представленные числами от двоичного до 36-кратного основания, поэтому для представления всех чисел, не являющихся основанием, требуется 36 символов.

final static char [] DigitTens = {
        '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
        '1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
        '2', '2', '2', '2', '2', '2', '2', '2', '2', '2',
        '3', '3', '3', '3', '3', '3', '3', '3', '3', '3',
        '4', '4', '4', '4', '4', '4', '4', '4', '4', '4',
        '5', '5', '5', '5', '5', '5', '5', '5', '5', '5',
        '6', '6', '6', '6', '6', '6', '6', '6', '6', '6',
        '7', '7', '7', '7', '7', '7', '7', '7', '7', '7',
        '8', '8', '8', '8', '8', '8', '8', '8', '8', '8',
        '9', '9', '9', '9', '9', '9', '9', '9', '9', '9',
        } ;

final static char [] DigitOnes = {
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        } ;

DigitTens и DigitOnes — это два массива: массив DigitTens предназначен для получения десятков числа от 0 до 99, а DigitOnes — для получения разряда единиц числа от 0 до 99.

Внутренний класс IntegerCache

private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer cache[];

    static {
        // high value may be configured by property
        int h = 127;
        String integerCacheHighPropValue =
            sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (integerCacheHighPropValue != null) {
            int i = parseInt(integerCacheHighPropValue);
            i = Math.max(i, 127);
            // Maximum array size is Integer.MAX_VALUE
            h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
        }
        high = h;

        cache = new Integer[(high - low) + 1];
        int j = low;
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);
    }

    private IntegerCache() {}
}

IntegerCache – это статический внутренний класс Integer. Он содержит массив целых чисел, которые могут иметь значение int. Он отвечает за хранение (высокий-низкий) статических объектов Integer и их инициализацию в статических блоках кода. Диапазон по умолчанию — [-128, 127], поэтому по умолчанию здесь создается только 256 объектов Integer.Когда диапазон значений Integer равен [-128, 127], соответствующий объект Integer получается напрямую из кэша без повторного создания экземпляров. . Эти кэшированные значения являются статическими и окончательными, что позволяет избежать повторного создания и повторного использования.

Если вы не настроите параметры виртуальной машины, это значение не изменится. В сочетании с методом valueOf(int) потребление ресурсов, вызванное созданием объектов, может быть снижено. Кроме того, если вы хотите изменить диапазон кеша этих значений, вы можете изменить максимальное значение значения кеша через -Djava.lang.Integer.IntegerCache.high=xxx при повторном запуске JVM, например -Djava.lang .Integer.IntegerCache.high=888 [-888] будет кэшироваться. 


метод

parseInt

public static int parseInt(String s) throws NumberFormatException {
    return parseInt(s,10);
}
public static int parseInt(String s, int radix)
            throws NumberFormatException
{
    /*
     * WARNING: This method may be invoked early during VM initialization
     * before IntegerCache is initialized. Care must be taken to not use
     * the valueOf method.
     */

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

    int result = 0;
    boolean negative = false;
    int i = 0, len = s.length();
    int limit = -Integer.MAX_VALUE;
    int multmin;
    int digit;

    if (len > 0) {
        char firstChar = s.charAt(0);
        if (firstChar < '0') { // Possible leading "+" or "-"
            if (firstChar == '-') {
                negative = true;
                limit = Integer.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;
}

Есть два метода parseInt, вот перегрузка (overload) java, о которой будет рассказано позже.Первый параметр — это преобразуемая строка, а второй параметр — базовое число (например, 2, 8, 10).

Источник уже приводил примеры:

* parseInt("0", 10) returns 0
* parseInt("473", 10) returns 473
* parseInt("+42", 10) returns 42
* parseInt("-0", 10) returns 0
* parseInt("-FF", 16) returns -255
* parseInt("1100110", 2) returns 102
* parseInt("2147483647", 10) returns 2147483647
* parseInt("-2147483648", 10) returns -2147483648
* parseInt("2147483648", 10) throws a NumberFormatException
* parseInt("99", 8) throws a NumberFormatException
* parseInt("Kona", 10) throws a NumberFormatException
* parseInt("Kona", 27) returns 411787d

ноInteger.parseInt("10000000000",10), броситjava.lang.NumberFormatExceptionИсключение, так как превышен максимальный диапазон целых чисел. 

Логика метода:

1. Судя по тому, что строка не пустая, а входящий шестнадцатеричный параметр находится вСимвол.MIN_RADIX , Символ.MAX_RADIXот 2 до 36.

2. Определить, что длина входной строки должна быть больше 0, а затем обработать ее в соответствии с тем, что первая строка может быть числом либо с отрицательным, либо с положительным знаком.

3. Затем следует основная логика преобразования строк в числа.

Например

Преобразование 127 в восьмеричное число 1*8*8+2*8+7*1=87

Преобразование 127 в десятичное число 1*10*10+2*10+7*1=127

Пройдите по строке слева направо, умножьте на базовое число, добавьте следующий символ, затем умножьте на базовое число, добавьте следующий символ и повторите до последнего символа.

Это также позволяет избежать проблемы обработки Integer.MIN_VALUE отдельно путем вычисления отрицательного числа, а затем добавления знакового бита, потому что отрицательное числоInteger.MIN_VALUEИзменение на положительное число приведет к переполнению значения, поэтому все операции выполняются с отрицательными числами. Здесь используется переменная mulmin, чтобы избежать проблемы цифрового переполнения.Простое использование положительных и отрицательных знаков не может точно определить, происходит ли переполнение (знак результата переполнения, вызванного умножением, неопределен). 

Конструктор

public Integer(int value) {
        this.value = value;
    }

public Integer(String s) throws NumberFormatException {
        this.value = parseInt(s, 10);
    }

Эти два конструктора, один для передачи типа int, другой типа String. Второй конвертируется вызовом метода parseInt.

метод getChars

static void getChars(int i, int index, char[] buf) {
    int q, r;
    int charPos = index;
    char sign = 0;

    if (i < 0) {
        sign = '-';
        i = -i;
    }

    // Generate two digits per iteration
    while (i >= 65536) {
        q = i / 100;
    // really: r = i - (q * 100);
        r = i - ((q << 6) + (q << 5) + (q << 2));
        i = q;
        buf [--charPos] = DigitOnes[r];
        buf [--charPos] = DigitTens[r];
    }

    // Fall thru to fast mode for smaller numbers
    // assert(i <= 65536, i);
    for (;;) {
        q = (i * 52429) >>> (16+3);
        r = i - ((q << 3) + (q << 1));  // r = i-(q*10) ...
        buf [--charPos] = digits [r];
        i = q;
        if (i == 0) break;
    }
    if (sign != 0) {
        buf [--charPos] = sign;
    }
}

Главное, что делает этот метод, — помещает значение int в массив char.

При обработке используются некоторые приемы: два старших байта int и два младших байта обрабатываются отдельно.

Часть while (i >= 65536) предназначена для обработки двух старших байтов, а часть больше 65536 использует деление, генерируя два десятичных символа за раз, фактически обрабатывая 2 цифры каждый раз ((q

Часть, меньшая или равная 65536, использует умножение и смещение для деления на 10. Например, (i * 52429) >>> (16+3) на самом деле приблизительно равно i/10, ((q

метод toString

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);
    }
public String toString() {
        return toString(value);
    }
public static String toString(int i, int radix) {
        if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
            radix = 10;

        if (radix == 10) {
            return toString(i);
        }

        char buf[] = new char[33];
        boolean negative = (i < 0);
        int charPos = 32;

        if (!negative) {
            i = -i;
        }

        while (i <= -radix) {
            buf[charPos--] = digits[-(i % radix)];
            i = i / radix;
        }
        buf[charPos] = digits[-i];

        if (negative) {
            buf[--charPos] = '-';
        }

        return new String(buf, charPos, (33 - charPos));
    }

Здесь есть три метода toString.

Первый метод toString очень прост, то есть сначала используйте stringSize для получения количества цифр, затем используйте getChars для получения массива символов, соответствующего числу, и, наконец, возвращайте тип String.

Второй проще и заключается в вызове первого метода toString.

Третий метод toString — с базовой информацией, он будет преобразован в соответствующую базовую строку. Все, что не находится в диапазоне от 2 до 36, будет рассматриваться как десятичное.

метод valueOf

public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }
public static Integer valueOf(String s) throws NumberFormatException {
        return Integer.valueOf(parseInt(s, 10));
    }
public static Integer valueOf(String s, int radix) throws NumberFormatException {
        return Integer.valueOf(parseInt(s,radix));
    }

В первом valueOf, поскольку IntegerCache кэширует объекты Integer со значениями [low, high], соответствующие объекты Integer могут быть напрямую получены из массива IntegerCache в диапазоне [-128, 127], а объекты вне диапазона должны быть воссоздан.

Второй и третий вызывают первый метод valueOf, но метод вызова parseInt() отличается.

метод декодирования

public static Integer decode(String nm) throws NumberFormatException {
    int radix = 10;
    int index = 0;
    boolean negative = false;
    Integer result;

    if (nm.length() == 0)
        throw new NumberFormatException("Zero length string");
    char firstChar = nm.charAt(0);
    // Handle sign, if present
    if (firstChar == '-') {
        negative = true;
        index++;
    } else if (firstChar == '+')
        index++;

    // Handle radix specifier, if present
    if (nm.startsWith("0x", index) || nm.startsWith("0X", index)) {
        index += 2;
        radix = 16;
    }
    else if (nm.startsWith("#", index)) {
        index ++;
        radix = 16;
    }
    else if (nm.startsWith("0", index) && nm.length() > 1 + index) {
        index ++;
        radix = 8;
    }

    if (nm.startsWith("-", index) || nm.startsWith("+", index))
        throw new NumberFormatException("Sign character in wrong position");

    try {
        result = Integer.valueOf(nm.substring(index), radix);
        result = negative ? Integer.valueOf(-result.intValue()) : result;
    } catch (NumberFormatException e) {
        // If number is Integer.MIN_VALUE, we'll end up here. The next line
        // handles this case, and causes any genuine format error to be
        // rethrown.
        String constant = negative ? ("-" + nm.substring(index))
                                   : nm.substring(index);
        result = Integer.valueOf(constant, radix);
    }
    return result;
}

Основная функция метода decode — декодировать строку.

По умолчанию он будет обрабатываться как десятичный, числа, начинающиеся с 0, будут обрабатываться как восьмеричные, а числа, начинающиеся с 0x и #, будут обрабатываться как шестнадцатеричные.

методы xxxvalue (byteValue, shortValue, intValue, longValue, floatValue, doubleValue)

public byte byteValue() {
        return (byte)value;
    }
public short shortValue() {
        return (short)value;
    }
public int intValue() {
        return value;
    }
public long longValue() {
        return (long)value;
    }
public float floatValue() {
        return (float)value;
    }
public double doubleValue() {
        return (double)value;
    }

Фактически он преобразуется в соответствующий тип

метод hashCode

public int hashCode() {
    return value;
}

состоит в том, чтобы вернуть значение типа int

метод равенства

public boolean equals(Object obj) {
    if (obj instanceof Integer) {
        return value == ((Integer)obj).intValue();
    }
    return false;
}

Прежде чем сравнивать одинаковые ли они, тип int будет преобразован в тип Integer через valueof.Суть equals в том, что его стоит сравнивать.

метод сравнения

public static int compare(int x, int y) {      

    return (x < y) ? -1 : ((x == y) ? 0 : 1);
}

Возвращает -1, если x меньше y, 0, если равно, и 1 в противном случае.

метод биткаунта

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

Этот метод в основном используется для вычисления количества единиц в двоичном числе.

Это операции сдвига, сложения и вычитания.

0x55555555равный01010101010101010101010101010101,0x33333333равный110011001100110011001100110011,0x0f0f0f0fравный1111000011110000111100001111.

сначала каждыйдваНабор статистических данных, чтобы увидеть, сколько 1 есть, например,10011111Тогда в каждых двух цифрах есть 1, 1, 2 и 2 единицы, обозначаемые как01011010, а затем считать каждыйчетыреГруппа видит, сколько есть единиц, и01011010Тогда в каждых четырех цифрах есть 2 или 4 единицы, обозначаемые как00100100, то каждый8группа для00000110,тогда16-бит, 32-бит, наконец, с0x3fВыполните операцию И, и полученное число равно количеству единиц.

метод наивысшего OneBit

    public static int highestOneBit(int i) {
        // HD, Figure 3-1
        i |= (i >>  1);
        i |= (i >>  2);
        i |= (i >>  4);
        i |= (i >>  8);
        i |= (i >> 16);
        return i - (i >>> 1);
    }
// 随便一个例子,不用管最高位之后有多少个1,都会被覆盖
// 00010000 00000000 00000000 00000000      raw
// 00011000 00000000 00000000 00000000      i | (i >> 1)
// 00011110 00000000 00000000 00000000      i | (i >> 2)
// 00011111 11100000 00000000 00000000      i | (i >> 4)
// 00011111 11111111 11100000 00000000      i | (i >> 8)
// 00011111 11111111 11111111 11111111      i | (i >> 16)
// 00010000 0000000 00000000 00000000       i - (i >>>1)

Этот метод возвращает самый высокий 1, а остальные 0. Сдвиг i вправо на один бит, а затем операция ИЛИ, затем правая часть старшего бита 1 также равна 1, а затем сдвиг вправо на два бита и операция ИЛИ, тогда все правые 1+2=3 бита равны 1, затем 1+2+4 = 7 бит равны 1, пока 1+2+4+8+16=31 не будут равны 1, и, наконец, используйтеi - (i >>> 1)Естественно получить окончательный результат.

самый низкий метод OneBit

    public static int lowestOneBit(int i) {
        // HD, Section 2-1
        return i & -i;
    }
// 例子
// 00001000 10000100 10001001 00101000    i
// 11110111 01111011 01110110 11011000    -i
// 00000000 00000000 00000000 00001000  i & -i

В соответствии с методом highOneBit метод lowOneBit получает наименьшее значение 1, а все остальные — 0 значений. Эта операция относительно проста, сначала возьмите отрицательное число, этот процесс должен инвертировать i положительного числа, а затем добавить 1. Полученный результат объединяется с i, который оказывается наименьшим значением 1, а другой равен 0.

метод numberOfLeadingZeros

    public static int numberOfLeadingZeros(int i) {
        // HD, Figure 5-6
        if (i == 0)
            return 32;
        int n = 1;
        if (i >>> 16 == 0) { n += 16; i <<= 16; }
        if (i >>> 24 == 0) { n +=  8; i <<=  8; }
        if (i >>> 28 == 0) { n +=  4; i <<=  4; }
        if (i >>> 30 == 0) { n +=  2; i <<=  2; }
        n -= i >>> 31;
        return n;
    }
// 方法很巧妙, 类似于二分法。不断将数字左移缩小范围。例子用最差情况:
// i: 00000000 00000000 00000000 00000001         n = 1
// i: 00000000 00000001 00000000 00000000         n = 17
// i: 00000001 00000000 00000000 00000000         n = 25
// i: 00010000 00000000 00000000 00000000         n = 29
// i: 01000000 00000000 00000000 00000000         n = 31
// i >>>31 == 0
// return 31

Этот метод возвращает количество нулей в двоичном коде i с самого начала. Если i равно 0, имеется 32 0. Обработка здесь фактически воплощает идею бинарного поиска.Сначала проверяют, равны ли старшие 16 бит 0. Если да, то есть как минимум 16 0. В противном случае сдвигаем 16 бит влево и продолжаем судить, а затем перемещаем 24 бита вправо, чтобы увидеть, равен ли он 0. Если это так, будет не менее 16+8=24 нулей, пока не будет получен окончательный результат.

Метод numberOfTrailingZeros

    public static int numberOfTrailingZeros(int i) {
        // HD, Figure 5-14
        int y;
        if (i == 0) return 32;
        int n = 31;
        y = i <<16; if (y != 0) { n = n -16; i = y; }
        y = i << 8; if (y != 0) { n = n - 8; i = y; }
        y = i << 4; if (y != 0) { n = n - 4; i = y; }
        y = i << 2; if (y != 0) { n = n - 2; i = y; }
        return n - ((i << 1) >>> 31);
    }
// 与求开头多少个0类似,也是用了二分法,先锁定1/2, 再锁定1/4,1/8,1/16,1/32。
// i: 11111111 11111111 11111111 11111111    n: 31
// i: 11111111 11111111 00000000 00000000    n: 15
// i: 11111111 00000000 00000000 00000000    n: 7
// i: 11110000 00000000 00000000 00000000    n: 3
// i: 11000000 00000000 00000000 00000000    n: 1
// i: 10000000 00000000 00000000 00000000    n: 0

Как и предыдущий метод numberOfLeadingZeros, этот метод возвращает количество нулей с конца двоичного числа i. Его идея аналогична предыдущей, и он также основан на идее бинарного поиска, и подробные шаги повторяться не будут.


обратный метод

public static int reverse(int i) {
        i = (i & 0x55555555) << 1 | (i >>> 1) & 0x55555555;
        i = (i & 0x33333333) << 2 | (i >>> 2) & 0x33333333;
        i = (i & 0x0f0f0f0f) << 4 | (i >>> 4) & 0x0f0f0f0f;
        i = (i << 24) | ((i & 0xff00) << 8) |
            ((i >>> 8) & 0xff00) | (i >>> 24);
        return i;
    }

Этот метод заключается в инвертировании i, а инверсия заключается в замене 1-го бита 32-м битом, второго бита 31-м битом и так далее. Его основная идея состоит в том, чтобы сначала поменять местами два соседних бита, например, 10100111 на 01011011, затем поменять местами соседние четыре бита на 10101101, затем поменять местами соседние восемь битов и, наконец, поменять местами средние 16 бит из 32 бит, а затем старшие 8 бит меняются местами с младшими 8 битами.

методы toHexString и toOctalString

public static String toHexString(int i) {
        return toUnsignedString0(i, 4);
    }
public static String toOctalString(int i) {
        return toUnsignedString0(i, 3);
    }
private static String toUnsignedString0(int val, int shift) {
        int mag = Integer.SIZE - Integer.numberOfLeadingZeros(val);
        int chars = Math.max(((mag + (shift - 1)) / shift), 1);
        char[] buf = new char[chars];

        formatUnsignedInt(val, shift, buf, 0, chars);

        return new String(buf, true);
    }
static int formatUnsignedInt(int val, int shift, char[] buf, int offset, int len) {
        int charPos = len;
        int radix = 1 << shift;
        int mask = radix - 1;
        do {
            buf[offset + --charPos] = Integer.digits[val & mask];
            val >>>= shift;
        } while (val != 0 && charPos > 0);

        return charPos;
    }

Эти два метода похожи и обсуждаются вместе. Посмотрите на имя, чтобы знать, что оно преобразуется в строку восьмеричной и шестнадцатеричной системы счисления. Видно, что метод toUnsignedString0 вызывается косвенно.Этот метод сначала рассчитает количество символов, необходимых для преобразования в соответствующую базу, а затем заполнит массив символов через метод formatUnsignedInt.Что делает этот метод, так это использует метод преобразования между базами (упомянутыми ранее), чтобы получить соответствующий символ.

=====================================================

Источник ссылки: https://juejin.cn/post/6844903491261956109