Trang chủHướng dẫnInterface trong Java 8: Default method và static method có gì mới?
Java

Interface trong Java 8: Default method và static method có gì mới?

CyStack blog 6 phút để đọc
CyStack blog11/07/2025
Locker Avatar

Bao Tran

Web Developer

Locker logo social
Reading Time: 6 minutes

Các thay đổi chính cho interface của Java 8 liên quan đến việc triển khai static method (phương thức tĩnh) và default method (phương thức mặc định). Trước phiên bản này, ta chỉ có thể khai báo chúng mà mà không được phép viết code triển khai trực tiếp trong interface. Nhưng kể từ Java 8, ta đã có thể triển khai code cho cả default method và static method ngay bên trong interface.

Default method và Static method

Thiết kế interface vốn là một công việc phức tạp. Nếu muốn thêm phương thức mới, ta sẽ phải sửa đổi tất cả các class đang triển khai interface đó. Khi một interface đã được sử dụng rộng rãi trong dự án, số lượng class triển khai nó có thể nhiều đến mức việc mở rộng interface gần như là bất khả thi.

Đây là lý do tại sao khi thiết kế ứng dụng, hầu hết các framework đều cung cấp một class triển khai cơ sở (base implementation class) để chúng ta mở rộng và ghi đè lại các phương thức phù hợp với ứng dụng của mình.

Trong bài này, chúng ta sẽ tìm hiểu về default method và static method trong interface, cũng như lý do chúng được đưa vào trong Java 8.

Default method trong Java Interface

Để tạo một default method trong interface của Java, ta cần sử dụng từ khóa default trong phần khai báo phương thức. Ví dụ:

package com.journaldev.java8.defaultmethod;

public interface Interface1 {

	void method1(String str);
	
	default void log(String str){
		System.out.println("I1 logging::"+str);
	}
}

Lưu ý rằng log(String str) là một default method. Giờ đây, khi một class triển khai Interface1, nó không bắt buộc phải cung cấp code triển khai cho các default method của interface này. Tính năng này giúp ta mở rộng interface bằng cách thêm các phương thức mới mà chỉ cần cung cấp một triển khai mặc định.

Giả sử ta có một interface khác với các phương thức như sau:

package com.journaldev.java8.defaultmethod;

public interface Interface2 {

	void method2();
	
	default void log(String str){
		System.out.println("I2 logging::"+str);
	}

}

Ta đã biết Java không cho phép một class kế thừa từ nhiều class khác. Điều này sẽ dẫn đến vấn đề kim cương (Diamond Problem) khi trình biên dịch không thể quyết định sẽ sử dụng phương thức của superclass (lớp cha) nào.

Với default method, vấn đề tương tự cũng có thể xảy ra với interface. Nếu một class triển khai cả Interface1Interface2 nhưng không triển khai default method chung của chúng, compiler sẽ không biết phải chọn phương thức nào.

Việc mở rộng nhiều interface là một phần không thể thiếu của Java. Bạn có thể thấy nó trong các class cơ bản của Java cũng như trong hầu hết các ứng dụng và framework dùng trong doanh nghiệp. Do đó, để đảm bảo vấn đề này không xảy ra với interface, Java bắt buộc chúng ta phải cung cấp bản triển khai cho các default method chung.

Vì vậy, nếu một class triển khai cả hai interface trên, nó sẽ phải cung cấp bản triển khai cho phương thức log(), nếu không compiler sẽ báo lỗi ngay tại thời điểm biên dịch.

Ta có một class đơn giản triển khai cả Interface1Interface2 sẽ như sau:

package com.journaldev.java8.defaultmethod;

public class MyClass implements Interface1, Interface2 {

	@Override
	public void method2() {
	}

	@Override
	public void method1(String str) {
	}

	@Override
	public void log(String str){
		System.out.println("MyClass logging::"+str);
		Interface1.print("abc");
	}
}

Những điểm quan trọng về default method trong interface của Java:

  1. Default method trong interface của Java giúp chúng ta mở rộng interface mà không sợ làm hỏng các class đã triển khai nó.
  2. Default method trong interface của Java đã giúp thu hẹp khoảng cách giữa interface và abstract class (lớp trừu tượng).
  3. Default method trong interface của Java giúp chúng ta tránh việc phải tạo các utility class (lớp tiện ích phụ trợ). Ví dụ, tất cả các phương thức của class Collections có thể được cung cấp ngay trong bản thân các interface.
  4. Default method trong interface của Java giúp chúng ta loại bỏ các class triển khai cơ sở, thay vào đó ta có thể cung cấp bản triển khai mặc định và các class con có thể lựa chọn ghi đè phương thức nào.
  5. Một trong những lý do chính của việc đưa default method vào interface là để nâng cao Collections API trong Java 8 nhằm hỗ trợ biểu thức lambda.
  6. Nếu một class trong chuỗi kế thừa đã có một phương thức với cùng signature (thông tin nhận diện phương thức như tên, tham số, kiểu trả về), thì default method sẽ không còn tác dụng. Một default method không thể ghi đè một phương thức từ class Object. Lý do rất đơn giản: Object là class cơ sở của tất cả các class trong Java. Vì vậy, ngay cả khi ta định nghĩa các phương thức của class Object dưới dạng default method trong interface, chúng cũng sẽ vô dụng vì phương thức của class Object sẽ luôn được ưu tiên sử dụng. Để tránh nhầm lẫn, Java không cho phép chúng ta có các default method ghi đè lại các phương thức của class Object.
  7. Default method trong interface của Java còn được gọi là defender method (phương thức bảo vệ) hoặc virtual extension method (phương thức mở rộng ảo).

