Lap trinh HDT Java, Object-Oriented Programming in Java

239

Click here to load reader

Transcript of Lap trinh HDT Java, Object-Oriented Programming in Java

Page 1: Lap trinh HDT Java, Object-Oriented Programming in Java

KHOA CỌNG NGH THỌNG TIN & TRUY N THỌNG

L P TRÌNH H NG Đ I T NG

JAVA

Biên so n: Vũ Duy Linh

CTU - 2015

Object Oriented Progamming in Java

TR NG Đ I H C C N TH

KHOA CỌNG NGH THỌNG TIN & TRUY N THỌNG

Page 2: Lap trinh HDT Java, Object-Oriented Programming in Java
Page 3: Lap trinh HDT Java, Object-Oriented Programming in Java

L i nói đ u

Giáo trình L p trình h ng đ i t ng Java được biên soạn nh m phục vụ cho ngư i học, nhất là cho sinh viên ngành Công nghệ thông tin, có được một tài liệu học tập chính th c và hiệu quả trong môi trư ng đào tạo, giảng dạy bậc đại học c a trư ng Đại học Cần Thơ.

Học phần được phân bố với số lượng là 03 tín chỉ, dành cho những đối tượng ngư i học mà đa phần chỉ mới tiếp cận được với ngôn ngữ lập trình căn bản C. Do vậy, việc cấu trúc và s p xếp kiến th c trong các chương cho giáo trình cũng được xem xét cẩn thận. Sau nhiều năm học phần này được giảng dạy, với th i lượng 02 tín chỉ lý thuyết và 01 tín chỉ thực hành, giáo trình đã xác định được cấu trúc hợp lý và chặt chẽ với kỳ vọng hướng ngư i học, từ mới b t đầu cũng như đã biết ngôn ngữ Java, đều có thể tiếp thu và đạt được mục tiêu c a học phần hướng đối tượng này. Trong đó, phần đầu giáo trình được đề cập đến những kiến th c cơ bản c a ngôn ngữ Java, sau đó sẽ được đưa từng phần kiến th c về đối tượng cũng như hướng đối tượng vào những phần tiếp theo, và cuối cùng là các kiến th c lập trình về giao diện ngư i dùng cũng như về cơ s dữ liệu. Như vậy, mục tiêu c a học phần này là ngư i học sẽ được trang bị đầy đ về các kiến th c như lập trình có cấu trúc, phân tích và thiết kế mô hình đối tượng cũng như hướng đối tượng, để từ đó có thể cài đặt chúng b ng ngôn ngữ Java, và quan trọng nhất là ngư i học có thể đọc hiểu được các sơ đồ c a những frameworks đã và đang phát triển rất mạnh gần đây c a những công nghệ như: Java, .Net hoặc .PHP,…

Giáo trình bao gồm 12 chương, mỗi chương đều có ví dụ minh họa với mã nguồn chạy trên môi trư ng Java SE 5 tr lên và các bài tập yêu cầu, nh m giúp sinh viên có các bài thực hành trong phòng máy và tự rèn luyện thêm nhà. Số ví dụ và bài tập này được đề cập từ đơn giản đến nâng cao mà đích đến là các bài tập lớn theo dạng case study cho các chương chính c a lập trình hướng đối tượng, điều hữu ích cần được trải nghiệm b i sinh viên học học phần này.

Với mong muốn có một tài liệu hữu ích cho sinh viên học tập và để tham khảo cho cộng đồng Java vùng đồng b ng Sông Cửu Long cũng như Việt Nam, giáo trình đã được biên soạn dựa vào kiến th c và các ví dụ minh họa từ nhiều nguồn trong và ngoài nước, cũng như từ những kinh nghiệm giảng dạy c a bản thân ngư i viết. Tuy nhiên, sự hiểu biết là hữu hạn nên những thiếu sót ch c hẳn sẽ khó tránh khỏi. Giáo trình rất mong nhận được sự chia xẻ và góp ý c a ngư i đọc cũng như c a sinh viên qua địa chỉ email: [email protected], để hoàn thiện và phục vụ cho việc học và giảng dạy tốt hơn.

Ngư i biên soạn,

Vũ Duy Linh

Page 4: Lap trinh HDT Java, Object-Oriented Programming in Java
Page 5: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java i

M C L C

Ch ng 1. Tổng quan v ngôn ngữ l p trình Java ..................................................... 1

1.1 Giới thiệu ............................................................................................................... 1

1.1.1 Môi trư ng phát triển ng dụng Java ............................................................. 1

1.1.2 Cài đặt môi trư ng phát triển ng dụng Java ................................................. 3

1.2 Những đặc tính và phạm vi ng dụng c a Java ..................................................... 5

1.2.1 Đặc tính Java .................................................................................................. 5

1.2.2 Phạm vi ng dụng Java ................................................................................... 6

Bài tập chương 1 .......................................................................................................... 6

Ch ng 2. L p trình Java c bản ................................................................................ 7

2.1 Cấu trúc chương trình Java đơn giản ..................................................................... 7

2.2 Các thành phần cơ bản ........................................................................................... 8

2.2.1 Từ khóa ........................................................................................................... 8

2.2.2 Kiểu dữ liệu nguyên th y ............................................................................... 9

2.2.3 Danh hiệu tự đặt ............................................................................................. 9

2.2.4 Biến ................................................................................................................. 9

2.2.5 Biến h ng ...................................................................................................... 11

2.2.6 Chú thích ...................................................................................................... 11

2.3 Các cấu trúc kiểm soát dòng lệnh ........................................................................ 11

2.3.1 Lệnh rẽ nhánh if ............................................................................................ 11

2.3.2 Lệnh rẽ nhánh switch .................................................................................... 13

2.3.2 Lệnh lặp có số lần xác định trước................................................................. 14

2.3.2.1 Dạng 1: for ..................................................................................................................... 14

2.3.2.2 Dạng 2: for-each ............................................................................................................ 14

2.3.2 Lệnh lặp có số lần chưa xác định trước ........................................................ 15

2.3.2.1 Dạng 1: while .. do ......................................................................................................... 15

2.3.2.2 Dạng 2: do .. while ......................................................................................................... 15

2.4 Phương th c tự định nghĩa ................................................................................. 16

2.4.1 Định nghĩa phương th c ............................................................................... 16

2.4.2 L i gọi phương th c ..................................................................................... 17

Bài tập chương 2 ........................................................................................................ 20

Page 6: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java ii

Ch ng 3. Khái ni m v l p trình h ng đ i t ng ................................................ 21

3.1 Giới thiệu ............................................................................................................. 21

3.1.1 Đối tượng...................................................................................................... 22

3.1.2 Lớp ............................................................................................................... 23

3.2 Các giai đoạn phát triển hệ thống hướng đối tượng ............................................ 24

3.2.1 Phân tích hệ thống hướng đối tượng ............................................................ 25

3.2.2 Thiết kế hệ thống .......................................................................................... 25

3.2.3 Thiết kế đối tượng ........................................................................................ 26

3.2.3.1 Trừu tượng hóa ............................................................................................................. 26

3.2.3.2 Thừa kế .......................................................................................................................... 28

3.2.4 Giai đoạn cài đặt ........................................................................................... 28

3.3 Quá trình phát triển chương trình hướng đối tượng ............................................ 31

3.4 Các đặc tính c a lập hướng đối tượng Java ........................................................ 33

3.4.1 Tính trừu tượng ............................................................................................ 33

3.4.2 Tính bao đóng ............................................................................................. 33

3.4.3 Tính thừa kế ................................................................................................ 34

3.4.4 Tính đa hình ................................................................................................. 34

3.4.5 Tính bền vững .............................................................................................. 35

Bài tập chương 3 ....................................................................................................... 36

Ch ng 4. L p, đ i t ng, truy n thông đi p và gói ............................................... 37

4.1 Lớp ...................................................................................................................... 37

4.1.1 Khái niệm ..................................................................................................... 37

4.1.2 Lớp tự định nghĩa ......................................................................................... 37

4.1.2.1 Cú pháp khai báo tổng quát .......................................................................................... 38

4.1.2.2 Kiểm soát truy cập đến các thành viên của lớp ............................................................. 39

4.1.2.3 Lớp tận cùng .............................................................................................. 40

4.2 Đối tượng ............................................................................................................. 40

4.2.1 Khái niệm ..................................................................................................... 40

4.2.2 Tạo đối tượng ............................................................................................... 40

4.3 Thành viên thể hiện và thành viên lớp ................................................................ 43

4.3.1 Thành viên thể hiện ...................................................................................... 43

4.3.2 Thành viên lớp .............................................................................................. 43

4.4 Phương th c dựng .............................................................................................. 45

4.5 Phương th c ghi và đọc ....................................................................................... 46

Page 7: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java iii

4.6 Phương th c h y ................................................................................................ 48

4.7 Truyền tham số .................................................................................................... 50

4.8 Truyền thông điệp giữa các đối tượng ................................................................. 57

4.9 Gói ..................................................................................................................... 62

Bài tập chương 4 ........................................................................................................ 65

Ch ng 5. Mảng chuẩn, l p Arrays và khung n n t p h p Java ........................... 67

5.1 Mảng chuẩn ......................................................................................................... 67

5.1.2 Mảng một chiều ............................................................................................ 67

5.1.3 Mảng nhiều chiều ......................................................................................... 69

5.1.4 Truyền tham số b ng mảng .......................................................................... 71

5.1.5 Lớp mảng Arrays .......................................................................................... 72

5.2 Khung nền tập hợp Java ...................................................................................... 73

5.2.1 Giới thiệu ...................................................................................................... 73

5.2.2 Danh sách mảng ........................................................................................... 74

5.2.3 Tập HashMap ............................................................................................... 76

5.2.4 LinkedHashMap và LinkedHashSet ............................................................. 78

Bài tập chương 5 ........................................................................................................ 80

Ch ng 6. L p bao gói kiểu nguyên thủy, và các l p chuỗi ký tự.......................... 81

6. 1 Lớp bao kiểu nguyên th y .................................................................................. 81

6.2 Lớp chuỗi ký tự String ......................................................................................... 83

6.2.1 Khai báo và kh i tạo ..................................................................................... 83

6.2.2 Truyền tham số b ng chuỗi String ............................................................... 84

6.3 Chuỗi StringBuffer .............................................................................................. 86

6. 4 Lớp StringTokenizer ........................................................................................... 87

Bài tập chương 6 ........................................................................................................ 88

Ch ng 7. Bao đóng, m i k t h p và thừa k ........................................................... 89

7. 1 Tính bao đóng ..................................................................................................... 89

7.2 Các mối kết hợp ................................................................................................... 90

7.2.1 Mối kết hợp phụ thuộc.................................................................................. 92

7.3.2 Mối kết hợp .................................................................................................. 94

7.3.2.1 Mối kết hợp có hướng/một chiều ................................................................................. 94

7.3.2.2 Mối kết hợp hai chiều ................................................................................................... 95

7.3.3 Mối kết hợp hạn định.................................................................................. 101

Page 8: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java iv

7.3.4 Lớp liên kết ................................................................................................ 102

7.3.5 Kết tập chặt ................................................................................................. 102

7.3.6 Kết tập lỏng ................................................................................................ 104

7.3.8 Mối kết hợp thực thi ................................................................................... 105

7.3 Thừa kế .............................................................................................................. 108

7.3.1 Các cơ chế trừu tượng ................................................................................ 108

7.3.1.1 Cơ chế phân lớp ........................................................................................................... 108

7.3.1.2 Tổng quát hóa .............................................................................................................. 109

7.3.1.3 Chuyên biệt hóa ........................................................................................................... 109

7.3.2 Phương pháp thiết kế .................................................................................. 110

Bài tập chương 7 ..................................................................................................... 117

Ch ng 8. Đa hình .................................................................................................... 125

8.1 Khái niệm đa hình ............................................................................................. 125

8.2 Đa hình tĩnh ....................................................................................................... 126

8.3 Chuyển đổi (ép) kiểu ......................................................................................... 127

8.4 Đa hình động ..................................................................................................... 131

Bài tập chương 8 ..................................................................................................... 137

Ch ng 9. L p trừu t ng và giao di n ................................................................. 139

9.1 Khái nhiệm về lớp trừu tượng ........................................................................... 139

9.2 Cách khai báo lớp trừu tượng ............................................................................ 139

9.3 Khái niệm giao diện .......................................................................................... 146

9.3.1 Cú pháp khai báo ........................................................................................ 147

9.3.2 Sự cài đặt giao diện .................................................................................... 147

9.3.3 Thừa kế bội b ng giao diện ........................................................................ 153

Bài tập chương 9 ..................................................................................................... 172

Ch ng 10. Ngo i l và xử lý ngo i l ..................................................................... 175

10.1 Giới thiệu ......................................................................................................... 175

10.2 Ngoại lệ ......................................................................................................... 176

10.2.1 Lớp chuẩn ngoại lệ Error.......................................................................... 177

10.2.2 Lớp chuẩn Exception ............................................................................. 178

10.3 Xử lý ngoại lệ ................................................................................................ 180

10.3.1 Thẩy ngoại lệ ............................................................................................ 180

10.3.2 Xử lý ngoại lệ ........................................................................................... 181

10.3.2.1 Câu lệnh try .. catch .. finally ..................................................................................... 181

Page 9: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java v

10.3.2.2 Lan truyền ngoại lệ .................................................................................................... 184

10.3.2 Câu lệnh kiểm ch ng biểu th c ................................................................ 185

Bài tập chương 10 .................................................................................................... 190

Ch ng 11. Luồng và t p tin .................................................................................... 191

11.1 Tập tin ............................................................................................................ 191

11.2 Luồng ............................................................................................................... 195

11.2.1 Khái niệm ................................................................................................. 195

11.2.2 Các luồng xuất nhập chuẩn (Stream I/O in Standard I/O) ..................... 196

Bài tập chương 11 .................................................................................................... 205

Ch ng 12. Giao di n ng i dùng và k t n i c sở dữ li u ................................ 207

12.1 Lập trình giao diện Java với SWT ................................................................... 207

12.2 Lập trình giao diện Java với Swing ................................................................. 211

12.3 Kết nối cơ s dữ liệu........................................................................................ 216

Bài tập chương 12 .................................................................................................... 228

Tài li u tham khảo ..................................................................................................... 229

Page 10: Lap trinh HDT Java, Object-Oriented Programming in Java
Page 11: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 1

Ch ng 1. Tổng quan v ngôn ngữ l p trình Java

Chương này sẽ cung cấp cho ngư i học các kiến th c cần thiết về môi trư ng, công nghệ và các lĩnh vực ng dụng c a Java. Giúp cho ngư i mới học đ thông tin để b t tay vào việc lập trình trên môi trư ng Java, đồng th i, có cái nhìn tổng thể về công nghệ Java đã và đang phát triển và được ng dụng trên thế giới.

1.1 Gi i thi u

Java là ngôn ngữ lập trình máy tính cấp cao được sử dụng rộng rãi nhất hiện nay trên thế giới. Nó được phát triển b i hãng Sun Microsystems vào năm 1991, và phiên bản đầu tiên gọi là Oak do James Gosling phát triển, đến năm 1995 tên chính th c được gọi là Java. Các nhà phát triển Java đầu tiên được kể đến là: James, Arthur Van, Karl Jacob cũng như các nhân vật nổi bật khác. Phương pháp lập trình hướng đối được Java hỗ trợ mạnh và lập trình viên được cung cấp một thư viện rất phong phú và đồ sộ để có thể triển khai các dự án nhiều cấp độ khác nhau. Ngôn ngữ Java thư ng được ưu tiên chọn lựa để phát triển các ng dụng tầm doanh nghiệp.

Trong các lãnh vực IT hiện nay, ngôn ngữ Java có thể phát triển được hầu hết các loại ng dụng mà điển hình có thể kể ra là: lập trình ng dụng nền web, lập trình di động, lập

trình trò chơi, lập trình mạng, phân tán và lập trình trên công nghệ đám mây (Cloud).

1.1.1 Môi tr ng phát triển ứng d ng Java

Hình 1.1: Java SE Platform

Page 12: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 2

th i điểm hiện nay, phiên bản Java SE 8 (Java platform standard edition) đang được sử dụng rộng rãi. Nó bao gồm bộ công cụ phát triển JDK 8 (Java SE Development Kit) và môi trư ng thực thi JRE 8 (Java SE Runtime Environment) như hình 1.1.

Hình 1.2: Môi trường phát triển và thực thi chương trình

Môi trư ng JRE cung cấp các lớp thư viện API (Application Programming Interface) và máy tính ảo Java (Java Virtual Machine). Máy tính ảo là công cụ thực thi mã (Java bytecode) trong tập tin .class dựa vào cách thông dịch (interpreter).

Hình 1.3: Kiến trúc mã trung gian c a Java

Như vậy, môi trư ng phát triển và thực thi Java được bộ JDK thực hiện qua hai giai đoạn: Biên dịch và thông dịch. Dựa vào các lệnh như java, javac mà mã nguồn Java được biên dịch thành các tập tin bytecode. Tiếp đến chúng được chuyển vào máy tính

Page 13: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 3

ảo Java để thông dịch thành mã máy (machine code) tương ng cho mỗi hệ điều hành mà JVM được cài vào đó như hình 1.2.

Do vậy, khác với ngôn ngữ C/C++ hoặc Delphi, Java sử dụng kiến trúc độc lập với mọi hệ điều hành (architecture independent) dựa trên mã trung gian (chính là tập tin byte code) để tạo nên một cuộc cách mạng mới cho lập trình: Viết một lần, chạy mọi nơi – write one, run anywhere như hình 1.3.

1.1.2 CƠi đặt môi tr ng phát triển ứng d ng Java

Trước hết, chúng ta download bộ JDK được hỗ trợ miễn phí cho nhiều hệ điều hành như Windows, Linux, Mac OS,… Chúng ta có thể lên địa chỉ website: http://www.oracle.com/technetwork/java/javase/downloads/index.html để tải về và cài đặt vào hệ thống máy tính. Sau khi cài đặt xong, cần thiết lập biến môi trư ng để Java có thể biên dịch và thực thi từ bất kỳ nơi nào trên hệ điều hành hỗ trợ nó.

Tiếp theo, chúng ta cũng cần tải và cài đặt các phần mềm hỗ trợ soạn thảo mã nguồn. giai đoạn mới học tập, ngư i học có thể sử dụng các trình soạn thảo văn bản đơn giản

như: NotePad++, jEdit, EditPlus, KompoZer,… hoặc các phần mềm có hỗ trợ môi trư ng phát triển tích hợp (Integrated Development Environment) như: NetBeans IDE, Eclipse IDE, JCreator IDE,... để soạn thảo các ng dụng đơn giản cũng như phát triển các ng dụng dựa trên các khung làm việc (Frameworks) phải cấu hình ph c tạp. Một số links hữu ích cho các phần mềm này như: https://netbeans.org/, http://www.eclipse.org/, http://www.jcreator.com/,...

Một số lệnh chế độ command line sau khi đã cài đặt JDK:

javac: Trình biên dịch java

java : Chạy ng dụng độc lập

jdb : Gỡ rối (Java Debugger)

appletviewer : Chạy ng dụng applets

javap: Để in mã trung gian Java (bytecodes)

javah: Tạo ra header files cho ngôn ngữ C.

Ví d 1.1: Sử dụng trình soản thảo như NotePad++, EditPlus, hoặc Wordpad rồi nhập vào mã lệnh java (source code) như chương trình đơn giản sau:

//Filename: HelloJavaApp.java

public class HelloJavaApp {

public static void main(String[] args) {

System.out.println("Hello! This is a Java application...");

}

}

Biên dịch mã nguồn: javac HelloJavaApp.java ↲ (Tạo file: HelloJavaApp.class)

Thực thi chương trình: java HelloJavaApp

Page 14: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 4

Kết quả chạy chương trình: Hello! This is a Java application…

Ví d 1.2: Viết ng dụng Java b ng Netbean IDE

Hình 1.4: Cấu trúc dự án đơn giản trên Netbean IDE

Ví d 1.3: Viết chương trình tính cộng 2 số a và b, với a, b là 2 số bất kỳ được nhập từ bàn phím theo cách nhập từ đối số dòng lệnh (command line)

package ctu.vdlinh.chapter1;

/**

* @author Vũ Duy Linh

*/

public class Cong {

public static void main(String[] args) {

double a, b;

a = Double.parseDouble(args[0]);

b = Double.parseDouble(args[1]);

System.out.printf("a + b= %.2f\n", a+b);

}

}

* Từ dấu nh c lệnh c a MS-DOS hoặc Linux gõ lệnh:

java ctu.vdlinh.chapter1 Cong 5.5 12.7 ↲

* Từ Netbean IDE 7.4: Vào ch c năng Run/Set Project Configuration/Customize... để thiết lập các đối số:

Page 15: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 5

Hình 1.5: Xác định giá trị cho các đối số c a phương th c main trong Netbean

* Từ Eclipse Mars IDE : Vào ch c năng Run/Run Configurations... để thiết lập các đối số đầu vào c a chương trình:

Hình 1.6: Xác định giá trị cho các đối số c a phương th c main trong Eclipse

1.2 Những đặc tính và ph m vi ứng d ng của Java

1.2.1 Đặc tính Java

Java là ngôn ngữ bậc cao, có tính thân thiện, đơn giản và dễ sử dụng. Java là ngôn ngữ kh i sướng việc sử dụng kiến trúc mã trung gian nên nó cần được biên dịch (compiled) và thông dịch (interpreted) để chạy chương trình. Bên cạnh đó, ngôn ngữ Java có có tính định kiểu mạnh, tư ng minh và hướng đối tượng.

Điểm nổi bật nhất là Java có tính bảo mật (secure) cao và an toàn hơn các ngôn ngữ khác do được kiểm tra an toàn trước từng bước (ngôn ngữ biên dịch thực thi: tính đóng gói .java .class class loader machine code) nên từ bên ngoài khó có thể xâm nhập vào chương trình được.

Page 16: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 6

Đặc tính quan trọng nữa là Java có tính khả chuyển cao vì JVM dựa trên nền tảng chính POSIX (Portable Operating System Interface [for Unix]) – Giao diện hệ điều hành linh động: Cung cấp mã nguồn di động cho các thiết bị đầu cuối, ngoại vi. Nó cung cấp khả năng lập trình phân tán (distribution): Hỗ trợ TCP, UDP, Socket và Network communication: Applets, servlets, aglets – hệ thống mobile agents, remote method invocation (RMI), Common Object Request Broker Architecture (CORBA),…

1.2.2 Ph m vi ứng d ng Java

Java là nền tảng cho hầu như mọi loại ng dụng mạng và là tiêu chuẩn toàn cầu cho việc phát triển và cung cấp các ng dụng nhúng và di động, trò chơi, ng dụng web, và phần mềm doanh nghiệp. Với hơn 9 triệu nhà phát triển trên toàn thế giới, Java cho phép bạn để phát triển và triển khai các ng dụng, các dịch vụ một cách hiệu quả.

Hiện nay, có thể nói, phạm vi ng dụng c a ngôn ngữ và công nghệ Java có mặt kh p mọi nơi: Từ máy tính xách tay đến trung tâm dữ liệu, từ ng dụng Console cho đến siêu máy tính khoa học, từ điện thoại di động đến ng dụng Internet. Dưới đây là các thông tin về ng dụng c a công nghệ Java theo http://www.java.com/en/about/

97% of Enterprise Desktops Run Java 89% of Desktops (or Computers) in the U.S. Run Java 9 Million Java Developers Worldwide #1 Choice for Developers #1 Development Platform 3 Billion Mobile Phones Run Java 100% of Blu-ray Disc Players Ship with Java 5 Billion Java Cards in Use 125 million TV devices run Java 5 of the Top 5 Original Equipment Manufacturers Ship Java ME

Bài t p ch ng 1

Bài 1.1: Sử dụng trình soạn thảo tùy ý, viết chương trình hiển thị câu ca dao:

“Công cha như núi Thái Sơn, Nghĩa mẹ như nước trong nguồn chảy ra.

Một lòng thờ mẹ kính cha,

Cho tròn chữ hiếu mới là đạo con!”

Bài 1.2: Sử dụng Netbean IDE, Eclipse IDE, JCreator IDE hoặc trình soạn thảo văn bản tùy ý để viết chương trình hiển thị kết quả phép nhân hai số nguyên được nhập từ dòng lệnh command line.

Page 17: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 7

Ch ng 2. L p trình Java c bản

Chương này sẽ trình bày các kiến th c c a ngôn ngữ lập trình Java căn bản để giúp cho ngư i học, học môn L p trình h ng đ i t ng Java, được dễ dàng hơn. Tuy nhiên, giáo trình chỉ trình bày ng n gọn các kiến th c Java cơ bản vì ngư i học đã được học phần L p trình căn bản như C. Các kiến th c bao gồm cấu trúc một chương trình Java cơ bản, các từ khóa, các kiểu dữ liệu cơ bản/nguyên th y, câu lệnh có cấu trúc rẽ nhánh và lặp, phân biệt sự khác biệt giữa dạng hàm và th tục c a phương th c,…

Có thể nói, m c độ lập trình căn bản, ngôn ngữ lập trình C và Java giống nhau nên ngư i học cần dành th i gian để tự rèn luyện phần Java căn bản này thông qua các kiến th c đã được học ngôn ngữ C. Trong học phần này, giáo trình cũng dành hơn một phần sáu th i lượng thực hành để sinh viên được hướng dẫn từ giảng viên.

2.1 C u trúc ch ng trình Java đ n giản

Cấu trúc chương trình Java dạng aplication cần có ít nhất một lớp chính (main class). Lớp chính là lớp mà có ch a phương th c main. Khái niệm về lớp và đối tượng sẽ được trình bày chi tiết trong phương pháp lập trình hướng đối tượng (HĐT) các phần sau. Cấu trúc cơ bản c a một chương chương trình Java có dạng như hình 2.1.

Hình 2.1: Cấu trúc chương trình Java cơ bản

Ví d 2.1: Minh họa cấu trúc chương trình đơn giản c a ngôn ngữ Java với chỉ một lớp chính (main class).

Các câu lệnh ví dụ trên được giải thích như sau: Dòng (1): Tạo các gói (package) là ctu.vdlinh.simple

Dòng (3) đến (8): Phần mô tả chương trình. Đây là phong cách lập trình chuyên nghiệp mà lập trình viên cần lưu ý khi viết và chuyển giao dự án.

Dòng (9): Nạp thư viện cần thiết cho chương trình.

Page 18: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 8

Dòng (11) đến (15) là lớp chính, FirstSample. Lớp chính là lớp có ch a phương th c

main trong nó. Khi là lớp chính, nó phải được lưu tên tập tin (file name) trùng với tên lớp, FirstSample.java.

Từ khóa public sẽ chỉ ra lớp hoặc phương th c đó được truy cập mọi nơi c a dự án. Từ khóa static c a phương th c main được gọi là phương th c lớp, và phương th c này có thể được gọi mà không cần phải kh i tạo đối tượng c a lớp ch a nó (phương th c static chỉ được phép truy xuất tới các biến static c a lớp do đã được fix sẵn trong bộ nhớ). Còn từ khóa void xác định đây là một phương th c dạng th tục: không trả về (return;) giá trị nào cả khi phương th c thực hiện xong.

2.2 Các thành ph n c bản

2.2.1 Từ khóa

Từ khóa (keywords) là các từ dành riêng cho ngôn ngữ Java, nó có ý nghĩa và ch c năng đã được xác định, và không được dùng nó vào các việc khác hoặc đặt tên danh hiệu trùng với các từ khóa này.

Dưới đây là danh sách một số từ khóa thông dụng c a ngôn ngữ Java:

abstract default if private this

assert do implements protected throw

boolean double import public throws

break else instanceof return transient

byte enum int short try

case extends interface static void

catch final long strictfp volatile

char finally native super while

class float new switch

continue for package synchronized

Page 19: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 9

2.2.2 Kiểu dữ li u nguyên thủy

Kiểu nguyên thuỷ (primitive data type): Còn được gọi là kiểu căn bản, đó là kiểu mà các phép toán được dịch trực tiếp sang các lệnh c a máy (operational data).

Vì Java là một ngôn ngữ định kiểu mạnh nên khi khai báo biến, h ng, chúng ta cần xác định cho chúng một kiểu dữ liệu nhất định.

Kiểu Kích th c

Khoảng giá tr

boolean 8 bit true hoặc false

byte 8 bit -128 đến 127

short 16 bit -32,768 đến 32,767

int 32 bit -2,147,483,648 đến +2,147,483,647

long 64 bit -9,223,372,036,854,775,808 +9,223,372,036,854,775,807

char 16 bit \u0000 đến \uFFFF (chuẩn unicode)

float 32 bit -3.40292347E+38 +3.40292347E+38

double 64 bit -1.7976931348623157E+308 +1.7976931348623157E+308

2.2.3 Danh hi u tự đặt

Quy t c đặt tên danh hiệu (identifier): B t đầu b ng một chữ cái, một dấu gạch dưới, hoặc một dấu dollard ($), không có khoảng tr ng, không trùng với các từ khoá và có phân biệt chữ hoa chữ thư ng. Trong lập trình, các danh hiệu được sử dụng phổ biến cho đặt tên biến, h ng, tên kiểu/lớp ngư i dùng.

Ví d 2.2: Đặt tên cho biến, h ng, tên phương th c… theo quy ước camel-case

Danh hiệu tự đặt hợp lệ: myList1, x1, tinhDelta…

Danh hiệu không hợp lệ: my List1, 1x, tinh-Delta,…

Ví d 2.3: Đặt tên lớp ngư i dùng theo quy ước proper-case

Đúng style: SinhVien, GiangVien, DBConnection,… //chuyên nghiệp

Sai style: sinhvien, giangVien, DBconnection,… //không nên sử dụng

2.2.4 Bi n

Biến (variable): Theo định nghĩa c a Khoa học máy tính, biến gồm một số ô nhớ được định danh duy nhất b i một danh hiệu. Chúng ta sử dụng biến để ch a một giá trị nào đó thuộc một kiểu dữ liệu xác định trước, và giá trị c a nó có thể thay đổi trong quá trình thực thi chương trình.

Cách 1: Khai báo và kh i tạo riêng biệt

kiểu_nguyên_thuỷ tên_Biến;

Page 20: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 10

tên_Biến = giá_trị; Cách 2: Khai báo và kh i tạo đồng th i

kiểu_nguyên_thuỷ tên_Biến = giá_trị; Mỗi biến được khai báo chỉ tồn tại trong phạm vi (scope) c a nó – tương tự như ngôn

ngữ C đã học.

Cần chú ý việc chuyển kiểu để tương thích với nhau, như minh họa th tự gán hợp lệ: double float long int short, char byte.

Ví d 2.4: Khai báo và kh i tạo đúng cho các biến

Boolean kiemTra = true; byte b = 100; short s = -100; int tich = 1;

int decVal = 26; int octVal = 032; int hexVal = 0x1a;

float diemTrB = 9.5f; double dienTich = 7278.25;

char capitalC = 'C'; char unicodeC='\u1EE9'; // Java sử dụng UTF-16

String uniGreeting="Ch\u00e0o b\u00e9: V\u0169\u0020Duy\u0020Th\u1EE9c!"

Hình 2.2: Hiển thị chuỗi ký tự unicode

Việc cấp pháp bộ nhớ cho các biến kiểu nguyên th y được quản lý b i Stack trong JVM nên mỗi biến đều được cấp phát một địa chỉ riêng biệt như sau:

Hình 2.3: Sơ đồ cấp phát bộ nhớ cho kiểu nguyên th y

Page 21: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 11

2.2.5 Bi n hằng

H ng (constant) cũng tương tự như biến ngoại trừ nó giữ một giá trị cố định (hay được gọi là các biến chỉ đọc). Trong Java, chúng được khai báo b i từ khóa final và quy định viết in hoa (upper-case), chẳng hạn như:

final int SI_SO = 40; final double PI = 3.1428;

Ví d 2.5: Viết chương trình với một lớp chính để nhập bán kính r c a hình tròn, tính diện tích và hiển thị các thông tin c a nó lên màn hình b ng Eclipse IDE:

/**

* Filename: HinhTron.java

*/

package ctu.vdlinh.chapter2;

public class HinhTron {

public static void main(String[] args) {

final double PI = 3.1428; // hằng PI

double bk = 5.5; // biến bán kính

double dt; // biến diện tích

dt = PI * bk * bk;

System.out.println("Bán kính= " + bk + ", diện tích= " + dt);

}

}

2.2.6 Chú thích

Java cung cấp 03 kiểu ghi chú thích (comments) khác nhau:

Cặp dấu /* */ được sử dụng cho chú thích có nhiều hàng

Cặp dấu xổ trái // được sử dụng cho chú thích đơn hàng

Cặp dấu /** */ được sử dụng để tạo tài liệu

Sử dụng Javadoc để tạo tập tin hướng dẫn dạng .html cho cácchú thích trong cặp dấu /** và */

2.3 Các c u trúc kiểm soát dòng l nh

2.3.1 L nh rẽ nhánh if

Trong Java có 3 dạng câu lệnh if

Dạng 1: if

