JavaRush /Blog Java /Random-VI /Các lớp trừu tượng trong Java với các ví dụ cụ thể

Các lớp trừu tượng trong Java với các ví dụ cụ thể

Xuất bản trong nhóm
Xin chào! Trong các bài giảng trước, chúng ta đã làm quen với các giao diện và tìm hiểu xem chúng cần thiết để làm gì. Chủ đề hôm nay sẽ có điểm chung với chủ đề trước. Hãy nói về các lớp trừu tượng trong Java. Các lớp trừu tượng trong Java với các ví dụ cụ thể - 1

Tại sao các lớp được gọi là "trừu tượng"

Chắc bạn còn nhớ “trừu tượng” là gì - chúng ta đã đề cập đến nó rồi :) Nếu bạn chợt quên, không sao cả, hãy nhớ: đây là nguyên tắc của OOP , theo đó khi thiết kế lớp và tạo đối tượng, cần phải làm nổi bật chỉ những thuộc tính chính của một thực thể và loại bỏ những thuộc tính phụ. Ví dụ: nếu chúng ta đang thiết kế một lớp học SchoolTeacher- một giáo viên trong trường - chúng ta có thể không cần đến đặc điểm “ chiều cao ”. Quả thực: đối với một giáo viên, đặc điểm này không quan trọng. Nhưng nếu chúng ta tạo một lớp trong chương trình BasketballPlayer- một cầu thủ bóng rổ - chiều cao sẽ trở thành một trong những đặc điểm chính. Vì vậy, một lớp trừu tượng là lớp “trống” trừu tượng nhất, gần đúng nhất đối với một nhóm các lớp trong tương lai. Chế phẩm này không thể được sử dụng ở dạng hoàn thiện - nó quá “thô”. Nhưng nó mô tả một trạng thái và hành vi chung nhất định mà các lớp trong tương lai - những lớp kế thừa của lớp trừu tượng - sẽ có.

Ví dụ về lớp trừu tượng Java

Hãy xem một ví dụ đơn giản với ô tô:
public abstract class Car {

   private String model;
   private String color;
   private int maxSpeed;

   public abstract void gas();

   public abstract void brake();

   public String getModel() {
       return model;
   }

   public void setModel(String model) {
       this.model = model;
   }

   public String getColor() {
       return color;
   }

   public void setColor(String color) {
       this.color = color;
   }

   public int getMaxSpeed() {
       return maxSpeed;
   }

   public void setMaxSpeed(int maxSpeed) {
       this.maxSpeed = maxSpeed;
   }
}
Đây là lớp trừu tượng đơn giản nhất trông như thế nào. Như bạn có thể thấy, không có gì đặc biệt :) Chúng ta cần nó để làm gì? Trước hết, anh ấy mô tả thực thể mà chúng ta cần một cách trừu tượng nhất có thể - một chiếc ô tô. Từ trừu tượng ở đây là có lý do. Không có “máy móc công bằng” trên thế giới. Có xe tải, xe đua, xe sedan, xe coupe, xe SUV. Lớp trừu tượng của chúng ta chỉ đơn giản là một “bản thiết kế” mà từ đó chúng ta sẽ tạo ra các lớp ô tô sau này.
public class Sedan extends Car {

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

   @Override
   public void brake() {
       System.out.println("The sedan slows down!");
   }

}
Điều này rất giống với những gì chúng ta đã nói trong các bài giảng về thừa kế. Chỉ ở đó chúng tôi mới có một lớp Carvà các phương thức của nó không trừu tượng. Nhưng giải pháp này có một số nhược điểm đã được sửa chữa trong các lớp trừu tượng. Đầu tiên và quan trọng nhất, không thể tạo một thể hiện của một lớp trừu tượng:
public class Main {

   public static void main(String[] args) {

       Car car = new Car(); // Error! The Car class is abstract!
   }
}
“Thủ thuật” này được thực hiện cụ thể bởi những người tạo ra Java. Một lần nữa, hãy nhớ: lớp trừu tượng chỉ là bản thiết kế cho các lớp "bình thường" trong tương lai . Bạn không cần bản sao của bản vẽ, phải không? Vì vậy, không cần phải tạo các thể hiện của một lớp trừu tượng :) Và nếu lớp đó Carkhông trừu tượng, chúng ta có thể dễ dàng tạo các đối tượng của nó:
public class Car {

