Bài giảng Lập trình hướng đối tượng - Bài 8: Đa hình (Tiếp theo)
Upcasting và Downcasting
◼ Chuyển đổi kiểu dữ liệu nguyên thủy
◼ Java tự động chuyển đổi kiểu khi
◼ Kiểu dữ liệu tương thích
◼ Chuyển đổi từ kiểu hẹp hơn sang kiểu rộng hơn
int i;
double d = i;
◼ Phải ép kiểu khi
◼ Kiểu dữ liệu tương thích
◼ Chuyển đổi từ kiểu rộng hơn sang kiểu hẹp hơn
int i;
byte b = i; byte b = (byte)i;
◼ Chuyển đổi kiểu dữ liệu tham chiếu
◼ Kiểu dữ liệu tham chiếu có thể được chuyển đổi kiểu khi
◼ Kiểu dữ liệu tham chiếu (lớp) tương thích
◼ Nằm trên cùng một cây phân cấp kế thừa
A var1 = new B();
A var1 = new A();
C var2 = (C)var1;
◼ Hai cách chuyển đổi
◼ Up-casting
◼ Down-casting

Trang 1

Trang 2

Trang 3

Trang 4

Trang 5

Trang 6

Trang 7

Trang 8

Trang 9

Trang 10
Tải về để xem bản đầy đủ
Bạn đang xem 10 trang mẫu của tài liệu "Bài giảng Lập trình hướng đối tượng - Bài 8: Đa hình (Tiếp theo)", để tải tài liệu gốc về máy hãy click vào nút Download ở trên
Tóm tắt nội dung tài liệu: Bài giảng Lập trình hướng đối tượng - Bài 8: Đa hình (Tiếp theo)
Bộ môn Công nghệ Phần mềm
Viện CNTT & TT
Trường Đại học Bách Khoa Hà Nội
IT3100
LẬP TRÌNH HƯỚNG ĐỐI TƯỢNG
Bài 08. Đa hình
Mục tiêu
◼ Giới thiệu về upcasting và downcasting
◼ Phân biệt liên kết tĩnh và liên kết động
◼ Nắm vững kỹ thuật đa hình
◼ Ví dụ và bài tập về các vấn đề trên với ngôn
ngữ lập trình Java
2
Nội dung
1. Upcasting và Downcasting
2. Liên kết tĩnh và Liên kết động
3. Đa hình (Polymorphism)
4. Ví dụ và bài tập
3
1. Upcasting và Downcasting
4
1. Upcasting và Downcasting
◼ Chuyển đổi kiểu dữ liệu nguyên thủy
◼ Java tự động chuyển đổi kiểu khi
◼ Kiểu dữ liệu tương thích
◼ Chuyển đổi từ kiểu hẹp hơn sang kiểu rộng hơn
int i;
double d = i;
◼ Phải ép kiểu khi
◼ Kiểu dữ liệu tương thích
◼ Chuyển đổi từ kiểu rộng hơn sang kiểu hẹp hơn
int i;
byte b = i; byte b = (byte)i;
5
1. Upcasting và Downcasting
◼ Chuyển đổi kiểu dữ liệu tham chiếu
◼ Kiểu dữ liệu tham chiếu có thể được chuyển đổi kiểu khi
◼ Kiểu dữ liệu tham chiếu (lớp) tương thích A
◼ Nằm trên cùng một cây phân cấp kế thừa
A var1 = new B();
A var1 = new A();
C var2 = (C)var1; B
◼ Hai cách chuyển đổi
◼ Up-casting
“dán cho nó một cái nhãn”
◼ Down-casting
C
6
1.1 Upcasting
◼ Up casting: đi lên trên cây phân cấp thừa kế
(moving up the inheritance hierarchy)
◼ Up casting là khả năng nhìn nhận đối tượng thuộc
lớp dẫn xuất như là một đối tượng thuộc lớp cơ sở.
◼ Tự động chuyển đổi kiểu
7
1.1 Upcasting
◼ Ví dụ:
public class Test1 { Person
public static void main(String arg[]) { - name: String
Employee e = new Employee(); - birthday: Date
Person p;
+ setName(String)
p = e;
p.setName(“Hoa”); ? + setBirthday(Date)
p.setSalary(350000); + getDetails(): String
// compile error
}
Employee
- salary: double
+ setSalary(double)
+ getDetails(): String
8
1.1 Upcasting Person
- name: String
- birthday: Date
◼ Ví dụ: + setName(String)
class Manager extends Employee { + setBirthday(Date)
Employee assistant;
+ getDetails(): String
// ...
public void setAssistant(Employee e) {
assistant = e; Employee
} - salary: double
// ... + setSalary(double)
} + getDetails(): String
public class Test2 {
public static void main(String arg[]) {
Manager
Manager junior, senior;
// ... - assistant: Employee
senior.setAssistant(junior); + setAssistant(Employee)
} + getDetails():String
} 9
1.1 Upcasting Person
- name: String
- birthday: Date
◼ Ví dụ: + setName(String)
public class Test3 { + setBirthday(Date)
String static teamInfo(Person p1,
+ getDetails(): String
Person p2) {
return "Leader: " + p1.getName() +
", member: " + p2.getName(); Employee
} - salary: double
public static void main(String arg[]) { + setSalary(double)
Employee e1, e2; + getDetails(): String
Manager m1, m2;
// ...
Manager
System.out.println(teamInfo(e1, e2));
System.out.println(teamInfo(m1, m2)); - assistant: Employee
System.out.println(teamInfo(m1, e2)); + setAssistant(Employee)
} + getDetails():String
} 10
1.2 Downcasting
◼ Down casting: đi xuống cây phân cấp thừa kế
(move back down the inheritance hierarchy)
◼ Down casting là khả năng nhìn nhận một đối tượng
thuộc lớp cơ sở như một đối tượng thuộc lớp dẫn
xuất.
◼ Không tự động chuyển đổi kiểu
→ Phải ép kiểu.
11
1.2 Downcasting Person
- name: String
- birthday: Date
◼ Ví dụ: + setName(String)
public class Test2 { + setBirthday(Date)
public static void main(String arg[]) {
+ getDetails(): String
Employee e = new Employee();
Person p = e; // up casting
Employee e1 = (Employee) p; Employee
// down casting - salary: double
Manager m = (Manager) ee; + setSalary(double)
// run-time error + getDetails(): String
Person p2 = new Manager();
Manager
Employee e2 = (Employee) p2;
} - assistant: Employee
} + setAssistant(Employee)
+ getDetails():String
12
Toán tử instanceof
◼ Kiểm tra xem một đối tượng có phải là thể hiện của
một lớp nào đó không
◼ Trả về: true | false (nếu đối tượng là null thì trả về
false)
public class Employee extends Person {}
public class Student extends Person {}
public class Test{
public doSomething(Person e) {
if (e instanceof Employee) {...
} else if (e instanceof Student) {...
} else {...
}
}
13
}
2. Liên kết tĩnh và liên kết động
(Static binding & dynamic binding)
14
Liên kết lời gọi hàm
◼ Liên kết lời gọi hàm (function call binding) là quy
trình xác định khối mã hàm cần chạy khi một lời gọi
hàm được thực hiện
◼ C: đơn giản vì mỗi hàm có duy nhất một tên
◼ C++: chồng hàm, phân tích chữ ký kiểm tra danh sách
tham số
15
Trong ngôn ngữ Hướng đối tượng
◼ Liên kết lời gọi phương thức
◼ Đối với các lớp độc lập (không thuộc cây thừa kế
nào), quy trình này gần như không khác với
function call binding
◼ so sánh tên phương thức, danh sách tham số để tìm định
nghĩa tương ứng
◼ một trong số các tham số là tham số ẩn: con trỏ this
bar.foo (); → lời gọi
này bị ràng buộc với định
nghĩa của phương thức
mà nó gọi
16
2.1 Liên kết tĩnh
◼ Liên kết tại thời điểm biên dịch
◼ Early Binding/Compile-time Binding
◼ Lời gọi phương thức được quyết định khi biên
dịch, do đó chỉ có một phiên bản của phương
thức được thực hiện
◼ Nếu có lỗi thì sẽ có lỗi biên dịch
◼ Ưu điểm về tốc độ
◼ C/C++ function call binding, và C++ method
binding cơ bản đều là ví dụ của liên kết tĩnh
(static function call binding)
17
2.1 Liên kết tĩnh
◼ Thích hợp cho các lời gọi hàm thông thường
◼ Mỗi lời gọi hàm chỉ xác định duy nhất một định
nghĩa hàm, kể cả trường hợp hàm chồng.
◼ Phù hợp với các lớp độc lập không thuộc cây
thừa kế nào
◼ Mỗi lời gọi phương thức từ một đối tượng của lớp
hay từ con trỏ đến đối tượng đều xác định duy
nhất một phương thức
18
2.2 Liên kết động
◼ Lời gọi phương thức được quyết định khi
thực hiện (run-time)
◼ Late binding/Run-time binding
◼ Phiên bản của phương thức phù hợp với đối
tượng được gọi
◼ Java trì hoãn liên kết phương thức cho đến thời
gian chạy (run-time) - đây được gọi là liên kết
động hoặc liên kết trễ
◼ Java mặc định sử dụng liên kết động
19
Ví dụ Person
- name: String
- birthday: Date
public class Test {
+ setName(String)
public static void main(String arg[]){
+ setBirthday(Date)
Person p = new Person();
+ getDetails(): String
// ...
Employee e = new Employee();
// ... Employee
Manager m = new Manager(); - salary: double
// ... + setSalary(double)
Person pArr[] = {p, e, m}; + getDetails(): String
for (int i=0; i< pArr.length; i++){
System.out.println(
pArr[i].getDetail()); Manager
} - assistant: Employee
} Tuỳ thuộc vào đối tượng + setAssistant(Employee)
} gọi tại thời điểm thực thi + getDetails():String
chương trình (run-time) 20
Câu hỏi
◼ Giả sử lớp Sub kế thừa từ lớp cha Sandwich. Tạo hai đối
tượng từ các lớp này:
Sandwich x = new Sandwich();
Sub y = new Sub();
◼ Phép gán nào sau đây là hợp lệ?
1. x = y;
2. y = x;
3. y = new Sandwich();
4. x = new Sub();
21
3. Đa hình
(Polymorphism)
22
3. Đa hình
◼ Ví dụ: Một hoạt động có thể được thực hiện trên một đối
tượng 2DShape cũng có thể được thực hiện trên một đối
tượng thuộc một trong ba lớp Tam giác, Hình tròn, Tứ giác.
◼ Lớp cha 2DShape định nghĩa giao diện chung
◼ Các lớp con Tam giác, Vòng tròn, Tứ giác phải theo giao diện này (kế thừa),
nhưng cũng được phép cung cấp các triển khai riêng của chúng (ghi đè)
Object
→ Khi một phương thức được
yêu cầu thông qua tham chiếu
lớp 2DShape, các đối tượng
2DShape, Tam giác, Hình tròn và Shape .
Tứ giác phản ứng khác nhau
2D Shape 3D Shape
Circle Triangle Quadrilateral Sphere Polyhedron
23
3. Đa hình
◼ Ví dụ:
public class 2DShape { public class Point extends 2DShape {
public void display() { private int x, y;
System.out.println("2D Shape"); ...
} public void display(){
} System.out.print("(" + x + "," + y + ")");
}
}
public class Circle extends 2DShape{
public static final double PI =
public class Quadrilateral extends 2DShape {
3.14159;
private Point p1, p2, p3, p4;
private Point p;
private double r; //radious
.....
...
public void display(){
public void display(){
System.out.println("Quadrilateral: ");
System.out.print("Circle: " +
r + ","); p1.display(); p2.display();
p.display(); p3.display(); p4.display();
System.out.println(); System.out.println();
} }
} } 24
3. Đa hình
◼ Ví dụ: Có nhiều sự lựa chọn một khi một phương thức được
gọi thông qua một tham chiếu lớp cha.
Object of super
class Object of Circle class
display() Circle: 1, (0,0)
Object of Point class
Application
2DShape display() (0,1)
program display()
Object of Quadrilateral class
Quadrilateral:
display() (0,0), (0,1), (1,0), (1,1)
2D Shape
25
3. Đa hình
◼ Polymorphism: Nhiều hình thức thực hiện, nhiều
kiểu tồn tại
◼ Khả năng của một biến tham chiếu thay đổi hành vi theo
đối tượng mà nó đang giữ.
◼ Đa hình trong lập trình
◼ Đa hình phương thức:
◼ Phương thức trùng tên, phân biệt bởi danh sách tham số.
◼ Đa hình đối tượng
◼ Nhìn nhận đối tượng theo nhiều kiểu khác nhau
◼ Các đối tượng khác nhau cùng đáp ứng chung danh sách các
thông điệp có giải nghĩa thông điệp theo cách thức khác nhau.
26
3. Đa hình
◼ Polymorphism: gia tăng khả năng tái sử dụng
những đoạn mã nguồn được viết một cách tổng
quát và có thể thay đổi cách ứng xử một cách linh
hoạt tùy theo loại đối tượng
◼ Tính đa hình (Polymorphism) trong Java được hiểu là
trong từng trường hợp, hoàn cảnh khác nhau thì đối
tượng có hình thái khác nhau tùy thuộc vào từng ngữ
cảnh
◼ Để thể hiện tính đa hình:
◼ Các lớp phải có quan hệ kế thừa với 1 lớp cha nào đó
◼ Phương thức được ghi đè (override) ở lớp con
27
3. Đa hình Person
- name: String
- birthday: Date
◼
Ví dụ: + setName(String)
◼ Các đối tượng khác nhau giải nghĩa + setBirthday(Date)
các thông điệp theo các cách thức + getDetails(): String
khác nhau
◼ Liên kết động (Java) Employee
Person p1 = new Person(); - salary: double
Person p2 = new Employee(); + setSalary(double)
Person p3 = new Manager(); + getDetails(): String
// ...
System.out.println(p1.getDetail()); Manager
System.out.println(p2.getDetail()); - assistant: Employee
System.out.println(p3.getDetail()); + setAssistant(Employee)
+ getDetails():String
28
3. Đa hình Person
- name: String
- birthday: Date
◼
Ví dụ: + setName(String)
class EmployeeList {
Employee list[]; + setBirthday(Date)
... + getDetails(): String
public void add(Employee e) {...}
public void print() {
for (int i=0; i<list.length; i++) { Employee
System.out.println(list[i]. - salary: double
getDetail());
+ setSalary(double)
}
} + getDetails(): String
...
EmployeeList list = new EmployeeList(); Manager
Employee e1; Manager m1; - assistant: Employee
...
+ setAssistant(Employee)
list.add(e1);
list.add(m1); + getDetails():String
list.print(); 29
3. Đa hình
◼ Ví dụ: Các đối tượng Triangle, Rectangle, Circle đều là các
đối tượng Shape
...
public static void handleShapes(Shape[] shapes){
// Vẽ các hình theo cách riêng của mỗi hình
for( int i = 0; i < shapes.length; ++i) {
shapes[i].draw();
}
...
// Gọi đến phương thức xóa,
// không cần quan tâm đó là hình gì
for( int i = 0; i < shapes.length; ++i) {
shapes[i].erase();
}
}
...
30
Câu hỏi
◼ Cho
biểu đồ lớp:
Phương thức printLine() của lớp nào sẽ được sử dụng trong mỗi trường
hợp dưới đây, biết rằng z là một đối tượng của lớp F? Giải thích ngắn gọn?
1. z.printLine(1)
2. z.printLine(2, "Object-Oriented Programming")
3. z.printLine("Java")
4. z.printLine("Object-Oriented Programming", "Java")
31
5. z.printLine("Object-Oriented Programming", 3)
Câu hỏi
◼ Những điều kiện nào trả về true? (Có thể xem Java
documentation để biết các quan hệ thừa kế giữa các lớp)
Biết rằng System.out là một đối tượng của lớp PrintStream.
1. System.out instanceof PrintStream
2. System.out instanceof OutputStream
3. System.out instanceof LogStream
4. System.out instanceof Object
5. System.out instanceof String
6. System.out instanceof Writer
32
Tổng kết
33
Tổng kết
◼ Upcasting và downcasting
◼ Nhìn nhận các đối tượng thuộc lớp cơ sở như đối
tượng thuộc lớp dẫn xuất (upcasting) và ngược
lại (down-casting)
◼ Liên kết tĩnh và liên kết động
◼ Liên kết lời gọi hàm lúc biên dịch (liên kết tĩnh)
hay lúc chạy chương trình (liên kết động)
◼ Đa hình
◼ Nhìn nhận một đối tượng dưới nhiều kiểu khác
nhau
34
Bài tập
35
Bài tập 1
◼ Kiểm tra các đoạn mã sau đây và vẽ sơ đồ lớp
tương ứng
36
Bài tập 2
◼ Giải thích các đầu ra (hoặc các lỗi nếu có) cho
chương trình thử nghiệm sau:
37
Bài tập 3
◼ Phân tích xây dựng các lớp như mô tả sau:
◼ Hàng điện máy <mã hàng, tên hàng, nhà sản
xuất, giá, thời gian bảo hành, điện áp, công
suất>
◼ Hàng sành sứ < mã hàng, tên hàng, nhà sản
xuất, giá, loại nguyên liệu>
◼ Hàng thực phẩm <mã hàng, tên hàng, nhà sản
xuất, giá, ngày sản xuất, ngày hết hạn dùng>
◼ Viết chương trình tạo mỗi loại một mặt hàng
cụ thể. Xuất thông tin về các mặt hàng này.
38
PhongBan NhanVien
- tenPhongBan: String - tenNhanVien: String
1 1..*
- soNhanVien: int + LUONG_MAX: double
+ SO_NV_MAX: int + tinhLuong(): double
+ themNV(NhanVien): + inThongTin()
boolean
+ xoaNV(): NhanVien
NhanVienCoHuu NhanVienHopDong
+ tinhTongLuong(): double
- luongCoBan: double - luongHopDong: double
+ inThongTin()
- heSoLuong: double + tinhLuong(): double
Bài tập 4 + tinhLuong(): double + inThongTin()
+ tangHeSoLuong(double):
◼ Xây dựng các lớp như boolean
biểu đồ ở hình bên + inThongTin()
◼ Sửa lớp NhanVien
thành lớp CanBoCoHuu
◼ Cho lớp CanBoCoHuu TruongPhong
thừa kế lớp abstract - phuCap: double
NhanVien
- soNamDuongChuc: int
◼ Tính tổng lương của tất
cả nhân viên trong + tinhLuong(): double
39
+ inThongTin()
phòng ban
41File đính kèm:
bai_giang_lap_trinh_huong_doi_tuong_bai_8_da_hinh_tiep_theo.pdf