if (booleanExpression) { statement(s); //Khối lệnh với điều kiện true }

Page 22: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 12

Dạng 2: if .. else

if (booleanExpression) { true-statement(s); //Khối lệnh với điều kiện true } else { false-statement(s); //Khối lệnh với điều kiện false }

Ví d 2.6: Chương trình minh họa sử dụng lệnh if .. else

//File name: LenhIfElse.java

package edu.vdlinh.chapter2;

public class LenhIfElse {

public static void main(String[] args) {

double markIELTS = 7.0;

if (markIELTS >= 6.5) {

System.out.println("Chúc mừng bạn!");

System.out.println("Bạn thật giỏi Anh văn!" ;

} else {

System.out.println("Hãy luyện tập và thử lại!");

}

}

}

Một toán tử điều kiện (conditional operator) có ch c năng tương tự như lệnh if .. else trên là dạng booleanExpr ? trueExpr : falseExpr;

Ví d 2.6: Minh họa toán tử điều kiện để tìm giá trị nhỏ hơn c a hai số nguyên.

int a =10, b =17;

int min = (a < b) ? a : b;

D ng 3: if .. elseif .. elseif .. else (nested-if)

if (booleanExpr_1) {

block_1; //Khối lệnh 1

} else if (booleanExpr_2){

block_2 ; //Khối lệnh 2

} else if ( booleanExpr_3 ) {

... // Khối lệnh tiếp theo

} else {

Page 23: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 13

block_else ; // Khối lệnh cuối cho else }

Ví d 2.7: Minh họa lệnh sử dụng nested-if cho 5 trư ng hợp phân biệt nhau

if (diemThi >= 8.5)

System.out.println("A");

else if (diemThi >= 7.5)

System.out.println("B");

else if (diemThi >= 6.5)

System.out.println("C");

else if (diemThi >= 4.0)

System.out.println("D");

else System.out.println("F");

2.3.2 L nh rẽ nhánh switch

switch (evaluatedExpression) { case constantExpr_1: block_1;

break;

case constantExpr_2: block_2;

break;

case constantExpr_n: block_n;

break;

default: default_block; }

Chú ý: Khác với lệnh if trên, biểu th c chọn lựa evaluatedExpression để rẽ nhánh trong lệnh switch có kiểu r i rạc như: int, char, hoặc enum.

Ví d 2.8: Minh họa sử dụng câu lệnh rẽ nhánh switch với kiểu liêt kê (enum)

//File name: JavaEnumSwitchCase.java

package ctu.vdlinh.chapter2;

public class JavaEnumSwitchCase{

enum ThucUong {

Page 24: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 14

Coffee, LaVie, Camvat

}

public static void main(String[] args) {

ThucUong chon = ThucUong.Coffee;

switch (chon) {

case Coffee:

System.out.println("Bạn chọn uống cafe. ");

break;

case LaVie:

System.out.println("Bạn chọn nước suối Lavie.");

break;

case Camvat:

System.out.println("Bạn chọn uống nước cam vắt.");

break;

}

}

}

2.3.2 L nh lặp có s l n xác đ nh tr c

2.3.2.1 Dạng 1: for

for ( initialization; booleanExpression; step ){ statement(s);

}

Trong đó: initialization để kh i tạo giá trị ban đầu c a biến chạy; boolean-expression: là điều kiện dừng, step: bước nhảy tăng hoặc giảm.

Ví d 2.9: Đoạn mã minh họa lệnh lặp với biến chạy i có giá trị đầu (kh i tạo) là 1 và giá trị cuối là 9 với bước nhảy là 2 rồi hiển thị nó.

for (int i = 1; i < 10; i+=2) {

System.out.print(i +"\t");

}

Kết quả của câu lệnh for là: 1 3 5 7 9

2.3.2.2 Dạng 2: for-each

for ( datatype variable: array | collection ){ statement(s);

}

Page 25: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 15

Câu lệnh for-each được sử dụng rất phổ biến trong lập trình kiểu đối tượng như ngôn ngữ Java. Trong hầu hết các mã lệnh, lập trình viên đều sử dụng collection để quản lý các đối tượng cho hiệu quả và tối ưu.

Ví d 2.10: Minh họa sử dụng câu lệnh for-each trên kiểu enum

//File name: JavaEnumSwitchCaseExample.java

package ctu.vdlinh.chapter2;

public class JavaEnumSwitchCaseExample {

enum WeekDay {

Sun, Mon, Tue, Wed, Thu, Fri, Sat

}

public static void main(String[] args) {

System.out.print("Days of week: ");

for (WeekDay day : WeekDay.values()) {

System.out.print(day + ", ");

}

}

}

2.3.2 L nh lặp có s l n ch a xác đ nh tr c

2.3.2.1 Dạng 1: while .. do

while (booleanExpression) { statement(s); }

Đây là dạng vòng lặp kiểm tra điều kiện trước khi thực hiện công việc hay khối lệnh. Nó sẽ lặp cho đến khi điều kiện tr thành false thì ngừng.

Ví d 2.11: Minh họa sử dụng câu lệnh while .. do với mỗi bước lặp là tăng 2

int i = 1;

while (i < 10) {

System.out.print(i +"\t");

i += 2;

}

Kết quả c a câu lệnh while .. do là: 1 3 5 7 9

2.3.2.2 Dạng 2: do .. while

do { statement(s); } while (booleanExpression);

Page 26: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 16

Tương tự như while .. do trên nhưng nó sẽ thực hiện công việc hay khối lệnh trước rồi mới kiểm tra điều kiện.

Ví d 2.12: Minh họa sử dụng câu lệnh do .. while với ít nhất một lần công việc (statements) được thực hiện.

int i = 1;

do {

System.out.print(i +"\t");

i += 2;

}while (i < 10 );

Kết quả c a câu lệnh do .. while là: 1 3 5 7 9

2.4 Ph ng thức tự đ nh nghĩa

trong các phương pháp lập trình trước đây như lập trình hướng th tục, các đoạn lệnh mà có ch c năng riêng biệt hoặc lặp đi lặp lại nhiều lần thư ng được tách thành các th tục (procedure) hoặc hàm (function) riêng biệt khỏi chương trình chính (phương th c main) và thư ng được gọi là các chương trình con (sub-program). Lợi ích c a chương trình con là hữu dụng vì tính module hóa theo từng ch c năng, tránh lặp lại các dòng code, và khả năng tái sử dụng.

2.4.1 Đ nh nghĩa ph ng thức

Trong giáo trình này, lập trình theo phương pháp hướng đối tượng, th tục và hàm được gọi là phương th c (method). Phương th c ngư i dùng (lập trình viên) tự định nghĩa (user-defined method) có cú pháp như sau:

[modifiers] returnType methodName([ parameterList ] ){ Body; //Gồm declarations; và statements;

}

Tên phương th c (methodName): Là phần b t buộc phải có. Nó thư ng được đặt theo dạng động từ vì hàm ch a ý nghĩa cho một thao tác (operation), một ng xử (behavior), hay thông điệp (message) nào đó c a đối tượng.

Danh sách các tham số (parameterList): Mỗi tham số bao gồm (tên) tham số hình th c (formal parameter) và kiểu dữ liệu (data type) c a nó. Nếu có nhiều tham số thì chúng sẽ được phân cách nhau b i dấu phẩy.

Tên phương th c và danh sách các tham số c a nó được gọi chung là chữ ký phương th c (method signature).

Các bổ từ (modifiers): Chúng là một trong những từ khóa c a bổ từ truy cập như: public, protected, private hoặc mặc định để trống (friendly) nh m xác định phạm vi truy cập c a phương th c này khi được gọi và/hoặc các bổ từ khác như static, abstract, synchronized,...

Kiểu dữ liệu trả về (returnValueType) : Khi một phương th c dạng hàm thì cần phải trả về một kết quả cho nó thông qua câu lệnh return ketQuaTraVe; còn khi phương th c dạng th tục ta sử dụng câu lệnh return; để không trả về kết quả nào cả.

Page 27: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 17

Thân phương th c (body method): Bao gồm khối các câu lệnh để khai báo biến, h ng cục bộ (phạm vi hoạt động chỉ trong phương th c ch a nó) và các câu lệnh tuần tự để thực hiện các nhiệm vụ theo ý c a lập trình viên và/hoặc trả về kết quả tính được cho phương th c.

Ví d 2.13: Phương th c tính tổng hai số thực

public static final double tinhTong(double a, double b){

double tong; //khai báo cục bộ (local)

tong = a + b; //lệnh tính tổng;

return tong; //lệnh trả về giá trị cho phương thức hàm

}

2.4.2 L i g i ph ng thức

Để phương th c được thực thi (run), thì phương th c đó phải được gọi thông qua tên phương th c và các tham số thực (actual parameters) được truyền đến cho các tham số hình th c (formal parameters) nếu có.

Ví d 2.14: Viết chương trình giải phương trình bậc nhất ax +b = 0

Page 28: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 18

Ví d 2.15: Tính dãy Fibonacci được định nghĩa: F1 = 1, F2 = 1 và Fn = Fn - 2 + Fn -1.

Hãy in dãy n số Fibonacci theo hai cách đệ quy và không đệ quy, với n là một số nguyên dương được nhập từ bàn phím.

// Filename: Fibonacci.java

package ctu.vdlinh.chapter2;

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

public class Fibonacci {

void nonRecursiveFibo(int m){ //không đệ quy

System.out.print("1");

int i=2; //xử lý từ số đến m

int f1=0, f2=1, f3;

while(i <= m){

f3 = f1 + f2;

System.out.print("\t"+f3);

f1 = f2; f2 = f3;

i++;

}

System.out.println();

}

int recursiveFibo(int m){ //đệ quy

if(m <= 2)return 1;

else return recursiveFibo(m-1) + recursiveFibo(m-2);

}

public static void main(String arg[])throws IOException {

BufferedReader br=new BufferedReader(new InputStreamReader(System.in));

System.out.print("Nhập giá trị n= ");

int n = Integer.parseInt(br.readLine());

System.out.println("Dãy n số Fibonacci không đệ quy) là:");

Fibonacci fibo = new Fibonacci();

fibo.nonRecursiveFibo(n);

System.out.println("Dãy n số Fibonacci đệ quy) là:");

for(int i=1; i<=n; i++) {

Page 29: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 19

System.out.print(fibo.recursiveFibo(i) + "\t");

}

System.out.println();

}

}

Kết quả chạy chương trình: Nhập giá trị n= 9

Dãy n số Fibonacci không đệ quy) là:

1 1 2 3 5 8 13 21 34

Dãy n số Fibonacci đệ quy) là:

1 1 2 3 5 8 13 21 34

Ví d 2.16: Viết chương trình nhập một số nguyên dương n>=2, in các số nguyên tố tìm được trong các số từ 1 đến n, với số nguyên tố là số chỉ chia hết cho 1 và chính nó.

// File name: SoNguyenTo.java

package ctu.vdlinh.chapter2;

import java.util.Scanner;

public class SoNguyenTo {

public static void main(String[] args) {

Scanner scan = new Scanner(System.in);

System.out.print("Nhập số nguyên dương n= " ;

short n = scan.nextShort();

scan.close();

System.out.println("Dãy các số nguyên tố tìm được:");

for (short i = 1; i <= n; i++) {

//kiểm tra i có là số nguyên tố không

short dem = 0;

for(short j=1; j<= i/2; j++){ //nên viết theo while/do

if(i % j == 0) dem++;

}

if(dem == 1) // i là SNT

System.out.printf("%4d", i);

}

System.out.println();

}

}

Page 30: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 20

Chạy thử chương trình: Nhập số nguyên dương n= 0

Dãy các số nguyên tố tìm được:

2 3 5 7

Bài t p ch ng 2

Bài 2.1: Viết chương trình giải phương trình ax + b = 0, với a, b là hai số thực được nhập tùy ý từ bàn phím.

Bài 2.2: Viết chương trình giải phương trình ax2 + bx + c = 0, với các hệ số kiểu số thực được nhập tùy ý từ bàn phím.

Bài 2.3: Viết chương trình nhập hai số thực a, b bất kỳ từ bàn phím. Hãy viết các phương th c sau:

a. phuongThucCong(a, b) // cộng hai số a và b

b. phuongThucTru(a, b) // trừ hai số a và b

c. phuongThucNhan(a, b) // nhân hai số a và b

d. phuongThucChia(a, b) // chia hai số a và b

rồi tính biểu th c a

baS

25

/)5(*12 // sử dụng các phương th c trên

Bài 2.4: Viết chương trình tính n!, với n được nhập từ bàn phím.

Bài 2.5: Viết chương trình nhập vào 2 số nguyên dương n và một số thực a tùy ý. Hãy tính và in kết quả lên màn hình cho biểu th c S1 và S2 như sau:

nnaaaaS ...321 32

!...!3!21

...2

32

n

aaaaS

n

Page 31: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 21

Ch ng 3. Khái ni m v l p trình h ng đ i t ng

Thế giới hiện hữu là các đối tượng, bao gồm thế giới tự nhiên và nhân tạo. Làm sao để đưa các đối tượng hữu hình và vô hình c a bài toán vào trong hệ thống máy tính là mục tiêu c a môn học.

Chương này, giáo trình sẽ đề cập đến các khái niệm cơ bản c a phương pháp lập trình đối tượng, hướng đối tượng đó là: Đối tượng, lớp các đối tượng, quá trình phân tích và mô hình đối tượng để ánh xạ thế giới thực vào máy tính. Đồng th i cũng đưa ra những đặc tính, những ưu điểm c a phương pháp hướng đối tượng so với các phương pháp lập trình trước đó.

3.1 Gi i thi u

Trong khoa học máy tính, thông thư ng, khi viết chương trình chúng ta thư ng dựa trên một phương pháp lập trình nào đó. Thông qua học phần Lập trình căn bản A b ng ngôn ngữ Pascal hoặc C, chúng ta đã làm quen với các phương pháp tiếp cận th tục (Procedural programming). Với phương pháp này, mã lệnh được module dựa trên các dựa trên các chương trình con (routines hoặc subroutines) để tránh sự lặp lại c a các dòng lệnh được thực hiện nhiều lần. Phương pháp lập này đã được sử dụng phổ biến từ những năm 1970, tuy nhiên nó tồn tại những khuyết điểm, bất lợi đối với xu hướng phát triển c a lãnh vực công nghệ phần mềm như: Khó thể hiện những thực thể trong tự nhiên, khó bảo trì, không bảo mật, chỉ phù hợp với những dự án nhỏ.

Ngược lại, triết lý c a lập trình hướng đối tượng lại tập trung vào các đối và sự tương tác c a chúng trong không gian c a bài toán. Và hệ thống ng dụng sẽ được xây dựng dựa trên mô hình các đối tượng này. Vì các đối tượng và sự tương tác c a chúng thuộc nhiều ch ng loại và rất đa dạng trong tự nhiên cũng như những sản phẩm nhân tạo (thế giới thực), nên một ng dụng phần mềm được phát triển b ng cách sử dụng phương pháp lập trình hướng đối tượng sẽ có tính tương đồng và sát với thực tế hơn so với các phương pháp lập trình hướng th tục hoặc có cấu trúc.

Hình 3.1: Các đối tượng và sự tương tác giữa chúng trong hệ thống

Về mặt kỹ thuật, phương pháp lập trình dạng th tục thư ng xem nhẹ việc bảo vệ dữ liệu mà đặt nặng vào việc sử dụng các thuật toán để áp lên các dữ liệu nh m đạt được kết quả mong muốn (Program = Data structure + Algorithm). Ngược lại với phương pháp

Page 32: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 22

trên, phương pháp lập trình HĐT lại nâng dữ liệu lên hàng ưu tiên. Điều này được thực hiện b ng cách đóng gói các dữ liệu và các phương th c phương th c biến đổi (Mutator methods /Setters) và phương th c truy cập (Accessor methods /Getters) mà chúng có quyền truy cập đến dữ liệu vào trong một đơn vị duy nhất đó là chính là đối tượng (Object).

Hình 3.2: Sự khác biệt quan điểm c a hai phương pháp lập trình

3.1.1 Đ i t ng

Đối tượng (object) là một khái niệm rất trực quan và phổ biến trong thế giới thực, nó là một đối tượng bất kỳ thuộc vào một loài nào đó trong tự nhiên, trong các thực thể nhân tạo, trong kinh doanh, trong các sản phẩm sử dụng, v.v… như hình 3.3.

Hình 3.3: Các đối tượng trong môi trường học tập

Mỗi đối tượng phần mềm (software object) là khái niệm tương tự như các đối tượng trong thế giới thực: chúng cũng bao gồm các trạng thái (state) và và các hành vi

Page 33: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 23

(behavior) c a nó. Trạng thái đại diện giá trị dữ liệu c a đối tượng (object’s data), còn hành vi là các thao tác mà đối tượng đó có thể thực hiện như hình 3.4.

Hình 3.4: Một đối tượng phần mềm

Ví d 3.1: Từ vi.wikipedia.org, có đưa các thông tin về danh hài Hoài Linh. Để minh họa cho khái niệm đối tượng, một số thông tin được trích ra như hình 3.5.

Hình 3.5: Danh hài Hoài Linh

Danh hài Hoài Linh này, hiển nhiên, là một đối tượng con ngư i, và được sống trong cộng đồng các đối tượng con ngư i khác. Một số thông tin c a đối tượng này gồm: họ tên là ắNguyễn Bảo Hoài LinhẰ, phái là nam, và tuổi hiện tại là 45, … Đối tượng này có các hành vi như diễn hài, làm MC, giám khảo,... Khi cần, danh hài này có thể tương tác với các đối tượng xung quanh khác b ng các hành vi như diễn kịch cho khán giải xem, làm giám khảo cho các thí sinh dự thi,….

Như vậy các thông tin này chính là trạng thái hiện hành c a đối tượng. Có những trạng thái bất biến theo th i gian như họ tên, phái, nhưng cũng có trạng thái thay đổi như tuổi chẳng hạn. Các hành vi thì luôn luôn tồn tại trong đối tượng này, nhưng mỗi th i điểm thì đối tượng này có thể có những hành vi khác nhau, chẳng hạn có ngày thì diễn kịch, có ngày thì làm MC,…

3.1.2 L p

Lớp (class) là một nguyên mẫu (prototype) định nghĩa cấu trúc cho sự đại diện các đối tượng có chung những đặc điểm (thuộc tính và các hành vi) c a chúng. Các đặc điểm này phải cung cấp được các thông tin khi đề cập đến nhóm đối tượng thuộc lớp đó và được gọi là thuộc tính c a đối tượng (object attributes). Các hành vi được sử chung cho

Page 34: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 24

các đối tượng cùng loại được gọi là hoạt động/phương th c c a đối tượng (object operations).

Theo Booch: một lớp là một tập các đối tượng chia sẻ từ một cấu trúc và hành vi chung (A class is a set of objects that share a common structure and a common

behavior).

Hình 3.6: Các đối tượng cùng chung một cấu trúc lớp Student

Trên sơ đồ sử dụng ký hiệu UML, một lớp có 03 phần đó là: Tên lớp (class name), các thuộc tính (attributes) và các hành vi (operations). Với ngôn ngữ lập trình, chúng được gọi là các trư ng (fields) và các phương th c (methods) tương ng.

Ví d 3.2: Lớp DienVien, được viết b ng ngôn ngữ giả và theo sơ đồ UML

class DienVien

Fields: //các trư ng

hoTen

gioiTinh

tuoi

Methods: //các phương th c

dienHai(){…}

lamGiamKhao(){…}

lamMC(){…}

Giả sử, trên sân khấu (hệ thống) có 3 diễn viên hài khác nhau như: Trư ng Giang, Chí Tài, và Hoài Linh, thì từ lớp DienVien tạo ra 3 đối tượng diễn viên với các định danh là dienVien1, dienVien2, dienVien3.

3.2 Các giai đo n phát triển h th ng h ng đ i t ng

Phát triển hệ thống hướng đối tượng đòi hỏi các kỹ thuật hướng đối tượng (Object-Oriented techiques) được sử dụng trong suốt quá trình phân tích và cài đặt c a hệ thống. Phương pháp này đòi hỏi ngư i phân tích phải xác định được các đối tượng trong hệ thống là cái gì, chúng sẽ ng xử (behave) như thế nào theo th i gian hoặc trong

Page 35: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 25

sự đáp ng (response) lại với các sự kiện, và các mối quan hệ nào giữa đối tượng này với các đối tượng khác trong hệ thống.

Hình 3.7: Các khái niệm chính c a hướng đối tượng

Mô hình hóa đối tượng (Object modeling) được dựa trên sự xác định (identifying) các đối tượng trong hệ thống và mối quan hệ giữa chúng. Các giai đoạn cơ bản vệc thiết kế hệ thống sử dụng mô hình hóa đối tượng là: Phân tích (Analysis stage), thiết kế hệ thống (System design stage), thiết kế đối tượng (Object design stage) và cuối là sự cài đặt chúng (Implementation).

3.2.1 Phân tích h th ng h ng đ i t ng

Phân tích hệ thống (System analysis stage) là giai đoạn đầu tiên c a phát triển phần mềm và cũng là bước đầu tiên trong kỹ thuật mô hình hóa đối tượng (OMT) mà triết lý c a nó là xem hệ thống ban đầu như là một tập các hệ thống con nhỏ hơn mà trong đó mỗi hệ thống con gồm các đối tượng tương tác với nhau. Do vậy, ngư i phát triển (developer) hệ thống cần tham khảo với các ngư i dùng để tìm ra những yêu cầu (requirements), và phân tích chúng để hiểu rõ ch c năng c a hệ thống đang quan tâm.

Dựa vào sự phân tích trên, ngư i phân tích sẽ phác thảo và đưa ra một mô hình (model) c a hệ thống mong muốn sao cho giống với những tình huống trong thế giới thực. Trong mô hình này chỉ đưa ra cái gì (what) mà hệ thống đòi hỏi phải thực hiện mà không cần quan tâm đến các chi tiết cần cài đặt.

Như vậy , trong thiết kế hướng đối tượng, ngư i phân tích phải trừu tượng sao cho tìm ra được một mô hình c a dự án mà đó nhấn mạnh vào việc tìm kiếm và mô tả các lớp đối tượng (class), hay các khái niệm (concepts) trong phạm vi bài toán.

3.2.2 Thi t k h th ng

Sau khi kiến trúc tổng thể c a hệ thống mong muốn đã được quyết định, giai đoạn tiếp theo là thiết kế đối tượng (System design stage). Trong giai đoạn này, hệ thống được tổ

Page 36: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 26

ch c thành một tập các hệ thống con (sub-systems) mà chúng tương tác qua lại được với nhau. Giai đoạn phân rã này, ngư i phân tích cần quan tâm đến các đặc điểm kỹ thuật cũng như những yêu cầu nào c a hệ thống đối với ngư i dùng đầu cuối (end-user).

Trong thực tế, giai đoạn này là xây dựng mô hình vật lý c a hệ thống thông tin từ mô hình được phân tích hệ thống nên phải tập trung để quyết định các vấn đề liên quan như chọn chiến lược nào để cài đặt data-stores như data structure, file hoặc database; xác định các nguồn tài nguyên (resources) và cơ chế để kiểm soát việc truy xuất chúng,…

3.2.3 Thi t k đ i t ng

Trong giai đoạn thiết kế đối (Object design stage), các chi tiết c a giai đoạn phân tích hệ thống và thiết kế hệ thống trên sẽ được cài đặt (implemented). Các đối tượng được xác định trong giai đoạn thiết kế hệ thống sẽ được thiết kế. Việc thiết kế các đối tượng này là chia mỗi nhóm đối tượng có đặc tính giống nhau được đại diện b i một đối tượng phần mềm (class) cũng như những cách chúng tương tác với nhau (thông qua mối kết hợp Has-a hoặc mối liên kết thừa kế sự Is-a giữa chúng) để thực hiện đầy đ và trọn vẹn các yêu cầu đề ra.

Các đoạn này được thực hiện nh vào quá trình trừu tượng hóa.

3.2.3.1 Trừu tượng hóa

Một trong những cơ chế then cơ nhất c a hướng đối tượng là sự trừu tượng hóa (abstraction). Trừu tượng là một phương pháp mạnh mẽ để quản lý xuyên suốt các hệ thống ph c tạp và nó được dùng để xác định các loại đối tượng, sự tương tác cũng như phân loại theo th bậc c a chúng.

Các đối tượng này được xác định dựa vào nguyên lý OBD, mà đó một tập các đối tượng tương tự nhau sẽ được quan sát và các đặc điểm chung c a chúng sẽ được liệt kê ra. Mỗi nhóm đối tượng giống nhau này được đại diện b i các thuộc tính và các phương th c c a chúng và ta gọi là lớp đối tượng (class).

Hình 3.8: Từ quan niệm tới đối tượng phầm mềm

Như vậy, quá trình trừu tượng hóa sẽ được dùng để hình thành được một mô hình các đối tượng (model hay abstraction). Khi xây dựng mô hình (model), chúng ta cần tránh rơi vào các m c chi tiết, mà thay vào đó cần tập trung vào một số tính năng quan trọng c a hệ thống. Quá trình này thư ng được dùng với một thuật ngữ khác là sự che dấu thông tin (Information Hiding).

Page 37: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 27

Lưu ý r ng, việc trừu tượng ra c a một lớp đối tượng thay đổi tùy theo vào mỗi ng dụng cụ thể c a nó. Chẳng hạn hạn như khi trừu tượng để định nghĩa một lớp các đối tượng cây bút (lớp Pen) cửa tiệm, các thuộc tính có thể quan tâm như là: màu s c bút, màu mực, loại bút,… trong khi đó, nếu ta định nghĩa một lớp Pen mà hệ thống quản lý nó là xư ng sản xuất thì các thuộc tính quan tâm có thể khác trên như: hình dạng, đư ng kính, kích thước,… c a nó.

Có nhiều m c (layers) c a sự trừu tượng hóa: M c trừu tượng cao nhất là dự án đang quan tâm sẽ được xem xét như một cộng đồng các đối tượng tương tác với nhau để đạt được những mục đích chung đề ra. M c trừu tượng tiếp theo là nhóm (group) các đối tượng hoạt động chung với nhau thành một đơn vị (unit) như package trong java, namespace trong C++ hoặc unit trong Delphi để dễ quản lý. M c trừu tượng th 3 đó là cung cấp dịch vụ (service) cho nhau giữa các đối tượng.

Khi ta xem xét sự tương tác giữa 02 lớp đối tượng riêng biệt trên mô hình dịch vụ thì đó chính là sự tương tác giữa client và server. Trong đó server có thể là một Interface trong Java (như ví dụ 3.3) để cung cấp những dịch vụ là các ch c năng (abstract behaviors/methods) cần phải có, còn client như là các lớp hoặc các lớp trừu tượng để cài đặt cụ thể các dịch vụ c a server. Khái niệm này sẽ được đề cập thêm trong phần truyền thông điệp (messages) giữa các đối tượng phần sau.

Ví d 3.3: Vai trò server c a interface List<E> phục vụ cho client là lớp trừu tượng AbstractList<E>

interface List <E>{

public boolean add(E e);

public boolean add(int index, E element);

public Iterator<E> iterator();

//… }

public abstract class AbstractList<E> extends AbstractColletion <E> implements List <E> {

//… }

M c trừu tượng tiếp nữa đó là xem xét trong cùng một phạm vi phía server thì nó phục vụ được gì từ phía client. Vs dụ như cùng List<E> nhưng phía Client có thể là LinkedList, có thể là ArrayList, Stack hoặc Vector.

Page 38: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 28

Hình 3.9: Dịch vụ và cung cấp dịch vụ

M c trừu tượng sau cùng là trừu tượng để thực hiện một nhiệm vụ (a single task, single method) riêng biệt duy nhất. Những quan tâm m c trừu tượng này là một dãy chính xác các thao tác tuần tự được sử dụng để thực hiện cho hoạt động (activity) đó.

Một dạng khác c a trừu tượng hóa còn là sự áp đặt cấu trúc (structure) lên một hệ thống c a dự án đang phát triển. Dạng trừu tượng cấu trúc này có thể phản ảnh một số khía cạnh thực tế c a hệ thống hoặc giúp chúng ta hiểu rõ được hệ thồng ph c tạp c a dự án hơn. Có thể thực hiện điều này thông qua nhiều cơ chế khác nhau như: Phân chia thành các bài toán con (division into parts), Sự bao gói và thay thế lẫn nhau (Encapsulation and interchangeability), giao diệm và lớp cài đặt (interface and implementation), dịch vụ (service view), các thành phần kết hợp Has-a (composition), chuyên biệt hóa Is-a (specialization), và các mẫu (patterns) . Một số trong các phần này sẽ được trình bày các chương sau.

3.2.3.2 Thừa kế

Có thể nói sự trừu tượng có mặt trong suốt quá trình phát triển phần mềm hướng đối tượng. Trong giai đoạn thiết kế đối tượng (Object design stage), sự trừu tượng còn được thể hiện rõ nét hơn trong khái niệm thừa kế. Thừa kế (Inheritance) là một trong những nguyên lý quan trọng nhất c a OOP, khái niệm này được sử dụng cho ý tư ng về tính tái sử dụng (reusability) c a các lớp đối tượng: Một lớp đối tượng mới có thể được định nghĩa b ng cách sử dụng (một) lớp tương tự đã tồn tại và thêm vào một vài đặc điểm mới cần quan tâm.

Bên cạnh việc dữ liệu là trung tâm, OOP còn thêm vào nhiều ý tư ng mới quan trọng như cơ chế gửi nhận thông điệp (messages) và đa hình (polymorphism).

3.2.4 Giai đo n cƠi đặt

Giai đoạn cài đặt (Implementation) này, các đối tượng được thiết kế sẽ được cài đặt hay lập trình theo ngôn ngữ lập trình hướng đối tượng nào đó, chẳng hạn b ng Java hoặc .Net, .PHP,…

Page 39: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 29

Ví d 3.4: Cài đặt lớp DienVien b ng mã lệnh Java

class DienVien{

public String hoTen;

private Boolean gioiTinh;

private Integer tuoi;

public void dienHai(){

//...

}

public void lamGiamKhao(){

//...

}

public void lamMC(){

//...

}

}

Ví d 3.5: Minh họa tính trừu tượng hóa để xây dựng mô hình đối tượng cho bài toán (đơn giản) quản lý máy laptop c a hãng Toshiba như hình 3.12.

Hình 3.12: Một sản phẩm máy laptop trên thị trường

Giai đoạn phân tích, thiết kế đối tượng: Để lưu giữ các thông tin sản xuất về máy laptop, các nhà quản lý Toshiba sẽ định nghĩa ra một lớp ToshibaLaptop chẳng hạn. Trong đó có các trư ng để lưu giữ các thông tin như số đơn vị hệ thống (system unit number), số hiệu mẫu (model/part number) và số sơ-ri (serial number). Các hành vi/hoạt động c a máy có thể thực hiện được như: kh i động máy, nhập/xuất và xử lý dữ liệu,…

Như vậy ta có thể định nghĩa một lớp máy laptop Toshiba qua các m c như sau:

Page 40: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 30

Hình 3.13: Minh họa các m c thiết kế một lớp

Mỗi đối tượng (phần mềm) lưu trữ trạng thái c a nó trong các biến trư ng (fields) và thực hiện các hành vi c a mình thông qua các phương th c, chẳng hạn như máy laptop hình 3.12 là một thể hiện (sản phẩm cụ thể) mà hãng Toshiba đưa ra thị trư ng.

Hình 3.14: Đối tượng myLaptop

Dựa vào giá trị các trạng thái c a các thuộc tính mà hãng sẽ phân biệt được máy này với các máy cùng loại được phân phối trên toàn thế giới.

Sau khi đã có mô hình đối tượng, kế đến là giai đoạn cài đặt mã lệnh Java cho lớp ToshibaLaptop như sau:

class ToshibaLaptop {

private String systemUnitNumber;

private String modelNumber;

private String serialNumber;

void boot() {

// ...

}

void readData() {

// ...

Page 41: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 31

}

void writeData() {

// ...

}

void processing() {

// ...

}

}

3.3 Quá trình phát triển ch ng trình h ng đ i t ng

Theo các tác giả R. Morelli và R.Walde, quá trình phát triển chương trình được thể hiện b i hình 3.15. Trong sơ đồ này, bước đầu là phải xác định rõ được các vấn đề c a dự án. Tiếp đến, phân rã bài toán ban đầu thành các bài toán nhỏ hơn dựa trên nguyên t c chia-để-trị (the divide-and-conquer principle) với tư duy xác định các đối tượng có thể có trong hệ thống và các kịch bản mà chúng sẽ tương tác với nhau như thế nào. Bước th ba là quá trình trừu tượng hóa để tạo ra một mô hình (model) các đối tượng trên nền tảng đối tượng (OBP-Object-based programming) hoặc hướng đối tượng. Hay nói cách khác, đây là bước phân tích và thiết kế sơ đồ lớp theo nền tảng OBP hoặc m rộng hơn OOP. Bước 4 là viết mã lệnh Java, và bước cuối cùng là kiểm thử và chỉnh sửa.

Hình 3.15: Sơ đồ phát triển chương trình

Page 42: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 32

Dưới đây là một ví dụ ng n gọn để minh họa việc phân tích và thiết kế hướng đối tượng cho một ng dụng là trò chơi tung xúc s c.

Ví d 3.6: Phân tích và thiết kế hướng đối tượng cho trò chơi đơn giản xúc s c ắDice gameẰ mà ngư i chơi đươc tung 2 lần. Nếu tổng điểm b ng 7 thì th ng ngược lại thua.

B c 1 - Xác đ nh s đồ use cases: Yêu cầu ngư i chơi phải l c xúc x c hai lần. Hệ thống sẽ hiển thị kết quả: Nếu giá trị mặt xúc x c có tổng cộng bảy, ngư i chơi chiến th ng; ngược lại, ngư i chơi bị thua.

Hình 3.16: Use case c a trò chơi

B c 2 - Xác đ nh mô hình mi n (Domain model = static view + conceptual class): Gồm các lớp khái niệm là Player, Die, và DiceGame, cùng với các mối kết hợp (associations) và các thuộc tính c a chúng.

Hình 3.17: Mô hình miền c a trò chơi

B c 3 - Xác đ nh biểu đồ t ng tác (Interaction Diagrams = dynamic view): Để minh họa cho quá trình tương tác c a các đối tượng b ng sơ đồ trình tự (sequence diagram). Nó chỉ ra một cách tuần tự các thông điệp (message) giữa các đối tượng phần mềm, và các l i gọi phương th c tương ng.

Hình 3.18: Mô hình tương tác c a trò chơi

Page 43: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 33

B c 4 - Xác đ nh s đồ l p thi t k (Design class diagrams = Static view): Ngược lại với mô hình miền, sơ đồ này không minh họa các lớp khái niệm trong thế giới thực mà nó chỉ ra các lớp phần mềm (software classes) bao gồm các thuộc tính và phương th c c a các lớp .

Hình 3.19: Sơ đồ lớp c a trò chơi

3.4 Các đặc tính của l p h ng đ i t ng Java

Lập trình hướng đối tượng là phương pháp lập trình dựa trên OBP và có m rộng thêm tính thừa kế và đa hình. Như vậy, tổng quát, phương pháp lập trình hướng đối tượng có các đặc tính sau:

3.4.1 Tính trừu t ng

Như đề cập trên, trừu tượng hóa công cụ để xây dựng được mô hình (model) c a hệ thống thực hướng đối tượng. Nó được sử dụng xuyên suốt từ giai đoạn phân tích đến giai đoạn cài đặt mã lệnh, thuật toán. Nh vào các phương c a trừu tượng mà một bài toán ban đầu ph c tạp khó hình dung, dần dần tr nên rõ ràng, cụ thể và có thể cài đặt được.

Trong giáo trình này, việc trừu tượng hóa sao cho giải quyết được một bài toán đang xét trong thế giới thực vào hệ thống máy tính b ng phương pháp hướng đối tượng thông qua kỹ thuật mô hình hóa đối tượng (Object-modeling technique), chỉ yêu cầu giới hạn qua (ít nhất) hai bước sau:

Bước 1: Xây dựng mô hình tĩnh các lớp đối tượng (sơ đồ lớp) hoặc mô hình động (mô hình tuần tự) giữa các đối tượng.

Bước 2: Sử dụng ngôn ngữ Java, với các tính năng mạnh c a nó, để viết và cài đặt bài toán (dự án, một hệ thống IT đang quan tâm) đã được thiết kế bước trên.

3.4.2 Tính bao đóng

Tính bao đóng (encapsulation): Là việc cài đặt mã lệnh cho các phương th c nội tại và cách th c truy xuất các thuộc tính c a lớp thành một đơn vị duy nhất Cung cấp một cơ chế duy nhất để bảo vệ dữ liệu (che dấu và bảo vệ dữ liệu khỏi ngư i dùng muốn can thiệp hoặc thao tác sai mục đích) là thông qua các interfaces (methods) mới có thể modify được các dữ liệu.

Page 44: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 34

Hình 3.20: Bao đóng

3.4.3 Tính thừa k

Thừa kế (inheritance): Là một cơ chế cho phép lập trình viên định nghĩa lớp con mới (child/ sub/ derived class) b ng cách m rộng từ (các) lớp cha/cơ s (parent/ super/ base class) đã tồn tại. Lớp con thừa hư ng các đặc điểm (properties = attribute + operations) từ lớp cha trong phạm vi truy xuất được phép. Quá trình phân tích tìm các lớp con dẫn xuất từ lớp cha được thực hiện qua cơ chế chuyên biệt hoá (specialization).

Hình 3.21: Thừa kế

Thừa kế là một trong những đặc tính quan trọng nhất trong phương pháp hướng đối tượng và có thể nói đó là một cuộc cách mạng c a lĩnh vực công nghệ phần mềm trong những năm gần đây.

3.4.4 Tính đa hình

Đa hình (polymorphism): là khả năng đảm nhận nhiều dạng: Một hành động (thông qua phương th c) được đối tượng thực hiện b ng nhiều cách khác nhau, và các đối tượng khác loại có thể thực hiện chung một ng xử theo cách riêng c a mình.

Page 45: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 35

3.4.5 Tính b n vững

Mục đích c a tính bền vững (persistence) là lưu giữ sự tồn tại c a đối tượng lâu hơn sự thực thi c a chương trình.

JFC sử dụng tuần tự hoá (serialization): Cơ chế để đảm bảo sự bền vững là sự tuần tự hóa - java.io.Serializable; Nó chuyển đổi dữ liệu (đối tượng) vào luồng (byte stream) và ghi nó vào tập tinđể lưu trữ - sử dụng phương th c writeObject(). Sau đó, chương trình sẽ được java bean khôi phục lại b ng cơ chế deserialization để có được trạng thái ban đầu c a đối tượng - sử dụng phương th c readObject().

Hình 3.22: Native Java persistence

Với công nghệ Java, các framework được phát triển để hỗ trợ cho tính năng persistence như: JPO/OpenJPA, TopLink, EclipseLink, Hibernate,…

Hình 3.23: Persistence frameworks

3.4.6 Tính đồng b hóa

Cơ chế đồng bộ hóa (concurrency) cho phép thực hiện nhiều ch c năng/công việc tại một th i điểm. Ví dụ như hệ điều hành đa nhiệm - Java thực hiện thông qua cơ chế tiến trình (processes) và tuyến đoạn (threads) và tuần tự hoá (synchronization). Java API là gói java.util.concurrent; Chú ý: Concurrent và Synchronized collection class đều cung

Page 46: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 36

cấp thread-safety, nhưng Synchronized collection như HashMap, ArrayList lại chậm hơn Concurrent collection như ConcurrentHashMap, CopyOnWriteArrayList. Lý do chính là khi locking, Synchronized collection lock toàn bộ đối tượng (whole object) trong khi đó Concurrent collection lại sử dụng thread-safety thông minh hơn (smartly).

3.4.7 Tính ủy quy n

Tính y quyền (delegation) là ch c năng cho phép một phương th c method_A c a lớp A thực hiện một nhiệm vụ thông qua một phương th c method_B lớp B. Điều này có thể thực hiện được thông qua các mối kết tập (associations) và và thừa kế (inheritance).

3.4.8 Tính tổng quát

Tính tổng quát (generics) cho phép các kiểu dữ liệu classes và interfaces là các tham số khi định nghĩa lớp, giao diện và phương th c. Các tham số kiểu (type parameters) cung cấp một cách để bạn có thể tái sử dụng cùng một đoạn mã (lớp generics, giao diện generics và phương th c generic) với các kiểu dữ liệu đầu vào khác nhau.

Với Java generics, cho phép sự trừu tượng hóa có đặc tính đa hình (parametric polymorphism) cũng như thừa kế các lớp generics.

Tóm l i: Trong phương pháp OOP, bốn nguyên lý chính được đề cập là: Trừu tượng, bao đóng, thừa kế và đa hình.

Bài t p ch ng 3

Bài 3.1: Hình dung bạn đang gia đình, hãy liệt kê càng nhiều càng tốt: - Các đối tượng và số lượng có trong gia đình bạn - Cho biết những đối tượng nào chung loài (lớp) nhau - Với mỗi loại đối tượng đó có những đặc điểm và hoạt động nào có thể có

Bài 3.2: Hãy trừu tượng hóa để xây dựng mô hình cho mỗi một đối tượng trong môi trư ng học tập bậc đại học:

- Đối tượng sinh viên - Đối tượng giảng viên - Đối tượng chuyên viên - Đối tượng môn học/ học phần - Đối tượng lớp học

Bài 3.3: Hãy liệt kê ra ít nhất 03 mô hình (mỗi mô hình có nhiều nhất là 3 lớp) mà có tính thừa kế b ng ngôn ngữ tự nhiên hoặc sơ đồ UML.

Bài 3.4: Sử dụng ngôn ngữ tự nhiên, hãy chỉ ra một ví dụ có trong thực tế tự nhiên hoặc những sản phảm nhân tạo mà có tính đa hình.

Bài 3.5: Dịch vụ ATM mà bạn được cung cấp để giao dịch thông qua thẻ có thể có những đặc tính nào c a hướng đối tượng? Hãy nêu ra và cho ví dụ cụ thể để minh họa điều đó.

Page 47: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 37

Ch ng 4. L p, đ i t ng, truy n thông đi p và gói

Trong chương này sẽ trình bày các kiến th c về lớp, việc tạo và h y các đối tượng, các cách truyền tham số kiểu dữ liệu nguyên th y và kiểu đối tượng, cách truyền nhận thông điệp giữa chúng và cách gom các lớp vào chung một gói (một không gian tên vùng) theo ngôn ngữ Java.

4.1 L p

4.1.1 Khái ni m

Lớp (class) đại diện cho một mẫu các đối tượng (vật thể hoặc phi vật thể) có chung những đặc điểm giống nhau, bao gồm các tên trư ng (fields) và các phương th c (methods) c a nó. Trong sơ đồ UML, ngư i ta thư ng sử dụng thêm thuật ngữ khác đó là tên thuộc tính (attributes) thay cho tên trư ng, và hành vi (behaviors/ operations) thay cho phương th c.

Trên sơ đồ UML, lớp có 03 phần là Tên lớp (Class name), các thuộc tính và hành vi như hình 4.1:

Hình 4.1: Ký hiệu UML cho lớp

Ví d 4.1: Các thầy cô giảng dạy trong trư ng Đại học Cần Thơ đều là đối tượng giảng viên nên định nghĩa một lớp GiangVien đại diện cho các thầy cô trong trư ng.

Hình 4.2: Định nghĩa lớp giảng viên

Lớp Giảng viên, ta quan tâm đến 03 thông tin: Mã số giảng viên, họ tên, chuyên ngành, và 02 phương th c là: giảng dạy học phần và nghiên c u khoa học.

4.1.2 L p tự đ nh nghĩa

Trong ngôn ngữ Java, lập trình viên có thể định nghĩa một lớp để đại diện cho một nhóm các đối tượng có chung những thuộc tính và phương th c như cú pháp sau.

Page 48: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 38

4.1.2.1 Cú pháp khai báo tổng quát

[Doc comment]

[Modifier] class Identifer [extends SuperClassName]

[implements Interfaces] {

ClassBody; //Members

} Trong đó, từ khóa (keyword) class đ ng trước một danh hiệu là tên lớp (Identifer)

và cặp dấu móc nhọn { } để b t đầu và kết thúc một lớp. Các thành phần tùy chọn (trong cặp [ ]) còn lại sẽ được đề cập sau.

Với ClassBody là phần định phần nghĩa thân c a lớp. Nó gồm phần khai báo các thuộc tính (còn được gọi là biến thành viên member variables) và các phương th c hay còn được gọi những phương th c thành viên (member methods).

Cú pháp chi tiết c a lớp tự định nghĩa: [Doc comment]

[Modifier] class Identifer [extends SuperClassName]

[implements Interfaces] {

[Modifier] dataType fieldName1;

[Modifier] dataType fieldName2;

//...

[Modifier] returnType Identifer1( [ParameterList] )[throws] {

MethodBody

}

[Modifier] returnType Identifer2( [ParameterList] )[throws] {

MethodBody

}

//…

}

Trong đó, cần phân biệt các loại biến khác nhau: Các biến thành viên được gọi là các trư ng (fields), các biến trong phương th c hoặc trong khối lệnh là các biến cục bộ (local variable), và các biến trong phần khai báo trong chữ ký phương th c (method signature) được gọi là các tham số (parameters).

Ví d 4.2: Với thực thể giảng viên trong sơ đồ UML hình 4.2 trên, ta có lớp GiangVien theo ngôn ngữ Java như sau:

Page 49: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 39

public class GiangVien {

private String maGV;

public String hoTen;

public Boolean gioiTinh;

public void giangDay(String maHP) {

//cài đặt thân phương thức

}

protected void nghienCuuKH() {

//cài đặt thân phương thức

}

}

4.1.2.2 Kiểm soát truy cập đến các thành viên của lớp

Các bổ từ m c độ truy cập (access level modifiers) xác định xem liệu các lớp khác có thể sử dụng biến trư ng hoặc gọi đến một phương th c cụ thể nào đó c a nó hay không. Có hai cấp độ kiểm soát truy cập đến các thành viên c a một lớp:

mức lớp (class level/ top level): được xác định b i bổ từ truy cập đ ng ngay trước từ khóa class. Nó có 2 dạng public hoặc không có modifier.

public: Lớp sẽ được truy cập mọi nơi trong dự án – anywhere.

Không có modifier: Lớp chỉ được truy cập trong phạm vi cùng gói (package-private hay friendly).

mức các thành viên của lớp (member level): được xác định b i bổ từ truy cập đ ng trước tên biến trư ng hoặc trước tên mỗi phương th c (fields và methods). Nó có thể là một trong 4 bổ từ truy cập sau:

private: Các thành viên chỉ có thể truy xuất được phạm vi bên trong lớp c a chính nó mà thôi, ngay cả các thành viên lớp con cũng không thể truy xuất tới được (không được thừa kế).

public: Các thành viên c a lớp sẽ được truy cập từ tất cả các lớp khác.

Không có modifier (friendly/ package access): Trong cùng gói là public còn khác gói là private.

protected: Các thành viên được truy xuất b i các phương th c cùng lớp, các phương th c trong các lớp con (được thừa kế) và các phương th c khác lớp nhưng phải cùng gói.

Ví d 4.3: Định nghĩa kiểu dữ liệu lớp HinhTron mà lớp này và phương th c tinhDienTich được truy xuất mọi nơi, biến trư ng banKinh chỉ được truy xuất trong thân c a lớp HinhTron, còn phương th c tinhChuVi được truy xuất trong phạm vi c a gói hiện hành.

Page 50: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 40

public class HinhTron { // mức lớp: public

private double banKinh; // mức thành viên: private

double tinhChuVi() { // mức thành viên: friendly

return 2 * Math.PI * banKinh; // có phương thức thể hiện

}

public double tinhDienTich() { // mức thành viên: public

return Math.PI * banKinh * banKinh;

}

}

4.1.2.3 L p t n cùng

Ngoài các bổ từ truy cập trên, còn có các bổ từ khác như final, synchronized, transient, native,…

Nếu m c lớp được khai báo với bổ từ modifier là final, thì được gọi là lớp tận cùng (final class), nghĩa là không cho phép m rộng hoặc thừa kế (inheriance) cho các lớp con làm hậu duệ c a nó.

Nếu m c thành viên được khai báo thêm từ khóa final thì đó là phương th c h ng (final method) hoặc biến h ng (final variable). Với phương th c h ng, thì không được phép ghi chồng (over-riding) lên nó.

4.2 Đ i t ng

4.2.1 Khái ni m

Đối tượng (object) là một thể hiện, instance, c a một lớp. Mỗi đối tượng phần mềm (A software object) lưu giữ các trạng thái (states) c a nó trong các biến trư ng (fields) ngay tại mỗi th i điểm run-time và được gọi là giá trị hiện hành c a đối tượng (object's data, và thực hiện các hành vi (behaviors) c a nó b ng các phương th c (methods). Phương th c là khối lệnh có cấu trúc (như phương pháp lập trình hướng th tục) được cài đặt để thao tác trên các biến trư ng (setter/getter) c a đối tượng cũng như thực hiện hành vi khác c a nó mà điển hình nhất là để truyền nhận thông điệp (message passing) giữa các đối tượng với nhau.

4.2.2 T o đ i t ng

Trước khi tạo đối tượng, chúng ta cần biết đối tượng sẽ được tạo ra từ một trong các lớp chuẩn Java, hoặc các lớp tự định nghĩa nào. Mỗi đối tượng có một định danh (identity/ name) để phân biệt nhau như: gv1, gv2 và được tạo ra thông qua từ khóa new trong Java.

Page 51: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 41

Hình 4.3: Tạo 2 đối tượng gv1, gv2 từ lớp Giảng viên

Cách 1: Khai báo và kh i tạo riêng biệt

TênLớp biếnThamChiếu;

biếnthamChiếu = new TênLớp([Các đối số]);

Biến tham chiếu (reference variable) là biến lưu trữ giá trị địa chỉ ô nhớ c a đối tượng được tạo mà nó trỏ đến. Nếu đối tượng chưa được tạo thì địa chỉ c a ô nhớ đó chưa xác định, còn ngược lại thì địa chỉ ô nhớ đó sẽ được cấp phát để ch a đối tượng. Chú ý r ng, trong Java, địa chỉ c a các biến c a tham chiếu được quản lý b i Stack, còn địa chỉ ch a đối tượng thì được quản lý b i Heap.

Ví d 4.4: HinhTron ht1; //khai báo biến tham chiếu ht1

Biến ht1 được gọi là tham chiếu đến đối tượng lớp hình tròn nhưng đối tượng chưa được tạo ra (địa chỉ Heap c a đối tượng hình tròn chưa xác định, no object instance)

ht1 = new HinhTron();

Biến ht1 được gọi là tham chiếu đối tượng (object reference) hình tròn. Các cách đọc khác có thể là: tham chiếu (tới đối tượng hình tròn) ht1; hoặc: Địa chỉ ch a đối tượng hình tròn được trỏ b i tham chiếu ht1.

Ta cũng có thể h y và giải phóng đối tượng khỏi bộ nhớ b ng cách gán giá trị null cho tham chiếu đối tượng như lệnh:

ht1 = null; //null reference

Cách 2: Khai báo và kh i tạo

TênLớp biếnThamChiếu = new TênLớp([Các đối số]);

Ví d 4.5: Khai báo và kh i tạo biến tham chiếu ht2 tới đối tượng HinhTron

HinhTron ht2 = new HinhTron();

Sau khi đã khai báo và kh i tạo, để truy xuất đến các biến trư ng và phương th c c a đối tượng xem hình 4.4, ta sử dụng theo dạng sau:

Page 52: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 42

thamChiếuĐốiTượng.tênBiếnTrư ng

thamChiếuĐốiTượng.tênPhươngThức([Các_đối_số])

Hình 4.4: Minh họa intelligent code completion c a Eclipse IDE

Sau đây là một số ví dụ minh cách cấp phát và quản lý bộ nhớ cho loại biến nguyên th y và biến kiểu đối tượng trong Java:

Hình 4.5: Minh họa cấp phát trong Stack và Heap

Ví d 4.6: Viết chương trình (theo OBP) để tạo một hình tròn có toạ độ tâm O(50,100), bán kính b ng 30 và hiển thị thông tin và diện tích c a nó.

//File name: LopChinh.java

class HinhTron {

int x = 50;

int y = 100;

Page 53: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 43

double banKinh = 30;

double tinhDienTich() {

return Math.PI * Math.pow(banKinh, 2);

}

}

public class LopChinh {

public static void main(String[] args) {

HinhTron ht = new HinhTron();

System.out.printf("Hình tròn vừa tạo có tâm O(%d,%d)" + " và diện tích= %.4f\n", ht.x, ht.y, ht.tinhDienTich());

}

}

4.3 Thành viên thể hi n và thành viên l p

Khi định nghĩa một lớp, chúng ta cần chú ý phân biệt rõ hai ch c năng cho hai loại biến trư ng và phương th c (gọi chung là các thành viên, members) đó là các thành viên thể hiện (instance members) và các thành viên lớp (class members) .

4.3.1 Thành viên thể hi n

Là các biến thể hiện (instance variables) và các phương th c thể hiện (instance methods). Đây là phần dữ liệu dành riêng cho mỗi đối tượng được tạo ra. Với cách này, địa chỉ c a mỗi đối tượng được tạo sẽ lưu vào trong vùng nhớ riêng biệt nhau.

Mục đích sử dụng tính năng này là khi chúng ta muốn các đối tượng được tạo ra cùng từ một lớp nhưng giá trị c a các thuộc tính (hay trạng thái) giữa chúng là được lưu giữ riêng biệt nhau. Ví dụ như: giá trị mã số sinh viên, họ tên, tuổi,… c a mỗi sinh viên là khác nhau nên chúng được gọi là biến thể hiện.

Với các phương th c thể hiện thì có thể thao tác/truy xuất trên cả hai loại biến trư ng: biến thể hiện (instance variables) và biến lớp (class variables).

4.3.2 Thành viên l p

Ngược lại với instance member, các thành viên (c a) lớp bao gồm các biến lớp (class variables) và phương th c lớp (class methods). Nó được xác định b i từ khóa static, được khai báo đ ng trước mỗi biến trư ng hoặc phương th c.

Đây là phần dữ liệu dành riêng cho lớp và được truy xuất trực tiếp b i tên lớp. Với cách này, các thành viên c a các đối tượng được tạo ra từ một lớp sẽ có chung địa chỉ c a biến lớp và được xem như biến dùng chung cho các đối tượng được tạo ra cùng từ một lớp.

Từ các phương th c thể hiện, chúng ta có thể truy xuất đến các biến thể hiện cũng như các biến lớp. Ngược lại, từ các phương th c lớp, chúng ta không thể truy cập đến các biến thể hiện được khai báo trong lớp hiện tại mà chỉ có thể đến các biến lớp và các

Page 54: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 44

phương th c lớp (khác) và không sử dụng từ khóa this và sufer. Các thành viên lớp được gọi thông qua tên lớp mà không cần phải thông qua tên đối tượng.

Thành viên lớp được sử dụng với mục đích khi chúng ta muốn giá trị thuộc tính (hay trạng thái) là chia xẻ chung với nhau giữa các đối tượng cùng lớp. Chẳng hạn như: Mỗi một nhiệm kỳ, mọi ngư i dân Việt nam đều có chung một ông Ch tịch nước, như vậy thuộc tính ắtên ch tịch nướcẰ c a mỗi đối tượng ngư i Việt là loại biến lớp. Ví dụ khác sinh động hơn là trong các trò chơi (games), chúng ta thư ng có kịch bản đối kháng giữa các nhóm đối tượng, nhóm đối tượng A đấu với nhóm các đối tượng B. Nếu số đối tượng A tồn tại trong hệ thống trong khi số đối tượng B không còn thì ta có thể kết luận ắBên A th ng bên BẰ. Như vậy việc đếm số lượng các đối tượng tồn tại c a mỗi loại trong hệ thống thực (run-time) cần phải sử dụng đến biến dùng chung này.

Ví d 4.7: Lớp giảng viên có ch a instance và class members

Hình 4.6: Minh họa thành viên thể hiện và thành viên lớp

//Filename: GiangVien.java

package ctu.vdlinh.chapter4;

class GiangVien {

private String maGV;

public String hoTen;

public Boolean gioiTinh = true; //Nam

public static String donViCQ = "Đại học Cần Thơ - CTU";

public void giangDay(String maHP) {

System.out.println("Giảng viên: " + maGV+ ", dạy mã số học phần " + maHP);

}

protected void nghienCuuKH() {

System.out.println("Nghiên cứu trong các lĩnh vực phù hợp.\n");

}

Page 55: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 45

public static void main(String[] args) {

System.out.println("Các giảng viên thuộc cơ quan chủ quản: "+ GiangVien.donViCQ +":\n");

GiangVien gv1 = new GiangVien();

gv1.maGV = "000001"; gv1.hoTen = "Trần Phước Đường";

gv1.giangDay("SH001"); gv1.nghienCuuKH();

GiangVien gv2 = new GiangVien();

gv2.maGV = "000002"; gv2.hoTen = "Võ Tòng Xuân";

gv2.giangDay("SH002"); gv2.nghienCuuKH();

GiangVien gv3 = new GiangVien();

gv3.maGV = "000514"; gv3.hoTen = "Phạm Thị Xuân Lộc";

gv3.gioiTinh = false; //Nữ

gv3.giangDay("CT106"); gv3.nghienCuuKH();

}

}

4.4 Ph ng thức dựng

Trong quá trình xây dựng lớp, chúng ta thư ng cài đặt các phương th c dựng c a nó. Phương th c dựng (constructors) được dùng để tạo mới một đối tượng, xác định giá trị ban đầu cho các thuộc tính c a đối tượng nếu có.

Trong một lớp có thể có nhiều phương th c dựng, tên c a mỗi phương th c dựng phải giống với tên lớp và là dạng th tục nên nó không có kiểu trả về (kiểu void).

Trong phương th c dụng, từ khóa this thư ng được sử dụng để phân biệt tên biến trư ng (variables ) với tên tham số hình th c (parametters) nếu chúng có tên giống nhau. Từ khóa this là một tham chiếu (reference to the current object) chỉ đến đối tượng hiện hành. Nó được dùng để phân biệt giữa biến thể hiện (instance variables) và các tham số hình th c khi chúng giống tên nhau

Sử dụng từ khóa super để tham chiếu tới đối tượng thuộc lớp cha. Nó được dùng để gọi các phương th c, các biến thành viên từ lớp cha. Trong Java có sẵn một phương th c dựng mặc định (không có tham số) và chúng ta có thể ghi chồng (overriding ) phương th c mặc định này.

Ví d 4.8: Lớp giảng viên có ch a instance, class members và có constructors

package ctu.vdlinh.chapter4;

class GiangVien {

private String maGV;

public String hoTen;

public Boolean gioiTinh = true;

public static String donViCQ = "CTU";

Page 56: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 46

public void giangDay(String maHP) {

System.out.println("Giảng viên: " + maGV+ ", dạy mã số học phần " + maHP);

}

protected void nghienCuuKH() {

System.out.println("Nghiên cứu trong các lĩnh vực phù hợp.\n");

}

public GiangVien(String maGV, String hoTen, Boolean gioiTinh, String dvcq) {

super();

this.maGV = maGV;

this.hoTen = hoTen;

this.gioiTinh = gioiTinh;

donViCQ = dvcq;

}

public static void main(String[] args) {

GiangVien gv1 = new GiangVien("000001","Trần Phước Đường", true,"Cantho university." );

gv1.giangDay("SH001"); gv1.nghienCuuKH();

GiangVien gv2 = new GiangVien("000002","Võ Tòng Xuân", true,"Angiang university." );

gv2.giangDay("SH002"); gv2.nghienCuuKH();

GiangVien gv3 = new GiangVien("000514","Phạm Thị Xuân Lộc", false, "Đại học Cần Thơ." ;

gv3.gioiTinh = false; //Nữ

gv3.giangDay("CT106"); gv3.nghienCuuKH();

System.out.println("Các thầy cô trên đều đã cùng 0 cơ quan chủ quản là: "+GiangVien.donViCQ);

}

}

4.5 Ph ng thức ghi vƠ đ c

Thông thư ng, các biến trư ng sẽ được đóng gói với modifiers các m c độ khác nhau. Để cập nhật và truy xuất chúng, ta thư ng dùng đến các phương th c đọc, ghi để định nghĩa ra một kênh giao tiếp (từ bên ngoài) tới chúng được an toàn và bảo mật. Do vậy phạm vi truy cập c a các phương th c này thư ng là public.

Page 57: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 47

Các phương th c ghi (setters) còn được gọi là phương th c thay đổi (mutator methods), chúng được dùng để thiết lập các giá trị cho các biến trư ng. Trong quá trình gán giá trị, cần có sự kiểm tra tính hợp lệ dữ liệu trước để an toàn hơn. Còn các phương th c đọc (setters), hay được gọi là phương th c truy xuất (accessor methods), chúng được dùng để lấy (get) giá trị c a các biến trư ng.

Thông thư ng, mỗi một biến thành viên bổ từ truy cập là private sẽ có một cặp phương th c getter, setter.

Ví d 4.9: Sử dụng phương các phương th c set/getters để đọc và ghi các biến thể hiện hiện có bổ từ truy cập private

/**

* file name: LopChinh.java

*/

package ctu.vdlinh.chapter4;

class HinhTron {

int x = 50, y = 50; //tọa độ tâm x, y

private double bk; //bán kính

public HinhTron(double bk) {

this.bk = bk;

}

public HinhTron(int x, int y, double bk) {

super();

this.x = x; this.y = y; this.bk = bk;

}

public double getBk() {

return bk;

}

public void setBk(double bk) {

if (bk < 0.0) {

System.err.println("Bán kính phải có giá trị dương. " ;

}

this.bk = bk;

}

public double tinhDienTich() {

return Math.PI * Math.pow(bk, 2);

}

}

Page 58: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 48

public class LopChinh {

public static void main(String[] args) {

HinhTron ht1 = new HinhTron(20, 20, 10.379); //bk = 10.379

System.out.printf("Diện tích hình tròn với bán kính= %.2f là: %.2f\n", ht1.getBk(), ht1.tinhDienTich());

ht .setBk . ; // đổi bk = 5.5

System.out.printf("Diện tích hình tròn với bán kính= %.2f là: %.2f\n", ht1.getBk(), ht1.tinhDienTich());

}

}

4.6 Ph ng thức hủy

Khác với C and C++, sự thu hồi bộ nhớ được Java tự động thực hiện b i Garbage collector, giúp cho ta thực hiện các yêu cầu trước khi đối tượng bị h y (destructors), đó phương th c finalize(). Ta có thể ghi chồng lại phương th c finalize() này để quản lý các đối tượng trong chương trình.

Ví d 4.10: Viết chương trình để định nghĩa kiểu lớp Circle, sau đó đếm số đối tượng được tạo ra/ được huỷ khi chạy chương trình.

package ctu.vdlinh.chapter4;

/**

* Created date: 17-01-2011

* File name: DemDoiTuong.java

*/ class Circle {

private int x, y; double radius; // biến thể hiện

private static int numOfCircles = 0; // biến lớp

/* ---------- Một số phương thức thể hiện ------------ */

public Circle() {

super();

x = y =1; radius = 0.5;

numOfCircles++;

}

public Circle(int x, int y, double radius) {

super();

this.x = x; this.y = y;

Page 59: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 49

this.radius = radius;

numOfCircles++;

}

public double getRadius() {

return radius;

}

public void setRadius(double radius) {

this.radius = radius;

}

public static int getNumOfCircle() {

return numOfCircles;

}

public double circumference() {

return (get_2Pi() * radius);

}

void showInfo(String name){

System.out.printf(name + "bán kính = %5.2f, và chu vi = %10.4f \n", getRadius(), circumference());

}

protected void finalize() throws Throwable {

super.finalize();

--numOfCircles;

}

/* ---------- Một số phương thức lớp ------------ */

public static void setNumOfCircles(int numOfCircles) {

Circle.numOfCircles = numOfCircles;

}

private static double get_2Pi() {

return 2 * Math.PI;

}

}

public class DemDoiTuong {

public static void main(String[] args) {

Circle c1 = new Circle();

Page 60: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 50

Circle c2 = new Circle(1, 20, 4.50);

Circle c3 = new Circle(50, 50, 12.25);

Circle c4 = new Circle(100, 50, 7.80);

System.out.println("Số đối tượng được tạo là: " + Circle.getNumOfCircle());

c1.showInfo("Hình tròn c1 có: ");

c2.showInfo("Hình tròn c2 có: ");

c3.showInfo("Hình tròn c3 có: ");

c4.showInfo("Hình tròn c4 có: ");

c3 = null;

Runtime.getRuntime().gc(); // System.gc();

System.runFinalization();

System.out.println("Số đối tượng còn lại sau khi hủy là: "+ Circle.getNumOfCircle());

}

}

4.7 Truy n tham s

Khi gọi phương th c có ch a tham số, ta cần phải truyền đối số cho nó. Trong Java, vì không có khái niệm con trỏ, nên tất cả các kiểu dữ liệu đều được truyền b ng tham trị (Pass by value).

Đối với biến kiểu nguyên th y (Primitive type variable): Khi ta ra l i gọi phương th c thì Java sẽ tạo một bản sao c a biến tham số thực và bản sao này sẽ truyền cho tham số hình th c giá trị c a biến bản sao tham số thực này sẽ b ng với giá trị c a biến tham số hình th c nhưng không ảnh hư ng đến giá trị c a tham số thực ban đầu.

Đối với biến kiểu tham chiếu/ đối tượng (Reference/ Object type variable): Java cũng truyền đối số b ng trị, nghĩa là giá trị (c a) biến tham chiếu c a tham số thực sẽ được truyền cho biến tham chiếu c a tham số hình th c. Như vậy, biến tham số thực và tham số hình th c đều tham chiếu đến cùng một đối tượng nên giá trị c a chúng sẽ ảnh hư ng đến nhau.

Ví d 4.11: Minh họa truyền tham số đối với kiểu nguyên th y và đối tượng.

package ctu.vdlinh.chapter4;

Page 61: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 51

/**

* Created date: 17-01-2011

* File name: PassParametters.java

*/

class HinhTron {

private int bk;

private String trThai;

public void setBk(int bk) {

this.bk = bk;

}

public void setTrThai(String trThai) {

this.trThai = trThai;

}

@Override

public String toString() {

return "trạng thái: \"" + trThai + "\" và bán kính= " + bk;

}

}

public class PassParametters {

static void passByObject(HinhTron ht2) {

ht .setTrThai "Đã cập nhật!" ; // thay đổi giá trị

ht2.setBk(400);

}

static void passByPrimitive(int a) {

a = 00; // thay đổi giá trị của tsht

}

public static void main(String[] args) {

int x = 100; // tham số thực

System.out.println("<*> Truyền tham số đối với kiểu nguyên thủy:");

System.out.println("\t>>> Trước khi gọi phương thức passByPrimitive, x= " + x);

passByPrimitive(x);

System.out.println("\t>>> Sau khi gọi phương thức passByPrimitive, x= " + x);

Page 62: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 52

System.out.println("\n<*> Truyền tham số đối với kiểu đối tượng:");

HinhTron ht1 = new HinhTron(); // tham số thực

ht .setTrThai "Ban đầu.");

ht1.setBk(300);

System.out.println("\t>>> Trước khi gọi phương thức passByObject, ht1:\n\t\t " + ht1.toString());

passByObject(ht1);

System.out.println("\n\t>>>Sau khi gọi phương thức passByObject,ht1:\n\t\t "+ ht1.toString());

}

}

Kết quả chương trình:

Sau đây là hình minh họa cho việc truyền đối với kiểu nguyên th y và kiểu đối tượng

trong ngôn ngữ Java

Hình 4.7: Minh họa truyền tham số cho kiểu nguyên th y và đối tượng

Page 63: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 53

Ví d 4.12: Định nghĩa một lớp ngư i dùng số thực (Complex), rồi sử dụng nó để tính một phép tính cụ thể.

//File: Complex.java

package ctu.vdlinh.chapter4;

/**

* @author Robert Sedgewick

* @author Kenvin Wayne

* website: www.princeton.edu

*/

public class Complex {

private final double re; // the real part

private final double im; // the imaginary part

// create a new object with the given real and imaginary parts

public Complex(double real, double imag) {

re = real;

im = imag;

}

// return a string representation of the invoking Complex object

public String toString() {

if (im == 0) return re + "";

if (re == 0) return im + "i";

if (im < 0) return re + " - " + (-im) + "i";

return re + " + " + im + "i";

}

// return abs/modulus/magnitude and angle/phase/argument

public double abs() {

// Math.sqrt(re*re + im*im)

return Math.hypot(re, im);

}

public double phase() {

// between -pi and pi

return Math.atan2(im, re);

}

Page 64: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 54

// return a new Complex object whose value is (this + b)

public Complex plus(Complex b) {

Complex a = this; // invoking object

double real = a.re + b.re;

double imag = a.im + b.im;

return new Complex(real, imag);

}

// return a new Complex object whose value is (this - b)

public Complex minus(Complex b) {

Complex a = this;

double real = a.re - b.re;

double imag = a.im - b.im;

return new Complex(real, imag);

}

// return a new Complex object whose value is (this * b)

public Complex times(Complex b) {

Complex a = this;

double real = a.re * b.re - a.im * b.im;

double imag = a.re * b.im + a.im * b.re;

return new Complex(real, imag);

}

// scalar multiplication

// return a new object whose value is (this * alpha)

public Complex times(double alpha) {

return new Complex(alpha * re, alpha * im);

}

// return a new Complex object whose value is the conjugate of this

public Complex conjugate() {

return new Complex(re, -im);

}

// return a new Complex object whose value is the reciprocal of this

public Complex reciprocal() {

double scale = re*re + im*im;

return new Complex(re / scale, -im / scale);

}

Page 65: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 55

// return the real or imaginary part

public double re() {

return re;

}

public double im() {

return im;

}

// return a / b

public Complex divides(Complex b) {

Complex a = this;

return a.times(b.reciprocal());

}

/* return a new Complex object whose value is the complex exponential of this */

public Complex exp() {

return new Complex(Math.exp(re) * Math.cos(im), Math.exp(re) * Math.sin(im));

}

/* return a new Complex object whose value is the complex sine of this */

public Complex sin() {

return new Complex(Math.sin(re) * Math.cosh(im), Math.cos(re) * Math.sinh(im));

}

/* return a new Complex object whose value is the complex cosine of this */

public Complex cos() {

return new Complex(Math.cos(re) * Math.cosh(im), -Math.sin(re) * Math.sinh(im));

}

/* return a new Complex object whose value is the complex tangent of this */

public Complex tan() {

return sin().divides(cos());

}

// a static version of plus

public static Complex plus(Complex a, Complex b) {

Page 66: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 56

double real = a.re + b.re;

double imag = a.im + b.im;

Complex sum = new Complex(real, imag);

return sum;

}

}

//File: ComplexTest.java

package ctu.vdlinh.chapter4;

/**

* website: www.princeton.edu

*

* Data type for complex numbers.

* The data type is "immutable" so once you create and initialize

* a Complex object, you cannot change it. The "final" keyword

* when declaring re and im enforces this rule, making it a

* compile-time error to change the .re or .im fields after

* they've been initialized.

*

*/

public class ComplexTest {

// sample client for testing

public static void main(String[] args) {

Complex a = new Complex(5.0, 6.0);

Complex b = new Complex(-3.0, 4.0);

System.out.println("a = " + a);

System.out.println("b = " + b);

System.out.println("Re(a) = " + a.re());

System.out.println("Im(a) = " + a.im());

System.out.println("b + a = " + b.plus(a));

System.out.println("a - b = " + a.minus(b));

System.out.println("a * b = " + a.times(b));

System.out.println("b * a = " + b.times(a));

System.out.println("a / b = " + a.divides(b));

System.out.println("(a / b) * b = " + a.divides(b).times(b));

Page 67: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 57

System.out.println("conj(a) = " + a.conjugate());

System.out.println("|a| = " + a.abs());

System.out.println("tan(a) = " + a.tan());

}

}

Kết quả chương trình: a = 5.0 + 6.0i

b = -3.0 + 4.0i

Re(a) = 5.0

Im(a) = 6.0

b + a = 2.0 + 10.0i

a - b = 8.0 + 2.0i

a * b = -39.0 + 2.0i

b * a = -39.0 + 2.0i

a / b = 0.36 - 1.52i

(a / b) * b = 5.0 + 6.0i

conj(a) = 5.0 - 6.0i

|a| = 7.810249675906654

tan(a) = -6.685231390246571E-6 + 1.0000103108981198i

4.8 Truy n thông đi p giữa các đ i t ng

Trong phương pháp lập trình hướng đối tượng, khi xây dựng mô hình các đối tượng, chúng ta cần phải xem xét đến những khả năng tương tác có thể có giữa chúng trong không gian bài toán đang xem xét. Sự tương tác này được thực hiện thông qua việc gửi yêu cầu, nhận và đáp ng yêu cầu giữa chúng. Sự yêu cầu và đáp ng yêu cầu như thế được thực hiện b i cơ chế truyền thông điệp (messages).

Hình 4.8: Sự tương tác giữa đối tượng Benjamin và Sean

Ví d 4.13: Trong hệ thống, các đối tượng sẽ tương tác với nhau theo một kịch bản sẵn có. Ví dụ như khách hàng Benjamin gửi một thông điệp đến cho ngư i bán hàng là Sean với yêu cầu ắTôi muốn đặt mua một bộ salon b ng da có 5 chỗ ngồi vào th 4 tuần tớiẰ. Tiếp đến, Sean sẽ xem xét xem có thể đáp ng được cho Benjamin không (chẳng hạn như gọi về cửa hàng, kiểm tra hàng và lịch trình,…) rồi sẽ thông báo kết quả đặt

Page 68: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 58

hàng lại cho anh ta là ắOk: Đồng ý, còn mặt hàng nàyẰ hoặc ắNot ok: Xin lỗi, mặt hàng này đã hếtẰ.

Hình 4.9: Sự tương tác giữa các đối tương bằng message

Với tình huống trong thế giới thực như trên, ta có cấu trúc lớp nhân viên, Customer, và lớp ngư i bán hàng, SalesPerson, như sau:

Class Customer

Attributes:

name

address

budget

Methods:

purchase() {send a purchase request to a salesperson}

getBudget() {return budget}

Class SalesPerson

Attributes:

name

Methods:

takeOrder() {

check with warehouse on stock availability

check with warehouse on delivery schedule

if ok then {

instruct warehouse to deliver stock(address, date)

return ok

}

else return not ok

}

Với lớp Customer, tạo ra đối tượng khách hàng có tên là ắBenjaminẰ như sau:

Page 69: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 59

Benjamin as an Object

Attributes:

name = "Benjamin"

address = "1, Robinson Road"

budget = 2000

Methods:

getBudget() {return budget}

purchase() {send a purchase request to a salesperson}

Với lớp SalesPerson, tạo ra đối tượng và 02 đối tượng bán hàng là ắSeanẰ và ắSaraẰ như sau:

Sean as an Object

Attributes:

name = "Sean"

Methods:

takeOrder() {

check with warehouse on stock availability

check with warehouse on delivery schedule

if ok then {

instruct warehouse to deliver stock(address, date)

return ok

} else return not ok

}

Sara as an Object

Attributes:

name = "Sara"

Methods:

takeOrder() {

check with warehouse on stock availability

check with warehouse on delivery schedule

if ok then {

instruct warehouse to deliver stock(address, date)

return ok

Page 70: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 60

} else return not ok

}

Như vậy: Thông điệp là một l i gọi phương th c từ một đối tượng gửi thông điệp (message-sending object) tới đối tượng nhận thông điệp (message-receiving object). Đối tượng gửi thông điệp được gọi là sender còn đối tượng nhận thông điệp gọi là receiver. ví dụ trên, Ben là sender còn Sean là receiver.

Một thông điệp thì bao gồm 3 thành phần:

- Định danh c a đối tượng tiếp nhận thông điệp (receiver),

- Tên phương th c (c a đối tượng receiver),

- Và các đối số (arguments) được truyền vào để cung cấp thêm thông tin cần thiết để thực hiện phương th c trên.

Benjamin as an Object

Attributes:

name = "Benjamin"

address = "1, Robinson Road"

budget = 2000

Methods:

purchase() {

Sean.takeOrder("Benjamin", "sofa", "1, Robinson Road","12 November")

}

getBudget() {return budget}

Một thông điệp là hợp lệ nếu đối tượng receiver có một phương th c (method) tương ng với tên phương th c và các đối số phù hợp (nếu có) c a thông điệp. Như vậy, đối

tượng sender sẽ thực thi một phương th c nào đó, chẳng hạn purchase(){…}, mà trong đó có l i gọi một phương th c c a đối tượng reciever để truyền thông điệp như takeOrder(){…}.

Sean as an Object

Attributes:

name = "Sean"

Methods:

takeOrder(who, stock, address, date) {

check with warehouse on stock availability

check with warehouse on delivery schedule

if ok then {

instruct warehouse to deliver stock to address on date

return ok

Page 71: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 61

} else return not ok

}

Trong lập trìnhhướng đối tượng, đối tượng Benjamin và Sean được tuân theo nguyên t c che dấu thông tin (information hiding) vì Sean làm như thế nào để đáp ng được yêu cầu c a Benjamin là điều mà Benjamin không thể biết hoặc bị che khuất đi.

Mô hình khách – ch (client – server): Trong quá trình trao đổi thông tin đối tượng luôn có dạng mô hình này. Đối tượng sender là phía client còn reciever là phía server.

Hình 4.10: Quá trình liên lạc giữa các đối tượng theo mô hình client-server

Thông điệp mang lại 02 lợi ích quan trọng, đó là: Các hành vi c a một đối tượng được thể hiện thông qua phương th c c a nó, và do đó (ngoài truy cập biến trực tiếp) nó hỗ trợ tất cả các tương tác có thể có giữa các đối tượng. Và đối tượng không cần phải trong cùng một quá trình (process) hoặc thậm chí trên cùng một máy để gửi và nhận thông điệp qua lại với nhau.

Các thông điệp này được sử dụng trong biểu đồ tương tác (interaction diagram) để thể hiện cho các đối tượng tương tác với nhau. Biểu đồ tương tác này là sự tổng quát hóa c a cả biểu đồ tuần tự (sequence diagram) và biểu đồ cộng tác (collaboration diagram) được chuyên biệt từ nó.

Hình 4.11: Minh họa messages trong sơ đồ tuần tự (Source: Tech-ICT.com)

Page 72: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 62

4.9 Gói

Gói (package) là một cách để gom chung các kiểu dữ liệu (lớp, giao diện,…) có liên hệ với nhau thành một nhóm với phạm vi quyền truy xuất nhất định - việc quan trọng đối với những dự án phát triển theo phương pháp lập trình hướng đối tượng. Ngoài ra, nó còn được dùng để phân vùng không gian tên (name space) để tránh xung đột tên (name) trong quá trình viết mã lệnh.

Hình 4.12: Ký hiệu UML c a package

Hệ thống phân cấp c a package được xác định thông qua từ khóa package thư ng đ ng trước việc định nghĩa cho một lớp.

Cú pháp: package tên_gói[.tên_gói_con];

class MyClass{

//members

}

Ví d 4.14: Tạo lớp MyStack thuộc vào gói mypackage.core

package mypackage.core;

class MyStack{

//members

}

Để sử dụng lớp vừa đình nghĩa trong một package, ta sử dụng từ khóa import để nạp chúng vào lớp/giao diện hiện hành, UsingMyStack, ta sử dụng một trong các cách sau:

Nạp tất cả các lớp trong package core vào lớp hiện hành UsingMyStack:

import mypackage.core.*;

class UsingMyStack{

//members

}

Hoặc chỉ nạp lớp MyStack vào lớp UsingMyStack như lệnh sau:

import mypackage.core. MyStack;

Hoặc truy xuất trực tiếp chúng thông qua dấu chấm phân cách trong hệ thống phân cấp c a gói:

class UsingMyStack{

Page 73: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 63

mypackage.core. MyStack myStack = new mypackage.core. MyStack();

}

Khi sử dụng gói, dự án cần phải được xác định phạm vi truy cập m c lớp, m c các thành viên lớp/giao diện c a các gói sao cho cho có thể truy xuất được với nhau.

Dưới đây là bảng phạm vi truy cập giữa c a chúng:

Ví d 4.15: Viết chương trình giải phương trình bậc 2 gồm hai lớp được đặt trong

hai gói khác nhau như hình 4.12

Hình 4.12: Cấu trúc dự án giải phương trình bậc hai

//file PTB2.java

package ctu.vdlinh.obp.package1;

public class PTB2 {

private double a, b, c;

public PTB2(double a, double b, double c) {

Page 74: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 64

this.a = a;

this.b = b;

this.c = c;

}

public void tinhPTB2() {

if (a == 0) {

if (b == 0) {

if (c == 0) {

System.out.println "Phương trình vô số nghiệm.");

} else {

System.out.println "Phương trình vô nghiệm.");

}

} else {

System.out.printf "Phương trình có nghiệm x= %.2f", -c / b);

}

} else {

double delta = (b * b) - (4 * a * c);

if (delta == 0) {

System.out.printf "Phương trình có nghiệm kép x1= x2= %.2f ", -b / (2 * a));

} else if (delta > 0) {

double x1 = (-b + Math.sqrt(delta)) / (2 * a);

double x2 = (-b - Math.sqrt(delta)) / (2 * a);

System.out.printf "Phương trình có nghiệm x1=%.2f, x2= %.2f ", x1, x2);

} else {

System.out.println "Phương trình nghiệm ảo.");

}

}

}

}

//File: MainClass.java

package ctu.vdlinh.obp.package2;

import java.util.Scanner;

Page 75: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 65

import ctu.vdlinh.obp.package1.PTB2;

public class MainClass {

public static void main(String[] args) {

Scanner in = new Scanner(System.in);

System.out.print("Nhập hệ số a= ");

double a = in.nextDouble();

System.out.print("Nhập hệ số b= ");

double b = in.nextDouble();

System.out.print("Nhập hệ số c= ");

double c = in.nextDouble();

in.close();

PTB2 ptb2 = new PTB2(a, b, c);

ptb2.tinhPTB2();

}

}

Minh họa kết quả chương trình: Nhập hệ số a= 3

Nhập hệ số b= 2

Nhập hệ số c= -1

Phương trình có nghiệm x1=0.33, x2= -1.00

Bài t p ch ng 4

Bài 4.1: Hãy trừu tượng để xây dựng mô hình đối tượng gồm hai lớp: Lớp số ph c và lớp phương trình bậc 2 để giải phương trình bậc 2 (có xét nghiệm ảo). Vẽ sơ đồ lớp và viết chương trình hoàn chỉnh.

Bài 4.1: Hãy trừu tượng để xây dựng mô hình cho bài toán trùng phương thông qua ít nhất hai lớp là: Lớp giải phương trình bậc nhất, lớp giải phương trình bậc 2,... được đặt trong một dự án có 2 package khác nhau. Hãy vẽ mô hình lớp và viết chương trình hoàn chỉnh b ng ngôn ngữ Java.

Bài 4.3: Hãy trừu tượng hóa để xây dựng sơ đồ lớp cho bài toán tính diện tích, chu vi c a các hình tròn, hình vuông, hình bình hành. Viết chương trình hoàn chỉnh b ng ngôn ngữ Java.

Bài 4.4: Hãy trừu tượng hóa để định nghĩa ra lớp phép tính một ngôi và lớp phép tính hai ngôi. Viết thêm lớp chính để sử dụng hai lớp vừa được định nghĩa trên cho một vài phép tính cụ thể.

Page 76: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 66

Bài 4.5: Dựa vào sự trừu tượng hóa c a bài tập 3.2, hãy minh họa những thông điệp có thể có giữa các đối tượng khi tương tác với nhau: Sinh viên, giảng viên, môn học b ng một trong các cách sau:

a. Ngôn ngữ tự nhiên b. Sơ đồ tuần tự

Page 77: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 67

Ch ng 5. Mảng chuẩn, l p Arrays và khung n n t p h p Java

Chương này đề cập đến các kiến th c về mảng chuẩn, lớp mảng và khung nền tập hợp (Collections framework) như ArrayLish, HashMap,… Chúng được sử dụng phổ biến trong giáo trình để minh họa sự cho các mối kết hợp giữa các lớp cũng như tập hợp các đối tượng. Ngoài ra, giáo trình cũng trình cả kiểu tập hợp tổng quát (Generic collections) để giúp cho việc viết chương trình được cập nhật theo các bộ JDK c a Java.

5.1 Mảng chuẩn

Mảng chuẩn (array): Là một kiểu dữ liệu có cấu trúc, gồm một dãy liên tục hữu hạn các phần tử cùng kiểu và được đại diện chung một tên biến. Kích thước c a mảng là cố định và được xác định tại th i điểm kh i tạo và cấp phát bộ nhớ thông qua toán tử new. Để thuận tiện, ta hiểu ngầm mảng là mảng chuẩn hay array.

Hình 5.1 Mảng một chiều

Vì Java xem mảng là kiểu dữ liệu tham chiếu/ đối tượng, nên nó phải được khai báo và kh i tạo trước khi sử dụng. Giá trị (value) mỗi phần tử được lưu trữ một chỉ số index (vị trí) cụ thể, chỉ số đầu tiên b t đầu từ 0.

5.1.2 Mảng m t chi u

Mảng một chiều có thể được hiểu như một danh sách các phần tử có cùng kiểu. Mỗi phần tử c a mảng được xác định và được truy nhập trực tiếp thông qua tên mảng cùng với chỉ dẫn truy nhập được để giữa hai ngoặc vuông [ ].

Cú pháp khai báo mảng m t chi u:

kiểu_dữ_liệu[] tênBiến; // phổ biến

hoặc: kiểu_dữ_liệu tênBiến[]; // ít phổ biến hơn

Ví d 5.1: int[] myIntArray;

Double myDoubleArray[];

Kh i tạo mảng: Mảng trước khi dùng để lưu dữ liệu cần phải được cấp phát bộ nhớ, kích thước c a mảng sẽ được xác định khi kh i tạo thông qua từ khóa new.

Cú pháp khởi t o:

Kiểu_dữ_liệu[] tênBiến = new Kiểu_dữ_liệu [Kích_thước]

Page 78: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 68

Hình 5.2 minh họa mảng một chiều myList đã được khai báo, kh i tạo và gán giá trị vào 10 phần tử kiểu số thực.

Hình 5.2 Khởi tạo giá trị mảng

Ví d 5.2: Khai báo và kh i tạo biến báo biến với các giá trị mặc định

double[] myList = new double[10]; // tạo mảng 10 phần tử

GiangVien[] bmTHUD = new GiangVien[15]; //15 giảng viên

Hoặc gán các giá trị cụ thể (không cần sử dụng new):

double[] myList = {5.6, 4.5, 3.3, 13.2, 4.0, 34.33, 34.0, 45.45, 99.99};

Ví d 5.3: Viết chương trình nhập vào một mảng 10 số thực. Hãy in dãy số vừa nhập, giá trị nhỏ nhất, lớn nhất và trung bình c a dãy.

// File: Array1DTest.java

package ctu.vdlinh.chapter5;

import java.util.Scanner;

public class Array1DTest {

public static void main(String[] args) {

Scanner input = new Scanner(System.in);

System.out.printf("Hãy nhập kích thức mảng, n= ");

int n = input.nextInt();

double[] myArr1D = new double[n];

for (int i = 0; i < n; i++) {

System.out.printf("Nhập myArr1D[%d]= ", i);

myArr1D[i] = input.nextDouble();

}

input.close();

double min = myArr1D[0], max = myArr1D[0], avg = myArr1D[0];

System.out.print("In mảng vừa nhập: \n" + myArr1D[0]);

Page 79: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 69

for (int i = 1; i < myArr1D.length; i++) {

if (min > myArr1D[i]) min = myArr1D[i];

if (max < myArr1D[i]) max = myArr1D[i];

avg += myArr1D[i];

System.out.print("\t" + myArr1D[i]);

}

System.out.printf("\nGiá trị nhỏ nhất: %.2f, lớn nhất:"

+ " %.2f, và trung bình= %.2f ", min, max, avg/n);

}

}

Kết quả chạy thử chương trình: Hãy nhập kích thức mảng, n= 5

Nhập myArr1D[0]= 12.5

Nhập myArr1D[1]= 23.4

Nhập myArr1D[2]= 15

Nhập myArr1D[3]= 8.5

Nhập myArr1D[4]= 20.7

In mảng vừa nhập:

12.5 23.4 15.0 8.520.7

Giá trị nhỏ nhất: 8.50, lớn nhất: 23.40, và trung bình= 16.02

5.1.3 Mảng nhi u chi u

Mảng nhiều chiều được xem như là mảng c a các mảng. Hình dưới đây minh họa mảng hai chiều a và các giá trị c a chúng.

Hình 5.3: Mảng hai chiều số nguyên © Robert Sedgewick, Kenvin Wayne

Page 80: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 70

Cú pháp khai báo mảng hai chi u:

KiểuDữLiệu[][] tênBiến;

Hoặc: Kiểu[][] tênBiến = new KiểuDữLiệu[KíchThước1][KíchThước2];

Ví d 5.4: Các khai báo và cấp phát bộ nhớ

int[][] mang2Chieu; //chưa cấp pháp bộ nhớ

double[][] a = new double[2][3];

double b[][] = new double[2][3];

double[][] c = new double[2][];

float[][] fArr; fArr = new float[2][3];

int[][] mang2D = { {12, 08, 67}, {78,10, 100}}

Ví d 5.5: Viết chương trình tạo ra một mảng 2 chiều có số lượng phần tử trên mỗi hàng khác nhau: hàng th nhất có 3 phần tử, hàng th hai có hai và hàng th ba có 5 phần tử (xem hình 5.4), giá trị c a chúng được nhập từ bàn phím.

Hình 5.4: Mảng hai chiều

Page 81: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 71

Chạy thử chương trình ta có kết quả như sau:

5.1.4 Truy n tham s bằng mảng

Có nghĩa là truyền theo cách tham trị cho kiểu dữ liệu tham chiếu/ đối tượng mảng: giá trị c a tham số thực sẽ cập nhật theo giá trị c a tham số hình th c.

Ví d 5.6: Viết chương trình thể hiện việc truyền tham số b ng đối tượng mảng để thay đổi các giá trị c a c a mảng b ng l i gọi phương th c.

Page 82: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 72

Ch y và kiểm thử k t quả:

5.1.5 L p mảng Arrays

Lớp Arrays trong Java thuộc vào gói java.util, trong đó, cung cấp các phương th c lớp (static) để thao tác trên mảng chẳng hạn như s p xếp (sort), tìm kiếm (binarySearch), sao chép (copy),… được thuận tiện dễ dàng hơn.

Ví d 5.7: Minh họa cách sử dụng các phương th c lớp c a lớp Arrays

//File name: ArraysClassDemo.java

package ctu.vdlinh.chapter5;

import java.util.Arrays;

public class ArraysClassDemo {

public static void main(String[] args) {

float floatArray[] = { 5.2f, 7.5f, 10.7f, 12.2f, 3.2f };

Page 83: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 73

System.out.println("Mảng ban đầu: "+ Arrays.toString(floatArray));

Arrays.sort(floatArray);

System.out.println("Mảng đã sắp xếp: "+ Arrays.toString(floatArray));

float k = 7.5f;

System.out.println("Vị trí của "+k+" trong mảng là: " + Arrays.binarySearch(floatArray, k ));

k = 10.5f;

System.out.println("Vị trí của "+k+" trong mảng là: " + Arrays.binarySearch(floatArray, k ));

Arrays.fill(floatArray, 2, 4, -5.5f);

System.out.println("Mảng đã ghi đè filled : " + Arrays.toString(floatArray));

}

} K t quả:

Mảng ban đầu: [5.2, 7.5, 10.7, 12.2, 3.2]

Mảng đã sắp xếp: [3.2, 5.2, 7.5, 10.7, 12.2]

Vị trí của 7.5 trong mảng là: 2

Vị trí của 10.5 trong mảng là: -4

Mảng đã ghi đè filled : [ . , . , -5.5, -5.5, 12.2] 5.2 Khung n n t p h p Java

5.2.1 Gi i thi u

Một tập hợp Java (Java collection) - đôi khi được gọi là một container - là một đối tượng mà nó nhóm nhiều phần tử (elements) vào trong một đơn vị (unit) duy nhất. Collections được sử dụng để lưu trữ, truy xuất, thao tác, và giao tiếp dữ liệu tổng hợp (aggregate data). Ví dụ như một bộ tập c a thẻ (collection of cards), một tập thư (collection of letters), hoặc một danh bạ điện thoại (collection of telephones), …

Nền tảng tập hợp Java (Java collections framework) : Là một kiến trúc thống nhất để đại diện và thao tác các collections.

Hình 5.5: Các giao diện collection chính.

Page 84: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 74

Tất cả các Collections framework đều ch a các nội dung chính sau:

- Giao diện (interface): Đây là những kiểu dữ liệu trừu tượng để đại diện cho collections. Giao diện cho phép các collections được điều khiển, chế tác một cách độc lập với những chi tiết mà chúng đại diện.

- Sự cài đặt (implementations): Là việc triển cài đặt cụ thể cho các lớp thực thi từ các giao diện collections (Collection interfaces) . Về bản chất, chúng là các cấu trúc dữ liệu tái sử dụng.

Hình 5.6: Collection interfaces và các lớp cài đặt (cụ thể)

- Thuật toán (algorithms): Đây là những phương th c hữu ích cho việc thực hiện tính toán (như tìm kiếm và s p xếp) trên các đối tượng mà cài đặt từ các giao diện collections. Các thuật toán là đa hình nên các phương th c cùng tên có thể được sử dụng trên nhiều sự cài đặt khác nhau từ một giao diện collection phù hợp.

Trong Java Collections framework bao gồm những interface cơ bản như Collection<E>: Biểu thị cho nhóm các đối tựợng, những đối tượng này được gọi là phần tử c a tập hợp. Set<E>: là tập hợp mà không ch a những phần từ trùng nhau. List<E>: là tập hợp đã s p sếp và có thể ch a những phần tử trùng nhau. Và Map<E>: là đối tựợng mà ánh xạ các khoá vào các giá trị và không ch a những khoá trùng nhau.

5.2.2 Danh sách mảng

Các mảng Java chuẩn là có độ dài cố định nên thư ng được gọi với tên là mảng tĩnh. Ngược lại, danh sách mảng (ArrayList) lại có kích thước co giãn được. Nghĩa là, tùy theo nhu cầu sử dụng mà ta có thể khai báo và cấp phát hoặc thu hồi bộ nhớ cho nó một cách linh hoạt tại th i điểm chạy chương trình (runtime) nên thư ng được gọi với tên là mảng động (giống như ngôn ngữ Delphi, C++,…). Điểm cần chú ý là ArrayList chỉ ch a đối tượng ch không chấp nhận ch a kiểu nguyên th y, trong khi đó mảng chuẩn có thể ch a cả hai.

Page 85: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 75

phiên bản từ Java 5, lập trình viên Java được hỗ trợ tính năng type-safe c a kiểu Generics nên được sử dụng rất phổ biến. Với Java 8, lớp ArrayList<E> trong Java kế thừa AbstractList<E> và thực thi từ các interface là List, RandomAccess, Cloneable, Serializable:

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable

Còn giao diện lặp (Iterator itnterface) cung cấp một số các phương th c để duyệt qua các phần tử bất kỳ tập hợp nào. Mỗi interface collection trong Java đều ch a một phương th c iterator để trả về một thực thể c a interface Iterator. Iterator có khả năng xoá những phần từ tập hợp trong quá trình lặp.

Ví d 5.8: Minh họa cách sử dụng mảng danh sách và Iterator

// File: ArrayListIteratorDemo.java

package ctu.vdlinh.chapter5;

import java.util.ArrayList;

import java.util.Iterator;

import java.util.List;

public class ArrayListIteratorDemo {

public static void main(String args[]) {

List<String> al = new ArrayList<String>();

al.add("Lập"); al.add("trình");

al.add "đối"); al.add "tượng");

System.out.println "Kích thước hiện tại của al: " + al.size());

