CHÀO! Trong các bài học trước, chúng ta đã làm quen sơ qua với khái niệm kế thừa. Hôm nay, chúng ta sẽ chạm vào chủ đề này một lần nữa, nhưng một lần nữa không quá sâu. Chúng tôi vẫn sẽ có một bài học chi tiết hơn về điều này trong tương lai. Hôm nay chúng ta sẽ xem nhanh một vài ví dụ thực tế và làm quen với một toán tử thú vị trong Java.
Di sản
Vậy thừa kế là gì? Kế thừa là một cơ chế lập trình (kể cả trong Java) cho phép bạn khai báo một lớp mới dựa trên một lớp hiện có. Sau đó, lớp dẫn xuất có quyền truy cập vào các trường và phương thức của lớp cha. Tại sao chúng ta cần điều này? Chà, hãy tưởng tượng rằng bạn cần tạo một số lớp ô tô trong một chương trình: Xe tải, Xe đua, Xe sedan, Xe bán tải, v.v. Ngay cả trước khi viết bất kỳ mã nào, bạn biết chắc rằng tất cả các lớp này đều có nhiều điểm chung: tất cả ô tô đều có một kiểu tên, năm sản xuất, kích thước động cơ, tốc độ tối đa, v.v. (chưa kể đến việc chúng đều có chung bánh xe và các bộ phận khác). Trong tình huống này, bạn có thể:- Tạo các trường này trong mỗi lớp (thêm chúng vào mỗi lớp ô tô mới khi bạn tạo nó)
- Mang các trường chung cho tất cả các ô tô vào một
Car
lớp cha, sau đó sử dụng từ khóa mở rộng để dẫn xuất tất cả các lớp cho các loại ô tô cụ thể từCar
lớp đó.
public class Car {
private String model;
private int maxSpeed;
private int yearOfManufacture;
public Car(String model, int maxSpeed, int yearOfManufacture) {
this.model = model;
this.maxSpeed = maxSpeed;
this.yearOfManufacture = yearOfManufacture;
}
}
public class Truck extends Car {
public Truck(String model, int maxSpeed, int yearOfManufacture) {
super(model, maxSpeed, yearOfManufacture);
}
}
public class Sedan extends Car {
public Sedan(String model, int maxSpeed, int yearOfManufacture) {
super(model, maxSpeed, yearOfManufacture);
}
}
Ở mức tối thiểu, chúng ta tránh được sự trùng lặp mã không cần thiết (và chúng ta nên luôn cố gắng đạt được điều đó khi viết chương trình). Ngoài ra, chúng tôi có cấu trúc lớp đơn giản và dễ hiểu, với tất cả các trường chung cho tất cả các ô tô được hợp nhất thành một lớp. Nếu xe tải có bất kỳ trường đặc biệt nào mà những chiếc xe khác không có, chúng có thể được khai báo trong Truck
lớp. Điều tương tự cũng xảy ra với các phương pháp. Tất cả các ô tô đều có một số hành vi chung có thể được mô tả bằng các phương thức, ví dụ: khởi động ô tô, tăng tốc/phanh, v.v. Các phương thức chung này có thể được hợp nhất vào lớp cha Car
và mỗi loại ô tô cụ thể có thể định nghĩa các hành động duy nhất của nó trong các lớp dẫn xuất của chúng .
public class Car {
public void gas() {
// Accelerate
}
public void brake() {
// Brake
}
}
public class F1Car extends Car {
public void pitStop() {
// Only race cars make pit stops
}
public static void main(String[] args) {
F1Car formula1Car = new F1Car();
formula1Car.gas();
formula1Car.pitStop();
formula1Car.brake();
}
}
Chúng tôi đã thêm các phương thức phổ biến cho tất cả các ô tô vào Car
lớp. Nhưng, hãy nhìn vào F1Car
hạng xe đại diện cho những chiếc xe đua "Công thức 1". Điểm dừng pit (điểm dừng để bảo dưỡng ô tô khẩn cấp) chỉ được thực hiện trong các cuộc đua, vì vậy chúng tôi đã thêm chức năng cụ thể này vào lớp dẫn xuất có liên quan.
toán tử instanceof
Trong Java, có một toán tử đặc biệt, instanceof , để kiểm tra xem liệu một đối tượng có được tạo dựa trên một lớp cụ thể hay không. Nó trả về true hoặc false tùy thuộc vào kết quả kiểm tra. Hãy xem cách nó hoạt động bằng cách sử dụng các lớp trong ví dụ về ô tô của chúng ta:
public class Truck extends Car {
public static void main(String[] args) {
Truck truck = new Truck();
System.out.println(truck instanceof Car);
}
}
Đầu ra: true Toán instanceof
tử trả về true , vì chúng ta có một Truck
đối tượng và tất cả các xe tải đều là ô tô. Lớp Truck
có nguồn gốc từ Car
lớp. Tất cả các xe tải được tạo dựa trên cha chung, Car
lớp. Hãy xem kỹ cách instanceof
toán tử được sử dụng. Bạn viết nó mà không có dấu chấm, vì nó là một toán tử, không phải là một phương thức ("đối tượng thể hiện của Lớp”). Hãy thử một cách khác:
public static void main(String[] args) {
Car car = new Car();
System.out.println(car instanceof Truck);
}
Kết quả: false Lớp Car
(và các đối tượng ô tô) không xuất phát từ Truck
lớp. Tất cả xe tải đều là ô tô, nhưng không phải ô tô nào cũng là xe tải. Car
các đối tượng không dựa trên Truck
lớp. Một ví dụ nữa:
public static void main(String[] args) {
Car car = new Car();
Truck truck = new Truck();
System.out.println(car instanceof Object && truck instanceof Object);
}
Đầu ra: Đúng Ở đây logic cũng đơn giản: tất cả các lớp trong Java, kể cả các lớp bạn tạo, đều xuống từ lớp đó Object
(mặc dù bạn không viết "extends Object"—nó đã được ngụ ý). Làm thế nào và khi nào điều này sẽ hữu ích? Toán instanceof
tử được sử dụng phổ biến nhất khi ghi đè equals()
phương thức. Ví dụ: đây là cách equals
phương thức được triển khai trong String
lớp:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String) anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
Trước khi so sánh a String
với đối tượng đã truyền, phương thức sẽ kiểm tra xem đối tượng có phải là một chuỗi không? Chỉ khi đó nó mới bắt đầu so sánh các thuộc tính của hai đối tượng. Nếu thử nghiệm này không tồn tại, bất kỳ đối tượng nào có trường giá trị và độ dài đều có thể được chuyển đến phương thức và được so sánh với Chuỗi, tất nhiên, điều này sẽ sai.
GO TO FULL VERSION