CodeGym /Các khóa học /JAVA 25 SELF /Phương thức static trong interface

Phương thức static trong interface

JAVA 25 SELF
Mức độ , Bài học
Có sẵn

1. Giới thiệu

Trước Java 8, interface chỉ là “hợp đồng”: chỉ có các phương thức trừu tượng, không có triển khai, không có logic, chỉ là cam kết. Nhưng từ Java 8, interface trở nên “tự chủ” hơn một chút: giờ chúng có thể chứa không chỉ phương thức default mà còn cả phương thức static.

Phương thức static trong interface là các phương thức thuộc về chính interface, chứ không thuộc về các cài đặt của nó (các lớp). Chúng không cần tạo đối tượng và được gọi trực tiếp qua tên interface.

Ví von:
Phương thức static trong interface giống như một tờ hướng dẫn dán trên tường văn phòng: mỗi nhân viên (lớp) đều có thể dùng nó, nhưng tờ hướng dẫn đó không thuộc về bất kỳ nhân viên nào.

Phương thức static trong interface cho phép nhóm các hàm trợ giúp liên quan đến interface đó, mà không làm “bẩn” không gian tên của các lớp hiện thực.

Cú pháp phương thức static trong interface

Phương thức static được khai báo bên trong interface với từ khóa static. Chúng có thể chứa phần triển khai (mã trong dấu ngoặc nhọn) và chỉ có thể được gọi qua tên interface.

Ví dụ:

public interface MathUtils {
    static int sum(int a, int b) {
        return a + b;
    }

    static double average(int a, int b) {
        return (a + b) / 2.0;
    }
}

Gọi phương thức static của interface:

int result = MathUtils.sum(5, 7);        // 12
double avg = MathUtils.average(10, 20);  // 15.0

Lưu ý:
Không thể gọi phương thức static của interface qua lớp hiện thực hoặc qua đối tượng! Chỉ được gọi qua tên interface.

2. Phương thức static của interface khác gì so với phương thức default?

Phương thức static:

  • Thuộc về chính interface.
  • Không được kế thừa bởi các lớp hiện thực.
  • Không thể được gọi thông qua đối tượng của lớp.
  • Không thể bị ghi đè trong lớp hiện thực.
  • Chỉ có thể được gọi qua tên interface.

Phương thức default:

  • Thuộc về đối tượng (instance) của lớp hiện thực interface.
  • Có thể bị ghi đè trong lớp hiện thực.
  • Có thể được gọi thông qua đối tượng của lớp hiện thực.
  • Được kế thừa bởi các lớp hiện thực.

Tóm lại: phương thức default mở rộng khả năng của đối tượng, còn phương thức static mở rộng chính interface.

Ví dụ so sánh:

interface Printer {
    default void print(String text) {
        System.out.println("Default: " + text);
    }

    static void info() {
        System.out.println("Printer interface v1.0");
    }
}

class ConsolePrinter implements Printer {}

public class Main {
    public static void main(String[] args) {
        Printer.info(); // Gọi phương thức static qua interface

        ConsolePrinter cp = new ConsolePrinter();
        cp.print("Hello!"); // Gọi phương thức default qua đối tượng
        // cp.info(); // Lỗi! Không thể gọi phương thức static qua đối tượng
    }
}

3. Tại sao cần phương thức static trong interface?

Trước khi có phương thức static trong interface, nếu bạn cần thêm một hàm tiện ích liên quan đến interface, bạn thường phải tạo các lớp riêng có hậu tố Utils hoặc Helper:

public interface Movable {
    void move(int x, int y);
}

public class MovableUtils {
    public static void resetPosition(Movable m) {
        m.move(0, 0);
    }
}

Giờ đây có thể làm điều đó ngay trong interface:

public interface Movable {
    void move(int x, int y);

    static void resetPosition(Movable m) {
        m.move(0, 0);
    }
}

Điều này làm cho mã logic và gắn kết hơn: các phương thức liên quan đến interface giờ “sống” ngay trong nó.

Ưu điểm:

  • Nhóm các hàm tiện ích ngay cạnh “hợp đồng” của interface.
  • Không “làm bẩn” không gian tên của các lớp hiện thực.
  • Cải thiện khả năng đọc và bảo trì mã.

4. Hạn chế và đặc điểm của phương thức static trong interface

Phương thức static của interface không được kế thừa bởi các lớp hiện thực.

Không thể gọi chúng qua đối tượng của lớp hiện thực hoặc qua tên lớp. Chỉ được gọi qua tên interface!

Phương thức static trong interface luôn có phần triển khai: chúng không thể là abstract hoặc default.

Chúng luôn có phần triển khai.

Phương thức static không thể truy cập các phương thức hay biến không static của interface.