al.add("C++"); al.add , "hướng");

System.out.println "Kích thước thay đổi khi thêm của al: " +al.size());

System.out.println("Nội dung của ArrayList là: "+ al);

al.remove(new String("C++")); // al.remove("C++");

al.add(al.size(), "Java");

//Sử dụng Iterator để duyệt các phân tử al

System.out.println("Nội dung của ArrayList thay đổi: ");

Iterator<String> itr = al.iterator();

while (itr.hasNext()) {

System.out.printf("%10s", itr.next());

}

// Chuyển sang mảng đối tượng String[]

String[] stringArrayObject = new String[al.size()];

Page 86: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 76

al.toArray(stringArrayObject);

System.out.println("\nNội dung của mảng String:");

for (String st : stringArrayObject)

System.out.printf("%10s", st);

}

}

Kết quả chương trình: Kích thước hiện tại của al: 4

Kích thước thay đổi khi thêm của al: 6

Nội dung của ArrayList là: [Lập, trình, hướng, đối, tượng, C++]

Nội dung của ArrayList thay đổi:

Lập trình hướng đối tượng Java

Nội dung của mảng String:

Lập trình hướng đối tượng Java

5.2.3 T p HashMap

Ví d 5.9: Sử dụng HashMap để thêm, xóa các đối tượng c a ngư i dùng định nghĩa (user define objects) package ctu.vdlinh.chapter5;

import java.util.HashMap;

import java.util.Set;

/**

* File name: MyDeleteKeyObject.java

* @author http://www.java2novice.com/

*/

public class MyDeleteKeyObject {

public static void main(String a[]) {

HashMap<Price, String> hm = new HashMap<Price, String>();

hm.put(new Price("Banana", 20), "Banana");

hm.put(new Price("Apple", 40), "Apple");

hm.put(new Price("Orange", 30), "Orange");

printMap(hm);

Price key = new Price("Banana", 20);

System.out.println("Deleting key...");

hm.remove(key);

Page 87: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 77

System.out.println("After deleting key:");

printMap(hm);

}

public static void printMap(HashMap<Price, String> map) {

Set<Price> keys = map.keySet();

for (Price p : keys) {

System.out.println(p + "==>" + map.get(p));

}

}

}

class Price {

private String item;

private int price;

public Price(String itm, int pr) {

this.item = itm; this.price = pr;

}

public int hashCode() {

int hashcode = 0; hashcode = price * 20;

hashcode += item.hashCode();

return hashcode;

}

public boolean equals(Object obj) {

if (obj instanceof Price) {

Price pp = (Price) obj;

return (pp.item.equals(this.item) && pp.price == this.price);

} else {

return false;

}

}

public String getItem() {

return item;

}

public void setItem(String item) {

this.item = item;

}

Page 88: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 78

public int getPrice() {

return price;

}

public void setPrice(int price) {

this.price = price;

}

public String toString() {

return "item: " + item + " price: " + price;

}

}

Kết quả chạy thử chương trình: item: Apple price: 40==>Apple

item: Orange price: 30==>Orange

item: Banana price: 20==>Banana

Deleting key...

After deleting key:

item: Apple price: 40==>Apple

item: Orange price: 30==>Orange

5.2.4 LinkedHashMap và LinkedHashSet

Ví d 5.10: Sử dụng LinkedHashMap và LinkedHashSet để quản lý các đối tượng tự định nghĩa. package ctu.vdlinh.chapter5;

import java.util.LinkedHashMap;

import java.util.LinkedHashSet;

import java.util.Map;

import java.util.Set;

/**

* File name: LinkedHashMapSetDemo.java

* @author https://www.caveofprogramming.com

*/

class Person {

private int id;

private String name;

public Person(int id, String name) {

Page 89: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 79

this.id = id; this.name = name;

}

public String toString() {

return "{ID is: " + id + "; name is: " + name + "}";

}

@Override

public int hashCode() {

final int prime = 31; int result = 1;

result = prime * result + id;

result = prime * result + ((name == null) ? 0 : name.hashCode());

return result;

}

public boolean equals(Object obj) {

if (this == obj) return true;

if (obj == null) return false;

if (getClass() != obj.getClass()) return false;

final Person other = (Person) obj;

if (id != other.id) return false;

if (name == null) {

if (other.name != null) return false;

} else if (!name.equals(other.name)) return false;

return true;

}

}

public class LinkedHashMapSetDemo {

public static void main(String[] args) {

System.out.println("Create some person objects:");

Person p1 = new Person(0, "Bob");

Person p2 = new Person(1, "Sue");

Person p3 = new Person(2, "Mike");

Person p4 = new Person(1, "Sue");

// Using LinkedHashMap

Map<Person, Integer> map = new LinkedHashMap<Person, Integer>();

map.put(p1, 1); map.put(p2, 2);

map.put(p3, 3); map.put(p4, 1);

Page 90: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 80

for (Person key : map.keySet()) {

System.out.println(key + ": " + map.get(key));

}

// Using LinkedHashSet

Set<Person> set = new LinkedHashSet<Person>();

set.add(p1); set.add(p2);

set.add(p3); set.add(p4);

System.out.println(set);

}

}

Kết quả chương trình: {ID is: 0; name is: Bob}: 1

{ID is: 1; name is: Sue}: 1

{ID is: 2; name is: Mike}: 3

[{ID is: 0; name is: Bob}, {ID is: 1; name is: Sue}, {ID is: 2; name is: Mike}]

Bài t p ch ng 5

Bài 5.1: Sử dụng mảng chuẩn, viết chương trình nhập vào một dãy n (n ≥ 5 ), số nguyên dương, tính trung bình cộng các số nguyên tố trong dãy n số đó.

Bài 5.2: Sử dụng mảng chuẩn, viết chương trình nhập vào một số n (n ≥ 5), tạo n số nguyên ngẫu nhiên có giá trị từ 10 đến 100. S p xếp dãy số theo th tự tăng dần (hoặc giảm dần) thông qua kiểu dữ liệu mảng.

Bài 5.3: Sử dụng mảng chuẩn 2 chiều, viết chương trình nhập vào mảng có 2 hàng, hàng th nhất có m (đối tượng) hình tròn với bán kính là tùy ý, hàng th hai có n hình vuông có cạnh dài tùy ý. Với hình tròn và hình vuông là lớp ngư i dùng tự định nghĩa để tính diện tích c a chúng và cho biết mỗi đơn vị tính c a diện tích hình tròn có giá 9000 đồng, c a diện tích hình vuông có giá 8000 đồng, hãy cho biết tổng tiền tương ng c a diện tích m hình tròn và n hình vuông trên.

Bài 5.4: Sử dụng kiểu ArrayList, viết chương trình nhập vào n đối tượng môn học với môn học gồm các thông tin là mã số và tên môn học. In ra màn hình các thông tin c a n môn học này.

Bài 5.5: Định nghĩa lớp Sinh viên, gồm có mã số, họ tên và ngày tháng năm sinh c a sinh viên, sử dụng kiểu dữ liệu tùy ý, viết chương trình nhập vào n đối tượng sinh viên. Hãy s p xếp n sinh viên này theo cách trư ng hợp sau:

- Theo mã số, - Theo họ tên - Theo ngày tháng năm sinh

Page 91: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 81

Ch ng 6. L p bao gói kiểu nguyên thủy, và các l p chuỗi ký tự

Chương này sẽ cung cấp cho ngư i học có thêm những kiến th c về các lớp được xây dựng sẵn trong Java, đó chính là các lớp bao kiểu cơ bản/nguyên th y và các lớp về chuỗi ký tự. Cũng như các chương 2 và chương 5, kiến th c c a chương này cũng nh m phục vụ cho việc học lập trình hướng đối tượng c a ngư i học được thuận tiện và cài đặt các dự án trong bài tập cũng như trong thực tế được dễ dàng hơn.

6. 1 L p bao kiểu nguyên thủy

Khi lập trình, có những trư ng hợp cần phải sử dụng đối tượng ch không phải là kiểu nguyên th y (như HashMap chẳng hạn) tgì chúng ta cần phải sử dụng lớp bao gói kiểu nguyên th y (wrapper class). Mỗi kiểu nguyên th y sẽ được Java hỗ trợ một lớp bao gói tương ng. Ví dụ kiểu nguyên th y int thì có lớp bao gói Integer, kiểu char tương

ng với lớp Character, kiểu boolean thì có lớp Boolean,…

Ngoài ra, các đối tượng thuộc lớp bao gói nguyên th y còn hỗ trợ nhiều phương th c cũng như các biến sẵn có, điều này giúp cho công việc lập trình được nhẹ nhàng và hiệu quả hơn.

Hình 6.1: Hệ thống phân cấp các lớp bao gói nguyên th y

Ví d 6.1: Khai báo hai biến số thực kiểu nguyên th y và số thực kiểu lớp số thực:

double diemTrBinh = 8.5; // kiểu nguyên th y double

Double diemTrB = new Double(8.5); // kiểu đối tượng c a lớp Double

Với biến diemTrBinh thì không có các phương th c cũng như thuộc tính kèm theo nhưng với biến tham chiếu diemTrB thì có sẵn các thuộc tính và các phương th c như minh họa hình 6.2.

Từ phiên bản Java 5 tr lên có hỗ trợ hai cơ chế chuyển đổi qua lại giữa kiểu nguyên th y và lớp bao gói nguyên th y, đó là autoboxing và unboxing. Trong đó: auto-boxing sẽ tự động chuyển đổi kiểu nguyên th y (int, float, double vv) thành các lớp bao gói nguyên th y tương ng (Integer, Float, Double, ...). Còn ngược lại với auto-boxing, auto-unboxing sẽ tự động chuyển đổi các lớp bao gói nguyên th y thành kiểu nguyên th y tương ng.

Page 92: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 82

Hình 6.2: Các biến và phương th c c a lớp Double

Ví d 6.2: Viết chương trình chia c a 2 số thực có sử dụng lớp Double và kỹ thuật auto-boxing và auto-unboxing.

//Filename: DoubleWrapperDemo.java

package ctu.vdlinh.chapter6;

import java.util.Scanner;

public class DoubleWrapperDemo {

public static void main(String[] args) {

Scanner in = new Scanner(System.in);

System.out.print("Nhập số thực d1= ");

double d1 = in.nextDouble();

System.out.print("Nhập số thực d2= ");

double d2 = in.nextDouble(); in.close();

Double wd = d1 / d2; // autoboxing

System.out.println("Kết quả của phép chia:");

if (wd.isInfinite())

System.out.printf("\t=> của 2 số thực %.2f /%.2f là bất định= %s ",d1,d2,wd);

else {

double d3 = wd; // auto-unboxing

System.out.printf("\t=> của 2 số thực %.2f /%.2f là xác định= %.2f ",d1,d2,d3);

}

}

}

Page 93: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 83

Kết quả chương trình: Nhập số thực d1= 10.5

Nhập số thực d2= 2.0

Kết quả của phép chia:

=> của 2 số thực 0. 0 / .00 là xác định= 5.25

Nhập số thực d1= 10.5

Nhập số thực d2= 0.0

Kết quả của phép chia:

=> của 2 số thực 10.50 /0.00 là bất định= Infinity

6.2 L p chuỗi ký tự String

Chuỗi là một dãy các ký tự. Khác với Delphi, C hoặc C++, Java xem chuỗi là một thể hiện c a lớp String ch không phải là một mảng các ký tự.

6.2.1 Khai báo và khởi t o

Có hai cách để khai báo và kh i tạo chuỗi ký tự

Cách 1: Sử dụng String literals

Đó là một dãy các ký tự được đặt trong cặp dấu nháy kép. Chuỗi literal là chuỗi mà giá trị c a nó thể hiện chính nó.

String tênBiến = literalString;

Ý nghĩa: Cách này sẽ sử dụng đ a chỉ vùng nh chung cho các biến chuỗi có giá trị chuỗi giống nhau.

Ví d 6.3: String hoTen1 = "Nguyễn Huệ"; // literalString: "Nguyễn Huệ"

String hoTen2 = "Nguyễn Huệ";

String hoTen3 = "Phan Bội Châu";

String monHoc = "Lập trình hướng đối tượng Java";

Cách 2: Sử dụng lớp String String tênBiến = new String ("Chuỗi cần tạo");

ụ nghĩa: Sử dụng đ a chỉ vùng nh riêng cho mỗi biến chuỗi.

Ví d 6.4: String hoTen4 = new String("Lý Thư ng Kiệt");

String hoTen5 = new String("Lý Thư ng Kiệt");

String hoTen6 = new String("Lê Lợi");

Ta có thể sử dụng cách vừa khai báo và kh i tạo tương ng cho String literals và String class cho tiện dụng hơn như cú pháp sau:

String tênBiếnChuỗi = "Chuỗi cần tạo";

String tênBiếnChuỗi = new String ("Chuỗi cần tạo");

String hocPhan = new String("Hướng đối tượng Java");

Page 94: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 84

Trong Java, đối tượng chuỗi có tính bất biến (Immutable) và không thể thay đổi giá trị khi chúng được tạo ra.

Để so sánh, ta cần chú ý đến việc so sánh giá trị c a chuỗi hay địa chỉ c a chúng. Ta sử dụng phương th c equals(Object anObject) để so sánh giá trị hai c a đối tượng: Trả về true nếu b ng và ngược lại trả về false. Còn so sánh địa chỉ đối tượng (địa chỉ reference ch a chuỗi) thì ta sử dụng toán tử so sánh b ng như firstObjectString == secondObjectString : Trả về true nếu địa chỉ c a hai đối tượng b ng nhau và ngược lại.

Ví d 6.5: Khai báo, kh i tạo, so sánh giá trị và địa chỉ c a các chuỗi

Kết quả chạy thử chương trình:

6.2.2 Truy n tham s bằng chuỗi String

Có nghĩa là truyền theo cách tham trị cho kiểu dữ liệu tham chiếu/ đối tượng chuỗi String. Tuy nhiên, do chuỗi String có tính bất biến, nên khi cần thay đổi một chuỗi String, Java luôn tạo ra một đối tượng chuỗi String mới với nội dung chuỗi đã được sửa đổi/cập nhật (và thư ng dùng một biến tham chiếu để chỉ đến đối tượng mới này).

Page 95: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 85

Do vậy, khi truyền đối tượng chuỗi String từ tham số thực (tham chiếu đối tượng chuỗi nguồn) tới tham số hình th c (tham chiếu đối tượng chuỗi đích) thì sẽ không làm thay đổi đối tượng chuỗi String ban đầu.

Ví d 6.6: Viết chương trình thể hiện việc truyền tham số b ng đối tượng mảng để thay đổi các giá trị c a c a mảng b ng l i gọi phương th c.

//Filename: PassStr.java

package ctu.vdlinh.chapter6;

public class PassStr {

static void kiemTra_Str(String tsht) {

tsht = new String("Chuỗi đã cập nhật!"); //cập nhật biến tsht

}

public static void main(String[] args) {

String tst = new String("Chuỗi ban đầu!");

System.out.println("Giá trị của tham sộ thực,, tst: ");

System.out.println("\t>> Trước khi ra lời gọi phương thức kiemTra_Str: " + tst);

kiemTra_Str(tst);

System.out.println("\t>>Sau khi phương thức kiemTra_Str hoàn thành: " + tst);

}

}

Ví d 6.7: Kiểm tra một từ có phải là Palindrome không?

Page 96: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 86

6.3 Chuỗi StringBuffer

Khác với chuỗi String khi tạo ra thì nội dung cố định, chuỗi StringBuffer khi được tạo ra thì có thể thay đổi được nên linh hoạt hơn.

StringBuffers là tuyến đoạn/luồng an toàn (thread-safe) vì đã đồng bộ các phương th c để kiểm soát việc truy cập: tại một th i điểm chỉ có một tuyến đoạn có thể truy cập vào StringBuffer. Do vậy, trong môi trư ng đa tuyến đoạn (multiple thread) các đối tượng StringBuffer thư ng an toàn để sử dụng.

Khi đối tượng StringBuffer được tạo ra ch a chuỗi ký tự: Độ dài c a chuỗi, String.length(), có thể khác với khả năng/s c ch a (capacity) c a StringBuffer, và ta có thể thay đổi độ dài c a nó b ng setLength(int newLength).

Các phương th c dựng thư ng dùng:

Page 97: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 87

new StringBuffer(): kh i tạo đối tượng StringBuffer có độ dài mặc định là 16 và không ch a ký tự nào cả.

new StringBuffer(int length): tương tự nhưng cấp phát bộ nhớ cho chuỗi ký tự có độ dài là length.

new StringBuffer(String s) ch a chuỗi s và có độ dài = 16 + s.length()

Ví d 6.6: Ví dụ về độ dài và s c ch a c a đối tượng StringBuffer

StringBuffer stringBuffer = new StringBuffer("Hello World");

System.out.println(stringBuffer.length()); // 11

System.out.println(stringBuffer.capacity()); // 27 = (11 + 16)

Có thể cập nhật thêm b ng phương th c append(…) , chèn insert(…), xóa delele(…) và sử dụng phương th c toString() để đổi StringBuffer sang String.

Ví d 6.7: Minh họa truyền tham số b ng đối tượng chuỗi StringBuffer

//Filename: PassStrBuffer.java

package ctu.vdlinh.chapter6;

public class PassStrBuffer {

static void kiemTra_Str(StringBuffer tsht) {

System.out.println("\t\tTrước khi cập nhật, tsht= "+ tsht);

tsht.delete(0,tsht.length()).append("Chuỗi ban đầu đã thay đổi!");

System.out.println("\t\ tSau khi cập nhật, tsht= "+ tsht);

}

public static void main(String[] args) {

StringBuffer tst = new StringBuffer("Chuỗi ban đầu!...");

System.out.println("Giá trị của tham số thực, tst: ");

System.out.println("\t>>Trước khi ra lời gọi kiemTra_Str: " + tst);

kiemTra_Str(tst);

System.out.println("\t>>Sau khi kiemTra_Str hoàn thành: " + tst);

}

}

6. 4 L p StringTokenizer

ng dụng: thư ng được dùng để tách từng nhóm ký tự (token) dựa vào (các) ký tự phân tách (delimiters) được xác định b i phương th c dựng c a nó.

Ví d 6.8: Kiểm tra một chuỗi (nhiều từ) có phải là Palindrome không?

Page 98: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 88

Bài t p ch ng 6

Bài 6.1: Sử dụng StringTokenizer, viết chương trình nhập vào một chuỗi bất kỳ, chuyển sang dạng proper (ký tự đầu mỗi từ là chữ hoa). Hãy cho biết tần số xuất hiện c a mỗi từ trong chuỗi.

Bài 6.2: Viết chương trình tạo địa chỉ email tự động cho một họ tên sinh viên và mã số sinh viên nào đó. Cách tạo địa chỉ email như sau: Chuyển họ tên thành chữ thư ng, lấy phần tên ghép với 7 ký số cuối c a mã sinh viên để tạo được phần user name, rồi lấy user name ghép với ký hiệu ằ@’ và tên miền (Mailserver) để thành một địa chỉ email. Chẳng hạn như: Họ tên là Phạm Thị Thy Ca, MSSV là b1101898 => Địa chỉ email được tạo là: [email protected].

Page 99: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 89

Ch ng 7. Bao đóng, m i k t h p và thừa k

Mô hình hóa hướng đối tượng được dựa trên 04 nguyên lý căn bản là: Bao đóng, trừu tượng (abstraction), thừa kế (inheritance), và đa hình (polymorphism). Chương này trình bày các kiến th c chính c a nội dung học phần hướng đối tượng đó là tính bao đóng, mối kết hợp Has-a, sự trừu tượng dựa trên phương pháp tổng quát hóa và chuyên biệt hóa để xác định mối liên kết Is-a giữa các lớp đối tượng.

7. 1 Tính bao đóng

Như đã được đề cập chương 3, tính bao đóng (encapsulation) là một trong những đặc điểm quan trọng c a lập trình hướng đối tượng, nó được dùng để ẩn đi các dữ liệu (fields) và chi tiết ph c tạp (logic) bên trong các hành vi (methods) c a đối tượng mà ngư i dùng không cần biết đến chúng.

Một ví dụ trong thực tế khi ngư i dùng mua chiếc Honda chẳng hạn, họ không cần phải biết block máy bên trong được sản xuất gồm những chi tiết gì, các chi tiết này g n kết như thế nào để vận hành được, mà thư ng chỉ quan tâm đến mẫu mã, màu s c, thương hiệu,… mà thôi. Như vậy ắBlock máyẰ được xem như là phần mà nhà sản xuất đóng gói lại hay che khuất đi, ngư i dùng chỉ cần biết đề xe, vô số, lên ga là chạy…

Phương pháp để thực hiện việc đóng gói là sử dụng các phương th c setters/ getters để thiết lập một cơ chế truy xuất đến các thuộc tính riêng cũng như các phương th c nội tại chi tiết bên trong c a đối tượng. Điều này đem lại lợi ích quan trọng là việc các đặt, sửa chữa nội dung bên trong lớp không ảnh hư ng đến các lớp khác liên quan.

Ví d 7.1: Hãy thiết kế và viết chương trình thể hiện tính bao đóng cho bài toán tìm dãy Fibonacci c a một số nguyên.

//File name: FibonacciTesting.java

package ctu.vdlinh.chapter7;

import java.io.IOException;

import javax.swing.JOptionPane;

class Fibonacci{

private int n;

private int[] fiboArr;

public void setN(int n) {

if(n<=0) System.out.printf("Lỗi: %d <0, không tính được Fibo!\n",n);

else {this.n = n; fiboArr = new int[n];}

}

public Fibonacci(int n) {

this.n = n; fiboArr = new int[n]; }

Page 100: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 90

private void tinhDayFibo(){

fiboArr[0] = fiboArr[1] = 1;

for (int i = 2; i < n; i++)

fiboArr[i] = fiboArr[i-2] + fiboArr[i-1];

}

public void inDayFibo() {

tinhDayFibo();

System.out.printf("Dãy Fibonacci(%d): \n",this.n);

for (int i = 0; i < fiboArr.length; i++) {

System.out.print(fiboArr[i]+" ");

}

System.out.println(); }

}

public class FibonacciTesting{

public static void main(String arg[])throws IOException {

int m = Integer.parseInt(

JOptionPane.showInputDialog(null,"Nhập m= ")); Fibonacci fi = new Fibonacci(m);

fi.inDayFibo();

m=-9; fi.setN(m); // thông báo lỗi m=15; fi.setN(m); // Ok

fi.inDayFibo();

}

}

Biên dịch, chạy có kết quả như sau: Dãy Fibonacci(5):

1 1 2 3 5

Lỗi: - <0, không tính được Fibo!

Dãy Fibonacci(15):

1 1 2 3 5 8 13 21 34 55 89 144 233 377 610

7.2 Các m i k t h p

Trong phương pháp lập trình đối tượng, việc mô hình hóa để xác định được mô hình đối tượng bao gồm các lớp đối tượng và các mối kết hợp (associations) giữa chúng là quan trọng nhất. Trong lập trình, mối kết hợp thư ng được sử dụng với thuật ngữ Có-m t (Has-a).

Page 101: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 91

Hình 7.1: Mối kết hợp giữa các lớp và mối liên kết giữa các đối tượng

Mối kết hợp (Associations): Mô tả mối liên kết thuộc về cấu trúc, tên c a mối liên được đặt theo dạng động từ và có gán các bản số (cardinalities). Hướng c a nó có thể một chiều hoặc hai chiều. Một số dạng khác nhau c a mối kết kết theo UML như sau:

Hình 7.2 Các dạng mối kết hợp

Mỗi mối kết hợp thư ng có tên (name) c a liên kết, tên vai trò (role name) c a mỗi lớp tới một lớp khác mà có liên kết với nó, và bản số (multiplicity) c a mỗi phía liên kết.

Hình 7.3: Các thông tin cần có c a mối kết hợp

Ví d 7.2: Giả sử có mối kết hợp như hình 7.4, ta có phát biểu như sau: Mỗi công ty (Company) có ít nhất một hoặc nhiều ngư i làm công (Person), và mỗi ngư i làm công có thể không làm công ty nào hết hoặc làm tối đa một công ty mà thôi. Nếu phát biểu theo tên vai trò thì: ắ Mỗi Company có nhiều employees, và mỗi Person sẽ có tối đa một employerẰ

Hình 7.4: Mối kết hợp giữa Company và Person

Page 102: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 92

Khi xác định các có mối kết hợp giữa các lớp, ta cần phân biệt rõ hai khái niệm về thuộc tính: thuộc tính c a lớp các đối tượng (attributes) và thuộc tính kết hợp (attribute associations) giữa các lớp đối tượng. Thuộc tính c a lớp đối tượng là dữ liệu được sử dụng để đại diện các đặc điểm c a các đối tượng cùng loại. Còn thuộc tính kết hợp (hoặc thuộc tính tham chiếu) được dùng để đại diện cho liên kết giữa một lớp các đối tượng này với một lớp các đối tượng khác. Trên sơ đồ UML, các thuộc tính kết hợp này chính là các role name và không được hiển thị tư ng minh (được hiểu ngầm ) như thuộc tính c a lớp các đối tượng.

Ví d 7.3: Minh họa thuộc tính đối tượng và thuộc tính kết hợp

Hình 7.5: Advertiser kết hợp một chiều tới Account

Trong lớp Advertiser có thuộc tính đối tượng được hiển thị tư ng minh private

String idAdvertiser và có một thuộc tính kết hợp ngầm định là private Account account.

Nó được dùng để lớp Advertiser liên kết tới lớp Account.

7.2.1 M i k t h p ph thu c

Mối kết hợp phụ thuộc (dependency) thư ng dùng để biểu diễn sự phụ thuộc c a lớp đối tượng này phụ thuộc vào lớp đối tượng khác.

Hình 7.6: Mối kết hợp phụ thuộc

Như hình 7.3 thể hiện mối phụ thuộc c a A phụ thuộc vào lớp B. Bản chất c a mối phụ thuộc này là khi thay đổi cấu trúc c a lớp được phụ thuộc B thì lớp phụ thuộc A sẽ bị ảnh hư ng theo. Mối phụ thuộc thể hiện b ng một tham chiếu (Has by reference ) từ lớp phụ thuộc A tới lớp được phụ thuộc B.

Trong lâp trình b ng ngôn ngữ Java, nó được cài đặt b ng cách là: từ một phương th c tùy ý trong lớp A có một phương th c để tạo một thể hiện c a lớp B, hoặc có một phương th c sử dụng một tham chiếu lớp B (chẳng hạn như kiểu c a tham số hình th c là lớp B) để gây ra sự phụ thuộc.

Ví d 7.4: Sơ đồ lớp hình 7.7 là mối quan hệ phụ thuộc c a lớp Xe hơi (Car) vào lớp Bánh xe (Wheel).

Hình 7.7: Car phụ thuộc Wheel

Page 103: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 93

Mã lệnh Java code sẽ như sau:

class Wheel {

private int size;

public void Wheel() {

//...

}

public void spin() {

//..

}

}

class Car {

private String model;

private String manufacturer;

public void Car() {

//...

}

public void doSth () {

Wheel wheel = new Wheel(); //tạo một thể hiện B

//Sử dụng phương thức trong wheel

}

public void turnRight(Wheel wheel) { //giữ tham chiếu tới Wheel //turn right...

}

public void useLeft(Wheel wheel) {

//turn left...

}

public void driveStraight(Wheel wheel) {

//go straight ahead...

wheel.spin(); //Sử dụng phương thức trong wheel

}

}

Page 104: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 94

7.3.2 M i k t h p

7.3.2.1 Mối kết hợp có hướng/một chiều

Hình 7.8: Mối kết hợp một chiều

Mối kết hợp một chiều (unidirectional association) này xuất hiện nhiều trong sơ đồ lớp. Nó thể hiện mối quan hệ từ A đến B, còn ngược lại thì không.

Ví d 7.5: Mối kết hợp có hướng 1 – 1 (unidirectional one-to-one association) giữa Nhà quảng cáo (Advertiser) và Tài khoản (Account).

Hình 7.9: Mối kết hợp 1-1 một chiều

Mã lệnh Java tương ng:

class Account{ //no usage of Advertiser

private String name;

//...

}

class Advertiser {

private String idAdvertiser; // thuộc tính của đối tượng

private Account account; // thuộc tính tham chiếu

public Advertiser(Account account) {

this.account = account;

}

public Account getAccount() {

return account;

}

}

Ví d 7.6: Mỗi Worker có một số điện thoại c a văn phòng và tùy ý có nhiều hoặc không có số điện thoại nhà.

Page 105: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 95

Hình 7.10: Hai mối kết hợp một chiều

Mã lệnh Java tương ng:

class Phone{

private String areaCode;

private String number;

// ...

}

class Worker {

private String ssn;

private String fullName;

private Phone officePhone;

private Collection<Phone> homePhones;

// hoặc sử dụng private Phone[] homePhones;

public void makeNewHomePhone() {

homePhones.add(new Phone("07103","856907"));

}

// ...

}

7.3.2.2 Mối kết hợp hai chiều

Mối kết hợp hai chiều (bidirectional association) có nghĩa là nó tương đương với hai mối kết hợp có hướng: từ A đến B và từ B đến A.

Hình 7.11: Mối kết hợp hai chiều

Ví d 7.7: Mối kết hợp 1–1 hai chiều (Bidirectional one-to-one association) giữa Nhà quảng cáo (Advertiser) và Tài khoản (Account).

Page 106: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 96

Hình 7.12: Mối liên kết 1-1 hai chiều

Mã lệnh Java tương ng:

class Advertiser {

private Account account;

public Advertiser() {

account = new Account();

}

public Account getAccount() {

return account;

}

}

class Account {

private Advertiser advertiser;

public Account(Advertiser advertiser) {

this.advertiser = advertiser;

}

public Advertiser getOwner() {

return advertiser;

}

}

Ví d 7.8: Mối kết hợp 1– nhiều hai chiều (Bidirectional one-to-many association), giả sử có mối quan hệ 1-nhiều qua lại giữa Nhà quảng cáo (Advertiser) và Tài khoản (Account).

Hình 7.13: Mối kết hợp hai chiều 1-nhiều

//File name: OneToManyTest.java

package ctu.vdlinh.chapter7;

import java.util.ArrayList;

Page 107: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 97

class Advertiser {

String idNumber;

String name;

private ArrayList<Account> accounts; //many

public Advertiser( ) {

accounts = new ArrayList<Account>();

}

Advertiser(String idNumber, String name) {

this.idNumber = idNumber;

this.name = name;

accounts = new ArrayList<Account>();

}

public String getIdNumber() {

return idNumber;

}

public void setIdNumber(String idNumber) {

this.idNumber = idNumber;

}

public void setName(String name) {

this.name = name;

}

public String getName() {

return name;

}

Advertiser(String name, ArrayList<Account> accounts) {

super();

this.name = name;

this.accounts = accounts;

}

public ArrayList<Account> getAccounts() {

return accounts;

}

public void setAccounts(ArrayList<Account> accounts) {

Page 108: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 98

this.accounts = accounts;

}

public void addAccount(Account account) {

accounts.add(account);

}

public void removeAccount(Account account) {

accounts.remove(account);

}

}

class Account {

String name;

private Advertiser advertiser; //one

Account(String name) {

this.name = name;

advertiser = new Advertiser();

}

Account(String name, Advertiser advertiser) {

this.name = name;

this.advertiser = advertiser;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public Advertiser getAdvertiser() {

return advertiser;

}

Page 109: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 99

public void setAdvertiser(Advertiser advertiser) {

this.advertiser = advertiser;

}

}

public class OneToManyTest {

public static void main(String[] args) {

Advertiser advertiser1 = new Advertiser("361487580","Nguyễn Nam Cường");

Account accACB = new Account("ACB");

Account accVCB = new Account("VCB");

Account accSGB = new Account("SGB");

advertiser1.addAccount(accACB);

advertiser1.addAccount(accVCB);

advertiser1.addAccount(accSGB);

System.out.print("1. Một Advertiser là "+ advertiser1.getName()+ " có nhiều tài khoản: ");

for (Account acc : advertiser1.getAccounts()) {

System.out.print( acc.getName()+"\t");

}

System.out.print("\n2. Mỗi Account chỉ thuộc một Advertiser: ");

Account accAgri = new Account("Agribank");

accAgri.getAdvertiser().setIdNumber("361487581");

accAgri.getAdvertiser().setName("Phạm Thị Thúy");

System.out.print(accAgri.getAdvertiser().idNumber+", "+ accAgri.getAdvertiser().name);

System.out.print("\n3. Mỗi Account chỉ thuộc một Advertiser: ");

Advertiser advertiser3 = new Advertiser("361487582","Phạm Bảo Quốc");

Account accTech = new Account("Techcombank", advertiser3);

System.out.print(accTech.getAdvertiser().idNumber+", " + accTech.getAdvertiser().name);

}

}

Page 110: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 100

Chạy có kết quả:

1. Một Advertiser là Nguyễn Nam Cường có nhiều tài khoản: ACB VCB SGB

2. Mỗi Account chỉ thuộc một Advertiser: 361487581, Phạm Thị Thúy

3. Mỗi Account chỉ thuộc một Advertiser: 361487582, Phạm Bảo Quốc Ví d 7.9: Mối liên kết hai chiều nhiều – nhiều (Bidirectional many-to-many

association) giữa giải đấu (Tournament ) và cầu th ( Player)

Hình 7.14: Mối kết hợp hai chiều nhiều-nhiều

Mã lệnh Java tương ng:

class Tournament {

private ArrayList<Player> players; //many

public Tournament() {

players = new ArrayList<Player>();

}

public void addPlayer(Player p) {

if (!players.contains(p)) {

players.add(p);

p.addTournament(this);

}

}

}

class Player {

private ArrayList<Tournament> tournaments; //many

public Player() {

tournaments = new ArrayList<Tournament> ();

}

public void addTournament(Tournament tournmt) {

if (!tournaments.contains(tournmt)) {

tournaments.add(tournmt);

t.addPlayer(this);

Page 111: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 101

}

}

}

7.3.3 M i k t h p h n đ nh

Mối kết hợp này (qualified association) được sử dụng để rút gọn số lượng bản số (multiplicity) c a một lớp bên nhiều trong các mối kết hợp một-nhiều hoặc nhiều-nhiều b ng cách sử dụng giá trị khóa (key).

Hình 7.15: Mối kết hợp hạn định

Ví d 7.10: Mối kết nối nhiều – nhiều giữa giải đấu và cầu th

Mã lệnh Java tương ng:

import java.util.Map;

class League {

private Map<String, Player> players;

public void addPlayer(String nickName, Player p) {

if (!players.containsKey(nickName)) {

players.put(nickName, p);

p.addLeague(nickName, this);

}

}

}

class Player {

private Map<String, League> leagues;

public void addLeague(String nickName, League league) {

if (!leagues.containsKey(league)) {

leagues.put(nickName, league);

league.addPlayer(nickName, this);

}

}

}

Page 112: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 102

7.3.4 L p liên k t

Lớp liên kết (Association class) được sinh ra trong mối liên kết nhiều-nhiều mà đó cần lưu lại các thông tin mới nảy sinh từ chúng.

Hình 7.16.a: Lớp liên kết trong mối kết hợp nhiều-nhiều

Lớp liên kết sinh ra từ mối kết hợp nhiều-nhiều có thể tương đương với hai mối kết hợp hai chiều 1-nhiều nh hình 7.16.b

Hình 7.16.b: Hai mối kết hợp 1-nhiều

7.3.5 K t t p chặt

Kết tập chặt (composition) thư ng được sử dụng để minh họa vòng đ i (lifecycle) c a đối tượng thuộc lớp B phụ thuộc nội tại vào vòng đ i c a đối tượng lớp A. Nói cách khác: nếu A được tạo thì B được tạo, nếu A h y thì B cũng bị h y theo.

Chẳng hạn như: ắMỗi trái tim luôn g n chặt với từng hơi th c a mỗi con ngư iẰ, ắMỗi xe có một động cơẰ, ắMỗi quyển sách có một hoặc nhiều chươngẰ,… Nó còn được gọi là mối kết hợp b i giá trị (Has by value). Trong Java ta sử dụng từ khóa final để đảm bảo đối tượng được kết tập chặt được tạo ra.

Ví d 7.11: Mối kết tập chặt 1-nhiều giữa House và Room: ắMỗi căn nhà được g n chặt b i một hoặc nhiều căn phòngẰ

Hình 7.17: Kết tập chặt một chiều 1-nhiều

Mã lệnh Java tương ng:

//File: CompositionTest.java

package ctu.vdlinh.composition;

Page 113: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 103

import java.util.ArrayList;

class Room{

private String name;

Room(String name) {

super();

this.name = name;

}

public String getName() {

return name;

}

}

class House {

private final int SO_PHONG_TOI_DA = 50;

private final ArrayList<Room> numOfRooms;

House() {

numOfRooms = new ArrayList<Room>(SO_PHONG_TOI_DA);

}

void addRoom(String aRoomName){

Room room = new Room(aRoomName);

numOfRooms.add(room);

}

public ArrayList<Room> getNumOfRooms() {

return numOfRooms;

}

}

public class CompositionTest {

public static void main(String[] args) {

House myHouse= new House();

myHouse.addRoom("Phòng khách 1,");

myHouse.addRoom("Phòng khách 2");

myHouse.addRoom("\n\tPhòng ngủ 1,");

myHouse.addRoom("Phòng ngủ 2,");

myHouse.addRoom("Phòng ngủ 3");

myHouse.addRoom("\n\tPhòng nấu ăn" ;

myHouse.addRoom("\n\tPhòng tắm 1,");

Page 114: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 104

myHouse.addRoom("Phòng tắm 2");

myHouse.addRoom("\n\tPhòng WC 1,");

myHouse.addRoom("Phòng WC 2.");

System.out.println("Danh sách các phòng trong myHouse:");

for (Room room : myHouse.getNumOfRooms()) {

System.out.print("\t"+ room.getName());

}

}

}

Kết quả chạy thử chương trình:

Danh sách các phòng trong myHouse:

Phòng khách 1, Phòng khách 2

Phòng ngủ 1, Phòng ngủ 2, Phòng ngủ 3 Phòng nấu ăn Phòng tắm 1, Phòng tắm 2 Phòng WC 1, Phòng WC 2.

7.3.6 K t t p l ng

Kết tập lỏng (aggregation) thể hiện vòng đ i c a đối tượng kiểu B không cùng chung với vòng đ i c a A Nếu A h y thì B có thể không bị h y theo.

Chẳng hạn như: ắMỗi TV có một RemoteẰ, ắMỗi laptop có một ổ đĩa CDẰ, ắMỗi tổ ch c (Organization) có nhiều ngư i (Person)Ằ. Nó còn được gọi là mối kết hợp b i tham chiếu (Has by reference)

Hình 7.18: Kết tập lỏng 1-nhiều hai chiều

Ví d 7.12: Mỗi tổ ch c (Organization) có nhiều ngư i (Person) là một minh họa cho mối kết tập lỏng.

class Person {

private String name;

private Organization organization; // one to..

}

class Organization {

private ArrayList<Person> employees; // .. many

Organization() {

employees = new ArrayList<Person>();

Page 115: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 105

}

void addPerson(Person aPerson){

employees.add(aPerson);

}

}

7.3.7 M i k t h p phản thơn/đ quy (self association)

Hình 7.19.a Hình 7.19.b

Ví d 7.13: Với hình 7.19.a ta có mối kết hợp đệ quy là mỗi một ngư i có thể là không phải hoặc chỉ là một vợ/chồng c a ngư i khác (vợ chồng c a nhau).

class Person {

private Person spouse;

//… }

Ví d 7.14: Hình 7.19.b thể hiện mối kết hợp phản thân, đó là mỗi một nút c a cây nhị phân có một nút đệ quy trái và một nút đệ quy phải liên kết đến nút nhị phân khác tương ng c a chính nó.

class BinaryTreeNode {

private BinaryTreeNode leftNode;

private BinaryTreeNode rightNode;

}

7.3.8 M i k t h p thực thi

Mối kết hợp thực thi (realization/implementation) thư ng được sử dụng trong lớp lớp thực thi (implementation class) và giao diện (interface: được đề cập chương sau) như minh họa hình 7.20.

Hình 7.20: Mối kết hợp phụ thuộc ActionListener vào ActionEvent

Page 116: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 106

Ví d 7.15: Minh họa sự kết hợp giữa các mối kết hợp phụ thuộc và mối kết hợp thực thi, được đại diện b i lớp thực thi MyActionListerner từ giao diện ActionListener, và sự phụ thuộc giữa interface ActionListener vào lớp ActionEvent.

//File: MyActionListerner.java

package ctu.vdlinh.chapter7;

import java.awt.BorderLayout;

import java.awt.Color;

import java.awt.Dimension;

import java.awt.Toolkit;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import javax.swing.ImageIcon;

import javax.swing.JButton;

import javax.swing.JFrame;

import javax.swing.JOptionPane;

public class MyActionListerner extends JFrame {

private static final long serialVersionUID = -5771494762272638465L;

MyActionListerner() {

super();

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JButton myButton = new JButton(" Click me ",new ImageIcon("cursor_arrow.png"));

myButton.setForeground(Color.RED);

myButton.addActionListener(

new ActionListener() {

@Override

public void actionPerformed(ActionEvent e) {

JOptionPane.showMessageDialog(null, "Hi! You clicked me.","Information", JOptionPane.INFORMATION_MESSAGE);

}

});

setLayout(new BorderLayout());

this.add(myButton, BorderLayout.SOUTH);

pack();

Page 117: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 107

this.setTitle("The dependency and realization association");

Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();

int height = screenSize.height;

int width = screenSize.width;

setSize(width / 2 - 200, height / 2 - 150);

setLocationRelativeTo(null);

setVisible(true);

}

}

//File: DependencyRealizationTest.java

package ctu.vdlinh.chapter7;

import javax.swing.SwingUtilities;

public class DependencyRealizationTest {

public static void main(String[] args) {

SwingUtilities.invokeLater(new Runnable() {

@Override

public void run() {

new MyActionListerner();

}

});

}

}

Chạy chương trình có kết quả sau:

Hình 7.21: Minh họa mối kết hợp dependency và realization

Page 118: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 108

7.3 Thừa k

Ngoài các mối liên kết Có-m t (Has-a) trên, trong phương pháp lập trình hướng đối tượng m rộng thêm tính năng quan trọng đó là thừa kế (inheritance). Thừa kế là một cơ chế cho phép lập trình viên m rộng một lớp cha cho một hoặc nhiều lớp con. Trong Java, thừa kế được sử dụng b i 02 phương cách:

Thừa kế lớp (class inheritance): Tạo lớp con mới như là sự m rộng (extends) c a lớp khác (giúp cho việc tái sử dụng mã lệnh - code). Trong Java, chỉ hỗ trợ thừa kế đơn đối với lớp (single class inheritance) ch không hỗ trợ thừa kế bội như Delphi, C++.

Thừa kế giao diện (interface inheritance): Tạo một lớp mới để cài đặt (implements) các phương th c đã được định nghĩa trong giao diện. Java hỗ trợ thừa kế bội giao diện đối với Interface (multiple interface inheritance), sẽ được trình bày phần Interface. Điều này giúp cho ngư i phân tích và thiết kế có thể dễ dàng trừu tượng bài toán trong thế giới thực.

7.3.1 Các c ch trừu t ng

Với một hệ thống cần phát triển mà có đa dạng các loại đối tượng thì vấn đề đặt ra cho ngư i phát triển là làm sao có thể thiết kế chương trình mà có thể bao hàm hết các đối tượng này với khả năng dễ quản lý, dễ m rộng và tái sử dụng nhất.

7.3.1.1 Cơ chế phân lớp

Các đối tượng có các đặc điểm tương đồng nhau sẽ được nhóm lại và định nghĩa thành một lớp. Hành động xác định và phân loại các đối tượng tương tự vào các lớp được gọi là phân lớp (classification ) trong mô hình hướng đối tượng.

Hình 7.22.a: Các động vật có xương sống Hình 7.22.b: Đặc điểm phân loại

Như vậy với cách phân loại dựa trên đặc điểm như hình 7.22.b, thì quần thể các đối tượng đang xét hình 7.22.a có 05 lớp ng với động vật có xương sống.

Page 119: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 109

Hình 7.23: Phân lớp loài cá

Riêng loài cá, nếu ta phân loại chi tiết hơn thì có thể tách ra thành 04 lớp con c a lớp Fish đó là Agnatha (lớp cá không hàm) , Osteichthyes (lớp cá xương) , Placodermi (cá da phiến) và Chondrichthyes (lớp cá sụn)

7.3.1.2 Tổng quát hóa

Tổng quát hóa (generalization) là quá trình n m b t những đặc điểm (properties: attributes + methods) tương đồng nhau giữa các lớp đối tượng rồi từ đó định nghĩa thêm một lớp mới ch a những đặc điểm chung đó. Lớp mới được hình thành được gọi là lớp tổng quát. Quá trình tổng quát hóa đi theo hướng từ dưới lên (bottom-up).

Ví dụ như dựa vào sự tương đồng là cả năm lớp động vật là Mammal, Fish, Bird, Reptile, và Amphibian đều là loài động vật có xương sống, nên ta có thể tổng quát hóa điều này b ng một lớp mới là Động vật có xương sống (Animal-with-Backbone)

Hình 7.24 Tổng quát hóa dựa trên bottom-up

Sau khi thực hiện quá trình tổng quát hóa, ta có được sơ đồ phân cấp lớp (class hierarchy) hình 7.24. Trong đó, lớp tổng quát được gọi là lớp cha/ lớp cơ s (super /base class) còn các lớp ban đầu được gọi là các lớp con (subclass).

7.3.1.3 Chuyên biệt hóa

Ngược với tổng quát hóa là chuyên biệt hóa (specialization), đó là quá trình n m b t những đặc điểm không tương đồng giữa các đối tượng trong một lớp rồi từ đó định nghĩa ra các lớp con riêng biệt mới với những khác biệt này. Quá trình chuyên biệt hóa đi theo chiều từ trên xuông dưới (top-down).

Page 120: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 110

Hình 7.25 Tổng quát hóa và chuyên biệt hóa

Như vậy mối tương quan giữa lớp con và lớp cha được tạo ra trong quá trình tổng quát hóa hoặc chuyên biệt hóa là mối liên kết Là-m t (Is-a).

Ví d 7.16: Các mối thừa kế ắLà- mộtẰ

Fish Is-a AnimalwithBackbone ắCá là một loài động vật có xươngẰ

Bird Is-a Animal ắChim là một loài động vậtẰ

7.3.2 Ph ng pháp thi t k

Hình 7.26: Các đặc điểm được thừa kế theo hệ thống phân cấp lớp

Từ một quan điểm tái sử dụng phần mềm, các đặc điểm bao gồm các thuộc tính và phương th c được định nghĩa trong lớp cha (superclass) nên được cung cấp cho các lớp con (subclasses) mà không cần phải khai báo rõ ràng trong chúng. Như vậy, theo

Page 121: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 111

phương pháp lập trình hướng đối tượng, cách tái sử dụng các đặc điểm như vậy được gọi là thừa kế.

Thừa kế giúp cho các lớp con có thể lấy những đặc điểm c a lớp cha (hoặc các interface cha) thông qua cơ chế tổng quát hóa theo cách lan truyền từ cha nó đến lớp cao nhất (topmost class) c a nó trong hệ thống phân cấp lớp.

Từ quan điểm trên, để hiện thực việc thừa kế theo ngôn ngữ Java, ta tiến hành các bước sau dựa trên sự chuyên biệt hóa như sau:

- Sử dụng một lớp tổng quát cha có sẵn mà không phải là lớp tuyệt tự (final class) để xác định những đặc điểm chung mà các lớp con sẽ được thừa hư ng (dựa trên sơ đồ phân cấp lớp c a mối liên kết Is-a). Từ đó xác định được các thành viên (inherited members) c a lớp cha có thể được thừa kế cho (các) lớp con c a nó.

- Thông qua cơ chế chuyên biệt hóa, định nghĩa các lớp con để m rộng thêm từ lớp cha thông qua từ khóa extends b ng cách thêm vào:

+ Các thuộc tính, phương th c đặc trưng riêng c a lớp con.

+ Phương th c trùng tên được gọi là ghi chồng (overriding methods), các biến trùng tên được gọi là biến ph lấp (shadowing variables).

+ Các private members lớp cha không thừa kế cho lớp con, tuy nhiên ta có thể sử dụng phương th c setters/getters để truy xuất các biến riêng lớp cơ s .

+ Quyền truy xuất m c thành viên c a các lớp, các lớp con thừa kế chung gói, khác gói được thể hiện bảng ắphạm vi truy cập m c thành viênẰ, xem bảng 7.1.

Bảng 7.1: Bảng phạm vi truy cập các thành viên c a lớp

+ Truy xuất các đặc điểm lớp cha thông qua từ khóa super, hoặc gọi phương th c dựng c a lớp cha b ng câu lệnh super([các_đối_số]).

Để cài đặt việc thừa kế b ng ngôn ngữ Java, ta sử dụng cú pháp sau:

[modifier] class Subclass extends Superclass {

//Class body;

}

Từ khóa extends được hiểu là sự m rộng lớp con hay được dẫn xuất từ lớp cha nó.

Page 122: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 112

Ví d 7.17 : Viết chương trình để minh họa tính thừa kế trong hình 7.26

package ctu.vdlinh.chapter7;

/**

* @author Danny Poo, Derek Kiong and Swarnalatha Ashok

*/

class Person {

private String name;

Person(String name) {

super();

this.name = name;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

}

class Employee extends Person {

private float basicSalary;

private String employeeNumber;

Employee(String name, String employeeNumber, float basicSalary) {

super(name);

this.employeeNumber = employeeNumber;

this.basicSalary = basicSalary;

}

public float getBasicSalary() {

return basicSalary;

}

public void setBasicSalary(float basicSalary) {

this.basicSalary = basicSalary;

}

public String getEmployeeNumber() {

return employeeNumber;

Page 123: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 113

}

public void setEmployeeNumber(String employeeNumber) {

this.employeeNumber = employeeNumber;

}

}

class Manager extends Employee {

private float allowance;

Manager(String name, String employeeNumber, float

basicSalary, float allowance) {

super(name, employeeNumber, basicSalary);

this.allowance = allowance;

}

public float getAllowance() {

return allowance;

}

public void setAllowance(float allowance) {

this.allowance = allowance;

}

}

class Secretary extends Employee { // Secretary = Employee

Secretary(String name, String employeeNumber, float basicSalary) {

super(name, employeeNumber, basicSalary);

}

}

public class TestInheritance {

public static void main(String[] args) {

Manager m = new Manager("Simon", "01234M", 9000.0f, 2000.0f);

Secretary s = new Secretary("Selene", "98765S", 2500.0f);

System.out.print("The Manager " + m.getName() + " (employee number " + m.getEmployeeNumber() + ")");

System.out.println(" has a salary of " + m.getBasicSalary());

System.out.println("The Secretary " + s.getName() + " (employee number " + s.getEmployeeNumber() + ")");

System.out.print("The Manager " + m.getName());

Page 124: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 114

System.out.println(" also has an allowance of " + m.getAllowance());

}

}

Chạy và có kết quả:

The Manager Simon (employee number 01234M) has a salary of 9000.0

The Secretary Selene (employee number 98765S)

The Manager Simon also has an allowance of 2000.0 Ví d 7.18: Hãy mô hình hóa để thiết kế và viết chương trình thể hiện các tính bao

đóng, thừa kế cho bài toán hình trụ như hình 7.27. Cho biết diện tích hình tròn, diện tích xung quanh và thể tích hình trụ. Trong đó: Diện tích xung quanh c a hình trụ b ng chu vi đáy nhân chiều cao, và thể tích c a khối trụ b ng diện tích đáy nhân với chiều cao.

Hình 7.27: Hình trụ và sơ đồ lớp

Mã lệnh Java c a bài toán:

//file name: LopChinh.java

package ctu.vdlinh.chapter7;

class HinhTron {

private int x, y; //tọa độ tâm x, y

private double bk; // bán kính

public HinhTron(double bk) {

super();

Page 125: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 115

this.bk = bk;

}

public HinhTron(int x, int y, double bk) {

super();

this.x = x;

this.y = y;

this.bk = bk;

}

public int getX() {

return x;

}

public int getY() {

return y;

}

public double getBk() {

return bk;

}

public void setBk(double bk) {

if (bk < 0.0) {

System.err.println("Bán kính phải có giá trị dương. " ;

}

this.bk = bk;

}

protected double dienTich() {

return Math.PI * Math.pow(bk, 2);

}

}

class HinhTru extends HinhTron{

private double chieuCao;

HinhTru(double bk, double chieuCao) {

super(bk);

this.chieuCao = chieuCao;

}

HinhTru(int x, int y, double bk, double chieuCao) {

super(x, y, bk);

Page 126: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 116

this.chieuCao = chieuCao;

}

public double getChieuCao() {

return chieuCao;

}

public void setChieuCao(double chieuCao) {

this.chieuCao = chieuCao;

}

private double chuVi(){

return 2*Math.PI * getBk();

}

public double dienTichXQ(){

return chuVi()*chieuCao;

}

public double theTich(){

return dienTich()*chieuCao;

}

}

public class LopChinh {

public static void main(String[] args) {

HinhTron hTron = new HinhTron(20, 20, 10.379); //bk = 10.379

System.out.printf("Diện tích hình tròn ứng với bán kính= %.2f là: %.2f\n", hTron.getBk(), hTron.dienTich());

HinhTru hTru = new HinhTru(hTron.getX(), hTron.getY(), hTron.getBk(), 45.50);

System.out.printf("Diện tích xung quanh: %.2f, và thể tích hình trụ là: %.2f \n",hTru.dienTichXQ(),hTru.theTich());

}

}

Chạy chương trình, ta có kết quả:

Diện tích hình tròn ứng với bán kính= 10.38 là: 338.42

Diện tích xung quanh: 2967.20, và thể tích hình trụ là: 15398.28

Page 127: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 117

Bài t p ch ng 7

Bài 7.1: Cho sơ đồ lớp (class diagram) như dưới đây và source code c a lớp Room.java và Office.java đã viết sẵn c a tác giả John King, hãy viết chương trình tạo ra n (n ≥ 2) căn phòng với các thông số khác nhau tùy ý, và in đầy đ các thông tin c a từng phòng này thông qua phương th c displayRoom.

Hình 7.28: Sơ đồ lớp thừa kế Room-Office

package ctu.vdlinh.chapter7;

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

/**

* Sample Room class

* @version 1.04 04/19/2000

* @author John King

*/

public class Room {

protected double length;

protected double width;

protected double footage;

protected String roomName;

public Room() {

Page 128: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 118

this.length = 10.0; this.width = 10.0;

this.roomName = "Generic"; calcFootage();

}

/**

* @param length, width, roomName

* @return return nothing

*/

public Room(double length, double width, String roomName) {

this.length = length; this.width = width;

this.roomName = roomName; calcFootage();

}

public Room(int length, int width, String roomName) {

this.length = (double) length; this.width = (double) width;

this.roomName = roomName; calcFootage();

}

public Room(float length, float width, String roomName) {

this.length = (double) length; this.width = (double) width;

this.roomName = roomName; calcFootage();

}

public double getLength() {

return length;

}

public double getWidth() {

return width;

}

public double getFootage() {

return footage;

}

public void calcFootage() {

footage = length * width;

}

public void displayRoom() {

System.out.println("\tRoom length:" + length);

System.out.println("\tRoom width:" + width);

System.out.println("\tRoom name:" + roomName);

Page 129: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 119

calcFootage();

System.out.println("\tRoom footage:" + footage);

}

public void setLength(double length) {

this.length = length;

}

public void setWidth(double width) {

this.width = width;

}

public void setLength(int length) {

this.length = (double) length;

}

public void setWidth(int width) {

this.width = (double) width;

}

public void setLength(float length) {

this.length = (double) length;

}

public void setWidth(float width) {

this.width = (double) width;

}

public void setRoomName(String roomName) {

this.roomName = roomName;

}

public void setRoomName() {

try {

System.out.print("Emter room name:");

InputStreamReader inStream = new InputStreamReader(System.in);

BufferedReader inBuf = new BufferedReader(inStream);

roomName = inBuf.readLine();

} catch (IOException e) {

System.out.println("I/O error!");

}

}

Page 130: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 120

} package ctu.vdlinh.chapter7;

/**

* Sample Office class

* @version 1.04 04/19/2000

* @author John King

*/

class Office extends Room {

protected int floors;

public Office() {

this.floors = 1; calcFootage();

}

public Office(int floors, double length, double width, String roomName) {

super(length, width, roomName);

this.floors = floors;

}

public void setFloors(double floors) {

this.floors = (int) floors;

}

public void setFloors(int floors) {

this.floors = floors;

}

public int getFloors() {

return floors;

}

public void calcFootage(){

footage = length * width * floors;

}

public void displayRoom() {

System.out.println("# of floors= "+this.floors);

super.displayRoom();

}

}

Page 131: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 121

Bài 7.2: Hãy trừu tượng hóa để vẽ sơ đồ lớp cho bài toán mỗi một khoa có nhiều sinh viên và mỗi sinh viên có thể học nhiều khoa khác nhau sao cho thể hiện mối kết hợp nhiều - nhiều và tính thừa kế. Viết dự án hoàn chỉnh b ng ngôn ngữ Java.

Bài 7.3: Cho sơ đồ các lớp như hình 7.29, với các thuộc tính: name (họ tên sinh viên Đại học: Undergraduate, Sau đại học: Graduate), test (mảng ch a điểm c a 3 bài kiểm tra test1, test2, và test3) và courseGrade (Kết quả là đạt hay không đạt).

Hình 7.29: Sơ đồ lớp thừa kế Students

// File: Student.java

class Student {

protected final static int NUM_OF_TESTS = 3;

protected String name;

protected int[] test;

protected String courseGrade;

public Student() {

this("No Name");

}

public Student(String studentName) {

name = studentName;

test = new int[NUM_OF_TESTS];

Page 132: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 122

courseGrade = "";

}

public String getCourseGrade() {

return courseGrade;

}

public String getName() {

return name;

}

public int getTestScore(int testNumber) {

return test[testNumber - 1];

}

public void setName(String newName) {

name = newName;

}

public void setTestScore(int testNumber, int testScore) {

test[testNumber - 1] = testScore;

}

public void computeCourseGrade() {

// do nothing - override this method in the subclass

}

}

Với công th c xét kết quả khóa học là ắPassẰ hoặc ắNo PassẰ cho Sinh viên đại học và sau đại học như trên ta được lớp UndergraduateStudent và GraduateStudent như sau:

class UndergraduateStudent extends Student { // SV đại học

public void computeCourseGrade() {

int total = 0;

for (int i = 0; i < NUM_OF_TESTS; i++) {

total += test[i];

}

if (total / NUM_OF_TESTS >= 70) {

courseGrade = "Pass"; // Đạt

Page 133: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 123

} else {

courseGrade = "No Pass"; // Không đạt

}

}

}

Hình 7.30: Mảng các đối tượng

class GraduateStudent extends Student { // SV sau đại học

public void computeCourseGrade() {

int total = 0;

for (int i = 0; i < NUM_OF_TESTS; i++) {

total += test[i];

}

if (total / NUM_OF_TESTS >= 80) {

courseGrade = "Pass";

} else {

courseGrade = "No Pass";

}

}

}

Khai báo và tạo một mảng roster có kiểu phần tử thuộc lớp Student như hình 7.30, viết chương trình nhập vào n=5 sinh viên (Đại học - nếu Type ="U", sau đại học – Type ="G") vào mảng roster như bảng sau. Sau đó tính và in kết quả cho những sinh viên lên màn hình.

Page 134: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 124

Bài 7.4: Sơ đồ lớp được cho như hình 7.31,

a. Hãy đọc và diễn giải sơ đồ theo ngôn ngữ tự nhiên. Hãy thêm một số phương th c cần thiết vào các lớp để có thể quản lý thông tin về các tài xế (Driver) và Tàu/xe lửa (Train).

Hình 7.31: Sơ đồ lớp Driver-Train

b. Giả sử có một số giá trị kh i tạo được cho như gợi ý sau:

Route r1 = new Route("Cantho", "Saigon"); //tuyến đư ng

ClockTime ct1 = new ClockTime(15, 05); //th i điểm

ClockTime ct2 = new ClockTime(19, 20);

Schedule s1 = new Schedule(ct1,ct2); // hành trình, lịch trình

Train train1 = new Train("T001",r1, s1, false,…); // chuyến/vé xe lửa

Route r2 = new Route("Rachsoi", "Rachgia");

ClockTime ct3 = new ClockTime(10, 30);

ClockTime ct4 = new ClockTime(12, 18);

Schedule s2 = new Schedule(ct5, ct6)

Train train2 = new Train("T003",r2, s2, true,…); Hãy viết chương trình tạo ra một danh sách có n chuyến xe lửa (Train) và m tài xế xe

lửa (Driver) rồi hiển thị các thông tin c a chúng lên màn hình.

Page 135: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 125

Ch ng 8. Đa hình

Trong chương này, giáo trình sẽ cung cấp cho ngư i học các khái niệm c a đa hình, các phương pháp cài đặt đa hình tĩnh và đa hình động cho các lớp cụ thể. Ngoài ra cũng đề cập đến phương pháp ép kiểu giữa các loại đối tượng được sử dụng phổ biến trong phương pháp lập trình trước đó.

8.1 Khái ni m đa hình

Trong thế giới thực, có rất nhiều đối tượng mà hình dạng, hành động c a chúng khác nhau. Ví dụ như chiếc bàn: có bàn tròn, bàn vuông, bàn oval,… tương tự như vậy có ngư i khi phát biểu b ng tiếng Việt, có lúc phát biểu b ng tiếng Anh, tiếng Đ c,…

Hình 8.1: Một đối tượng đa (dạng) ngôn ngữ

Trư ng hợp khác về đa hình là có những đối tượng khác loài nhau cùng có chung một hành động nhưng cách thể hiện mỗi loài thì khác nhau, chẳng hạn như hành động ắnói chuyệnẰ c a mỗi loài lại đa dạng khác nhau.

Hình 8.2: Một hành động được đa (dạng) đối tượng thực hiện

Page 136: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 126

Như vậy đa hình (polymorphism): Là khả năng đảm nhận nhiều dạng: Một hoạt động (thông qua phương th c) được đối tượng thực hiện b ng nhiều cách khác nhau, và các đối tượng khác loại cùng thực hiện chung một ng xử theo cách riêng c a mình. Tính năng này giúp cho chương trình tr nên tổng quát hơn ch không đơn điệu cá biệt.

8.2 Đa hình tĩnh

Đa hình tĩnh (static polymorphism) có thể được cài đặt thông qua phương pháp nạp chồng (overloading) trong một lớp và được xác định th i điểm biên dịch (compile-time) chương trình. Phương pháp này còn được gọi là kỹ thuật liên kết sớm (static/early binding): Trình biên dịch xác định rõ sẽ dùng phương th c nào trong các phương th c cùng tên để thực thi.

N p chồng (overloading): Là trư ng hợp khi có nhiều phương th c cùng tên trong cùng một lớp với số lượng và kiểu tham số khác nhau và được gọi là đa hình phương th c.

Ví d 8.1: Định nghĩa một lớp PhepTinh như hình sau và viết chương trình tính cộng hai số để minh họa dạng đa hình tĩnh hay đa hình dạng phương th c.

Hình 8.3: Nạp chồng phương th c

Source Java: OverLoading_Testing.java

package ctu.vdlinh.chapter8;

class PhepTinh {

void cong(int a, int b) {

System.out.printf("Tổng 2 số nguyên: %d + %d = %d \n", a, b, a + b);

}

void cong(float a, int b) {

System.out.printf("Tổng 2 số thực: %.2f + %d = %.2f \n", a, b, a + b);

}

void cong(float a, float b) {

System.out.printf("Tổng 2 số thực: %.2f + %.2f = %.2f \n", a, b, a + b);

}

Page 137: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 127

void cong(double a, double b) {

System.out.printf("Tổng 2 số thực: %.2f + %.2f = %.2f \n", a, b, a + b);

}

void cong(String s1, String s2) {

System.out.printf("Cộng 2 chuỗi: %s + %s = %s \n", s1, s2, s1 +" "+ s2);

}

}

public class OverLoading_Testing {

public static void main(String[] args) {

PhepTinh pt = new PhepTinh();

pt.cong(5, 10);

pt.cong(10.25f, 5);

pt.cong(10.25f, 4.5f);

pt.cong(10.25, 5.25);

pt.cong("Lập trình", "HĐT Java" ;

}

}

Kết quả khi chạy:

Tổng 2 số nguyên: 5 + 10 = 15

Tổng 2 số thực: 10.25 + 5 = 15.25

Tổng 2 số thực: 10.25 + 4.50 = 14.75

Tổng 2 số thực: 10.25 + 5.25 = 15.50

Cộng 2 chuỗi: Lập trình + HĐT Java = Lập trình HĐT Java

8.3 Chuyển đổi (ép) kiểu

Trước khi tìm hiểu về đa hình động, chúng ta tìm hiểu trước về khái niệm thư ng dùng trong lập trình đó là ép kiểu. Có hai dạng kiểu trong lập trình:

Ép kiểu lên (upcasting): Đối tượng kiểu lớp con/lớp dẫn xuất được tham chiếu một cách tự động b i đối tượng kiểu lớp cha/lớp cơ s (tự động chuyển đổi kiểu) theo hướng từ dưới lên trong hệ thống cây phân cấp thừa kế (inheritance hierarchy). Nói cách khác, upcasting là khả năng nhìn nhận đối tượng thuộc lớp con như là một đối tượng thuộc lớp cha.

Chuyển kiểu xu ng (downcasting): Theo th tự ngược lại c a upcasting, downcasting là khả năng nhìn nhận một đối tượng thuộc cha như một đối tượng thuộc lớp con và nó không tự động chuyển đổi kiểu nên cần phải ép kiểu tư ng minh.

Page 138: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 128

Ví d 8.2: Các phép ép kiểu lên, ép kiểu xuống tư ng minh và không tư ng minh

Hình 8.4: Cây phân cấp thừa kế c a động vật

DongVat dv = new BoSat(); // Upcasting: OK

BoSat bs = (BoSat) dv; // Downcasting: OK (tư ng minh)

DongVatCoVu dvcv = dv; // Downcasting Error: type mismatch

DongVatCoVu dvcv2 = new DongVatCoVu();

Nguoi nguoi = new Nguoi();

nguoi = (Nguoi) dvcv2; /* Downcasting: Biên dịch thì không báo lỗi. Khi chạy thì phát sinh lỗi */

Ví d 8.3: Sử dụng cách lập trình ép kiểu truyền thống (downcasting - không phải đa hình), lưu ý đặt tên phương th c c a mỗi lớp khác nhau để thấy được tính chất này.

Hình 8.5: Sơ đồ minh họa downcasting

Page 139: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 129

Mã nguồn Java:

package ctu.vdlinh.chapter8;

/**

* Filename: DowncastTesting.java

* Sử dụng Downcasting và instanceOf

*/

class DongVat {

private int soChan = 2;

public int getSoChan() {

return soChan;

}

public void setSoChan(int soChan) {

this.soChan = soChan;

}

}

class Cho extends DongVat {

public void gauGau() {

setSoChan(4);

System.out.println("\tĐộng vật thuộc \""+ getClass().getSimpleName() +"\" có " + getSoChan() + " chân và sủa gâu gâu...");

}

}

class Meo extends DongVat {

public void meoMeo() {

setSoChan(4);

System.out.println("\tĐộng vật thuộc \""+ getClass().getSimpleName() +"\" có " + getSoChan() + " chân và kêu meo meo...");

}

}

class Vit extends DongVat {

public void capCap() {

setSoChan(2);

System.out.println("\tĐộng vật thuộc \""+ getClass().getSimpleName() +"\" có " + getSoChan() + " chân và kêu cạp cạp...");

}

}

class Cop extends DongVat {

public void guGu() {

Page 140: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 130

setSoChan(4);

System.out.println("\tĐộng vật thuộc \""+ getClass().getSimpleName() +"\" có " + getSoChan() + " chân và gầm gừ gừ...");

}

}

public class DowncastTesting {

public static void theHien(DongVat dv) {

if (dv instanceof Cho) {

Cho cho = (Cho) dv; //downcasting

cho.gauGau();

//((Cho) dv).gauGau();

} else if (dv instanceof Meo) {

Meo meo = (Meo) dv;

meo.meoMeo();

} else if (dv instanceof Vit) {

((Vit) dv).capCap();

} else ((Cop) dv).guGu();

/* ----- Ép kiểu xuống: Biên dịch thành công; Chạy bị lỗi run-time ----

Cop cop = new Cop(); // thuộc lớp con

DongVat dongVat = new DongVat(); // thuộc lớp cha

cop = (Cop) dongVat; // éo kiểu xuống tường minh

---------------------------------------------------------------------- */

}

public static void main(String[] args) {

System.out.println("Tạo các đối tượng và thể hiện chúng:");

theHien(new Cop()); theHien(new Cho());

theHien(new Meo()); theHien(new Vit());

}

}

Biên d ch và ch y, có k t quả:

Tạo các đối tượng và thể hiện chúng:

Động vật thuộc "Cop" có 4 chân và gầm gừ gừ...

Động vật thuộc "Cho" có 4 chân và sủa gâu gâu...

Động vật thuộc "Meo" có 4 chân và kêu meo meo...

Động vật thuộc "Vit" có 2 chân và kêu cạp cạp...

Page 141: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 131

8.4 Đa hình đ ng

Đa hình động (dynamic polymorphism) được thực hiện thông qua phương pháp ghi chồng (overriding) th i điểm thực thi chương trình (run-time) và được gọi là kỹ thuật liên kết động (dynamic/late binding): chỉ khi chạy chương trình mới xác định được sẽ dùng phương th c c a lớp nào để thực thi.

Trong ngôn ngữ Java, ta có thể cài đặt đa hình b ng phương pháp nạp chồng trong một lớp hoặc phương pháp ghi chồng từ việc thừa kế lớp cụ thể (concrete class), lớp trừu tượng (abstract class ) và lớp tổng quát (generic class) cũng như ghi chồng từ giao diện (interface).

Ghi chồng (overriding): Ghi chồng là phương th c lớp con ghi đè lên phương th c cùng tên lớp cha. Nó cho phép một phương th c có nhiều dạng tác động khác nhau trên các loại đối tượng khác nhau, và còn được gọi là dạng đa hình đối tượng.

Ví d 8.4: Hãy mô hình hóa để thiết kế và viết chương trình tính diện tích hình tròn, diện tích và thể tích hình cầu sao cho thể hiện tính thừa kế, tính bao đóng và đa hình theo dạng đối tượng?

Hình 8.6: Sơ đồ lớp cho ví dụ

Mã nguồn Java :

/**

* File name: HinhTron.java

*/

package ctu.vdlinh.package1;

Page 142: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 132

public class HinhTron {

private int x, y;

protected double bk;

public HinhTron(int x, int y, double bk) {

this.x = x;

this.y = y;

this.bk = bk;

}

public int getX() {

return x;

}

public void setX(int x) {

this.x = x;

}

public int getY() {

return y;

}

public void setY(int y) {

this.y = y;

}

public void hienThi() {

System.out.printf("\nĐối tượng hình tròn có diện tích= %. f đvt .", tinhDienTich ;

}

protected double tinhDienTich() { // Hình tròn

return Math.PI * Math.pow(bk, 2);

}

}

/**

* File name: HinhCau.java

*/

package ctu.vdlinh.package1;

public class HinhCau extends HinhTron {

public HinhCau(int x, int y, double bk) {

super(x, y, bk);

Page 143: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 133

}

@Override

public void hienThi() { // overriding method

System.out.printf("\nHình cầu có diện tích= %. f đvt và thể tích =%. f đvt .", tinhDienTich , tinhTheTich ;

}

@Override

protected double tinhDienTich() { // overriding

return 4 * Math.PI * Math.pow(bk, 2);

}

double tinhTheTich() {

return 4 / 3 * Math.PI * Math.pow(bk, 3);

}

}

/**

* File name: DynamicBidingTesting.java

* @author Vũ Duy Linh

*/

package ctu.vdlinh.package2;

import ctu.vdlinh.package1.*;

public class DynamicBindingTesting {

public static void main(String[] args) {

HinhTron refBaseClase;

refBaseClase = new HinhTron(100, 50, 50);

refBaseClase.hienThi(); //thông tin hình tròn

refBaseClase = new HinhCau(100, 200, 50);

refBaseClase.hienThi(); //thông tin hình cầu

}

}

Kết quả demo chương trình: Hình tròn có diện tích= . đvt .

Hình cầu có diện tích= . đvt , thể tích = .0 đvt .

Ví d 8.5: Dựa vào hình 8.7, viết chương trình tạo một số các đối tượng thuộc các lớp trên. Sau đó cho biết số lượng đối tượng thuộc vào lớp ắĐộng vậtẰ, ắĐộng vật có vúẰ và ắBò sátẰ. Trong ví dụ này, sử dụng tính năng Generic/ parameterized type để minh họa cho việc sử dụng đa hình tham số (parametric polymorphism).

Page 144: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 134

Hình 8.7: Sơ đồ minh họa liên kết động

Mã nguồn cho ví dụ 8.5

/**

* Filename: DynamicBindingTesting.java

* @author Vũ Duy Linh

*/

package ctu.vdlinh.chapter8;

import java.util.ArrayList;

import java.util.Iterator;

class DongVat{

void hienThi(){

System.out.println "Đối tượng loài động vật.");

}

}

class DongVatCoVu extends DongVat{

void hienThi(){

System.out.println "Đối tượng loài động vật có vú.");

}

}

Page 145: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 135

class Nguoi extends DongVatCoVu{

void hienThi(){

System.out.println "Đối tượng loài người.");

}

}

class CaHeo extends DongVatCoVu{

void hienThi(){

System.out.println "Đối tượng loài cá heo.");

}

}

class Bo extends DongVatCoVu{

void hienThi(){

System.out.println "Đối tượng loài bò.");

}

}

class BoSat extends DongVat{

void hienThi(){

System.out.println "Đối tượng loài bò sát.");

}

}

class ThanLan extends BoSat{

void hienThi(){

System.out.println "Đối tượng loài thằn lằn.");

}

}

class Rua extends BoSat{

void hienThi(){

System.out.println "Đối tượng loài rùa");

}

}