   private String model;
   private String color;
   private int maxSpeed;

   public void gas() {
       // some logic
   }

   public  void brake() {
       // some logic
   }
}


public class Main {

   public static void main(String[] args) {

       Car car = new Car(); // Everything is OK, the machine has been created
   }
}
Bây giờ chúng tôi có một số loại ô tô kỳ lạ trong chương trình của mình - không phải xe tải, không phải xe đua, không phải sedan, mà là một thứ gì đó nói chung. Điều “chỉ là một cỗ máy” đó không tồn tại trong tự nhiên. Ví dụ tương tự có thể được đưa ra với động vật. Hãy tưởng tượng nếu các đối tượng xuất hiện trong chương trình của bạn Animal- “ chỉ là một con vật ”. Nó thuộc loại gì, thuộc họ nào, có đặc điểm gì - không rõ ràng. Sẽ thật kỳ lạ khi thấy anh ấy trong chương trình. Không có “động vật” nào trong tự nhiên. Chỉ có chó, mèo, cáo, chuột chũi và những loài khác. Các lớp trừu tượng giải phóng chúng ta khỏi “ chỉ các đối tượng ”. Chúng cung cấp cho chúng ta trạng thái và hành vi cơ bản. Ví dụ: tất cả ô tô đều phải có kiểu dáng , màu sắctốc độ tối đa , đồng thời chúng cũng phải có khả năng tăng gaphanh . Đó là tất cả. Đây là một sơ đồ trừu tượng chung, sau đó bạn tự thiết kế các lớp mình cần. Xin lưu ý: hai phương thức trong một lớp trừu tượng cũng được chỉ định là abstract và chúng hoàn toàn không được triển khai. Lý do là như nhau: các lớp trừu tượng không tạo ra "hành vi mặc định" cho "máy đơn thuần". Họ chỉ nói rằng họ có thể sản xuất được tất cả ô tô. Tuy nhiên, nếu bạn vẫn cần hành vi mặc định, bạn có thể triển khai các phương thức trong một lớp trừu tượng. Java không cấm điều này:
public abstract class Car {

   private String model;
   private String color;
   private int maxSpeed;

   public void gas() {
       System.out.println("Let's go!");
   }

   public abstract void brake();

   //getters and setters
}


public class Sedan extends Car {

   @Override
   public void brake() {
       System.out.println("The sedan slows down!");
   }

}

public class Main {

   public static void main(String[] args) {

       Sedan sedan = new Sedan();
       sedan.gas();
   }
}
Đầu ra của bảng điều khiển: “Tăng tốc!” Như bạn có thể thấy, chúng tôi đã triển khai một phương thức trong lớp trừu tượng nhưng không triển khai phương thức thứ hai. Kết quả là, hành vi của lớp của chúng tôi Sedanđược chia thành hai phần: nếu bạn gọi một phương thức trên đó gas(), nó sẽ "kéo lên" từ lớp trừu tượng cha Carbrake()chúng tôi đã xác định lại phương thức trong lớp đó Sedan. Hóa ra nó rất thuận tiện và linh hoạt. Nhưng bây giờ lớp học của chúng ta không còn trừu tượng nữa ? Rốt cuộc, trên thực tế, một nửa số phương pháp của anh ấy đã được thực hiện. Trong thực tế - và đây là một tính năng rất quan trọng - một lớp là trừu tượng nếu ít nhất một trong các phương thức của nó là trừu tượng . Ít nhất một trong hai, ít nhất một trong hàng nghìn phương pháp - không thành vấn đề. Chúng ta thậm chí có thể triển khai tất cả các phương thức và không để lại bất kỳ phương thức trừu tượng nào. Sẽ có một lớp trừu tượng không có các phương thức trừu tượng. Về nguyên tắc, điều này là có thể và trình biên dịch sẽ không tạo ra lỗi, nhưng tốt hơn hết là bạn không nên làm điều này: từ trừu tượng sẽ mất ý nghĩa và các lập trình viên đồng nghiệp của bạn sẽ rất ngạc nhiên khi thấy điều này:/ Hơn nữa, nếu một phương thức được đánh dấu bằng từ trừu tượng, mỗi lớp con cháu phải triển khai hoặc được khai báo là trừu tượng. Nếu không trình biên dịch sẽ báo lỗi . Tất nhiên, mỗi lớp chỉ có thể kế thừa từ một lớp trừu tượng nên về mặt kế thừa không có sự khác biệt giữa lớp trừu tượng và lớp thông thường. Việc chúng ta kế thừa từ một lớp trừu tượng hay từ một lớp thông thường không quan trọng, chỉ có thể có một lớp cha.

