Java

Interface in Java

Xin chào, trong bài viết này chúng ta sẽ tìm hiểu về Interface trong Java.


HIỂU VỀ INTERFACE

Có thể coi Interface như một class không có các Instance Variable và các method của nó mới chỉ được khai báo chứ chưa được định nghĩa. Vì các method trong Interface chưa được định nghĩa đầy đủ nên chúng ta không thể tạo một instance từ Interface.

Các interface sẽ được thực thi bởi các class, tức là các class sẽ cung cấp phần định nghĩa cho các method được khai báo trong Interface. Mỗi class sẽ thực thi Interface theo cách riêng của nó, nhưng tất cả các method được khai báo trong Interface sẽ phải được định nghĩa.

Với Interface, Java cung cấp khả năng “one interface, multiple methods” cho các class, có nghĩa là nhiều class khác nhau có thể cùng thực thi một interface với phần định nghĩa cho từng method được tùy biến ở từng class. Nhờ các tính năng này mà chương trình sẽ trong sáng hơn, dễ sử dụng cũng như bảo trì hơn.


ĐỊNH NGHĨA MỘT INTERFACE

Để định nghĩa một Interface chúng ta sử dụng từ khóa interface như sau:

public interface Demo {
    int year = 2018;
    void init();
}

Từ khóa public để chỉ ra rằng interface Demo có thể được sử dụng ở bất cứ đâu. Nếu không sử dụng public (mặc định) thì interface Demo chỉ tồn tại ở bên trong package mà nó được khai báo.

Bất cứ biến (variable) nào được khai báo bên trong interface đều ngầm mang thuộc tính finalstatic, có nghĩa là nó không thể bị thay đổi bởi các class thực thi interface.

Tất cả method và biến được khai báo trong interface đều mặc định có thuộc tính public.


IMPLEMENTING INTERFACE

Để một class có thể thực thi các interface, chúng ta sử dụng từ khóa implements:

class classname [extends superclass] [implements interface_1 [, interface_2...]] {
    // class-body
}

Một class có thể thực thi nhiều interface. Các method được thực thi bởi class phải được khai báo public và có tên, kiểu dữ liệu trả về, danh sách tham số với giống với method được khai báo trong interface.

Example 1: Implement an interface

public class test {

    public static void main(String[] args) {
        Example e = new Example();
        e.hello();
        e.goodbye();
    }
}

interface Demo {
    int year = 2018;
    void hello();
}

class Example implements Demo {
    public void hello() {
        System.out.println("Hello "+Demo.year);
    }
    public void goodbye() {
        System.out.println("Goodbye");
    }
}

Output:
Hello 2018
Goodbye

Mặc dù không thể tạo instance nhưng các interface có thể được dùng để tạo biến tham khảo đến các đối tượng của một class đã thực thi interface đó.

Example 2:

public class test {

    public static void main(String[] args) {
        Demo d = new Example();
        d.hello();
        // d.goodbye(); ERROR!
    }
}

interface Demo {
    int year = 2018;
    void hello();
}

class Example implements Demo {
    public void hello() {
        System.out.println("Hello "+Demo.year);
    }
    public void goodbye() {
        System.out.println("Goodbye");
    }
}

Output:
Hello 2018

Giải thích:
– Dòng 4,5: chúng ta đã sử dụng biến d có kiểu Demo để tham khảo đến instance của class Example.
– Biến d có kiểu Demo nên nó chỉ có thể truy cập đến method hello(), vì method này đã được khai báo trong interface Demo và nó không thể truy cập đến các class-members khác của class Example.

Một class thực thi một interface nhưng không cung cấp đầy đủ định nghĩa cho tất cả các method được khai báo trong interface đó phải được khai báo là abstract, điều này là tương tự với abstract class.


BIẾN TRONG INTERFACE

Vì các biến (variable) trong interface đều mang thuộc tính final và static nên chúng ta có thể sử dụng interface để chia sẻ các dữ liệu hằng số giữa các class (tương tự với file header trong lập trình C/C++). Nếu các interface này chỉ chứa biến (không chứa method) thì nó không cần được thực thi bởi các class.

Example 3:

interface Constants {
    int MONDAY = 0;
    int TUESDAY = 1;
    int WEDNESDAY = 2;
    int THURSDAY = 3;
    int FRIDAY = 4;
    int SATURDAY = 5;
    int SUNDAY = 6;
}

KẾ THỪA INTERFACE

Interface B có thể kế thừa các thuộc tính từ một interface A khác với cú pháp tương tự như đối với class. Khi một class thực thi interface B, nó phải cung cấp định nghĩa cho tất cả các method mà B khai báo và thừa kế.

Example 4:

public class test {

    public static void main(String[] args) {
        Example e = new Example();
        e.methodA();
        e.methodB();
    }
}

interface A {
    void methodA();
}

interface B extends A {
    void methodB();
}

class Example implements B {
    public void methodA() {
        System.out.println("This is methodA.");
    }

    public void methodB() {
        System.out.println("This is methodB.");
    }
}

Output:
This is methodA.
This is methodB.


DEFAULT INTERFACE METHODS

Ở đầu bài viết chúng ta có nói đến rằng các interface chỉ cung cấp khai báo cho các method, còn việc định nghĩa cho các method này là của các class. Các class, hoặc là bắt buộc phải cung cấp đầy đủ định nghĩa cho tất cả các method có trong interface mà nó implement, hoặc là sẽ phải khai báo là abstract. Tuy nhiên, khi chương trình được mở rộng, cập nhật các tính năng mới, chẳng hạn như một vài method được thêm vào interface, chúng ta bắt buộc phải cập nhật cho tất cả các class đã implement interface đó, điều này khá mất thời gian và không hề đơn giản.

Nhận thấy nhược điểm trên, Java 8 đã cung cấp một khả năng mới cho interface, đó là default method. Default method cho phép chúng ta định nghĩa một method ngay bên trong interface. Như vậy, với default method, chúng ta có thể thoải mái cập nhật các interface và các class cần thiết mà không lo ngại rằng các class còn lại sẽ bị ảnh hưởng.

Cần lưu ý rằng, dù được cung cấp thêm default method nhưng interface bây giờ vẫn chỉ là interface như trước đây. Có nghĩa là nó không thể tự tạo instance mà chỉ được thực thi thông qua class; nó không thể chứa thông tin trạng thái (các biến) mà chỉ có thể chứa các hằng số; nó chỉ cung cấp khai báo (lớp trừu tượng) chứ không cung cấp định nghĩa cho các method.

Để khai báo default method chúng ta sử dụng từ khóa default.

Example 5:

public class test {

    public static void main(String[] args) {
        Example e = new Example();
        e.method();
        e.defaultMethod();
    }
}

interface A {
    void method();
    default void defaultMethod() {
        System.out.println("This is defaultMethod.");
    }
}

class Example implements A {
    public void method() {
        System.out.println("This is method.");
    }
}

Output:
This is method.
This is defaultMethod.

Sự xuất hiện của default method cũng phát sinh ra một số vấn đề khi một class thực thi nhiều interface. Ví dụ: ta có hai interface A và B khai báo method demo() với hai default method khác nhau. Nếu một class MyClass thực thi hai interface A và B thì method demo() nào sẽ được sử dụng? Để giải quyết vấn đề này, Java đưa ra một số quy tắc sau:

  1. Trong tất cả các trường hợp, method demo() được định nghĩa bởi class được ưu tiên hơn default method;
  2. Nếu class MyClass không cung cấp định nghĩa cho method demo() của hai interface A, B thì sẽ xuất hiện lỗi;
  3. Trong trường hợp interface B thừa kế từ interface A và thực hiện overriding default method demo() thì method demo() của interface B sẽ được ưu tiên. Interface B có thể gọi method demo() của interface A bằng từ khóa super: A.super.demo() .

Example 6:

public class test {

    public static void main(String[] args) {
        Example e = new Example();
        e.intro();
        e.demo();
    }
}

interface A {
    default void demo() {
        System.out.println("This is method A.");
    }
    void intro();
}

interface B extends A {
    default void demo() {
        A.super.demo();
        System.out.println("This is method B.");
    }
}

class Example implements B {
    public void intro() {
       System.out.println("This is intro.");
    }
}

Output:
This is intro.
This is method A.
This is method B.


STATIC METHOD IN INTERFACE

Kể từ Java 8, interface có thể định nghĩa các static method bên trong nó. Cách sử dụng static interface method không thay đổi so với static class method.

Tuy nhiên cần lưu ý rằng, static interface method không thể được thừa kế bằng cách implements hay extends interface.

Example 7:

public class test {

    public static void main(String[] args) {
        Example e = new Example();
        A.intro();
        e.demo();
    }
}

interface A {
    default void demo() {
        System.out.println("This is method A.");
    }
    static void intro() {
        System.out.println("This is intro.");
    }
}

class Example implements A {
    // để trống
}

Output:
This is intro.
This is method A.


SUMMARY

Qua bài viết này chúng ta đã tìm hiểu về cách sử dụng interface trong Java và các vấn đề liên quan. Cảm ơn các bạn đã theo dõi bài viết.

Thân ái và quyết thắng.

Reference:
[1] Java The Complete Reference – Ninth Edition.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s