Page 146: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 136

class TacKe extends ThanLan{

void hienThi(){

System.out.println "Đối tượng loài tắc kè.");

}

}

class KyNhong extends ThanLan{

void hienThi(){

System.out.println("Đối tượng loài kỳ nhông.");

}

}

public class DynamicBindingTesting {

public static void main(String[] args) {

BoSat bs = new BoSat();

bs.hienThi(); // Đối tượng loài bò sát.

BoSat tl = new ThanLan();

tl.hienThi(); // Đối tượng loài thằn lằn.

DongVat dv = tl; /* upcasting tới DongVat. Tham chiếu dv sẽ tự động liên kết tới đối tượng được tham chiếu bởi tl*/

dv.hienThi(); //Đối tượng loài thằn lằn.

/* TacKe tk = tl; // downcasting -> Type mismatch error: cannot convert from BoSat to TacKke */

ArrayList<DongVat> dsdv = new ArrayList<DongVat>();

dsdv.add(new DongVat());

dsdv.add(new DongVatCoVu()); //upcasting

dsdv.add(new Nguoi());

dsdv.add(new Nguoi());

dsdv.add(new Nguoi());

dsdv.add(new CaHeo());

dsdv.add(new CaHeo());

dsdv.add(new Bo());

dsdv.add(new Bo());

dsdv.add(new BoSat());

Page 147: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 137

dsdv.add(new TacKe());

dsdv.add(new TacKe());

dsdv.add(new KyNhong());

dsdv.add(new KyNhong());

dsdv.add(new KyNhong());

int slgDongVat=0, slgDVCV=0, slgBS = 0;

System.out.println("\n---Liệt kê các đối tượng được tạo ---");

Iterator<DongVat> itr = dsdv.iterator();

while (itr.hasNext()) {

DongVat dongVat = itr.next();

//dynamic binding via parametric polymorphism

dongVat.hienThi();

if( dongVat instanceof DongVat) slgDongVat++;

if( dongVat instanceof DongVatCoVu) slgDVCV++;

if( dongVat instanceof BoSat) slgBS++;

}

System.out.printf("\nSố đối tượng được tạo từ (Is-a) lớp DongVat là %d.\n",slgDongVat);

System.out.printf("Số đối tượng được tạo từ lớp DongVatCoVu là %d.\n",slgDVCV);

System.out.printf("Số đối tượng được tạo từ lớp

BoSat là %d.\n",slgBS);

}

}

Kết quả c a chương trình: Số đối tượng được tạo từ (Is-a) lớp DongVat là 15.

Số đối tượng được tạo từ lớp DongVatCoVu là 8.

Số đối tượng được tạo từ lớp BoSat là 6.

Bài t p ch ng 8

Bài 8.1: Hãy trừu tượng hóa để xây dựng sơ đồ lớp cho bài toán tính diện tích, chu vi, thể tích (nếu có) c a các hình tròn, elip, hình vuông, chữ nhật, thoi, bình hành, hình trụ, hình nón, hình khối vuông lập phương sao cho có tồn tại ít nhất các tính bao đóng, thừa kế và đa hình. Viết dự án hoàn chỉnh b ng ngôn ngữ Java.

Page 148: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 138

Bài 8.2: Hãy trừu tượng hóa để xây dựng sơ đồ lớp cho bài toán Quản lý các thông số và tính năng phương tiện giao thông tiện đư ng bộ cho:

Loại xe 2 bánh như: xe 50cc, 100cc, 150cc,… c a hãng Honda, Suzuki, Piaggio,…

Loại xe 4 bánh như: xe tải, xe khách, xe hơi c a các hãng Toyota, Mercedes, Hyundai,…

Sao cho thể hiện được các mối kết hợp Has-A, Is-A, bao đóng và đa hình. Viết dự án hoàn chỉnh b ng ngôn ngữ Java.

Page 149: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 139

Ch ng 9. L p trừu t ng và giao di n

Chương này sẽ trình bày các dạng khác nhau giữa lớp cụ thể, lớp trừu tượng cũng như giao diện và lớp thực thi giao diện. Các dạng thừa kế và đa hình thông qua các lớp trừu tượng và giao diện cũng sẽ được đề cập. Đồng th i, chương này cũng tống hợp các kiến th c c a các chương trước vào những ví dụ và các bài tập lớn là những dự án có tính nghiên c u (case study) nh m giúp cho ngư i học có khả năng phân tích, thiết kế các dự án lớn trong thực tế theo phương pháp lập trình hướng đối tượng.

9.1 Khái nhi m v l p trừu t ng

Trong quá trình thiết kế chương trình, chúng ta thư ng đi theo quy trình: Từ tổng quát (general) đến cụ thể (specific). Tổng quát là có tính trừu tượng, chung chung chưa rõ ràng cụ thể. Nó chỉ dừng lại m c khái niệm đó là những cái gì, chúng dấp dáng làm sao (what) ch chưa quan tâm đến việc làm sao để chúng hoạt động được, cài đặt chúng ra sao (how). Việc định nghĩa một lớp mà còn tồn tại những điểm chưa thể rõ ràng ngay được, còn mang tính tổng quát như thế được gọi là lớp trừu tượng (abstract class).

Hay nói cách khác, khi đang định nghĩa lớp, chúng ta thư ng xác định tên c a lớp là (cái) gì, đồng th i liệt kê (outline) ra các đặc tính gồm các thuộc tính và các phương th c c nó. Nếu trong các phương th c mà tồn tại ít nhất một phương th c chưa thể cài đặt cụ thể được do nó còn tính tổng quát, thì đó là lớp trừu tượng.

Ngược lại với tính tổng quá là tính cụ thể, đó là trư ng hợp điển hình, rõ ràng và hoàn toàn tư ng minh. Một lớp, mà khi định nghĩa, có các đặc điểm rõ ràng, riêng biệt như trên được gọi là các lớp cụ thể (concrete class): có thể cài đặt tất cả các hành vi (phương th c) một cách chi tiết.

Như vậy, khác với lớp trừu tượng, lớp cụ thể là lớp mà mọi phương th c c a nó đều được cài đặt hoàn chỉnh hay nói cách khác tất cả các phương th c c a nó là các phương th c cụ thể. Các chương trước đều được trình bày dựa trên quan điểm c a lớp cụ thể.

Mục đích c a lớp trừu tượng là để cung cấp một lớp cơ s thích hợp mà từ đó các lớp dẫn xuất khác có thể kế thừa để có thể chia sẻ một thiết kế chung. Quá trình trừu tượng từ m c tổng quát cho đến m c cụ thể có thể có nhiều m c độ khác nhau để giảm dần m c trừu tượng xuống hay tăng dần m c cụ thể lên.

9.2 Cách khai báo l p trừu t ng

[Modifier] abstract class TênLớpTrừuTượng {

[Modifier] data_type tênTrư ng_1;

[Modifier] data_type tênTrư ng_m;

// Khai báo các chữ ký phương th c trừu tượng

[Modifier] abstract return_type tênPhươngTh c_1([Các_Tham_số]);

[Modifier] abstract return_type tênPhươngTh c_i([Các_Tham_số]);

Page 150: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 140

// Định nghĩa các phương th c cụ thể

[Modifier] return_type tênPhươngTh c_j([Các_Tham_số]){

//…

return (giá trị trả về);

}

[Modifier] return_type tênPhươngTh c_n([Các_Tham_số]){

//…

return (giá trị trả về);

}

}

Lớp trừu tượng được định nghĩa b i từ khóa abstract. Nó phải tồn tại ít nhất một hoặc tất cả các phương th c trừu tượng (abstract methods). Phương th c trừu tượng được khai báo với từ khóa abstract và chữ ký c a phương th c (method signature): chỉ có phần tên và danh sách các tham số c a phương th c.

Lớp trừu tượng thư ng đóng vai trò làm lớp cha (lớp cơ s ) để các con thừa kế từ nó, lớp con này cũng có thể là lớp trừu tượng hoặc là lớp cụ thể. Trong sơ đồ cây phân cấp thừa kế, các lớp nút lá chính là các lớp cụ thể: cài đặt đầy đ các phương th c trừu tượng lớp cha cho các m c lên đến nút gốc.

Do là lớp trừu tượng nên ta không thể sử dụng từ khóa new để tạo các thể hiện (đối tượng) từ lớp này được.

Ví d 9.1: Chương trình thể hiện sự thừa kế thông qua lớp trừu tượng. Các lớp cụ thể được thiết kế và viết theo các cách khác nhau để minh họa cho việc truy xuất các biến trư ng c a lớp trừu tượng từ chúng.

Hình 9.1: Sơ đồ lớp trừu tượng Shape

Page 151: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 141

Mã nguồn java cho ví dụ này:

/**

* Filename: AbstractclassTesting.java

* Thừa kế thông qua lớp trừu tượng

*/

package ctu.vdlinh.chapter9;

class RGB{ //lớp cụ thể

private int red, green, blue;

public RGB() {

red = 255;

green = 0;

blue = 0;

}

public RGB(int red, int green, int blue) {

this.red = red;

this.green = green;

this.blue = blue;

}

@Override

public String toString() {

return "là RGB("+red+","+green+","+blue+")";

}

}

abstract class Shape { //lớp trừu tượng

private RGB color;

private String name;

// ----------- Các phương thức cụ thể -------------

public Shape() {

color =null;

name = "No name";

}

public Shape(String name) {

this.name = name;

color =null;

}

Page 152: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 142

public Shape(RGB color, String name) {

this.color = color;

this.name = name;

}

public void setColor(RGB color) {

this.color = color;

}

public void setName(String name) {

this.name = name;

}

public void displayInformation(){

System.out.print("Hình "+name+" có màu "+color);

}

// ----------- Phương thức trừu tượng -------------

abstract double computeArea();

}

class Rectangle extends Shape{ //lớp cụ thể

private double length;

private double width;

RGB rgbColor = new RGB();

public Rectangle(double length, double width) {

super("chữ nhật");

super.setColor(rgbColor);

this.length = length;

this.width = width;

}

@Override

double computeArea() { //ghi chồng phương thức cụ thể

return length * width;

}

}

class Triangle extends Shape{ //concrete class

private double base;

private double height;

Page 153: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 143

public void setBase(double base) {

this.base = base;

}

public void setHeight(double height) {

this.height = height;

}

@Override

double computeArea() { // override concrete method

return (base * height)/2;

}

}

class Circle extends Shape{ //concrete class

private double radius;

public Circle(RGB color, String name, double radius) {

super(color, name); this.radius = radius;

}

@Override

double computeArea() {

return Math.PI * radius * radius;

}

}

public class AbstractclassTesting {

public static void main(String[] args) {

//Lấy màu và tên hình mặc định

Rectangle rectangle = new Rectangle(20, 15 );

rectangle.displayInformation();

System.out.printf(" và diện tích= %.2f\n", rectangle.computeArea());

//Dùng phương thức set/get để xác định màu và tên hình

Triangle triangle = new Triangle();

triangle.setColor(new RGB(0,255,0));

triangle.setBase(12.5); triangle.setHeight(5.5);

triangle.setName("tam giác"); triangle.displayInformation();

System.out.printf(" và có diện tích= %.4f\n", triangle.computeArea());

Page 154: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 144

//Dùng phương thức dựng để xác định tên hình và màu sắc

Circle circle = new Circle(new RGB(0,0,255), "tròn", 10);

circle.displayInformation();

System.out.printf(" và có diện tích= %.3f\n", circle.computeArea());

}

}

Biên dịch, chạy và có kết quả:

Hình chữ nhật có màu là RGB(255,0,0) và diện tích= 300.00 Hình tam giác có màu là RGB(0,255,0) và có diện tích= 34.3750 Hình tròn có màu là RGB(0,0,255) và có diện tích= 314.159

Ví d 9.2: Cài đặt tính đa hình thông qua lớp trừu tượng để các đối tượng động vật như chó, mèo, vịt,… thể hiện các thông tin về chúng.

Hình 9.2: Đa hình thông qua lớp trừu tượng

Mã nguồn java:

/**

* File name: PolymorphismAbstractclass.java

* Cài đặt tính đa hình thông qua lớp trừu tượng.

*/

package ctu.vdlinh.chapter9;

abstract class DongVat {

private int soChan = 2;

public int getSoChan() {

return soChan;

}

public void setSoChan(int soChan) {

Page 155: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 145

this.soChan = soChan;

}

abstract void tiengKeu();

}

class Cho extends DongVat {

public void tiengKeu() {

setSoChan(4);

System.out.println "Động vật có " + getSoChan() + " và sủa gâu gâu.");

}

}

class Meo extends DongVat {

public void tiengKeu() {

setSoChan(4);

System.out.println "Động vật có " + getSoChan() + " và kêu meo meo.");

}

}

class Vit extends DongVat {

public void tiengKeu() {

setSoChan(2);

System.out.println "Động vật có " + getSoChan() + " và kêu cạp cạp.");

}

}

class Cop extends DongVat {

public void tiengKeu() {

setSoChan(4);

System.out.println "Động vật có " + getSoChan() + " và gầm gừ gừ.");

}

}

public class PolymorphismAbstractclass {

static void theHien(DongVat dv) {

dv.tiengKeu();

}

public static void main(String[] args) {

Page 156: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 146

theHien(new Cho());

theHien(new Meo());

theHien(new Vit());

theHien(new Cop());

}

}

Kết quả khi chạy chương trình:

Động vật có 4 và sủa gâu gâu. Động vật có 4 và kêu meo meo. Động vật có 2 và kêu cạp cạp. Động vật có 4 và gầm gừ gừ.

9.3 Khái ni m giao di n

Giao diện (Interface): Là một thực thể trừu tượng m c cao hơn cả lớp trừu tượng. Trong khi lớp là mẫu (template) cho việc hình thành đối tượng thì interface là mẫu để hình thành các lớp. Một interface thư ng liệt kê một loạt (các thuộc tính h ng và) các ch c năng (methods) cần phải có, và các ch c năng này đảm nhiệm thực hiện việc gì (what). Các phương th c này chỉ dừng lại m c trừu tượng ch không cần phải biết làm cụ thể như thể nào (how) th i điểm thiết kế. Để cụ thể các ch c năng này thao tác và hoạt động ra sao thì không được chỉ ra trên Interface mà sẽ được chỉ ra trên lớp thực thi interface này.

Hình 9.3: Minh họa giao diện USB

Với interface, ngôn ngữ Java hỗ trợ tính năng thừa kế bội. Đây là một công cụ giúp cho ngư i phân tích thiết kế chương trình theo phương pháp HĐT dễ dàng mô hình hóa bài toán sát với thế giới tự nhiên hơn. m c độ chuyên nghiệp, interface còn được sử dụng phổ biến trong các mẫu thiết kế hướng đối tượng (Design patterns).

Page 157: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 147

9.3.1 Cú pháp khai báo

Sử dụng từ khóa interface để khai báo một giao diện, có thể được thừa kế bội thông qua từ khóa extends, bao gồm các biến h ng lớp và các phương th c trừu tượng như sau:

[public] interface TênGiaoDiện [extends CácGiaoDiệnCha]{

// Khai báo các hằng, ngầm định là public static final

data_type TÊN_H NG_1 = value_1;

data_type TÊN_H NG_m = value_m;

// Khai báo các tên phương th c trừu tượng, ngầm định: public abstract

return-type tênPhươngTh c_1([Các_Tham_số]);

return-type tênPhươngTh c_n([Các_Tham_số]);

}

Cũng giống như abstract class, ta cũng không thể tạo một thể hiện từ interface thông qua từ khóa new.

Ví d 9.3: Định nghĩa giao diện là IDongVat chỉ có một phương th c trừu tượng

hoặc

Hình 9.4: Sơ đồ UML cho interface

interface IDongVat {

void tuGioiThieu();

}

9.3.2 Sự cƠi đặt giao di n

Interface được xem như là một mẫu để hình thành các lớp. Do đó cần phải có các lớp làm nhiệm vụ cài đặt cụ thể, thông qua từ khóa implements, các phương th c trừu tượng trong interface để các phương th c này và được gọi là lớp thực thi giao diện (implementation class)

Cú pháp cài đặt lớp thực thi giao diện:

[Modifiers] [abstract] class TênLớp implements TênGiaoDiện [, TênGiaoDiện2,… ] {

// Phần thân c a lớp

}

Page 158: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 148

Ví d 9.3: Định nghĩa giao diện IDongVat và các lớp thực thi Meo, Chuot được cài đặt từ giao diện.

Hình 9.5: Sơ đồ lớp và dự án

//File name: IDongVat.java

package ctu.vdlinh.implementinginterface;

public interface IDongVat {

void tuGioiThieu();

}

//File name: ImplementInterfaceTesting.java package ctu.vdlinh.implementinginterface;

class Meo implements IDongVat{

public void tuGioiThieu(){

System.out.println "Xin chào, tôi là Doremon đại diện họ nhà mèo.");

}

}

class Chuot implements IDongVat{

public void tuGioiThieu(){

System.out.println("Xin chào, tôi là Mickey đại diện họ nhà chuột.");

}

}

public class ImplementInterfaceTesting {

public static void main(String[] args) {

IDongVat dv = new Meo(); dv.tuGioiThieu();

dv= new Chuot(); dv.tuGioiThieu();

}

}

Page 159: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 149

Chạy chương trình, ta được kết quả:

Xin chào, tôi là Doremon đại diện họ nhà mèo.

Xin chào, tôi là Mickey đại diện họ nhà chuột.

Một cách tổng quát, lớp thực thi có thể được thừa kế đơn từ một lớp cha và cài đặt từ nhiều giao diện như cú pháp được sử dụng phổ biến trong ngôn ngữ Java như sau:

[Modifiers] [abstract] class TênLớpCon extends TênLớpCha implements TênGiaoDiện [,TênGiaoDiện 2,…] {

// Phần thân c a lớp

}

Ví d 9.4: Định nghĩa một lớp thực thi PhuongTrinhBacNhat thừa kế từ lớp cơ s PhepTinh và các giao diện IPhepCong, IPhepTru, IPhepNhan, IPhepChia.

class PhuongTrinhBacNhat extends PhepTinhCoBan implements IPhepCong, IPhepTru, IPhepNhan, IPhepChia {

private ManHinh mh;

public void cong() {

mh.setKetQua(String.format("%.2f", mh.getA() + mh.getB()));

}

//...

}

Ví d 9.5: Giả sử máy tính bỏ túi được mô hình hóa đối tượng theo sơ đồ lớp như hình 9.6, hãy viết chương trình hoàn chỉnh ng dụng này.

Hình 9.6: Sơ đồ lớp c a máy tính bỏ túi

Page 160: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 150

Mã l nh Java:

//Filename: ManHinh.java

package ctu.vdlinh.package1;

public class ManHinh {

private double a, b;

private String ketQua;

public ManHinh() {

super();

}

public ManHinh(double a, double b){

this.a = a;

this.b = b;

}

public double getA() {

return a;

}

public double getB() {

return b;

}

public String getKetQua() {

return ketQua;

}

public void setKetQua(String ketQua) {

this.ketQua = ketQua;

}

}

//Filename: PhepTinhCoBan.java

package ctu.vdlinh.package2;

import ctu.vdlinh.package1.ManHinh;

interface IPhepCong {

void cong();

}

interface IPhepTru {

void tru();

Page 161: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 151

}

interface IPhepNhan {

void nhan();

}

interface IPhepChia {

void chia();

}

public class PhepTinhCoBan implements IPhepCong, IPhepTru, IPhepNhan, IPhepChia {

private ManHinh mh;

public PhepTinhCoBan(ManHinh mh) {

this.mh = mh;

}

public PhepTinhCoBan() {

}

public ManHinh getMh() {

return mh;

}

public void cong() {

mh.setKetQua(String.format("%.2f", mh.getA() + mh.getB()));

}

public void tru() {

mh.setKetQua(String.format("%.2f", mh.getA() - mh.getB()));

}

public void nhan() {

mh.setKetQua(String.format("%.2f", mh.getA() * mh.getB()));

}

public void chia() {

if (mh.getB() == 0) {

mh.setKetQua("Lỗi: Phép chia không!");

} else

mh.setKetQua(String.format("%.2f", mh.getA() / mh.getB()));

}

}

Page 162: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 152

//file name: MayTinhBoTui.java

package ctu.vdlinh.package3;

import java.util.Scanner;

import ctu.vdlinh.package1.ManHinh;

import ctu.vdlinh.package2.PhepTinhCoBan;

public class MayTinhBoTui {

public static void main(String[] args) {

double so1, so2; char c;

Scanner in = new Scanner(System.in);

do {

System.out.print("Nhập số thứ 1= "); so1 = in.nextDouble();

System.out.print("Nhập số thứ 2= "); so2 = in.nextDouble();

ManHinh mh = new ManHinh(so1,so2);

PhepTinhCoBan pt = new PhepTinhCoBan(mh);

System.out.print("Bạn cần tính phép toán nào: (+, -,* , /) va T để thoát? ");

String s = in.next();

c = s.charAt(0);

switch (c) {

case '+':

pt.cong();

System.out.println("Tổng= " + pt.getMh().getKetQua());

break;

case '-':

pt.tru();

System.out.println("Hiệu= " + pt.getMh().getKetQua());

break;

case '*':

pt.nhan();

System.out.println("Tích= " + pt.getMh().getKetQua());

break;

case '/':

pt.chia();

System.out.println "Thương= " + pt.getMh .getKetQua ;

break;

Page 163: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 153

}

} while (Character.toUpperCase(c) != 'T');

System.out.println "Chương trình kếtthúc.");

in.close();

}

}

Chạy thử chương trình: Nhập số thứ 1= 12 Nhập số thứ 2= 6 Bạn cần tính phép toán nào (+, -,* , /) va T de thoat ? + Tổng= 18.00 Nhập số thứ 1= 12 Nhập số thứ 2= 0 Bạn cần tính phép toán nào (+, -,* , /) va T de thoat ? / Thương= Lỗi: Phép chia không!

9.3.3 Thừa k b i bằng giao di n

Java cho phép định nghĩa một giao diện con được thừa kế từ nhiều giao diện cha. Điều này giúp cho việc mô hình hóa đối tượng và trừu tượng hóa trong những dự án lớn trong có trong thế giới tự nhiên được dễ dàng hơn.

Ví d 9.6: Mô hình hóa đối hướng đối tượng để cài đặt một máy bay th y phi cơ (Sea plane) lưỡng dụng như sơ đồ lớp hình 9.7.

Hình 9.7: Sơ đồ lớp th y phi cơ

Mã lệnh Java

Page 164: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 154

// File name: SeaPlane.java

package ctu.vdlinh.interfacesinheritance;

interface FlyPlane {

public void land();

public void takeOff();

}

interface FlyingBoat {

public void fly();

public void run();

}

interface Boeing extends FlyPlane, FlyingBoat {

public void engine();

}

interface ChampionAircraft {

public void body();

}

public class SeaPlane implements Boeing, ChampionAircraft {

public void takeOff() {

System.out.println("\t- take off from water/the sea");

}

public void land() {

System.out.println("\t- make a landing on water");

}

public void fly() {

System.out.println("\t- fly in the air");

}

public void run() {

System.out.println("\t- run/swim on water");

}

public void engine() {

System.out.println("\t- Engine was made by Boeing");

}

public void body() {

Page 165: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 155

System.out.println("\t- Body was constructed by Champion Aircraft corporation");

}

}

// File name: IMITesting.java

package ctu.vdlinh.interfacesinheritance;

/**

* @author Vu Duy Linh

* @version 1.1 2012-05-25

*/

public class IMITesting {

public static void main(String[] args) {

SeaPlane mySeaPlane = new SeaPlane();

//Thực hiện các chức năng để trở thành một thủy phi cơ

System.out.println("Some information about my sea plane: ");

mySeaPlane.engine();

mySeaPlane.body();

System.out.println("And it can:");

mySeaPlane.takeOff();

mySeaPlane.land();

mySeaPlane.fly();

mySeaPlane.run();

}

}

K t quả khi ch y ch ng trình: Some information about my sea plane:

- Engine was made by Boeing

- Body was constructed by Champion Aircraft corporation

And it can:

- take off from water/the sea

- make a landing on water

- fly in the air

- run/swim on water

Tương tự như lớp, Interface cũng thể hiện tính đa hình động (đa hình thông qua giao diện) như ví dụ 9.7 dưới đây.

Page 166: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 156

Ví d 9.7: Đa hình động đối tượng c a các lớp con: Chim công (Peacock), chim kền kền (Vulture), chim hạc (Crane)

Hình 9.8: Sơ đồ lớp cho ví dụ

//File name: DynamicPolyInterface.java

package ctu.vdlinh.chapter9;

/**

* @author Unknown

* Reference: The website of WAY2JAVA

*/

interface Bird {

public abstract void eat(); // I

}

class Peacock implements Bird {

public void eat() { // II

System.out.println("Peacock eats grains.");

}

}

class Vulture implements Bird {

public void eat() { // III

System.out.println("Vulture eats flesh.");

}

}

class Crane implements Bird {

public void eat() { // IV

System.out.println("Crane eats fish.");

}

Page 167: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 157

}

public class DynamicPolyInterface {

public static void main(String args[]) {

Bird b1; // reference variable of interface

Peacock p1 = new Peacock();

b1 = p1; b1.eat(); // calls II

Vulture v1 = new Vulture();

b1 = v1; b1.eat(); // calls III

Crane c1 = new Crane();

b1 = c1; b1.eat(); // calls IV

}

}

Khi chạy ta có kết quả sau:

Peacock eats grains.

Vulture eats flesh.

Crane eats fish.

Ví d 9.8: Với sơ đồ lớp đã được cho như hình 9.9, đã thể hiện được các tính bao đóng, trừu tượng, thừa kế, đa hình,… để tính lương cho các loại nhân viên khác nhau.

Hình 9.9: Sơ đồ lớp cho ví dụ tiền lương

Page 168: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 158

Sau đây là mã lệnh viết theo phương pháp lập trình hướng đối tượng Java, với phong cách chuyên nghiệp, được trích nguyên văn c a tác giả Deitel & Associaties, Inc.

package deitel_associates; /** * File: Payable.java

* Payable interface declaration. * @author Deitel & Associates, Inc. */ public interface Payable {

/** * calculate payment; no implementation * @return the payment for this item */ double getPaymentAmount(); } // end interface Payable

package deitel_associates;

/**

* File: Employee.java

* Employee abstract superclass implements Payable.

* @author Deitel & Associates, Inc.

*/

public abstract class Employee implements Payable {

private String firstName;

private String lastName;

private String socialSecurityNumber;

/**

* three-argument constructor

* @param first first name of employee

* @param last last name of employee

* @param ssn SSN of employee

*/

public Employee(String first, String last, String ssn) {

firstName = first;

lastName = last;

socialSecurityNumber = ssn;

} // end three-argument Employee constructor

/**

Page 169: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 159

* set first name

* @param first first name of employee

*/

public void setFirstName(String first) {

firstName = first; // should validate

} // end method setFirstName

/**

* return first name

* @return first name of employee

*/

public String getFirstName() {

return firstName;

} // end method getFirstName

/**

* set last name

* @param last last name of employee

*/

public void setLastName(String last) {

lastName = last; // should validate

} // end method setLastName

/**

* return last name

* @return last name of employee

*/

public String getLastName() {

return lastName;

} // end method getLastName

/**

* set social security number

* @param ssn SSN of employee

*/

public void setSocialSecurityNumber(String ssn) {

socialSecurityNumber = ssn; // should validate

} // end method setSocialSecurityNumber

/**

Page 170: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 160

* return social security number

* @return SSN of employee

*/

public String getSocialSecurityNumber() {

return socialSecurityNumber;

} // end method getSocialSecurityNumber

/**

* return String representation of Employee object

* @return String representation of Employee object

*/

@Override

public String toString() {

return String.format( "%s %s\nsocial security number: %s",

getFirstName(),getLastName(), getSocialSecurityNumber());

} // end method toString

// Note: We do not implement Payable method getPaymentAmount here so

// this class must be declared abstract to avoid a compilation error.

} // end abstract class Employee

package deitel_associates;

/**

* File: Invoice.java

* Invoice class implements Payable.

* @author Deitel & Associates, Inc.

*/

public class Invoice implements Payable {

private String partNumber;

private String partDescription;

private int quantity;

private double pricePerItem;

/**

* four-argument constructor

* @param part the part number

* @param description the part description

* @param count how many

* @param price cost per item

Page 171: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 161

*/

public Invoice(String part, String description, int count,

double price) {

partNumber = part;

partDescription = description;

setQuantity(count); // validate and store quantity

setPricePerItem(price); // validate and store price per item

} // end four-argument Invoice constructor

/**

* set part number

* @param part the part number

*/

public void setPartNumber(String part) {

partNumber = part; // should validate

} // end method setPartNumber

/**

* get part number

* @return the part number

*/

public String getPartNumber() {

return partNumber;

} // end method getPartNumber

/**

* set description

* @param description the part description

*/

public void setPartDescription(String description) {

partDescription = description; // should validate

} // end method setPartDescription

/**

* get description

* @return the part description

*/

public String getPartDescription() {

return partDescription;

Page 172: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 162

} // end method getPartDescription

/**

* set quantity

* @param count how many

*/

public void setQuantity(int count) {

if ( count >= 0 ) quantity = count;

else

throw new IllegalArgumentException("Quantity must be >= 0");

} // end method setQuantity

/**

* get quantity

* @return how many

*/

public int getQuantity() {

return quantity;

} // end method getQuantity

/**

* set price per item

* @param price price per item

*/

public void setPricePerItem(double price) {

if ( price >= 0.0 ) pricePerItem = price;

else throw new IllegalArgumentException(

"Price per item must be >= 0");

} // end method setPricePerItem

/**

* get price per item

* @return price per item

*/

public double getPricePerItem() {

return pricePerItem;

} // end method getPricePerItem

/**

* return String representation of Invoice object

Page 173: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 163

* @return String representation of Invoice object

*/

@Override

public String toString() {

return String.format("%s: \n%s: %s (%s) \n%s: %d \n%s: $%,.2f",

"invoice", "part number", getPartNumber(), getPartDescription(),

"quantity", getQuantity(), "price per item", getPricePerItem());

} // end method toString

/**

* method required to carry out contract with interface Payable

* @return the cost of this invoice

*/

@Override

public double getPaymentAmount() {

return getQuantity() * getPricePerItem(); // calculate total cost

} // end method getPaymentAmount

} // end class Invoice

package deitel_associates;

/**

* File: CommissionEmployee.java

* CommissionEmployee class extends Employee.

* @author Deitel & Associates, Inc.

*/

public class CommissionEmployee extends Employee {

private double grossSales; // gross weekly sales

private double commissionRate; // commission percentage

/**

* five-argument constructor

* @param first first name of employee

* @param last last name of employee

* @param ssn SSN of employee

* @param sales gross sales of employee

* @param rate commission rate of employee

Page 174: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 164

*/

public CommissionEmployee(String first, String last, String ssn,

double sales, double rate) {

super(first, last, ssn);

setGrossSales(sales);

setCommissionRate(rate);

} // end five-argument CommissionEmployee constructor

/**

* set commission rate

* @param rate commission rate of employee

*/

public void setCommissionRate(double rate) {

if (rate > 0.0 && rate < 1.0) commissionRate = rate;

else throw new IllegalArgumentException(

"Commission rate must be > 0.0 and < 1.0");

} // end method setCommissionRate

/**

* return commission rate

* @return commission rate of employee

*/

public double getCommissionRate() {

return commissionRate;

} // end method getCommissionRate

/**

* set gross sales amount

* @param sales gross sales of employee

*/

// set gross sales amount

public void setGrossSales(double sales) {

if (sales >= 0.0) grossSales = sales;

else throw new IllegalArgumentException(

"Gross sales must be >= 0.0" );

} // end method setGrossSales

/**

* return gross sales amount

Page 175: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 165

* @return gross sales of employee

*/

public double getGrossSales() {

return grossSales;

} // end method getGrossSales

/**

* calculate pay; implements Payable interface * method getPaymentAmount

* @return pay of employee

*/

@Override

public double getPaymentAmount() {

return getCommissionRate() * getGrossSales();

} // end method getPaymentAmount

/**

* return String representation of CommissionEmployee object

* @return String representation of CommissionEmployee object

*/

@Override

public String toString() {

return String.format("%s: %s\n%s: $%,.2f; %s: %.2f",

"commission employee", super.toString(),

"gross sales", getGrossSales(),

"commission rate", getCommissionRate());

} // end method toString

} // end class CommissionEmployee

package deitel_associates;

/**

* File: HourlyEmployee.java

* HourlyEmployee class extends Employee.

* @author Deitel & Associates, Inc.

*/