Tại sao không có tính kế thừa đa lớp trong Java?

Chúng tôi đã nói rằng không có tính đa kế thừa trong Java, nhưng chúng tôi vẫn chưa thực sự hiểu tại sao. Hãy thử điều này ngay bây giờ. Vấn đề là nếu Java có nhiều kế thừa, các lớp con sẽ không thể quyết định nên chọn hành vi nào. Giả sử chúng ta có hai lớp - TosterNuclearBomb:
public class Toster {


 public void on() {

       System.out.println("The toaster is on, the toast is getting ready!");
   }

   public void off() {

       System.out.println("The toaster is off!");
   }
}


public class NuclearBomb {

   public void on() {

       System.out.println("Взрыв!");
   }
}
Như bạn có thể thấy, cả hai đều có một phương thức on(). Trong trường hợp máy nướng bánh mì, nó bắt đầu nấu bánh mì nướng và trong trường hợp bom hạt nhân, nó gây ra vụ nổ. Ồ:/ Bây giờ hãy tưởng tượng rằng bạn quyết định (tôi không biết tại sao đột nhiên!) tạo ra thứ gì đó ở giữa. Và đây là lớp học của bạn - MysteriousDevice! Tất nhiên, mã này không hoạt động và chúng tôi trình bày nó đơn giản như một ví dụ về “nó có thể như thế nào”:
public class MysteriousDevice extends Toster, NuclearBomb {

   public static void main(String[] args) {

       MysteriousDevice mysteriousDevice = new MysteriousDevice();
       mysteriousDevice.on(); // And what should happen here? Will we get a toast, or a nuclear apocalypse?
   }
}
Hãy xem chúng ta có gì nào. Thiết bị bí ẩn đến từ cả Máy nướng bánh mì và Bom hạt nhân. Cả hai đều có một phương thức on()và kết quả là không rõ phương thức nào on()sẽ kích hoạt đối tượng MysteriousDevicenếu chúng ta gọi nó. Đối tượng sẽ không thể hiểu được điều này. Chà, như một quả anh đào trên chiếc bánh: Bom hạt nhân không có phương pháp off(), vì vậy nếu chúng ta đoán sai thì sẽ không có cách nào để tắt thiết bị. Các lớp trừu tượng trong Java với các ví dụ cụ thể - 2 Chính vì sự nhầm lẫn này, khi một đối tượng không rõ nó nên chọn hành vi nào, mà những người tạo ra Java đã từ bỏ tính đa kế thừa. Tuy nhiên, bạn hãy nhớ rằng các lớp Java triển khai nhiều giao diện. Nhân tiện, bạn đã gặp ít nhất một lớp trừu tượng trong quá trình học của mình! Mặc dù vậy, có lẽ tôi đã không nhận thấy điều đó :)
public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar>
Đây là bạn cũ của bạn - lớp Calendar. Nó trừu tượng và có nhiều người thừa kế. Một trong số đó là GregorianCalendar. Bạn đã sử dụng nó trong các bài học về ngày tháng :) Mọi thứ dường như đã rõ ràng, chỉ còn một điểm duy nhất: sự khác biệt cơ bản giữa các lớp trừu tượng và giao diện là gì ? Tại sao họ thêm cả hai vào Java mà không giới hạn chỉ một? Điều này có thể là đủ. Chúng ta sẽ nói về điều này trong bài giảng tiếp theo! Thấy bạn:)
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION