Почему дополнительный байтовый массив var2 используется в методе hashCode служебного класса StringLatin1? - PullRequest
2 голосов
/ 26 января 2020

Текущий код:

public static int hashCode(byte[] value) {
    int h = 0;
    byte[] var2 = value;
    int var3 = value.length;

    for(int var4 = 0; var4 < var3; ++var4) {
        byte v = var2[var4];
        h = 31 * h + (v & 255);
    }

    return h;
}

Возможный код:

public static int hashCode(byte[] value) {
    int h = 0;
    int var2 = value.length;

    for(int var3 = 0; var3 < var2; ++var3) {
        byte v = value[var3];
        h = 31 * h + (v & 255);
    }

    return h;
}

В пакете java.lang существует служебный класс с именем StringLatin1. Этот класс имеет hashCode метод, который будет вызываться из String метода класса hashCode, если текущее значение строки - латинское.

PS: я использую Java 11.

Ответы [ 2 ]

2 голосов
/ 26 января 2020

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

1 голос
/ 27 января 2020

Это стандартный шаблон для каждого l oop.

Когда вы пишете

for(Type variable: expression) {
    // body
}

, expression будет оцениваться ровно один раз в начале l oop, а полученная ссылка на коллекцию или массив запоминается в течение l oop. Это также подразумевает, что если expression является переменной, и эта переменная присваивается в теле l oop, это не влияет на текущую l oop.

соответствующую часть спецификация гласит:

  • В противном случае Выражение обязательно имеет тип массива, T[].

    Пусть L1 ... Lm будет (возможно, пустой) последовательностью меток, непосредственно предшествующих расширенному оператору for.

    Расширенный оператор for эквивалентен основному c for оператор формы:

    T[] #a = Expression;
    L1: L2: ... Lm:
    for (int #i = 0; #i < #a.length; #i++) {
        {VariableModifier} TargetType Identifier = #a[#i];
        Statement
    }
    

    #a и #i - это автоматически генерируемые идентификаторы, которые отличаются от любых других идентификаторов (автоматически генерируемых или иным образом), которые находятся в области действия на точка, в которой происходит расширенный оператор for.

    TargetType - это объявленный тип локальной переменной в заголовке расширенного оператора for.

Если вы сравните декомпилированную версию sion

public static int hashCode(byte[] value) {
    int h = 0;
    byte[] var2 = value;
    int var3 = value.length;

    for(int var4 = 0; var4 < var3; ++var4) {
        byte v = var2[var4];
        h = 31 * h + (v & 255);
    }

    return h;
}

с фактическим исходным кодом

public static int hashCode(byte[] value) {
    int h = 0;
    for (byte v : value) {
        h = 31 * h + (v & 0xff);
    }
    return h;
}

вы узнаете перевод. var2, var3 и var4 являются синтетическими c переменными. Стоит отметить:

  • В принципе, компилятор может проанализировать сценарий, чтобы распознать, что value является локальной переменной, которая не назначена в теле l oop, поэтому никаких дополнительных переменных не будет нужен здесь. Но экономия по сравнению со стандартной стратегией перевода не считалась целесообразной реализацией дополнительной логики c.
  • Аналогичным образом, это решение компилятора, стоит ли запоминать размер инвариантного массива в другой локальной переменной. Как показано выше, спецификация не обязывает его.

Можно сказать, что слабым местом декомпилятора является не распознавать для каждого l oop и переводить его обратно, однако есть как правило, неоднозначность при попытке отобразить скомпилированный код в конструкции исходного кода, так как существует множество вариантов для создания одного и того же кода.

...