public class HourlyEmployee extends Employee {

private double wage; // wage per hour

private double hours; // hours worked for week

Page 176: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 166

/**

* five-argument constructor

* @param first first name of employee

* @param last last name of employee

* @param ssn SSN of employee

* @param hourlyWage hourly wage of employee

* @param hoursWorked number of hours worked by employee

*/

public HourlyEmployee(String first, String last, String ssn,

double hourlyWage, double hoursWorked) {

super(first, last, ssn);

setWage(hourlyWage); // validate and store hourly wage

setHours(hoursWorked); // validate and store hours worked

} // end five-argument HourlyEmployee constructor

/**

* set wage

* @param hourlyWage hourly wage of employee

*/

public void setWage(double hourlyWage) {

if (hourlyWage >= 0.0) wage = hourlyWage;

else throw new IllegalArgumentException(

"Hourly wage must be >= 0.0" );

} // end method setWage

/**

* return wage

* @return hourly wage of employee

*/

public double getWage() {

return wage;

} // end method getWage

/**

* set hours worked

* @param hoursWorked number of hours worked by employee

*/

public void setHours(double hoursWorked) {

Page 177: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 167

if ( ( hoursWorked >= 0.0 ) && ( hoursWorked <= 168.0 ) )

hours = hoursWorked;

else throw new IllegalArgumentException(

"Hours worked must be >= 0.0 and <= 168.0" );

} // end method setHours

/**

* return hours worked

* @return number of hours worked by employee

*/

public double getHours() {

return hours;

} // end method getHours

/**

* calculate pay; override Payable interface method getPaymentAmount

* @return pay of employee

*/

@Override

public double getPaymentAmount() {

if (getHours() <= 40) // no overtime

return getWage() * getHours();

else

return 40 * getWage() + (getHours() - 40) * getWage() * 1.5;

} // end method getPaymentAmount

// return String representation of HourlyEmployee object

@Override

public String toString() {

return String.format( "hourly employee: %s\n%s: $%,.2f; %s: %,.2f", super.toString(), "hourly wage", getWage(),

"hours worked", getHours() );

} // end method toString

} // end class HourlyEmployee

package deitel_associates;

/**

* File: SalariedEmployee.java

* SalariedEmployee class extends Employee, which implements Payable.

Page 178: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 168

* @author Deitel & Associates, Inc.

*/

public class SalariedEmployee extends Employee {

private double weeklySalary;

/**

* four-argument constructor

* @param first first name of the employee

* @param last last name of the employee

* @param ssn SSN of the employee

* @param salary the salary the employee

*/

public SalariedEmployee(String first, String last, String ssn,

double salary) {

super(first, last, ssn); // pass to Employee constructor

setWeeklySalary(salary); // validate and store salary

} // end four-argument SalariedEmployee constructor

/**

* set salary

* @param salary the salary of the employee

*/

public void setWeeklySalary(double salary) {

if ( salary >= 0.0 ) weeklySalary = salary;

else throw new IllegalArgumentException(

"Weekly salary must be >= 0.0" );

} // end method setWeeklySalary

/**

* return salary

* @return the salary of the employee

*/

public double getWeeklySalary() {

return weeklySalary;

} // end method getWeeklySalary

/**

* calculate pay; implement interface Payable method that was

* abstract in superclass Employee

Page 179: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 169

* @return pay of the employee

*/

@Override

public double getPaymentAmount() {

return getWeeklySalary();

} // end method getPaymentAmount

/**

* return String representation of SalariedEmployee object

* @return String representation of SalariedEmployee object

*/

@Override

public String toString() {

return String.format("salaried employee: %s\n%s: $%,.2f",

super.toString(), "weekly salary", getWeeklySalary());

} // end method toString

} // end class SalariedEmployee

package deitel_associates;

/**

* File: BasePlusCommissionEmployee.java

* BasePlusCommissionEmployee class extends CommissionEmployee.

* @author Deitel & Associates, Inc.

*/

public class BasePlusCommissionEmployee extends CommissionEmployee {

private double baseSalary; // base salary per week

/**

* six-argument constructor

* @param first first name of employee

* @param last last name of employee

* @param ssn SSN of employee

* @param sales total sales of employee

* @param rate commission rate of employee

* @param salary base salary of employee

*/

public BasePlusCommissionEmployee(String first, String last,

String ssn, double sales, double rate, double salary) {

Page 180: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 170

super(first, last, ssn, sales, rate);

setBaseSalary(salary); // validate and store base salary

} // end six-argument BasePlusCommissionEmployee constructor

/**

* set base salary

* @param salary base salary of employee

*/

public void setBaseSalary(double salary) {

if (salary >= 0.0) baseSalary = salary;

else throw new IllegalArgumentException(

"Base salary must be >= 0.0" );

} // end method setBaseSalary

/**

* return base salary

* @return base salary of employee

*/

public double getBaseSalary() {

return baseSalary;

} // end method getBaseSalary

/**

* calculate pay; override method getPaymentAmount in * CommissionEmployee

* @return pay of employee

*/

@Override

public double getPaymentAmount() {

return getBaseSalary() + super.getPaymentAmount();

} // end method getPaymentAmount

/**

* return String representation of BasePlusCommissionEmployee object

* @return String representation of BasePlusCommissionEmployee

*/

@Override

public String toString() {

return String.format("%s %s; %s: $%,.2f",

Page 181: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 171

"base-salaried", super.toString(),

"base salary", getBaseSalary());

} // end method toString

} // end class BasePlusCommissionEmployee

package deitel_associates;

/**

* File: PayrollSystemTest.java

* Employee hierarchy test program

* @author Deitel & Associates, Inc.

*/

public class PayrollSystemTest {

public static void main( String[] args ) {

SalariedEmployee salariedEmployee =

new SalariedEmployee( "John", "Smith", "111-11-1111", 800);

HourlyEmployee hourlyEmployee = new HourlyEmployee( "Karen", "Price", "222-22-2222", 16.75, 40 );

CommissionEmployee commissionEmployee = new CommissionEmployee( "Sue","Jones", "333-33-3333", 10000, .06 );

BasePlusCommissionEmployee basePlusCommissionEmployee =

new BasePlusCommissionEmployee("Bob", "Lewis", "444-44-4444", 5000, .04, 300 );

System.out.println( "Employees processed individually:\n" );

System.out.printf( "%s\n%s: $%,.2f\n\n",

salariedEmployee, "earned", salariedEmployee.getPaymentAmount() );

System.out.printf( "%s\n%s: $%,.2f\n\n",

hourlyEmployee, "earned",hourlyEmployee.getPaymentAmount());

System.out.printf( "%s\n%s: $%,.2f\n\n",commissionEmployee, "earned", commissionEmployee.getPaymentAmount() );

System.out.printf( "%s\n%s: $%,.2f\n\n",

basePlusCommissionEmployee,

"earned", basePlusCommissionEmployee.getPaymentAmount() );

// create four-element Employee array

Employee[] employees = new Employee[ 4 ];

// initialize array with Employees

employees[ 0 ] = salariedEmployee;

Page 182: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 172

employees[ 1 ] = hourlyEmployee;

employees[ 2 ] = commissionEmployee;

employees[ 3 ] = basePlusCommissionEmployee;

System.out.println( "Employees processed polymorphically:\n" );

// generically process each element in array employees

for ( Employee currentEmployee : employees ) {

System.out.println( currentEmployee ); // invokes toString

// determine whether element is a BasePlusCommissionEmployee

if ( currentEmployee instanceof BasePlusCommissionEmployee ){

// downcast Employee reference to

// BasePlusCommissionEmployee reference

BasePlusCommissionEmployee employee =

( BasePlusCommissionEmployee ) currentEmployee;

employee.setBaseSalary( 1.10 * employee.getBaseSalary() );

System.out.printf( "new base salary with 10%% increase is: $%,.2f\n", employee.getBaseSalary() );

} // end if

System.out.printf(

"earned $%,.2f\n\n", currentEmployee.getPaymentAmount() );

} // end for

// get type name of each object in employees array

for ( int j = 0; j < employees.length; j++ )

System.out.printf( "Employee %d is a %s\n", j,

employees[ j ].getClass().getName() );

} // end main

} // end class PayrollSystemTest

Bài t p ch ng 9

Bài 9.1: M rộng bài tập 7.3, sinh viên hãy phân tích và thiết kế sơ đồ lớp sao cho có ch a Interface, Abstract class,… Gợi ý: Dự án thể hiện càng nhiều tính hướng đối tượng càng tốt và có khả năng tái sử dụng code.

Bài 9.2: Hãy m rộng bài tập 8.1 sao cho có ch a Interface, Abstract class và đặt trong ít nhất hai package khác nhau.

Bài 9.3: Case study 1 - Cho Class diagram về hệ thống ATM như hình 9.10: a. Dựa vào tài liệu tham khảo, hãy tìm hiểu và diễn giải sơ đồ lớp này.

Page 183: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 173

b. Giả sử bạn là Trư ng nhóm (Team leader) có 03 thành viên, hãy trừu tượng hóa và thiết kế sơ đồ lớp b ng UML để phân chia công việc cho các thành viên trong nhóm sao cho dự án kết thúc (hoàn chỉnh) sau d ngày.

Hình 9.10: Sơ đồ lớp c a hệ thống ATM

Bài 9.4: Case study 2 - Dự án về Th vi n - The Library Application Revisited. Dựa vào tài liệu tham khảo, hãy tìm hiểu sơ đồ lớp này và cài đặt b ng ngôn ngữ Java.

Hình 9.11: Sơ đồ lớp c a hệ thống ATM

Page 184: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 174

Bài 9.5: Case study 3 – Dự án Quản lý các thông s vƠ tính năng ph ng ti n giao thông. Dự án giai đoạn đầu, Version 1.0, hiện quan tâm đến 03 phương tiện giao thông: Đư ng bộ, đư ng th y và đư ng hàng không (Phương tiện đư ng s t sẽ được m rộng Version 2.0)

1. Phương tiện đư ng bộ: - Xe 4 bánh: xe tải, xe khách, xe hơi c a các hãng Toyota, Mercedes, Hyundai,

Ford… - Xe 2 bánh: xe 50cc, 100cc, 150cc,… cho xe hãng Honda, Suzuki, Piaggio,

Yamaha,… 2. Phương tiện đư ng th y:

- Thuyền nhỏ (không động cơ): Xuồng, ghe, thuyền tam bản (xuồng ba lá),… - Thuyền lớn (có g n động cơ): thuyền máy, ca-nô, du thuyền, tàu th y,…

3. Phương tiện đư ng hàng không: - Máy bay phản lực: Boeing, Airbus, B52,… - Máy bay trực thăng: AH-64A, MH-60S Seahawk, CASA C-212 Aviocar,…

Yêu c u: Hãy ánh xạ thế giới thực c a bài toán vào máy tính theo phương pháp thiết kế và lập trình hướng đối tượng thông qua sơ đồ lớp (class diagram) và/hoặc sơ đồ tuần tự (sequence diagram) được thể hiện qua các công cụ UML và sinh mã nguồn Java tương ng.

Chú ý: M c độ bài tập chỉ dừng m c minh họa, sinh viên có thể giới hạn m c độ chi tiết c a dự án, không cần phải đầy đ các ch c năng như một phần mềm hoàn chỉnh.

a. Dự án cần quản lý một số phương tiện chỉ thu c vào 01 lo i phương tiện giao thông như: Ca-nô, xuồng ba lá, honda wave-α, Airbus, Seahawk,…

b. Dự án cần quản lý gồm cả một số phương tiện lưỡng dụng thu c vào nhi u lo i phương tiện giao thông như: Xe hơi bay, th y phi cơ, xe wave-α,… như hình 9.12

Xe hơi bay Xe hơi lội nước

Th y phi cơ Xe wave-α v.v…

Hình 9.12: Các phương tiện giao thông

Page 185: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 175

Ch ng 10. Ngo i l và xử lý ngo i l

Chương này đề cập đến các kiến th c để giúp cho về các loại lỗi có thể xảy ra khi chạy chương trình, đó là những ngoại lệ phát sinh có thể có và cách xử lý chúng sao cho chương trình chạy đúng với những kịch bản c a dự án. Các ngoại lệ được trình bày gồm ngoại lệ có kiểm soát và không kiểm soát, lớp chuẩn ngoại lệ Throwable và các lớp con c a nó, câu lệnh try..catch..finally để b t ngoại lệ.

10.1 Gi i thi u

Trong quá trình viết chương trình, với một ngôn ngữ bậc cao như Java, C#, Delphi, Objective-C, … lập trình viên có thể thư ng gặp các lỗi như sau:

Lỗi cú pháp (Syntax errors): Lỗi này dễ nhận thấy khi lập trình viên không tuân theo đúng cú pháp c a ngôn ngữ lập trình và được trình biên dịch hỗ trợ sửa lỗi.

Ví d 10.1: Lỗi cú pháp trong ngôn ngữ Java

int a = (5 +7;

boolean kt := true;

Lỗi ngữ nghĩa (Semantic errors): Đây là những lỗi tiềm ẩn mà một lập trình viên dễ m c phải, Nó được phân ra 2 loại: Lỗi ngữ nghĩa tĩnh (static semantic errors) th i điểm biên dịch (compile-time) và lỗi ngữ nghĩa động (dynamic semantic errors) th i điểm chạy chương trình (run-time).

Ví d 10.2: Lỗi ngữ nghĩa trong ngôn ngữ Java

char c = "A"; // type mismatch/incompatibility;

int[] a = new int [3];

a[3] = 12; // java.lang.ArrayIndexOutOfBoundsException

Lỗi logic (Logical errors): Chương trình cho ra những kết quả không mong muốn hoặc sai do thuật toán bị sai logic, hoặc biểu th c toán học nào đó. Lỗi này là hoàn toàn b i nhóm phát triển phần mềm hoặc lập trình viên trực tiếp coding nên trình biên dịch không thể hỗ trợ được. Nếu chương trình có lỗi logic mang tính hệ thống thì chương trình sẽ bị break down và như thế sẽ không thể chuyển giao được.

Ví d 10.3: int cong(int a, int b) {

return a * b;

}

Để giúp cho ngư i viết chương trình có thể kiểm soát và quản lý được các lỗi th i điểm biên dịch cũng như chạy chương trình, ngôn ngữ Java đã cung cấp một cơ chế gọi là ắNgoại lệẰ và ắXử lý ngoại lệẰ, để kh c phục những lỗi mà đôi khi bất khả kháng đối với các nhà phát triển ví dụ như sự cố lỗi thiết bị đọc, lỗi đư ng truyền tín hiệu,… sao cho chương trình chạy theo đúng những kịch bản biết trước.

Page 186: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 176

10.2 Ngo i l

Ngoại lệ (exception) là một cơ chế để thông báo và xử lý các lỗi trong chương trình gặp phải. Khi chương trình phát hiện ra lỗi thì một ngoại lệ tương ng với lỗi sẽ được thẩy/ném/tung ra (throws) để từ đó có cách xử lý thích hợp.

Hình 10.1: Minh họa chương trình có và không có bugs

Có hai loại ngoại lệ cần phân biệt:

Ngoại lệ được kiểm soát (checked exception): Bao gồm tất cả các lỗi cú pháp và một số lỗi ngữ nghĩa tĩnh. Chúng sẽ được phát hiện b i trình biên dịch Java trong th i điểm biên dịch như hình 10.2.

Hình 10.2: Ngoại lệ được kiểm soát

Ngoại lệ không được kiểm soát (unchecked exception): Là lỗi không được phát hiện trong quá trình biên dịch mà chúng chỉ được phát hiện khi chạy chương trình (run-time). Chúng bao gồm các lỗi ngữ nghĩa động và các lỗi logic. Hình 10.3 minh họa cho một ngoại lệ thuộc dạng unchecked exception.

Page 187: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 177

Hình 10.3: Ngoại lệ không được kiểm soát

Các kiểu ngoại lệ được thẩy lên thông qua các lớp chuẩn ngoại lệ c a Java là lớp java.lang.Throwable và các lớp con c a nó theo hệ thống phân cấp như hình sau:

Hình 10.4: Các lớp phục vụ cho ngoại lệ

10.2.1 L p chuẩn ngo i l Error

Hình 10.5: Lớp Error

Page 188: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 178

Lớp Error là một lớp con c a Throwable để chỉ ra các vấn đề nghiêm trọng, gây nguy hiểm (cho sự thực thi chương trình, không được Java phát hiện trong quá trình biên dịch và thuộc loại unchecked exception.

10.2.2 L p chuẩn Exception

Bao gồm lớp RuntimeException cùng với các lớp con c a nó (unchecked exception) và các lớp con khác (checked exception).

Hình 10.6: Lớp Exception

Hình 10.7 thể hiện các lớp con c a lớp Exception trong Java 7, chi tiết được xem trên đư ng link: http://docs.oracle.com/javase/7/docs/api/java/lang/Exception.html

Hình 10.7: Thư viện Java lang.Exception

Sau đây sẽ liệt kê ra một số lớp ngoại lệ trong thư viện chuẩn Java mà có phát sinh lỗi ngoại lệ RuntimeException thư ng gặp:

java.util.EmptyStackException: Lỗi khi ngăn xếp rỗng (empty stack)

Page 189: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 179

Stack stack = new Stack();

stack.pop(); // java.util.EmptyStackException

java.util.NoSuchElementException: Lỗi xảy ra chẳng hạn như trư ng hợp không có phần tử cần tìm trong kiểu liệt kê (enum types)

ArrayList al = new ArrayList();

al.add(new String("Hi!"));

Iterator iterator = al.iterator();

iterator.next(); // ok

iterator.next(); // hết còn phần tử: java.util.NoSuchElementException

java.lang.ArithmaticException: khi tính toán số học sai, như chia cho 0

double a = 10/0; // java.lang.ArithmeticException: / by zero.

java.lang.ArrayStoreException: khi gán sai kiểu đối tượng. Ví dụ như truyền một đối tượng chuỗi vào mảng đối tượng số nguyên.

Object[] x = new Integer[5]; x[0] = new String("Java");

// java.lang.ArrayStoreException: java.lang.String

java.lang.ClassCastException: khi ép kiểu cho một đối tượng chưa được kh i tạo

Object y = new Integer(10); /* y = new Double(y.toString()); // ok */

y = (Double) y; /*java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Double */

java.lang.IllegalArgumentException: Lỗi truyền đối số sai quy cách.

Integer.parseInt("Java in year 2010"); /*java.lang.NumberFormatException: For input string: "Java in year 2010" */

java.lang.IndexOutOfBoundsException: Chỉ số vượt ra ngoài phạm vi c a đối tượng

int[] a = {5, 10, 15};

int v = a[3]; // java.lang.ArrayIndexOutOfBoundsException: 3

java.lang.NegativeArraySizeException: lỗi do kích thước mảng âm.

double[] mang = new double[-10]; //java.lang.NegativeArraySizeException

java.lang.NullPointerException: lỗi truy xuất đối tượng chưa được kh i tạo

double[][] array2D = new double[5][];

array2D[0][0]=8.0; //java.lang.NullPointerException

java.lang.SecurityException: Lỗi không được quyền truy cập.

java.lang.IllegalThreadStateException: liên quan đến các trạng thái c a tuyến đoạn và java.lang.IllegalMonitorStateException: thực hiện các phương th c c a đối tượng monitor (đối tượng giám sát tuyến đoạn) không hợp lệ.

Page 190: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 180

10.3 Xử lý ngo i l

Khi một ngoại lệ xảy ra, một đối tượng thuộc lớp ngoại lệ liên quan đến lỗi đó sẽ được tạo và ném ra. Nh đối tượng ngoại lệ được ném ra này mà ngư i lập trình có thể b t được nó để xử lý lỗi, giúp cho chương trình không bị ng t ngang một cách đột ngột.

Java cung cấp rất đa dạng các lớp ngoại lệ giúp hiệu quả trong việc b t lỗi ngoại lệ. Ví dụ như: lớp ArithmaticException để quản lý lỗi ngoại lệ c a phép toán chia 0, lớp NullPointerException để xử lý lỗi truy xuất đối tượng chưa được kh i tạo,…

Sơ đồ hình dưới đây thể hiện cơ chế tung-h ng giữa thẩy và b t ngoại lệ để xử lý:

Hình 10.8: Ngoại lệ và xử lý

Như vậy xử lý ngoại lệ (exception handling) như một dạng như cấu trúc điều khiển: Khi gặp phải một lỗi, luồng chương trình đang chạy sẽ bị dừng và thẩy lên một ngoại lệ, ngoại lệ này sẽ được n m b t và xử lý sao cho ng dụng đang chạy được kết thúc một cách chuyên nghiệp theo đúng kịch bản sẵn có.

10.3.1 Thẩy ngo i l

Có hai cách để thẩy ngoại lệ tương ng với từ khóa throw và throws.

Từ khóa throw được dùng để tự động thẩy ra một đối tượng ngoại lệ khi JVM phát hiện thấy hoặc những tình huống mà lập trình viên lư ng trước có thể thẩy ra ngoại lệ để xử lý.

Cú pháp: throw throwableObject;

Với throwableObject là một đối tượng thuộc lớp Throwable hoặc lớp con nó.

Ví d 10.4: throw new ArrayIndexOutOfBoundsException("Lỗi chỉ số mảng");

Từ khóa throws được dùng để thẩy ra một hoặc nhiều ngoại lệ từ phương th c khi ta định nghĩa nó.

Page 191: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 181

Cú pháp: [modifiers] returntype methodName([parametters]) throws Class_Exception1,... , Class_Exception_n {

// thân phương th c

}

Với Class_Exception_i: là lớp Throwable hoặc lớp con c a nó.

Ví d 10.5: void tinhMang(int[] a) throws NullPointerException, ArithmeticException{

// lỗi có thể do mảng chưa được kh i tạo, lỗi chia cho không,…

}

10.3.2 Xử lý ngo i l

Trong quá trình viết chương trình, có thể có rất nhiều trư ng hợp phát sinh ra ngoại lệ mà lập trình viên phải lư ng được trước hết mọi trư ng hợp trong phạm vi c a dự án. Để b t và xử lý các lỗi ngoại lệ có thể phát sinh, câu lệnh được sử dụng hiệu quả nhất đó là try .. catch.. finally.

10.3.2.1 Câu lệnh try .. catch .. finally

Câu lệnh này giúp lập trình viên có thể b t các loại lỗi ngoại lệ phát sinh và có những xử lý thích ng với mỗi một chúng b ng câu lệnh catch nhiều tầng như sau:

try {

// statements

/* Nếu các câu lệnh statements không có lỗi thì chạy bình thư ng, ngược lại sẽ thẩy lên một ngoại lệ để b t (catch ) nó*/

} catch (Exception_type_1 e1) {

// … và khối lệnh dùng để xử lý với ngoại lệ loại e1

} catch (Exception_type_2 e2) {

// … và xử lý với loại e2

} catch (Exception_type_3 e3) {

// … và xử lý với loại e3

} catch (Exception e) { // Loại Exception th n

// … và xử lý với loại ngoại lệ e

} finally {

/* Khối lệnh thích hợp sau cùng khi đã b t mọi lỗi ngoại lệ. Nóluôn được thi hành dù có phát sinh lỗi ngoại lệ hay không */

}

Ví d 10.6: Minh họa việc JVM tự động thẩy ra lỗi ngoại lệ và sử dụng câu lệnh try .. catch để xử lý lỗi vi phạm về chỉ số mảng.

Page 192: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 182

Ví d 10.7: Minh họa việc lập trình viên quản lý thẩy ngoại lệ b ng lệnh throw và sử

dụng câu lệnh try .. catch để xử lý lỗi ngoại lệ về chỉ số mảng.

Ví d 10.8: Minh họa việc thẩy ngoại lệ b ng lệnh throw, throws và câu lệnh try ..

catch để xử lý một số lỗi ngoại lệ.

/*

* Reference: http://www.java2s.com/

* File: MainClass.java

*/

Page 193: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 183

package ctu.vdlinh.chapter10;

public class MainClass {

public static void main(String[] args) {

String input = null;

try {

String capitalized = capitalize(input);

System.out.println(capitalized);

} catch (NullPointerException e) {

System.out.println(e.toString());

}

}

public static String capitalize(String s) throws NullPointerException {

if (s == null) {

throw new NullPointerException("Your passed a null argument");

}

Character firstChar = s.charAt(0);

String theRest = s.substring(1);

return firstChar.toString().toUpperCase() + theRest;

}

}

Chạy chương trình: Your passed a null argument

Ví d 10.9: Ví dụ minh họa định nghĩa một lớp ngư i dùng là một lớp con được thừa kế từ lớp Exception.

/*

* Ref: http://www.studytonight.com/

* File: MyException.java

*/

package ctu.vdlinh.chapter10;

public class MyException extends Exception {

private static final long serialVersionUID = 1L;

private int ex;

MyException(int a) {

ex = a;

}

Page 194: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 184

public String toString() {

return "MyException[" + ex + "] is less than zero";

}

}

class Test {

static void sum(int a, int b) throws MyException {

if (a < 0) {

throw new MyException(a);

} else {

System.out.println(a + b);

}

}

public static void main(String[] args) {

try {

sum(-10, 10);

} catch (MyException me) {

System.out.println(me);

}

}

}

Kết quả chạy chương trình: MyException[-10] is less than zero

10.3.2.2 Lan truyền ngoại lệ

Lan truyền ngoại lệ (exception propogation) là một cách lan truyền ngoại lệ từ phương th c này đến phương th c khác thông qua l i gọi phương th c.

Ví d 10.10: Ví dụ minh họa về lan truyền ngoại lệ

/*

* File: CheckedExceptionProp.java

* @author: Vũ Duy Linh

*/

package ctu.vdlinh.chapter10;

import java.util.Scanner;

public class CheckedExceptionProp {

public static void main(String[] args) throws Exception {

Scanner input = new Scanner(System.in);

Page 195: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 185

System.out.print("Nhập một sô nguyên a= ");

int a = input.nextInt(); input.close();

phuongThuc1(a);

}

private static void phuongThuc1(int a) throws Exception {

phuongThuc2(a); //phương thức 1 gọi phthức thứ 2

}

private static void phuongThuc2(int b) throws Exception {

Exception exception = new Exception("Lỗi ngoại lệ: Bạn đã nhập số âm= "+ b);

if (b < 0) throw exception;

System.out.println("Ok bạn đã nhập đúng điều kiện: Số nguyên " + b +" >=0");

}

}

Biên dịch, chạy thử chương trình: Nhập một số nguyên a= 100 Ok bạn đã nhập đúng điều kiện: Số nguyên 100 >=0

10.3.2 Câu l nh kiểm chứng biểu thức

Khẳng định (assertion) là một câu lệnh trong ngôn ngữ Java để cho phép bạn kiểm tra những giả thuyết c a chương trình một cách hiệu quả. Mỗi khẳng định có ch a một biểu th c boolean mà khi nó đúng thì biểu th c (khẳng định) sẽ được thực thi, còn ngược lại thì hệ thống sẽ ném ra một lỗi ngoại lệ. Trong Java có từ khóa assert để thực hiện việc này.

Cú pháp: assert biểuTh cLogic [: "Chuỗi thông báo lỗi" ];

Sẽ kiểm ch ng biểu th c logic xem có phải là khẳng định đúng (true) không, nếu sai thì sinh ra lỗi java.lang.AssertionError, ngược lại thì chương trình tiếp tục. Nếu có thêm phần tùy chọn, lập trình viên tự đưa ra thông báo lỗi b ng ắChuỗi thông báo lỗiẰ thay vì thông báo lỗi mặc định c a JVM.

Chú ý: Để chương trình không bị ng t ngang, lập trình viên cần sử dụng câu lệnh try..catch..finally để b t lỗi ngoại lệ phát sinh (nếu có).

Page 196: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 186

Ví d 10.11: Đoạn mã chương trình minh họa việc sử dụng khẳng định một biểu th c b ng từ khóa assert.

Chú ý các phép chia không trong ngôn ngữ Java:

double a = 1/0; // java.lang.ArithmeticException: / by zero

double a = 1/0.0; // Infinity (vô cực)

Page 197: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 187

Ví d 10.12: Chương trình minh họa cách sử dụng từ khóa assert cho các trư ng hợp: Tiên kiểm (pre-conditions), hậu kiểm (post-conditions) cho các phương th c, và kiểm ch ng bất biến lớp đối tượng (class invariants).

/**

* @author JavaPractices's Teams

* File: Flower.java

*/

package ctu.vdlinh.chapter10;

import java.util.Random;

public final class Flower {

public static void main(String[] arguments) {

final Flower tulip = new Flower("Tulip", 1);

tulip.grow(); tulip.grow();

System.out.println(tulip);

tulip.randomGrowOrWither();

System.out.println(tulip);

tulip.wither(); tulip.wither();

System.out.println(tulip);

}

public Flower(final String aSpecies, final int aInitialLength) {

// assert is NOT used to validate params of public methods

if (!isValidSpecies(aSpecies)) { /* sử dung phthức private để kiểm tra pre-conditions */

throw new IllegalArgumentException("Species must have content.");

}

if (!isValidLength(aInitialLength)) {

throw new IllegalArgumentException("Initial length must be positive.");

}

fSpecies = aSpecies; fLength = aInitialLength;

// check the class invariant

assert hasValidState() : "Construction failed - not valid state.";

}

public boolean isMature() {

return fLength > 5;

Page 198: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 188

}

// Increase the length by at least one unit.

public void grow() {

/* this style of checking post-conditions is NOT recommended, since the copy of fLength is always made, even when assertions are disabled. */

final int oldLength = fLength;

fLength += getLengthIncrease(fLength);

// post-condition: length has increased

assert fLength > oldLength;

// check the class invariant

assert hasValidState() : this;

}

/* Decrease the length by one unit, but only if the resulting length will still be greater than 0. */

public void wither() {

/* this local class exists only to take a snapshot of the current state. although bulky, this style allows post-conditions of arbitrary complexity. */

class OriginalState {

OriginalState() {

fOriginalLength = fLength;

}

int getLength() {

return fOriginalLength;

}

private final int fOriginalLength;

}

OriginalState originalState = null;

/* construct object inside an assertion, in order to ensure that no construction takes place when assertions are disabled this assert is rather unusual in that it will always succeed, and in that it has side-effects it creates an object and sets a reference */

assert(originalState = new OriginalState()) != null;

if (fLength > 1) { --fLength; }

/* post-condition: length has decreased by one or has remained the same */

Page 199: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 189

assert fLength <= originalState.getLength();

// check the class invariant

assert hasValidState() : this;

}

//Randomly select one of three actions: do nothing, grow, wither

public void randomGrowOrWither() {

Random generator = new Random();

int action = generator.nextInt(3);

/* according to the documentation for the Random class, action

should take one of the values 0,1,2. */

if (action == 0) { // do nothing

} else if (action == 1) {

grow();

} else if (action == 2) {

wither();

} else {

// this is still executed if assertions are disabled

throw new AssertionError("Unexpected value for action: " + action);

}

// check the class invariant

assert hasValidState() : this;

}

/** Use for debugging only. */

public String toString() {

final StringBuilder result = new StringBuilder();

result.append(this.getClass().getName());

result.append(": Species="); result.append(fSpecies);

result.append(" Length="); result.append(fLength);

return result.toString();

}

private final String fSpecies;

private int fLength;

/*Implements the class invariant. Perform all checks on the state of the object. One may assert that this method returns true at the end of every public method.*/

Page 200: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 190

private boolean hasValidState() {

return isValidSpecies(fSpecies) && isValidLength(fLength);

}

/** Species must have content. */

private boolean isValidSpecies(final String aSpecies) {

return aSpecies != null && aSpecies.trim().length() > 0;

}

/** Length must be greater than 0. */

private boolean isValidLength(final int aLength) {

return aLength > 0;

}

/** Length increase depends on current length. */

private int getLengthIncrease(int aOriginalLength) {

// since this is a private method, an assertion

// may be used to validate the argument

assert aOriginalLength > 0 : this;

int result = 0

if (aOriginalLength > 10) { result = 2;

} else { result = 1; }

assert result > 0 : result;

return result;

}

}

Chạy chương trình ta có kết quả random như sau: ctu.vdlinh.chapter10.Flower: Species=Tulip Length=3

ctu.vdlinh.chapter10.Flower: Species=Tulip Length=4

ctu.vdlinh.chapter10.Flower: Species=Tulip Length=2

Bài t p ch ng 10

Bài 10.1: Sửa mã nguồn các ví dụ trong giáo trình lý thuyết sao cho chương trình b t được các lỗi ngoại lệ có thể phát sinh khi chạy chương trình.

Bài 10.2: Sửa mã nguồn các bài tập c a các chương trên sao cho chương trình b t được các lỗi ngoại lệ có thể phát sinh khi chạy chương trình.

Page 201: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 191

Ch ng 11. Luồng và t p tin

Dữ liệu được lưu trữ trong các biến và mảng trong chương trình là tạm th i, giá trị c a các biến sẽ bị mất đi khi ra khỏi phạm vi (scope) c a chúng hoặc khi chương trình kết thúc. Để duy trì lâu dài c a dữ liệu, ngay cả sau khi các chương trình mà tạo ra các dữ liệu kết thúc, thì chương trình máy tính phải sử dụng đến các tập tin (files).

Trong chương này sẽ đề cập về kiến trúc c a Java để xử lý các file lập trình. Dữ liệu có thể được lưu trữ trong các tập tin văn bản hoặc tập tin đối tượng, cách lấy thông tin từ các tập tin và thư mục b ng lớp chuẩn File và các cơ chế ghi-đọc dữ liệu từ các tập tin.

11.1 T p tin

Trong lập trình liên quan đến việc đọc ghi dữ liệu lên bộ nhớ ngoài, chúng ta thư ng thực hiện các công việc liên quan đến tập tin, thư mục (File I/O),… như m tập tin, kiểm tra sự tồn tại c a chúng theo một đư ng dẫn tuyệt đối hoặc tương nào đó, xác định hoặc kiểm tra quyền truy xuất vào chúng,...

Trong Java, có hai package chúng ta cần quan tâm đó là gói java.io cho các phiên bản từ java 6 tr về trước, và gói java.nio.file có mặt từ phiên bản java 7 đến nay.

Trong package java.io: chúng ta có các lớp liên quan đến tập tin đó là lớp File, RandomAccessFile (và một luồng FileStream) như hình dưới đây. Chi tiết xem link: https://docs.oracle.com/javase/8/docs/api/java/io/package-tree.html

Hình 11.1: Thư viện Java IO

Ví d 11.1: Viết chương trình tạo và ghi vào text file, nếu file chưa có thì tạo mới còn đã tồn tại thì cập nhập thêm vào (append).

package ctu.vdlinh.chapter11;

import java.io.BufferedWriter;

import java.io.File;

import java.io.FileNotFoundException;

import java.io.FileWriter;

Page 202: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 192

import java.io.IOException;

/**

* Simple Java program to append content and text into File.

* file name: FileAppendTest.java

* @author Javin Paul

*/

public class FileAppendTest {

public static void main(String args[]) throws FileNotFoundException, IOException {

//name of File on which text will be appended,

//currently file contains only one line

//as "This data is before any text appended into file."

String path = "D:/HDTJava/sample.txt";

//creating file object from given path

File file = new File(path);

/*FileWriter second argument is for append if its true than FileWritter will write bytes at the end of File (append) rather than beginning of file */

FileWriter fileWriter = new FileWriter(file,true);

/* Use BufferedWriter instead of FileWriter for better performance */

BufferedWriter bufferFileWriter = new BufferedWriter(fileWriter);

fileWriter.append("This text should be appended in File form Java Program\n");

fileWriter.append("ABC");

/*Don't forget to close Streams or Reader to free FileDescriptor associated with it */

bufferFileWriter.close();

System.out.println("Java Program for appending content into File has been completed");

}

}

Tronng package java.nio.file: cung cấp cho chúng ta nhiều lớp liên quan đến tập tin đó là lớp Files, FileStore, Path,… Chi tiết xem link: https://docs.oracle.com/javase/8/docs/api/java/nio/file/package-tree.html

Page 203: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 193

Hình 11.2: Thư viện nio.file

Ví d 11.2: Liệt kê các tập tin trong mỗi thư mục một cách đệ quy.

package ctu.vdlinh.chapter11;

/**

* @author java2s.com

* File: ListFileTest.java

*/

import java.io.IOException;

import java.nio.file.FileVisitResult;

import java.nio.file.Files;

import java.nio.file.Path;

import java.nio.file.Paths;

import java.nio.file.SimpleFileVisitor;

import java.nio.file.attribute.BasicFileAttributes;

class ListFiles extends SimpleFileVisitor<Path> {

private final int indentionAmount = 3;

private int indentionLevel;

public ListFiles() {

indentionLevel = 0;

}

private void indent() {

for (int i = 0; i < indentionLevel; i++) {

System.out.print(' ');

}

Page 204: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 194

}

@Override

public FileVisitResult visitFile(Path file, BasicFileAttributes attributes) {

indent();

System.out.println("Visiting file:" + file.getFileName());

return FileVisitResult.CONTINUE;

}

@Override

public FileVisitResult postVisitDirectory(Path directory, IOException e) throws IOException {

indentionLevel -= indentionAmount;

indent();

System.out.println("Finished with the directory: " + directory.getFileName());

return FileVisitResult.CONTINUE;

}

@Override

public FileVisitResult preVisitDirectory(Path directory, BasicFileAttributes attributes) throws IOException {

indent();

System.out.println("About to traverse the directory: " + directory.getFileName());

indentionLevel += indentionAmount;

return FileVisitResult.CONTINUE;

}

@Override

public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {

System.out.println("A file traversal error ocurred");

return super.visitFileFailed(file, exc);

}

}

public class ListFileTest {

public static void main(String[] args) {

try {

Path path = Paths.get("D:/HDTJava");

Page 205: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 195

ListFiles listFiles = new ListFiles();

Files.walkFileTree(path, listFiles);

} catch (IOException ex) {

ex.printStackTrace();

}

}

}

11.2 Luồng

11.2.1 Khái ni m

Một luồng (stream) đại diện cho dãy dữ liệu có s p th tự một chiều liên tục và liền kề nhau. Nó là một dãy tuần tự các byte với chiều dài không xác định. Nền tảng nhất c a lập trình nhập/ xuất tập tin (I/O files) trong Java dựa trên luồng.

Hình 11.3: Một file gồm n bytes

Về mặt lý thuyết, mỗi luồng được g n với một đầu ghi là writer và đầu khác để đọc là reader. Trong Java, tất cả các luồng xuất/nhập là một chiều ngoại trừ các tập tin truy xuất ngẫu nhiên (RandomAccessFile). Thông thư ng, chương trình cần phải m hai luồng: Một luồng đầu vào được gọi là luồng nhập: để đọc dữ liệu từ nguồn vào chương trình và một luồng đầu ra được gọi là luồng xuất: ghi dữ liệu từ chương trình vào nguồn dữ liệu như hình 11.4.

Page 206: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 196

Hình 11.4: Luồng nhập và luồng xuất

11.2.2 Các luồng xu t nh p chuẩn

Chương trình đọc các dữ liệu đầu vào từ các nguồn dữ liệu như từ bàn phím, tập tin, mạng, bộ nhớ đệm, hoặc một chương trình khác rồi sau đó ghi các kết quả đầu ra để lưu giữ dữ liệu lại (ví dụ, hiển thị giao diện điều khiển, tập tin, mạng, bộ nhớ đệm, hoặc một chương trình khác). Trong Java I/O, đầu vào và đầu ra được xử lý b i các lồng (Stream I/O in Standard I/O).

Trong Java, các luồng này được đặt trong package java.io như sơ đồ hình th bậc dưới đây. Đây là lượng kiến th c phong phú, để xem chi chi tiết, hãy tham khảo đư ng link: http://docs.oracle.com/javase/8/docs/api/java/io/package-tree.html

Page 207: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 197

Hình 11.5: Package java.io

Sau đây tóm t t ch c năng c a một số lớp liên quan trọng được sử dụng minh họa trong giáo trình để phục vụ cho vệc làm bài tập lớn (case study).

Lớp trừu tượng cho luồng nhập (abstract class InputStream) và lớp trừu tượng lồng ghi (abstract class OutputStream): định nghĩa các ch c chính để đọc/ghi dãy các byte không có cấu trúc (unstructured sequence of bytes). Tất cả các luồng byte khác trong Java được xây dựng trên nền tảng c a hai lớp cơ s này.

Lớp cụ thể FilterInputStream và lớp cụ thể FilterOutputStream: Đây là các luồng lọc cho đầu vào và luồng đầu ra. Ch c năng chính c a nó dùng để chuyển dữ liệu trên đư ng đi hoặc cung cấp các ch c năng bổ sung.

Lớp cụ thể BufferedInputStream và BufferedOutputStream: Là các luồng filter chuyên biệt để đọc ghi các dữ liệu I/O trong thực tế như các bộ nhớ ngoài nh m giúp tăng hiệu quả đọc ghi dữ liệu.

Ví d 11.3: Sử dụng FileInputStream và BufferedInputStream để minh họa việc ghi dữ liệu vào tập tin văn bản.

/*

* File name: BufferedInputStreamDemo.java

* Reference: http://www.tutorialspoint.com/java

*

*/

package ctu.vdlinh.chapter11;

import java.io.BufferedInputStream;

import java.io.InputStream;

import java.io.FileInputStream;

import java.io.IOException;

Page 208: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 198

public class BufferedInputStreamDemo {

public static void main(String[] args) throws IOException {

InputStream is = null;

BufferedInputStream bis = null;

try {

is = new FileInputStream("D:/VDLinh/HDTJava/Test.txt");

// input stream is converted to buffered input stream

bis = new BufferedInputStream(is);

// read number of bytes available

int numByte = bis.available();

byte[] buf = new byte[numByte]; // byte array declared

// read byte into buf, starts at offset 2, 3 bytes to read

bis.read(buf);// , 2, 3); // offset = 2, length = 3

for (byte b : buf) { // for each byte in buf

System.out.print((char) b + ": " + b + " | ");

}

} catch (Exception e) {

e.printStackTrace();

} finally {

// releases any system resources associated with the stream

if (inStream != null)

inStream.close();

if (bis != null)

bis.close();

}

}

}

Với tập tin văn bản Test.txt có nội dung là ABCDE, ta chạy có kết quả như sau: A: 65 | B: 66 | C: 67 | D: 68 | E: 69 |

Lớp cụ thể DataInputStream và DataOutputStream: Được chuyên biệt từ luồng lọc (filter streams) để có thể đọc và ghi các kiểu dữ liệu nhiều byte (multibyte) như short, long, VARCHAR(100 BYTE) trong Database.

Ví d 11.4: Sử dụng DataInputStream để viết chương trình để đọc rồi hiển thị nội dung c a tập tin văn bản.

package ctu.vdlinh.chapter11;

Page 209: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 199

/**

* Filename: DataInputStreamEOF.java

* Ref: http://www.java2s.com/

*

*/

import java.io.DataInputStream;

import java.io.EOFException;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.IOException;

public class DataInputStreamEOF {

public static void main(String args[]) {

DataInputStream is = null; byte ch;

try {

is = new DataInputStream(new FileInputStream("D:/VDLinh/HDTJava/Flower.java"));

while (true) { // exception deals catches EOF

ch = is.readByte();

System.out.print((char) ch);

System.out.flush();

}

} catch (EOFException eof) {

System.out.println(" >> Normal program termination.");

} catch (FileNotFoundException noFile) {

System.err.println("File not found! " + noFile);

} catch (IOException io) {

System.err.println("I/O error occurred: " + io);

} catch (Throwable anything) {

System.err.println("Abnormal exception caught !: " + anything);

} finally {

if (is != null) {

try {

is.close();

} catch (IOException ignored) {

Page 210: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 200

}

}

}

}

}

Kết quả demo chương trình:

Lớp FileInputStream, FileOutputStream: Để đọc và ghi những luồng bytes dữ

liệu như tập tin hình ảnh.

Ví d 11.5: Viết chương trình copy file và cho biết th i gian copy thực hiện xong b ng BufferedInputStream.

/**

* File: FileCopyBufferedStream.java

* Source: http://www.ntu.edu.sg/

*/

import java.io.BufferedInputStream;

import java.io.BufferedOutputStream;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

public class FileCopyBufferedStream {

public static void main(String[] args) {

String inFileStr = "D:/VDLinh/HDTJava/LearningJava.pdf";

String outFileStr = "D:/VDLinh/HDTJava/LearningJava-out.pdf";

long startTime, elapsedTime;

File fileIn = new File(inFileStr);

Page 211: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 201

System.out.println("File size is " + fileIn.length() + " bytes");

try {

BufferedInputStream in = new BufferedInputStream( new FileInputStream(inFileStr));

BufferedOutputStream out = new BufferedOutputStream( new FileOutputStream(outFileStr));

startTime = System.nanoTime();

int byteRead;

while ((byteRead = in.read()) != -1) {

out.write(byteRead);

}

elapsedTime = System.nanoTime() - startTime;

System.out.println("Elapsed Time is " + (elapsedTime / 1000000.0) + " msec");

in.close();

out.close();

} catch (IOException ex) {

ex.printStackTrace();

}

}

}

Kết quả demo:

File size is 25743822 bytes

Elapsed Time is 2889.795801 msec.

Lớp ObjectInputStream, ObjectOutputStream: là các luồng filter chuyên biệt để ghi toàn bộ các trạng thái c a đối tượng theo dạng tuần tự (serialize) và tái tạo lại chúng (deserialize) để tr thành đối tượng.

Ví d 11.6: Tạo đối tượng sinh viên và lưu vào tập tin, sau đó đọc đối tượng từ tập tin mới lưu rồi tái tạo các trạng thái đối tượng để hiển thị lên màn hình.

/**

* Filename: IOSTesting.java

*/

package ctu.vdlinh.chapter11;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

Page 212: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 202

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.ObjectInputStream;

import java.io.ObjectOutputStream;

import java.io.Serializable;

class SinhVien implements Serializable {

private static final long serialVersionUID = 3248550334338339781L;

private String mssv;

private String hoTen;

SinhVien(String mssv, String hoTen) {

super();

this.mssv = mssv;

this.hoTen = hoTen;

}

public String getMssv() {

return mssv;

}

public void setMssv(String mssv) {

this.mssv = mssv;

}

public String getHoTen() {

return hoTen;

}

public void setHoTen(String hoTen) {

this.hoTen = hoTen;

}

}

public class IOSTesting {

public static void main(String[] args) throws FileNotFoundException,

IOException, ClassNotFoundException {

SinhVien sv = new SinhVien "B 00 ","Vũ Thị Bích Liên");

File file = new File("D:/VDLinh/HDTJava/objectFileSV.dat");

ObjectOutputStream ous = new ObjectOutputStream( new FileOutputStream(file));

Page 213: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 203

ous.writeObject(sv);

ous.close();

ObjectInputStream ois = new ObjectInputStream( new FileInputStream(file));

sv = (SinhVien) ois.readObject();

ois.close();

System.out.println "Đọc đối tượng sinh viên và tái tạo (deserialize) các trạng thái: \n\tMSSV: "+ sv.getMssv()+ "\n\tHọ tên:" + sv.getHoTen());

}

}

Kết quả chạy demo chương trình:

Lớp trừu tượng Reader và Writer: Hai super class này đều làm việc trên kiểu dữ

liệu ký tự (character data). Đối với lớp Reader, mỗi ký tự khi được đọc b ng phương th c read() sẽ trả về là một số nguyên không dấu 16-bit (unsigned 16-bit integer) từ 0 đến 65535, và -1 nếu đọc hết luồng (end-of-stream). Ngoài ra còn có hai biến thể c a phương th c read dùng để đọc một khối các ký tự vào mảng ký tự.

Lớp InputStreamReader và lớp OutputStreamWriter được dùng như là cầu nối giữa luồng byte với luồng character. Với InputStreamReader, nó đọc các bytes và giải mã (decode) chúng thành các ký tự b ng các sử dụng một bảng mã cụ thể (charset). Ngược lại, lớp sau sẽ mã hóa (encode) các ký tự thành các bytes dựa vào một charset cụ thể trước khi ghi vào. Hai lớp con c a chúng tương ng là lớp FileReader, FileWriter được dùng để đọc hoặc ghi file ký tự. Tuy nhiên, để đọc và ghi với bảng mã 16 bits như tiếng Việt chẳng hạn, ta nên sử dụng BufferedReader/ BufferedWriter.

Ví d 11.7: Ghi và đọc file tiếng Việt (UTF-16)

package ctu.vdlinh.chapter11;

import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.FileReader;

import java.io.IOException;

import java.io.InputStreamReader;

Page 214: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 204

import java.io.OutputStreamWriter;

import java.nio.charset.Charset;

/**

* Filename: OSWriterIOReaderTest.java

* @author Vu Duy Linh

*

*/

public class OSWriterIOReaderTest {

public static void main(String[] args) {

try {

FileOutputStream fos = new FileOutputStream("D:/VDLinh/HDTJava/MyFile.txt");

OutputStreamWriter osw = new OutputStreamWriter( fos, "UTF-16");

BufferedWriter bw = new BufferedWriter(osw);

bw.write("Chào tạm biệt Năm 0 !" ;

bw.newLine();

bw.write("Happy New Year, 2016!...");

bw.close();

} catch (IOException e) {

e.printStackTrace();

}

// try (FileReader fr = new // FileReader("D:/VDLinh/HDTJava/MyFile.txt")) {

// int character;

// while ((character = fr.read()) != -1) {

// System.out.print((char) character);

// }

// } catch (IOException ioe) {

// System.out.println(ioe.getMessage());

// }

try {

BufferedReader br = new BufferedReader(new InputStreamReader(

new FileInputStream("D:/VDLinh/HDTJava/MyFile.txt"), Charset.forName("UTF-16")));

Page 215: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 205

String line;

while ((line = br.readLine()) != null) {

System.out.println(line);

}

br.close();

} catch (IOException ioe) {

ioe.printStackTrace();

}

}

}

Kết quả chạy chương trình: Chào tạm biệt năm 0 ! Happy New Year, 2016!...

Bài t p ch ng 11

Bài 11.1: Định nghĩa một lớp ABC tùy ý có ch a ít nhất 03 biến trư ng có kiểu chuỗi ký tự, số thực và kiểu ngày tháng năm (Chẳng hạn lớp MamNon, các bé học Mầm non, có các trư ng: Họ tên kiểu chuỗi, ngày sinh kiểu ngày tháng năm, cân nặng và/hoặc chiều cao kiểu số thực). Hãy viết chương trình:

a. Nhập danh sách thông tin đầy đ cho n đối tượng khác nhau thộc vào lớp ABC này vào tập tin (text file/ object file/…) được lưu vào [drive:][path]<filename> tùy ý.

b. Đọc nội dung tập tin vừa tạo/cập nhật trên và hiển thị lên màn hình

c. Lấy ví dụ là lớp MamNon, hãy tìm và hiển thị thông tin đầy đ c a các bé có cân nặng từ w1 đến w2 và/hoặc chiều cao từ h1 đến h2 (với w1, w2, h1, h2 là các giá trị được nhập từ ngư i dùng)

d. Tương tự câu c, hãy liệt kê các bé có ngày sinh từ ngày d1 đến d2

Bài 11.2: Viết lại chương trình cho bài tập 4.1 b ng cách đọc dữ liệu nhập từ tập tin, tính và cập nhật kết quả vào tập tin.

Bài 11.3: Viết lại chương trình cho bài tập 4.3 b ng cách đọc dữ liệu nhập từ (các) tập tin, tính và cập nhật kết quả vào (các) tập tin đó.

Bài 11.4: Viết lại chương trình cho bài tập 5.3 b ng cách đọc dữ liệu nhập từ (các) tập tin, tính và cập nhật kết quả vào (các) tập tin đó.

Bài 11.5: Viết lại chương trình cho bài tập 5.5 b ng cách đọc dữ liệu nhập từ (các) tập tin, tính và lưu kết quả vào (các) tập tin tùy ý khác .

Bài 11.6: Viết lại chương trình cho bài tập 7.2 b ng cách đọc dữ liệu nhập từ (các) tập tin, tính và cập nhật kết quả vào (các) tập tin đó.

Page 216: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 206

Bài 11.7: Viết lại chương trình cho bài tập 7.4 b ng cách đọc dữ liệu nhập từ (các) tập tin, tính và cập nhật kết quả vào (các) tập tin tùy ý đó.

Bài 11.8: Viết lại chương trình cho bài tập 8.1 b ng cách đọc dữ liệu nhập từ (các) tập tin, tính và cập nhật kết quả vào (các) tập tin đó.

Page 217: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 207

Ch ng 12. Giao di n ng i dùng và k t n i c sở dữ li u

Chương này được đề cập ng n gọn nh m để giúp cho sinh viên tiếp cận việc lập trình

giao diện ngư i dùng (Form UI) trên Java thông qua 2 phần mềm phát triển Java phổ biến là Netbeans IDE và Eclipse IDE, đồng th i cũng đề cập sơ qua về sự kết nối dữ liệu (Java Database Connectivity) tới các hệ cơ s dữ liệu như mySQL, SQL Server,…

12.1 L p trình giao di n Java v i SWT

SWT (Standard Widget Toolkit) là một lớp thư viện mới để tạo các giao diện ngư i dùng đồ họa (GUI) trong Java. SWT được tạo ra như thành phần kết tập chặt với dự án Eclipse, SWT cho phép các nhà phát triển để xây dựng hiệu quả, ng dụng khả chuyển (portable application) mà có thể truy cập trực tiếp vào các ch c năng giao diện ngư i dùng (user-interface facilities of the operating systems) c a hệ điều hành mà nó được cài đặt. Theo các tác giả Steve Northover và Mike Wilson thì công nghệ mang tính cách mạng này làm cho nó có thể tạo ra các ng dụng dựa trên nền tảng Java mà chúng ta sẽ không thấy có sự phân biệt với các ng dụng khác c a chính hệ điều hành.

Ví d 12.1: Dưới đây minh họa việc sử dụng SWT trong Eclipse để viết chương trinh GUI cho 4 phép tính cơ bản c a 2 số a và b.

package ctu.vlinh.chapter12;

/**

* @author Vũ Duy Linh

* Simple SWT application

*/

import org.eclipse.swt.SWT;

import org.eclipse.swt.widgets.Display;

import org.eclipse.swt.widgets.MessageBox;

import org.eclipse.swt.widgets.Monitor;

import org.eclipse.swt.widgets.Shell;

import org.eclipse.swt.widgets.Text;

import org.eclipse.swt.widgets.Label;

import org.eclipse.swt.widgets.Combo;

import org.eclipse.swt.custom.StyledText;

import org.eclipse.swt.events.SelectionAdapter;

import org.eclipse.swt.events.SelectionEvent;

import org.eclipse.swt.graphics.Rectangle;

import org.eclipse.wb.swt.SWTResourceManager;

Page 218: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 208

public class Calc {

protected Shell shlSimpleCalculator;

private Text txtNhapa;

private Text txtNhapb;

private StyledText styledTextKQ;

public static void main(String[] args) {

try {

Calc window = new Calc();

window.open();

} catch (Exception e) {

e.printStackTrace();

}

}

/**

* Open the window. //Visitor pattern. Observer pattern (also called

* Listener pattern)

*/

public void open() {

Display display = Display.getDefault();

createContents();

Monitor primaryMonitor = display.getPrimaryMonitor();

Rectangle bounds = primaryMonitor.getBounds();

Rectangle rect = shlSimpleCalculator.getBounds();

int x = bounds.x + (bounds.width - rect.width) / 2;

int y = bounds.y + (bounds.height - rect.height) / 2;

shlSimpleCalculator.setLocation(x,y);

shlSimpleCalculator.setText("Simple calculator – SWT Application");

shlSimpleCalculator.open();

shlSimpleCalculator.layout();

while (!shlSimpleCalculator.isDisposed()) {

if (!display.readAndDispatch()) {

display.sleep();

}

Page 219: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 209

}

}

/**

* Create contents of the window.

*/

protected void createContents() {

shlSimpleCalculator = new Shell(); // <=> JFrame cua Swing

shlSimpleCalculator.setImage(SWTResourceManager.getImage ("D:\\GameAndoid\\MaytinhWF\\src\\icon\\calc.jpg"));

shlSimpleCalculator.setSize(382, 234);

txtNhapa = new Text(shlSimpleCalculator, SWT.BORDER);

txtNhapa.setBounds(82, 17, 76, 21);

Label lblNhapa = new Label(shlSimpleCalculator, SWT.NONE);

lblNhapa.setBounds(22, 20, 54, 21);

lblNhapa.setText("Nhập a=");

Label lblNhapb = new Label(shlSimpleCalculator, SWT.NONE);

lblNhapb.setText("Nhập b=");

lblNhapb.setBounds(203, 20, 54, 21);

txtNhapb = new Text(shlSimpleCalculator, SWT.BORDER);

txtNhapb.setBounds(262, 17, 85, 21);

final Combo cboPhepTinh = new Combo(shlSimpleCalculator, SWT.NONE | SWT.READ_ONLY);

cboPhepTinh.setItems(new String[] { "+", "-", "*", "/" });

cboPhepTinh.addSelectionListener(new SelectionAdapter() {

@Override

public void widgetSelected(SelectionEvent e) {

double a, b;

try {

a = Double.parseDouble(txtNhapa.getText());

b = Double.parseDouble(txtNhapb.getText());

} catch (Exception e2) {

MessageBox mb = new MessageBox(shlSimpleCalculator, SWT.ICON_ERROR | SWT.OK);

mb.setText("Thong bao");

mb.setMessage("Giá trị nhập không hợp lệ.");

mb.open();

Page 220: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 210

return;

}

String strKQ;

int index = cboPhepTinh.getSelectionIndex();

String strToanTu = cboPhepTinh.getItem(index);

char c = strToanTu.charAt(0);

switch (c) {

case '+':

strKQ = String.valueOf(a + b);

styledTextKQ.setText(strKQ);

break;

case '-':

strKQ = String.valueOf(a - b);

styledTextKQ.setText(strKQ);

break;

case '*':

strKQ = String.valueOf(a * b);

styledTextKQ.setText(strKQ);

break;

case '/':

if (b != 0) strKQ = String.valueOf(a / b);

else strKQ = "Lỗi: chia không.";

styledTextKQ.setText(strKQ);

break;

default:

break;

}

}

});

cboPhepTinh.setBounds(22, 76, 136, 23);

Label lblToanTu = new Label(shlSimpleCalculator, SWT.NONE);

lblToanTu.setBounds(21, 57, 92, 15);

lblToanTu.setText("Chọn phép tính:");

Label lblKetQua = new Label(shlSimpleCalculator, SWT.NONE);

lblKetQua.setBounds(203, 57, 55, 15);

Page 221: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 211

lblKetQua.setText("Kết quả:");

styledTextKQ = new StyledText(shlSimpleCalculator, SWT.BORDER);

styledTextKQ.setBounds(201, 72, 146, 63);

}

}

Kết quả demo Form UI:

Hình 12.1: Standard Widget Toolkit application

12.2 L p trình giao di n Java v i Swing

Swing được xây dựng dựa trên nên c a AWT (Abstract Windows Toolket) và được phát triển hoàn toàn b ng ngôn ngwx Java và có sử dụng các thành phần nhẹ (components lightweight) c a AWT. Khác với AWT, kiến trúc c a các thành phần Swing dễ tùy biến về giao diện và ch c năng hơn (appearance và behavior). Trong trư ng hợp nếu cần, ta có thể trộn lẫn các thành phần c a Swing chung với các thành phần c a AWT.

Swing Java là một phần c a JFC, nó bao gồm các phần: Look and feel, Accessibility, Java 2D, Drag and Drop,…

Ví d 12.2: Sử dụng JTable c a Java Swing để viết chương trình đơn giản để hiển thị ra danh sách các nhân viên (Employees).

package ctu.vdlinh.chapter12;

/**

* Filename: Employee.java

* @author http://www.codejava.net/

* Define POJO model: This class is simply a value bean which

* represents the entity

Page 222: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 212

*/

public class Employee {

private int id;

private String name;

private double hourlyRate;

private boolean partTime;

public Employee(int id, String name, double hourlyRate, boolean partTime) {

super();

this.id = id;

this.name = name;

this.hourlyRate = hourlyRate;

this.partTime = partTime;

}

public int getId() {

return id;

}

public void setId(int id) {

this.id = id;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public double getHourlyRate() {

return hourlyRate;

}

public void setHourlyRate(double hourlyRate) {

this.hourlyRate = hourlyRate;

}

public boolean isPartTime() {

return partTime;

Page 223: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 213

}

public void setPartTime(boolean partTime) {

this.partTime = partTime;

}

}

/**

* @author http://www.codejava.net/

* Filename: EmployeeTableModel.java

*/

package ctu.vdlinh.chapter12;

import java.util.List;

import javax.swing.table.AbstractTableModel;

import ctu.vdlinh.model.Employee;

public class EmployeeTableModel extends AbstractTableModel {

private static final long serialVersionUID = -1098291250269473649L;

private final List<Employee> employeeList;

private final String[] columnNames = new String[] { "Id", "Name", "Hourly Rate", "Part Time" };

@SuppressWarnings("rawtypes")

private final Class[] columnClass = new Class[] { Integer.class, String.class, Double.class, Boolean.class };

public EmployeeTableModel(List<Employee> employeeList) {

this.employeeList = employeeList;

}

@Override

public String getColumnName(int column) {

return columnNames[column];

}

@Override

public Class<?> getColumnClass(int columnIndex) {

return columnClass[columnIndex];

}

Page 224: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 214

@Override

public int getColumnCount() {

return columnNames.length;

}

@Override

public int getRowCount() {

return employeeList.size();

}

@Override

public Object getValueAt(int rowIndex, int columnIndex) {

Employee row = employeeList.get(rowIndex);

if (0 == columnIndex) {

return row.getId();

} else if (1 == columnIndex) {

return row.getName();

} else if (2 == columnIndex) {

return row.getHourlyRate();

} else if (3 == columnIndex) {

return row.isPartTime();

}

return null;

}

@Override

public boolean isCellEditable(int rowIndex, int columnIndex) {

return true;

}

@Override

public void setValueAt(Object aValue, int rowIndex, int columnIndex) {

Employee row = employeeList.get(rowIndex);

if (0 == columnIndex) {

row.setId((Integer) aValue);

} else if (1 == columnIndex) {

row.setName((String) aValue);

} else if (2 == columnIndex) {

Page 225: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 215

row.setHourlyRate((Double) aValue);

} else if (3 == columnIndex) {

row.setPartTime((Boolean) aValue);

}

}

}

/**

* @author codejava.net

* EditableTableExample.java

*/

package ctu.vdlinh.chapter12;

import java.util.ArrayList;

import java.util.List;

import javax.swing.JFrame;

import javax.swing.JScrollPane;

import javax.swing.JTable;

import javax.swing.SwingUtilities;

import ctu.vdlinh.model.Employee;

/**

* @author codejava.net

* filename: EditableTableExample.java

*

*/

public class EditableTableExample extends JFrame {

private static final long serialVersionUID = 1L;

public EditableTableExample() {

Employee row1 = new Employee(1, "John", 40.0, false);

Employee row2 = new Employee(2, "Rambo", 70.0, false);

Employee row3 = new Employee(3, "Zorro", 60.0, true);

// build the list

List<Employee> employeeList = new ArrayList<Employee>();

employeeList.add(row1);

Page 226: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 216

employeeList.add(row2);

employeeList.add(row3);

// create the model

EmployeeTableModel model = new EmployeeTableModel(employeeList);

// create the table

JTable table = new JTable(model);

// add the table to the frame

this.add(new JScrollPane(table));

this.setTitle("Editable Table Example");

this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

this.pack();

this.setVisible(true);

}

public static void main(String[] args) {

SwingUtilities.invokeLater(new Runnable() {

@Override

public void run() {

new EditableTableExample();

}

});

}

}

Kết quả chương trình:

Hình 12.2: ng dụng bằng Swing

12.3 K t n i c sở dữ li u

Việc sử dụng cơ s dữ liệu c a một hệ quản trị cơ s dữ liệu nào đó trong lập trình ng dụng Java là rất phổ biến, đặc biệt là trong các ng dụng Web app.

Page 227: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 217

Java cung cấp 4 type để kết nối đó là: JDBC-ODBC bridge, Native API connection driver, Network connection driver, và Database Protocol driver.

Trong thực tế, Java có thể kết nối với tất cả các hệ quản trị CSDL như: mySQL, PostgreSQL, SQL Server, Oracle, DB2,…

Ví d 12.3: Dưới đây minh họa một chương trình Form UI đơn giản có kết nối với cơ s dữ liệu quản lý giáo vụ (qlgv) b ng hệ quản trị CSDL mySQL để thực hiện các thao tác cơ bản c a bảng sinh viên: Create, read, update và delete (CRUD).

Hình 12.3: Cấu trúc dự án và mySQL

//File name: SinhVien.java

package ctu.vdlinh.bll_dal;

public class SinhVien {

private String maSV;

private String hoTenSV;

private String msLop;

public SinhVien() {

super();

}

public String getMsLop() {

return msLop;

}

Page 228: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 218

public void setMsLop(String msLop) {

this.msLop = msLop;

}

public SinhVien(String maSV, String hoTenSV) {

this.maSV = maSV;

this.hoTenSV = hoTenSV;

}

public String getMaSV() {

return maSV;

}

public void setMaSV(String maSV) {

this.maSV = maSV;

}

public String getHoTenSV() {

return hoTenSV;

}

public void setHoTenSV(String hoTenSV) {

this.hoTenSV = hoTenSV;

}

}

//File: SinhVienBean.java

package ctu.vdlinh.bll_dal;

import java.sql.SQLException;

import javax.sql.rowset.JdbcRowSet;

import com.sun.rowset.JdbcRowSetImpl;

public class SinhVienBean {

static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";

static final String DB_URL ="jdbc:mysql://localhost:3306/qlgv?

useUnicode=true&characterEncoding=UTF-8";

static final String DB_USER = "root";

static final String DB_PASS = "vdlinh";

private JdbcRowSet rowSet = null;

public SinhVienBean() {

try {

Page 229: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 219

Class.forName(JDBC_DRIVER);

rowSet = new JdbcRowSetImpl();

rowSet.setUrl(DB_URL);

rowSet.setUsername(DB_USER);

rowSet.setPassword(DB_PASS);

rowSet.setCommand("SELECT * FROM Sinhvien");

rowSet.execute();

}

catch (SQLException | ClassNotFoundException ex) {

ex.printStackTrace();

}

}

public SinhVien create(SinhVien sv) {

try {

rowSet.moveToInsertRow();

rowSet.updateString("mssv",sv.getMaSV());

rowSet.updateString("hoten", sv.getHoTenSV());

rowSet.updateString("mslop", sv.getMsLop());

rowSet.insertRow();

rowSet.moveToCurrentRow();

} catch (SQLException ex) {

try {

rowSet.rollback();

sv = null;

} catch (SQLException e) {

}

ex.printStackTrace();

}

return sv;

}

public SinhVien update(SinhVien sv) {

try {

rowSet.updateString("mssv",sv.getMaSV());

rowSet.updateString("hoten", sv.getHoTenSV());

rowSet.updateString("mslop", sv.getMsLop());

Page 230: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 220

rowSet.updateRow();

rowSet.moveToCurrentRow();

} catch (SQLException ex) {

try {

rowSet.rollback();

} catch (SQLException e) {

}

ex.printStackTrace();

}

return sv;

}

public void delete() {

try {

rowSet.moveToCurrentRow();

rowSet.deleteRow();

} catch (SQLException ex) {

try {

rowSet.rollback();

} catch (SQLException e) { }

ex.printStackTrace();

}

}

public SinhVien moveFirst() {

SinhVien sv = new SinhVien();

try {

rowSet.first();

sv.setMaSV(rowSet.getString("mssv"));

sv.setHoTenSV(rowSet.getString("hoten"));

sv.setMsLop(rowSet.getString("mslop"));

} catch (SQLException ex) {

ex.printStackTrace();

}

return sv;

}

public SinhVien moveLast() {

Page 231: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 221

SinhVien sv = new SinhVien();

try {

rowSet.last();

sv.setMaSV(rowSet.getString("mssv"));

sv.setHoTenSV(rowSet.getString("hoten"));

sv.setMsLop(rowSet.getString("mslop"));

} catch (SQLException ex) {

ex.printStackTrace();

}

return sv;

}

public SinhVien moveNext() {

SinhVien sv = new SinhVien();

try {

if (rowSet.next() == false) rowSet.previous();

sv.setMaSV(rowSet.getString("mssv"));

sv.setHoTenSV(rowSet.getString("hoten"));

sv.setMsLop(rowSet.getString("mslop"));

} catch (SQLException ex) {

ex.printStackTrace();

}

return sv;

}

public SinhVien movePrevious() {

SinhVien sv = new SinhVien();

try {

if (rowSet.previous() == false) rowSet.next();

sv.setMaSV(rowSet.getString("mssv"));

sv.setHoTenSV(rowSet.getString("hoten"));

sv.setMsLop(rowSet.getString("mslop"));

} catch (SQLException ex) {

ex.printStackTrace();

}

return sv;

}

Page 232: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 222

public SinhVien getCurrent() {

SinhVien sv = new SinhVien();

try {

rowSet.moveToCurrentRow();

sv.setMaSV(rowSet.getString("mssv"));

sv.setHoTenSV(rowSet.getString("hoten"));

sv.setMsLop(rowSet.getString("mslop"));

} catch (SQLException ex) {

ex.printStackTrace();

}

return sv;

}

public void refresh() throws SQLException{

rowSet.refreshRow();

}

}

//QLSV_UI.java

package ctu.vdlinh.gui;

import javax.swing.ImageIcon;

public class QLSV_UI extends JPanel {

private static final long serialVersionUID = 1L;

private JTextField tfMSSV = new JTextField(10);

private final JLabel lblHoten = new JLabel("Họ tên: ");

private final JTextField tfHoTen = new JTextField(30);

private final JLabel lblLp = new JLabel("MS Lớp:");

private final JTextField tfMSLop = new JTextField(30);

private JButton btnCreate = new JButton("Create");

private final JButton btnUpdate = new JButton("Update");

private final JButton btnDelete = new JButton("Delete");

private final JButton btnPrevious = new JButton("Previous");

private final JButton btnNext = new JButton("Next");

private final JButton btnFirst = new JButton("First");

private final JButton btnLast = new JButton("Last");

Page 233: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 223

private SinhVienBean svBean = new SinhVienBean();

public QLSV_UI() {

setBackground(new Color(192, 192, 192));

tfMSLop .setColumns(10);

tfHoTen.setColumns(10);

setBorder(new TitledBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null), "Chi tiết sinh viên:"));

setLayout(new BorderLayout(5, 5));

add(initFields(), BorderLayout.NORTH);

add(initButtons(), BorderLayout.CENTER);

setFieldData(svBean.moveFirst());

}

private void createIcons(){

btnCreate.setMnemonic('C');

btnCreate.setIcon(new ImageIcon(QLSV.pathIcons+"\\Create16.png"));

btnUpdate.setMnemonic('U');

btnUpdate.setIcon(new ImageIcon(QLSV.pathIcons+"\\Update16.png"));

btnDelete.setMnemonic('D');

btnDelete.setIcon(new ImageIcon(QLSV.pathIcons+"\\Delete16.png"));

btnFirst.setMnemonic('F');

btnFirst.setIcon(new ImageIcon(QLSV.pathIcons+"\\First16.png"));

btnPrevious.setMnemonic('P');

btnPrevious.setIcon(new ImageIcon(QLSV.pathIcons+"\\Previous16.png"));

btnNext.setMnemonic('N');

btnNext.setIcon(new ImageIcon(QLSV.pathIcons+"\\Next16.png"));

btnLast.setMnemonic('L');

btnLast.setIcon(new ImageIcon(QLSV.pathIcons+"\\Last16.png"));

}

private JPanel initFields() {

JPanel jpnFields = new JPanel();

Page 234: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 224

jpnFields.setBorder(new LineBorder(Color.CYAN));

jpnFields.setLayout(new MigLayout("", "[][596.00]", "[][][]"));

JLabel lblMaSoSv = new JLabel("Mã số SV: ");

jpnFields.add(lblMaSoSv, "cell 0 0,alignx left,aligny center");

jpnFields.add(tfMSSV, "cell 1 0,alignx left,aligny top");

jpnFields.add(lblHoten, "cell 0 1,alignx left,aligny center");

jpnFields.add(tfHoTen, "cell 1 1,growx,aligny top");

jpnFields.add(lblLp, "cell 0 2,alignx left,aligny center");

jpnFields.add(tfMSLop, "cell 1 2,growx,aligny top");

return jpnFields;

}

private JPanel initButtons() {

createIcons();

JPanel jpnButtons = new JPanel();

jpnButtons.setLayout(new FlowLayout(FlowLayout.CENTER, 3, 15));

jpnButtons.add(btnCreate);

btnCreate.addActionListener(new ButtonHandler());

jpnButtons.add(btnUpdate);

btnUpdate.addActionListener(new ButtonHandler());

jpnButtons.add(btnDelete);

btnDelete.addActionListener(new ButtonHandler());

jpnButtons.add(btnFirst);

btnFirst.addActionListener(new ButtonHandler());

jpnButtons.add(btnPrevious);

btnPrevious.addActionListener(new ButtonHandler());

jpnButtons.add(btnNext);

btnNext.addActionListener(new ButtonHandler());

jpnButtons.add(btnLast);

btnLast.addActionListener(new ButtonHandler());

return jpnButtons;

}

private void setFieldData(SinhVien sv) {

tfMSSV.setText(sv.getMaSV());

tfHoTen.setText(sv.getHoTenSV());

tfMSLop.setText(sv.getMsLop());

Page 235: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 225

}

private SinhVien getFieldData() {

SinhVien sv = new SinhVien();

sv.setMaSV(tfMSSV.getText());

sv.setHoTenSV(tfHoTen.getText());

sv.setMsLop(tfMSLop .getText());

return sv;

}

private boolean isEmptyFieldData() {

return (tfMSSV.getText().trim().isEmpty()

&& tfHoTen.getText().trim().isEmpty()

&& tfMSLop.getText().trim().isEmpty());

}

private class ButtonHandler implements ActionListener {

@Override

public void actionPerformed(ActionEvent e) {

SinhVien sv = getFieldData();

switch (e.getActionCommand()) {

case "Save":

if (isEmptyFieldData()) {

JOptionPane.showMessageDialog(null,

"Cannot create an empty record");

return;

}

if (svBean.create(sv) != null)

JOptionPane.showMessageDialog(null,

"New Student created successfully.");

btnCreate.setText("Create");

break;

case "Create":

sv.setMaSV("");

sv.setHoTenSV("");

sv.setMsLop("");

setFieldData(sv);

btnCreate.setText("Save");

Page 236: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 226

break;

case "Update":

if (isEmptyFieldData()) {

JOptionPane.showMessageDialog(null,

"Lỗi: Không thể cập nhật mẫu tin rỗng.");

return;

}

if (svBean.update(sv) != null)

JOptionPane.showMessageDialog(

null,"Sinh viên có MSSV: " + sv.getMaSV() + " đã cập nhật thành công.");

break;

case "Delete":

if (isEmptyFieldData()) {

JOptionPane.showMessageDialog(null,

"Lỗi: Không thể xóa mẫu tin rỗng.");

return;

}

sv = svBean.getCurrent();

svBean.delete();

JOptionPane.showMessageDialog(

null,"Sinh viên có MSSV: " + sv.getMaSV() + " đã bị xóa.");

setFieldData(svBean.moveNext());

break;

case "First":

setFieldData(svBean.moveFirst()); break;

case "Previous":

setFieldData(svBean.movePrevious()); break;

case "Next":

setFieldData(svBean.moveNext()); break;

case "Last":

setFieldData(svBean.moveLast()); break;

default:

JOptionPane.showMessageDialog(null,

Page 237: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 227

"Không có lệnh này.");

}

}

}

}

//File: QLSV.java

package ctu.vdlinh.gui;

import java.awt.EventQueue;

public class QLSV {

private JFrame frmMain;

public static String pathIcons = System.getProperty("user.dir") + "\\icons";

public static void main(String[] args) {

EventQueue.invokeLater(new Runnable() {

public void run() {

try {

QLSV windowQLSV = new QLSV();

windowQLSV.frmMain.setTitle("Quản lý (CRUD) sinh viên sử dụng Swing và mySql");

windowQLSV.frmMain.setVisible(true);

} catch (Exception e) {

e.printStackTrace();

}

}

});

}

public QLSV() {

initialize();

}

private void initialize() {

frmMain = new JFrame();

pathIcons = System.getProperty("user.dir") + "\\icons";

frmMain.setIconImage(Toolkit.getDefaultToolkit().getImage( pathIcons+"\\LogoApp.png"));

frmMain.setBounds(100, 100, 677, 199);

Page 238: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 228

frmMain.setLocationRelativeTo(null);

frmMain.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

frmMain.getContentPane().add(new QLSV_UI());

}

}

Kết quả của chương trình ứng với các thao tác CRUD:

Hình 12.3: ng dụng sử dụng Swing và mySQL

Bài t p ch ng 12

Bài 12.1: Sử dụng SWT hoặc Swing để viết chương trình GUI cho bài toán giải phương trình bậc hai (xét cả nghiệm ảo) theo phương pháp hướng đối tượng.

Bài 12.2: Sử dụng Swing hoặc SWT trong Netbeans/Eclipse để viết chương trình GUI cho bài tập 9.1.

Bài 12.3: Sử dụng Swing hoặc SWT trong Netbeans/Eclipse để viết chương trình GUI cho bài tập 9.4.

Bài 12.4: Sử dụng Swing hoặc SWT trong Netbeans/Eclipse để viết chương trình GUI cho bài tập 9.5.

Page 239: Lap trinh HDT Java, Object-Oriented Programming in Java

Lập trình hướng đối tượng Java 229

Tài li u tham khảo

[1] Bernd Bruegge & Allen H. Dutoit (2010), Object-Oriented Software Engineering

Using UML, Patterns, and Java™,Third Edition, Prentice Hall. [2] Cay S. Horstmann, Gary Cornell (2013), Core Java™ Volume I—Fundamentals,

Ninth Edition, Prentice Hall. [3] C. Thomas Wu, (1999), An introduction to object-oriented programming with

Java, McGraw-Hill. [4] Danny Poo, Derek Kiong, Swarnalatha Ashok (2008), Object-Oriented

Programming and Java, Second edition, Springer. [5] Đoàn Văn Ban, (2005), Lập trình hướng đối tượng với Java, NXB. Khoa học và

Kỹ thuật

[6] Joshua Bloch (2008), Effective Java: Programming Language Guide, Second Edition, Addison Wesley.

[7] K. Barclay, J. Savage (2004), Object-Oriented Design with UML and Java, Elsevier.

[8] Paul Deitel, Harvey Deitel (2012), JavaTM How to Program, 9th Edition.

[9] R. Morelli, R. Walde (2012), Java, Java, Java Object-Oriented Problem Solving, 3rd Edition.

[10] Robert Cecil Martin (2002), UML for Java Programmers, Prentice Hall.

[11] Stephen Gilbert, Bill McCarty (1997), Object-Oriented programming in java, Waite Group Press.

[12] Trần Tiến Dũng (1999), Giáo trình lý thuyết và bài tập Java, NXB. Giáo Dục.

Compiled by Vu Duy-Linh Email: [email protected]

(Tài li u đ c sử d ng mi n phí cho c ng đồng, xin không đ c l y để bán hoặc thu phí khi download v i b t kỳ lý do gì.)