Static method trong Java Interface

Static method trong interface của Java tương tự như default method, ngoại trừ việc chúng ta không thể ghi đè chúng trong các class triển khai. Tính năng này giúp ta tránh được các kết quả không mong muốn trong trường hợp các bản triển khai ở các class con có chất lượng không tốt.

Hãy xem qua một ví dụ đơn giản:

package com.journaldev.java8.staticmethod;

public interface MyData {

	default void print(String str) {
		if (!isNull(str))
			System.out.println("MyData Print::" + str);
	}

	static boolean isNull(String str) {
		System.out.println("Interface Null Check");

		return str == null ? true : "".equals(str) ? true : false;
	}
}

Bây giờ, hãy xem một class triển khai có phương thức isNull() được viết không đúng cách:

package com.journaldev.java8.staticmethod;

public class MyDataImpl implements MyData {

	public boolean isNull(String str) {
		System.out.println("Impl Null Check");

		return str == null ? true : false;
	}
	
	public static void main(String args[]){
		MyDataImpl obj = new MyDataImpl();
		obj.print("");
		obj.isNull("abc");
	}
}

Lưu ý rằng isNull() trong class này là một phương thức của class thông thường, nó không ghi đè phương thức của interface. Ví dụ, nếu ta thêm annotation @Override vào phương thức isNull() này, trình biên dịch sẽ báo lỗi. Khi chạy ứng dụng, ta sẽ nhận được output sau.

Interface Null Check
Impl Null Check

Nếu ta đổi phương thức trong interface từ static thành default, ta sẽ nhận được output như sau.

Impl Null Check
MyData Print::
Impl Null Check

Static method của interface chỉ thuộc về bản thân interface đó. Nếu ta xóa phương thức isNull() khỏi class MyDataImpl, ta sẽ không thể gọi nó thông qua đối tượng MyDataImpl. Tuy nhiên, giống như các static method khác, ta có thể gọi static method của interface bằng cách dùng tên của interface.

Ví dụ, câu lệnh sau là hợp lệ:

boolean result = MyData.isNull("abc");

Những điểm quan trọng về static method trong interface của Java:

  1. Static method trong interface là một phần của interface, ta không thể sử dụng nó thông qua các đối tượng của class triển khai.
  2. Static method trong interface rất hữu ích để cung cấp các phương thức tiện ích, ví dụ như kiểm tra null, sắp xếp collection, v.v.
  3. Static method trong interface giúp tăng cường tính an toàn bằng cách không cho phép các class triển khai ghi đè chúng.
  4. Ta không thể định nghĩa một static method trong interface có signature trùng với các phương thức của class Object. Làm vậy sẽ gây ra lỗi biên dịch: “This static method cannot hide the instance method from Object”. Điều này không được phép trong Java vì Object là class cha của mọi class, và ta không thể có một static method ở cấp độ class và một thực thể method khác có cùng signature.
  5. Ta có thể dùng static method trong interface để loại bỏ các utility class (ví dụ như Collections) và chuyển tất cả các static method của chúng vào các interface tương ứng, giúp việc tìm kiếm và sử dụng trở nên dễ dàng hơn.

Interface hàm trong Java

Trước khi kết thúc bài viết, chúng tôi muốn giới thiệu sơ lược qua về interface hàm (functional interface). Một interface chỉ có duy nhất một abstract method (phương thức trừu tượng, chỉ có khai báo, chưa có thân hàm) được gọi là interface hàm.

Có một annotation mới là @FunctionalInterface có thể được dùng để đánh dấu một interface là interface hàm. Annotation này là một công cụ giúp tránh việc ta vô tình thêm các abstract method khác vào một interface hàm. Tuy ta không phải bắt buộc sử dụng nó, đây là một thói quen tốt để tránh lỗi cơ bản này.

Interface hàm là một tính năng được chờ đợi từ lâu của Java 8 vì nó cho phép chúng ta sử dụng biểu thức lambda để khởi tạo chúng. Một package mới là java.util.function với nhiều interface hàm đã được thêm vào để cung cấp các kiểu đích (target type) cho biểu thức lambda và tham chiếu phương thức (method reference).

Chúng ta sẽ tìm hiểu sâu hơn về interface hàm và biểu thức lambda trong các bài viết sau. Hãy nhớ đón đọc để biết cách áp dụng chúng trong việc đơn giản hóa xử lý logic và làm cho code ngắn gọn và dễ tái sử dụng hơn.

0 Bình luận

Đăng nhập để thảo luận

Chuyên mục Hướng dẫn

Tổng hợp các bài viết hướng dẫn, nghiên cứu và phân tích chi tiết về kỹ thuật, các xu hướng công nghệ mới nhất dành cho lập trình viên.

Đăng ký nhận bản tin của chúng tôi

Hãy trở thành người nhận được các nội dung hữu ích của CyStack sớm nhất

Xem chính sách của chúng tôi Chính sách bảo mật.

Đăng ký nhận Newsletter

Nhận các nội dung hữu ích mới nhất