Сохраняют ли записи Java 14 на самом деле память в аналогичном объявлении класса или они больше похожи на syntacti c sugar? - PullRequest
8 голосов
/ 14 апреля 2020

Я надеюсь, что Java 14 записей на самом деле используют меньше памяти, чем аналогичный класс данных.

Являются ли они или использование памяти одинаковым?

Ответы [ 3 ]

7 голосов
/ 14 апреля 2020

Чтобы добавить к основному c анализу, выполненному с помощью @ lugiorgi , и аналогичное заметное отличие, которое я мог бы придумать при анализе байт-кода, заключается в реализации toString, equals и hashcode.

С одной стороны, ранее использовавшийся класс с переопределенными API-интерфейсами класса Object, выглядящий как

public class City {
    private final Integer id;
    private final String name;
    // all-args, toString, getters, equals, and hashcode
}

, создает байт-код следующим образом

 public java.lang.String toString();
    Code:
       0: aload_0
       1: getfield      #7                  // Field id:Ljava/lang/Integer;
       4: aload_0
       5: getfield      #13                 // Field name:Ljava/lang/String;
       8: invokedynamic #17,  0             // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/Integer;Ljava/lang/String;)Ljava/lang/String;
      13: areturn

  public boolean equals(java.lang.Object);
    Code:
       0: aload_0
       1: aload_1
       2: if_acmpne     7
       5: iconst_1
       6: ireturn
       7: aload_1
       8: ifnull        22
      11: aload_0
      12: invokevirtual #21                 // Method java/lang/Object.getClass:()Ljava/lang/Class;
      15: aload_1
      16: invokevirtual #21                 // Method java/lang/Object.getClass:()Ljava/lang/Class;
      19: if_acmpeq     24
      22: iconst_0
      23: ireturn
      24: aload_1
      25: checkcast     #8                  // class edu/forty/bits/records/equals/City
      28: astore_2
      29: aload_0
      30: getfield      #7                  // Field id:Ljava/lang/Integer;
      33: aload_2
      34: getfield      #7                  // Field id:Ljava/lang/Integer;
      37: invokevirtual #25                 // Method java/lang/Integer.equals:(Ljava/lang/Object;)Z
      40: ifne          45
      43: iconst_0
      44: ireturn
      45: aload_0
      46: getfield      #13                 // Field name:Ljava/lang/String;
      49: aload_2
      50: getfield      #13                 // Field name:Ljava/lang/String;
      53: invokevirtual #31                 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
      56: ireturn

  public int hashCode();
    Code:
       0: aload_0
       1: getfield      #7                  // Field id:Ljava/lang/Integer;
       4: invokevirtual #34                 // Method java/lang/Integer.hashCode:()I
       7: istore_1
       8: bipush        31
      10: iload_1
      11: imul
      12: aload_0
      13: getfield      #13                 // Field name:Ljava/lang/String;
      16: invokevirtual #38                 // Method java/lang/String.hashCode:()I
      19: iadd
      20: istore_1
      21: iload_1
      22: ireturn

On с другой стороны, представление записи для того же

record CityRecord(Integer id, String name) {}

производит байт-код меньше, чем

 public java.lang.String toString();
    Code:
       0: aload_0
       1: invokedynamic #19,  0             // InvokeDynamic #0:toString:(Ledu/forty/bits/records/equals/CityRecord;)Ljava/lang/String;
       6: areturn

  public final int hashCode();
    Code:
       0: aload_0
       1: invokedynamic #23,  0             // InvokeDynamic #0:hashCode:(Ledu/forty/bits/records/equals/CityRecord;)I
       6: ireturn

  public final boolean equals(java.lang.Object);
    Code:
       0: aload_0
       1: aload_1
       2: invokedynamic #27,  0             // InvokeDynamic #0:equals:(Ledu/forty/bits/records/equals/CityRecord;Ljava/lang/Object;)Z
       7: ireturn

Примечание : к тому, что я мог наблюдать на средствах доступа и Сгенерирован байт-код конструктора, они одинаковы как для представления, так и здесь исключены из данных.

1 голос
/ 14 апреля 2020

Я провел несколько быстрых и грязных тестов, выполнив следующие действия:

public record PersonRecord(String firstName, String lastName) {}

против

import java.util.Objects;

public final class PersonClass {
    private final String firstName;
    private final String lastName;

    public PersonClass(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public String firstName() {
        return firstName;
    }

    public String lastName() {
        return lastName;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        PersonClass that = (PersonClass) o;
        return firstName.equals(that.firstName) &&
                lastName.equals(that.lastName);
    }

    @Override
    public int hashCode() {
        return Objects.hash(firstName, lastName);
    }

    @Override
    public String toString() {
        return "PersonRecord[" +
                "firstName=" + firstName +
                ", lastName=" + lastName +
                "]";
    }
}

Файл скомпилированной записи занимает 1,475 байта, класс - 1,664 байта. Разница в размере, вероятно, происходит из-за различных реализаций equals / toString / hashCode.

Может быть, кто-то может сделать какое-то копание байт-кода ...

0 голосов
/ 30 апреля 2020

правильно, я согласен с [@lugiorgi] и [@Naman], единственная разница в сгенерированном байт-коде между записью и эквивалентным классом заключается в реализации методов: toString, equals и hashCode , Который в случае класса записей реализован с использованием инструкции invoke Dynami c (indy) для того же метода bootstrap в классе: java.lang.runtime.ObjectMethods (недавно добавлен в проект записей). Тот факт, что эти три метода, toString, equals и hashCode, вызывают один и тот же метод bootstrap, экономит больше места в файле класса, чем вызов 3 различных методов начальной загрузки. И, конечно, как уже показано в других ответах, экономит больше места, чем генерация очевидного байт-кода

...