1. Giới thiệu giao diện

Hôm nay là ngày của bạn cho kiến ​​thức. Một chủ đề mới và thú vị khác là giao diện.

Khái niệm về một giao diện là đứa con của các nguyên tắc trừu tượng và đa hình. Một giao diện rất giống với một lớp trừu tượng, trong đó tất cả các phương thức đều trừu tượng. Nó được khai báo giống như một lớp, nhưng chúng ta sử dụng từ interfacekhóa.

interface Feline
{
   void purr();
   void meow();
   void growl();
}

Dưới đây là một số thông tin hữu ích về giao diện:

1. Khai báo giao diện

interface Drawable
{
   void draw();
}

interface HasValue
{
   int getValue();
}
  1. Thay vì classtừ khóa, chúng tôi viết interface.
  2. Nó chỉ chứa các phương thức trừu tượng (không viết abstracttừ khóa)
  3. Trên thực tế, các giao diện có tất cảpublic các phương thức
2. Kế thừa giao diện

Một giao diện chỉ có thể kế thừa các giao diện. Nhưng một giao diện có thể có nhiều cha mẹ. Một cách khác để nói điều này là nói rằng Java có nhiều giao diện kế thừa. Ví dụ:

interface Piece extends Drawable, HasValue
{
   int getX();
   int getY();
}

3. Kế thừa các lớp từ giao diện

Một lớp có thể kế thừa nhiều giao diện (chỉ từ một lớp). Điều này được thực hiện bằng cách sử dụng implementstừ khóa. Ví dụ:

abstract class ChessItem implements Drawable, HasValue
{
   private int x, y, value;
   public int getValue()
   {
      return value;
   }

   public int getX()
   {
      return x;
   }

   public  int getY()
   {
      return y;
   }
}

Lớp ChessItem được khai báo là trừu tượng: nó thực hiện tất cả các phương thức kế thừa ngoại trừ draw. Nói cách khác, ChessItemlớp chứa một phương thức trừu tượng — draw().

Ý nghĩa kỹ thuật của từ khóa extendsimplementslà như nhau: cả hai đều là sự kế thừa. Sự khác biệt đã được thực hiện để cải thiện khả năng đọc mã. Chúng tôi cũng nói rằng các lớp được kế thừa (thông qua extends) và các giao diện được triển khai (thông qua implements)

4. Biến

Đây là điều quan trọng nhất: các biến thông thường không thể được khai báo trong các giao diện (mặc dù các biến tĩnh thì có thể).

Nhưng tại sao chúng ta cần giao diện? Khi nào chúng được sử dụng? Các giao diện có hai ưu điểm mạnh so với các lớp:



2. Tách "mô tả phương pháp" khỏi việc thực hiện chúng.

Trước đây, chúng tôi đã nói rằng nếu bạn muốn cho phép các phương thức của lớp bạn được gọi từ các lớp khác, thì các phương thức của bạn cần được đánh dấu bằng từ publickhóa. Nếu bạn muốn một số phương thức đó chỉ được gọi từ bên trong lớp của mình, bạn cần đánh dấu chúng bằng từ privatekhóa. Nói cách khác, chúng ta chia các phương thức của lớp thành hai loại: "dành cho mọi người sử dụng" và "chỉ sử dụng cho chính chúng ta".

Các giao diện giúp tăng cường sự phân chia này hơn nữa. Chúng tôi sẽ tạo một lớp đặc biệt "cho mọi người sử dụng" cũng như lớp thứ hai "chỉ dành cho mục đích sử dụng của riêng chúng tôi", lớp này sẽ kế thừa lớp đầu tiên. Đây là đại khái nó sẽ trông như thế nào:

Trước Sau đó
class Student
{
   private String name;
   public Student(String name)
   {
      this.name = name;
   }

   public String getName()
   {
      return this.name;
   }

   private void setName(String name)
   {
      this.name = name;
   }
interface Student
{
   public String getName();
}

class StudentImpl implements Student
{
   private String name;
   public StudentImpl(String name)
   {
      this.name = name;
   }

