Mỗi phiên bản mới của Java khác với các phiên bản trước đó. Là một ví dụ về sự thay đổi như vậy từ tài liệu mà chúng tôi đã đề cập, ngôn ngữ này không có enumstrước Java 5.
Các phương thức mặc định trong giao diện - 1
Vì vậy, Java 8 khác biệt đáng kể so với Java 7. Tất nhiên, chúng tôi sẽ không bỏ qua những đổi mới quan trọng. Vì chúng ta đang nói về các giao diện trong bài học này, nên hãy xem xét một bản cập nhật cho ngôn ngữ: các phương thức mặc định trong giao diện . Bạn đã biết rằng một giao diện không thực hiện hành vi . Mục đích của nó là để mô tả hành vi nào phải tồn tại trong tất cả các đối tượng thực hiện giao diện . Nhưng các nhà phát triển thường xuyên gặp phải các tình huống trong đó việc triển khai một phương thức giống nhau ở tất cả các lớp. Hãy xem ví dụ về chiếc ô tô cũ của chúng tôi:
public interface Car {

   public void gas();

   public void brake();
}
public class Sedan implements Car {

   @Override
   public void gas() {
       System.out.println("Gas!");
   }

   @Override
   public void brake() {
       System.out.println("Brake!");
   }
}


public class Truck implements Car {

   @Override
   public void go() {
       System.out.println("Gas!");
   }

   @Override
   public void brake() {
       System.out.println("Brake!");
   }
}


public class F1Car implements Car {
   @Override
   public void go() {
       System.out.println("Gas!");
   }

   @Override
   public void brake() {
       System.out.println("Brake!");
   }
}
Bạn nghĩ vấn đề chính với mã này là gì? Bạn có thể nhận thấy rằng chúng tôi đã viết một loạt mã trùng lặp! Đây là một vấn đề phổ biến trong lập trình và nó nên tránh. Một vấn đề khác là không có giải pháp cụ thể nào trước khi phát hành Java 8. Khi phiên bản đó ra mắt, có thể xác định các phương thức mặc định và triển khai chúng ngay bên trong một giao diện! Đây là cách thực hiện:
public interface Car {

   public default void gas() {
       System.out.println("Gas!");
   }

   public default void brake() {
       System.out.println("Brake!");
   }
}

public class Sedan implements Car {

}

public class Truck implements Car {

}

public class F1Car implements Car {

}
Giờ đây, các phương thức gas()brake()giống nhau cho tất cả các ô tô đã được chuyển vào giao diện, loại bỏ nhu cầu mã trùng lặp. Và các phương thức có sẵn trong mỗi lớp!
public class Main {

   public static void main(String[] args) {

       F1Car f1Car = new F1Car();
       Sedan sedan = new Sedan();
       Truck truck = new Truck();
       truck.gas();
       sedan.gas();
       f1Car.brake();
   }
}
Điều gì sẽ xảy ra nếu có 100 lớp với một gas()phương thức, nhưng chỉ 99 lớp trong số đó có cùng hành vi? Điều đó có làm hỏng mọi thứ không? Phương pháp mặc định sẽ không hoạt động trong trường hợp này? Tất nhiên là không :) Các phương thức giao diện mặc định có thể bị ghi đè.
public class UnusualCar implements Car {
   @Override
   public void go() {
       System.out.println("This car accelerates differently!");
   }

   @Override
   public void brake() {
       System.out.println("This car slows down differently!");
   }
}
Tất cả 99 loại ô tô khác sẽ sử dụng phương pháp mặc định, trong khiUnusualCarlớp là một ngoại lệ. Không làm hỏng bức tranh toàn cảnh, nó sẽ bình tĩnh xác định hành vi của chính nó. Đa kế thừa trong các giao diện. Như bạn đã biết, không có đa kế thừa trong Java. Có nhiều lý do cho việc này. Chúng tôi sẽ xem xét chúng một cách chi tiết trong một bài học riêng biệt. Trong các ngôn ngữ khác, chẳng hạn như C++, tình hình ngược lại. Không có nhiều kế thừa đưa ra một thách thức nghiêm trọng, vì cùng một đối tượng có thể có một số đặc điểm và hành vi khác nhau. Ví dụ, chúng ta là con cái đối với cha mẹ, học sinh đối với giáo viên và bệnh nhân đối với bác sĩ. Trong cuộc sống thực, chúng ta đảm nhận nhiều vai trò khác nhau và theo đó, cư xử khác nhau: rõ ràng là chúng ta tương tác với giáo viên khác với bạn thân. Hãy thử dịch tình huống này thành mã. Hãy tưởng tượng rằng chúng ta có hai lớp: Pond và Aviary. Một cái ao cần những con chim biết bơi, trong khi một cái chuồng chim cần những con biết bay. Để thể hiện điều này, chúng tôi đã tạo hai lớp cơ sở:FlyingBirdWaterfowl.
public class Waterfowl {
}

public class FlyingBird {
}
Theo đó, chúng tôi sẽ gửi những con chim kế thừa FlyingBirdđến chuồng chim, trong khi những con xuất phát Waterfowlsẽ xuống ao. Mọi thứ có vẻ đơn giản. Nhưng chúng ta nên làm gì nếu chúng ta cần xác định một con vịt ở đâu đó? Vịt vừa bơi vừa bay. Nhưng chúng tôi không có nhiều kế thừa. May mắn thay, Java hỗ trợ nhiều triển khai giao diện. Nếu một lớp không thể kế thừa nhiều lớp cha, thì việc triển khai nhiều giao diện rất dễ dàng! Con vịt của chúng ta có thể là một con chim bay cũng như một con chim bơi :) Để đạt được kết quả mong muốn, tất cả những gì chúng ta cần làm là tạo FlyingBirdWaterfowlgiao diện thay vì các lớp.
public class Duck implements FlyingBird, Waterfowl {

   // Methods of both interfaces combine easily into one class

   @Override
   public void fly() {
       System.out.println("Flying!");
   }

   @Override
   public void swim() {

       System.out.println("Swimming!");
   }
}
Điều này có nghĩa là chương trình của chúng tôi vẫn giữ được khả năng quản lý các lớp một cách linh hoạt. Khi chúng tôi kết hợp điều đó với các phương thức mặc định, khả năng xác định hành vi của các đối tượng của chúng tôi trở nên gần như vô hạn! :)