Java SE 16 record 型別說明與使用

2022-09-23 18:00:18

Java SE 16 record 型別說明與使用

作者:Grey

原文地址:

部落格園:Java SE 16 record 型別說明與使用

CSDN:Java SE 16 record 型別說明與使用

說明

record 是 Java SE 16 的新特性

record 的使用場景

假設我們想建立一個不可變的類 Point,它有 x 和 y 的座標。我們想範例化Point物件,讀取它們的欄位,並將它們儲存在 List 中或在 Map 中作為鍵值使用。

我們可以這樣實現 Point 類

public class Point {

    private final int x;
    private final int y;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Point point = (Point) o;

        if (x != point.x) return false;
        return y == point.y;
    }

    @Override
    public int hashCode() {
        int result = x;
        result = 31 * result + y;
        return result;
    }

    @Override
    public String toString() {
        return "Point{" + "x=" + x + ", y=" + y + '}';
    }

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }


    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }
}

如上程式碼中重複寫了很多模板程式碼,使用 Lombok,程式碼可以簡化成如下方式

@AllArgsConstructor
@Getter
@EqualsAndHashCode
@ToString
public class Point {
  private final int x;
  private final int y;
}

現在有了 record 上述所有程式碼可以簡化為

public record Point(int x, int y) {}

使用javac Point.java && javap Point,我們可以檢視到 Point 反編譯後的結果

public final class Point extends java.lang.Record {
  public Point(int, int);
  public final java.lang.String toString();
  public final int hashCode();
  public final boolean equals(java.lang.Object);
  public int x();
  public int y();
}

和我們最初始的 Point 類定義是一樣的,所以 record 可以大量簡化程式碼的編寫。

我們可以像正常使用類一樣使用 record

範例程式碼

public class App {
    public static void main(String[] args) {
        Point p = new Point(3, 4);
        int x = p.x();
        int y = p.y();
        System.out.println(x + " " + y);


        Point p2 = new Point(3, 4);
        Point p3 = new Point(7, 5);

        System.out.println(p2.equals(p)); // 輸出 true
        System.out.println(p2.equals(p3)); // 輸出 false
    }
}

record 可以通過如下方式來實現多建構函式

public record Point(int x, int y) {
    public Point() {
        this(3, 3);
    }

    public Point(int v) {
        this(v, v + 3);
    }
}

record 中可以包括 static 型別變數,範例如下

public record Point(int x, int y) {
    private static final int ZERO = 0;
    private static long count = 0;

    public Point() {

        this(ZERO, ZERO);
        synchronized (Point.class) {
            count++;
        }
    }
    public static synchronized long getCount() {
        return count;
    }
    public Point(int v) {
        this(v, v + 3);
    }
}

如果要覆蓋 record 的預設建構函式,則函數入參一定要和 record 的入參保持一致,否則會報錯

正確

public record Point(int x, int y) {
    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

錯誤

public record Point(int x, int y) {
    public Point(int m, int n) {
        this.x = m;
        this.y = n;
    }
}

record 中可以自定義非 static 方法,例如

public record Point(int x, int y) {
    public double distanceTo(Point target) {
        int dx = target.x() - this.x();
        int dy = target.y() - this.y();
        return Math.sqrt(dx *dx + dy* dy);
    }
}

呼叫方法

public class App {
    public static void main(String[] args) {
        Point from = new Point(17, 3);
        Point to = new Point(18, 12);
        double distance = from.distanceTo(to);
        System.out.println(distance);
    }
}

record 也可以實現介面,但是無法繼承類

正確


public record Point(int x, int y) implements WithXCoordinate {}

public interface WithXCoordinate {
    int x();
}

錯誤

public record Point(int x, int y) extends WithXCoordinate {}

public class WithXCoordinate {
    int x(){}
}

record 也無法被其他類繼承,例如

錯誤

public record Point(int x, int y)  {}

public class WithXCoordinate extends Point{
    int x(){}
}

原始碼

hello-record

參考檔案

Java Records