Chúng chỉ có thể truy cập các thành viên static khác của interface (ví dụ các hằng static final).

Phương thức static của interface có thể là private (Java 9+).

Có thể tạo các phương thức private static trợ giúp để dùng bên trong interface.

5. Ví dụ: phương thức static cho interface Movable

Hãy xem cách thêm phương thức static vào interface Movable. Giả sử chúng ta có interface Movable được nhiều lớp khác nhau hiện thực (ví dụ robot, động vật, phương tiện).

Bước 1. Khai báo interface với phương thức static:

public interface Movable {
    void move(int x, int y);

    static void resetPosition(Movable obj) {
        obj.move(0, 0);
    }

    static double distance(int x1, int y1, int x2, int y2) {
        int dx = x2 - x1;
        int dy = y2 - y1;
        return Math.sqrt(dx * dx + dy * dy);
    }
}

Bước 2. Hiện thực interface trong một lớp:

public class Robot implements Movable {
    private int x, y;

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

    @Override
    public void move(int x, int y) {
        System.out.println("Robot di chuyển đến điểm (" + x + "," + y + ")");
        this.x = x;
        this.y = y;
    }

    public void printPosition() {
        System.out.println("Vị trí hiện tại: (" + x + "," + y + ")");
    }
}

Bước 3. Sử dụng các phương thức static của interface:

public class Main {
    public static void main(String[] args) {
        Robot robby = new Robot(10, 15);
        robby.printPosition();

        // Đặt lại vị trí qua phương thức static của interface
        Movable.resetPosition(robby);
        robby.printPosition();

        // Tính khoảng cách giữa các điểm qua phương thức static của interface
        double dist = Movable.distance(0, 0, 10, 15);
        System.out.println("Khoảng cách: " + dist);
    }
}

Kết quả:

Vị trí hiện tại: (10,15)
Robot di chuyển đến điểm (0,0)
Vị trí hiện tại: (0,0)
Khoảng cách: 18.027756377319946

Lưu ý:
Chúng ta gọi Movable.resetPosition(robby), chứ không phải robby.resetPosition(). Phương thức static rất tiện để dùng cho các thao tác thuộc về logic của interface, chứ không phải của một đối tượng cụ thể.

6. Private static-method trong interface

Đôi khi trong interface cần các phương thức trợ giúp chỉ để dùng nội bộ (ví dụ để tránh lặp mã trong nhiều phương thức static hoặc default). Từ Java 9, interface hỗ trợ các phương thức private static.

Ví dụ:

public interface Logger {
    static void logInfo(String message) {
        log("INFO", message);
    }
    static void logError(String message) {
        log("ERROR", message);
    }
    private static void log(String level, String message) {
        System.out.println("[" + level + "] " + message);
    }
}

Bây giờ log() không thể truy cập từ bên ngoài interface, nhưng được dùng bên trong các phương thức static khác.

7. Static-method trong thư viện chuẩn của Java ở đâu?

Phương thức static trong interface được dùng rất nhiều trong thư viện chuẩn của Java, đặc biệt là trong collections và các functional interface.

Ví dụ:

  • Comparator.comparing(), Comparator.reverseOrder() — các phương thức static của interface Comparator.
  • Predicate.isEqual() — phương thức static của interface Predicate.
  • List.of(), Set.of(), Map.of() (Java 9+) — các phương thức static để tạo collections bất biến.

Ví dụ với Comparator:

import java.util.Comparator;

public class Main {
    public static void main(String[] args) {
        Comparator<String> cmp = Comparator.reverseOrder();
        int res = cmp.compare("a", "b"); // số dương, vì "a" > "b" theo thứ tự đảo ngược
        System.out.println(res);
    }
}

8. Các lỗi thường gặp khi làm việc với phương thức static của interface

Lỗi số 1: cố gắng gọi phương thức static qua đối tượng của lớp hiện thực.
Điều này sẽ không hoạt động! Phương thức static của interface chỉ được gọi qua tên interface, ví dụ Movable.resetPosition(obj), chứ không phải obj.resetPosition().

Lỗi số 2: cố gắng ghi đè phương thức static của interface trong lớp hiện thực.
Phương thức static không được kế thừa và không thể ghi đè! Nếu bạn khai báo trong lớp một phương thức static cùng tên, đó sẽ là một phương thức khác hoàn toàn, không liên quan đến interface.

Lỗi số 3: quên rằng phương thức static không thể truy cập các thành viên không static.
Phương thức static của interface chỉ có thể dùng các thành viên static (ví dụ các hằng static final), chứ không thể truy cập các phương thức hay biến không static.

Lỗi số 4: nhầm lẫn với phương thức default.
Phương thức default được gọi qua đối tượng, còn static chỉ qua tên interface. Đừng nhầm lẫn!

Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION