Обработка массива виртуальной машиной Java - PullRequest
1 голос
/ 15 марта 2020

У меня глупый вопрос ко всем вам. Учитывая следующий Java Код

public void funct(String a) {
    byte[] bytearr;

    bytearr = new byte[a.getBytes().length];
    bytearr = a.getBytes();
}

Изменяет ли новый вызов что-нибудь? В частности, код обрабатывается иначе, чем

public void funct(String a) {
    byte[] bytearr;

    bytearr = a.getBytes();
}

Я спрашиваю, потому что при выполнении оба представляют одинаковые результаты, и я не могу получить, если

  • Они разные (в первом случае пространство выделяется и заполняется, а во втором это больше похоже на «назначение указателя»).
  • Они одинаковые, и я много думаю.
  • Во-вторых, это неправильно, но JVM умнее меня и исправляет это.

В целом, любое предложение наблюдать за распределением памяти / магией c поведения за JVM было бы очень полезно.

Спасибо!

Ответы [ 3 ]

2 голосов
/ 15 марта 2020

Разница лишь в том, что вы создаете лишний ненужный объект в первом фрагменте. Если вы хотите доказать это, вы можете указать вторую ссылку на массив на первую, распечатать их эквивалентность, затем вызвать string.getBytes () для первого массива и снова проверить их эквивалентность:

        String aString = new String("something");

        byte[] byteArray1 = new byte[aString.length()];
        byte[] byteArray2 = byteArray1;
        System.out.println(byteArray1==byteArray2);

        byteArray1 = aString.getBytes();
        System.out.println(byteArray1==byteArray2);

Он выводит true перед aString.getBytes (), потому что ссылки указывают на один и тот же объект. Затем aString.getBytes () возвращает новый массив byte [], поэтому byteArray1 больше не == byteArray2. Это отвечает на вопрос или вы искали что-то еще?

2 голосов
/ 15 марта 2020

Конечный результат обоих блоков кода одинаков. Первая версия выполняет некоторую ненужную дополнительную работу.

Версия 1

Позволяет go просмотреть первую версию шаг за шагом.

Шаг 1)

bytearr = new byte[a.getBytes().length];

bytearr assignment

Создается новый пустой массив и bytearr указывает на него.

Шаг 2)

bytearr = a.getBytes();

overwriting the reference of bytearr

a.getBytes() создает второй массив. bytearr обновляется, чтобы указывать на этот новый массив. Старый (синий) массив теперь является мусором, потому что ссылки на него больше не хранятся. Сборщик мусора JVM со временем освободит занятую им память.

Версия 2

bytearr = a.getBytes();

direct assignment

bytearr напрямую указывает на массив, созданный a.getBytes(). Конечный результат тот же, но эта версия более эффективна.

Подробнее о версии 1

На самом деле версия 1 создает еще один массив во время вызова a.getBytes().length. Первоначальное объяснение было пропущено для простоты.

Таким образом, в версии 1 задействованы 3 экземпляра массива:

  1. Тот, который был создан во время вызова a.getBytes().length для измерения размер (не показан на диаграммах для простоты).
  2. Пустой, созданный new byte[...] с этим размером (синий).
  3. Тот, который был создан во время второго вызова a.getBytes() (зеленый).
1 голос
/ 15 марта 2020

Они разные, давайте посмотрим на байт-код:

1. версия :

   L0
    LINENUMBER 9 L0
    ALOAD 0
    ICONST_0
    AALOAD
    INVOKEVIRTUAL java/lang/String.getBytes ()[B
    ARRAYLENGTH
    NEWARRAY T_BYTE
    ASTORE 1
   L1
    LINENUMBER 10 L1
    ALOAD 0
    ICONST_0
    AALOAD
    INVOKEVIRTUAL java/lang/String.getBytes ()[B
    ASTORE 1
   L2
    LINENUMBER 11 L2
    RETURN
   L3
    LOCALVARIABLE args [Ljava/lang/String; L0 L3 0
    LOCALVARIABLE bytearr [B L1 L3 1
    MAXSTACK = 2
    MAXLOCALS = 2

2. версия :

   L0
    LINENUMBER 9 L0
    ALOAD 0
    ICONST_0
    AALOAD
    INVOKEVIRTUAL java/lang/String.getBytes ()[B
    ASTORE 1
   L1
    LINENUMBER 10 L1
    RETURN
   L2
    LOCALVARIABLE args [Ljava/lang/String; L0 L2 0
    LOCALVARIABLE bytearr [B L1 L2 1
    MAXSTACK = 2
    MAXLOCALS = 2

Разница заключается в том, что инструкции выходят из дополнительной строки:

LINENUMBER 9 L0
ALOAD 0
ICONST_0
AALOAD
INVOKEVIRTUAL java/lang/String.getBytes ()[B
ARRAYLENGTH
NEWARRAY T_BYTE
ASTORE 1

Это приводит к дополнительным издержкам (getBytes вызывается дважды, больше инструкций) , Вызывая bytearr = a.getBytes(), jvm уже обрабатывает размер хранимого массива.

Но поскольку первая инициализация избыточна, она, вероятно, будет оптимизирована компилятором в некоторый момент (после достаточного количества запусков). Тем не менее, нет необходимости в дополнительных инструкциях и менее читаемом коде.

...