1. Interface trong Java là gì?

Interface là một kiểu dữ liệu tham chiếu trong Java. Một Iterface trong Java là một bản thiết kế của một lớp mà trong đó chỉ có các phương thức trừu tượng. Nó chỉ có thể chứa hằng số và tên các phương thức, không có phần thân phương thức. Một lớp mô tả các hành động và thuộc tính của đối tượng còn Interface thì mô tả các hành động của lớp đó. Interface không thể được khởi tạo như các lớp mà chỉ có thể mở rộng từ các lớp hoặc kế thừa từ một Interface khác.

Tất cả các phương thức của Interface cần được định nghĩa trong class. Ngoại trừ việc một lớp triển khai Interface là lớp trừu tượng abstract. Cùng với đó thì trong Interface ta cũng không thể khai báo hàm tạo và không thể kế thừa nó từ một lớp. Ngoại trừ lớp trừu tượng thì tất cả các lớp mở rộng Interface phải định nghĩa lại tất cả các phương thức của Interface.

Mục đích của Interface là để thay thế đa kế thừa lớp của những ngôn ngữ khác (ví dụ như C++, Python…). Ngoài ra, Interface sẽ giúp đồng bộ và thống nhất trong việc phát triển hệ thống trao đổi thông tin.

2. So sánh giữa Interface và Class trong Java

Trong Java, Interface và Class có một số điểm giống nhau như:

  • Một Interface được viết trong một file với định dạng .java , với tên của Interface giống tên của file
  • Bytecode của Interface được lưu trong file có định dạng .class
  • Khai báo Interface trong một package , những file bytecode tương ứng cũng có cấu trúc thư mục có cùng tên package

Cùng với một số điểm giống nhau thì Interface và Class cũng có một số điểm khác nhau như:

  • Ta không thể khởi tạo một Interface
  • Một Interface không chứa bất cứ hàm Contructor nào
  • Tất cả các phương thức của Interface đều là abstract
  • Một Interface không thể chứa một trường nào trừ các trường vừa staticfinal
  • Một Interface không thể kế thừa từ lớp, nó được triển khai bởi một lớp
  • Một Interface có thể kế thừa từ nhiều Interface khác

3. Khai báo Interface trong Java

3.1. Khai báo Interface trong Java

Chúng ta sẽ sử dụng từ khóa Interface để tạo ra một Interface trong Java.

Cú pháp :

interface MyInterface
{
   /* Tất các các method đều mặc định thêm public abstract method.
    * Các method không có thân hàm
    */
   public void method1();
   public void method2();
}

Ví dụ:

interface Language {
    public static final double PI = 3.14;
    public void getType();
    public void getVersion();
}

Trong ví dụ trên, Language là một Interface, biến double PI là một biến hằng và khai báo với public , static , final. Các phương thức trừu tượng là getType()getVersion().

Trong NetBeans hay một số ứng dụng chạy Java khác để tạo Interface ta cần click chuột phải vào tên package chọn File -> New -> Interface và tiến hành đặt tên Interface.

Ví dụ ta tạo mới một Interface có tên là InterfaceJava. Sau khi tạo ta sẽ có một file InterfaceJava.java với nội dung như sau:

package vidu;
 
public interface InterfaceJava {
     
}

Ví dụ : viết chương trình vẽ một hình bất kỳ với màu đỏ sao cho cách sử dụng là giống nhau bất kể nó là hình gì

  • File Shape.java
public interface Shape {
     
    String color = "red";
     
    void draw();
     
}
  • File Rectangle.java
public class Rectangle implements Shape {
 
    @Override
    public void draw() {
        System.out.println("Draw " + color + " rectangle");
    }
     
}
  • File Circle.java
public class Circle implements Shape {
 
    @Override
    public void draw() {
        System.out.println("Draw " + color + " circle");
    }
     
}
  • File ShapeApp.java
public class ShapeApp {
    public static void main(String[] args) {
        Shape rect = new Rectangle();
        rect.draw();
        System.out.println("---");
        Shape circle = new Circle();
        circle.draw();      
    }
}

Kết quả

Draw red rectangle
---
Draw red circle

3.2. Từ khóa implements trong Interface

Giống như các class trừu tượng, chúng ta không thể khởi tạo các đối tượng của Interface. Tuy nhiên, chúng ta có thể thực thi các Interface trong các class khác. Trong Java, chúng ta sử dụng từ khóa implements để thực thi các Interface.

Ví dụ:

interface Polygon {
    void getArea(int length, int breadth);
}

class Rectangle implements Polygon {
    public void getArea(int length, int breadth) {
        System.out.println("Diện tích của hình chữ nhật là " + (length * breadth));
    }
}

class Main {
    public static void main(String[] args) {
        Rectangle r1 = new Rectangle();
        r1.getArea(5, 6);
    }
}

Kết quả

Diện tích của hình chữ nhật là 30

3.3. Một số lưu ý khi khai báo Interface

Từ khóa public cho biết Interface này có thể sử dụng ở bất kỳ package nào. Nếu chúng ta không khai báo phạm vi truy cập cho Interface thì mặc định Interface này chỉ có thể được sử dụng trong package chứa nó.

Các phương thức là trừu tượng trong Interface cũng không cần phải sử dụng từ khóa abstract mà chỉ cần khai báo tên phương thức, phạm vi truy cập, kiểu trả về của phương thức và kết thúc bằng dấu chấm phẩy.

Tất cả các phương thức trong Interface đều mặc định là public nên chúng ta không cần khai báo public và tương tự. Các thuộc tính trong Interface phải là một hằng số và chúng ta cũng không cần phải khai báo static final và chỉ cần khai báo kiểu dữ liệu, tên biến và giá trị khởi tạo của hằng số đó.

Khi ghi đè các phương thức được định nghĩa trong Interface, có một số quy tắc sau:

  • Các checked exception không nên được khai báo trong phương thức implements. Thay vào đó nó nên được khai báo trong phương thức Interface hoặc các lớp phụ được khai báo bởi phương thức Interface.
  • Signature (ký số) của phương thức Interface và kiểu trả về nên được duy trì khi ghi đè phương thức (overriding method).
  • Một lớp triển khai chính nó có thể là abstract và vì thế các phương thức Interface không cần được triển khai.

Khi triển khai Interface có một vài quy tắc sau:

  • Một lớp có thể triển khai một hoặc nhiều interface tại một thời điểm và phân tách nhau bằng dấu phẩy.
  • Một lớp chỉ có thể kế thừa một lớp khác, nhưng được triển khai nhiều Interface.
  • Một Interface có thể kế thừa từ một Interface khác, tương tự cách một lớp có thể kế thừa lớp khác.

4. Kế thừa với Interface trong Java

4.1. Kế thừa từ Interface

Một Interface kế thừa từ một Interface khác tương tự như một class kế thừa từ một class. Chúng ta vẫn sẽ sử dụng từ khóa extends. Một lớp mở rộng từ Interface con sẽ kế thừa tất cả các phương thức có trong Interface đó. Một Interface có thể kế thừa từ nhiều Interface và các Interface được ngăn cách với nhau bởi dấu phẩy.

Ví dụ:

  • File Person.java
package vidu2;
 
public interface Person {
     
    void nhap();
    void hienThi();
 
}
  • File Student.java
package vidu2;
 
public interface Student extends Person {
 
    void nhapDiem();
     
}
package vidu2;
 
public class Main implements Student {
 
    @Override
    public void nhap() {
        System.out.println("Đây là phương thức nhap() của Interface Person");
    }
 
    @Override
    public void hienThi() {
        System.out.println("Đây là phương thức hienThi() của Interface Person");
    }
 
    @Override
    public void nhapDiem() {
        System.out.println("Đây là phương thức nhapDiem() của Interface Student");
    }
 
    public static void main(String[] args) {
        Main demo = new Main();
        demo.nhap();
        demo.hienThi();
        demo.nhapDiem();
    }
}

Kết quả

Day la phuong thuc nhap() cua Interface Person
Day la phuong thuc hienThi() cua Interface Person
Day la phuong thuc nhapDiem() cua Interface Student

Ta đã tạo một Interface có tên là Person với Interface con Student kế thừa từ Interface Person và khai báo phương thức nhapDiem() cho Interface này. Lớp Main được khai báo là lớp mở rộng của Interface Student. Trong lớp Main sẽ có 3 phương thức đó là phương thức nhap()hienThi() của Interface Person, phương thức nhapDiem() của Interface Student. Trong hàm main(), tạo đối tượng và gọi đến 3 phương thức trên, lúc đó chúng ta sẽ có kết quả biên dịch.

4.2. Đa kế thừa trong Java bởi Interface

Trong Java, các class thông thường thì chỉ được phép extends từ một class cha duy nhất có thể là một class khác hoặc abstract class. Thế nhưng trong Interface chúng ta có thể extends nhiều Interface khác. Nếu một lớp triển khai đa kế thừa, hoặc một Interface kế thừa từ nhiều Interface thì đó là đa kế thừa.

Ví dụ:

interface Printable{  
void print();  
}  
  
interface Showable{  
void show();  
}  
  
class A7 implements Printable,Showable{  
  
public void print(){System.out.println("Hello");}  
public void show(){System.out.println("Welcome");}  
  
public static void main(String args[]){  
A7 obj = new A7();  
obj.print();  
obj.show();  
 }  
}

Kết quả

Hello
Welcome

5. Phương thức trong Interface

5.1. Phương thức private và static trong Interface

Với việc phát hành Java 8, các Interface giờ đây có thể bao gồm các phương thức tĩnh. Tương tự như một class, chúng ta có thể truy cập các phương thức tĩnh của một Interface bằng cách sử dụng các tham chiếu của nó.

Ví dụ: Polygon.staticMethod();

Ngoài ra, các Interface hỗ trợ các phương thức private với việc phát hành Java 9. Bây giờ ta có thể sử dụng các phương thức private và phương thức private static trong các Interface.

Vì ta không thể khởi tạo Interface, các phương thức private được sử dụng làm phương thức hỗ trợ cho các phương thức khác trong các Interface.

5.2. Phương thức default trong Interface

Với việc phát hành Java 8, các phương thức được triển khai (các phương thức default) đã được tích hợp bên trong một Interface. Trước đó, trong Java tất cả các phương thức đều là phương thức trừu tượng.

Để khai báo các phương thức default bên trong các Interface, ta sử dụng từ khóa default.

Ví dụ:

public default void getSides() {
   // body of getSides()
}
interface  Polygon {
   void getArea();
   default void getSides() {
      System.out.println("I can get sides of polygon.");
   }
}

class Rectangle implements Polygon {
   public void getArea() {
      int length = 6;
      int breadth = 5;
      int area = length * breadth;
      System.out.println("Diện tích của hình chữ nhật là "+area);
   }

   public void getSides() {
      System.out.println("Tôi có 4 mặt.");
   }
}

class Square implements Polygon {
   public void getArea() {
      int length = 5;
      int area = length * length;
      System.out.println("Diện tích của hình vuông là "+area);
   }
}

class Main {
   public static void main(String[] args) {
      Rectangle r1 = new Rectangle();
      r1.getArea();
      r1.getSides();

      Square s1 = new Square();
      s1.getArea();
   }
}

Kết quả

Diện tích của hình chữ nhật là 30
Tôi có 4 mặt.
Diện tích của hình vuông là 25

Ở đây ta đã tạo ra một Interface Polygon. Interface Polygon này có một phương thức defaultgetSides() và một phương thức trừu tượng là getArea(). Class Square sau đó thực hiện Polygon. Class Square triển khai phương thức trừu tượng getArea() và ghi đè phương thức default getSides(). Ta vừa tạo ra một class Square khác cũng triển khai Interface Polygon. Ở đây, class Square chỉ cần thực thi phương thức trừu tượng getArea().