Toán tử instanceof
Thuộc phần Lập trình hướng đối tượng trong hành trình Java của Coddy. Bài học 31 trên 87.
Bài học trước cho thấy việc ép kiểu xuống có thể gây ra ClassCastException nếu đối tượng không thực sự thuộc kiểu mà bạn đang ép sang. Toán tử instanceof giúp giải quyết vấn đề này bằng cách cho phép bạn kiểm tra kiểu của đối tượng trước khi ép kiểu.
Cú pháp khá đơn giản: object instanceof ClassName trả về true nếu đối tượng là một instance của lớp đó (hoặc bất kỳ lớp con nào của nó):
Animal animal = new Dog();
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
dog.bark(); // Có thể gọi các phương thức riêng của Dog một cách an toàn
}Kiểm tra này ngăn lỗi khi chạy bằng cách đảm bảo phép ép kiểu sẽ thành công. Toán tử này cũng trả về true với các kiểu lớp cha trong hệ thống phân cấp:
Dog dog = new Dog();
System.out.println(dog instanceof Dog); // true
System.out.println(dog instanceof Animal); // true
System.out.println(dog instanceof Object); // trueKể từ Java 16, bạn có thể kết hợp việc kiểm tra và ép kiểu trong một bước bằng cách sử dụng đối sánh mẫu:
if (animal instanceof Dog dog) {
dog.bark(); // 'dog' đã được ép kiểu và sẵn sàng để dùng
}Cú pháp gọn hơn này loại bỏ dòng ép kiểu riêng. Lưu ý rằng instanceof trả về false khi kiểm tra với null, vì vậy bạn không cần kiểm tra null riêng.
Thử thách
DễHãy xây dựng một hệ thống kiểm tra phương tiện sử dụng toán tử instanceof để nhận diện và xử lý an toàn các loại phương tiện khác nhau. Bạn sẽ tạo một hệ thống phân cấp phương tiện và viết code kiểm tra kiểu thực tế của từng phương tiện trước khi truy cập các tính năng riêng của nó.
Bạn sẽ sắp xếp code trong bốn tệp:
Vehicle.java: Tạo lớp cơ sở dùng chung cho tất cả phương tiện. Mỗi phương tiện có trườngmodel(String). Thêm hàm khởi tạo để thiết lập trường này, phương thức gettergetModel()và phương thứcinspect()để in ra:Inspecting vehicle: [model]Car.java: Tạo một lớp kế thừa Vehicle. Ô tô có thêm trườngnumDoors(int). Dùngsuperđể khởi tạo lớp cha. Thêm phương thứccheckDoors()để in ra:[model] has [numDoors] doorsMotorcycle.java: Tạo một lớp khác kế thừa Vehicle. Xe máy có trườnghasSidecar(boolean). Thêm phương thứccheckSidecar()để in ra[model] has a sidecarhoặc[model] has no sidecartùy theo giá trị boolean.Main.java: Đây là lúcinstanceoftrở nên thiết yếu! Bạn sẽ nhận bốn đầu vào: mẫu xe ô tô, số cửa, mẫu xe máy và xe máy có thùng phụ hay không (true/false).Tạo một mảng các tham chiếu
Vehiclechứa một Car và một Motorcycle. Sau đó lặp qua mảng và thực hiện các thao tác sau với từng phương tiện:- Gọi phương thức cơ sở
inspect() - Dùng
instanceofđể kiểm tra xem đó có phải là Car không. Nếu đúng, ép kiểu xuống một cách an toàn rồi gọicheckDoors() - Dùng
instanceofđể kiểm tra xem đó có phải là Motorcycle không. Nếu đúng, ép kiểu xuống một cách an toàn rồi gọicheckSidecar()
- Gọi phương thức cơ sở
Bạn sẽ nhận bốn đầu vào: mẫu xe ô tô (String), số cửa (int), mẫu xe máy (String) và có thùng phụ hay không (boolean).
Đầu ra gồm bốn dòng. Với mỗi phương tiện, bạn sẽ thấy thông báo kiểm tra, sau đó là phần kiểm tra riêng theo loại phương tiện. Toán tử instanceof đảm bảo bạn chỉ gọi các phương thức của Car trên đối tượng Car thực tế và các phương thức của Motorcycle trên đối tượng Motorcycle thực tế, nhờ đó tránh được mọi ClassCastException!
Tự làm thử
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Đọc dữ liệu đầu vào
String carModel = scanner.nextLine();
int numDoors = Integer.parseInt(scanner.nextLine());
String motorcycleModel = scanner.nextLine();
boolean hasSidecar = Boolean.parseBoolean(scanner.nextLine());
// TODO: Tạo đối tượng Car với carModel và numDoors
// TODO: Tạo đối tượng Motorcycle với motorcycleModel và hasSidecar
// TODO: Tạo mảng các tham chiếu Vehicle chứa Car và Motorcycle
// TODO: Duyệt qua mảng và với mỗi phương tiện:
// 1. Gọi phương thức inspect()
// 2. Dùng instanceof để kiểm tra xem đó có phải là Car không, sau đó ép kiểu xuống và gọi checkDoors()
// 3. Dùng instanceof để kiểm tra xem đó có phải là Motorcycle không, sau đó ép kiểu xuống và gọi checkSidecar()
}
}
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Lập trình hướng đối tượng
1Kiến thức cơ bản về lập trình hướng đối tượng
Tệp bên ngoàiGiới thiệu về lập trình hướng đối tượngLớp và đối tượngTừ khóa thisPhương thứcTrường (thuộc tính)Phương thức khởi tạoNạp chồng phương thức khởi tạoÔn tập: Máy tính đơn giản4Kế thừa
Kế thừa cơ bản (extends)Từ khóa superGhi đè phương thức (@Override)Chuỗi gọi hàm khởi tạoLớp ObjectKế thừa đơn và đa cấpVì sao không hỗ trợ kế thừa nhiều lớpÔn tập: Phân cấp lớp Employee7Phương thức đặc biệt và lớp Object
Phương thức toString()equals() và hashCode()Phương thức clone()compareTo() và ComparableGiao diện ComparatorÔn tập: sắp xếp tùy chỉnh2Bộ điều chỉnh quyền truy cập và đóng gói
Tổng quan về các mức truy cậpPhương thức getter và setterẨn thông tinTừ khóa finalÔn tập: Trình quản lý tài khoản ngân hàng5Tính đa hình
Kiến thức cơ bản về nạp chồng phương thứcGhi đè phương thức (thời gian chạy)Chuyển kiểu lên và chuyển kiểu xuốngToán tử instanceofLớp và phương thức trừu tượngÔn tập: máy tính hình học8Khái niệm OOP nâng cao
Kết hợp và kế thừaKết tập và hợp thànhLớp bên trong, lớp lồng nhau và lớp ẩn danhKiểu enum và phương thức enumBản ghi (Java 16+)Lớp sealed (Java 17+)3Thuộc tính lớp và thành viên tĩnh
Biến của instance và biến tĩnhPhương thức tĩnhKhối tĩnhHằng số (static final)Ôn tập: bộ đếm và tiện ích6Giao diện và lớp trừu tượng
Giới thiệu về giao diệnTriển khai giao diệnTriển khai nhiều giao diệnPhương thức mặc định và tĩnh trong giao diệnLớp trừu tượng và giao diệnGiao diện hàmÔn tập: hệ thống thanh toán9Kiểu tổng quát
Giới thiệu về kiểu tổng quátLớp tổng quátPhương thức tổng quátTham số kiểu có giới hạnKý tự đại diện (?, extends, super)Ôn tập: vùng chứa tổng quát12Mẫu thiết kế, phần 2
Mẫu CommandMẫu AdapterMẫu DecoratorMẫu Template MethodMẫu StateMẫu CompositeMẫu IteratorTự luyện tập: Trình biên dịch Java online