   public String getName()
   {
      return this.name;
   }

   private void setName(String name)
   {
      this.name = name;
   }
}
public static void main(String[] args)
{
   Student student = new Student("Alibaba");
   System.out.println(student.getName());
}
public static void main(String[] args)
{
   Student student = new StudentImpl("Ali")
   System.out.println(student.getName());
}

Chúng tôi chia lớp của chúng tôi thành hai: một giao diện và một lớp kế thừa giao diện . Và lợi thế ở đây là gì?

Nhiều lớp khác nhau có thể thực hiện (kế thừa) cùng một giao diện. Và mỗi người có thể có hành vi riêng của mình. Ví dụ, ArrayList LinkedListlà hai triển khai khác nhau của Listgiao diện.

Do đó, chúng tôi không chỉ ẩn các triển khai khác nhau mà còn ẩn chính lớp triển khai (vì chúng tôi chỉ cần giao diện trong mã). Điều này cho phép chúng ta rất linh hoạt: ngay khi chương trình đang chạy, chúng ta có thể thay thế đối tượng này bằng đối tượng khác, thay đổi hành vi của đối tượng mà không ảnh hưởng đến tất cả các lớp sử dụng nó.

Đây là một kỹ thuật rất mạnh khi kết hợp với tính đa hình. Hiện tại, vẫn chưa rõ tại sao bạn nên làm điều này. Trước tiên, bạn cần gặp các chương trình có hàng chục hoặc hàng trăm lớp để hiểu rằng các giao diện có thể giúp cuộc sống của bạn dễ dàng hơn rất nhiều so với việc không có chúng.


3. Đa thừa kế

Trong Java, tất cả các lớp chỉ có thể có một lớp cha. Trong các ngôn ngữ lập trình khác, các lớp thường có thể có nhiều lớp cha. Điều này rất thuận tiện, nhưng cũng mang lại nhiều rắc rối.

Những người tạo ra Java đã đi đến một thỏa hiệp: họ cấm nhiều kế thừa các lớp, nhưng cho phép nhiều kế thừa giao diện. Một giao diện có thể có nhiều giao diện cha. Một lớp có thể có nhiều giao diện cha nhưng chỉ có một lớp cha.

Tại sao họ cấm nhiều lớp kế thừa nhưng lại cho phép nhiều kế thừa giao diện? Vì cái gọi là vấn đề thừa kế kim cương:

đa thừa kế

Khi lớp B kế thừa lớp A, nó không biết gì về lớp C và D. Vì vậy, nó sử dụng các biến của lớp A khi nó thấy phù hợp. Lớp C cũng làm như vậy: nó sử dụng các biến của lớp A, nhưng theo một cách khác. Và tất cả điều này dẫn đến một cuộc xung đột trong lớp D.

Hãy xem ví dụ đơn giản sau đây. Giả sử chúng ta có 3 lớp:

class Data
{
   protected int value;
}
class XCoordinate extends Data
{
   public void setX (int x) { value = x;}
   public int getX () { return value;}
}
class YCoordinate extends Data
{
   public void setY (int y) { value = y;}
   public int getY () { return value; }
}

Lớp Data lưu trữ biến value. Lớp hậu duệ XCoordin của nó sử dụng biến đó để lưu trữ xgiá trị và YCoordinatelớp hậu duệ sử dụng nó để lưu trữ ygiá trị.

Và nó hoạt động. Riêng biệt. Nhưng nếu chúng ta muốn lớp XYCoordinates kế thừa cả hai lớp XCoordinateYCoordinate, thì chúng ta sẽ nhận được mã bị lỗi. Lớp này sẽ có các phương thức của các lớp tổ tiên của nó, nhưng chúng sẽ không hoạt động chính xác, bởi vì chúng có cùng value variable.

Nhưng vì các giao diện không thể có các biến, nên chúng không thể có loại xung đột này. Theo đó, nhiều giao diện kế thừa được cho phép.