Download as pdf or txt
Download as pdf or txt
You are on page 1of 208

Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

BÀI 1: MỘT SỐ KHÁI NIỆM CƠ BẢN

Mục tiêu:
Trong bài này, Anh/Chị cần đạt được những mục tiêu sau:
1. Đối tượng và các thành phần liên quan.
2. Các đặc trưng: đóng gói, che giấu, kế thừa, đa hình.
3. Giới thiệu các ngôn ngữ lập trình hướng đối tượng.
Nội dung:

1. Phương pháp lập trình hướng đối tượng


Sự ra đời và phát triển của máy tính điện tử kéo theo sự phát triển của các
phương pháp lập trình cho máy tính điện tử. Bắt đầu từ phương pháp sơ khai, đơn
giản nhất là lập trình tuần tự, tiếp đến là lập trình có cấu trúc và hiện nay, được sử
dụng rộng rãi trong các môi trường hiện đại là phương pháp lập trình hướng đối
tượng (Object-Oriented Programming, viết tắt là OOP).
Phương pháp lập trình có cấu trúc dựa trên cách thức giải quyết bài toán theo
hướng chức năng. Theo đó, để giải quyết một bài toán lớn chúng ta phân rã (theo
chức năng) thành nhiều bài toán nhỏ, cứ tiếp tục như vậy để đạt được những bài
toán đơn giản và có thể triển khai lập trình dễ dàng. Quá trình này gọi là phân tích
từ trên xuống “top-down”. Phương pháp này dựa trên ngôn ngữ mô tả bài toán, chủ
yếu chúng ta phải tìm ra các “động từ” để đưa ra các chức năng cần giải quyết trong
quá trình phân tích. Mỗi bài toán con thu được trong phương pháp này sẽ được lập
trình để thực hiện dưới dạng một chương trình con, như vậy để giải quyết bài toán
lớn chúng ta sẽ có nhiều mô-đun chương trình con trong một hệ thống chương trình.
Hiện nay, trong hầu hết các môi trường lập trình đều cung cấp phương pháp lập
trình hướng đối tượng. Các nguyên lý và việc áp dụng phương pháp này được khởi
nguồn từ những năm 1960, sau đó vào những năm 1980, các ngôn ngữ lập trình
hướng đối tượng được phát triển như Smalltalk, Eiffel, C++ và đặc biệt vào những
năm 1990, ngôn ngữ Java được phát triển rất mạnh bởi hãng Sun Microsystems, cho
đến nay được sử dụng rộng rãi.
Phương pháp lập trình hướng đối tượng dựa trên cách thức giải quyết bài toán
theo hướng các đối tượng. Theo đó, chúng ta sẽ xem xét về sự tồn tại của các đối
tượng trong bài toán, mối quan hệ tương tác giữa chúng để thực hiện mục tiêu đặt ra

Kỹ thuật lập trình hướng đối tượng - Bài 1 Trang 1


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

cho bài toán, từ đó áp dụng phương pháp phân tích và thiết kế từ dưới lên (“bottom-
up”). Trong tài liệu này không đi sâu trình bày về phương pháp phân tích và thiết
hướng đối tượng, chúng ta sẽ làm quen với phương pháp thông qua ví dụ minh họa
so sánh giữa phương pháp dựa trên chức năng và phương pháp dựa trên đối tượng
như sau.
Để minh họa, chúng ta xem xét bài toán quản lý sinh viên chẳng hạn.

Hình vẽ 1.1: Minh họa bài toán quản lý sinh viên


Rõ ràng, theo hướng chức năng chúng ta đơn giản có thể liệt kê các công việc
thực hiện gồm: cập nhật hồ sơ sinh viên; lên kế hoạch đào tạo; tổ chức thi và lên
điểm;.... Ở đây chúng ta đã phân rã bài toán cần làm thành các công việc (hay chức
năng) nhỏ, như vậy về phía lập trình cơ bản xây dựng các mô-đun chương trình con
để giải quyết từng công việc này. Đối với phương pháp giải quyết dựa trên đối
tượng, chúng ta xem xét bài toán này cần có các đối tượng sinh viên, các đối tượng
giáo viên, các đối tượng người quản lý, các đối tượng môn học,.... Trong đó, mỗi
loại có thể có nhiều đối tượng khác nhau như sinh viên có thể lên đến hàng nghìn
đối tượng. Số lượng cho mỗi loại đối tượng là khác nhau và phụ thuộc vào từng bài
toán cụ thể. Sau đó sẽ xem xét mối quan hệ tương tác giữa các đối tượng này để
thực hiện các mục tiêu của bài toán đặt ra.
Phương pháp lập trình hướng đối tượng phát sinh nhiều khái niệm mới, yêu cầu
người lập trình cần nắm vững và chúng sẽ được trình bày ở phần tiếp sau.

2. Các khái niệm, đặc trưng của lập trình hướng đối tượng
2.1. Các khái niệm cơ bản trong lập trình hướng đối tượng

Kỹ thuật lập trình hướng đối tượng - Bài 1 Trang 2


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

- Đối tượng (objects): là các thể hiện trên bộ nhớ của một gói gồm các biến và
hàm trong chương trình phần mềm. Trong thực tế khái niệm này rất rộng, nó ám chỉ
đến mọi sự vật, hiện tượng của thế giới thực. Tuy nhiên, khái niệm đối tượng trong
lập trình (hay còn gọi là đối tượng phần mềm – software objects) sẽ hạn hẹp hơn
nhiều, chủ yếu đề cập đến khía cạnh thông tin của các đối tượng. Do đó, chúng ta sẽ
có các đối tượng trong không gian thực của bài toán, tương ứng là các đối tượng
trong không gian của chương trình.
Ví dụ về các đối tượng như các sinh viên, giáo viên, môn học, lớp học, hay đối
tượng là những chiếc xe máy, xe ô-tô, thậm chí là các bánh xe, cánh quạt,...
Chúng ta có thể phân loại gồm đối tượng vô hình và hữu hình. Trong ví dụ trên
thì môn học, lớp học là các đối tượng vô hình, còn sinh viên, giáo viên,… là các đối
tượng hữu hình.
- Thuộc tính (properties): là các thành phần (dưới dạng các biến - variables)
trong đối tượng để mô tả thông tin dữ liệu hay trạng thái (states) của đối tượng
(Hình vẽ 1.2). Ví dụ các đối tượng sinh viên có thuộc tính là họ và tên, ngày-tháng-
năm sinh, quê quán,... hay các đối tượng môn học có tên môn học, số tín chỉ, điều
kiện tiên quyết,...
- Phương thức (methods): là các thành phần (dưới dạng các hàm) trong đối
tượng để mô tả hành vi (behavior) hay khả năng xử lý của đối tượng (Hình vẽ 1.2).
Các phương thức khi thực hiện sẽ xử lý trên các thuộc tính và có thể sẽ làm biến đối
trạng thái của đối tượng, tức làm thay đổi giá trị trong các thuộc tính. Ví dụ các đối
tượng xe ô-tô có phương thức khởi động máy, tăng/giảm ga, chuyển số,... hay các
đối tượng sinh viên có phương thức nhận bài kiểm tra, làm bài kiểm tra, tham dự
buổi học...

Hình vẽ 1.2: Đối tượng và các thành phần của đối tượng.
- Thông điệp (messages): Chúng ta thấy rằng, các đối tượng phần mềm sẽ quan
hệ và tương tác với nhau nhằm để thực hiện mục tiêu của bài toán đặt ra. Khi một
đối tượng A muốn một đối tượng B thực hiện một phương thức trên B, thì đối tượng
A phải gửi một thông điệp tương ứng đến đối tượng B. Thực chất ở đây là việc đối

Kỹ thuật lập trình hướng đối tượng - Bài 1 Trang 3


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

tượng A gọi thực hiện một phương thức trên đối tượng B. Hình vẽ 1.3 sau minh họa
cho thông điệp F(x) được gọi bởi đối tượng A đến đối tượng B.

Hình vẽ 1.3: Thông điệp từ đối tượng A đến đối tượng B


Một thông điệp sẽ gồm 3 thành phần như sau:
+ Đối tượng (object): xác định thông điệp sẽ chuyển đến, hay địa chỉ nơi đối
tượng được thể hiện trên bộ nhớ mà phương thức sẽ được thực hiện. Hình vẽ 1.3
minh họa thông điệp với thành phần đối tượng là B.
+ Tên phương thức (method) cần gọi: trong Hình vẽ 1.3 có tên phương thức là
“F”.
+ Các tham số truyền cho phương thức (parameters): trong Hình vẽ 1.3 có tham
số là “x” được truyền cho lời gọi phương thức “F” trên đối tượng B.
- Lớp đối tượng (classes, hay gọi tắt là lớp): Trong chương trình hướng đối
tượng, có thể xuất hiện nhiều đối tượng có cùng kiểu (hay cùng đặc trưng) như các
hình chữ nhật, các công nhân,... Do đó, một lớp đối tượng được xem như là một
bản thiết kế chi tiết để định nghĩa các thành phần (thuộc tính và phương thức) cho
tất cả các đối tượng cùng một kiểu.
Lớp là một khái niệm trừu tượng, nó đóng vai trò như bản mẫu cho việc tạo lập
hay xây dựng (tức các thể hiện - instance) các đối tượng trong chương trình. Hình
vẽ 1.4 sau minh họa cho lớp “Dog” và một đối tượng “Rayne” của “Dog”. Lớp
“Dog” có các thuộc tính gồm Color (màu), Eye Color (màu mắt), Height (chiều
cao), Length (chiều dài), Weight (cân nặng) và đối tượng “Rayne” có các giá trị
thuộc tính tương ứng màu xám, mắt xanh, cao 18 inc, dài 36 inc và nặng 30 pound.
Các phương thức của “Dog” gồm Sit (ngồi), Lay Down (nằm xuống), Shake (lắc
mình), Come (đi).

Kỹ thuật lập trình hướng đối tượng - Bài 1 Trang 4


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Hình vẽ 1.4: Lớp “Dog” và đối tượng “Rayne”


Hình vẽ 1.5 sau minh họa cho lớp “Student” và các đối tượng sinh viên tương
ứng.

Hình vẽ 1.5: Lớp “Student” và các đối tượng


2.2. Các đặc trưng của lập trình hướng đối tượng
Cho đến nay, các nhà phát triển ứng dụng cũng như các tác giả nghiên cứu về
phương pháp lập trình hướng đối tượng đều đề cập đến 4 đặc trưng cơ bản của
phương pháp lập trình hướng đối tượng. Các vấn đề chi tiết cũng như phương pháp
lập trình khai thác các đặc trưng này sẽ được đề cập ở những chương sau, trong
phần này chúng ta điểm qua khái niệm về chúng.
- Tính đóng gói (encapsulation): như khái niệm đối tượng đã được đề cập, mỗi
đối tượng bao gồm các thành phần thuộc tính để mô tả thông và và các phương thức
thể hiện hành vi xử lý thông tin. Như vậy, chúng ta đã đóng gói các thành phần này
lại với nhau nhằm phản ánh toàn bộ nội dung của đối tượng (minh họa Hình vẽ 1.6).
Xem xét từ góc độ lập trình chúng ta thấy trong chương trình gồm các biến
chứa dữ liệu, các đơn vị xử lý (hàm) thao tác trên các biến nhằm xử lý và tính toán

Kỹ thuật lập trình hướng đối tượng - Bài 1 Trang 5


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

để thực hiện yêu cầu đặt ra của bài toán. Vì thế, các kết quả đóng gói từ các biến và
các hàm để hình thành các lớp đối tượng sẽ đem lại hiệu quả thực hiện chương trình
tốt hơn. Mục tiêu đặt ra là đóng gói sao cho phản ánh được nội dung thông tin và
hành vi xử lý thông tin của các lớp đối tượng mà chương trình cần có.

Hình vẽ 1.6: Minh họa sự đóng gói các thành phần


Tính đóng gói còn làm đơn giản hóa quá trình tương tác xử lý giữa các đối
tượng, bởi vì nó che đi sự phức tạp cố hữu nội tại bên trong một đối tượng. Các đối
tượng khác tương tác xử lý thông qua những giao tiếp bên ngoài mà không cần phải
quan tâm đến sự phức tạp bên trong của đối tượng đó. Chẳng hạn, một máy tính cá
nhân bản thân bên trong nó chứa những các bộ phận chi tiết, vi mạch phức tạp
nhưng chúng ta sử dụng chỉ cần vài thao tác bấm nút là có thể tương tác với nó.

Hình vẽ 1.6: Đóng gói nhằm che đi những chi tiết phức tạp bên trong
- Tính che giấu thông tin (data-hiding): các thành phần sau khi được đóng gói
chúng ta có thể thiết lập cơ chế về khả năng truy xuất xử lý đến các thành phần đó
hay được gọi là phạm vi tác động (scope). Rõ ràng, tính chất này có được là nhờ sự
đóng gói (Hình vẽ 1.8).

Kỹ thuật lập trình hướng đối tượng - Bài 1 Trang 6


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Hình vẽ 1.8: Minh họa cơ chế che dấu thông tin


- Tính kế thừa (inheritance): là khái niệm quan trọng trong lập trình hướng đối
tượng. Thực tế, các đối tượng không hoàn toàn tách rời nhau mà chúng có những
quan hệ nhất định. Chẳng hạn, con mèo và con chó có chung một số đặc điểm và
chúng đều được gọi vật nuôi, hay sinh viên và giáo viên có những đặc điểm chung
vì đều là con người... Như vậy, nếu các lớp đối tượng có chung một số đặc điểm và
được xem như có quan hệ “là” (is a) với lớp đối tượng khác thì chúng ta nói có sự
kế thừa giữa chúng.

Hình vẽ 1.9: Minh họa sự kế thừa giữa các lớp đối tượng
Trong Hình vẽ 1.9, đối tượng “oHuman” và “oPet” đều kế thừa các đặc điểm từ
“oAnimal” tức chúng đều có não bộ (brain = true) và đều có chân, nhưng số chân
giữa “oHuman” và “oPet” khác nhau, tương tự giữa “oDog” và “oCat” với “oPet”.
- Tính đa hình (polymorphism): là một khái niệm khá phức tạp trong lập trình
hướng đối tượng, nó cho phép nhiều đối tượng xử lý, phản hồi cho cùng một thông
điệp. Một khía cạnh khác, đa hình tức là cùng một đối nhưng được khai thác, xử lý
dưới nhiều hình thức khác nhau. Tính đa hình được gắn liền với ngữ cảnh trong
chương trình, mỗi ngữ cảnh sẽ cho ra một hình thức khai thác, xử lý cụ thể phù hợp.
Chẳng hạn, Hình vẽ 1.9 cho thấy một con mèo có thể xem như là một vật nuôi, hoặc
một động vật, phụ thuộc vào ngữ cảnh khai thác.

Bốn tính chất của phương pháp lập trình hướng đối tượng là những tính chất
rất đặc trưng, các vấn đề về kỹ thuật và phương pháp sử dụng, khai thác những
tính chất này sẽ được trình bày kỹ ở những chương tiếp theo. Phần sau chúng
ta xem xét về ngôn ngữ lập trình hướng đối tượng.

3. Ngôn ngữ lập trình hướng đối tượng


3.1. Sự phát triển của các ngôn ngữ lập trình hướng đối tượng

Kỹ thuật lập trình hướng đối tượng - Bài 1 Trang 7


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Về cơ bản, một ngôn ngữ lập trình được gọi là hướng đối tượng nếu nó cung
cấp đủ 4 đặc trưng đã xem xét ở trên: tính đóng gói, tính che dấu thông tin, tính kế
thừa và tính đa hình.
Ngôn ngữ lập trình hướng đối tượng được phát triển cùng với sự hình thành và
phát triển của phương pháp lập trình hướng đối tượng (Hình vẽ 1.10). Phương pháp
này được khởi xướng vào những năm 1960 tại Na-uy, sau đó được các nhà nghiên
cứu, ứng dụng phát triển rất mạnh mẽ. Có thể xem ngôn ngữ Simula của Christian
Nygaard và cộng sự tại đại học Oslo là ngôn ngữ đầu tiên hỗ trợ hướng đối tượng.
Sau đó những năm 1970 và 1980 tiếp theo là sự phát triển các ngôn ngữ Smalltalk,
Eiffel và C++.
Ngôn ngữ Java được xây dựng và phát triển bởi James Gosling và cộng sự tại
hãng Sun Microsystems, nó trở nên phổ biến vào cuối những năm 1990. Khác với
C++ có sự kết hợp của cả lập trình cấu trúc và hướng đối tượng, Java là ngôn ngữ
thuần hướng đối tượng, tức mọi thành phần của chương trình đều phải được đóng
gói thành các lớp đối tượng, mọi hành động (actions) đều được thực hiện trên các
đối tượng và các lớp. Đặc điểm thứ hai của Java khác C++ đó là các đối tượng
không cần đến việc giải phóng bộ nhớ sau khi khai thác xử lý xong của người lập
trình do cơ chế tự động “thu gom rác” (garbage collection) được cung cấp sẵn bởi
Java, điều này giống với 2 ngôn ngữ Smalltalk và Eiffel.

Si Smal C J C
mula ltalk ++ ava #
1 1 1 1 2 2
960 970 980 990 000 010

Hình vẽ 1.10: Lịch sử phát triển các ngôn ngữ hướng đối tượng
Trong khuôn khổ tài liệu này, chúng ta tập trung khai thác sử dụng ngôn ngữ
Java để thể hiện cho các vấn đề của phương pháp lập trình hướng đối tượng. Các
phần tiếp sau sẽ trình bày cụ thể hơn về ngôn ngữ lập trình Java.
3.2. Ngôn ngữ lập trình Java
Java là ngôn ngữ lập trình được sử dụng khá phổ biến hiện nay, nó không chỉ
được dùng để phát các ứng dụng cho máy tính mà còn sử dụng để phát triển các ứng
dụng cho các thiết bị di động như điện thoại di động, điện thoại thông minh,... đặc
biệt là lập trình trên hệ điều hành Android.
Một số đặc điểm của ngôn ngữ Java:

Kỹ thuật lập trình hướng đối tượng - Bài 1 Trang 8


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

- Cấu trúc cú pháp lệnh của ngôn ngữ hầu hết kế thừa từ C/C++ nên dễ tiếp cận
nếu đã biết ngôn ngữ C/C++, mềm dẻo và linh hoạt trong sử dụng nhưng cũng rất
chặt chẽ về cú pháp.
- Là ngôn ngữ lập trình thuần hướng đối tượng như đã đề cập ở trên.
- Java áp dụng cơ chế bộ nhớ động cho mọi đối tượng trong chương trình. Do
đó, một khai báo biến bất kỳ có kiểu lớp đều dưới dạng tham chiếu (con trỏ), tức là
một biến chứa địa chỉ của đối tượng.
Về phía hệ thống, các đối tượng khi tạo sẽ được cấp phát bộ nhớ trên vùng heap
(trên RAM), do đó mỗi đối tượng có một địa chỉ tương ứng. Để truy cập xử lý các
đối tượng này chúng ta phải khai báo các biến tham chiếu để lưu giữ địa chỉ của đối
tượng (Hình vẽ 1.11).

Hình vẽ 1.11: Minh họa tham chiếu và 02 đối tượng


- Độc lập với môi trường thực hiện. Đây là đặc điểm nổi bật của Java, tức một
chương trình bằng ngôn ngữ Java sau khi được biên dịch có thể chạy được trên các
hệ nền khác nhau (hệ nền được hiểu bao gồm hệ điều hành và hệ thống phần cứng).
Hình vẽ 1.12 minh họa điều này, chương trình sau khi viết và biên dịch có thể chạy
trên hệ điều hành Windows, Unix, hoặc MacOS.

Kỹ thuật lập trình hướng đối tượng - Bài 1 Trang 9


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Hình vẽ 1.12: Sự độc lập với hệ nền của chương trình Java
Với đặc điểm này, giới lập trình Java thường sử dụng khẩu hiệu thể hiện là
“write one, run anywhere” để ám chỉ rằng chương trình Java được viết một lần và
chạy ở khắp mọi nơi.
Sự độc lập này được thực hiện nhờ cơ chế máy ảo (Java Virtual Machine -
JVM) để thực hiện chương trình. JVM là một hệ thống phần mềm được xây dựng
và đóng gói sẵn, sau đó cài đặt trên các thiết bị, máy tính với chức năng dùng để
thông dịch các câu lệnh của chương trình Java khi thực hiện. Quá trình lập trình,
biên dịch và chạy chương trình Java được thể hiện qua sơ đồ sau.

Hình vẽ 1.13: Quá trình biên dịch và chạy chương trình Java
Trong đó, chương trình Java được lập trình và lưu bằng tệp tin mã nguồn phần
mở rộng *.java (gọi là Java Source). Sau khi biên dịch (compiler) sẽ tạo thành

Kỹ thuật lập trình hướng đối tượng - Bài 1 Trang 10


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

chương trình mã byte (Java Bytecodes) và lưu trữ thành tệp tin có phần mở rộng
*.class, phân phối đến các máy ứng dụng. Việc chạy chương trình Java trên một hệ
nền nào đó sẽ nhờ máy ảo (Java Virtual Machine) thông dịch các lệnh mã byte về
mã máy để thực thi.
3.3. Lập trình bằng ngôn ngữ Java
Để lập trình bằng Java, trước hết chúng ta phải cài đặt phần mềm phát triển ứng
dụng có tên là JDK (Java Development Kit) được cung cấp miễn phí tại địa chỉ
“http:// www.oracle.com/ technetwork/ java/ javase/ downloads/ index.html”. Sau
khi cài đặt thường có thư mục “Java” với hai thư mục con là “jdk<số hiệu phiên
bản>” chứa trình biên dịch và “jre<phiên bản>” chứa hệ thống thư viện và máy ảo
Java.
Java được cung cấp khá nhiều môi trường phần mềm để lập trình như JCreator,
Eclipse, NetBean... song để thuận tiện trong tài liệu chúng ta sẽ thực hiện trên môi
trường Eclipse, đây là phần mềm miễn phí và thuận tiện, chỉ cần copy vào máy để
chạy, không cần cài đặt hay cấu hình phức tạp (giao diện có dạng sau).

Hình vẽ 1.14: Giao diện làm việc với Eclipse


Tuy nhiên, chúng ta có thể không dùng môi trường mà biên soạn chương trình
trên một phần mềm nào đó, lưu lại tệp tin *.java và sử dụng lệnh trực tiếp của JDK
để biên dịch và chạy thử. Lệnh biên dịch và chạy thử chương trình Java sử dụng 2
tệp tin “javac.exe” và “java.exe” trong thư mục “BIN” của thư mục đã cài đặt JDK.
Cú pháp thực hiện lệnh biên dịch là:

javac tên_tệp_chương_trình.java
Lệnh để chạy thử chương trình là:

Kỹ thuật lập trình hướng đối tượng - Bài 1 Trang 11


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

java tệp_chương_trình
Quy tắc chung của một tệp chương trình bằng Java gồm các phần sau:

/*Phần 1: Khai báo thư viện*/

import tên_thư_viện1;

import tên_thư_viện2;

...

/*Phần 2: Lớp chương trình chính*/

public class tên_lớp {

//các_nội_dung_của_lớp_chương_trình

public static void main(String[] ts){

//nội_dung_chương_trình_chính

/*Phần 3: Các lớp đối tượng khác*/


Trong đó, phần khai báo thư viện có thể không dùng vì một số thư viện được
mặc định sẵn. Tên lớp chứa chương trình chính (hàm “main”) phải trùng với tên tệp
chương trình vì nó là lớp “public”. Nhắc lại, các chú thích được viết trong bộ cặp ký
tự /* và */ nếu viết trên nhiều dòng, còn trên một dòng sử dụng ký hiệu //.

Ví dụ một chương trình Java đơn giản (có tên tệp là “vidu.java”):

Kết quả dịch và chạy thử chương trình trên Eclipse (cửa sổ màn hình “Console”
để chứa kết quả chạy và các thông báo khi chạy chương trình) là:

Kỹ thuật lập trình hướng đối tượng - Bài 1 Trang 12


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Một số quy tắc/quy ước cần ghi nhớ khi lập trình Java:
- Sử dụng toán tử “new” để sinh đối tượng từ lớp cho việc sử dụng, khai thác và
xử lý, cụ thể: biến = new tên_lớp( tham_số_nếu_có );
- Các từ khóa lệnh viết thường, ví dụ: import, for, if, while, case, return, break,
continue...;
- Các tên lớp đối tượng viết dạng chuẩn (chữ cái đầu từ viết HOA, sau đó chữ
thường, các từ ghép thành tên hoặc viết tắt cũng theo quy ước này), ví dụ: Scanner,
System, JButton, JOptionPane...;
- Các tên hằng được viết chữ hoa, ví dụ: EXIT_ON_CLOSE, PI,
CLOSE_OPTION, QUESTION_MESSAGE...;
- Các tên biến (thuộc tính) viết chữ thường;
- Các tên hàm (phương thức) viết từ đầu (động từ) bằng chữ thường, các từ sau
đó theo dạng chuẩn, ví dụ: print, showMessageDialog, setText...
- Các lệnh không đứng độc lập, bắt buộc một lệnh cần thực hiện phải trên một
đối tượng hoặc trên một lớp nào đó, và thậm chí có thể trên nhiều lớp và đối tượng
khi chúng bao nhau. Quy tắc chung được viết theo kiểu phân cấp (dùng dấu chấm)
như sau:

cấp_1.cấp_2...cấp_n.lệnh_cần_gọi( tham_số );
trong đó cấp_i là thể hiện của một gói (package) hay một lớp (class) hay một
đối tượng (object).
Ví dụ: Lệnh sau để tính căn bậc hai của 2012 gán vào biến y

double y = Math.sqrt(2012);
hoặc lệnh sau sẽ in một dòng chữ lên màn hình,

System.out.print(“Xin chao ban. Toi dang hoc JAVA.”);


- Các phép toán, kiểu dữ liệu chuẩn (đơn)... đều kế thừa từ C/C++ nên không
trình bày chi tiết ở đây, coi như người đọc đã biết C/C++.
Chúc các Anh/Chị học tập tốt!

Kỹ thuật lập trình hướng đối tượng - Bài 1 Trang 13


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

BÀI 2: CÁC THÀNH PHẦN CO BẢN TRONG JAVA

Mục tiêu:
Trong bài này, Anh/Chị cần đạt được những mục tiêu sau:
1. Các thành phần cơ bản trong ngôn ngữ Java.
2. Các trúc điều khiển trong lập trình java.
3. Kỹ thuật vào – ra dữ liệu.
4. Kỹ thuật xử lý dữ liệu nâng cao.
Nội dung:

1. Các thành phần cơ bản trong ngôn ngữ Java


Cũng giống như ngôn ngữ C/C++, các toán tử của Java để viết biểu thức tính
toán trong chương trình được giới thiệu ở bảng sau:

Toán tử Ký hiệu

gán =

tăng, giảm ++, --

đa năng +, -, ~, !, (ép kiểu)

nhân, chia, chia dư *, /, %

cộng, trừ, kết nối +, -, +

dịch bít <<, >>, >>>

so sánh <, <=, >, >=, ==, !=, instanceof

tác động bít &, |, ^

kết nối lôgíc &&, ||

điều kiện ?:

Kỹ thuật lập trình hướng đối tượng - Bài 2 Trang 1


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

gán kết hợp +=, -=, *=, %=,...


Cách viết các toán tử tương tự các ngôn ngữ lập trình khác, phép ++,-- có thể
sử dụng tiền tố hoặc hậu tố với mức ưu tiên trước hoặc sau. Ví dụ:

x = 5;

y = x++; /*sẽ gán x vào y, sau đó tăng x lên 1*/

y = ++x; /*sẽ tăng x trước và gán x vào y sau.*/


- Phép toán ép kiểu cho phép chúng ta chuyển dữ liệu từ một kiểu này sang
kiểu khác, tuy nhiên việc này có thể làm mất dữ liệu nếu kiểu đích có miền giá trị
nhỏ hơn. Ví dụ:

int x=140276;

short y = (short) x; /*khi hiện kết quả sẽ có y=9204, dữ liệu bị mất*/


Thông thường việc ép kiểu được dùng trong các tham chiếu, trình bày ở phần
sau.
- Phép toán chia (/) sẽ cho kết quả phần nguyên nếu hai dữ liệu là số nguyên,
nếu một dữ liệu số thực sẽ cho kết quả chính xác của phép chia. Phép chia dư (%)
chỉ thực hiện trên số nguyên. Ví dụ:
9/2 sẽ cho kết quả 4,
9.0/2 hoặc 9/2.0 sẽ cho kết quả 4.5
Toán tử dịch bít sang trái <<, sang phải >>, và sang phải không dấu >>> tác
động lên từng bít của dữ liệu. Ví dụ:

short x = -45;
thì biểu diễn nhị phân là (không sử dụng số bù 2)

1 0 0 0 0 0 0 0 0 0 1 0
1 1 0 1
Khi dịch trái (<<) bít dấu (bên trái cùng) sẽ được giữ nguyên, các bít còn lại
được chuyển sang trái đi một số ô theo yêu cầu phép toán, ví dụ:

short y = x<<2;
khi đó y=-180 (tương ứng với nhân 22=4), và giá trị nhị phân là

Kỹ thuật lập trình hướng đối tượng - Bài 2 Trang 2


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

1 0 0 0 0 0 0 0 1 0 1 1
0 1 0 0
Khi dịch phải (>>) bít dấu được giữ nguyên, chỉ dịch các bít còn lại, ví dụ:

short y = x>>2;
khi đó y=-11 và giá trị nhị phân là

1 0 0 0 0 0 0 0 0 0 0 0
1 0 1 1
Khi dịch phải không dấu (>>>) thì bít dấu cũng được dịch theo các bít giá trị, vì
vậy đôi khi phép toán này cho kết quả không có nghĩa, ví dụ:

int y = x>>>2;
khi đó y=1073741812.
- Toán tử so sánh chỉ tác động trên những dữ liệu phù hợp như: số, ký tự, và
tham chiếu. Tuy nhiên tham chiếu chỉ thực hiện được phép so sánh bằng (==) và so
sánh khác (!=).
- Toán tử lôgíc (&&, ||) để kết nối các biểu thức lôgíc, thường được dùng trong
các điều kiện của lệnh rẽ nhánh, lệnh lặp.
- Phép toán ba ngôi (?:) sẽ tác động lên ba dữ liệu, cú pháp như sau:

(điều kiện) ? biểu thức 1 : biểu thức 2


Máy sẽ thực hiện cho kết quả <biểu thức 1> nếu <điều kiện> đúng, ngược lại
cho kết quả <biểu thức 2>. Ví dụ:

x = (a>b)? a-b : b-a;


sẽ cho kết quả số lớn – số bé giữa hai số a và b.
- Đặc biệt phép toán nối (+) để thực hiện nối hai xâu ký tự, nối xâu ký tự với
một ký tự, nối xâu ký tự với số nguyên, số thực. Ví dụ:

“Ha” + “noi”, hoặc “Hano” + ‘i’ cho kết quả là “Hanoi”,

45 + “ABC” cho kết quả là “45ABC”,

“ABC” + 45 cho kết quả là “ABC45”.


Vì trong Java dữ liệu ký tự có thể được xử lý như là số nguyên (theo mã của ký
tự) nên phép nối giữa số và ký tự sẽ thực hiện như phép cộng, ví dụ:

Kỹ thuật lập trình hướng đối tượng - Bài 2 Trang 3


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

45 + ‘A’
cho kết quả là 110, vì mã của ký tự ‘A’ là 65.
- Biểu thức: biểu thức là kết hợp giữa các phép toán tác động lên dữ liệu thực
hiện tính toán và xử lý. Trong biểu thức có thể dùng dấu mở đóng ngoặc để ưu tiên
thực hiện phép toán cao nhất, nếu không máy sẽ theo thứ tự ưu tiên mặc định (nhân
chia trước, cộng trừ sau). Ví dụ:

x = 7+8*2; sẽ cho kết quả x=23, nhưng

y = (7+8)*2; sẽ cho kết quả y=30.


- Câu lệnh: câu lệnh (statements) là kết hợp các từ khóa, biểu thức để yêu cầu
máy thực hiện một thao tác tính toán, xử lý nào đó. Kết thúc một câu lệnh phải có
dấu chấm phẩy (;), trên một dòng có thể viết nhiều câu lệnh và một lệnh có thể được
viết trên nhiều dòng.
- Khối lệnh: khối lệnh (nhóm lệnh) được đóng khung bởi cặp dấu { và }, nếu
một hành động xử lý nào đó cần đến nhiều lệnh thì phải sử dụng khối lệnh. Kết thúc
khối lệnh (sau dấu }) không cần dấu chấm phẩy (;).
- Chú thích trong Java: có 2 cách viết chú thích, đó là viết sau cặp dấu // để chú
thích một dòng hoặc viết trong cặp dấu /* và */ để chú thích trên nhiều dòng.
Tuy nhiên có thể viết chú thích trong cặp /** và */ và thường được sử dụng cho
trong công cụ sinh mã HTML của Java.

2. Các cấu trúc điều khiển trong lập trình


Trong bất kỳ một ngôn ngữ lập trình nào của máy tính, ngoài cấu trúc thực hiện
lệnh tuần tự là đặc trưng của máy tính điện tử hiện nay đều cung cấp hai cấu trúc
điều khiển cơ bản đó là rẽ nhánh và lặp. Cũng vậy, trong Java quy tắc thực hiện các
cấu trúc đó như sau.
2.1. Lệnh rẽ nhánh (if, switch)
Lệnh rẽ nhánh cho phép điều khiển máy thực hiện một hoặc một vài trong các
trường hợp đã đưa ra, có 2 lệnh if và switch với cách viết như sau:

if ( điều-kiện )

nhóm-lệnh-1;

else

nhóm-lệnh-2;

Kỹ thuật lập trình hướng đối tượng - Bài 2 Trang 4


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

và:

switch ( biểu-thức ) {

case giá-trị-1:

nhóm-lệnh-1;

break;

case giá-trị-2:

nhóm-lệnh-2;

break;

case giá-trị-n:

nhóm-lệnh-n;

break;

default:

nhóm-lệnh-n+1;

}
Lệnh if thực hiện <nhóm-lệnh-1> nếu <điều-kiện> có giá trị đúng, ngược lại
thực hiện <nhóm-lệnh-2>. Tuy nhiên có thể lệnh if không sử dụng trường hợp
ngược lại (không có else và <nhóm-lệnh-2>) thì máy sẽ bỏ qua nếu <điều-kiên> sai.
Lệnh switch thực hiện so sánh giá trị của <biểu-thức> với các <giá-trị-1> đến
<giá-trị-n>, nếu bằng ở <giá-trị-k> nào (với k=1,2,…,n) thì thực hiện <nhóm-lệnh-k>
tương ứng cho đến khi gặp lệnh break.
Ví dụ hiện số lớn trong hai số a và b:

if ( a>b )

System.out.println(“Số lớn là : ” + a);

else

if ( b>a )

Kỹ thuật lập trình hướng đối tượng - Bài 2 Trang 5


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

System.out.println(“Số lớn là : ” + b);

else

System.out.println(“Hai số bằng nhau”);


hoặc hiện ngày trong tuần bằng tiếng anh theo số ngày tương ứng:

switch ( a ){

case 1:

System.out.println(“Sunday”);

break;

case 2:

System.out.println(“Monday”);

break;

case 3:

System.out.println(“Tuesday”);

break;

case 4:

System.out.println(“Wednesday”);

break;

case 5:

System.out.println(“Thursday”);

break;

case 6:

System.out.println(“Friday”);

break;

case 7:

Kỹ thuật lập trình hướng đối tượng - Bài 2 Trang 6


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

System.out.println(“Saturday”);

break;

default:

System.out.println(“Không phải là ngày trong tuần”);

}
Trong đó lệnh System.out.println(...) để hiện dữ liệu ra màn hình sẽ được trình
bày chi tiết sau.
Lệnh if ở trên chúng ta sử dụng lồng nhau, trong <nhóm-lệnh-2> có một lệnh if
khác. Thực hiện các lệnh if lồng nhau theo thứ tự từ ngoài vào trong.
Trong lệnh switch nếu không sử dụng lệnh break trong một trường hợp nào đó
thì các nhóm lệnh của các trường hợp tiếp theo kể từ một trường hợp bằng xẩy ra sẽ
tự động thực hiện cho đến khi gặp một lệnh break.
Nếu trong một nhóm có nhiều lệnh thì phải đóng khối bằng cặp ký tự { và }, ví
dụ:

if ( a>b )

x=a-b; b=a; a=x;

else

x=a+b;

System.out.println(“Tổng hai số là : ” + x);

Kỹ thuật lập trình hướng đối tượng - Bài 2 Trang 7


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

2.2. Lệnh lặp (for, while, do-while)


Lệnh lặp cho phép thực hiện một nhóm lệnh nhiều lần trên máy, mặc dù chúng
ta chỉ viết một lần trong chương trình. Trong Java có 3 cách viết lệnh lặp gồm for,
while, do-while được trình bày chi tiết sau đây.
Cách viết lệnh for:

for ( nhóm-lệnh-1 ; điều-kiện ; nhóm-lệnh-2 )

nhóm-lệnh-lặp;

}
Cách viết lệnh while:

while ( điều-kiện )

nhóm-lệnh-lặp;

}
Cách viết lệnh do-while:

do {

nhóm-lệnh-lặp;

} while ( điều-kiện );
Lệnh for máy thực hiện <nhóm-lệnh-1> đầu tiên, tiếp theo kiểm tra <điều-
kiện>, nếu đúng máy thực hiện <nhóm-lệnh-lặp>, xong thực hiện <nhóm-lệnh-2>
và lặp lại kiểm tra <điều-kiện> cho đến khi có giá trị sai.
Lệnh while máy sẽ kiểm tra <điều-kiện> và thực hiện <nhóm-lệnh-lặp>, quá
trình lặp lại cho đến khi <điều-kiện> có giá trị sai.
Lệnh do-while máy thực hiện <nhóm-lệnh-lặp> trước, sau đó kiểm tra <điều-
kiện> nếu đúng sẽ lặp lại thực hiện <nhóm-lệnh-lặp> cho đến khi sai.
Ví dụ hiện các số nguyên lẻ từ 50 đến 100 bằng lệnh for,

for ( i=50; i<=100; i++ )

Kỹ thuật lập trình hướng đối tượng - Bài 2 Trang 8


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

if ( i%2!=0 )

{ System.out.println(“ ” + i );

}
Ví dụ tìm ước số chung lớn nhất của hai số a và b bằng lệnh while,

while ( a!=b )

if ( a>b ) a = a-b;

else b = b-a;

}
Ví dụ tính tổng các chữ số của một số nguyên n bằng lệnh do-while,

tong = 0;

do
{

tong += n%10;

n = n/10;

} while (n>0);
Hai lệnh lặp for và while có thể viết thay thế nhau tương đương, với lệnh do-
while khác với hai lệnh trên: nó thực hiện nhóm lặp trước rồi mới kiểm tra điều kiện
lặp, còn lệnh for/while kiểm tra điều kiện lặp nếu đúng mới thực hiện nhóm lặp. Vì
vậy lệnh do-while sẽ thực hiện nhóm lặp ít nhất một lần, ngược lại lệnh for/while có
thể không thực hiện nhóm lặp.
2.3. Lệnh break và continue
Lệnh break để dừng vòng lặp vô điều kiện, thường dùng trong nhóm lệnh lặp
và lệnh “switch” như trên. Khi máy gặp lệnh này sẽ kết thúc lệnh lặp cho dù điều
kiện lặp có đúng hay sai. Cũng như trong lệnh switch ở trên, máy sẽ kết thúc thực
hiện các nhóm lệnh tiếp theo khi gặp một lệnh break.

Kỹ thuật lập trình hướng đối tượng - Bài 2 Trang 9


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Ví dụ sử dụng lệnh continue trong lệnh lặp để hiện các số từ 1 đến 10 và tính
tổng các số lẻ như sau:

for ( i=1; i<=10; i++ )

System.out.print( i + “ , ” );

if ( i%2 == 0 ) continue;

t = t + i;

System.out.print( “\n Tong cac so le la : ” + t );


Các cấu trúc lệnh lặp (for, while, do-while) trên có thể sử dụng theo cơ chế
“lồng nhau”, tức là trong nhóm lặp của lệnh này có chứa một lệnh lặp khác. Ví dụ
hai lệnh lặp for như sau:

for ( i=1; i<5; i+=2 )

for ( j=i+1; j<5; j++)

System.out.print( “\n (” + i + “ , ” + j + “)” );

}
Ví dụ trên sẽ hiện các cặp số (1,2); (1,3); (1,4); (3,4).
Khác với lập trình C/C++ trong cách tổ chức chương trình, C/C++ cho phép lập
trình các hàm độc lập, còn Java bắt buộc các hàm phải được gói trong các lớp, gọi
là phương thức, trình bày chi tiết ở phần sau.

3. Kỹ thuật vào/ra dữ liệu


Nhập và xuất dữ liệu là hai thao tác cơ bản của mọi chương trình phần mềm để
tương tác thông tin giữa người dùng với máy tính, do đó chúng thường xuyên được
sử dụng. Các thao tác nhập/xuất (hay còn gọi là vào/ra) dữ liệu thực hiện chủ yếu
với bàn phím, màn hình và ổ đĩa lưu trữ. Các dữ liệu đưa vào từ các thiết bị này gọi
là dữ liệu nguồn (Data Source).

Kỹ thuật lập trình hướng đối tượng - Bài 2 Trang 10


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Hình vẽ 2.1: Minh họa nhập/xuất dữ liệu của chương trình


Java cung cấp cơ chế vào/ra dữ liệu theo dòng (stream) ở hai cấp độ, thứ nhất là
mức thấp dữ liệu được mã hóa dưới dạng byte và làm việc trực tiếp với các thiết bị,
thứ hai là mức cao dữ liệu được định dạng theo từng kiểu để dễ dàng xử lý trong
chương trình.

Chư
ơng trình Dòng mức Các
phần thấp thiết bị màn
mềm hình, bàn
Dòng mức
phím, ổ
cao

Hình vẽ 2.2: Cơ chế vào/ra dữ liệu theo dòng


Mỗi dòng mức thấp hay mức cao đều có hai loại đối tượng, đó là dòng nhập dữ
liệu (input stream) cung cấp thao tác đọc dữ liệu (read) từ các thiết bị nhập vào
chương trình và dòng xuất (output stream) cung cấp thao tác ghi dữ liệu (write) từ
chương trình ra các thiết bị.

Hình vẽ 2.3: Hai thao tác cơ bản đọc/ghi dữ liệu


Chúng ta thường sử dụng hai dòng này ở chế độ bao nhau, tức đối tượng dòng
mức cao bao đối tượng dòng mức thấp. Các dòng mức thấp làm việc kết nối trực
tiếp với các thiết bị và thực hiện đọc/ghi dữ liệu dưới dạng byte. Còn dòng mức cao
khi đọc sẽ nhận dữ liệu các byte từ dòng mức thấp chuyển hóa thành các dữ liệu

Kỹ thuật lập trình hướng đối tượng - Bài 2 Trang 11


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

theo từng kiểu phù hợp với nhu cầu xử lý trong chương trình, khi xuất thì các dữ
liệu sẽ được chuyển hóa thành các byte đưa lên dòng mức thấp để xuất ra các thiết
bị vật lý (hình vẽ sau minh họa điều này).

Chư
ơng trình

Hình vẽ 2.4: Cơ chế bao nhau của các dòng mức cao/thấp
Java cung cấp hệ thống khá phong phú dưới dạng các lớp đối tượng. Sau
đây là danh sách một số lớp đối tượng cơ bản hay dùng.

Thuộc
Stt Tên lớp đối tượng thư Chức năng
viện

1 InputStream java.io Nhập dữ liệu mức thấp

2 FileInputStream java.io Đọc dữ liệu tệp tin mức thấp

3 DataInputStream java.io Nhập dữ liệu có định kiểu

4 ObjectInputStream java.io Nhập dữ liệu dạng đối tượng

5 ByteArrayInputStream java.io Đọc dữ liệu dựa trên mảng byte

6 BufferedInputStream java.io Nhập dữ liệu theo vùng nhớ đệm

7 OutputStream java.io Xuất dữ liệu mức thấp

8 FileOutputStream java.io Ghi dữ liệu ra tệp tin mức thấp

9 DataOutputStream java.io Xuất dữ liệu có định kiểu

10 ObjectOutputStream java.io Xuất dữ liệu dạng đối tượng

Kỹ thuật lập trình hướng đối tượng - Bài 2 Trang 12


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

11 ByteArrayOutputStream java.io Xuất dữ liệu dạng mảng byte

12 BufferedOutputStream java.io Xuất dữ liệu theo vùng nhớ đệm

13 File java.io Xử lý tệp tin

14 Scanner java.util Xử lý nhập dữ liệu đơn giản

15 System java.lang Cung cấp các đối tượng, tham số

16 PrintStream java.io Xuất dữ liệu có thêm các định


dạng
Các thiết bị thường sử dụng để nhập/xuất dữ liệu hiện nay gồm màn hình, bàn
phím, ổ đĩa và giao tiếp mạng máy tính. Tất cả các thiết bị đều có thể áp dụng các
lớp đối tượng trên để thực hiện. Sau đây chúng ta xem xét nhập/xuất dữ liệu đối với
các thiết bị chuẩn.
3.1 . In dữ liệu ra màn hình
Sử dụng đối tượng “out” thuộc lớp “PrintStream” cung cấp chức năng in dữ
liệu ra màn hình dạng Console (là một cửa sổ dạng text để hiển thị các dòng ký tự).
Các lệnh thực hiện gồm:

System.out.print( D );

System.out.println( D );

System.out.printf( F, D );
Trong đó “D” là dữ liệu cần in gồm một biểu thức xác định giá trị dữ liệu. Lệnh
“println” sẽ xuống dòng sau khi in xong, lệnh “printf” sẽ in dữ liệu có định dạng
quy định bởi “F” gồm các thành phần sau:

%[argument_index$][flags][width][.precision]conversion
Phần trong cặp dấu ngoặc [ và ] là tùy chọn, như vậy bắt buộc là dấu “%” và
phần “conversion” để quy định chuyển dữ liệu gồm các kiểu hay dùng như “%d”,
“%f”, “%s”, “%x”, “%td”, “%tm”, “%tY”, “%tH”, “%tM”, “%tS”... tương ứng dữ
liệu in ra là số nguyên, số thực, xâu ký tự, số hexa, ngày, tháng, năm, giờ, phút,
giây...
“argument_index” cho biết quy định này dành cho dữ liệu thứ mấy trong “D”.

Kỹ thuật lập trình hướng đối tượng - Bài 2 Trang 13


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

“flags” quy định trạng thái in dữ liệu như “-”, “0”, “+”, “(” tương ứng để căn
trái dữ liệu, thêm số 0 vào bên trái các số, luôn có dấu trước các số, thêm cặp dấu
ngoặc ( và ) trước số âm.
“width” và “precision” quy định độ rộng dữ liệu in và độ chính xác số thực (số
lượng chữ số thập phân).

Ví dụ các lệnh in sau:

System.out.print(“Hello WORLD.”); /*in dòng chữ*/

System.out.println(2012); /*in ra số 2012 và xuống dòng*/

System.out.printf(“Two numbers: %d and %f”, 10, 11.0); /*in định dạng số nguyên và số
thực*/
sẽ cho kết quả là

Đối với lệnh in có định dạng chúng ta quy định thêm độ rộng (width - “w”) dữ
liệu in, độ chính xác thập phân (precision - “p”) của số thực bằng cách chèn thêm
“w” hay “w.p” vào giữa cặp ký tự định dạng. Mặc định máy sẽ căn phải dữ liệu, tức
chèn thêm các khoảng trắng bên trái dữ liệu theo đủ độ rộng quy định. Để căn trái
chúng ta quy định độ rộng là số âm. Ví dụ sau
System.out.printf("Width is [%10d]",2012); /*in có độ rộng*/
System.out.printf("\nPrecision is [%-10.2f]", 5.1/4); /*in căn trái và có độ chính xác đối
với số thực*/

cho kết quả là

Một số ký tự điều khiển trong lệnh in dữ liệu:

Ký hiệu Ý nghĩa

Kỹ thuật lập trình hướng đối tượng - Bài 2 Trang 14


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

\\ In ra ký tự \

%% In ra ký tự %

\n In xuống dòng

\t In một khoảng trắng tab

\ In ký tự nháy kép

\ In ký tự nháy đơn

Kỹ thuật lập trình hướng đối tượng - Bài 2 Trang 15


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

3.2 . Nhập dữ liệu từ bàn phím


Chúng ta sử dụng đối tượng lớp “Scanner” để nhập dữ liệu từ bàn phím, đối
tượng này bao đối tượng mức thấp là “System.in” được định nghĩa trong Java để kết
nối đến bàn phím. Quy tắc tạo đối tượng để nhập như sau:

Scanner  = new Scanner(System.in);


Sau đó sử dụng các lệnh nhập trên đối tượng vừa tạo gồm:

Lệnh Ý nghĩa

.nextLine() Nhập một xâu ký tự

.nextInt() Nhập một số nguyên

.nextFloat() Nhập một thực,...


Ví dụ minh họa sau sẽ nhập một số nguyên và một số thực, sau đó in ra tổng
của chúng,

Scanner obj = new Scanner(System.in);

int a; float b;

System.out.print(“Nhap a:”); a = obj.nextInt();

System.out.print(“Nhap b:”); b = obj.nextFloat();

System.out.printf(“\nKet qua tong: %f”, a+b);


và kết quả chạy thử trên màn hình là,

3.3. Đọc và ghi dữ liệu trên tệp


Các tệp tin trên ổ đĩa được xử lý thông qua đối tượng lớp “File”, tuy nhiên để
đơn giản chúng ta có thể dùng trực tiếp đối tượng “FileInputStream” hoặc
“FileOutputStream”. Sau đó sử dụng các đối tượng là dòng nhập/xuất mức cao để
bao bên ngoài đối tượng này cho việc đọc/ghi dữ liệu có định kiểu. Các đối tượng

Kỹ thuật lập trình hướng đối tượng - Bài 2 Trang 16


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

có thể dùng như “DataInputStream” để đọc dữ liệu và “DataOutputStream” để ghi


dữ liệu có định kiểu, dùng “Scanner” để đọc dữ liệu đơn giản và “PrintStream” để
ghi dữ liệu theo định dạng (dạng text).
Chúng ta sẽ làm quen với một phương pháp đọc/ghi dữ liệu trên tệp tin dạng
đơn giản (xử lý dạng tệp text).

Hình vẽ 2.5: Phương pháp đọc/ghi tệp dạng đơn giản


- Ghi dữ liệu vào tệp (dạng văn bản):

/*Bước 1: Tạo đối tượng ghi tệp*/

PrintStream  = new PrintStream(

new FileOutputStream(“tên-tệp”));

/*Bước 2: Thực hiện lệnh ghi tệp*/

.print( D );

.println( D );

.printf( F, D );

/*Bước 3: Đóng tệp*/

.close();
Các lệnh ghi dữ liệu giống với in ra màn hình vì đây là xử lý dạng tệp text (“D”
là dữ liệu cần lưu, “F” là định dạng cho dữ liệu). Tên tệp có thể bao gồm cả đường
dẫn đầy đủ.
Trường hợp muốn ghi thêm dữ liệu nếu tệp đã có nội dung chúng ta chỉ cần
thêm giá trị “true” vào lệnh tạo đối tượng “FileOutputStream” ở bước 1. Cụ thể
bước 1 sẽ là,

PrintStream  = new PrintStream(

Kỹ thuật lập trình hướng đối tượng - Bài 2 Trang 17


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

new FileOutputStream(“tên-tệp”,true));

- Sau đây là 3 bước để đọc dữ liệu từ tệp (dạng văn bản):

/*Bước 1: Tạo đối tượng ghi tệp*/

Scanner  = new Scanner(

new FileInputStream(“tên-tệp”));

/*Bước 2: Thực hiện lệnh đọc tệp*/

 = .nextLine(); /*đọc một xâu*/

 = .nextInt(); /*đọc số nguyên*/

 = .nextFloat(); /*đọc số thực*/

/*Bước 3: Đóng tệp*/

.close();
Các lệnh đọc dữ liệu giống với lệnh nhập dữ liệu từ bàn phím.
Quá trình đọc/ghi tệp có thể phát sinh lỗi, đặc biệt ở bước 1 (tạo đối tượng xử
lý tệp) sẽ gặp lỗi nếu tên tệp đưa vào không hợp lệ. Các lỗi này được gọi là ngoại lệ
(Exception), do đó các bước đọc/ghi tệp được đặt trong cấu trúc xử lý ngoại lệ (sẽ
trình bày chi tiết ở phần sau) như sau,

try{

/*Các bước xử lý tệp*/

}catch(Exception e){}
hoặc đơn giản sau khai báo chương trình chính (hàm main) có mệnh đề “throws
Exception”, cụ thể:

public static void main(String[]ts) throws Exception {

/*nội dung chương trình chính*/

}
Ví dụ sau sẽ ghi dữ liệu chuỗi họ tên có xuống dòng, hai số năm sinh và tiền
lương của một nhân viên vào tệp “staff.txt” trên thư mục “F:\”,

Kỹ thuật lập trình hướng đối tượng - Bài 2 Trang 18


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

PrintStream o = new PrintStream(

new FileOutputStream("f:\\staff.txt"));

o.printf("Duong Nguyen Long Khanh\n%d %f",

2002,4500000.0);

o.close();
ta có kết quả nội dung của tệp được mở bằng “WordPad” như sau

Ví dụ thứ 2 sẽ thực hiện đọc dữ liệu từ tệp vừa tạo và in ra màn hình kết quả,

Scanner o = new Scanner(

new FileInputStream("f:\\staff.txt"));

String t = o.nextLine();

int y = o.nextInt();

float s = o.nextFloat();

o.close();

System.out.printf("Ket qua doc:\n%s \n%d %10.2f", t,y,s);


sẽ cho kết quả trên màn hình đúng như các dữ liệu đã lưu trước đó,

Trường hợp cần đọc/ghi dữ liệu có định kiểu và thậm chí là các đối tượng phức
tạp chúng ta làm việc với tệp tin dạng nhị phân, sử dụng các lớp đối tượng
“DataInputStream”, “ObjectInputStream” và “DataOutputStream”,
“ObjectOutputStream”. Các lệnh đọc/ghi dữ liệu trên các đối tượng này gồm:

Lệnh Ý nghĩa

Kỹ thuật lập trình hướng đối tượng - Bài 2 Trang 19


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

.readInt() Đọc một số nguyên

.readFloat() Đọc một số thực

.readUTF() Đọc một xâu ký tự dạng UTF

.readObject() Đọc một đối tượng

.writeInt(  ) Lưu một số nguyên

.writeFloat(  ) Lưu một số thực

.writeUTF(  ) Lưu một xâu ký tự dạng UTF

.writeObject() Lưu một đối tượng,...

Ví dụ sau đây sẽ thực hiện lưu 100 số đầu của dãy Fibonaci (có dạng
1,1,2,3,5,8,... số sau bằng tổng 2 số kế trước) vào tệp có tên “fibonaci.txt”,

DataOutputStream o = new DataOutputStream(

new FileOutputStream("fibonaci.txt"));

int a=1,b=1,c;

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

o.writeInt(a); /*lưu số nguyên a vào tệp*/

c=a+b; /*tính số tiếp theo*/

a=b; /*gán a bằng số b*/

b=c; /*gán b bằng số tiếp theo*/

o.close();

4. Xử lý mảng
Như đã trình bày, java cung cấp cơ chế bộ nhớ động hoàn toàn nên các khai
báo mảng đều có dạng tham chiếu (là dạng con trỏ) chứa địa chỉ của vùng nhớ
mảng. Ví dụ sau sẽ khai báo 2 tham chiếu mảng một chiều và hai chiều,

Kỹ thuật lập trình hướng đối tượng - Bài 2 Trang 20


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

int a[]; /*tham chiếu mảng một chiều*/

float b[][]; /*tham chiếu mảng hai chiều*/


Lệnh tạo mảng được thực hiện bởi phép toán “new” và xác định kích thước của
mảng, ví dụ

a = new int[100]; /*tạo mảng 100 phần tử gán*/

b = new float[10][20]; /*tạo mảng 10 hàng, 20 cột*/


Việc truy cập xử lý mảng theo chỉ số phần tử (tính từ 0,1,2,...) và trên mảng có
phép toán “length” để xác định số phần tử hiện tại, ví dụ

a.length /*để xác định số phần tử của mảng được tham chiếu bởi a*/

b.length /*để xác định số hàng*/

b[i].length /*để xác định số cột ở hàng i*/

Phần tử Try nhập phần tử 8 viết là


đầu a[8]
Các chỉ số phần
tử
Độ dài mảng
10
Hình vẽ 2.6: Tổ chức dữ liệu mảng một chiều
Mặc định khi tạo mảng máy ảo (JVM) sẽ đặt các phần tử về giá trị 0, tuy nhiên
chúng ta có thể khai báo mảng và gán dữ liệu trực tiếp, khi đó máy sẽ tự tạo một
mảng theo dữ liệu được gán tương ứng, ví dụ:

int a[] = {1,1,2,3,5,8,13}; /*một chiều*/

float b[][] = {{5,3,2},{6,3,7},{3,2,4}}; /*hai chiều*/


Mảng hai chiều thực chất là mảng của mảng một chiều, tức chiều hàng là một
mảng mà mỗi phần tử là một tham chiếu đến mảng một chiều khác. Do đó mỗi hàng
của mảng hai chiều không nhất thiết có độ dài (số phần tử) giống nhau.

Kỹ thuật lập trình hướng đối tượng - Bài 2 Trang 21


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Các hàng (mảng một


M chiều)
ảng
các
tham
Hình vẽ 2.7: Minh họa tổ chức mảng hai chiều
Ví dụ sau sẽ tạo một mảng hai chiều 3 hàng, mỗi hàng có số phần tử khác
nhau,

int a[][] = new int[3][]; /*mảng hai chiều có 3 hàng*/

a[0] = new int[5]; /*hàng 0 có 5 phần tử*/

a[1] = new int[10]; /*hàng 1 có 10 phần tử*/

a[2] = new int[3]; /*hàng 2 có 3 phần tử*/


Với cơ chế quản lý bộ nhớ động nên Java cung cấp hệ thống gom rác (garbage
collection) một cách tự động, tuy nhiên khi cần giải phóng vùng nhớ chúng ta có thể
thực hiện trực tiếp bằng hai bước sau:

Bước 1: Đặt các tham chiếu về giá trị null

Bước 2: Sử dụng lệnh System.gc(); để giải phóng bộ nhớ

5. Một số xử lý cơ bản khác


5.1. Xử lý dữ liệu ngày tháng- Date
Kiểu dữ liệu “Date” dùng để xử lý ngày tháng và thời gian, các thành phần cơ
bản của “Date” gồm:

Lệnh Ý nghĩa

Date( ms ) Tạo đối tượng theo số mili giây

Date( d, m, y ) Tạo đối tượng theo ngày, tháng,


năm

.after( d ) Kiểm tra sau ngày khác

.before( d ) Kiểm tra trước ngày khác

Kỹ thuật lập trình hướng đối tượng - Bài 2 Trang 22


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

.equals( d ) So sánh 2 ngày bằng nhau

.getDay(), getMonth(), Lấy ngày, tháng, năm


getYear()

.getHours(), Lấy giờ, phút, giây


getMinutes(), getSeconds()
Ví dụ sau sẽ tạo đối tượng kiểu Date theo thời gian hiện tại của máy và hiện kết
quả ra màn hình,

Date d = new Date(System.currentTimeMillis());

System.out.printf("Hien tai la %1$tH:%1$tM:%1$tS - ngay %1$td/%1$tm/%1$tY", d);

có kết quả như sau,

5.2. Xử lý xâu ký tự - String


Java cung cấp kiểu dữ liệu “String” để lưu và xử lý xâu ký tự, nó là một lớp đối
tượng. Tuy nhiên chúng ta có một số phép toán trực tiếp như:
- Phép gán (=)

String s = “Hà nội - Việt nam”;


- Phép nối xâu (+)

String s = “Hạ Long” + “:” + “Quảng Ninh”;


thậm chí nối các dữ liệu số (kết quả biểu thức) tạo thành xâu,

String s = “Kết quả:” + 2012/3.0;


Các hàm (phương thức) trên kiểu String gồm:

Lệnh Ý nghĩa

.length() Lấy độ dài (số ký tự) của xâu

Kỹ thuật lập trình hướng đối tượng - Bài 2 Trang 23


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

.trim() Cắt bỏ khoảng cách ở hai đầu xâu

.charAt( i ) Lấy ký tự thứ i trong xâu (bắt đầu từ 0)

.substring( i , j ) Lấy xâu con từ i đến j-1 trong xâu

.equals( s ) So sánh bằng với xâu ký tự khác

.startsWith( s ) Kiểm tra có là đoạn con bắt đầu của xâu

.endsWith( s ) Kiểm tra có là đoạn con kết thúc của xâu

.replaceAll ( s, t ) Thay thế đoạn con t cho s trong xâu

.getBytes() Chuyển xâu về mảng byte

.indexOf( s ) Cho biết vị trí xuất hiện đầu của đoạn con
s

.lastIndexOf( s ) Cho biết vị trí xuất hiện cuối của đoạn


con s

.toLowerCase() Chuyển xâu ký tự về dạng chữ thường

.toUpperCase() Chuyển xâu ký tự lên dạng chữ hoa

.compareTo( s ) So sánh với một ký tự khác, trả về >0, <0


nếu nó lớn hơn, nhỏ hơn xâu s theo thứ
tự từ điển

String.format( F, D ) Chuyển dữ liệu theo định dạng về xâu


Trong đó lệnh “format” có tham số “F” quy định các định dạng chuyển dữ liệu
“D” về chuỗi, hai tham số này giống như trong lệnh “printf” đã đề cập ở phần trên.
Ví dụ sau sẽ chuyển dữ liệu thời gian hiện tại của máy có kiểu “Date” về dạng
chuỗi “dd/mm/yyyy”,

Date a = new Date(System.currentTimeMillis());

String s = String.format(“ %1$td / %1$tm / %1$tY ”, a);

Kỹ thuật lập trình hướng đối tượng - Bài 2 Trang 24


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Ngoài ra, Java cung cấp lớp “Character” để làm việc xử lý trên dữ liệu ký tự
gồm một số lệnh cơ bản sau,

Character.isDigit( ký_tự );

Character.isLetter( ký_tự );

Character.toUpperCase( ký_tự );

Character.toLowerCase( ký_tự );
tương ứng để kiểm tra ký tự có là chữ số (Digit) hay chữ cái (Letter) không, để
chuyển ký tự về dạng chữ hoa (UpperCase), chữ thường (LowerCase).
5.3. Xử lý số ngẫu nhiên - Random
Java cung cấp lớp đối tượng “Random” để xác định số ngẫu nhiên, cách dùng
như sau:

/*Bước 1: Tạo đối tượng Random*/

Random a = new Random();

/*Bước 2: Dùng lệnh để lấy số ngẫu nhiên*/

a.nextInt(); /*lấy số nguyên*/

a.nextInt( g ); /*lấy số nguyên từ 0 đến g-1*/

a.nextFloat(); /*lấy số thực từ 0 đến 1*/


Ví dụ sau sẽ lấy một mảng 2 chiều các số 0,1 ngẫu nhiên sau đó hiện ra màn
hình kết quả lấy được,

Random d = new Random();

int a[][] = new int[1+d.nextInt(20)][1+d.nextInt(20)];

for(int i=0;i<a.length;i++)

for(int j=0;j<a[i].length;j++) a[i][j] = d.nextInt(2);

System.out.print("Mang ngau nhien vua lay la");

for(int i=0;i<a.length;i++){

Kỹ thuật lập trình hướng đối tượng - Bài 2 Trang 25


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

System.out.println();

for(int j=0;j<a[i].length;j++)

System.out.printf("%3d", a[i][j]);

}
sẽ có kết quả một lần chạy như sau:

5.4. Tính toán toán học - Math


Java cung cấp lớp xử lý các phép toán học cơ bản, chúng được sử dụng dưới
dạng trực tiếp trên (theo cơ chế “static” sẽ trình bày sau) gồm các lệnh sau:

Lệnh Ý nghĩa

Math.sqrt(x) Tính căn bậc hai

Math.pow(x,y) Tính lũy thừa xy

Math.sin( x ), cos, asin, Tính lượng giác sin, cos, asin, acos...
acos,...

Math.abs( x ) Tính giá trị tuyệt đối

Math.exp( x ) Tính lũy thừa cơ số E

Math.log( x ) Tính logarit tự nhiên

Math.min( x, y ), max Tính min, max

Math.round( x ) Làm tròn số

Math.ceil( x ) Lấy số nguyên cận trên

Kỹ thuật lập trình hướng đối tượng - Bài 2 Trang 26


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Math.floor( x ) Lấy số nguyên cận dưới

Math.PI, E Lấy số PI, cơ số E

Ví dụ sau sẽ nhập tọa độ x,y của một điểm trên mặt phẳng, tính khoảng cách từ
điểm đó đến gốc tọa độ hiện ra màn hình và lấy cận trên, dưới của nó.

float x,y; double kc;

Scanner n = new Scanner(System.in);

System.out.print("Nhap toa do x,y:");

x=n.nextFloat(); y=n.nextFloat();

kc = Math.sqrt(Math.pow(x, 2)+Math.pow(y,2));

System.out.printf("Khoang cach:%.6f, can tren:%d, duoi:%d",

kc, (int)Math.ceil(kc), (int)Math.floor(kc));


kết quả trên màn hình sẽ là:

5.5. Chuyển đổi dữ liệu


Thông thường trong quá trình xử lý nhu cầu chuyển đổi kiểu dữ liệu là khá cần
thiết, chẳng hạn ta có dữ liệu số thực kiểu “double” nhưng giá trị của nó lại chỉ là số
nguyên (kiểu “int”) và để thực hiện phép chia dư chắc chắn cần phải chuyển kiểu từ
“double” sang “int”. Trường hợp này chúng ta sử dụng cơ chế ép kiểu theo cú pháp:

(kiểu_mới)dữ_liệu_kiểu_cũ
Ví dụ:

double x = Math.sqrt(16);

int a = (int)x;
sẽ ép kiểu “double” của giá trị trong biến “x” thành giá trị kiểu “int”.

Kỹ thuật lập trình hướng đối tượng - Bài 2 Trang 27


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Chú ý việc chuyển dữ liệu bằng có chế ép kiểu này có thể bị mất thông tin,
chẳng hạn có số thực 12.45 ép sang kiểu nguyên sẽ bị mất phần lẻ thập phân là 0.45.
Trong trường hợp muốn chuyển dữ liệu xâu ký tự dạng số về giá trị số thì áp
dụng các lệnh của lớp gói kiểu dữ liệu cơ bản, cụ thể:

Integer.parseInt( xâu_số_nguyên );

Float.parseFloat( xâu_số_thực );

Double.parseDouble( xâu_số_thực );...


Chúng ta có lệnh chuyển các dữ liệu về dạng xâu theo định dạng bằng lệnh,

String.format( F , D );
như đã trình bày ở phần trên.
Ngoài ra, để chuyển dữ liệu dạng xâu về dạng ngày (kiểu lớp Date) chúng ta sử
dụng đối tượng lớp “SimpleDateFormat” và thực hiện lệnh “parse” trên đối tượng
đó. Cụ thể các bước như sau,

/*Bước 1: Tạo đối tượng SimpleDateFormat*/

SimpleDateFormat =new SimpleDateFormat(“định-dạng”);

/*Bước 2: Sử dụng lệnh parse để chuyển*/

Date  = .parse(“dữ-liệu-ngày”);
Trong đó, chuỗi “định-dạng” gồm các ký tự quy định các thành phần của dữ
liệu ngày gồm:

Ký hiệu Ý nghĩa Biểu diễn Ví dụ

d Ngày trong tháng Số 1-31

M Tháng trong năm Số 1-12

y Năm Số 2012

H Giờ trong ngày Số 0-23

m Phút trong một giờ Số 0-59

Kỹ thuật lập trình hướng đối tượng - Bài 2 Trang 28


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

s Giây trong một phút Số 0-59


và xâu cần chuyển về dữ liệu ngày trong lệnh “parse” phải phù hợp với định
dạng đã được tạo. Ví dụ (sử dụng gộp 2 bước ở trên),

Date d = new SimpleDateFormat("d-M-y").parse("10-8-2012");

System.out.printf("\nDate: %1$td/%1$tm/%1$tY", d);

System.out.printf("\nTime: %1$tH:%1$tM:%1$tS", d);


sẽ chuyển xâu ký tự “10-8-2012” về dạng ngày, sau đó in ra màn hình thông tin
ngày/tháng/năm và giờ:phút:giây.
5.6. Xử lý ngoại lệ - Exception
Ngoại lệ (Exception) là các lỗi phát sinh trong khi chạy chương trình. Theo
cách truyền thống, chúng ta dùng các giá trị trạng thái kết quả xử lý hoặc các biến
toàn cục, khi đó người lập trình kiểm soát bằng cách kiểm tra các giá trị này để biết
có lỗi hay không và xử lý tương ứng. Tuy nhiên hiện nay, các ngôn ngữ lập trình
hiện đại cung cấp cơ chế xử lý các lỗi thuận tiện và đồng bộ hơn đó là cơ chế ngoại
lệ.
Các ngoại lệ được chia làm nhiều loại theo nhóm lỗi tương ứng gồm:

Ngoại lệ Các lỗi tương ứng

Exception Bao hàm tất cả các lỗi

IOException Lỗi vào/ra dữ liệu

NumberFormatException Lỗi định dạng dữ liệu số

OutOfMemoryException Lỗi tràn bộ nhớ

NullPointerException Lỗi tham chiếu có giá trị null

IllegalArgumentException Lỗi sai tham số truyền cho hàm

ArithmeticException Lỗi tính toán toán học

ArrayIndexOutOfBoundsException Lỗi xử lý mảng ngoài chỉ số,...

Kỹ thuật lập trình hướng đối tượng - Bài 2 Trang 29


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Thông thường để đơn giản chúng ta dùng Exception để bao hàm tất cả các lỗi
nếu có. Sử dụng cú pháp sau để xử lý lỗi phát sinh trong chương trình.

try{

/*Đoạn mã chương trình cần kiểm tra lỗi*/

}catch(ExceptionType1 e1){

/* Xử lý lỗi thứ 1*/

}catch(ExceptionType2 e2){

/* Xử lý lỗi thứ 2*/

}catch(ExceptionType3 e3){

/*Xử lý lỗi thứ 3*/

}...

finally{

/*Xử lý cuối cùng*/

}
Trong đó phần “catch” cần tối thiểu là một lỗi cho khối “try” và có thể bỏ qua
“finally”. Đoạn mã chương trình cần kiểm tra lỗi có thể do chúng ta mong muốn vì
sợ rằng khi chạy có thể sinh lỗi, tuy nhiên một số lệnh trong Java khi chạy nếu có
lỗi sẽ chủ động phát sinh và bắt buộc chúng ta xử lý như trên. “ExceptionType”
trong “catch” là một trong các kiểu ngoại lệ tương ứng với lỗi cần kiểm tra xử lý
trong bảng trên.
Khi máy tính thực hiện đoạn chương trình theo cú pháp trên, trước hết sẽ thực
thi đoạn mã nằm trong khối “try”. Nếu phát sinh lỗi ngay lập tức tìm kiếm lỗi đó có
nằm trong danh sách kiểu lỗi trong các khối “catch”, nếu tìm thấy ở đâu sẽ xử lý
bằng cách chạy đoạn mã tương ứng. Ngược lại, nếu không tìm thấy sẽ ngắt chương
trình và đưa ra màn hình Console thông báo lỗi. Khối “finally” luôn luôn được thực
hiện cho dù đoạn mã trong khối “try” có chạy thành công hay không.
Như vậy nếu không bắt hết các kiểu ngoại lệ thì nguy cơ chương trình bị ngắt
trong quá trình thực là có thực. Để đơn giản, chúng ta sử dụng kiểu “Exception” để
bao hàm hầu hết các lỗi và xử lý trong chương trình. Ví dụ sau sẽ nhập một chuỗi

Kỹ thuật lập trình hướng đối tượng - Bài 2 Trang 30


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

ký tự, và chuyển nó thành số nguyên (nếu được) đưa ra thông báo kết quả. Nếu
không sẽ đưa ra thông báo lỗi và tiếp tục chạy chương trình.

try{

Scanner n = new Scanner(System.in);

System.out.print("Nhap xau ky tu: ");

String s = n.nextLine();

int a = Integer.parseInt(s);

System.out.printf("\nKET QUA CHUYEN: %d\n",a);

}catch(Exception e){

System.out.print("\nWRONG NUMBER\n");

}finally{

System.out.print("\nFINALLY\n");

System.out.print("\nCONTINUE\n");
Kết quả chạy chương trình trong cả 2 trường hợp nhập đúng và không đúng số
nguyên.


Tuy nhiên nếu chúng ta sử dụng kiểu ngoại lệ không phù hợp và máy không
tìm thấy thì chương trình sẽ bị ngắt, chẳng hạn đổi kiểu ngoại lệ trong khối “catch”
của ví dụ trên thành “IllegalStateException” sẽ cho kết quả khi nhập sai là,

Kỹ thuật lập trình hướng đối tượng - Bài 2 Trang 31


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

và sẽ không chạy tiếp các lệnh sau khối “try-catch-finally”, chương trình bị
ngắt giữa chừng.
Trường hợp chúng ta muốn kiểm soát lỗi nhưng không sử dụng khối “try-
catch-finally” sẽ thay thế bằng việc sử dụng mệnh đề “throws” ngay sau tên phương
thức (hàm) chứa khối lệnh này. Ví dụ như sau:

void Test() throws Exception{

Scanner n = new Scanner(System.in);

System.out.print("Nhap xau ky tu: ");

String s = n.nextLine();

int a = Integer.parseInt(s);

System.out.printf("\nKET QUA CHUYEN: %d\n",a);

}
Như vậy tại nơi gọi hàm “Test” này sẽ phải thực hiện xử lý ngoại lệ bằng cú
pháp “try-catch-finally” như trên hoặc tiếp tục áp dụng mệnh đề “throws” như
trên... Nếu quá trình áp dụng mệnh đề “throws” ở tất cả các phương thức (hàm) thì
cuối cùng các ngoại lệ sẽ đưa đến hàm “main” của chương trình.
Tuy nhiên, khi áp dụng mệnh đề “throws” thì máy sẽ ngắt quá trình thực hiện
của phương thức tương ứng nếu gặp lỗi, tức là toàn bộ nội dung của phương thức
được coi như là đoạn mã cần kiểm tra xử lý lỗi (nằm trong khối “try”), cho dù
chúng ta mong muốn phương thức đó vẫn được tiếp tục chạy và bỏ qua lỗi.

Kỹ thuật lập trình hướng đối tượng - Bài 2 Trang 32


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

BÀI 3: LẬP TRÌNH LỚP VÀ ĐỐI TƯỢNG

Mục tiêu:
Trong bài này, Anh/Chị cần đạt được những mục tiêu sau:
1. Phân tích các đối tượng và thiết kế lớp.
2. Cài đặt lập trình lớp – class.
3. Lập trình đối tượng – object.
Nội dung:

1. Phân tích các đối tượng và thiết kế lớp


Chúng ta có thể xem lớp như một khuôn mẫu (template) của đối tượng
(Object). Trong đó bao gồm dữ liệu của đối tượng (thuộc tính - properties) và các
hàm thành viên (phương thức - methods) tác động lên thành phần dữ liệu đó. Các
đối tượng được xây dựng bởi các lớp nên được gọi là các thể hiện của lớp (class
instance).
Trong hầu hết các lớp, các biến thể hiện được truy cập bởi các phương thức
định nghĩa trong lớp đó. Vì vậy, chính các phương thức quyết định dữ liệu của lớp
có thể dùng như thế nào. Lớp định nghĩa một kiểu dữ liệu mới, dùng để tạo các đối
tượng thuộc kiểu lớp đó, mỗi đối tượng có vùng nhớ riêng.
Chúng ta đã biết Lập trình hướng đối tượng (Object Oriented Programming -
OOP) là một trong những tiếp cận mạnh mẽ, và rất hiệu quả để xây dựng nên những
chương trình ứng dụng trên máy tính. Từ khi ra đời cho đến nay lập trình OOP đã
chứng tỏ được sức mạnh, vai trò của nó trong các đề án tin học. Chương này sẽ giúp
bạn đọc tìm hiểu về các vấn đề cơ bản về lập trình hướng đối tượng trong java
thông qua việc tạo lập các lớp, các đối tượng và các tính chất của chúng.
Minh họa giữa lớp và đối tượng như sau:

Lớp(class)

Đối Đối Đối

Kỹ thuật lập trình hướng đối tượng - Bài 3 Trang 1


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Một lớp sau khi được định nghĩa, chúng ta có thể tạo ra nhiều đối tượng và xử
lý trên các đối tượng đó thực hiện yêu cầu đặt ra. Đối tượng là cái tồn tại có thật
trên máy, chiếm một dung lượng bộ nhớ nhất định của máy tính, còn lớp chỉ tồn tại
ở mức khái niệm.
Lớp không thay đổi, trong khi dữ liệu chứa trong một đối tượng có thể thay đổi.
Các thuộc tính của lớp được thiết lập trong suốt thời gian chay chương trình, không
thể thêm bớt thuộc tính trong lúc chương trình đang chạy. Khi một đối tượng được
tạo từ một lớp, nó sẽ là một thành phần của lớp đó cho đến khi bị huỷ bỏ. Sự tồn tại
của đối tượng có hạn chế, đối tượng sẽ được tạo ra và hủy bỏ theo đúng trình tự.
1.1. Phân tích đối tượng, thuộc tính và phương thức cho đối tượng (từ các thực
thể dữ liệu hoặc từ bản mô tả)
Khi phân tích và phát triển một hệ thống phần mềm hướng đối tượng, chúng ta
thường thực hiện theo các bước sau:
 Phân tích yêu cầu (Requirement analysis)
 Phân tích (Analysis)
 Thiết kế (Design)
 Lập trình (Programming)
 Kiểm tra (Testing)
Phân tích yêu cầu: Việc tìm hiểu các trường hợp sử dụng (use case) để nắm
bắt các yêu cầu của người sử dụng (khách hàng), của vấn đề cần giải quyết. Qua
trường hợp sử dụng này, các nhân tố bên ngoài có tham gia vào hệ thống cũng được
mô hình hóa bằng các tác nhân. Mỗi trường hợp sử dụng được mô tả bằng văn bản,
đặc tả yêu cầu của khách hàng.
Phân tích: Từ các đặc tả yêu cầu trên, hệ thống sẽ bước đầu được mô hình hóa
bởi các khái niệm lớp, đối tượng và các cơ chế để diễn tả hoạt động của hệ thống.
Trong giai đoạn phân tích chúng ta chỉ mô tả các lớp trong lĩnh vực của vấn đề cần
giải quyết chứ chúng ta không đi sâu vào các chi tiết kỹ thuật.
Thiết kế: Trong giai đoạn thiết kế, các kết quả của quá trình phân tích được mở
rộng thành một giải pháp kỹ thuật. Một số các lớp được thêm vào để cung cấp cơ sở
hạ tầng kỹ thuật như lớp giao diện, lớp cơ sở dữ liệu, lớp chức năng, …
Lập trình: Đây còn gọi là bước xây dựng, giai đoạn này sẽ đặc tả chi tiết kết
quả của giai đoạn thiết kế. Các lớp của bước thiết kế sẽ được chuyển thành mã
nguồn theo một ngôn ngữ lập trình theo hướng đối tượng nào đó.

Kỹ thuật lập trình hướng đối tượng - Bài 3 Trang 2


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Kiểm tra: Kiểm tra sự hoạt động, tương tác giữa các đối tượng, sự đáp ứng các
chức năng người dùng yêu cầu,…
Để hiểu được kỹ thuật lập trình hướng đối tượng, trước hết chúng ta cần nắm
vững khái niệm đối tượng. Bạn có thể nhìn xung quanh và thấy được nhiều đối
tượng trong thế giới thực như: cái bàn, quyển vở, cây viết, tivi, xe hơi, con gà,...
Trong một hệ thống hướng đối tượng, mọi thứ đều là đối tượng. Cụ thể, khi sử dụng
máy tính, ta thường nhìn thấy rất nhiều đối tượng như: một bảng tính, một ô trong
bảng tính, một biểu đồ, một bảng báo cáo, một con số hay một số điện thoại, một
tập tin, một thư mục, một máy in, một câu hoặc một từ, thậm chí một ký tự, tất cả
chúng là những ví dụ của một đối tượng. Rõ ràng chúng ta viết một chương trình
hướng đối tượng cũng có nghĩa là chúng ta đang xây dựng một mô hình của một vài
bộ phận trong thế giới thực. Tuy nhiên các đối tượng này có thể được biểu diễn hay
mô hình trên máy tính.
Một đối tượng thế giới thực là một thực thể cụ thể mà thông thường bạn có thể
sờ, nhìn thấy hay cảm nhận được. Tất cả các đối tượng trong thế giới thực đều có
thuộc tính (property) và hành động (behaviour). Tuy nhiên, việc lưu trữ và xử lý các
đối tượng của thế giới thực trên máy tính cần được thay đổi chút ít cho phù hợp
(biểu diễn – mô hình hóa) các đối tượng thế giới thực bằng các đối tượng phần
mềm). Ví dụ, với đối tượng “Xe máy”, chúng ta có thể mô hình hóa bằng đối tượng
phần mềm như sau:
Thuộc tính Hành động
 Khởi động
 Nhãn hiệu
 Di chuyển
 Kiểu dáng
 Chuyển số
 Màu sắc
Xe máy  Phanh
 Dung tích xi lanh
 Nhập thông tin
 Năm sản xuất
 Sửa màu sắc
 Giá thành
 Sửa giá thành
Xét một cách đặc biệt, chỉ một đối tượng riêng rẽ thì chính nó không hữu dụng.
Một chương trình hướng đối tượng thường gồm có hai hay nhiều hơn các đối tượng
phần mềm tương tác lẫn nhau như là sự tương tác của các đối tượng trong trong thế
giới thực.
1.2. Phân tích tương tác giữa các đối tượng (message)
Khi muốn một hành động cụ thể nào đó của đối tượng được thực hiện, ta gửi
một thông điệp (message) tới đối tượng, thông điệp này định nghĩa hoạt động của
đối tượng.

Kỹ thuật lập trình hướng đối tượng - Bài 3 Trang 3


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Khi một đối tượng nhận được một thông điệp, nó thực hiện một phương thức
tương ứng. Ví dụ, một đối tượng được tạo từ lớp “Xe máy” trên, muốn nhập thông
tin chi tiết cho các thuộc tính của một thể hiện cụ thể của lớp xe máy, ta gửi tới đối
tượng thông điệp. Khi đối tượng nhận được thông điệp, nó sẽ tìm và thực thi
phương thức “Nhập thông tin”.
Trong trường hợp giữa 2 đối tượng muốn tương tác với nhau, các đối tượng này
cần gửi các thông điệp cho nhau. Ví dụ, đối tượng “khách hàng” muốn biết thông
tin về giá thành của một đối tượng xe máy cụ thể sẽ gửi yêu cầu (thông điệp), và
khách hàng cũng sẽ nhận được thông tin về giá cả thông qua một thông điệp được
gửi lại từ đối tượng “Xe máy”.

K G 4 X
hách e máy
hàng

Đôi khi đối tượng nhận cần thông tin nhiều hơn để biết chính xác thực hiện
công việc gì. Ví dụ khi cần sửa đổi màu sơn của một đối tượng xe máy cụ thể thì
ngoài việc gửi thông điệp yêu cầu sửa, chúng ta phải chỉ rõ mầu sơn mới, thông tin
này được truyền đi kèm theo thông điệp và được gọi là các tham số (parameters).
1.3. Thiết kế các lớp đối tượng
Một lớp là một mô hình khái niệm về một thực thể. Nó mang tính cách tổng
quát chứ không mang tính cách đặc thù.
Khi định nghĩa một lớp, chúng ta muốn phát biểu rằng một lớp sẽ phải có một
tập hợp các thuộc tính và các hành động riêng. Chẳng hạn như một định nghĩa lớp
“Con người” dưới đây:

Con người
Họ tên
Ngày sinh
Chiều cao
Đi
Đứng
Nói

Lớp này định nghĩa thực thể ‘Con người’. Mọi thực thể thuộc kiểu ‘Con người’
sẽ đều có những đặc tính và những hành động như đã được định nghĩa.
Một khi một lớp đã được định nghĩa, chúng ta biết được những thuộc tính và
những hành động của những thực thể ‘trông giống’ như lớp này. Vì thế, một lớp,
bản chất của nó là một nguyên mẫu (prototype).

Kỹ thuật lập trình hướng đối tượng - Bài 3 Trang 4


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

2. Cài đặt lập trình lớp - class


2.1. Quy tắc lập trình lớp trong Java. Thành viên dữ liệu và hàm.
a) Khai báo và định nghĩa lớp
Một lớp được định nghĩa theo cú pháp sau:
[public] [final] [abstract] class <tên_lớp>
{
// khai báo các thuộc tính của lớp
kiểu_dữ_liệu <tên_biến>;
// khai báo các phương thức của lớp
kiểu_dữ_liệu <tên_hàm(kiểu_dữ_liệu
tên_biến_tham_số)>
{ //Các lệnh trong thân phương thức.
}
}
Chú ý: Các thành phần trong cặp ngoặc vuông [] là thành phần tùy chọn.Các
thành phần trong cặp ngoặc nhọn <> là thành phần bắt buộc người dùng tự đặt tên
theo qui tắc đặt tên biến. Một lớp luôn tồn tại cặp ngoặc móc {} để xác định phần
bắt đầu và kết thúc của khai báo lớp.
Ví dụ 3.2.1: Định nghĩa lớp hình tròn với các thuộc tính: tọa độ tâm (x,y), bán
kính (bk) và phương thức tính diện tích.
public class HINHTRON
{
// khai báo các thuộc tính của lớp
private float bk;
private int x,y;
// khai báo các phương thức của lớp
public float dt()
{ return bk*bk*3.14;
}
}
Một số chú ý:
 Mặc định, một lớp chỉ có thể được sử dụng bởi một lớp khác trong cùng
một gói với lớp đó, nếu muốn gói khác có thể sử dụng được lớp này thì
ta phải khai báo lớp với từ khóa public.

Kỹ thuật lập trình hướng đối tượng - Bài 3 Trang 5


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

 Nếu có từ khóa abstract, chương trình dịch java biết đây là một lớp trừu
tượng, ta không thể tạo ra một thể hiện của lớp này.
 Nếu có từ khóa final, chương trình dịch java biết đây là một lớp hằng,
không thể kế thừa.
 Từ khóa class báo cho chương trình biết ta đang định nghĩa lớp.
 Từ khóa extends xác định lớp ta đang định nghĩa kế thừa từ lớp nào.
 implements là từ khoá cho java biết lớp này sẽ triển khai giao diện
interface, đây là một dạng tương tự như kế thừa bội của java.

b) Khai báo thuộc tính


Thuộc tính (properties) của lớp được khai báo bên trong lớp như sau:
class <ClassName>
{
// khai báo những thuộc tính của lớp
<Phạm vi truy nhập> <kiểu dữ liệu> tên_biến;
//…
}
Thuộc tính của lớp là một biến có kiểu dữ liệu bất kỳ, nó có thể lại là một biến
có kiểu là chính lớp đó.
Khi khai báo các thành phần của lớp (thuộc tính và phương thức) có thể dùng
một trong các từ khóa private, public, protected để giới hạn sự truy nhập đến thành
phần đó:
 Các thành phần private chỉ có thể được truy nhập từ bên trong thân các
phương thức của lớp đó.
 Các thành phần protected cũng giống với private nhưng có thể truy nhập
từ bất cứ lớp con nào kế thừa từ nó.
 Các thành phần public có thể được truy nhập từ bên trong lẫn bên ngoài
lớp.
Nếu một thành phần của lớp khi khai báo mà không sử dụng một trong ba từ
khóa private, public hoặc protected thì sự truy nhập là bạn bè, tức là thành phần này
có thể được truy nhập từ bất cứ lớp nào trong cùng gói với lớp đó. Như vậy, các
thành phần mặc định sẽ có phạm vi nhìn thấy được rộng hơn các thành phần
private, nhưng hẹp hơn các thành phần protected.

Kỹ thuật lập trình hướng đối tượng - Bài 3 Trang 6


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

 Chú ý: Ta phải phân biệt được việc khai báo như thế nào là khai báo thuộc tính,
khai báo như thế nào là khai báo biến thông thường? Câu trả lời là tất cả các khai
báo bên trong thân của một lớp và bên ngoài tất cả các phương thức (bao gồm cả
hàm tạo) là khai báo thuộc tính, các khai báo ở những nơi khác là khai báo biến.
Có thể minh họa cơ chế phạm vi của các thành viên qua sơ đồ sau:

Tệp chương trình


(*.java)
priv Lớp
ate A

prot
ected

publ
ic

Hình 3.2.1: Mô hình cơ chế phạm vi các thành viên


Như vậy qua minh họa chúng ta thấy các thành viên private chỉ được sử dụng
bên trong lớp, các thành viên protected được sử dụng bên trong và ngoài lớp nhưng
chỉ bên trong tệp chương trình, còn public có thể dùng cả bên trong và bên ngoài
lớp, ngoài tệp chương trình.
c) Khai báo và định nghĩa phương thức
Cú pháp chung để định nghĩa một hàm:
[<Phạm vi truy nhập>]<Kiểu trả về> <Tên hàm >
([<Danh sách tham biến hình thức>]) [<Mệnh đề
throws>]
{
//Các lệnh trong thân phương thức
}
Trong đó:
 <Kiểu trả về> có thể là kiểu nguyên thủy, kiểu lớp hoặc không có giá trị
trả lại (kiểu void).

Kỹ thuật lập trình hướng đối tượng - Bài 3 Trang 7


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

 <Danh sách tham biến hình thức> bao gồm dãy các tham biến (kiểu và
tên) phân cách với nhau bởi dấu phẩy.
 <Phạm vi truy nhập> chỉ tính chất của phương thức, có thể có các từ
khóa thể hiện như sau: public, protected, private, mặc định (không chỉ rõ
tính chất nào), static, abstract, final, native, synchoronized.
 <Mệnh đề throws>: là một đối tượng đặc biệt được tạo ra khi chương
trình gặp lỗi. Java sẽ trả lại cho chương trình ngoại lệ này theo từ khóa
throws. Các ngoại lệ, nếu có, được phân cách nhau bởi dấu phẩy.
Các tính chất public, protected, private, static, final và mặc định (không chỉ rõ
phạm vi) của hàm tương tự như đối với thuộc tính chứa dữ liệu của lớp. Còn các
tính chất abstract, synchronized và native được sử dụng với các ý nghĩa như sau:
 Các hàm abstract
Hàm thành phần khai báo trừu tượng (abstract) có dạng:
abstract <Kiểu trả về> <Tên hàm>([<Danh sách tham
biến>])[<Mệnh đề
throws>];
Hàm abstract là hàm prototype, chỉ khai báo phần định danh hàm mà không
định nghĩa nội dung thực hiện, do vậy nó là hàm không đầy đủ. Hàm abstract
thường chỉ tổ chức cho các lớp abstract và nó phải được cài đặt nội dung thực hiện
ở trong các lớp con cháu của lớp chứa hàm đó.
Lưu ý:
- Hàm final không thể khai báo abstract và ngược lại.
- Các hàm trong interface đều là các hàm abstract.
 Các hàm synchronized
Java hỗ trợ chương trình thực hiện đa luồng (multi threads). Có thể có nhiều
luồng muốn thực hiện đồng thời trên một đối tượng nào đó. Có những loại thiết bị,
ví dụ như máy in, kênh truyền chẳng hạn, đòi hỏi phải có cơ chế để chỉ một luồng
được thực hiện, nghĩa là phải thực hiện đồng bộ. Tại mỗi thời điểm, chỉ một luồng
(tiến trình) được khai báo đồng bộ synchronized được thực hiện trên đối tượng chỉ
định.
 Các hàm native
Hàm khai báo native được gọi là hàm ngoại. Nội dung thực hiện của hàm
native không được định nghĩa trong Java mà định nghĩa ở những ngôn ngữ lập trình

Kỹ thuật lập trình hướng đối tượng - Bài 3 Trang 8


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

khác như C/C++. Những hàm native chỉ cần khai báo prototype như là các thành
phần của lớp.
JNI (Java Native Interface) là một loại API (Abstract Programming Interface)
cho phép các hàm của Java gọi tới hàm ngoại được cài đặt trong C.
 Chú ý:
o Nếu trong lớp có ít nhất một phương thức trừu tượng thì lớp đó phải là lớp
trừu tượng.
o Không có thuộc tính trừu tượng.
o Ta không thể tạo đối tượng của lớp trừu tượng.
o Khác với ngôn ngữ C++, các phương thức của lớp trong java yêu cầu người
dùng bắt buộc phải khai báo giá trị trả về cho phương thức, nếu phương thức
không trả về dữ liệu thì dùng từ khóa void. (Trong ngôn ngữ C++ thì mặc
định phương thức sẽ trả về kiểu int nếu ta không chỉ rõ giá trị trả về)
Thông thường một thành phần của lớp chỉ truy xuất trong sự liên kết với một
đối tượng thuộc lớp của nó. Tuy nhiên, có thể tạo ra một thành phần mà có thể dùng
một độc lập một mình, không cần tham chiếu đến một đối tượng cụ thể, có thể được
truy xuất trước khi bất kỳ đối tượng nào của lớp đó được tạo ra, bằng cách đặt trước
khai báo của nó từ khoá static. Cách truy xuất hàm lớp :
<Tên lớp>.<Tên phương thức>(Danh sách tham số);
Các hàm toán học của lớp Math trong Package Java.Lang là hàm lớp nên khi
gọi không cần phải khởi tạo đối tượng Ví dụ : double a = Math.sqrt(9);
2.2. Tham chiếu this
Tham chiếu this là một tham chiếu ẩn (biến ẩn) đặc biệt luôn tồn tại trong các
lớp của java: một lớp có đúng một biến ẩn this. Biến này được sử dụng khi chạy và
nó trỏ đến bản thân lớp chứa nó. Biến this thường được sử dụng trong các hàm khởi
tạo của lớp.
Nếu biến được định nghĩa trong thân một phương thức, đó là biến địa phương
chỉ tồn tại khi phương thức được gọi. Nếu biến địa phương như vậy được đặt tên
trùng với thuộc tính, nó sẽ che khuất thuộc tính trong thân phương thức.
Ví dụ 3.2.2: tham chiếu this
class ViDu
{ int test = 10;
// Thuộc tính

Kỹ thuật lập trình hướng đối tượng - Bài 3 Trang 9


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

void printTest()
{ int test = 20;
// Biến địa phương
System.out.println(“test = ”+test); // In
biến địa phương
}
public static void main(String args[])
{ ViDu a = new ViDu();
a.printTest();
}
}
Sau câu lệnh a.printTest(); chương trình sẽ in giá trị của biến địa phương test
(kết quả là 20). Nếu muốn in giá trị của thuộc tính test của lớp, ta sử dụng từ khóa
this. Từ khoá this có thể dùng bên trong bất cứ phương thức nào để tham chiếu đến
đối tượng hiện hành, khi biến đối tượng trùng tên với biến địa phương.
Thay dòng lệnh trên:
System.out.println(“test = “ + this.test); // In giá trị thuộc tính test của đối
tượng a
Có thể xem con trỏ this là đối thứ nhất của hàm thành phần. Khi một lời gọi
hàm thành phần được phát ra bởi một đối tượng thì tham số truyền cho con trỏ this
chính là địa chỉ của đối tượng đó.
Trong trường hợp tên tham số của phương thức, tên biến và các tham chiếu
khác trong phương thức lại trùng tên nhau thì trong lớp phải sử dụng tham chiếu
this mới truy xuất được các thuộc tính này.
Ví dụ 3.2.3:
class A
{
int x, y;
public void gan(int x, int y)
{
int x=10, y=20;
this.x=x;
this.y =y;
}
}

Kỹ thuật lập trình hướng đối tượng - Bài 3 Trang 10


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

3. Lập trình đối tượng - object


3.1. Tham chiếu lớp. Thiết lập đối tượng (thể hiện của lớp)
Sau khi định nghĩa một lớp ta có thể xem lớp như là một kiểu dữ liệu, vì vậy ta
có thể khai báo và tạo các biến, mảng đối tượng. Việc khai báo này cũng tương tự
như khai báo các biến, mảng nguyên thủy, với cú pháp như sau:
<Tên lớp> <Tên biến đối tượng>;
<Tên lớp> [Kích thước mảng] <Tên biến mảng>;
Về bản chất mỗi đối tượng trong java là một con trỏ trỏ tới một vừng nhớ, vùng
nhớ này chính là vùng nhớ dùng để lưu trữ các thuộc tính. Vùng nhớ dành cho con
trỏ này được cấp phát trên stack, còn vùng nhớ dành cho các thuộc tính của đối
tượng này được cấp phát trên heap.
Sau đó, để thực sự tạo ra đối tượng và gán địa chỉ của đối tượng cho biến này ta
dùng toán tử new:
<Tên biến đối tượng> = new <Tên lớp>();
3.2. Truy xuất xử lý đối tượng (toán tử chấm “•”)
Khi truy nhập đến các thuộc tính và phương thức từ trong thân các phương thức
của lớp, ta có thể viết trực tiếp tên thuộc tính, phương thức đó (hoặc sử dụng thêm
với tham chiếu this). Tuy nhiên, nếu muốn truy nhập đến các thuộc tính và phương
thức từ tham chiếu đối tượng ta cần chỉ rõ tên đối tượng đi kèm. Mỗi thuộc tính hay
phương thức đều thuộc về một đối tượng, vì vậy không thể viết tên thuộc một cách
riêng rẽ mà bao giờ cũng phải có tên đối tượng đi kèm, giống như cách viết trong
cấu trúc của C/C++ hay bản ghi của PASCAL. Nói cách khác, cách truy xuất thuộc
tính và phương thức của đối tượng như sau:

.
<biến_đối_tượng> <tên_thuộc_tính>
.
<biến đối tượng> tên_phương_thức ([danh sách đối số]);
Ví dụ 3.3.1: Truy xuất đến các thành phần của đối tượng.
import java.io.*;
public class PHANSO
{
private int tu,mau;
public void nhap() throws IOException
{
BufferedReader in=new BufferedReader (new
InputStreamReader(System.in));

Kỹ thuật lập trình hướng đối tượng - Bài 3 Trang 11


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

System.out.print("Nhap tu so = ");
tu =Integer.parseInt(in.readLine());
System.out.print("Nhap mau so = ");
mau =Integer.parseInt(in.readLine());
}
public void hien()
{
System.out.print( tu + "/" + mau);
}
public static void main(final String[] args) throws IOException
{
PHANSO a= new PHANSO();
a.nhap();
a.hien();
}
}

3.3. Xử lý danh sách đối tượng theo mảng


Một lớp (sau khi định nghĩa) có thể xem như một kiểu đối tượng và có thể dùng
để khai báo các biến, mảng đối tượng. Cách khai báo biến, mảng đối tượng cũng
giống như khai báo biến, mảng các kiểu khác (như int, float, cấu trúc, hợp,...), theo
mẫu sau:
Tên_lớp <danh sách biến đối tượng>;
Tên_lớp[] <danh sách mảng> ;
Trong Java, có thể khai báo mảng chứa các phần có bất kỳ kiểu dữ liệu nào, kể
cả kiểu tham chiếu đến đối tượng. Khi một mảng được tạo ra, tham chiếu đến một
lớp, ta nói đó là một mảng các đối tượng.
Các đối tượng được khởi tạo chỉ khi hàm tạo của đối tượng được gọi khi thực
thi chương trình. Sau khi đối tượng được khởi tạo, nó có thể truy nhập thông qua
biến đối tượng.
Ví dụ, với lớp PHANSO đã định nghĩa trên, ta có thể khai báo mảng các đối
tượng phân số theo cú pháp:
int n=3;
PHANSO [] a= new PHANSO[n]; //Khai báo mảng a với 3 phần tử

Kỹ thuật lập trình hướng đối tượng - Bài 3 Trang 12


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Giá trị ngầm định của mỗi phần tử mảng đối tượng là null. Lúc này, mỗi phần
tử của mảng thực chất cũng là một tham chiếu đối tượng lớp phân số, vì thế để khởi
tạo các phân số ta dùng vòng lặp:
int i;
for(i=0;i<n;i++)
a[i]= new PHANSO();
for(i=0;i<n;i++)
a[i].nhap();

Kỹ thuật lập trình hướng đối tượng - Bài 3 Trang 13


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

BÀI 4: CÁC VẤN ĐỀ TRONG LẬP TRÌNH LỚP VÀ ĐỐI TƯỢNG

Mục tiêu:
Trong bài này, Anh/Chị cần đạt được những mục tiêu sau:
1. Các đặc tính static và final.
2. Kỹ thuật nạp chồng (Overloading).
3. Phương thức tạo (constructor).
4. Lớp con (nested class).
Nội dung:

1. Các đặc tính static và final


1.1. Thuộc tính tĩnh (static)
Thuộc tính được khai báo với từ khóa static gọi thuộc tính tĩnh.
Ví dụ:
class nhanvien
{
static int tuoi=30;// đây là thuộc tính tĩnh
int sonamcongtac;// đây là thuộc tính thường
……
}
Các thuộc tính tĩnh được cấp phát một vùng bộ nhớ cố định, trong java bộ
nhớ dành cho các thuộc tính tĩnh chỉ được cấp phát khi lần đầu tiên ta truy cập
đến nó. Sau đây là các đặc điểm của thuộc tính tĩnh:
+ Thành phần tĩnh là chung của cả lớp, nó không là của riêng một đối
tượng nào cả.
+ Để truy xuất đến thuộc tính tĩnh có thể dùng một trong hai cách sau.
 Tên lớp.Tên thuộc tính tĩnh;
 Tên đối tượng.Tên thuộc tính tĩnh;
Cả hai cách truy xuất trên đều có tác dụng như nhau

Kỹ thuật lập trình hướng đối tượng - Bài 4 Trang 1


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

+ Khởi gán giá trị cho thuộc tính tĩnh. Thành phần tĩnh có thể được khởi
gán theo hai cách sau:
 Sử dụng khối khởi đầu tĩnh
 Sử dụng khởi đầu trực tiếp khi khai báo như ví dụ trên
Chú ý: Chúng ta không thể sử dùng hàm tạo để khởi đầu các thuộc tính tĩnh,
bởi vì hàm tạo không phải là phương thức tĩnh
1.2. Phương thức tĩnh (static)
Một phương thức được khai báo là static thì được gọi là phương thức tĩnh

class HOCSINH

static float DTB;// đây là thuộc tính tĩnh

// phương thức tĩnh

static void inhs()

System.out.println ( DTB);

}
Phương thức tĩnh là chung cho cả lớp, nó không lệ thuộc vào một đối tượng cụ
thể nào
+ Lời gọi phương thức tĩnh xuất phát từ:
Tên của lớp: tên lớp.tên phương thức tĩnh(tham số);
Tên của đối tượng: tên đối tượng.tên phương thức
tĩnh(tham số);
+Vì phương thức tĩnh là độc lập với đối tượng do vậy ở bên trong phương thức
tĩnh ta không thể truy cập các thành viên không tĩnh của lớp đó, tức là bên trong
phương thức tĩnh ta chỉ có thể truy cập đến các thành viên tĩnh mà thôi.
+ Ta không thể sử dụng từ khóa this bên trong phương thức tĩnh.
1.3. Đặc tính final

Kỹ thuật lập trình hướng đối tượng - Bài 4 Trang 2


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Trong java từ khoá final có nhiều nghĩa khác nhau, nghĩa của nó tùy thuộc
vào ngữ cảnh cụ thể, nhưng nói chung là cái này không thể thay đổi được.
+ Thuộc tính final
Trong java nếu một thuộc tính có từ khóa final đứng trước thì thuộc tính
đó là hằng.
Ví dụ:

public class PT

{ // dinh nghia hang co value bang 20

static final int value = 20;

public static void main ( String arg[] )

{ PT thu = new PT ();

System.out.println("value= " +thu.value);

}
Chú ý:
 Khi khai báo một thuộc tính là final thì thuộc tính này là hằng, do vậy ta
không thể thay đổi giá trị của nó.
 Khi khai báo một thuộc tính final thì phải cung cấp giá trị khởi tạo cho nó.
 Nếu một thuộc tính vừa là final và static như ví dụ trên thì nó chỉ có một
vùng nhớ duy nhất cho cả lớp.
+ Phương thức final
Một phương thức bình thường có thể bị ghi đè ở lớp dẫn xuất, nếu không muốn
ghi đè ở lớp dẫn xuất thì chúng ta dùng từ khoá final trước phương thức đó
+ Lớp final
Nếu lớp là final thì có nghĩa là sẽ không có lớp kế thừa từ lớp này
Chú ý:
Nếu một lớp final thì chúng ta không cần thiết khái báo phương thức final trong
lớp này. Vì không có phương thức nào ghi đè phương thức này do đó không có kế
thừa.

Kỹ thuật lập trình hướng đối tượng - Bài 4 Trang 3


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

2. Kỹ thuật nạp chồng (overloading) phương thức


Việc khai báo trong một lớp nhiều phương thức có cùng tên nhưng khác tham
số (khác kiểu dữ liệu, khác số lượng tham số) gọi là khai báo chồng phương thức
(overloading)
Ví dụ:

public class kythuatnapchong

static void print(String s, int i)

System.out.println("String: " + s +", int: " + i);

static void print(int i, String s)

System.out.println("int: " + i +", String: " + s);

public static void main(String[] args)

print("Khoa CNTT-VDHM", 11);

print(99, "96 DINH CONG");

Kỹ thuật lập trình hướng đối tượng - Bài 4 Trang 4


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Chú ý:
 Khi chúng ta gọi một hàm được nàp chồng. Nếu không tìm thấy hàm thích
hợp thì sẽ thông báo lỗi.
 Ta không thể sử dụng giá trị trả về của hàm để phân biệt sự khác nhau giữa
hai phương thức nạp chồng
 Không nên lạm dụng nhiều phương thức nạp chồng vì trình biên dịch mất
nhiều thời gian dò tìm và phán đoán, đôi khi còn dẫn đến sai sót
 Khi gọi các hàm nạp chồng ta nên có lệnh chuyển kiểu tường mình để trình
biên dịch tìm ra hàm phù hợp một cách nhanh nhất
 Trong java không định nghĩa nạp chồng toán tử như trong ngôn ngữ C++

3. Phương thức tạo (constructor)


3.1. Công dụng
Phương thức tạo dựng là một phương thức đặc biệt, thường dùng để khởi tạo
một đối tượng mới. Thông thường người ta thường sử dụng hàm tạo để khởi gán giá
trị cho các thuộc tính của đối tượng và có thể thực hiện một số công việc cần thiết
khác nhằm chuẩn bị cho đối tượng mới.
3.2. Cách viết hàm tạo
+ Các đặc điểm của hàm tạo:
 Hàm tạo có tên trùng với tên của lớp.
 Hàm tạo không bao giờ trả về kết quả.
 Nó sẽ được gọi tự động khi một đối tượng của lớp được tạo ra.
 Hàm tạo có thể có đối số như các phương thức thông thường khác.
 Trong một lớp có thể có nhiều hàm tạo.
Ví dụ 1: Sử dụng hàm tạo để in ra màn hình xâu “khoa cong nghe thong tin-96 dinh
cong-ha noi”

class Sinhvien

Sinhvien()

// đây là hàm tạo

Kỹ thuật lập trình hướng đối tượng - Bài 4 Trang 5


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

System.out.println("khoa cong nghe thong tin-96 dinh cong-ha noi


");

public class viduhamtao1

public static void main(String[] args)

for(int i = 0; i < 10; i++)

new Sinhvien();// goi ham tao

Ví dụ 2: Sự dụng hàm tạo có đối

class Giaovien

Giaovien(int i)

System.out.println("So thu tu giao vien: " + i);

public class Viduhamtao2

public static void main(String[] args)

Kỹ thuật lập trình hướng đối tượng - Bài 4 Trang 6


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

for(int i = 0; i < 10; i++)

new Giaovien(i);// goi ham tao co doi

3.3. Hàm tạo mặc định


Khi xây dựng một lớp mà không xây dựng hàm tạo thì java sẽ cung cấp cho ta
một hàm tạo không đối mặc định, hàm này thực chất không làm gì cả, nếu trong lớp
đã có ít nhất một hàm tạo thì hàm tạo mặc định sẽ không được tạo ra. Khi ta tạo ra
một đối tượng thì sẽ có một hàm tạo nào đó được gọi, nếu trình biên dịch không tìm
thấy hàm tạo tương ứng nó sẽ thông báo lỗi, điều này thường xảy ra khi chúng ta
không xây dựng hàm tạo không đối nhưng khi tạo dựng đối tượng ta lại không
truyền vào tham số như trong ví dụ dưới đây.

public class Test

{ public Test(String s)

System.out.println(s);

public static void main(String[] args)

{ Test thu = new Test(); // lỗi vì lớp này không có hàm tạo không đối

Test thu1 = new Test("Hello World"); //không báo lỗi

3.4. Nạp chồng hàm tạo


Trong một lớp có thể có nhiều hàm tạo nhưng yêu cầu bắt buộc là các tham số
của mỗi hàm tạo phải khác nhau (khác kiểu dữ liệu, khác số lượng tham số). Sau
đây là ví dụ về nạp chồng hàm tạo trong một lớp.

Kỹ thuật lập trình hướng đối tượng - Bài 4 Trang 7


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

// Ham khoi tao khong tham so

public Time() { this( 0, 0, 0 ); }

// Ham khoi tao mot tham so

public Time( int h ) { this( h, 0, 0 ); }

// Ham khoi tao hai tham so

public Time( int h, int m ) { this( h, m, 0 ); }

// Ham khoi tao ba tham so

public Time( int h, int m, int s ) { setTime( h, m, s ); }

// Ham sao chep

public Time( Time time )

this( time.hour, time.minute, time.second );

// Su dung cac cau tu

Time t1 = new Time(); // 00:00:00

Time t2 = new Time( 2 ); // 02:00:00

Time t3 = new Time( 21, 34 ); // 21:34:00

Time t4 = new Time( 12, 25, 42 ); // 12:25:42

Time t5 = new Time( 27, 74, 99 ); // 00:00:00

Time t6 = new Time( t4 ); // 12:25:42

4. Lớp con (nested class) - Lớp trong lớp (static nested class, inner class)
Có thể định nghĩa một lớp bên trong một lớp khác. Lớp như vậy gọi là lớp lồng
(Nested Class) và được cài đặt như sau :

class NhanVien{ // Lớp bao bên ngoài

Kỹ thuật lập trình hướng đối tượng - Bài 4 Trang 8


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

...

static class CongNhan { // Lớp lồng tĩnh

...

class CanBo { // Lớp lồng phi tĩnh hay lớp nội bộ

...

}
Lớp lồng chỉ được biết bên trong tầm vực của lớp bao bên ngoài. Bộ dịch Java
sẽ báo lỗi nếu một đoạn mã bất kỳ bên ngoài lớp bao cố dùng trực tiếp lớp lồng.
Một lớp lồng có quyền truy cập đến các thành viên của lớp bao bên ngoài, thậm
chí nếu chúng được khai báo private. Tuy nhiên, lớp bao không thể truy xuất các
thành phần của lớp lồng.
Có hai kiểu lớp lồng : tĩnh và phi tĩnh.
Lớp lồng tĩnh (static nested class) được bổ sung từ khoá static. Nó không thể
tham chiếu trực tiếp đến biến hay phương thức đối tượng được định nghĩa trong lớp
bao, mà chỉ dùng chúng thông qua đối tượng. Vì giới hạn này nên lớp lồng tĩnh ít
được dùng. Hầu hết các lớp lồng là lớp nội bộ
Lớp lồng phi tĩnh (nonstatic nested class) không bổ sung từ khoá static, còn
được gọi là lớp nội bộ (inner class). Nó có thể truy cập trực tiếp đến các biến và
phương thức đối tượng của lớp ngoài.
Ví dụ:

class Outer {

int outer_x = 100;

void test()

Inner inner = new Inner();

inner.display_x();

Kỹ thuật lập trình hướng đối tượng - Bài 4 Trang 9


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

class Inner

// có thể truy xuất trực tiếp biến đối tượng của lớp Outer

int inner_y = 10;

void display_x()

System.out.println(“display : outer_x = “ + outer_x);

void display_y()

// không thể truy xuất biến đối tượng của lớp Inner

System.out.println(“display : inner_y = “ + inner_y); // Error

class InnerClassDemo

public static void main(String args[])

Outer outer = new Outer();

outer.test();

Kỹ thuật lập trình hướng đối tượng - Bài 4 Trang 10


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

BÀI 5: LẬP TRÌNH KẾ THỪA

Mục tiêu:
Trong bài này, Anh/Chị cần đạt được những mục tiêu sau:
1. Thừa kế.
2. Phương pháp phân tích thiết kế bottom-up.
3. Lập trình lớp dẫn xuất.
4. Một số vấn đề xử lý trong kế thừa.
Nội dung:

1. Quan hệ “là” và kế thừa


1.1. Sự quan hệ giữa các đối tượng
Thực tế các đối tượng trong một hệ thống xử lý của chương trình luôn có quan
hệ, tương tác lẫn nhau. Như đã trình bày, một đối tượng tương tác đến một đối
tượng khác thông qua cơ chế thông điệp (message), còn mối quan hệ giữa các đối
tượng thường có 3 dạng chủ yếu:
- Quan hệ “là” (is): hay còn gọi là quan hệ Generalization, thể hiện cho các lớp
đối tượng có chia sẻ một số giống nhau về cấu trúc (các thành phần biến nhớ hay
thuộc tính) và hành vi (hàm hay phương thức). Chẳng hạn lớp đối tượng Sinh viên
(Student) và Giáo viên (Teacher) cùng chia sẽ sự giống nhau về thuộc tính như họ
và tên, ngày sinh, quê quán,... và phương thức như nhập dữ liệu, in dữ liệu ra màn
hình, tính tuổi,... Và nội dung chia sẽ này được thiết kế thành một lớp tổng quát hơn,
chẳng hạn lớp Con người (Person). Rõ ràng, thực tế chỉ ra Sinh viên và Giáo viên
đều là (is) Con người.
Trong UML, quan hệ “là” giữa các lớp đối tượng được thể hiện bằng đường
thẳng nối giữa hai lớp, ở một đầu có ký hiệu mũi tên thể hiện lớp trừu tượng hay
tổng quát hơn. Minh họa bằng hình vẽ sau,

Kỹ thuật lập trình hướng đối tượng - Bài 5 Trang 1


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

- Quan hệ “có” (has): hay còn gọi quan hệ Aggregations, tức đối tượng này
đóng vai trò là thành phần tạo ra đối tượng kia. Chẳng hạn, đối tượng xe hơi (Car)
có (chứa) các đối tượng bánh xe (Wheel). Quan hệ này còn được thể hiện bằng một
dạng mạnh hơn đó là quan hệ đối tượng thành phần (Composition), đã được xem
xét ở phần trước, tức các đối tượng sẽ được chứa và chỉ tồn tại bên trong một đối
tượng khác và chúng sẽ bị hủy cùng với đối tượng chứa. Minh họa (theo ngôn ngữ
đặc tả thiết kế UML) bằng hình vẽ sau (đường nối có hình thoi ở một đầu thể hiện
lớp đối tượng chứa và đầu kia thể hiện lớp đối tượng thành phần).

- Quan hệ liên hợp (association): thể hiện các đối tượng thuộc cùng một phạm
vi tác động để chúng có thể truy cập, khai thác lẫn nhau. Chẳng hạn một đối tượng
Company muốn gửi một thông điệp (hay truy cập khai thác, xử lý) đến một đối
tượng Employee thì phải biết phương thức (hay nội dung) cần gọi trên đối tượng
Employee, minh họa bằng hình vẽ sau.

1.2. Phương pháp phân tích và thiết kế bottom-up


Trong phân tích và thiết kế hướng đối tượng, phương pháp được áp dụng chủ
yếu là bottom-up (từ dưới lên). Theo đó, chúng ta xuất phát từ không gian thực các
đối tượng của bài toán để thiết kế các lớp đối tượng, sau đó bằng phương pháp tổng
quát hóa (tức là tìm kiếm sự chia sẽ giống nhau về nội dung) để thiết kế các lớp đối
tượng ở mức cao (tổng quát hay trừu tượng hơn).

Kỹ thuật lập trình hướng đối tượng - Bài 5 Trang 2


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Quá trình phân tích và thiết kế có chia thành 3 không gian các lớp đối tượng
như sau: thứ nhất, không gian các đối tượng thực tế của bài toán, ở đây gồm tất cả
các đối tượng có liên quan và nhằm mục tiêu giải quyết bài toán với nội dung và
hành vi đầy đủ. Thứ hai, không gian các lớp đối tượng trong chương trình. Vì chức
năng máy tính là xử lý thông tin do đó không gian các đối tượng trong chương trình
được thiết kế theo hướng thông tin và xử lý thông tin, tức các nội dung và hành của
các đối tượng chỉ mang tính thông tin và là những dạng thông tin có thể biểu diễn
được trên máy tính. Thứ ba, không gian các lớp đối tượng thiết kế. Với mục tiêu
chính tằng cường sử dụng lại (giảm bớt sự trùng lặp) nên các lớp đối tượng có mức
trừu tượng cao (tổng quát hơn) sẽ được thiết kế.

Kỹ thuật lập trình hướng đối tượng - Bài 5 Trang 3


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Minh họa 3 không gian các đối tượng và lớp đối tượng như sau:

Các đối Các đối tượng Các lớp đối


tượng trong không trong không gian tượng trong không
gian thực của bài của chương trình gian thiết kế
Kích thước của không gian các đối tượng trong chương trình có thể nhỏ hơn
không gian các đối tượng thực trong bài toán, bởi vì trong chương trình chỉ thể hiện
được các đối tượng cũng như nội dung của đối tượng về mặt thông tin. Mặt khác,
trong không gian thiết kế có thể phát sinh thêm các lớp trừu tượng, có mức khái
quát cao hơn so với các lớp đối tượng trong chương trình yêu cầu.
Phương pháp phân tích và thiết kế hướng đối tượng thường xuất phát theo 2
hướng: thứ nhất, từ bản mô tả về bài toán sau đó chúng ta tìm kiếm các đối tượng
dựa trên mô tả “danh từ”, các thuộc tính của đối tượng dựa trên mở tả “tính từ” và
các hành vi của đối tượng dựa trên mô tả “động từ”. Thứ hai, dựa trên bản phân tích
và thiết kế về các thực thể dữ liệu theo truyền thống để đưa ra các lớp đối tượng,
sau đó phân tích bổ sung thêm các hành vi cho đối tượng.
Khác với phân tích hướng chức năng thường được thực hiện bằng phương pháp
top-down, quá trình phân tích thiết kế hướng đối tượng áp dụng phương pháp
bottom-up. Chúng ta xuất phát từ bài toán để phân tích các đối tượng trong không
gian thực của bài toán, tư đó chúng ta phân loại và đưa ra thiết kế các lớp đối tượng
của chúng. Dựa trên các lớp đối tượng này chúng ta đi tìm kiếm sự chia sẽ giống
nhau về các đặc tính (thuộc tính và phương thức) của chúng để đưa ra thiết kế các
lớp có mức trừu tượng cao hơn (tổng quát hơn). Quá trình đi lên như vậy được gọi
là bottom-up, việc dừng lại ở mức nào phụ thuộc vào thực tế của bài toán cũng như
chủ quan của người phân tích. Hiện nay chưa có một quy trình tổng thể dưới dạng
hình thức hóa toán học để thực hiện điều này.

Kỹ thuật lập trình hướng đối tượng - Bài 5 Trang 4


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Chẳng hạn, từ các đối tượng con sử tử, con chó phốc và chó đốm chúng ta phân
thành 2 loại: thứ nhất là loại động vật ăn thịt hoang dã, thứ hai là con vật nuôi trong
nhà. Chúng ta đưa ra thiết kế 2 lớp đối tượng gồm “Predator Wild Cats” và “Pet
Dogs”. Từ hai lớp đối tượng này chúng ta lại thiết kế lớp tổng quát hơn là
“Mammal” gồm các đặc tính chia sẽ giống nhau giữa chúng như lông, máu nóng, đi
bằng bốn chân,... và hành vi như ăn, ngủ, sinh sản,... (hình vẽ trên).
Mỗi phương án phân loại đối tượng từ bài toán thực để đưa ra thiết kế lớp, mỗi
phương án thiết kế lớp có mức tổng quát hơn từ các lớp mức thấp đều cho một kết
quả khác nhau của thiết kế và đem lại hiệu quả xây dựng và phát triển ứng dụng
khác nhau. Việc đánh giá phương án nào cho kết quả tốt nhất là chưa có phương
pháp tổng thể, chủ yếu dựa vào trải nghiệm thực tế của người phân tích và kết quả
ứng dụng của phần mềm tương ứng.
1.3. Các khái niệm liên quan đến kế thừa
- Kế thừa (inheritance): là một quan hệ giữa các lớp, trong đó một lớp chia sẻ
cấu trúc và hành vi của nó cho một hoặc nhiều lớp khác. Kế thừa thể hiện cho quan
hệ “là” giữa các đối tượng như đề cập ở trên.
Lập trình kế thừa là việc xây dựng một lớp mới dựa trên một hoặc nhiều lớp đã
có bằng cách sử dụng lại nội dung của các lớp này và bổ sung thêm các nội dung
mới. Chẳng hạn, chúng ta có lớp “Circle” với nội dung được chia sẽ trong lớp
“Cylinder” như hình vẽ sau.

Kỹ thuật lập trình hướng đối tượng - Bài 5 Trang 5


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

- Lớp cơ sở: hay còn gọi là lớp cha, là lớp có nội dung được chia sẻ, hay lớp đã
có dùng để xây dựng lớp mới với nội dung được sử dụng lại. Thuật ngữ được dùng
là “base class” hoặc “superclass”.
- Lớp dẫn xuất: hay còn gọi là lớp con, là lớp mới xây dựng có nội dung bao
gồm 2 phần, thứ nhất là nội dung được kế thừa từ lớp cơ sở, thứ hai là nội dung mới
bổ sung thêm. Thuật ngữ được dùng là “derived class” hoặc “subclass”.
Trong hình vẽ trên, lớp cơ sở (cha) là “Circle” có thuộc tính gồm bán kính
(radius), màu (color) và phương thức getArea(), getRadius(),... và lớp dẫn xuất (con)
là “Cylinder” ngoài các nội dung được kế thừa từ lớp “Circle” có thêm thuộc tính
height và phương thức như getHeight(), getVolume(),...
- Kế thừa đơn: là một lớp dẫn xuất kế thừa nội dung của duy nhất một lớp cơ sở.
Minh họa hình vẽ ở trên.
- Kế thừa bội: là một lớp dẫn xuất kế thừa nội dung của nhiều lớp cơ sở khác
nhau. Hiện nay kế thừa bội ít được cung cấp bởi các ngôn ngữ lập trình hướng đối
tượng hiện đại vì nó phát sinh nhiều rắc rối mà hiệu quả đem lại không lớn. Hình vẽ
sau minh họa kế thừa bội, lớp “Car” kế thừa nội dung từ 2 lớp “Vehicle” và
“Motorized”.

Kỹ thuật lập trình hướng đối tượng - Bài 5 Trang 6


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

- Chuỗi các lớp kế thừa: là danh sách các lớp kế thừa lẫn nhau, trong đó một
lớp là cơ sở của kế thừa này và đồng thời là dẫn xuất của một kế thừa khác.
- Lược đồ phân cấp kế thừa: bao gồm nhiều chuỗi kế thừa trong đó một lớp là
cơ sở của nhiều kế thừa và đồng thời là dẫn xuất của một kế thừa khác.
Hình vẽ sau minh họa (1) là kế thừa đơn từ A sang B, (4) là kế thừa bội từ A và
B sang C, (2) là chuỗi kế thừa từ A sang B và từ B sang C, (5) là lược đồ kế thừa từ
A sang B, C và từ B sang D.

2. Lập trình lớp dẫn xuất


2.1. Quy tắc lập trình lớp dẫn xuất
Java cung cấp phương pháp lập trình kế thừa (lớp dẫn xuất) thông qua từ khóa
“extends”, với ý nghĩa chúng ta sẽ mở rộng một lớp đã có để bổ sung thêm các nội
dung mới.
Cú pháp như sau:

class tên_lớp_con extends tên_lớp_cha {

Kỹ thuật lập trình hướng đối tượng - Bài 5 Trang 7


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

/*các nội dung thay đổi và

nội dung mới bổ sung cho lớp con*/

}
Trong đó, “tên_lớp_cha” là lớp cơ sở dùng để mở rộng (kế thừa),
“tên_lớp_con” đặt tùy ý theo quy tắc tên. Nội dung được bổ sung bao gồm cả thuộc
tính (các biến) và phương thức (các hàm). Ví dụ sau,

class P2D{

int x,y;

public P2D(){ x=y=5; }

public int sum(){ return x+y; }

class P3D extends P2D{

int z;

public P3D(){ z=7; }

public int sum(){ return x+y+z; }

}
sẽ định nghĩa một lớp P2D (điểm trên mặt phẳng) làm cơ sở gồm thuộc tính
{x,y} và các phương thức {P2D (hàm tạo), sum (tính tổng)}, lớp thứ hai có tên P3D
(điểm trong không gian) kế thừa từ P2D có thêm thuộc tính {z} và các phương thức
{P3D (hàm tạo), sum (tính tổng)}. Như vậy một đối tượng của lớp P3D có tổng
cộng 3 thuộc tính {x,y,z} và các phương thức xử lý từ hai lớp P2D và P3D. Minh
họa bằng hình vẽ sau.

Kỹ thuật lập trình hướng đối tượng - Bài 5 Trang 8


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

P2D

extends

P3D

P2D(

sum()
P3D(

sum()

2.2. Phạm vi truy xuất trong kế thừa


Các thành viên (bao gồm biến và hàm) được kế thừa từ lớp cơ sở vào lớp dẫn
xuất sẽ có phạm vi tác động được thay đổi tùy theo phạm vi gốc định nghĩa của
chúng trong lớp cơ sở. Cụ thể:
- Các thành viên có phạm vi “public” và “protected” sẽ được bảo toàn trong lớp
dẫn xuất;
- Các thành viên có phạm vi “private” sẽ không được truy xuất xử lý trực tiếp
trong lớp dẫn xuất;
- Phạm vi mặc định được bảo toàn trong kế thừa nếu các lớp thuộc cùng gói
(package), nếu các lớp ở các gói khác nhau thì các thành viên có phạm vi mặc định
sẽ không được truy xuất xử lý trực tiếp giữa các lớp kế thừa. Ngược lại, phạm vi
“protected” được bảo toàn trong kế thừa mà không phụ thuộc chúng nằm cùng gói
hay khác gói.
Hình vẽ sau minh họa cơ chế phạm vi trong kế thừa:

Kỹ thuật lập trình hướng đối tượng - Bài 5 Trang 9


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

(vùng private)
(extends khác
gói)
(vùng mặc
(vùng private)
định)

(vùng
(vùng mặc
protected)
định)
(vùng public) (vùng
protected)

(vùng public)

(extends cùng
gói)
(vùng private) Kế thừa khác gói thì
phạm vi “mặc định”
(vùng mặc không được truy cập
định)
(vùng
protected) Kế thừa cùng gói thì
(vùng public) phạm vi của các thành
viên được bảo toàn
Ví dụ sau định nghĩa hai lớp “A” và “B” có quan hệ kế thừa (B kế thừa A),

class A{

private int x=1;

int y=2;

protected int z=3;

public int w=4;

public int getX(){ return x; }

class B extends A{

Kỹ thuật lập trình hướng đối tượng - Bài 5 Trang 10


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

int sum(){ return getX()+y+z+w; }

}
Theo quy tắc, ba biến “y, z, w” trong lớp “A” được bảo toàn phạm vi khi kế
thừa sang lớp “B” cho nên chúng ta vẫn xử lý bình thường (xem hàm “sum”). Biến
“x” trong lớp “A” chỉ dùng riêng, không thể truy xuất bên trong lớp “B”, do đó hàm
“sum” trong “B” muốn lấy giá trị của biến “x” phải thực hiện thông qua hàm
“getX” đã được viết trong “A”.
2.3. Xử lý thành viên kế thừa (tham chiếu super)
Trong các phần trước chúng ta sử dụng tham chiếu “this” để truy cập xử lý đối
tượng hiện thời bên trong các phương thức của một lớp. Ở đây, khi một lớp dẫn
xuất kế thừa các thành viên của một lớp cơ sở thì việc truy cập xử lý chúng được
thực hiện theo 2 trường hợp:
- Nếu các thành viên kế thừa không trùng tên với các thành viên mới trong lớp
dẫn xuất thì chúng ta truy cập xử lý như thông thường (chỉ cần viết tên của chúng là
được);
- Nếu các thành viên kế thừa trùng tên với các thành viên mới trong lớp dẫn
xuất thì chúng ta sử dụng tham chiếu “super” để truy cập xử lý, quy tắc như sau:

super.tên_thành_viên_kế_thừa_cần_truy_cập
Như vậy, trong một phương thức của lớp chúng ta có hai tham chiếu “this” và
“super” để truy cập xử lý. Minh họa bằng hình vẽ sau.

Kỹ thuật lập trình hướng đối tượng - Bài 5 Trang 11


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Lớp cơ sở: A

Lớp dẫn xuất:


this B

extends
super
this

instance of

t
his supe
r

Đối tượng của lớp con “B” mang trong nó 2 phần nội dung, đó là nội dung
được kế thừa từ lớp cha “A” (có tô màu) và nội dung của bản thân “B”. Do đó trong
một phương thức bất kỳ của đối tượng này có tham chiếu “super” để truy cập xử lý
phần nội dung kế thừa từ “A”, còn tham chiếu “this” để truy cập xử lý ngay chính
đối tượng đó (phần nội dung của “B”).
Rõ ràng, tham chiếu “this” có thể được dùng để khai thác xử lý tất cả các thành
viên trong đối tượng (gồm các thành viên kế thừa từ cơ sở và thành viên mới trong
lớp con).

Ví dụ sau sẽ định nghĩa ba lớp theo sơ đồ kế thừa trong hình vẽ, lớp “Vehicle” là
cơ sở và các lớp con là “Car”, “Truck”, “Motorcycle”.

class Vehicle {

String bien_dk = "38F8-3338";

Kỹ thuật lập trình hướng đối tượng - Bài 5 Trang 12


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

String ten_chuxe = "Duong Long Khanh";

void chuyenChuXe(String ten_chumoi) {

ten_chuxe = ten_chumoi;

void show(String title){

System.out.printf("%s",title);

System.out.printf("\nBien dang ky: %s",bien_dk);

System.out.printf("\nTen chu xe: %s",ten_chuxe);

//... các nội dung khác của lớp “Vehicle”

class Car extends Vehicle {

int so_cua = 4;

void show(String title){

super.show(title);

System.out.printf("\nSo canh cua: %d",so_cua);

//... các nội dung khác của lớp “Car”

class Truck extends Vehicle {

int so_cau = 3;

void show(String title){

super.show(title);

System.out.printf("\nSo cau (truc) xe: %d",so_cau);

Kỹ thuật lập trình hướng đối tượng - Bài 5 Trang 13


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

//... các nội dung khác của lớp “Truck”

class Motorcycle extends Vehicle {

boolean co_mai_che = false;

void show(String title){

super.show(title);

if(co_mai_che) System.out.print("\nCo mai che");

else System.out.print("\nKhong co mai che");

//... các nội dung khác của lớp “Motorcycle”

}
Trong lớp “Vehicle” có hàm “show” để hiện các thông tin của đối tượng ra màn
hình Console, cũng vậy các lớp con ở sau (kế thừa Vehicle) gồm “Car”, “Truck”,
“Motorcyle” đều chứa hàm “show” để hiện thông tin. Tuy nhiên, các nội dung cần
hiện gồm phần được kế thừa và phần mới, trong khi phần được kế thừa đã thực hiện
trong hàm “show” của lớp cơ sở “Vehicle” do đó chỉ cần gọi hàm này bằng lệnh,

super.show( ... );
trong các lớp con (dẫn xuất) là được. Sau đó viết lệnh hiện thêm các thông mới
nếu có của lớp đối tượng tương ứng. Chẳng hạn, trong hàm “show” của lớp “Car”
hiện thêm thông tin và số cửa, của lớp “Truck” hiện thêm thông về số cầu (trục) của
xe,...
Hàm “show” của các lớp ở trên được thiết kế có tham số “title” chứa thông báo
khi hiện thông tin của đối tượng. Nội dung thông báo này có thể thay đổi tùy theo
thời điểm chạy của hàm trên cùng một đối tượng nên thiết kế dưới dạng tham số là
hợp lý. Chẳng hạn, sau khi nhập của đối tượng “a” thuộc lớp “Car” ta viết lệnh hiện
thông tin như sau,

a.show(“Thông tin xe vừa nhập”);

Kỹ thuật lập trình hướng đối tượng - Bài 5 Trang 14


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

sau đó (trong khi xử lý) đối tượng xe hơi này bị chuyển chủ sở hữu bằng lệnh,

a.chuyenChuXe(“Duong Ha Linh”);
khi đó lệnh hiện thông tin đối tượng sẽ là,

a.show(“Thông tin xe sau khi chuyển chủ”);

2.4. Xử lý danh sách đối tượng không cùng kiểu


Một tham chiếu lớp cơ sở có thể thực hiện tham chiếu đến bất kỳ đối tượng nào
của các lớp dẫn xuất sau nó. Ví dụ sau sẽ sử dụng tham chiếu của lớp cơ sở
“Vehicle” để tham chiếu đến các đối tượng dẫn xuất “Car”, “Truck”, “Motorcycle”
và xử lý,

Vehicle a; //khai báo tham chiếu cơ sở “Vehicle”

a = new Car(); //tạo đối tượng con “Car”

(1) a.show(“\n>>>Thông tin xe hơi là”);

a = new Truck(); //tạo đối tượng con “Truck”

(2) a.show(“\n>>>Thông tin xe tải là”);

a = new Motorcycle(); //tạo đối tượng “Motorcycle”

(3) a.show(“\n>>>Thông tin xe mô-tô là”);


Khi xử lý (gọi hàm, truy xuất dữ liệu) trên đối tượng thông qua tham chiếu cơ
sở, máy ảo Java sẽ thực hiện xử lý nội dung đó trên đúng đối tượng đang được tham
chiếu. Cụ thể, trong ví dụ trên lệnh (1) sẽ chạy hàm “show” trong lớp “Car” của đối
tượng, lệnh (2) chạy hàm “show” trong lớp “Truck” và tượng tự, lệnh (3) chạy hàm
“show” trong lớp “Motorcycle”. Kết quả trên màn hình là,

Kỹ thuật lập trình hướng đối tượng - Bài 5 Trang 15


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Theo cơ chế này, một tham chiếu có thể thực hiện tham chiếu đến các đối
tượng có kiểu khác nhau, khi cần biết đối tượng đang được xử lý thuộc lớp nào
(được sinh bởi lớp nào) chúng ta sử dụng toán tử “instanceof” như sau,

tham_chiếu instanceof tên_lớp


Phép toán trả về kết quả “true” nếu đối tượng đang được tham chiếu được sinh
bởi lớp tương ứng, ngược lại trả về giá trị “false”. Ví dụ như sau sẽ hiện thông tin
của đối tượng với tiêu đề phù hợp cho đối tượng đang xử lý dựa trên phép toán
“instanceof”,

if( a instanceof Vehicle)

a.show(“\n>>>Thông tin xe là”);

else if( a instanceof Car)

a.show(“\n>>>Thông tin xe hơi là”);

else if( a instanceof Truck)

a.show(“\n>>>Thông tin xe tải là”);

else if( a instanceof Motorcycle)

a.show(“\n>>>Thông tin xe mô-tô là”);

else /*...xử lý tiếp...*/

Kỹ thuật lập trình hướng đối tượng - Bài 5 Trang 16


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Cơ chế này cho phép chúng quản lý danh sách các đối tượng thuộc các lớp khác
nhau trên cùng một kiểu tham chiếu, các đối tượng này có cùng kế thừa từ một lớp
cơ sở. Danh sách dạng này được gọi là “heterogenous collection”.
Ví dụ chúng ta muốn quản lý một danh sách các đối tượng người lao động với
các ngành nghề khác nhau tương ứng với các lớp như sau:

Người
lao động

Công Kỹ sư Nhân
nhân viên

CN CN KS KS
Cơ Mỏ Hóa CN
Một cách đơn giản là tạo một mảng các tham chiếu có kiểu là “Người lao
động”, sau đó tạo các đối tượng kiểu lớp con ở sau theo yêu cầu quản lý. Có thể
minh họa bằng hình vẽ sau:

CN
 Cơ
 khí
KS
 Hóa
 chất KS
. CNT
.. T
Nhân viên

Danh sách các Đối tượng khác kiểu (heterogenous


tham chiếu collection)

Trong hình vẽ trên, dãy tham chiếu “p” dùng để tham chiếu đến các đối tượng
khác kiểu nhau. Chẳng hạn, p[0] tham chiếu đến đối tượng lớp “CN Cơ khí”, p[1]
tham chiếu đến đối tượng lớp “KS Hóa chất”,...

Kỹ thuật lập trình hướng đối tượng - Bài 5 Trang 17


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

3. Một số vấn đề xử lý trong kế thừa


3.1. Phương thức tạo trong kế thừa
Phương thức tạo, như đã trình bày, là một dạng phương thức đặc biệt của lớp.
Nó có đặc điểm trùng tên với lớp, không có kiểu trả về và máy tự chạy trên bất kỳ
một đối tượng khi mới sinh.
Phương thức tạo của một lớp cơ sở không được sử dụng lại bên trong lớp dẫn
xuất kế thừa từ nó. Điều này khác với các phương thức thông thường là được sử
dụng lại bên trong lớp dẫn xuất. Thuy nhiên, cơ chế hàm tạo được bảo toàn tức là
bất kỳ một đối tượng được sinh mới (bằng lệnh “new”) thì máy sẽ thực hiện các
hàm tạo ở các lớp kế thừa nhau theo thứ tự từ trên xuống. Cụ thể, đối tượng của lớp
dẫn xuất được sinh thì hàm tạo lớp cơ sở chạy trước, tiếp đến hàm tạo lớp dẫn xuất.
Ví dụ sau định nghĩa hai lớp “A1” và “B1”, lớp “B1” kế thừa từ “A1”, trong
lớp “A1” có 2 biến “x,y”, lớp “B1” có biến “z” và mỗi lớp đều có một hàm tạo gán
dữ liệu cho các biến:

class A1 {

int x,y;

A1(){ x=y=5; } /*(1)*/

class B1 extends A1 {

int z;

B1(){ z=7; } /*(2)*/

int sum(){ return x+y+z; }

}
Khi sinh đối tượng của “B1” máy sẽ chạy hàm tạo (1) của “A1” trước, tiếp đến
chạy hàm tạo (2) của “B1” cho đối tượng đó. Ví dụ lệnh sau,

B1 b = new B1();
thì đối tượng của “b” sẽ có nội dung dữ liệu như được gán trong các hàm tạo (1)
và (2) ở trên. Cụ thể biến “x” và “y” bằng 5, biến “z” bằng 7. Do đó lệnh sau,

System.out.print( b.sum() );

Kỹ thuật lập trình hướng đối tượng - Bài 5 Trang 18


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

sẽ in ra màn hình kết quả là số 17 (tổng của 5+5+7).


Quá trình trên minh họa bằng hình vẽ sau.

Lớp cơ sở: A1

x y

Lớp dẫn xuất:


B1
Hàm tạo
A1() z

extends Hàm tạo


B1()
Chạy hàm tạo Hàm cộng
cơ sở trước - A1() “sum()”
b = new
B1();
x y z Chạy hàm tạo
dẫn xuất sau - B1()

Quá trình này cũng được đảm bảo trong trường hợp kế thừa nhiều mức, khi đó
bất kỳ một đối tượng trong chuỗi kế thừa nhiều mức được sinh thì máy chạy các
hàm tạo từ lớp cơ sở trên cùng, lần lượt tiếp theo đến các dẫn xuất phía sau và cuối
cùng tại lớp ứng với đối tượng được sinh.
Chẳng hạn ta có chuỗi kế thừa 4 mức như hình vẽ sau, một đối tượng của lớp
“D” được sinh thì máy chạy các hàm tạo theo thứ tự của “A”, “B”, “C” và cuối
cùng là “D”. Trong khi đối tượng của lớp “C” được sinh thì máy chạy hàm tạo theo
thứ tự của “A”, “B” và cuối cùng của “C”, tương tự nếu đối tượng của “B” được
sinh thì máy chạy hàm tạo theo thứ tự của “A”, “B”.

Kỹ thuật lập trình hướng đối tượng - Bài 5 Trang 19


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

A n
ew

B n
ew

C n
ew

n
D
ew

Đối với hàm tạo có tham số, chúng ta phải truyền dữ liệu cho các tham số từ
lớp dẫn xuất (lớp con) ngược lên lớp cơ sở (lớp cha) theo quy tắc sau:

super( các_dữ_liệu_truyền_cho_hàm_tạo_cơ_sở );
lệnh này bắt buộc phải đặt ở đầu tiên trong nội dung hàm tạo lớp dẫn xuất. Ví
dụ sau định nghĩa hai lớp “A1”, lớp “B1” kế thừa từ “A1” với các hàm tạo có tham
số,

class A1 {

int x,y;

A1(int x,int y){ this.x=x; this.y=y; }

class B1 extends A1 {

int z;

B1(int x,int y,int z)

Kỹ thuật lập trình hướng đối tượng - Bài 5 Trang 20


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

{ super(x,y);

this.z=z;

/*(2)*/

int sum(){ return x+y+z; }

}
trong đó, hàm tạo dẫn xuất (2) ở lớp “B1” thực hiện truyền dữ liệu cho hàm tạo
cơ sở (1) của lớp “A1” bằng lệnh,

super(x,y);
ngay đầu tiên trong nội dung hàm tạo (2) ở lớp “B1”. Khi thực hiện sinh đối
tượng từ lớp “B1” bằng lệnh sau,

B1 b = new B1(3,2,5);
thì máy sẽ gọi hàm tạo (2) trong “B1” với dữ liệu (3,2,5) truyền cho các tham
số (x,y,z) tương ứng. Như vậy lệnh “super(x,y)” gọi hàm tạo (1) ở lớp cơ sở “A1”
với dữ liệu truyền (x,y) (tức (3,2)) cho tham số ở hàm tạo (1), sau đó chạy tiếp nội
dung trong hàm (2). Kết quả đối tượng mới sinh có nội dung dữ liệu được gán x=3,
y=2 (do hàm cơ sở (1)) và z=5 (do hàm dẫn xuất (2)). Lệnh sau,

System.out.print( b.sum() );
sẽ cho kết quả in ra trên màn hình số 10 (3+2+5).
3.2. Kỹ thuật ghi đè (overriding) và nạp chồng (overloading)
Như đã trình bày, một phương thức (hàm) ở lớp cơ sở có thể được nạp chồng
lại ngay bên trong lớp đó (tức các hàm này có tên trùng nhau, khác nhau về tham
số).
Tương tự, trong kế thừa, một hàm ở lớp cơ sở có thể được nạp chồng lại bên
trong lớp dẫn xuất theo nguyên tắc của kỹ thuật nạp chồng. Tuy nhiên, điều đặc biệt
là một hàm ở lớp cơ sở có thể được lập trình lại (thay bằng một nội dung mới nhưng
các khai báo hoàn toàn giữ nguyên về tên hàm, kiểu hàm, tham số hàm) bên trong
lớp dẫn xuất. Đây được gọi là kỹ thuật ghi đè (overriding) trong kế thừa. Hình vẽ
sau minh họa điều này.

Kỹ thuật lập trình hướng đối tượng - Bài 5 Trang 21


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Lớp cơ sở: A

void sum()
Phiên bản ghi
(1) đè
Lớp dẫn xuất:
B
void sum()
(2)
extends
void sum( x )
Phiên bản nạp
chồng (3)

Trong sơ đồ trên, hàm “sum” phiên bản (1) ở lớp cơ sở được nạp chồng bởi
phiên bản (3) trong lớp dẫn xuất vì có thêm tham số so với bản gốc (1), và nó được
ghi đè bởi phiên bản (2) trong lớp dẫn xuất.
Đối với nạp chồng, khi gọi hàm máy sẽ dựa vào các dữ liệu truyền cho tham số
để tìm đến đúng phiên bản thực hiện sao cho các tham số của phiên bản hàm đó phù
hợp với các dữ liệu được truyền và nhận chúng.
Đối với ghi đè, khi gọi hàm máy sẽ dựa vào đối tượng đang được tham chiếu và
sẽ thực hiện đúng phiên bản của đối tượng đó (tương ứng với lớp của nó). Trong
trường hợp này, muốn gọi phiên bản ở lớp cơ sở chúng ta phải sử dụng tham chiếu
“super” trong hàm lớp dẫn xuất. Ví dụ như sau,

class A1 {

private int x = 5, y = 7;

int sum(){ return x+y; } /*(1)*/

class B1 extends A1 {

private int z = 3;

int sum(){ return super.sum()+z; } /*(2)*/

class C1 extends B1 {

Kỹ thuật lập trình hướng đối tượng - Bài 5 Trang 22


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

private int w = 9;

int sum(){ return super.sum()+w; } /*(3)*/

}
định nghĩa 3 lớp gồm “A1”, “B1” kế thừa từ “A1”, “C1” kế thừa từ “B1”. Cả 3
lớp đều có hàm “sum”, ở đây phiên bản (3) ghi đè (2), phiên bản (2) ghi đè (1).
Trong phiên bản (2) và (3) có gọi hàm cơ sở nên phải dùng tham chiếu “super”
bằng lệnh “super.sum()” như trên. Rõ ràng, nội dung ở phiên bản sau sẽ hoàn thiện,
đầy đủ hơn (theo một nghĩa nào đó) so với phiên bản trước nhằm phù hợp với lớp
đối tượng mới được xây dựng.
3.3. Đặc tính static, final trong kế thừa
Như đã trình bày, đặc tính “static” (tĩnh) có thể đặt cho từng thành viên trong
lớp và các thành viên đó mang đặc tính sử dụng chung cho mọi đối tượng của lớp.
Thậm chí chúng ta có thể khai thác sử dụng chúng trực tiếp trên các lớp mà không
cần đối tượng. Thực chất, nó đóng vai trò như các biến hay các hàm dùng toàn cục
với phạm vi sử dụng thông qua một lớp.
Trong kế thừa của Java, đặc tính “static” của một thành viên được bảo toàn sau
khi thành viên đó được kế thừa vào các lớp dẫn xuất (lớp con). Thực chất, thành
viên đó sẽ được mở rộng phạm vi sử dụng trên các lớp kế thừa về sau. Hình vẽ sau
minh họa điều này,

s Thành
viên tĩnh ở lớp

Kế thừa vào lớp dẫn


xuất, và bảo toàn đặc tính

Do đó chúng ta truy cập xử lý thành viên tĩnh có thể thông qua bất kỳ một lớp
nào trong chuỗi kế thừa mà không cần đối tượng, tuy nhiên vẫn có thể truy cập xử
lý trên các đối tượng thông thường. Ví dụ như sau,

Kỹ thuật lập trình hướng đối tượng - Bài 5 Trang 23


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

class A1 {

static int e1 = 9;

class B1 extends A1 {

static int e2 = 10;

static int sum(){ return e1+e2; }

class C1 extends B1 {

static int e3 = 15;

}
định nghĩa lớp cơ sở “A1” chứa biến tĩnh “e1”, lớp “B1” kế thừa “A1” có thêm
biến tĩnh “e2” và hàm tĩnh “sum” để cộng “e1” và “e2”, lớp “C1” kế thừa từ “B1”
có thêm biến tĩnh “e3”. Như vậy, trong “B1” có thể truy cập xử lý cả biến “e1” theo
cơ chế tĩnh như “e2” trong chính nó, chẳng hạn có lệnh,

B1.e1 = 5;
cũng tương đương với lệnh sau,

A1.e1 = 5;
vì chúng cùng truy cập xử lý đến biến sử dụng chung “e1”. Tương tự, trong lớp
“C1” có thể truy cập xử lý các biến “e1”, “e2” và hàm “sum” theo cơ chế tĩnh, ví dụ
hai lệnh (1) và (2) sau là tương đương:

System.out.print( C1.sum() ); /*(1)*/

System.out.print( B1.sum() ); /*(2)*/


Đặc tính “final” để định nghĩa một biến hoặc hàm có nội dung không đổi (dưới
dạng hằng). Trong kế thừa cũng vậy, khi chúng ta định nghĩa một thành viên của
lớp có đặc tính “final” thì nội dung của chúng không thể thay đổi, đặc tính này của
một thành viên cũng được bảo toàn khi thành viên đó được kế thừa trong các lớp
dẫn xuất tiếp theo. Đặc biệt các hàm có “final” không thể ghi đè (overriding) ở các
lớp dẫn xuất. Ví dụ như sau,

Kỹ thuật lập trình hướng đối tượng - Bài 5 Trang 24


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

class A {

final int x=5;

final int sqr(){ return x*x; } /*(1)*/

class B extends A {

int x = 7;

final int sqr(){ return ...; } /*(2)*/

}
có biến “x” trong lớp cơ sở “A” có đặc tính “final” nhưng trong lớp dẫn xuất
“B” biến “x” lại không có đặc tính này. Thực chất đây là hai biến hoàn toàn độc lập
nhau, và như vậy trong “B” có thể khai thác sử dụng hai biến “x”. Trong “B”,
chúng ta sử dụng cú pháp “super.x” để xử lý biến “x” kế thừa từ lớp “A”, còn sử
dụng thông thường “x” hoặc “this.x” để chỉ đến biến “x” mới của “B”.
Trong khi đó, hàm “sqr” trong “A” có đặc tính “final” và chúng ta không được
phép lập trình lại nó trong lớp dẫn xuất (ghi đè) cho dù có bỏ hay không đặc tính
này của hàm. Cụ thể, phiên bản (2) trong “B” ghi đè phiên bản (1) trong “A” máy
sẽ báo lỗi.
Thậm chí, chúng ta có thể định nghĩa một lớp có đặc tính “final”, ví dụ:

final class A {

/*...nội dung của lớp...*/

}
Lớp được định nghĩa có đặc tính “final” như trên sẽ không thể áp dụng kế thừa
sang các lớp dẫn xuất. Hay nói cách khác, lớp này là phiên bản cuối cùng, không
thể mở rộng.

Kỹ thuật lập trình hướng đối tượng - Bài 5 Trang 25


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

BÀI 6: CƠ CHẾ ẢO VÀ TRỪU TƯỢNG

Mục tiêu:
Trong bài này, Anh/Chị cần đạt được những mục tiêu sau:
1. Cơ chế phương thức ảo.
2. Cơ chế trừu tượng (abstract)
3. Lập trình giao diện lớp (interface)
Nội dung:

Gới thiệu cơ chế ảo và trừu tượng


Hai đặc điểm mạnh nhất của kế thừa đó là khả năng sử dụng lại mã chương
trình và đa hình (polymorphism) Tính đa hình là khả năng thiết kế và cài đặt các hệ
thống mà có thể mở rộng dễ dàng hơn. Các chương trình có thể được viết để xử lý
tổng quát – như các đối tượng lớp cơ sở – các đối tượng của tất cả các lớp tồn tại
trong một phân cấp. Khả năng cho phép một chương trình sau khi đã biên dịch có
thể có nhiều diễn biến xảy ra là một trong những thể hiện của tính đa hình – tính
muôn màu muôn vẻ – của chương trình hướng đối tượng, một thông điệp được gởi
đi (gởi đến đối tượng) mà không cần biết đối tượng nhận thuộc lớp nào Tính đa
hình cho phép cài đặt các lớp dẫn xuất khác nhau từ một lớp nguồn. Một đối tượng
có thể có nhiều kiểu khác nhau gọi là tính đa hình.
Tính đa hình là một trong những đặc trưng mạnh của lập trình hướng đối tượng,
nó thể hiện một đối tượng có thể được sử dụng nhiều hình thức khác nhau. Theo
quan hệ là (“is a”) trong thiết kế hướng đối tượng, một đối tượng được xem như
kiểu lớp con, lớp cha, lớp ông,... và các lớp cơ sở ở phía trên trong cây kế thừa.

1. Cơ chế phương thức ảo


Phương thức ảo là một cơ chế rất hay trong lập trình hướng đối tượng, nó cho
phép thực hiện một phương thức theo hoàn cảnh cụ thể của việc truy xuất trên đối
tượng tương ứng. Cơ chế này phải được kết hợp với kỹ thuật viết đè phương thức
(overrideen method) trong kế thừa. Khi gọi một phương thức máy sẽ tìm từ trên
xuống (từ lớp cơ sở đến lớp dẫn xuất) và thực hiện phiên bản được viết đè mới nhất
trong lớp cuối cùng cho lời gọi đó.
Tính đa hình thể hiện qua việc: cùng một phương thức nhưng có nội dung thực
hiện khác nhau trên các đối tượng khác nhau. Phương thức gọi được xác định thông

Kỹ thuật lập trình hướng đối tượng - Bài 6 Trang 1


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

qua đối tượng được tham chiếu, không thông qua kiểu khai báo của tham chiếu.
Trong Java, các phương thức luôn mang tính đa hình.
Để thực hiện được tính đa hình ta phải thực hiện các bước sau:
 Lớp cơ sở đánh dấu phương thức ảo bằng từ khóa virtual hoặc abstract.
 Các lớp dẫn xuất định nghĩa lại phương thức ảo này (đánh dấu bằng từ
khóa override).
 Những thành viên (member fields) or những thuộc tính (properties) và
những hàm tĩnh (static) thì không được khai báo Virtual.
Phương thức ảo là phương thức được định nghĩa ở lớp cơ sở (lớp cha) mà các
lớp dẫn xuất (lớp con) muốn sử dụng phải định nghĩa lại. Những trường thành viên
(member fields) và những hàm tĩnh thì không được khai báo ảo.
Lớp trừu tượng chỉ được dùng làm lớp cha cho các lớp khác, nó không có các
thể hiện (instance). Lớp trừu tượng định nghĩa các thuộc tính chung cho các lớp con
của nó. Ví dụ có thể thiết kế lớp Hình tròn, Hình vuông... kế thừa từ lớp trừu tượng
Hình. Lớp Hình có thuộc tính là tên hình, các phương thức tính diện tích, chu vi...
Lớp trừu tượng (abstract) thường có ít nhất một phương thức trừu tượng, là
phương thức không có cài đặt: public abstract void draw();
Khai báo lớp trừu tượng: public abstract class ClassName {…}
Các lớp con của một lớp cha trừu tượng phải cài đặt tất cả các phương thức trừu
tượng. Nếu không nó cũng sẽ trở thành lớp trừu tượng.
Không thể tạo các đối tượng của một lớp trừu tượng nhưng có thể khai báo biến
thuộc kiểu lớp trừu tượng để tham chiếu đến các đối tượng thuộc lớp con của nó.
Lớp trừu tượng là lớp không có khai báo các thuộc tính thành phần và các
phương thức. Các lớp dẫn xuất của nó sẽ khai báo thuộc tính, cài đặt cụ thể các
phương thức của lớp trừu tượng.
Ví dụ 6.1.1: Định nghĩa các lớp trừu tượng
abstract class A
{
abstract void method_1();
}
public class B extends A
{ public void method_1()
{

Kỹ thuật lập trình hướng đối tượng - Bài 6 Trang 2


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

// cài đặt chi tiết cho phương thức method_1


// trong lớp con B.
//…
}
}
public class C extends A
{
public void method_1()
{
// cài đặt chi tiết cho phương thức method_1
// trong lớp con C.
//…
}
}
Lưu ý: Các phương thức được khai báo dùng các tiền tố private và static thì
không được khai báo là trừu tượng abstract. Tiền tố private thì không thể truy xuất
từ các lớp dẫn xuất, còn tiền tố static thì chỉ dùng riêng cho lớp khai báo mà thôi.

2. Cơ chế trừu tượng (abstract) trong phương thức và lớp


2.1. Khái niệm abstract
Trong trường hợp chúng ta muốn định nghĩa một lớp cha theo một cấu trúc trừu
tượng cho trước mà không cần hiện thực đầy đủ các phương thức, tức là ta muốn
tạo một lớp cha có dạng chung cho tất cả các lớp con và để các lớp con hiện thực
chi tiết, khi đó, bạn muốn chắc chắn lớp con có chồng lặp phương thức. Những
phương thức phải được chồng lặp trong lớp con gọi là phương thức trừu tượng,
được khai báo abstract và không có phần thân phương thức.
2.2. Lớp và phương thức trừu tượng
Khai báo: Lớp trừu tượng được khai báo như lớp thông thường nhưng có thêm
từ khóa abstract.
Ví dụ:

abstract class People

private int namsinh;

Kỹ thuật lập trình hướng đối tượng - Bài 6 Trang 3


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

private String hoten;

public People(int ns, String ht)

namsinh=ns; hoten=ht;

public String gethoten()

return hoten;

abstract String tostring();

}
Ta thấy rằng một lớp trừu tượng thực sự là một lớp với đầy đủ các thành phần,
không giống như interface. Giả sử trong chương trình có các đối tượng SinhVien,
GiaoVien. Các đối tượng này đều có một phương thức tostring để trả về một chuỗi
bao gồm toàn bộ thông tin về chúng. Đây là tình huống sử dụng phương thức trừu
tượng một cách hiệu quả: abstract string tostring();
Chú ý là các phương thức trừu tượng không có phần thân. Lớp SinhVien kế
thừa từ People được cài đặt như sau.

public class SinhVien extends People

private String lop;

private double diemtongket;

//Phuong thuc khoi tao

public SinhVien(int ns, String ht, String l, double dtk)

//dung Phuong thuc khoi tao cua lop cha

Kỹ thuật lập trình hướng đối tượng - Bài 6 Trang 4


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

super(ns,ht);

lop=l;

diemtongket=dtk;

//cai dat Phuong thuc tostring

public String tostring()

return String.valueof(namsinh)+String.valueof(diemtongket)+hoten;

}
Khi một phương thức được khai báo là abstract thì lớp chứa nó cũng phải là
một lớp abstract. Khi sử dụng phương thức abstract cho một lớp thì nhất thiết phải
có một lớp khác kếthừa và khai báo cài đặt chồng thì mới có tác dụng. Khi kế thừa
một lớp có chứa phương thức trừu tượng thì phương thức đó bắt buộc phải được cài
đặt.

3. Lập trình giao diện lớp


3.1. Giao diện lớp và cách lập trình
Giao diện theo nghĩa thông thường là những thể hiện bề ngoài của các phần nội
dung của một đối tượng nào đó, thông qua giao diện các đối tượng có thể tương tác
với nhau dễ dàng, thuận tiện và đem lại hiệu quả cao. Chẳng hạn, một chiếc xe hơi
(car) có rất nhiều chi tiết máy móc phức tạp ở bên trong (tức phần nội dung) nhưng
chỉ thể hiện bề ngoài để người lái xe có thể tương tác thật đơn giản gồm cần số,
chân phanh, chân ga, bánh lái,... và qua giao diện này người lái xe điều khiển thật
dễ dàng (hình vẽ).

Kỹ thuật lập trình hướng đối tượng - Bài 6 Trang 5


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Chi tiết bên trong xe hơi Giao diện cho người lái xe
Trong lập trình Java, khái niệm giao diện lớp (interface) cũng được hiểu với
hàm ý tương tự. Bên trong nội dung của một lớp đối tượng bao gồm các biến chứa
dữ liệu (gọi là thuộc tính của đối tượng) và các hàm xử lý (gọi là phương thức của
đối tượng) chứa các câu lệnh rất phức tạp. Giao diện lớp là tập các khai báo hàm
(kiểu hàm, tên hàm và danh sách các tham số hàm) và các biến ở dạng “static” và
“final”. Các đối tượng tương tác với nhau qua giao diện này.

<Lớp đối tượng> (Giao diện lớp)


1. Các biến chứa dữ
liệu

Tương tác

2. Các hàm chứa


lệnh xử lý

Giao diện của một lớp không nhất thiết chứa đầy đủ khai báo các thành phần có
trong lớp đó, mà chỉ cần những thành phần dùng để tương tác với các đối tượng
khác qua giao diện.
Một lớp đối tượng có thể được định nghĩa nhiều giao diện khác nhau với các
mục đích tương tác tương ứng. Cũng vậy, một giao diện có thể là giao diện cho
nhiều lớp đối tượng có cùng mục đích tương tác. Chẳng hạn, một người khi đến
buổi dạ hội sẽ có trang phục (có thể coi là giao diện) dạ hội, nhưng khi đến công sở
sẽ được thay đổi trang phụ công sở cho phù hợp.
Phương pháp định nghĩa một giao diện cho lớp đối tượng như sau:

Kỹ thuật lập trình hướng đối tượng - Bài 6 Trang 6


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

interface <tên_giao_diện> {

<khai-báo-các-thành-phần-trên-giao-diện>

}
Trong đó: <tên_giao_diện> là tự đặt theo qua tắc tên, các thành phần được khai
báo gồm mẫu hàm và các biến ở dạng “static” và “final”.
Ví dụ 6.3.1: Định nghĩa một giao diện cho các lớp đối tượng xử lý hình học
gồm gốc tọa để vẽ trên màn hình đồ họa, các hàm di chuyển, hàm co giãn, hàm tính
diện tích, tính chu vi.
Chúng ta chưa quan tâm đến đối tượng hình học xử lý cụ thể, mà ở đây chỉ
quan tâm khi xử lý các đối tượng hình học sẽ có những phần gì sẽ được đề cập. Nội
dung xử lý của từng phần đó rõ ràng phụ thuộc vào đối tượng cụ thể mà chúng ta
làm việc. Chẳng hạn, tính diện tích hình chữ nhật lấy độ dài cạnh lớn nhân với độ
dài cạnh bé, nhưng tính diện tích hình tròn lấy bình phương của bán kính nhân với
số,...
Nội dung định giao diện giao diện như sau.

interface GH {

public static final int OX = 300, OY = 300;

public void dichuyen(float dx, float dy);

public float cogian(float tyle);

public float tinhDT();

public float tinhCV();

public void show(String tb);

3.2. Phương pháp khai thác sử dụng giao diện


Từ giao diện đã được định nghĩa, chúng ta xây dựng lớp đối tượng để nội dung
hóa cho các thành phần hàm tương ứng với giao diện đó. Quy tắc để lập trình lớp
cài đặt (implements) nội dung cho một giao diện như sau:

class <tên_lớp> implements <tên_giao_diện> {

Kỹ thuật lập trình hướng đối tượng - Bài 6 Trang 7


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

<lập-trình-nội-dung-của-lớp>

}
Trong đó: từ khóa “implements” để chỉ ra một lớp có thể hiện nội dung các
thành phần các giao diện. Nội dung lớp bắt buộc phải lập trình nội dung các hàm
mà giao diện yêu cầu (đã khai báo trong giao diện), xem hình minh họa.

(Giao diện lớp) <Lớp đối tượng>


1. Các nội dung thể hiện

implements
2. Các nội dung mới

Cũng tương tự như kế thừa, các biến định nghĩa trong giao diện có thể được
khai thác, sử dụng trong lớp. Ngoài ra, lớp có thể định nghĩa thêm các thành phần
mới nhằm đáp ứng theo thiết kế cho đối tượng cần xử lý.
Ví dụ 6.3.2: Lập trình lớp đối tượng hình vuông “HV” thể hiện nội dung cho
các thành phần của giao diện “GH” ở trên.
Hình vuông cần thêm các biến tọa độ góc trái (x,y), độ dài cạnh (a) và kiểu dữ
liệu được chọn là float (số thực). Các hàm xử lý tính toán khá đơn giản như sau:

class HV implements GH

float x,y,a;

HV(float x,float y,float a)

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

Kỹ thuật lập trình hướng đối tượng - Bài 6 Trang 8


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

public void dichuyen(float dx,float dy)

x += dx; y += dy;

public void cogian(float tyle)

a *= tyle;

public float tinhDT()

return a*a;

public float tinhCV()

return 4*a;

public void show(String tb)

System.out.printf(“ %s ”, tb);

System.out.printf(“\nx=%.3f, y=%.3f, a=%.3f ”,

x, y, a);

System.out.printf(“\nDien tich:%.3f”,tinhDT());

System.out.printf(“\nChu vi:%.3f”,tinhCV());

Kỹ thuật lập trình hướng đối tượng - Bài 6 Trang 9


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

}
Lớp đối tượng sau khi lập trình thể hiện nội dung các thành phần của giao diện
được khai thác, sử dụng như một lớp thông thường. Chúng ta có thể sử dụng tham
chiếu kiểu giao diện để xử lý đối tượng. Ví dụ sau sẽ tạo đối tượng hình vuông (HV)
và xử lý các hàm đã được xây dựng nội dung,

GH a = new HV(5,8,3);

a.show(“\n Hinh vuong vua tao la”);

a.dichuyen(5,-7);

a.show(“\n Hinh vuong sau khi di chuyen la”);

a.cogian(1.5F);

a.show(“\n Hinh vuong sau khi gian 50% la”);


Trong trường hợp cần tạo đối tượng trực tiếp từ giao diện và lập trình nội dung
để xử lý chúng ta áp dụng quy tắc sau:

tham_chiếu = new tên_giao_diện(tham_số_hàm_tạo_nếu_có)

<lập-trình-nội-dung-của-đối tượng cần-xử-lý>

};
Điều này khá thuận tiện trong trường hợp các đối tượng thể hiện nội dung đơn
giản cho các giao diện và chỉ thích hợp với việc dùng 1 lần.
Trong lập trình Java, cũng như bất kỳ một ngôn ngữ với môi trường lập trình
nào, hệ thống thư viện được cung cấp khá đầy đủ. Các chương trình ứng dụng chủ
yếu khai thác hệ thống thư viện có sẵn để giải quyết yêu cầu đặt ra. Do đó trong
chương trình sử dụng các lớp đối tượng, các lệnh có trong thư viện bằng việc viết
lệnh gọi đến chúng. Tuy nhiên, có một số trường hợp các phần nội dung trong thư
viện khi chạy cần truy cập (gọi) đến các phần được xây dựng trong chương trình,
đây là được gọi là cơ chế gọi ngược (xem hình vẽ).

Kỹ thuật lập trình hướng đối tượng - Bài 6 Trang 10


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Thư viện Java Chương trình ứng dụng

A a

new 
h Xử lý
implements
B
g 
g
B 
Trên hình vẽ, đối tượng “a” được sinh từ lớp “A” và khi chạy xử lý nội dung “h”
của đối tượng này thì máy cần xử lý đến giao diện “B”. Do vậy chúng ta phải xây
dựng lớp đối tượng “B” để làm nội dung “g” cho thành phần “g” cần xử lý.
Cơ chế này được áp dụng triệt để khi chúng ta lập trình xử lý sự kiện trên giao
diện người dùng đồ họa (GUI) của màn hình, lập trình đa luồng,... sẽ được trình bày
chi tiết ở sau.
3.3. Cơ chế khung (generic)
Khung (generic) hay còn gọi là khuôn mẫu trong Java là một kỹ thuật lập trình
cho phép một lớp đối tượng có thể làm việc với nhiều kiểu dữ liệu khác nhau.
Chẳng hạn chúng ta có lớp đối tượng xử lý một danh móc nối, rõ ràng dữ liệu trong
danh sách tùy theo nhu cầu sử dụng có thể là số nguyên, số thực, xâu ký tự, hay các
đối tượng,...
Khi chúng ta xây dựng một lớp đối tượng có chứa yếu tố chưa xác định là các
kiểu dữ liệu thì được xem như là nó một khuôn mẫu. Tuy nhiên, yếu tố này bắt buộc
phải được xác định cụ thể sử dụng, khai thác tức là khi tạo ra đối tượng từ lớp.
Quy tắc tạo một lớp ở dạng generic như sau:

class tên_lớpdanh-sách-yếu-tố-chưa-xác-định {

<lập-trình-nội-dung-lớp>

}
Trong đó: các yếu tố chưa xác định được viết tên (thường là các chữ cái) để
phân biệt, chúng cách nhau dấu phẩy (,) và đặt bên trong cặp dấu lớn-nhỏ “<...>”.

Kỹ thuật lập trình hướng đối tượng - Bài 6 Trang 11


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Phần nội dung lập trình của lớp có sử dụng các yếu tố chưa xác định để triển khai
như là các kiểu dữ liệu (để khai báo biến, kiểu hàm, kiểu tham số hàm,...).
Ví dụ 6.3.3: Ví dụ tạo một lớp xử lý mảng có hàm tạo xác định độ lớn mảng,
hàm thêm phần tử, hàm lấy nội dung phần tử và xóa phần tử với kiểu phần tử là yếu
tố chưa xác định như sau (yếu tố chưa xác định “T” được quy định là kiểu lớp kế
thừa Object, vì trong Java tất cả các lớp đều phải được kế thừa từ Object).

class MyArray<T extends Object>{

T a[];

int size, n;

MyArray(int size){

this.size=size;

a = (T[])new Object[size]; n = 0;

boolean add(T x){

if(n<size){ a[n++] = x; return true; }

else return false;

boolean set(T x,int i){

if(i>=0&&i<n){ a[i] = x; return true; }

else return false;

T get(int i){

if(i>=0&&i<n) return a[i]; else return null;

T remove(int i){

Kỹ thuật lập trình hướng đối tượng - Bài 6 Trang 12


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

T x = get(i);

if(x!=null) n--;

return x;

}
Để sử dụng lớp dạng “generic” chúng ta phải quy định rõ cho yếu tố chưa xác
định của lớp tại nơi dùng. Chẳng hạn như lớp “MyArray” ở trên khi dùng có thể xác
định T là kiểu “String” thì,

MyArray<String> a = new MyArray<String>(10);


sẽ tạo đối tượng lớp “MyArray” với kích thước 10 và kiểu phần tử là “String”.
Đối tượng này sau đó được sử dụng, khai thác các thành phần (biến, hàm) như
những đối tượng bình thường khác. Chẳng hạn,

a.add("Nguyễn Văn An");

a.add("Trần Quốc Vượng");

a.add("Vũ Tiến Đại");

for(int i=0;i<a.n;i++){

System.out.printf("\n%s",a.get(i)); }

sẽ thêm 3 họ tên vào đối tượng và hiện ra màn hình danh sách họ tên đó.
Lớp “MyArray” ở trên có thể áp dụng với yếu tố “T” với mọi kiểu lớp có thể.
Rõ ràng, lớp ở dạng “generic” như là một khuôn mẫu để khai thác sử dụng đa dạng,
theo nhiều tình huống khác nhau dựa trên quy định kiểu cho yếu tố chưa xác định.
Ngoài ra, chúng ta có thể lập trình hàm (phương thức) trong lớp có chứa yếu tố
chưa xác định đóng vai trò kiểu dữ liệu cho hàm hoặc tham số. Quy tắc thực hiện
như sau:

yếu_tố_chưa_xác_định kiểu_hàm tên_hàm(tham_số_hàm){

nội-dung-của-hàm

Kỹ thuật lập trình hướng đối tượng - Bài 6 Trang 13


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Ví dụ sau lập trình hàm có yếu tố chưa xác định là T đóng vai trò là kiểu dữ
liệu của tham số.

class A{

static <T> void show(T a){

System.out.print(a);

}
Khi đó sử dụng hàm này với tham số a có kiểu bất kỳ. Chẳng hạn, các lệnh sau
sử dụng với T là kiểu int, double và String tương ứng.

A.show(2012);

A.show(15.7);

A.show("Hà Nội - Việt Nam");


Hệ thống thư viện Java cung cấp khá nhiều lớp ở dạng “generic”, có thể liệt kê
một số lớp cơ bản sau:

Vector<T>
- Lớp xử lý véc-tơ với kiểu phần tử chưa xác định;

ArrayList<T>
- Lớp xử lý mảng với kiểu phần tử chưa xác định;

Stack<T>
- Lớp xử lý cấu trúc dữ liệu ngăn xếp;

LinkedList<T>
- Lớp xử lý danh sách móc nối, lớp này có thể dùng như một hàng đợi (Queue)
vì nó implements từ giao diện Queue;

HashSet<T>
- Lớp xử lý tập hợp có kiểu phần tử chưa xác định và hỗ trợ dưới dạng bảng
băm;

TreeSet<T>

Kỹ thuật lập trình hướng đối tượng - Bài 6 Trang 14


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

- Lớp xử lý tập hợp có kiểu phần tử chưa xác định và hỗ trợ dưới dạng cây;

Iterator<T> hoặc ListIterator<T>


- Giao diện dùng để xác định dãy các phần tử dữ liệu để lặp trên các phần tử đó
trong quá trình xử lý;...
Ví dụ 6.3.4: Lập trình sử dụng lớp đối tượng LinkedList để nhập một dãy số
nguyên cho đến khi nhập 0 và hiện ra màn hình.

import java.util.Iterator;

import java.util.LinkedList;

import java.util.Scanner;

public class vidu_6_3_4 {

public static void main(String[] args) {

Scanner a = new Scanner(System.in);

LinkedList<Integer> b = new LinkedList<Integer>();

while(true){

System.out.print("Nhập số nguyên (0=stop):");

int x=a.nextInt();

if(x==0) break; else b.add(x);

Iterator<Integer> e = b.listIterator();

System.out.print("\nDãy số nguyên vừa nhập là:");

while(e.hasNext()) System.out.print(e.next()+" ");

}
Kết quả trên màn hình sẽ có dạng sau:

Kỹ thuật lập trình hướng đối tượng - Bài 6 Trang 15


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Kỹ thuật lập trình hướng đối tượng - Bài 6 Trang 16


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

BÀI 7: LẬP TRÌNH ĐỒ HỌA VÀ XỬ LÝ SỰ KIỆN

Mục tiêu:
Trong bài này, Anh/Chị cần đạt được những mục tiêu sau:
1. Kỹ thuật lập trình đa luồng.
2. Kỹ thuật Serialize/Deserialize trên các lớp đối tượng
3. Lập trình đồ họa (GUI) và xử lý sự kiện
Nội dung:

1. Kỹ thuật lập trình đa luồng


1.1. Khái niệm đa luồng
Luồng (hay còn gọi Thread) là quá trình trọn vẹn thực hiện một đơn vị chương
trình. Trong đó: quá trình trọn vẹn được hiểu kể từ khi bắt đầu thực hiện cho đến
khi kết thúc; đơn vị chương trình là một đoạn mã lệnh để thực hiện xử lý một công
việc nào đó, đơn vị chương trình này thường là một hàm.

Hàm xử lý
{A}

Gọ

Quá trình chạy luồng thực hiện hàm xử


lý {A}
Đa luồng (multi-thread) là kỹ thuật cho phép chương trình ứng dụng chạy
nhiều luồng đồng thời. Thực chất, khi mỗi luồng gắn với việc thực hiện một hàm thì
đa luồng là việc chạy nhiều hàm đồng thời bên trong chương trình. Khái niệm này
được chia sẽ từ khái niệm đa nhiệm (multi-task), bên trong hệ thống cho phép chạy
nhiều chương trình đồng thời. Khi đó, hệ thống máy tính sẽ phân chia tài nguyên và
điều phối đến các chương trình, các luồng đang cùng thực hiện để xử lý.
Hình vẽ minh họa sau cho thấy các thời điểm chạy với số các luồng khác nhau.
Thời điểm t1 chạy 2 luồng GUI và random, đến t2 chạy 3 luồng (có thêm query), đến
t3 chạy 4 luồng (có thêm plus),... hay thời điểm t6 chỉ chạy có 1 luồng là GUI.

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 1


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

t1 t2 t3 t4 t5

Để hiểu rõ hơn về đa luồng, chúng ta so sánh với đơn luồng thông qua ví dụ
sau. Trong lập trình, mặc định gọi các hàm xử lý là đơn luồng, tức khi một hàm
được gọi để chạy thì hàm đang thực hiện sẽ bị tạm dừng và chờ cho đến hàm được
gọi chạy xong mới tiếp tục.
Giả sử một chương trình có 3 hàm A, B và C, trong đó hàm A gọi đến B, C tại
2 thời điểm và hàm B gọi đến C (xem hình vẽ). Các đoạn chương trình trong các
hàm A, B, C được đánh số thứ tự (1), (2), (3), (4), (5), (6).

Bắt
đầu (1)  (4)  (6)  (5)  (2) 
(3)

Đơn
4) luồng
1)

6) Đa
2)
luồng
(1)   

Kết
thúc
Với trường hợp đơn luồng, sau khi thực hiện hết đoạn (1) trong A, có lệnh gọi
B thì hàm A tạm dừng và chuyển sang chạy B. Trong B, sau khi chạy đoạn (4) thì
có lệnh gọi C và hàm B tạm dừng chuyển sang chạy C. Thực hiện xong đoạn (6)
trong C sẽ quay về chạy tiếp đoạn (5) trong B đang bị tạm dừng trước đó, xong
đoạn (5) sẽ quay về chạy tiếp đoạn (2) trong A đang bị tam dừng do gọi B,... và cứ

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 2


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

tiếp tục cho đến khi kết thúc. Như vậy ta có lần lượt các đoạn chương trình được
thực hiện như trên hình vẽ là một dãy theo thứ tự tương ứng.
Đối với trường hợp đa luồng chúng ta có thể gọi nhiều hàm chạy đồng thời, tức
việc gọi một hàm không ảnh hưởng đến hàm đang thực chạy. Khi đó, trong sơ đồ
trên ta có các đoạn chương trình diễn ra trình tự sau (các đoạn chương trình trong
ngoặc { là đồng thời chạy, phần bị gạch là giả sử đã chạy hết). Xuất phát với hàm A
máy chạy đoạn (1), hết đoạn này có lệnh gọi hàm B sẽ chạy đoạn (4) và theo cơ chế
đa luồng nên vẫn tiếp tục chạy đoạn (2) của A, cứ như vậy cho đến khi kết thúc.
Có thể thấy, có chế đa luồng cho phép gọi chạy nhiều hàm đồng thời để thực
hiện nhiều công việc cùng lúc trong chương trình. Thậm chí, một hàm xử lý được
gọi nhiều lần đồng thời (xem hàm C ở trên) để chạy bên trong chương trình. Phần
tiếp theo, chúng ta xem xét phương pháp lập trình đa luồng trong Java.
1.2. Phương pháp lập trình đa luồng
Java cung cấp cơ chế lập trình đa luồng dựa trên các lớp đối tượng và giao diện
gồm:

Thread
- Lớp dùng để tạo, quản lý và điều khiển chạy luồng.

Runnable
- Giao diện dùng để lập trình hàm xử lý đa luồng, hàm này sẽ được gọi chạy
đồng thời với các luồng khác.
Mỗi luồng trong Java được nghĩa các trạng thái trong quá trình chạy (hay gọi là
vòng đời) gồm các giai đoạn sau (xem hình vẽ):

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 3


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

- Trạng thái khởi tạo: khi tạo đối tượng Thread để thực hiện đa luồng;
- Trạng thái sẵn sàng để chạy đa luồng: khi đối tượng Thread đã được cấp phát
tài nguyên của hệ thống phục vụ cho việc chạy đa luồng;
- Trạng thái đang chạy: khi gọi hàm xử lý đa luồng;
- Trạng thái chờ: khi đối tượng Thread đang yêu cầu bị tạm dừng, luông sẽ tạm
dừng theo thời gian hoặc theo trạng thái đóng/mở;
- Trạng thái kết thúc: khi gọi lệnh kết thúc luồng hoặc kết thúc thực hiện hàm
xử lý luồng.
Trong Java chúng ta có thể triển khai lập trình đa luồng bằng 2 cách: thứ nhất,
sử dụng lớp Thread để kế thừa và viết nội dung hàm xử lý luồng có tên là “run”.
Sau đó tạo đối tượng để chạy luồng;

Thư viện của Chương trình ứng

Thre

ru exten T1
n()
ru
{
n() n

{

/*Bước 1: Xây dựng lớp kế thừa Thread với hàm run */

class T1 extends Thread {

public void run(){

<lập-trình-nội-dung-hàm-xử-lý-luồng>

/*Bước 2: Tạo đối tượng chạy luồng*/

new T1().start();

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 4


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Thứ hai, sử dụng giao diện Runnable để xây dựng lớp và viết nội dung hàm xử
lý luồng cũng có tên là “run”. Sau đó tạo đối tượng lớp này cùng với đối tượng
Thread để gắn kết với nhau cho việc chạy luồng.

Thư viện của Chương trình ứng

Thre
n 

T2 Liê
Run ru n kết với

imple n() n
r {
un()

/*Bước 1: Xây dựng lớp thực thi Runnable với hàm run */

class T2 implements Runnable {

public void run(){

<lập-trình-nội-dung-hàm-xử-lý-luồng>

/*Bước 2: Tạo đối tượng cùng với Thread để chạy luồng*/

new Thread(new T1()).start();


Ví dụ 7.1.1: Lập trình 2 luồng (một luồng in các số từ 1 đến 10 và luồng còn lại
in các số từ 10 về 1) bằng 2 cách trên.

class T1 extends Thread{

public void run(){

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

System.out.printf("[T1=%d]",i);

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 5


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

try{ sleep(50); }catch(Exception e){}

class T2 implements Runnable{

public void run(){

for(int i=10;i>=1;i--){

System.out.printf("[T2=%d]",i);

try{ Thread.sleep(50); }catch(Exception e){}

public class vidu1 {

public static void main(String[] args) {

new T1().start();

new Thread(new T2()).start();

}
Trong ví dụ có sử dụng lệnh tạm dừng luồng Thread.sleep(...) để quan sát khi in
ra. Vì áp dụng đa luồng nên kết quả chạy sẽ thấy cả giá trị in của luồng T1 & T2
xen lẫn nhau trên màn hình, như sau:

1.3. Cơ chế đồng bộ giữa các luồng

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 6


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Khi các luồng cùng đồng thời thực hiện và cùng truy xuất đến một tài nguyên
thì có thể dẫn tính không nhất quán đối với việc truy xuất tài nguyên đó. Chẳng hạn,
hai luồng T1 & T2 cùng xử lý đến một tệp tin trên ổ đĩa, T1 đang mở tệp để cập
nhật dữ liệu trong khi T2 mở tệp để đọc dữ liệu. Nếu T1 chưa cập nhật xong (giả sử
mới lưu được nửa đầu tệp) mà T2 lại đọc tệp thì dữ liệu đọc của T2 sẽ không nhất
quán (nửa đầu đã được cập nhật, nửa còn lại chưa cập nhật) (xem hình vẽ).

Tệp
tin
Luồn Luồn
g T1 g T2
t1) t1) Mở tệp
Mở tệp t2) Đọc
t2) Lưu dữ toàn bộ
liệu vào
nửa đầu
t3) Lưu dữ
Để thực hiện đồng bộ trong việc truy xuất tài nguyên khi lập trình đa luồng,
Java cung cấp phương pháp “synchronized” trên phương thức hoặc trên đoạn
chương trình đối với một đối tượng cụ thể.
Đối với việc đồng bộ trên một phương thức ta thực hiện:

synchronized kiểu-hàm tên-hàm( tham-số ){

lập-trình-nội-dung-hàm

}
Khi đó, việc gọi đến hàm này trên một đối tượng từ các luồng sẽ được đồng bộ.
Tức là khi một luồng đang chạy hàm trên một đối tượng thì các luồng khác phải chờ
cho đến khi hàm được thực hiện xong mới có thể gọi chạy hàm này được.
Đối với đồng bộ trên một đoạn mã lệnh đối với một đối tượng ta sử dụng quy
tắc:

synchronized( đối-tượng ){

đoạn-chương-trình-xử-lý-cần-đồng-bộ

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 7


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Khi đó, các luồng nếu cùng chạy xử lý đoạn mã lệnh trên sẽ được đồng bộ. Tức
là khi một luồng đang chạy đoạn chương trình trên với đối tượng xử lý tương ứng
thì các luồng khác phải chờ cho đến khi đoạn mã lệnh được chạy xong mới có thể
tiếp tục chạy đoạn chương trình đó ở các luồng khác.
Ví dụ 7.1.2: Lập trình 2 luồng chạy trên một đối tượng đếm và in ra màn hình
số đếm trên một hàm “print” được áp dụng cơ chế đồng bộ.

public class vidu1 {

public static void main(String[] args) {

A a = new A();

new T1(a,"T1").start();

new T1(a,"T2").start();

class A{

int c=0;

void print(){

synchronized (this)

for(int i=0;i<5;i++){

c += i;

System.out.printf("\nThread[%s](counter=%d)",

Thread.currentThread().getName(),c);

yield();

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 8


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

class T1 extends Thread{

A a = null;

T1(A a,String name){ super(name); this.a=a; }

public void run(){

for(int i=0;i<10;i++){

a.print();

yield();

}
Hàm “print” trong đối tượng lớp A trên được đồng bộ do đó khi chạy hai luồng
thì hàm này luôn được thực hiện xong trên một luồng rồi mới chạy cho luồng khác.
Lệnh “yield()” kích hoạt các luồng khác cùng đồng thời chạy. Kết quả trên màn
hình sẽ luôn có bộ 5 giá trị của mỗi luồng được in ra liền nhau (không bị xen kẽ
giữa các luồng trên hàm này). Kết quả trên màn hình là:

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 9


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Trường hợp bỏ cơ chế đồng bộ hàm “print” đến đối tượng lớp A thì kết quả sẽ
không đủ bộ 5 giá trị được in ra cho mỗi lần hàm “print” được chạy (xen lẫn các giá
trị in ra của hàm “print” trên các luồng),

2. Kỹ thuật Serialize/Deserialize trên các lớp đối tượng


Serialize là một kỹ thuật trong Java cho phép lập trình thực hiện cơ chế vào/ra
dữ liệu trên các đối tượng một cách thuận tiện. Trong đó, nội dung của một đối
tượng được biểu diễn thành một chuỗi byte nhớ liên tiếp, các thao tác xử lý vào/ra
dữ liệu trên đối tượng sẽ thực hiện dưới dạng chuỗi byte.
Chẳng hạn hình vẽ sau cho thấy việc trao đổi các đối tượng giữa máy trạm
(client) với máy chủ (server) được thực hiện thông qua có chế serialize với chuỗi
byte nhớ biểu diễn cho các đối tượng cần trao đổi đó.

Đối với việc vào/ra đối tượng trên tệp tin cũng tương tự, hình vẽ sau minh họa
cơ chế xuất đối tượng ra file và ngược lại đọc đối tượng từ file.

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 10


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Serializa Deseriali
tion zation

Như trên hình vẽ ta thấy, thao tác ngược lại của việc lưu tệp hay xuất đối tượng
ra thiết bị ngoài được gọi là deserialized. Tức là chuyển chuỗi byte biểu diễn về
dạng đối tượng ban đầu.
Java cung cấp giao diện “Serializable” để mọi lớp đối tượng đều có thể thực thi
(implements) nhằm thực hiện cơ chế này. Khi các lớp có thực thi giao diện thì
chúng ta có thể thực hiện các phương thức đọc/ghi đối tượng trên các dòng
nhập/xuất dữ liệu ObjectOutputStream () và ObjectInputStream (). Cụ thể:

.writeObject(  ); //ghi đối tượng

.readObject(); //đọc đối tượng


Lệnh đọc đối tượng cần phải ép kiểu về kiểu lớp tương ứng với đối tượng cần
xử lý.
Ví dụ 7.2.1: Lập trình áp dụng cơ chế Serialized và Deserialized để đọc và ghi
dữ liệu đối tượng trên tệp tin.
- Lớp xử lý thông tin cá nhân:

import java.io.Serializable;

public class PersonDetails implements Serializable {

private String name;

private int age;

private String sex;

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 11


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

public PersonDetails(String name, int age, String sex) {

this.name = name;

this.age = age;

this.sex = sex;

public int getAge() { return age; }

public void setAge(int age) { this.age = age; }

public String getName() { return name; }

public void setName(String name) { this.name = name; }

public String getSex() { return sex; }

public void setSex(String sex) { this.sex = sex; }

}
- Lớp xử lý lưu tệp:

public class PersonPersist {

public static void main(String[] args) {

String filename = "person.txt";

PersonDetails person1 = new PersonDetails("hemanth",10, "Male");

PersonDetails person2 = new PersonDetails("bob", 12, "Male");

PersonDetails person3 = new PersonDetails("Richa", 10, "Female");

List list = new ArrayList();

list.add(person1);

list.add(person2);

list.add(person3);

FileOutputStream fos = null;

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 12


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

ObjectOutputStream out = null;

try {

fos = new FileOutputStream(filename);

out = new ObjectOutputStream(fos);

out.writeObject(list);

out.close();

System.out.println("Object Persisted");

} catch (IOException ex) {

ex.printStackTrace();

}
- Lớp xử lý đọc tệp:

import java.io.FileInputStream;

import java.io.IOException;

import java.io.ObjectInputStream;

import java.util.ArrayList;

import java.util.List;

public class GetPersonDetails {

public static void main(String[] args) {

String filename = "person.txt";

List pDetails = null;

FileInputStream fis = null;

ObjectInputStream in = null;

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 13


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

try {

fis = new FileInputStream(filename);

in = new ObjectInputStream(fis);

pDetails = (ArrayList) in.readObject();

in.close();

} catch (IOException ex) {

ex.printStackTrace();

} catch (ClassNotFoundException ex) {

ex.printStackTrace();

// print out the size

System.out.println("Person Details Size: "

+ pDetails.size());

System.out.println();

3. Lập trình đồ họa (GUI) và xử lý sự kiện


Các ngôn ngữ lập trình hiện nay cung cấp các đối tượng đồ họa, chúng có thể
được điều khiển bởi người lập trình, hay bởi người sử dụng. Một trong số những kết
quả quan trọng nhất chính là các ngôn ngữ hiện nay được dựa trên Giao diện người
dùng đồ họa (Graphical User Interface - GUI). Chương này cung cấp cho sinh viên
những kiến thức cơ bản để xây dựng giao diện (Graphic User Interface - GUI) của
chương trình ứng dụng bằng ngôn ngữ java:
 Các nguyên tắc thiết kế giao diện.
 Các thư viện, gói xây dựng giao diện: gồm lớp (class), giao diện
(interface) quản lý sự kiện và thành phần (components) xây dựng nên
giao diện người dùng.

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 14


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

 Bộ quản lý các hình thức trình bày (layout managers).


 Xử lý sự kiện.
GUI cung cấp chức năng nhập liệu theo cách thân thiện với người dùng. GUI
đa dạng từ ứng dụng đến ứng dụng và có thể chứa nhiều điều khiển như hộp văn
bản, nhã, hộp danh sách hay các điều khiển khác. Các ngôn ngữ lập trình khác nhau
cung cấp nhiều cách khác nhau để tạo GUI. Các ngôn ngữ như VB hay VC++ có
thể cung cấp chức năng kéo và thả trong khi đó phần mềm giống như C++ yêu cầu
người lập trình phải viết toàn bộ mã để xây dựng GUI.
Một thành phần (Component) GUI là một đối tượng trực quan. Người dùng
tương tác với đối tượng này thông qua con trỏ chuột hay bàn phím. Các thành phần
như là button, label v.v… có thể được nhìn thấy trên màn hình. Bất kỳ cái gì chung
cho tất cả các thành phần GUI đều được tìm thấy trong lớp Component. Để tạo các
đối tượng GUI chúng ta cần nhập gói java.awt.
3.1. Thư viện AWT và SWING
a) AWT (Abstract Windowing Toolkit)
AWT (Abstract Windowing Toolkit) là bộ thư viện dùng để xây dựng giao diện
người dùng cho một chương trình ứng dụng có đầy đủ các thành phần cơ bản như:
Label, Button, Checkbox, Radiobutton, Choice, List, Text Field, Text Area,
Scrollbar, Menu, Frame… Giống như các API của Windows, java cung cấp cho
người lập trình thư viện awt. Nhưng khác với các hàm API, thư viện awt không phụ
thuộc hệ điều hành.

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 15


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Cấu trúc gói AWT được minh họa như hình sau:

Compo
nents

B Chec L C Ca
utton kBox abel hoice nvas

Cont TextComp
ainer onent

Pane Win Text Text


l dow Field Area

Appl F Di
et rame alogs
Hình 7.3.1a: Cấu trúc gói AWT
AWT là một bộ các lớp trong Java cho phép chúng ta tạo GUI và chấp nhận các
nhập liệu của người dùng thông qua bàn phím và chuột. AWT cung cấp các thành
phần khác nhau để tạo GUI hiệu quả và lôi cuốn người sử dụng. Các thành phần
này này có thể là:
 Container
 Component
 Layout manager
 Graphic
 Font
 Event
Hình sau đây mô tả một phần của hệ thống phân cấp lớp AWT:

Object

CheckboxGroup MenuComponent BorderLayout

Component FlowLayout GridLayout

Hình 7.3.1b: Hệ thống cây phân cấp lớp AWT

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 16


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

b) SWING
Swing là bộ công cụ GUI thế hệ kế tiếp mà Sun Microsystems tạo ra cho phép
môi trường phát triển enterprise trong Java. Bằng môi trường phát triển enterprise,
chúng ta hiểu rằng, các lập trình viên có thể sử dụng Swing để tạo ra các ứng dụng
Java có khả năng mở rộng với một dãy nhiều thành phần mạnh mẽ. Thêm vào đó,
bạn có thể kế thừa hoặc chỉnh sửa những thành phần này để điều khiển việc hiển thị
và các hành xử của chúng.
Swing là một tập hợp các thành phần giao diện bao gồm các thành phần đơn
giản nhất như các label, button tới các thành phần phức tạp như table, tree. Hầu hết
các thành phần giao diện trong swing đều kế thừa từ Jcomponent. Bản thân
JComponent lại kế thừa từ java.awt.Container. Đa số các component có trong awt
đều có trong swing, và tên của các component tương ứng sẽ có chử J đứng trước.
Một số component của swing:
– JComponent
– JLabel
– JButton
– JList
– JMenuBar
– JOptionPane
– JPanel
– JFrame
– JApplet
– …
Trong chương này, ta sẽ tìm hiểu các thành phần, lớp đối tượng của awt, sau
khi nắm được các khái niệm về các đối tượng cũng như các kỹ thuật cơ bản xử lý
trên các đối tượng có trong awt, bạn đọc có thể tự tìm hiểu về swing.
3.2. Các thành phần của AWT
a) Lớp Container
Container là đối tượng vật chứa hay những đối tượng có khả năng quản lý và
nhóm các đối tượng khác lại. Ta có thể hiểu Container là vùng mà bạn có thể đặt
các thành phần giao diện của bạn vào đó. Bất cứ vật gì mà kế thừa từ lớp Container
sẽ là vật chứa. Applet là một vật chứa, applet được dẫn xuất từ Panel, lớp Panel lại
được dẫn xuất từ lớp Container.

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 17


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Một vật chứa có thể chứa nhiều phần tử, các phần tử này có thể được vẽ hay
được tô màu tuỳ thích. Bạn hãy xem vật chứa như một cửa sổ. Như khung (frame),
pane, latch, hook, và các thành phần có kích thước nhỏ hơn khác.
Gói java.awt chứa một lớp gọi là Container. Lớp này trực tiếp hay gián tiếp
phái sinh ra hai vật chứa được sử dụng phổ biến nhất là Frame và Panel.
Frame và Panel là các vật chứa thường được sử dụng. Frame là cửa sổ độc lập
nhưng ngược lại Panel là vùng nằm trong cửa sổ khác. Panel không có các đường
biên, chúng được trình bày trong một cửa sổ do trình duyệt hay appletviewer cung
cấp. Appletviewer là một công cụ được JDK hỗ trợ để xem các applet. Frame là lớp
con của Window. Chúng được trình bày trong một cửa sổ độc lập, cửa sổ này có
chứa các đường biên xung quanh.
Một số đối tượng Container trong Java: Panel, Frame, Dialogs,
ScrollPanes,…Sau đây ta sẽ tìm hiểu chi tiết hơn về các đối tượng này.
 Frame
Frame không phụ thuộc vào applet và trình duyệt. Frame có thể hoạt động như
một vật chứa hay như một thành phần (component). Bạn có thể sử dụng một trong
những hàm tạo (constructor) sau để tạo một frame:
Frame(): hàm tạo không đối, dùng để tạo một frame nhưng không hiển thị
(invisible).
Frame(String title): hàm tạo có một đối số kiểu String, tạo một frame không
hiển thị, có tiêu đề.

 Ví dụ: 7.3.2.1: Hiển thị một Frame trên cửa sổ:


import java.awt.*;
import java.awt.event.*;
class FrameDemo extends Frame
{
public FrameDemo(String title)
{
super(title);
}
public static void main(String args[])
{
FrameDemo myFrame=new FrameDemo("Frame Demo");

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 18


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

myFrame.setSize(300,200);
myFrame.setVisible(true);
myFrame.setBackground(Color.BLUE );
myFrame.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent we)
{
System.exit(0);
}
});
}
}
Kết quả chương trình:

 Panel
Panel được sử dụng để nhóm một số các thành phần lại với nhau. Cách đơn
giản nhất để tạo một panel là sử dụng phương thức khởi tạo của nó, hàm tạo không
đối Panel(). Panel không thể được nhìn thấy trực tiếp. Do đó, chúng ta cần thêm
panel đến một frame. Vì vậy ta cần tạo một frame mới và thêm Panel mới được tạo
này vào đó.

 Ví dụ: 7.3.2.2: Hiển thị một Panel trên cửa sổ:


import java.awt.*;
import java.awt.event.*;
class PanelDemo extends Panel
{
public static void main(String args[])

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 19


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

{
PanelDemo myPanel=new PanelDemo();
myPanel.setBackground(Color.red );
Frame myFrame=new Frame("Panel Demo");
myFrame.add(myPanel);
myFrame.setSize(300,200);

myFrame.setVisible(true);
myFrame.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent we)
{
System.exit(0);
}
});
}
}
Kết quả chương trình:

Đối với khung chứa Panel thì các Panel có thể lồng vào nhau, vì vậy khung
chứa Panel thường được dùng để bố trí các nhóm components bên trong một khung
chứa khác.
 Dialog
Dialog là một lớp khung chứa tựa Frame và còn được gọi là popup window.
Lớp Dialog tương tự như lớp Frame, nghĩa là Dialog là lớp con của lớp window.
Cửa sổ dạng này thường được dùng để đưa ra thông báo, hay dùng để lấy dữ liệu
nhập từ ngoài vào thông qua các đối tượng, thành phần trên dialog như TextField.
Dialog cũng là một cửa sổ nhưng không đầy đủ chức năng như đối tượng khung
chứa Frame.

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 20


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

 Ví dụ: 7.3.2.3: Hiển thị một một Dialog trên cửa sổ, người dùng phải đóng
Dialog này trước nếu muốn chuyển sang chức năng khác.
Frame myframe=new Frame(“My frame”); //Tạo frame với tiêu
để (“My frame”
String title = “Title”;
boolean modal = true; //Nhận giá trị true hoặc false
Dialog dlg=new Dialog(myframe, title, modal);
Tham số modal chỉ ra rằng dialog sẽ ngăn chặn bất kỳ tương tác nào xảy đến
với các cửa sổ được mở khác, trong khi dialog đang được hiển thị trên màn hình.
Kiểu hộp thoại này ngăn chặn người dùng tương tác với các cửa sổ khác (của cùng
ứng dụng) trên màn hình, cho tới khi dialog được đóng lại.
 ScrollPanes
ScrollPanes là một khung chứa tương tự khung chứa Panel, nhưng có thêm 2
thanh trượt giúp ta tổ chức và xem được các đối tượng lớn choán nhiều chỗ trên
màn hình như những hình ảnh hay văn bản nhiều dòng.

 Ví dụ: 7.3.2.4: Hiển thị một một TextArea nằm trong một khung chứa
ScrollPanes.
import java.awt.*;
import java.awt.event.*;
class ScrollPaneDemo01
{
public static void main(String args[])
{
Frame myFrame = new Frame("My frame");
ScrollPane mySP=new ScrollPane();
TextArea myTextArea=new TextArea();
mySP.add(myTextArea);
myFrame.add(mySP);
myFrame.setSize(400,300);
myFrame.setVisible(true);
myFrame.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent we)
{

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 21


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

System.exit(0);
}
});
}
}
Kết quả chương trình:

b) Lớp Component
Component là một đối tượng có biểu diễn đồ họa được hiển thị trên màn hình
mà người dùng có thể tương tác được, ví dụ như các điều khiển button, checkbox,
scrollbar,… Lớp Component là một lớp trừu tượng.
TextField
TextComponent
TextArea
Button

C Label
o
m
Checkbox
p
o
n List
e
n Choice
t Panel Applet
Container
Window Frame
Canvas
Dialog
Scrollbar

Hình 7.3.2a: Mô hình phân lớp lớp Component


Một số phương thức của Component:
 void setVisible(boolean): hiển thị hoặc ẩn component
 Dimension getSize(): trả về kích thước của component
 void setSize(Dimension): thay đổi kích thước
 void setEnabled(): “bật” hoặc “tắt” component

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 22


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

 void repaint(): cập nhật lại component


 void update(Graphics g): được gọi qua repaint()
 void paint(Graphics g): được gọi qua update()
 void setBackground(Color): đặt màu nền
Lớp Container trong gói java.awt có 2 class phổ biến nhất là Frame và Panel.
Frame là một cửa sổ tách biệt và có border. Panel là một vùng chứa không có
border và nó được chứa trong một cửa sổ.
Một số điều khiển của lớp Component:

 Label
Lớp này được sử dụng để hiển thị một xâu văn bản (String). Nó không thể được
sửa đổi. Sử dụng một trong những hàm tạo (constructor) sau đây để tạo một label:
Label() //Tạo một Label rỗng.
Label(String labeltext) //Tạo một Label với nội dung truyền vào.
Label(String labeltext, int alignment) //Tạo một Label với một chế độ căn
lề alignment, có thể là Label.LEFT, Label.RIGHT hay Label.CENTER.
Các phương thức được sử dụng phổ biến của label được trình bày ở bảng bên
dưới:
Phương thức Chức năng
setFont(Font f) Thay đổi phông chữ đang được chọn của Label
setText(String s) Thiết lập nhãn cho Label
getText() Lấy nội dung hiện hành của Label
Bảng 7.3.2.1: Các phương thức của Label

 Ví dụ 7.3.2.5: Hiển thị một label có nội dung "Label Test" giữa cửa sổ ứng dụng.
import java.awt.*;
import java.awt.event.*;
class LabelTest extends Frame
{
Label label1=new Label("Label Test",Label.CENTER);
public LabelTest(String title)
{ super(title);
add(label1);
}

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 23


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

public static void main(String args[])


{
LabelTest myLabel =new LabelTest("Label");
myLabel.setSize(300,200);
myLabel.show();
myLabel.addWindowListener(new WindowAdapter()
{ public void windowClosing(WindowEvent we)
{ System.exit(0);
}
});
}
}
Kết quả chương trình:

 TextField
Một textfield là một vùng chỉ chứa một dòng đơn, trong đó văn bản có thể được
trình bày hay được nhập vào bởi người dùng. Trong Java, một trong những
constructor sau có thể được sử dụng để tạo một textfield:
 TextField(): Tạo một textfield mới.
 TextField(int columns): Tạo một textfield mới với số cột được cho.
 TextField(String s): Tạo một textfield mới với chuỗi văn bản được cho.
 TextField(String s, int columns): Tạo một textfield mới với nhãn và số
cột được cho.
Các phương thức thường được sử dụng của đối tượng TextField được tóm tắt
trong bảng sau:
Phương thức Chức năng
setEchoChar(char) Thiết lập các kí tự được trình bày trong dạng của
một kí tự được cho.
setText(String s) Thiết lập nhãn cho TextField.

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 24


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

getText() Trả về nhãn của TextField.


setEditable(boolean) Xác định trường có thể được soạn thảo hay không.
Trường chỉ được soạn thảo khi giá trị này được
đặt là True.
isEditable() Xác định xem trường có đang trong mode soạn
thảo hay không. Giá trị trả về kiểu Boolean.
Bảng 7.3.2.2: Các phương thức của TextField

 Ví dụ 7.3.2.6: Hiển thị một TextField trên cửa sổ, người sử dụng có thể nhập dữ
liệu vào TextField này.
import java.awt.*;
import java.awt.event.*;
class TextFieldTest extends Frame
{
TextField tf1=new TextField("text",30);
public TextFieldTest(String title)
{
super(title);
setLayout(new FlowLayout());
add(tf1);
}
public static void main(String args[])
{
TextFieldTest myTextField=new TextFieldTest("TextField Test");
myTextField.setSize(300,200);
myTextField.show();
myTextField.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent we)
{
System.exit(0);
}
});
}
}

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 25


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

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

 TextArea
Một Textarea được sử dụng khi văn bản nhập vào trên hai hay nhiều dòng.
Textarea có một scrollbar. Thành phần TextArea là một trường văn bản có thể được
soạn thảo với đặc tính nhiều dòng.
Để tạo một Textarea, làm theo các bước sau:
 Tạo một phần tử (đối tượng TextArea).
 Chỉ ra số dòng hay số cột phần tử này cần có.
 Bố trí phần tử này trên màn hình.
Trong Java, bạn có thể sử dụng các constructor sau để tạo TextArea:
TextArea(): Tạo một TextArea mới.
TextArea(int rows, int cols): Tạo một TextArea mới với số lượng cột và

dòng được cho.


TextArea(String text): Tạo một TextArea mới với nhãn được cho.
TextArea(String text, int rows, int cols): Tạo một TextArea mới với nhãn,

số dòng và số cột được cho.


Các phương thức thường được sử dụng nhiều nhất của TextArea:
Phương thức Chức năng
setText(String) Thiết lập nhãn cho TextArea.
getText() Trả về nhãn của TextArea.
setEdiable(boolean) Xác định xem trường có thể được soạn thảo
hay không. Trường có thể được soạn thảo
khi giá trị này là True.
isEdiable() Xác định xem trường có đang trong mode

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 26


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

soạn thảo được không. Trả về giá trị là kiểu


Boolean.
insertText(String, int) Chèn String được cho vào vị trí index được
cho.
replaceText(String, int, int) Thay thế văn bản nằm giữa vị trí int, int
được cho.
Bảng 7.3.2.3: Các phương thức của TextArea

 Ví dụ 7.3.2.7: Hiển thị một TextArea trên cửa sổ, người sử dụng có thể nhập dữ
liệu vào TextArea này. Dữ liệu có thể được nhập trên nhiều dòng.
import java.awt.*;
import java.awt.event.*;
class TextAreaTest extends Frame
{
TextArea ta1=new TextArea("Type text here",5,30);
public TextAreaTest(String title)
{
super(title);
setLayout(new FlowLayout());
ta1.setEditable(true);
add(ta1);
}
public static void main(String args[])
{ TextAreaTest myTextArea=new TextAreaTest("TextArea Test");
myTextArea.setSize(300,200);
myTextArea.show();
myTextArea.addWindowListener(new WindowAdapter()
{ public void windowClosing(WindowEvent we)
{ System.exit(0);
}
});
}
}
Kết quả chương trình:

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 27


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

 Button
Nút nhấn hay còn gọi là nút lệnh là một phần nguyên của bất kỳ GUI nào. Sử
dụng button là cách dễ nhất để chặn các tác động của người dùng.
Để tạo một button, bạn làm theo các bước sau:
 Tạo phần tử button với một nhãn chỉ ra mục đích của button.
 Bố trí phần tử này trên màn hình.
 Hiển thị phần tử trên màn hình.
Sử dụng một trong hai constructor sau để tạo các button trong Java:
Button() //Hàm tạo không đối số
Button(String text) //Hàm tạo nút lệnh với 1 đối số tiêu đề
Sử dụng các phương thức setLabel() và getLabel() để thiết lập và nhận về nhãn của
button.

 Ví dụ: 7.3.2.8: Hiển thị 3 nút lệnh (button) trên cửa sổ ứng dụng.
import java.awt.Button;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.event.*;
class ButtonTest extends Frame
{
Button b1 = new Button("red");
Button b2 = new Button("Green");
Button b3 = new Button("Blue");

public ButtonTest(String title)


{
super(title);

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 28


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

setLayout(new FlowLayout());
add(b1);
add(b2);
add(b3);
}
public static void main(String args[])
{
ButtonTest myButton= new ButtonTest("Button");
myButton.setSize(300,200);
myButton.show();
myButton.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent we)
{
System.exit(0);
}
});
}
}
Kết quả chương trình:

 Checkbox và RadioButton
Checkbox được sử dụng khi người dùng tiến hành chọn một hay nhiều tùy
chọn. Người dùng phải click trên các checkbox để chọn hay bỏ chọn chúng. Một
radiobutton cũng tương tự như một checkbox. Nó được sử dụng như một option
button để xác định các chọn lựa. Bạn có thể chỉ chọn một button trong nhóm các nút
radiobutton, ngược lại bạn có thể chọn nhiều hơn một checkbox tại một thời điểm.
Làm theo các bước sau để tạo các checkbox hay radiobutton:
 Tạo phần tử.

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 29


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

 Quyết định trạng thái khởi đầu của phần tử (chọn hay không chọn).
 Bố trí các phần tử trên màn hình.
 Hiển thị các phần tử trên màn hình.
Thành phần checkbox có thể sử dụng một lớp phụ được gọi là CheckboxGroup để
tạo ra các radiobutton.
Sử dụng các constructor sau để tạo các checkbox trong Java:
Checkbox(): Tạo một checkbox trống.
Checkbox(String text): Tạo một checkbox với nhãn được cho.
Để tạo các radiobutton, đầu tiên ta tạo đối tượng CheckboxGroup như sau:
CheckboxGroup cg=new CheckboxGroup();
Sau đó chúng ta tạo các button, như chỉ ra dưới đây:
Checkbox male=new Checkbox(“male”, cg, true);
Checkbox female=new Checkbox(“female”, cg, false);
Chúng ta sử dụng các phương thức setState() và getState() để thiết lập và nhận về
trạng thái của checkbox.

 Ví dụ: 7.3.2.9: Hiển thị 3 mục chọn (Checkbox) trên cửa sổ ứng dụng. Người sử
dụng có thể chọn một hoặc nhiều hoặc không chọn mục nào.
import java.awt.*;
import java.awt.event.*;
class CheckboxTest extends Frame
{
Label l1=new Label("Color:");
Checkbox b1=new Checkbox("Red",false);
Checkbox b2=new Checkbox("Green",false);
Checkbox b3=new Checkbox("Blue",false);
public CheckboxTest(String title)
{
super(title);
setLayout(new GridLayout(8,1));
add(l1);
add(b1);
add(b2);

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 30


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

add(b3);
}
public static void main(String args[])
{
CheckboxTest myCheckBox=new CheckboxTest("Checkbox Test");
myCheckBox.setSize(300,200);
myCheckBox.show();
myCheckBox.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent we)
{
System.exit(0);
}
});
}
}
Kết quả chương trình:

 Ví dụ: 7.3.2.10: Hiển thị 3 mục chọn (RadioButton) trên cửa sổ ứng dụng. Người
sử dụng chỉ có thể chọn tối đa một mục.
import java.awt.*;
import java.awt.event.*;
class CheckboxTest extends Frame
{
Label l1=new Label("Color:");
CheckboxGroup cbg=new CheckboxGroup();
Checkbox b1=new Checkbox("Red",cbg,false);

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 31


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Checkbox b2=new Checkbox("Green",cbg,false);


Checkbox b3=new Checkbox("Blue",cbg,false);
public CheckboxTest(String title)
{
super(title);
setLayout(new GridLayout(8,1));
add(l1);
add(b1);
add(b2);
add(b3);
}
public static void main(String args[])
{
CheckboxTest myCheckBox=new CheckboxTest("Checkbox Test");
myCheckBox.setSize(300,200);
myCheckBox.show();
myCheckBox.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent we)
{
System.exit(0);
}
});
}
}
Kết quả chương trình:

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 32


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

 Choice List
Thỉnh thoảng, rất cần thiết để trình bày một danh sách các chọn lựa đến người
dùng trên một GUI. Người dùng có thể click vào một hay nhiều item từ danh sách.
Một danh sách chọn lựa được tạo bằng cách sử dụng một số các chuỗi (String) hay
các giá trị văn bản.
Để tạo các danh sách chọn lựa, hãy làm theo các bước được cho sau đây:
 Tạo danh sách các phần tử.
 Thêm các item (có kiểu là String) vào danh sách, mỗi lần chỉ thêm được
một item.
 Bố trí danh sách trên màn hình.
 Hiển thị danh sách trên màn hình.
Java hỗ trợ lớp Choice cho phép chúng ta tạo các danh sách chứa nhiều item. Khi
danh sách vừa được tạo ra, nó sẽ rỗng.
Choice myChoice = new Choice();
Mỗi thời điểm chỉ thêm được một item bằng cách sử dụng phương thức addItem
như được chỉ ra bên dưới:
myChoice colors.addItem(“Red”);
myChoice colors.addItem(“Green”);

 Ví dụ: 7.3.2.11: Hiển thị một ChoiceList với các tháng trong năm:
import java.awt.*;
import java.awt.event.*;
class ChoiceListTest extends Frame
{
Label l1=new Label("Chọn tháng:");
Choice months=new Choice();
public ChoiceListTest(String title)
{
super(title);
setLayout(new FlowLayout());
l1.setFont(new java.awt.Font("Times New Roman",1,13));
add(l1);
for (int i=1;i<=12;i++)

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 33


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

months.addItem("Tháng "+i);
add(months);
}
public static void main(String args[])
{
ChoiceListTest myChoiceList=new ChoiceListTest("ChoiceList
Test");
myChoiceList.setFont(new java.awt.Font("Times New
Roman",1,13));
myChoiceList.setSize(300,200);
myChoiceList.show();
myChoiceList.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent we)
{
System.exit(0);
}
});
}
}
Kết quả chương trình:

c) Lớp Layout manager


Layout manager điều khiển cách trình bày vật lý của các phần tử GUI như là
button, textbox, option button v.v… Một layout manager tự động bố trí các thành

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 34


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

phần này trong container. Khung chứa container nhận các đối tượng từ bên ngoài
đưa vào và nó phải biết làm thế nào để tổ chức sắp xếp “chỗ ở” cho các đối tượng
đó. Mỗi đối tượng khung chứa đều có một bộ quản lý chịu trách nhiệm thực hiện
công việc đấy đó là bộ quản lý trình bày (Layout Manager). Các bộ quản lý trình
bày mà thư viện AWT cung cấp cho ta bao gồm:
 FlowLayout: Sắp xếp các đối tượng từ trái qua phải và từ trên xuống dưới.
Các đối tượng đều giữ nguyên kích thước của mình.
 BorderLayout: Các đối tượng được đặt theo các đường viền của khung
chứa theo các cạnh West, East, South, North và Center tức Đông, Tây,
Nam, Bắc và Trung tâm hay Trái, Phải, Trên, Dưới và Giữa tùy theo cách
nhìn của chúng ta.
 GridLayout: Tạo một khung lưới vô hình với các ô bằng nhau. Các đối
tượng sẽ đặt vừa kích thước với từng ô đó. Thứ tự sắp xếp cũng từ trái qua
phải và từ trên xuống dưới.
 GridBagLayout: Tương tự như GridLayout, các đối tượng khung chứa
cũng được đưa vào một lưới vô hình. Tuy nhiên kích thước các đối tượng
không nhất thiết phải vừa với 1 ô mà có thể là 2, 3 ô hay nhiều hơn tùy
theo các ràng buộc mà ta chỉ định thông qua đối tượng GridBagConstraint.
 Null Layout: Cách trình bày tự do. Đối với cách trình bày này người lập
trình phải tự động làm tất cả từ việc định kích thước của các đối tượng,
cũng như xác định vị trí của nó trên màn hình. Ta không phụ thuộc vào
những ràng buộc đông, tây , nam, bắc gì cả.
 Ví dụ 7.3.2.12: minh họa về FlowLayout Manager: các đối tượng từ trái
qua phải và từ trên xuống dưới.
import java.awt.*;
import java.awt.event.*;
class FlowLayoutDemo extends Frame
{
Button btn1=new Button("Button 1");
Checkbox chb1=new Checkbox("Checkbox 1");
Checkbox chb2=new Checkbox("Checkbox 2");

public FlowLayoutDemo(String title)


{
super(title);

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 35


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

setLayout(new FlowLayout(FlowLayout.CENTER));
add(btn1);
add(chb1);
add(chb2);
}

public static void main(String args[])


{
FlowLayoutDemo myFlowLayout=new FlowLayoutDemo("Flow
Layout");
myFlowLayout.setSize(200,200);
myFlowLayout.show();
myFlowLayout.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent we)
{
System.exit(0);
}
});
}
}
Kết quả chương trình:

 Ví dụ 7.3.2.13: minh họa về BorderLayout manager: Cửa sổ được chia làm 5


vùng: đông, tây, nam, bắc và vùng trung tâm. Mỗi vùng hiển thị một Button.
import java.awt.*;
import java.awt.event.*;
class BorderLayoutDemo01 extends Frame
{
public BorderLayoutDemo01(String title)

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 36


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

{
super(title);
Button b1=new Button("East Button");
Button b2=new Button("West Button");
Button b3=new Button("South Button");
Button b4=new Button("North Button");
Button b5=new Button("Center Button");
setLayout(new BorderLayout());
add(b1,BorderLayout.NORTH);
add(b2,BorderLayout.WEST);
add(b3,BorderLayout.EAST);
add(b4,BorderLayout.SOUTH);
add(b5,BorderLayout.CENTER);
}
public static void main(String args[])
{
BorderLayoutDemo01 myBorderLayout=new
BorderLayoutDemo01

("BorderLayout Test");
myBorderLayout.setSize(400,300);
myBorderLayout.show();
myBorderLayout.addWindowListener(new WindowAdapter()
{ public void windowClosing(WindowEvent we)
{ System.exit(0);
}
});
}
}
Kết quả chương trình:

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 37


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

 Ví dụ 7.3.2.14: minh họa về GridLayout Manager: Chương trình tạo 1


GridLayout với 2 hàng, 2 cột:
import java.awt.*;
import java.awt.event.*;
class GridTest extends Frame
{
Button btn[];
String str[]={"1","2", "3", "4"};
public GridTest(String title)
{
super(title);
setLayout(new GridLayout(2,2));
btn=new Button[str.length];
for (int i=0; i<str.length;i++)
{
btn[i]=new Button(str[i]);
add(btn[i]);
}
}
public static void main(String args[])
{ GridTest t=new GridTest("Grid Layout");
t.setSize(300,200);
t.show();

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 38


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

t.addWindowListener(new WindowAdapter()
{ public void windowClosing(WindowEvent we)
{ System.exit(0);
}
});
}
}
Kết quả chương trình:

 Ví dụ 7.3.2.15: minh họa về GridBagLayout Manager: Tạo một mảng các


Button và cho hiển thị trên cửa sổ dưới dạng lưới. Mỗi button có tiêu đề là 1 ký tự
của xâu "abcdefghi".
import java.awt.*;
import java.awt.event.*;
class GridBagLayoutDemo01 extends Frame
{
Button btn[];
String str="abcdefghi";
public GridBagLayoutDemo01(String title)
{
super(title);
setLayout(new GridLayout(3,3));
btn=new Button[str.length()];
for (int i=0; i<str.length();i++)
{
btn[i]=new Button(str.substring(i,i+1));
add(btn[i]);

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 39


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

}
}
public static void main(String args[])
{
GridBagLayoutDemo01 myGBL=new GridBagLayoutDemo01("Grid
Layout");
myGBL.setSize(300,200);
myGBL.show();
myGBL.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent we)
{ System.exit(0);
}
});
}
}
Kết quả chương trình:

d) Lớp Menu
Ngôn ngữ Java có một tập hợp các lớp đối tượng để tạo các menu. Có hai loại
menu-pull down và pop-up. Menu làm cho ứng dụng ta xây dựng dễ sử dụng hơn.
Ta chỉ có đặt duy nhất một thanh menubar trong một frame. Menubar là một thanh
nằm ngang được đặt tại đỉnh của frame. Nó liệt kê các mục chọn khác nhau hay còn
gọi là menu. Một menu độc lập có thể chứa các mục chọn con, các mục con này
được gọi là Menu Item. Java cung cấp các Checkbox MenuItem, chúng có thể được
bật hay mở, phụ thuộc vào trạng thái.

 Ví dụ 7.3.2.16: Tạo cửa sổ với các menu và subMenu (menu con)

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 40


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

import java.awt.*;
import java.awt.event.*;
class MenuDemo01 extends Frame implements ActionListener,
MouseListener
{
MenuItem exitItem;
PopupMenu optionsMenu;
Frame frame;
public MenuDemo01()
{
setTitle("Menu Test");
setSize(300,200);

MenuBar mbar=new MenuBar();


setMenuBar(mbar);

Menu fileMenu=new Menu("File");


mbar.add(fileMenu);
fileMenu.addActionListener(this);
MenuItem newItem=new MenuItem("New");
fileMenu.add(newItem);
MenuItem openItem=new MenuItem("Open");
fileMenu.add(openItem);
fileMenu.addSeparator();
MenuItem saveItem=new MenuItem("Save");
fileMenu.add(saveItem);
MenuItem saveAsItem=new MenuItem("Save As");
fileMenu.add(saveAsItem);
fileMenu.addSeparator();
exitItem=new MenuItem("Exit");
fileMenu.add(exitItem);
saveAsItem.addActionListener(this);

Menu editMenu=new Menu("Edit");


mbar.add(editMenu);

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 41


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

editMenu.addActionListener(this);
MenuItem cutItem=new MenuItem("Cut");
editMenu.add(cutItem);
MenuItem copyItem=new MenuItem("Copy");
editMenu.add(copyItem);
MenuItem pasteItem=new MenuItem("Paste");
editMenu.add(pasteItem);

Menu helpMenu=new Menu("Help");


mbar.add(helpMenu);
helpMenu.addActionListener(this);
MenuItem contentItem=new MenuItem("Content");
helpMenu.add(contentItem);
MenuItem indexItem=new MenuItem("Index");
helpMenu.add(indexItem);
Menu findMenu=new Menu("Find");
helpMenu.add(findMenu);
addMouseListener(this);
MenuItem nameItem=new MenuItem("Search by Name");
findMenu.add(nameItem);
MenuItem cacheItem=new MenuItem("Search from cache");
findMenu.add(cacheItem);
optionsMenu=new PopupMenu("Options");
editMenu.add(optionsMenu);
optionsMenu.addActionListener(this);
MenuItem readItem=new MenuItem("Read Only");
optionsMenu.add(readItem);
optionsMenu.addSeparator();
Menu formatMenu=new Menu("Format text");
optionsMenu.add(formatMenu);
this.add(optionsMenu);
formatMenu.addActionListener(this);
CheckboxMenuItem insertItem=new CheckboxMenuItem("Insert",true);
formatMenu.add(insertItem);

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 42


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

CheckboxMenuItem overtypeItem=new
CheckboxMenuItem("Overtype",false);
formatMenu.add(overtypeItem);
}
public void actionPerformed(ActionEvent ae)
{
if (ae.getActionCommand().equals("Exit"))
{
System.exit(0);
}
}
public void mouseEntered(MouseEvent m){}
public void mouseExited(MouseEvent m){}
public void mouseClicked(MouseEvent m) //Sự kiện bấm chuột
(cả phải,trái)
{
optionsMenu.show(this,m.getX(),m.getY());
}
public void mouseReleased(MouseEvent m){}
public void mousePressed(MouseEvent m){}
public static void main(String[] args)
{
MenuDemo01 myMenu=new MenuDemo01();
myMenu.show();
myMenu.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent we)
{ System.exit(0);
}
});
}
}
Kết quả chương trình:

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 43


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

3.3. Xử lý các sự kiện


Các hệ thống GUI xử lý các tương tác người dùng với sự trợ giúp của mô hình
hướng sự kiện (Event - Driven). Tương tác của người dùng có thể là di chuyển
chuột, nhấn phím, nhả phím v.v…Tất cả các thao tác này thiết lập một sự kiện của
một loại nào đó.
Việc xử lý những sự kiện này phụ thuộc vào ứng dụng. Abstract Windowing
Toolkit (AWT) xử lý một vài sự kiện. Môi trường mà các ứng dụng này được thi
hành ví dụ như trình duyệt cũng có thể xử lý các sự kiện khác. Người lập trình cũng
cần phải xử lý những sự kiện nhất định và cần phải viết hàm xử lý các sự kiện đó.
a) Mô hình xử lý sự kiện (Event-Handling Model)
Những sự kiện được phát sinh khi người dùng tương tác với giao diện chương
trình (GUI). Những tương tác thường gặp như: di chuyển, nhấn chuột, nhấn một nút
nhấn, chọn một MenuItem trong hệ thống thực đơn, nhập dữ liệu trong một ô văn
bản, đóng cửa sổ ứng dụng, … Khi có một tương tác xảy ra thì một sự kiện được
gởi đến chương trình. Thông tin về sự kiện thường được lưu trữ trong một đối
tượng dẫn xuất từ lớp AWTEvent. Những kiểu sự kiện trong gói java.awt.event có
thể dùng cho cả những component AWT và JFC. Đối với thư viện JFC thì có thêm
những kiểu sự kiện mới trong gói java.swing.event.
Có 3 yếu tố quan trọng trong mô hình xử lý sự kiện:
 Nguồn phát sinh sự kiện (event source): là thành phần của giao diện mà
người dùng tác động.
 Sự kiện (event object): Tóm tắt thông tin về xử kiện xảy ra, bao gồm
tham chiếu đến nguồn gốc phát sinh sự kiện và thông tin sự kiện sẽ gởi
đến cho bộ lắng nghe xử lý.
 Bộ lắng nghe sự kiện (event listener): Một bộ lắng nghe là một đối
tượng của một lớp hiện thực một hay nhiều interface của gói
java.awt.event hay java.swing.event (đối với những component trong
thư viện JFC). Khi được thông báo, bộ lắng nghe nhận sự kiện và xử lý.

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 44


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Nguồn phát sinh sự kiện phải cung cấp những phương thức để đăng ký
hoặc hủy bỏ một bộ lắng nghe. Nguồn phát sinh sự kiện luôn phải gắn
với một bộ lắng nghe, và nó sẽ thông báo với bộ lắng nghe đó khi có sự
kiện phát sinh đó.
Một Event Listener lắng nghe một sự kiện nào đó mà một đối tượng đã thiết
lập. Mỗi event listener cung cấp các phương thức xử lý những sự kiện này. Lớp thi
hành listener cần phải định nghĩa những phương thức này. Để sử dụng mô hình này,
bạn làm theo các bước sau:
 Cài đặt giao diện listener thích hợp. Cấu trúc như sau:
public class MyApp extends Frame implements ActionListener
 Xác định tất cả các thành phần tạo ra sự kiện. Các thành phần có thể là các
button, label, menu item, hay window. Ví dụ, để đăng ký một thành phần với
listener, ta có thể sử dụng:
Tên_biến_đối_tượng.exitbtn.addActionListener(this);
 Xác định tất cả các sự kiện được xử lý. Các sự kiện có thể là một
‘ActionEvent’ nếu một button được click hay một ‘mouseEvent’ nếu như
chuột được kéo đi.
 Thi hành các phương thức của listener và viết hàm xử lý sự kiện tương ứng
với các phương thức.
Một đối tượng Event-Listener lắng nghe những sự kiện khác nhau phát sinh từ
các components của giao diện chương trình. Với mỗi sự kiện khác nhau phát sinh
thì phương thức tương ứng trong những Event-Listener sẽ được gọi thực hiện. Mỗi
interface Event-Listener gồm một hay nhiều các phương thức mà chúng cần cài đặt
trong các lớp hiện thực (implements) interface đó. Những phương thức trong các
interface là trừu tượng vì vậy lớp (bộ lắng nghe) nào hiện thực các interface thì phải
cài đặt tất cả những phương thức đó. Nếu không thì các bộ lắng nghe sẽ trở thành
các lớp trừu tượng.
Bảng sau đây chỉ ra các sự kiện khác nhau và mô tả về chúng:
Lớp sự kiện Mô tả
Phát sinh khi một button được nhấn, một item trong danh
ActionEvent sách chọn lựa được nhấn đúp (double-click) hay một menu
được chọn.
AdjustmentEvent Phát sinh khi một thanh scrollbar được sử dụng.
Phát sinh khi một thành phần được thay đổi kích thước, được
ComponentEvent
di chuyển, bị ẩn hay làm cho hoạt động được.

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 45


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

FocusEvent Phát sinh khi một thành phần mất/nhận focus từ bàn phím.
Phát sinh khi một mục menu được chọn hay bỏ chọn; hay khi
ItemEvent
một checkbox hay một item trong danh sách được click.
Phát sinh khi một cửa sổ được kích hoạt, được đóng, được mở
WindowEvent
hay thoát.
Phát sinh khi giá trị trong thành phần textfield hay textarea bị
TextEvent
thay đổi.
MouseEvent Phát sinh khi chuột di chuyển, click, được kéo hay thả ra.
KeyEvent Phát sinh khi bàn phím ấn, nhả.
Bảng 7.3.2.4: Các sự kiện các đối tượng
Các giao diện cần được cài đặt để xử lý một trong số những sự kiện này là:
 ActionListener
 AdjustmentListener
 ComponentListener
 FocusListener
 ItemListener
 WindowListener
 TextListener
 MouseListener
 MouseMotionListener
 KeyListener
b) Xử lý sự kiện chuột
Java cung cấp hai intefaces lắng nghe (bộ lắng nghe sự kiện chuột) là
MouseListener và MouseMotionListener để quản lý và xử lý các sự kiện liên quan
đến thiết bị chuột. Những sự kiện chuột có thể “bẫy” cho bất kỳ component nào trên
GUI mà dẫn xuất từ java.awt.component.
Các phương thức của interface MouseListener:
 public void mousePressed(MouseEvent event): được gọi khi một nút
chuột được nhấnvà con trỏ chuột ở trên component.
 public void mouseClicked(MouseEvent event): được gọi khi một nút
chuột được nhấn và nhả trên component mà không di chuyển chuột.
 public void mouseReleased(MouseEvent event): được gọi khi một nút
chuột nhả sa khi kéo rê.

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 46


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

 public void mouseEntered(MouseEvent event): được gọi khi con trỏ


chuột vào trong đường biên của một component.
 public void mouseExited(MouseEvent event): được gọi khi con trỏ chuột
ra khỏi đường biên của một component.
Các phương thức của interface MouseMotionListener:
 public void mouseDragged(MouseEvent even ): phương thức này được
gọi khi người dùng nhấn một nút chuột và kéo trên một component.
 public void mouseMoved(MouseEvent event): phương thức này được gọi
khi di chuyển chuột trên component.
Mỗi phương thức xử lý sự kiện chuột có một tham số MouseEvent chứa thông
tin về sự kiện chuột phát sinh chẳng hạn như: tọa độ x, y nơi sự kiện chuột xảy ra.
Những phương thức tương ứng trong các interfaces sẽ tự động được gọi khi chuột
tương tác với một component.
Để biết được người dùng đã nhấn nút chuột nào, chúng ta dùng những phuơng
thức, những hằng số của lớp InputEvent (là lớp cha của lớp MouseEvent).

 Ví dụ 7.3.2.17: Xử lý các sự kiện của đối tượng Mouse trên cửa sổ ứng dụng.
import java.awt.*;
import java.awt.event.*;
class MouseEventDemo01 extends Frame implements
MouseListener,MouseMotionListener
{
private Label myLabel;
public MouseEventDemo01()
{
super("MouseEvent Test");
myLabel=new Label();
myLabel.setText("Mô phỏng các sự kiện của đối tượng Mouse");
this.setLayout(new FlowLayout());
this.add(myLabel);
addMouseListener(this);
addMouseMotionListener(this);
setSize(400,100);
setVisible(true);

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 47


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

}
public void mouseClicked(MouseEvent event)
{
myLabel.setText("Bạn vừa bấm chuột tại
("+event.getX()+","+event.getY()+")");
}
public void mousePressed(MouseEvent event)
{
myLabel.setText("Bấm chuột tại
("+event.getX()+","+event.getY()+")");
}
public void mouseReleased(MouseEvent e)
{
myLabel.setText("Nhả chuột tại ("+e.getX()+","+e.getY()+")");
}
public void mouseEntered (MouseEvent e)
{
myLabel.setText("Chuột bên trong cửa sổ");
}
public void mouseMoved (MouseEvent e)
{
myLabel.setText("Chuột di chuyển đến
("+e.getX()+","+e.getY()+")");
}
public void mouseDragged(MouseEvent e)
{
myLabel.setText("Kéo chuột tới ("+e.getX()+","+e.getY()+")");
}
public void mouseExited(MouseEvent event)
{
myLabel.setText("Chuột bên ngoài cửa sổ");
}
public static void main(String[] abc)
{
MouseEventDemo01 myMouse=new MouseEventDemo01();

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 48


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

myMouse.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent we)
{
System.exit(0);
}
});
}
}
Kết quả chương trình:

c) Xử lý sự kiện bàn phím


Để xử lý sự kiện bàn phím java hỗ trợ một bộ lắng nghe sự kiện đó là interface
KeyListener. Một sự kiện bàn phím đượcphát sinh khi người dùng nhấn và nhả một
phím trên bàn phím.
Một lớp hiện thực KeyListener phải cài đặt các phương thức keyPressed,
keyReleased và keyTyped. Mỗi phương thức này có một tham số là một đối tượng
kiểu KeyEvent. KeyEvent là lớp con của lớp InputEvent.
Các phương thức của interface KeyListener
 Phương thức keyPressed được gọi khi một phím bất kỳ được nhấn.
 Phương thức keyTyped được gọi thực hiện khi người dùng nhấn một
phím không phải “phím hành động” (như phím mũi tên, phím Home,
End, PageUp, PageDown, các phím chức năng như: Num Lock,
PrintScreen, ScrollLock, CapsLock, Pause).
 Phương thức keyReleased được gọi thực hiện khi nhả phím nhấn sau khi
sự kiện keyPressed hoặc keyTyped.

 Ví dụ 7.3.2.18: Xử lý các sự kiện bấm phím trên cửa sổ ứng dụng.


import java.awt.*;
import java.awt.event.*;
public class KeyEventDemo01 extends Frame implements KeyListener

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 49


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

{ TextField t1;
Label l1;
public KeyEventDemo01(String s )
{ super(s);
Panel p =new Panel();
l1 = new Label (" Chờ phím bấm! " ) ;
l1.setFont(new java.awt.Font("Times New Roman",1,16));
p.add(l1);
add(p);
addKeyListener ( this ) ;
setSize (400,200 );
setLocation(300,300);
setVisible(true);
addWindowListener(new WindowAdapter()
{ public void windowClosing(WindowEvent e)
{ System.exit(0);
}
});
}
public void keyTyped ( KeyEvent e )
{ l1.setText("Bạn bấm phím: "+ e.getKeyChar());
}
public void keyPressed ( KeyEvent e){}
public void keyReleased ( KeyEvent e ){}
public static void main (String[]args )
{ new KeyEventDemo01 ("KeyListener Test" ) ;
}
}
Kết quả chương trình:

Kỹ thuật lập trình hướng đối tượng - Bài 7 Trang 50


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

BÀI 8: MỘT SỐ KỸ THUẬT NÂNG CAO

Mục tiêu:
Trong bài này, Anh/Chị cần đạt được những mục tiêu sau:
1. Lập trình kết nối mạng.
2. Lập trình ứng dụng Applet
Nội dung:

1. Lập trình kết nối mạng


Internet hay World Wide Web (www) đã ngày càng quen thuộc với hầu hết tất
cả chúng ta và vai trò của nó là không thể phủ nhận. Đặc biệt đối với các tổ chức,
Internet và web giữ một vị trí vô cùng quan trọng trong các chiến dịch hệ thống
thông tin của họ. Java cung cấp một số lượng lớn các thư viện giúp chúng ta dễ
dàng hơn rất nhiều trong việc phát triển các ứng dụng mạng. Java cho phép chương
trình tìm kiếm thông tin, kết nối các máy tính với nhau trên khắp thế giới, trong một
quốc gia hay chỉ trong phạm vi một tổ chức. Với Java, applets và các ứng dụng
hoàn toàn có thể giao tiếp được với nhau.
Lập trình kết nối mạng là một chủ đề rộng và phức tạp. Trong phạm vi cuốn
sách này, chúng tôi giới thiệu những nội dung cần thiết về các khái niệm và khả
năng giao tiếp mạng trong Java. Các khả năng cao cấp khác sẽ được đưa ra thảo
luận nhiều hơn trong các cuốn sách tiếp theo.
Những chức năng giao tiếp mạng căn bản trong Java được bao hàm trong các
lớp và giao diện thuộc gói java.net, thông qua chúng Java cung cấp phương thức kết
nối stream-based communications cho phép các ứng dụng xem việc giao tiếp
mạng như các dòng chảy dữ liệu. Các lớp và phương thức này cũng cho phép
packet-based communications trong việc truyền tải các gói thông tin độc lập mà
thường được sử dụng trong truyền audio và video trên Internet. Trong phần này,
chúng tôi sẽ hướng dẫn các bạn làm thế nào để tạo và thao tác với các socket và làm
thế nào để giao tiếp với gói (packet) và dòng chảy dữ liệu (stream).
Chúng ta tập trung vào cả hai mặt trong mối quan hệ khách-chủ. Máy khách
(client) yêu cầu một vài hành động được thực thi, và máy chủ (server) thực hiện
các hoạt động đó cũng như trả lời tới máy khách. Một ví dụ điển hình cho phương
thức thực thi này là giữa trình duyệt và Web server. Khi một người dùng chọn một
website để truy cập thông qua trình duyệt (ứng dụng trên máy khách), một yêu cầu

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 1


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

được gửi đi tới một Web server tương ứng (ứng dụng trên máy chủ). Khi đó, thông
thường server sẽ trả lời máy khách bằng việc gửi một trang web HTML thích hợp.
Socket-based communications trong Java cho phép việc đọc và viết một
socket cũng đơn giản như là đọc và viết một file vậy. Để hiểu rõ hơn, socket là một
cấu trúc mềm thể hiện đầu cuối của một kết nối. Có 2 loại socket: stream socket và
datagram socket.
Với stream socket, một process (tiến trình) thiết lập một liên kết tới một process
khác. Khi liên kết được duy trì, dòng chảy dữ liệu giữa các process vẫn tiếp tục.
Thường được nhắc đến như là giao tiếp có kết nối, sử dụng phương thức TCP
(Transmisstion Control Protocol).
Đối với datagram socket, các gói thông tin độc lập lần lượt được gửi đi, nói
cách khác là giao tiếp không kết nối, sử dụng phương thức UDP (User Datagram
Protocol). Tuy nhiên không thể đảm bảo liệu các gói tin có đến theo thứ tự đúng
hay không. Với UDP, các gói tin thậm chí có thể bị mất hoặc trùng lặp. Đây cũng
chính là những vấn đề mà các lập trình viên cần giải quyết khi chọn làm theo cách
này. UDP được sử dụng phù hợp nhất trong các ứng dụng mạng không yêu cầu
kiểm tra lỗi và sự tin cậy như TCP. Stream socket và phương thức TCP là sự lựa
chọn của số lượng lớn đa số lập trình viên Java.
Thông qua các ví dụ dưới đây, chúng ta sẽ thấy rằng rất nhiều vấn đề về giao
tiếp mạng được xử lý bởi Java APIs.
1.1. Thao tác với URLs
Internet cung cấp rất nhiều phương thức truyền thông trong đó, HTTP (Hyper
Transfer Protocol) là căn bản của World Wide Web, sử dụng URIs (Uniform
Resource Identifiers) để xác định dữ liệu trên Internet. URIs nhằm xác định vị trí
của tài liệu được gọi là URLs (Uniform Resource Locators). Thông thường URLs
tham chiếu tới file hoặc thư mục và cũng có thể tham chiếu tới các đối tượng thực
hiện các nhiệm vụ phức tạp như tra cứu cơ sở dữ liệu hay tìm kiếm trên Internet.
Với bất cứ HTTP URL công khai nào tồn tại văn bản HTML ở bất cứ đâu trên Web,
chúng ta đều có thể truy cập được thông qua HTTP.
Thao tác với URLs nay trở nên dễ dàng với Java. Nếu ta sử dụng một URL
tham chiếu đến vị trí chính xác của một file nguồn, (Web page chẳng hạn) như một
đối số tới phương thức showDocument trong giao diện AppletContext, thì trình
duyệt mà applet đang thực thi sẽ hiển thị file nguồn đó. Applet trong ví dụ 7.4.1 và
7.4.2 cho phép người dùng chọn một Web page từ JList và hiển thị trên trình duyệt.
Trong ví dụ này, giao tiếp mạng được thực hiện bởi trình duyệt.

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 2


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Ví dụ 7.4.1. Code HTML hiển thị applet giúp cho việc chon site

<html>
<head>
<title> Site Selector </title><meta http-equiv="Content-Type"
content="text/html; charset=UTF-8">
</head>
<body>
<applet codebase = "classes" code = "SiteSelector.class" width =
"300" height = "75">
<param name = "title0" value = "Java – Trang chủ">
<param name = "location0" value = "http://java.sun.com/">
<param name = "title1" value = "W3schools">
<param name = "location1" value = "http://www.w3schools.com/">
<param name = "title2" value = "Sổ tay PHP">
<param name = "location2" value = "http://www.php.net/">
<param name = "title3" value = "Zing mp3 | Thế giới âm nhạc">
<param name = "location3" value = "http://www.mp3.zing.vn/">
</applet>
</body>
</html>
Ví dụ 7.4.2. Thể hiện tài liệu xác định bởi URL trên trình duyệt

import java.applet.AppletContext;
import java.awt.BorderLayout;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import javax.swing.JApplet;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 3


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

public class SiteSelector extends JApplet


{
private HashMap< Object, URL > sites; // HashMap chứa tên sites
và URLs
private ArrayList< String > siteNames; // Tên sites
private JList siteChooser; // Danh sách lựa chọn- sites hiển thị trên
trình duyệt

// read HTML parameters and set up GUI


@Override
public void init()
{ sites = new HashMap< >(); // tạo HashMap
siteNames = new ArrayList< >(); // tạo ArrayList
// nhận tham số (param) truyền vào từ tài liệu HTML
getSitesFromHTMLParameters();
// tạo GUI components and giao diện
add( new JLabel( "Click chọn site bạn muốn tới !" ),
BorderLayout.NORTH );
siteChooser = new JList( siteNames.toArray() ); // tạo JList từ
mảng tên sites
siteChooser.addListSelectionListener(
new ListSelectionListener() // lớp trong lớp (anonymous inner class)
{ // tới trang Web page đã chọn
@Override
public void valueChanged( ListSelectionEvent event )
{ // lấy tên site đã chọn
Object object = siteChooser.getSelectedValue();
// sử dụng tên site xác định URL tương ứng
URL newDocument = sites.get( object );
// chọn trình duyệt hiện tại
AppletContext browser = getAppletContext();
// thông báo trình duyệt tải trang mới
browser.showDocument( newDocument );
} // kết thúc phương thức valueChanged
} // kết thúc lớp trong lớp

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 4


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

); // kết thúc addListSelectionListener

add( new JScrollPane( siteChooser ), BorderLayout.CENTER );


} // kết thúc phương thức init

// hàm - nhận tham số (param) truyền vào từ tài liệu HTML


private void getSitesFromHTMLParameters()
{ String title; // tiêu đề site
String location; // vị trí của site
URL url; // URL
int counter = 0; // biến đếm
title = getParameter( "title" + counter ); // nhận tiêu đề site đầu tiên
// duyệt đến hết các param từ văn bản HTML
while ( title != null )
{ // nhận vị trí site
location = getParameter( "location" + counter );
try // thêm title và URL vào HashMap và tiêu đề vào ArrayList
{ url = new URL( location ); // chuyển đổi URL từ vị trí site
sites.put( title, url ); // thêm tiêu đề và URL vào HashMap
siteNames.add( title ); // thêm tiêu đề vào ArrayList
} // kết thúc try
catch ( MalformedURLException urlException )
{ urlException.printStackTrace();
} // kết thúc catch
counter++;
title = getParameter( "title" + counter ); // nhận tiêu đề site tiếp theo
} // kết thúc vòng while
} // kết thúc phương thức getSitesFromHTMLParameters
} // kết thúc lớp SiteSelector
Kết quả hiển thị như sau:

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 5


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Applet này đã rất hay trong việc vận dụng applet parameters được truyền vào
thông qua văn bản HTML. Điều này cũng giúp tùy chỉnh applet trở nên dễ dàng hơn
rất nhiều thông qua tham số truyền vào. Trong trường hợp này, văn bản HTML sử
dụng 8 tham số được xác định bởi tag <param> được đặt giữa cặp
<applet></applet> cho phép applet có thể đọc giá trị và sử dụng chúng để tùy chỉnh
chính nó. Số lượng tham số truyền vào applet là không hạn chế. Mỗi tham số xác
định 1 tên (name) và 1 giá trị (value).
Phương thức getParameter nhận name trong thẻ param như một đối số và trả
lại kết quả dạng chuỗi là giá trị (value) tương ứng với tên tham số đó. Trong ví dụ
này, tham số đại diện cho tiêu đề và vị trí của mỗi website mà người dùng có thể lựa
chọn. Tiêu đề (title#), mỗi tiêu đề có một vị trí tương ứng (location#), trong đó # bắt
đầu với 0 và tăng dần 1 đơn vị. Câu lệnh sau:
String title = getParameter( "title0" );
lấy giá trị tương ứng với tham số “title0” và gán nó vào mảng title. Nếu không
có thẻ <param> nào xác định tham số “title0”, hàm getParameter trả lại kết quả null.

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 6


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Những kết quả nhận được sau đó được hiển thị dạng JList trong applet. Lớp
SiteSelector sử dụng một HashMap (trong gói java.util) để lưu trữ danh sách tên
website và url.
Tạo danh sách chọn
Thêm vào đó, một ArrayList các tên sites (gói java.util) được sử dụng kết hợp
phương thức toArray để khởi tạo JList. Một ArrayList là một mảng tham chiếu có
kích thước động. Phương thức add trong lớp ArrayList cho phép thêm một phần tử
vào cuối mảng.
Các dòng 25, 26 trong phương thức init() khởi tạo một đối tượng HashMap và
một ArrayList. Dòng 29 là lời gọi hàm getSiteFromHTMLParameters (được định
nghĩa ở các dòng từ 60 đến 89) để nhận các tham số được truyền vào applet thông
qua văn bản HTML.
Phương thức getSiteFromHTMLParameters
Để rõ hơn về phương thức getSiteFromHTMLParameters, dòng 67 sử dụng
phương thức getParameter trong Applet lấy thông tin về tiêu đề website. Nếu tiêu
đề khác null, vòng lặp các dòng từ 70 đến 88 bắt đầu thực hiện. Vẫn là phương thức
getParameter dòng 73 lấy thông tin về location. Dòng 77 tạo một đối tượng URL
mới với giá trị location. Hàm khởi tạo URL sẽ kiểm tra liệu tham đối có phải là một
URL hợp lệ. Nếu không, hàm khởi tạo gọi ngoại lệ MalformedURLException.
Chú ý rằng hàm khởi tạo URL phải được bao bởi try{}. Nếu xuất hiện
MalformedURLExeption, hàm printStackTrace được gọi và cho kết quả tới Java
console. Trên hệ điều hành Windows, Java console có thể xem được bằng cách
click chuột phải vào biểu tượng Java trên thanh taskbar. Sau đó, chương trình tiếp
tục duyệt các tiêu đề Web tiếp theo và bỏ qua các URL không hợp lệ. Do đó các
tiêu đề đó không được hiển thị trong JList. (không tồn tại trong HashMap)
Trong trường hợp ngược lại, mục đích dòng 78 thêm tiêu đề Web và URL vào
HashMap, và dòng 79 thêm tiêu đề vào ArrayList. Dòng 87 nhận tiêu đề tiếp theo từ
văn bản HTML. Vòng lặp tiếp tục cho đến khi lời gọi hàm getParameter dòng 87 trả
lại “null”.
Khi lời gọi phương thức getSiteFromHTMLParameters kết thúc, các dòng từ 32
đến 56 nhằm xây dựng giao diện GUI cho applet. Dòng 32 thêm JLabel “Click chọn
site bạn muốn tới !” với thuộc tính NORTH trong BorderLayout JFrame hiển thị kết
quả. Dòng 34 tạo JList siteChooser cho phép người dùng chọn một webpage để
chuyển hướng. Tiếp theo các dòng từ 35 đến 54 tạo hàm xử lý sự kiện -

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 7


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

ListSelectionListener nhận thay đổi từ siteChooser. Dòng 56 cho phép danh sách
website hiển thị trong BorderLayout với thuộc tính CENTER.
Khi người dùng lựa chọn một Website được liệt kê trong siteChooser, chương
trình gọi phương thức valueChanged (các dòng từ 39 đến 52). Dòng 42 nhận tên site
đã được chọn từ JList. Dòng 45 truyền tên site đó vào phương thức get trong
HashMap trả về URL tương ứng và được gán cho biến newDocument.
Dòng 48 sử dụng phương thức Applet, getAppletContext để tham chiếu tới đối
tượng bao hàm applet (ở đây là trình duyệt). Dòng 51, phương thức showDocument
nhận đối số là một đối tượng URL và truyền nó tới AppletContext (trình duyệt).
Cuối cùng, trình duyệt hiển thị trên cửa sổ hiện tại trang web được xác định bởi
URL đó. Trong ví dụ này, tất cả đều là tài liệu HTML.
Đối với những lập trình viên đã quen với HTML frame, phương thức
showDocument trong AppletContext thường được sử dụng với 2 tham đối: URL và
đích đến bao gồm “_blank”, “_self” và “_top”.
1.2. Đọc file từ Web server
Trong ví dụ tiếp theo, chúng tôi giới thiệu một ứng dụng mạng (ví dụ 7.4.2) sử
dụng giao diện người dùng Swing GUI với JEditorPane (gói javax.swing) để hiển
thị nội dung của một file được lưu trên web server. Người sử dụng nhập vào khung
JTextField một URL và chương trình hiển thị tài liệu tương ứng (nếu có) trong
JEditorPane. Lớp JEditorPane có thể hiển thị đổng thời cả dạng văn bản thông
thường và văn bản định dạng HTML, (xem screen shot biểu số 24.4) vì vậy ứng
dụng có thể coi như là một trình duyệt web đơn giản. Chúng ta cũng sẽ tập trung
vào làm thế nào để xử lý HyperlinkEvents khi mà người dùng click vào một liên kết
trong văn bản HTML. Kỹ thuật được sử dụng trong ví dụ dưới đây cũng có thể sử
dụng trong applet tuy nhiên, một applet chỉ được phép đọc những file đã download
về máy.
Ví dụ 7.4.2. Tạo kết nối để đọc file thông qua URL

1 // ReadServerFile.java
2 // Sử dụng JEditorPane hiển thị nội dung file trên
webserver
3
4 import java.awt.BorderLayout;
5 import java.awt.event.ActionEvent;
6 import java.awt.event.ActionListener;
7 import java.io.IOException;
8 import javax.swing.JEditorPane;

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 8


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

9 import javax.swing.JFrame;
1 import javax.swing.JOptionPane;
0 import javax.swing.JScrollPane;
1 import javax.swing.JTextField;
1 import javax.swing.event.HyperlinkEvent;
1 import javax.swing.event.HyperlinkListener;
2
1 public class ReadServerFile extends JFrame
3
{
1
private JTextField enterField; // JTextField cho phép
4
nhập URL
1
private JEditorPane contentsArea; // cho phép hiển thị
5
website
1
6
// cài đặt GUI
1
public ReadServerFile()
7
{
1
8 super ("Trình duyệt Web đơn giản");
1
9 // tạo enterField và đăng kí listener
2 enterField = new JTextField("Nhập vào URL");
0 enterField.addActionListener(
2 new ActionListener()
1 { // đọc tài liệu từ URL
2 @Override
2 public void actionPerformed(ActionEvent
2
event)
3 {
2 getThePage(event.getActionCommand());
4 } // kết thúc phương thức actionPerformed
2 } // kết thúc lớp trong lớp
5
); // kết thúc lời gọi addActionListener
2
6
add(enterField, BorderLayout.NORTH);
2
7

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 9


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

2 contentsArea = new JEditorPane(); // tạo


8 contentsArea
2 contentsArea.setEditable(false);
9 contentsArea.addHyperlinkListener(
3 new HyperlinkListener()
0 { // nếu người dùng click vào liên kết --> điều
hướng tới trang đó
3
1 @Override
3 public void hyperlinkUpdate(HyperlinkEvent
2 event)
3 {
3 if(event.getEventType() ==
3
4 HyperlinkEvent.EventType.ACTIVATED)
3 getThePage(event.getURL().toString());
5
} // kết thúc phương thức hyperlinkUpdate
3
} // kết thúc lớp trong lớp
6
); // kết thúc lời gọi addHyperlinkListener
3
7
add(new JScrollPane(contentsArea),
3
BorderLayout.CENTER);
8
setSize(400, 300); // đặt size cho cửa sổ hiển thị
3
9 setVisible(true); // hiển thị cửa sổ
4 } // kết thúc hàm khởi tạo ReadServerFile
0
4 // tải tài liệu
1 private void getThePage(String location)
4 {
2 try
4 { // tải tài liệu và hiển thị location
3 contentsArea.setPage(location); // đặt page
4 contentsArea.setText(location); // đặt text
4 } // kết thúc try
4 catch(IOException ioException)
5
{
4

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 10


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

6 JOptionPane.showMessageDialog(this,
4 "Lỗi load trang", "Bad URL",
7 JOptionPane.ERROR_MESSAGE);
4 } // kết thúc catch
8 } // kết thúc phương thức getThePage
4 } // kết thúc lớp ReadServerFile
9
5
0
5
1
5
2
5
3
5
4
5
5
5
6
5
7
5
8
5
9
6
0
6
1
6
2
6
3
6
4

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 11


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

6
5
6
6
6
7
6
8
6
9
7
0
7
1
7
2
7
3
7
4
7
5

Ví dụ: ReadServerFileTest.java

1 // ReadServerFileTest.java
2 // Khởi tạo và chạy ReadServerFile.
3
4 import javax.swing.JFrame;
5
6 public class ReadServerFileTest
7 {
8 public static void main(String args[])
9 {
1 ReadServerFile application = new ReadServerFile();
0
application.setDefaultCloseOperation(JFrame.EXIT_ON_CLO
1

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 12


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

1 SE);
1 } // kết thúc hàm main
2 } // kết thúc lớp ReadServerFileTest
Kết quả:

Lớp ReadServerFile bao gồm enterField dạng JTextField cho phép người dùng
nhập URL trỏ tới file cần đọc và contentsArea dạng JEditorPane hiển thị nội dung
file. Khi người dùng nhấn Enter sau khi nhập URL, ứng dụng gọi phương thức
actionPerformed (các dòng từ 31 đến 34). Dòng 33 sử dụng ActionEvent phương
thức getActionCommand để nhận chuỗi mà người dùng đã nhập vào JTextField và
truyền vào phương thức getThePage (các dòng từ 61 đến 74).
Dòng 65 gọi JEditorPane phương thức setPage để download tài liệu được xác
định bởi “location” và hiển thị trong JEditorPane. Nếu có lỗi xảy ra trong quá trình
load tài liệu, setPage báo ngoại lệ IOException. Cũng tương tự như vậy, nếu người
dùng nhập vào một URL không hợp lệ, lỗi MalformedURLException (lớp con của

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 13


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

IOException) xảy ra. Ngược lại, nếu load thành công, dòng 66 hiển thị vị trí hiện tại
trong enterField.
Thực tế, trong một tài liệu HTML chứa nhiều yếu tố “liên kết” tới một tài liệu
khác trên Internet như text, hình ảnh hay các yếu tố giao diện khác. Trong trường
hợp người dùng click vào một trong những yếu tố này, JEditorPane tạo ra một
HyperlinkEvent (gói javax.swing.event) và báo cho tất cả HyperlinkListerners (gói
javax.swing.event) đã được đăng kí của sự kiện đó. Trong ví dụ này, một
HyperlinkListener đã được khai báo để xử lý những sự kiện này ở các dòng từ 42
đến 53. Khi một HyperlinkEvent xảy ra, chương trình gọi tới phương thức
hyperlinkUpdate (các dòng từ 56 đến 51). Hai dòng 48, 49 sử dụng HyperlinkEvent
phương thức getEventType để xác định loại của HyperlinkEvent. Lớp
HyperlinkEvent có chứa một lớp con public được gọi là EventType khai báo 3 đối
tượng EventType tĩnh đại diện cho 3 loại sự kiện liên kết. Bao gồm:
“ACTIVATED” - người dùng đã click một liên kết yêu cầu chuyển hướng,
“ENTERED” – người dùng đang chỉ chuột vào một liên kết, và “EXITED” – người
dùng đã di chuyển chuột ra khỏi liên kết. Nếu một liên kết được ACTIVATED,
dòng 50 sử dung HyperlinkEvent phương thức getURL để lấy URL được đại diện
bởi liên kết đó. Phương thức toString cũng đã được sử dụng chuyển dạng của URL
về String sau đó được truyền vào phương thức getThePage.
Chú ý: Các HyperlinkEvent chỉ làm việc khi JEditorPane đặt setEditable(false).
(dòng 41)
1.3. Tạo lập Server đơn giản sử dụng Stream socket
Hai ví dụ đã được nêu ra từ trước sử dụng những khả năng kết nối mạng cấp
cao trong Java để giao tiếp giữa các ứng dụng. Trong những ví dụ này, lập trình
viên không có trách nhiệm tạo lập kết nối giữa máy khách và server. Chương trình
đầu tiên dựa vào trình duyệt để giao tiếp với webserver. Chương trình thứ 2 lại dựa
trên JEditorPane để thực hiện kết nối. Bắt đầu từ phần này, chúng ta đi vào tạo lập
ứng dụng của chính chúng ta và hoàn toàn có thể giao tiếp với ứng dụng khác.
Tạo lập một server đơn giản trong Java yêu cầu 5 bước. Bước thứ nhất: tạo đối
tượng ServerSocket. Một lời gọi tới hàm khởi tạo ServerSocket như sau:

ServerSocket server = new ServerSocket( port, số lượng host tối


đa );
nhằm mục đích đăng kí một cổng TCP port number và xác định số lượng host
tối đa có thể kết nối tới server. Port được sử dụng bởi máy khách để xác định ứng
dụng server trên máy chủ, còn được gọi là “handsharke point”. Nếu số lượng máy

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 14


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

khách đã đạt tối đa thì server sẽ từ chối kết nối tiếp theo. Hàm khởi tạo tạo lập cổng
đợi cho các kết nối từ máy khách – tiến trình này được biết đến như là “binding the
server to the port”. Mỗi máy khách sẽ yêu cầu kết nối tới server thông qua cổng
này và tại một thời điểm chỉ duy nhất một ứng dụng có thể kết nối tới một cổng port
xác định trên server.
Mỗi kết nối tới máy khách được gắn với một socket để chương trình quản lý.
Trong bước 2: server luôn sẵn sàng chấp nhận yêu cầu kết nối từ máy khách. Để
làm được điều đó, chương trình gọi ServerSocket phương thức accept như trong câu
lệnh dưới đây:

ServerSocket server = new ServerSocket( port, số lượng host tối


đa );
Khi một kết nối tới máy khách được thiết lập, hàm trả về một socket. Socket
này cho phép server tương tác với máy khách đó. Những tương tác này thực tế lại
xảy ra ở một cổng port khác với “handshake point”. Nhờ vậy cổng port đã xác định
ở Bước 1 tiếp tục được sử dụng trở lại để chấp nhận kết nối khác trong các server đa
luồng.
Bước 3: Thiết lập đối tượng OutputStream và InputStream cho phép server giao
tiếp với máy khách thông qua gửi và nhận các bytes dữ liệu. Server gửi thông tin tới
máy khách thông qua một OuputStream và tương tự, nhận thông tin từ máy khách
thông qua một InputStream. Server gọi hàm getOutputStream trên socket để tham
chiếu tới OutputStream và hàm getInputStream để tham chiếu tới InputStream của
socket đó.
Đối tượng “stream” có thể được sử dụng để truyền hoặc nhận từng bytes độc
lập hay chuỗi các bytes lần lượt bằng các phương thức “write” đối với
OutputStream và “read” đối với InputStream.Thông thường, gửi và nhận các giá trị
thuộc kiểu cơ bản (int, double …) hoặc các đối tượng tuần tự - serializable (String
hoặc các kiểu tuần tự khác) hiệu quả hơn so với gửi bytes. Trong trường hợp này,
chúng ta có thể sử dụng kỹ thuật để bao xung quanh OutputStream và InputStream
bằng các loại stream khác như ObjectOuputStream và ObjectInputStream. Ví dụ
như:

ObjectInputStream input =
new ObjectInputStream( connection.getInputStream() );
ObjectOutputStream output =
new ObjectOutputStream( connection.getOutputStream() );

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 15


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Việc tạo các mối quan hệ này tuyệt vời ở chỗ bất cứ một thứ gì server viết vào
ObjectOutputStream đều được gửi thông qua OutputStream và tồn tại ở
InputStream tại máy khách và ngược lại. Nhơ đó, việc truyền dữ liệu qua mạng trở
nên liền mạch và được xử lý hoàn toàn bởi Java.
Bước 4 là giai đoạn xử lý (processing), trong giai đoạn này server và máy
khách giao tiếp với nhau thông qua các đối tượng OuputStream và InputStream.
Bước 5, khi việc truyền dữ liệu hoàn thành, server gọi phương thức “close”
ngắt kết nối trên stream và socket.

1.4. Tạo lập máy khách đơn giản sử dụng Stream socket
Tạo lập một máy khách đơn giản trong Java yêu cầu 4 bước. Bước thứ nhất,
chúng ta tạo một socket kết nối tới server. Đó là vai trò của hàm khởi tạo socket có
cú pháp gọi hàm như sau:

Socket tên_kết _nối = new Socket( địa chỉ server, port );


Hàm khởi tạo Socket sử dụng 2 tham đối, địa chỉ server và số hiệu cổng port.
Nếu kết nối thành công, câu lệnh trên trả lại một socket. Trong trường hợp không
thành công, chương trình bắt lỗi IOException. Lỗi UnknownHostException xảy ra
khi hệ thống không thể xử lý địa chỉ server được cung cấp (địa chỉ IP tương ứng).
Trong Bước 2, máy khách sử dụng Socket phương thức getInputStream và
getOuputStream để tham chiếu tới InputStream và OuputStream của socket đó. Nếu
server gửi đi thông tin trong một biểu mẫu với các kiểu thực, máy khách nên nhận
được các thông tin có cùng định dạng đó. Vì thế, nếu server gửi đi giá trị với một
ObjectOutputStream thì máy khách nên đọc chúng với một ObjectInputStream (như
đã đề cập trong phần trước 7.4.3. Tạo lập server đơn giản sử dụng Stream socket).
Bước 3 là giai đoạn xử lý, tương tự đối với server, máy khách và server giao
tiếp thông qua các đối tượng InputStream và OutputStream. Trong bước cuối cùng
Bước 4, máy khách ngắt kết nối khi việc truyền tải dữ liệu đã hoàn thành bằng
lời gọi hàm “close” trên stream và socket. Chú ý là máy khách phải xác định được
khi nào server đã kết thúc việc gửi thông tin, thì khi đó lời gọi close mới chuẩn xác
được. Ví dụ điển hình đó là InputStream phương thức read trả lại giá trị “1” báo
hiệu end-of-stream (cũng được gọi là EOF end-of-file). Nếu một ObjectInputStream
được sử dụng để đọc thông tin từ server, lỗi EOFException xảy ra cho biết end-of-
stream.

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 16


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

1.5. Tương tác Client/Server và kết nối Stream socket


Trong ví dụ 7.4.5 và 7.4.6 sử dụng stream socket để minh họa một ứng dụng
chat client/server. Server đợi kết nối từ client. Khi một client kết nối tới server, ứng
dụng trên server gửi tới client một đối tượng String (nhắc lại rằng String là đối
tượng tuần tự-serialiable) thông báo kết nối thành công. Tin nhắn này sau đó hiển
thị trên ứng dụng client. Trong mỗi ứng dụng client và server đều cung cấp textfield
cho phép người sử dụng nhập tin nhắn và gửi nó tới ứng dụng còn lại. Khi client
hoặc server gửi đi chuỗi “TERMINATE”, kết nối kết thúc. Sau đó server tiếp tục
đợi client tiếp theo kết nối. Lớp “Server” được khai báo trong biểu số 24.5 và lớp
“Client” trong biểu số 24.7. Các screen shot cũng được bổ sung trong biểu số 24.7
nhằm minh họa rõ hơn hoạt động của client và server.
Ví dụ 7.4.5. Ứng dụng server
//Server.java
// Cài đặt server nhận kết nối từ client,
// gửi tin nhắn tới client, và ngắt kết nối
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import javax.swing.*;

public class Server extends JFrame


{
private JTextField enterField; // khung nhập tin nhắn
private JTextArea displayArea; // khung hiển thị tin nhắn
private ObjectOutputStream output; // output stream tới
client
private ObjectInputStream input; // input stream từ client
private ServerSocket server; // server socket
private Socket connection; // kết nối tới client
private int counter = 1; // biến đếm số kết nối

// set up GUI

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 17


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

public Server()
{
super ("Server");

enterField = new JTextField(); // tạo khung nhập tin


nhắn
enterField.setEditable(false);
enterField.addActionListener(
new ActionListener()
{ //send message to client
@Override
public void actionPerformed(ActionEvent
event)
{
sendData(event.getActionCommand());
enterField.setText("");
} // kết thúc phương thức actionPerformed
} // kết thúc lớp trong lớp
); // kết thúc lời gọi addActionListener

add(enterField, BorderLayout.NORTH);

displayArea = new JTextArea(); // tạo khung hiển thị


tin nhắn
add(new JScrollPane(displayArea),
BorderLayout.CENTER);

setSize(300, 150); // đặt kích thức cửa sổ hiển thị


setVisible(true); // cho phép hiển thị cửa sổ
} // kết thúc hàm khởi tạo Server

// cài đặt và chạy Server


public void runServer()
{
try // cài đặt server để tiếp nhận và xử lý kết nối

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 18


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

{
server = new ServerSocket(12345, 100); // tạo
serverSocket

while (true)
{
try
{
waitForConnection(); // đợi kết nối
getStreams(); // nhận input và output streams
processConnection(); // xử lý kết nối
} // kết thúc try
catch (EOFException eofException)
{
displayMessage("\nServer đã ngắt kết nối");
} // kết thúc catch
finally
{
closeConnection(); // ngắt kết nối
counter++;
} // kết thúc finally
} // kết thúc while
} // kết thúc try
catch(IOException ioException)
{
ioException.printStackTrace();
} // kết thúc catch
} // kết thúc phương thức runServer

// Đợi kết nối và hiển thị thông tin kết nối


private void waitForConnection() throws IOException
{
displayMessage("Đang đợi kết nối từ client!. ..\n");
connection = server.accept(); // cho phép server chấp
nhận kết nối

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 19


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

displayMessage("Kết nối " + counter + "nhận từ: " +


connection.getInetAddress().getHostName());
}

// nhận streams để nhận và gửi dữ liệu


private void getStreams() throws IOException
{
// cài đặt output stream cho đối tượng
output = new
ObjectOutputStream(connection.getOutputStream());
output.flush(); // phát đi output buffer và gửi thông tin
header

// cài đặt input stream cho đối tượng


input = new
ObjectInputStream(connection.getInputStream());

displayMessage("\nĐã nhận I/O streams\n");


}

// xử lý kết nối với client


private void processConnection() throws IOException
{
String message = "Kết nối thành công!";
sendData(message); // gửi thông báo kết nối thành
công

// enable enterField cho phép server nhập tin nhắn


setTextFieldEditable(true);

do // xử lý tin nhắn từ client


{
try // đọc và hiển thị tin nhắn
{
message = (String) input.readObject(); // nhận tin

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 20


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

nhắn mới
displayMessage("\n" + message); // hiển thị tin
năắn
} // kết thúc try
catch (ClassNotFoundException
classNotFoundException)
{
displayMessage("\nĐối tượng nhận được không
đúng định dạng !");
} // kết thúc catch

} while (!message.equals("CLIENT>>>
TERMINATE"));
} // kết thúc phương thức processConnection

// Ngắt stream và socket


private void closeConnection()
{
displayMessage("\nĐang ngắt kết nối!. ..\n");
setTextFieldEditable(false); // disable khung nhập tin
nhắn

try // ngắt output, input và socket stream


{
output.close();
input.close();
connection.close();
} // kết thúc try
catch (IOException ioException)
{
ioException.printStackTrace();
} // kết thúc catch
} // kết thúc phương thức closeConnection

// gửi tin nhắn tới client

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 21


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

private void sendData(String message)


{
try // gửi đối tượng tới client
{
output.writeObject("SERVER>>> " + message);
output.flush(); // phát output tới client
displayMessage("\nSERVER>>> " + message);
} // kết thúc try
catch (IOException ioException)
{
displayArea.append("\nLỗi tạo đối tượng gửi đi!");
} // kết thúc catch
} // kết thúc phương thức sendData

// thao tác với khung hiển thị tin nhắn


private void displayMessage (final String
messageToDisplay)
{
SwingUtilities.invokeLater(
new Runnable(){
@Override
public void run() // update khung hiển thị tin nhắn
{
displayArea.append(messageToDisplay); // mở
rộng tin nhắn
} // kết thúc phương thức run
} // kết thúc lớp trong lớp
); // kết thúc lời gọi SwingUtilities.invokeLater
} // kết thúc phương thức displayMessage

// thao tác với khung nhập tin nhắn


private void setTextFieldEditable(final boolean editable)
{
SwingUtilities.invokeLater(
new Runnable()

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 22


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

{
@Override
public void run() // cho phép người dùng nhập tin
nhắn khi đã kết nối
{
enterField.setEditable(editable);
} // kết thúc phương thức run
} // kết thúc lớp trong lớp
); // kết thúc lời gọi SwingUtilities.invokeLater
} // kết thúc phương thức setTextFieldEditable
} // kết thúc lớp Server

Lớp Server
Hàm khởi tạo Server (các dòng 30 đến 55) tạo nên giao diện server, bao gồm
JTextField và JTextArea. Kết quả hiển thị trên JTextArea. Khi phương thức main
(các dòng 7 đến 12 biểu số 24.6) thực thi, tạo nên một đối tượng Server với hình
thức đóng cửa sổ mặc định và gọi tới phương thức runServer (được khai báo từ
dòng 58 đến 87).
Ví dụ 7.4.6. Lớp kiểm tra Server

1 // ServerTest.java
2 // Test ứng dụng server
3 import javax.swing.JFrame;
4
5 public class ServerTest
6 {
7 public static void main (String args[])
8 {
9 Server application = new Server(); // tạo lập server
1
0 application.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
1 application.runServer(); // chạy ứng dụng server
1 } // kết thúc hàm main
1 } // kết thúc lớp ServerTest
2
1

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 23


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

3
Phương thức runServer cài đặt server cho phép nhận và xử lý chỉ duy nhất một
kết nối tại một thời điểm. Dòng 62 tạo một ServerSocket dưới tên server có nhiệm
vụ đợi các kết nối từ client ở cổng 12345. Một tham đối khác được truyền vào hàm
khởi tạo đó là số lượng kết nối tối đa có thể kết nối tới server (trong ví dụ này là
100). Khi đạt đến số lượng kết nối tối đa, server sẽ từ chối các kết nối tiếp theo từ
client.
Dòng 68 gọi phương thức waitForConnection (từ dòng 90 đến 96) để đợi yêu
cầu kết nối từ máy khách. Sau khi kết nối được thiết lập, dòng 69 gọi phương thức
processConnection (từ dòng 122 đến 133) để gửi tin nhắn báo kết nối thành công tới
client đồng thời xử lý tất cả các tin nhắn nhận được từ máy khách. Khối “finally”
(dòng 76 đến 80) ngắt kết nối với client thông qua lời gọi phương thức
closeConnection (dòng 136 đến 151) thậm chí trong trường hợp có lỗi xảy ra.
Phương thức displayMessage (các dòng từ 169 đến 180) cũng được gọi từ những
phương thức này để hiển thị tin nhắn trong JTextArea.
Trong phương thức waitForConnection (các dòng từ 90 đến 96), dòng 93 sử
dụng ServerSocket phương thức accept để đợi yêu cầu kết nối từ client. Khi một kết
nối được thiết lập, phương thức này trả về một socket và được gán cho kết nối
connection. Phương thức accept bị khóa cho đến khi nhận được một kết nối. Các
dòng 94, 95 cho kết quả là host name của máy khách yêu cầu kết nối tới server.
Phương thức getInetAddress trong socket trả lại một InetAddress (gói java.net)
chứa thông tin của máy khách, ví dụ như địa chỉ IP (127.0.0.1) và hostname
(localhost) rất tiện dụng cho việc testing các ứng dụng mạng trên chính máy tính
của chúng ta (còn được gọi là loopback address). Nếu getHostName được gọi trên
một InetAdress có IP 127.0.0.1, thì host name tương ứng trả về sẽ là localhost.
Phương thức getStream (dòng 99 đến 109) nhận các tham chiếu tới những
socket stream khác nhau và sử dụng để khởi tạo lần lượt một ObjectOutputStream
(dòng 102) và một ObjectInputStream (dòng 106). Chú ý rằng lời gọi
ObjectOutputStream phương thức flush (dòng 103) sẽ send tới ObjectInputStream
tương ứng trên client một “stream header” chứa các thông tin về phiên bản đối
tượng tuần tự được sử dụng để gửi dữ liệu. ObjectInputStream yêu cầu những thông
tin này để có thể chuẩn bị nhận những dữ liệu đó một cách chuẩn xác.
Dòng 114 trong phương thức processConnection (các dòng từ 112 đến 133) gọi
phương thức sendData gửi thông báo tới client “SERVER>>> Kết nối thành
công!”. Vòng lặp ở các dòng 120 đến 132 thực hiện cho đến khi server nhận được
tin nhắn ngắt kết nối “CLIENT>>> TERMINATE”. Dòng 124 sử dụng

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 24


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

ObjectInputStream phương thức readObject đọc chuỗi tin nhắn được gửi đến từ
client. Sau đó, dòng 125 gọi phương thức displayMessage hiển thị tin nhắn trong
JTextArea.
Khi cuộc hội thoại kết thúc và ngắt kết nối, trở lại với phương thức
processConnection, đổng thời chương trình gọi phương thức closeConnection (từ
dòng 136 đến 151) đóng socket và các stream gắn với socket đó. Sau đó server tiếp
tục đợi các yêu cầu kết nối tiếp theo với dòng 68 ở vị trí bắt đầu vòng lặp while.
Khi người sử dụng trên ứng dụng server nhập tin nhắn và nhấn Enter, chương
trình lập tức gọi phương thức actionPerformed (từ dòng 40 đến 44) thực hiện đọc
chuỗi nhập vào từ khung nhập tin nhắn và sau đó là phương thức sendData (từ dòng
154 đến 166) để gửi chuỗi tin nhắn đó tới client. Phương thức sendData tạo đối
tượng, gửi đi output buffer và với cùng một chuỗi đó được thêm vào và hiển thị trên
cửa sổ ứng dụng server. Ở đây không cần thiết tới displayMessage để thay đổi
khung hiển thị tin nhắn, bởi vì phương thức sendData được gọi từ một hàm xử lý sự
kiện, vì thế sendData thực thi như một phần của luồng xử lý tiến trình riêng (event-
dispatch thread).
Trong ví dụ được nêu ra ở đây, server lần lượt nhận một kết nối, xử lý, ngắt kết
nối và đợi yêu cầu kết nối tiếp theo. Một cách hoạt động khác dường như hiệu quả
và thực tế hơn sẽ là một server tiếp nhận một kết nối, cài đặt cần thiết để xử lý như
một luồng thực thi riêng rẽ (event-dispatch thread), sau đó ngay lập tức trở lại trạng
thái đợi các yêu cầu kết nối tiếp theo. Các luồng riêng rẽ đang xử lý những kết nối
hiện tại hoàn toàn có thể tiếp tục thực thi trong khi server đang tập trung xử lý một
yêu cầu kết nối mới, tất cả chúng đều được xử lý một cách đồng thời. Chúng ta sẽ
tập trung nhiều hơn vào server xử lý đa luồng trong phần 7.4.3.
Lớp Client
Cũng giống như lớp server, hàm khởi tạo (các dòng từ 29 đến 56) trong lớp
Client tạo giao diện GUI cho ứng dụng với một JTextField và một JTextArea.
Client hiển thị kết quả trên khung hiển thị tin nhắn JTextArea. Khi phương thức
main (từ dòng 7 đến 19 Biểu số 24.8) thực thi xác định hình thức đóng cửa sổ mặc
định và gọi tới phương thức runClient(được khai báo ở các dòng từ 59 đến 79).
Trong ví dụ này, vai trò máy khách có thể là bất cứ máy tính nào trên Internet với
địa chỉ IP hoặc host name của máy chủ server là một tham đối được đưa vào
chương trình. Ví dụ trong câu lênh sau:

java Client 192.168.1.15


sẽ gửi yêu cầu kết nối tới máy chủ có địa chỉ IP là 192.168.1.15.

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 25


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Ví dụ: Ứng dụng Client

1 // Client.java
2 // Client that reads and displays information sent from a Server.
3 import java.io.EOFException;
4 import java.io.IOException;
5 import java.io.ObjectInputStream;
6 import java.io.ObjectOutputStream;
7 import java.net.InetAddress;
8 import java.net.Socket;
9 import java.awt.BorderLayout;
1 import java.awt.event.ActionEvent;
0 import java.awt.event.ActionListener;
1 import javax.swing.JFrame;
1 import javax.swing.JScrollPane;
1 import javax.swing.JTextArea;
2 import javax.swing.JTextField;
1 import javax.swing.SwingUtilities;
3
1
public class Client extends JFrame
4
{
1
private JTextField enterField; // khung nhập tin nhắn
5
private JTextArea displayArea; // khung hiển thị tin nhắn
1
6 private ObjectOutputStream output; // output stream gửi tới
server
1
7 private ObjectInputStream input; // input stream từ server
1 private String message = ""; // tin nhắn từ server
8 private String chatServer; // host server sẽ kết nối
1 private Socket client; // socket giao tiếp server
9
2 // khởi tạo chatServer và cài đặt giao diện GUI
0 public Client (String host)
2 {
1 super("Client");// Tên thanh tiêu đề cửa sổ ứng dụng
2
2 chatServer = host; // đặt server mà client sẽ kết nối

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 26


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

2
3 enterField = new JTextField(); // khởi tạo khung nhập tin
2nhắn
4 enterField.setEditable(false);
2 enterField.addActionListener(
5 new ActionListener()
2 { // gửi tin nhắn server
6 @Override
2 public void actionPerformed(ActionEvent event)
7
{
2
sendData(event.getActionCommand());
8
enterField.setText("");
2
} // kết thúc phương thức actionPerformed
9
} // kết thúc lớp trong lớp
3
0 ); // kết thúc lời gọi addActionListener
3
1 add(enterField, BorderLayout.NORTH); // thêm vào cửa sổ
3hiển thị
2
3 displayArea = new JTextArea(); // khởi tạo khung hiển thị
3 tin nhắn
3 add(new JScrollPane(displayArea), BorderLayout.CENTER); // thêm
vào cửa sổ hiển thị
4
3
setSize(300, 150); // đặt kích thước cho cửa sổ hiển thị
5
setVisible(true); // hiển thị cửa sổ: có
3
6 } // kết thúc hàm khởi tạo Client
3
7 // Kết nối và xử lý tin nhắn từ server
3 public void runClient()
8 {
3 try // kết nối tới server, nhận các stream và xử lý kết nối
9 {
4 connectToServer(); // tạo socket -> tạo kết nối
0 getStreams(); // nhận input và output stream
4 processConnection(); // xử lý kết nối

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 27


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

1 } // kết thúc try


4 catch (EOFException eofException)
2 {
4 displayMessage("\nClient đã ngắt kết nối!");
3 } // kết thúc catch
4 catch (IOException ioException)
4 {
4 ioException.printStackTrace();
5
} // kết thúc catch
4
finally
6
{
4
closeConnection(); // ngắt kết nối
7
} // kết thúc finally
4
8 } // kết thúc phương thức runClient
4
9 // kết nối tới server
5 private void connectToServer() throws IOException
0 {
5 displayMessage("Đang kết nối. ..\n");
1
5 // tạo socket -> tạo kết nối tới server
2 client = new Socket(InetAddress.getByName(chatServer),
512345);
3
5 // hiển thị thông tin kết nối
4 displayMessage("Đã kết nối tới: " +
5 client.getInetAddress().getHostName());
5
} // kết thúc phương thức connectToServer
5
6
// nhận các stream cho phép gửi và nhận dữ liệu
5
private void getStreams() throws IOException
7
{
5
8 // cài đặt output stream
5 output = new
9 ObjectOutputStream(client.getOutputStream());

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 28


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

6 output.flush(); // phát đi ouput buffer, gửi thông tin header


0
6 // cài đặt input stream
1 input = new ObjectInputStream(client.getInputStream());
6
2 displayMessage("\nĐã nhận I/O streams\n");
6 }
3
6
// xử lý kết nối với server
4
private void processConnection() throws IOException
6
{
5
// enable enterField cho phép người dùng nhập tin nhắn
6
6 setTextFieldEditable(true);
6
7 do // xử lý và hiển thị tin nhắn
6 {
8 try // đọc và hiển thị tin nhắn
6 {
9 message = (String) input.readObject(); // đọc tin nhắn
7mới
0 displayMessage("\n" + message); // hiển thị tin nhắn
7 } // kết thúc try
1 catch (ClassNotFoundException
7classNotFoundException)
2 {
7 displayMessage("\nĐối tượng nhận được không đúng
3 định dạng!");
7 } // kết thúc catch
4 } while (!message.equals("SERVER>>> TERMINATE"));
7 } // kết thúc phương thức processConnection
5
7
// ngắt các stream và socket
6
private void closeConnection()
7
{
7
displayMessage("\nĐang ngắt kết nối!. ..");
7

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 29


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

8 setTextFieldEditable(false); // disable khung nhập tin nhắn


7
9
8 try // đóng socket, input và output stream
0 {
8 output.close();
1 input.close();
8 client.close();
2
} // kết thúc try
8
catch (IOException ioException)
3
{
8
ioException.printStackTrace();
4
} // kết thúc catch
8
5 } // kết thúc phương thức closeConnection
8
6 // gửi tin nhắn tới server
8 private void sendData(String message)
7 {
8 try // gửi đối tượng tới server
8 {
8 output.writeObject("CLIENT>>> " + message);
9 output.flush(); // phát đi dữ liệu output
9 displayMessage("\nCLIENT>>> " + message);
0 } // kết thúc try
9 catch (IOException ioException)
1
{
9
displayArea.append("\nLỗi tạo đối tượng gửi đi!");
2
} // kết thúc catch
9
} // kết thúc phương thức sendData
3
9
4 // thao tác với khung hiển thị tin nhắn
private void displayMessage(final String messageToDisplay){
9
5 SwingUtilities.invokeLater(
9 new Runnable()
6 {

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 30


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

9 @Override
7 public void run() // cập nhật khung hiển thị tin nhắn
9 {
8 displayArea.append(messageToDisplay);
9 } //kết thúc phương thức run
9 } // kết thúc lớp trong lớp
1 ); // kết thúc lời gọi SwingUtilities
00
} // kết thúc phương thức displayMessage
1
// thao tác với khung nhập tin nhắn
01
private void setTextFieldEditable(final boolean editable)
1
{
02
SwingUtilities.invokeLater(
1
03 new Runnable()
{
1 @Override
04 public void run()// cho phép người dùng nhập tin nhắn
1khi đã kết nối
05 {
1 enterField.setEditable(editable);
06 } // kết thúc phương thức run
1 } // kết thúc lớp trong lớp
07 ); // kết thúc lời gọi tới SwingUtilities.invokeLater
1 } // kết thúc phương thức setTextFieldEditable
08 } // kết thúc lớp Client
1
09
1
10
1
11
1
12
1
13

Ví dụ: Lớp kiểm tra Client

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 31


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

// ClientTest.java
// Test ứng dụng Client
import javax.swing.JFrame;

public class ClientTest


{
public static void main(String args[])
{
Client application; // khai báo ứng dụng client

// nếu không đặt địa chỉ IP của server


if (args.length == 0)
application = new Client("127.0.0.1"); // kết nối tới localhost
else
application = new Client(args[0]); // sử dụng IP để kết nối

application.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
application.runClient(); // chạy ứng dụng Client
} // kết thúc hàm main
} // kết thúc lớp ClientTest
Kết quả:

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 32


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 33


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Client phương thức runClient (các dòng từ 59 đến 79) cài đặt kết nối tới server,
xử lý tin nhắn từ server và ngắt kết nối khi cuộc hội thoại kết thúc. Dòng 63 gọi
phương thức connectToServer (được khai báo ở các dòng từ 95 đến 105) nhận các
tham chiếu tới những đối tượng stream ứng với socket. Sau đó, dòng 65 gọi phương
thức processConnection (khai báo từ dòng 108 đến 126) để nhận và hiển thị tin
nhắn được gửi đến từ server. Khối finally (tại dòng 75 đến 78) gọi tới
closeConnection (các dòng từ 129 đến 144) để đóng các stream và socket thậm chí
trong trường hợp có lỗi xảy ra. Phương thức displayMessage (từ dòng 162 đến 173)
được gọi bởi các phương thức này sử dụng “event-dispatch thread” để hiển thị tin
nhắn trong cửa sổ ứng dụng.
Phương thức connectToServer (các dòng từ 82 đến 92) khởi tạo một socket gọi
là client (dòng 87) từ đó tạo lập kết nối. Phương thức này truyền 2 tham đối tới hàm
khởi tạo socket gồm địa chỉ IP máy chủ và cổng port (12345) mà tại đó ứng dụng
server đang đợi yêu cầu kết nối. Đối với tham đối đầu tiên, InetAddress static
phương thức getByName trả về một đối tượng InetAddress chứa địa chỉ IP được
xác định bởi người dùng thông qua tham đối truyền vào ứng dụng- “args” (hoặc
mặc định là 127.0.0.1). Phương thức getByName có thể nhận một chuỗi đại diện
cho hoặc địa chỉ IP thực hoặc host name của server. Tham đối thứ nhất cũng có thể
được thể hiện dưới các cách viết khác nhau. Ví dụ đối với localhost – 127.0.0.1, có
thể viết như sau:

InetAddress.getByName( "localhost" )
Hoặc

InetAddress. getLocalHost()

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 34


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Ở đây, chúng ta lựa chọn chạy ứng dụng trên cùng một máy (localhost) với
mục đích testing. Thông thường, tham đối thứ nhất là địa chỉ IP của một máy tính
khác. Khi đó ta dùng phương thức getByName để lấy đối tượng InetAddress với
tham đối là địa chỉ IP hoặc host name của máy tính đó. Tham đối thứ 2 của hàm
khởi tạo socket là cổng port. Port này phải hoàn toàn trùng khớp với với cổng port
mà server đang đợi yêu cầu kết nối (được gọi là handshake point). Một khi kết nối
được thiết lập, các dòng 90, 91 hiển thị một tin nhắn cho ta biết tên của máy chủ mà
máy khách đang kết nối tới.
Tương tự như lớp Server
Vòng lặp trong phương thức processConnection (từ dòng 108 đến 126) thực thi
cho đến khi nhận được tin nhắn “SERVER>>> TERMINATE”. Dòng 117 đọc
chuỗi tin nhắn gửi đến từ server và dòng 118 gọi phương thức displayMessage hiển
thị tin nhắn trên cửa sổ ứng dụng.
Sau khi cuộc đối thoại hoàn thành, phương thức closeConnection (từ dòng 129
đến 144) đóng các stream và socket.
Khi người sử dụng ứng dụng client nhập vào tin nhắn và nhấn Enter, chương
trình gọi phương thức actionPerformed (các dòng 41 đến 45) đọc chuỗi nhập vào và
gửi tới server thông qua lời gọi phương thức sendData (dòng 147 đến 159). Phương
thức sendData tạo đối tượng và truyền đi output buffer đồng thời hiển thị chính
chuỗi tin nhắn đó trên cửa sổ client. Một lần nữa, không cần thiết phải gọi phương
thức displayMessage để thay đổi khung hiển thị ở đây, bởi vì phương thức sendData
được gọi ra từ một hàm xử lý sự kiện.

2. Lập trình ứng dụng Applet


2.1. Hai loại ứng dụng Java
 Applet

Chương trình Java chạy trong mộttrangweb nhờ vào trình duyệt hỗ trợ Java.
 Stand-alone Application

Giao diện dòng lệnh (console): Tương tác với người dùng thông qua các dòng
ký tự.
Giao diện đồ hoạ (GUI): Tương tác với người dùng bằng nhiều cách khác nhau
như hình ảnh, nút nhấn, biểu tượng…việc xử lý ứng dụng dựa trên các sự kiện.
2.2. Xây dựng các applet
LớpApplet

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 35


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Java có lớp java.applet.Applet kế thừa từ lớp java.awt.Component cho phép tạo


ra các applet trong Web.
Mọi lớp applet do người dùng tạo ra đều phải kế thừa từ lớp Applet.
Ví dụ 1: Tạo file chuongtrinhapplet.java
import java.applet.Applet;
import java.awt.Graphics;
public class chuongtrinhapplet1 extends Applet
{
public void paint(Graphics g)
{
g.drawString("Khoa CNTT-VDHM-HN", 24, 48);
}
}
Dịch: javac chuongtrinhapplet.java
Thực thi applet
Tạo file thuapplet.html như sau:
<html>
<APPLET CODE=“ chuongtrinhapplet.class” WIDTH=500 HEIGHT=500
</APPLET>
</html>
Sau đó mở file này bằng trình duyệt WEB
2.3. Khung của một applet cơ bản
Sau đây là cấu trúc vòng đời của một chương trình applet cơ bản

import java.applet.Applet;
import java.awt.Graphics;

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 36


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

public class TestApplet extends Applet


{
public void init() {…}
public void start() {…}
public void stop() {…}
public void destroy {…}
public void paint( Graphics g) {…}
}
2.4. Hoạt động của Applet
Phương Chức năng
thức

init() Được gọi trong quá trình khởi tạo applet. Trong quá
trình khởi tạo, nó sẽ tạo đối tượng để cung cấp cho applet.
Phương thức này được dùng để tải các hình ảnh đồ hoạ, khởi
tạo các biến và tạo các đối tượng.

start() Được gọi khi một applet bắt đầu thực thi.Một khi quá
trình khởi tạo hoàn tất, thì applet được khởi động. Phương
thức này được dùng để khởi động lại applet sau khi nó đã
ngừng trước đó

stop() Được gọi khi ngừng thực thi một applet. Một applet bị
ngừng trước khi nó bị huỷ.

destroy() Được dùng để huỷ một applet. Khi một applet bị huỷ,
thì bộ nhớ, thời gian thực thi của vi xử lý, không gian đĩa
được trả về cho hệ thống.

Chú ý: paint() không phải là phương thức của Applet mà là của Component.
paint() được gọi mỗi khi cửa sổ được vẽ lại.
2.5. Hoạt động của Applet
Vòng đời của một Applet:
Nạp một applet: applet được khởi tạo và thực thi
Chuyển hoặc trở về trang Web: Các phương thức stop và start sẽ được gọi
Nạp lại applet: như quá trình nạp applet

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 37


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Thoát khỏi trình duyệt: phương thức stop và destroy sẽ được gọi.
2.6. Lớp Graphics
java.awt.Graphics là lớp cung cấp các phương thức vẽ đồ hoạ cơ bản:
 Đường thẳng (Line)
 Đường oval (Oval)
 Hình chữ nhật (Rectangle)
 Đa giác (Polygon)
 Vănbản(Text)
 Hình ảnh (Image),….

Hệ toạ độ:

 Vẽ đường thẳng
public void drawLine(int x1, int y1, int x2, int y2);
 Vẽ hình chữ nhật
public void drawRect(int x, int y, int width, int height);
 Tô một hình chữ nhật
public void fillRect(int x, int y, int width, int height);
 Xoá một vùng chữ nhật
public void clearRect(int x, int y, int width, int height);
 Vẽ đa giác
public void drawPolygon(int[] x, int[] y, int numPoint);
public void drawPolygon(Polygon p);
Ví dụ. Vẽ đa giác, đoạn thẳng và hình chữ nhật
import java.applet.Applet;
import java.awt.Graphics;
public class vedagiac extends Applet
{
public void init()

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 38


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

{
System.out.println("ve cac hinh ");
}
public void paint(Graphics g)
{
g.drawLine(10, 10, 400, 250);
g.drawLine(45, 12, 67, 300);
g.drawRect(100, 50, 130, 170);
g.fillRect(120, 70, 70, 70);
int[] x = { 280, 210, 330, 430, 270,350 };
int[] y = { 20, 140, 170, 70, 90,120 };
g.drawPolygon(x, y, x.length);
}
}
Kết quả chương trình

 Vẽ đường tròn/elip
public void drawOval(int x, int y, int width, int height);
 Tô đường tròn/elip
public void fillOval(int x, int y, int width, int height);
 Vẽ cung tròn
public void drawArc(int x, int y, int width, int height,
int startAngle, int arcAngle);
 Vẽ xâu kí tự
public void drawString(String str, int x, int y);
 Vẽ ảnh
public void drawImage(Image img, int x, int y,...);

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 39


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

import java.applet.Applet;
import java.awt.Graphics;
public class demovehinh extends Applet
{
public void init()
{
System.out.println("Minh hoa cac hinh don gian");
}
public void paint(Graphics g)
{
int xstart = 70, ystart = 40, size = 100;
g.drawOval(xstart, ystart, size, size);
g.drawOval(xstart + (size*3)/4, ystart, size, size);
g.drawOval(xstart + size/2, ystart + size/2, size, size);
g.drawArc(xstart, ystart, 300, 200, 0, -90);
g.drawString("Khoa CNTT 96 Dinh Cong !", xstart + 265, ystart +
90);
}
}

Dưới đây là kết quả của chương trình

Dưới đây là chương trình dưới thiệu về cách load ảnh vào chương trình
(cachdunganh.java)
import java.applet.Applet;

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 40


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

import java.awt.Graphics;
import java.awt.Image;
public class cachdunganh extends Applet
{ public void init()
{ System.out.println("chuong trinh load anh");
}
public void paint(Graphics g)
{ Image image = getToolkit().getImage("truck1.jpg");
g.drawImage(image, 10, 10, this);
}
}

Dưới đây là kết quả của chương trình:

2.7. Các lớp tiện ích khác


 Lớp Point: biểu diễn điểm trên màn hình.
 Lớp Dimension: biểu diễn kích thước về chiều rộng và chiều cao của một đối
tượng.
 Lớp Rectangle: biểu diễn hình chữ nhật.
 Lớp Polygon: biểu diễn đa giác.
 Lớp Color: biểu diễn màu sắc.
import java.applet.Applet;
import java.awt.*;

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 41


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

public class viduvemau extends Applet


{
public void paint(Graphics g)
{
Dimension size = getSize();
g.setColor(Color.orange);
g.fillRect(0, 0, size.width, size.height);
Color color = new Color(10, 150, 20);
g.setColor(color);
g.drawString("Vien Dai Hoc Mo HN",
size.width/2 - 50, size.height/2);
}
}

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

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 42


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

2.8. Xử lý font vẽ
import java.applet.Applet;
import java.awt.*;
public class xulyfont extends Applet
{
public void paint(Graphics g)
{
Font font = new Font("Arial", Font.BOLD, 15);
g.setFont(font);
g.drawString("Dang ap dung phong Arial, Dam, kich thuoc 30", 50,
50);
}
}

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 43


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Bài tập cuối chương


Bài tập 7.1: Xây dựng chương trình sử dụng phương thức getByname để tạo ra mọt
InetAddress
Bài tập 7.2: Xây dựng chương trình lấy về tên máy khi biết địa chỉ IP của nó, bằng
cách sử dụng phương thức getHostName
Bài tập 7.3: Xây dựng chương trình HostLookUp tương tự như chương trình
NSLookUp của Window, chương trình này có nhiệm vụ khị bạn gõ vào IP thì nó sẽ
trả về tên miền và ngược lại
Bài tập 7.4: Xây dựng chương trình tạo ra một URL và kiểm tra xem giao thức
tương ứng với các URL có được hỗ trợ trong virtual machine của bạn hay không?
Bài tập 7.5: Xây dựng chương trình ứng dụng chat giữa hai máy tính
Bài tập 7.6: Xây dựng chương trình truyền và nhận file giữa hai máy tính
Bài tập 7.7: Xây dựng chương trình cho phép nhập vào 2 số nguyên a và b. Xây
dựng các phép tính cộng, trừ, nhân, chia.
Bài tập 7.8: Xây dựng chương trình bằng java applet cho phép nhập vào ba số thực.
Kiểm tra xem ba cạch đó có tạo thành tam giác hay không? Sau đó tính diện tích và
chu vi của tam giác đó.
Bài tập 7.9: Xây dựng chương trình giải phương trình bậc hai trên java applet.
Bài tập 7.10: Xây dựng chương trình mô phỏng quyển sách trên webste.
Bài tập 7.11: Xây dựng ứng dụng mô phỏng thuật toán sắp xếp chọn (selection sort
và Bubble Sort).
Bài tập 7.12: Một công ty cần quản lý các phương tiện gồm có các loại phương tiện
cơ bản sau ô tô, xe máy. Mỗi loại phương tiện cần quản lý các thông số cơ bản sau:
Hãng sản xuất, biển số, màu xe, năm xản xuất, giá thành, họ tên chủ đăng ký
phương tiện. Ngoài ra, ô tô thì phải biết thêm một số thông tín sau, số ghế, loại máy,
còn xe máy thì biết thêm công suất
a, Xây dựng các lớp cho các phương tiện, trong đó lớp ô tô, xe máy là được kế thừa
từ lớp phương tiện giao thông nói chung
b, Viết chương trình thực hiện các menu sau
1/ Đăng ký loại phương tiện mới
2/ Tìm theo họ tên chủ đăng ký phương tiện
3/ Thoát khỏi hệ thống

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 44


Trung tâm Đào tạo E-learning Cơ hội học tập cho mọi người

Hãy viết chương trình applet thực hiện các yêu cầu trên. Có các giao diện cho người
dùng nhập dữ liệu và hiển thị dữ liệu cũng như tìm kiếm thông tin.

Kỹ thuật lập trình hướng đối tượng - Bài 8 Trang 45


TRƯỜNG ĐẠI HỌC MỞ HÀ NỘI ĐỀ KIỂM TRA TỰ LUẬN
KHOA CÔNG NGHỆ THÔNG TIN Môn: IT07(Lập trình hướng đối tượng)
**********************

Họ tên sinh viên:…………………………… Ngày sinh:………..…… Lớp: …………………..

ĐỀ SỐ 1
*Đề Bài: Viết chương trình theo hướng đối tượng thực hiện quản lý danh sách TAI NGHE
theo yêu cầu sau:
-Lớp PHUKIEN cho phép mô tả thông tin chung phụ kiện gồm:
+Thuộc tính: MaPK(Mã phụ kiện), TenPK(Tên phụ kiện), MauSac(Màu sắc)
+Phương thức: Khởi tạo, nhap( ), xuat( ), …
-Lớp TAINGHE kế thừa từ lớp PHUKIEN bổ sung thêm các thuộc tính và định nghĩa thêm
các phương thức sau:
+Thuộc tính bổ sung: Loai(Loại tai nghe), SoLuongMua(Số lượng mua),
DonGiaBan(Đơn giá bán)
+Phương thức định nghĩa mới và bổ sung: Khởi tạo, nhap( ), xuat( ), thanhTien( ), …
Trong đó: Thành tiền = Số lượng mua * Đơn giá bán
-Chương trình chính cần quản lý danh sách TAINGHE với các yêu cầu sau:
+ Nhập danh sách tai nghe từ bàn phím
+ In lại danh sách tai nghe đã được nhập
+ Lưu danh sách tai nghe vào file "tainghe.dat"
+ Tính tổng tiền tất cả các tai nghe có trong danh sách

*Hướng dẫn cách làm bài và nộp bài


-Sinh viên tạo 01 file chương trình java hoặc tạo Project để thực hiện
-Đầu mỗi file chương trình phải có đủ thông tin: Mã sinh viên, Họ tên, Lớp
-Tên File chính của chương trình được đặt tên theo nguyên tắc sau:
Nguyên tắc: Mã SV–Họ tên–Lớp–Số đề.java
Ví dụ: 1910A001-NguyenThiHa-19A5-De01.java

HẾT!
TRƯỜNG ĐẠI HỌC MỞ HÀ NỘI ĐỀ KIỂM TRA TỰ LUẬN
KHOA CÔNG NGHỆ THÔNG TIN Môn: IT07(Lập trình hướng đối tượng)
**********************

Họ tên sinh viên:…………………………… Ngày sinh:………..…… Lớp: …………………..

ĐỀ SỐ 2
*Đề Bài: Viết chương trình theo hướng đối tượng thực hiện quản lý việc nhập
SACHGIAOKHOA theo yêu cầu sau:
-Lớp TAILIEU cho phép mô tả thông tin chung tài liệu gồm:
+Thuộc tính: MaTaiLieu(Mã tài liệu), TenTaiLieu(Tên tài liệu), NamXB(Năm xuất bản)
+Phương thức: Khởi tạo, nhap( ), xuat( ), …
-Lớp SACHGIAOKHOA kế thừa từ lớp TAILIEU bổ sung thêm các thuộc tính và định
nghĩa thêm các phương thức sau:
+Thuộc tính bổ sung: Lop(Lớp), DonGiaNhap(Đơn giá nhập), SoLuongNhap(Số lượng
nhập)
+Phương thức định nghĩa mới và bổ sung: Khởi tạo, nhap( ), xuat( ), thanhTien( ), …
Trong đó: Thành tiền = Đơn giá nhập * Số lượng nhập
-Chương trình chính cần quản lý nhập danh sách SACHGIAOKHOA với các yêu cầu sau:
+ Nhập danh sách sách giáo khoa từ bàn phím
+ In lại danh sách sách giáo khoa đã nhập
+ Lưu danh sách sách giáo khoa vào file "sachgiaokhoa.dat"
+ Tính tổng tiền tất cả các sách giáo khoa đã nhập

*Hướng dẫn cách làm bài và nộp bài


-Sinh viên tạo 01 file chương trình java hoặc tạo Project để thực hiện
-Đầu mỗi file chương trình phải có đủ thông tin: Mã sinh viên, Họ tên, Lớp
-Tên File chính của chương trình được đặt tên theo nguyên tắc sau:
Nguyên tắc: Mã SV–Họ tên–Lớp–Số đề.java
Ví dụ: 1910A001-NguyenThiHa-19A5-De01.java

HẾT!
TRƯỜNG ĐẠI HỌC MỞ HÀ NỘI ĐỀ KIỂM TRA TỰ LUẬN
KHOA CÔNG NGHỆ THÔNG TIN Môn: IT07(Lập trình hướng đối tượng)
**********************

Họ tên sinh viên:…………………………… Ngày sinh:………..…… Lớp: …………………..

ĐỀ SỐ 3
*Đề Bài: Viết chương trình theo hướng đối tượng thực hiện quản lý việc thu
HOADONDICHVU của chung cư theo yêu cầu sau:
-Lớp CUDAN cho phép mô tả thông tin chung cư dân ở các căn hộ gồm:
+Thuộc tính: SoPhong(Số phòng), TenCD(Tên cư dân), SoDT(Số điện thoại)
+Phương thức: Khởi tạo, nhap( ), xuat( ), …
-Lớp HOADONDICHVU kế thừa từ lớp CUDAN bổ sung thêm các thuộc tính và định
nghĩa thêm các phương thức sau:
+Thuộc tính bổ sung: TenDV(Tên dịch vụ), SoLuongSuDung(Số lượng sử dụng),
DonGia(Đơn giá)
+Phương thức định nghĩa mới và bổ sung: Khởi tạo, nhap( ), xuat( ), thanhTien( ), …
Trong đó: Thành tiền = Số lượng sử dụng * Đơn giá
-Chương trình chính cần quản lý nhập danh sách HOADONDICHVU với các yêu cầu sau:
+ Nhập danh sách hóa đơn dịch vụ từ bàn phím
+ In lại danh sách hóa đơn dịch vụ đã nhập
+ Lưu danh sách hóa đơn dịch vụ vào file "hoadondichvu.dat"
+ Tính tổng tiền tất cả các hóa đơn dịch vụ đã nhập

*Hướng dẫn cách làm bài và nộp bài


-Sinh viên tạo 01 file chương trình java hoặc tạo Project để thực hiện
-Đầu mỗi file chương trình phải có đủ thông tin: Mã sinh viên, Họ tên, Lớp
-Tên File chính của chương trình được đặt tên theo nguyên tắc sau:
Nguyên tắc: Mã SV–Họ tên–Lớp–Số đề.java
Ví dụ: 1910A001-NguyenThiHa-19A5-De01.java

HẾT!
GỢI Ý CÁCH CHẤM ĐIỂM BÀI KIỂM TRA

TT NỘI DUNG ĐIỂM GHI CHÚ

Sinh viên tổ chức bài Project và lưu thư


mục
Đặt tên file đúng yêu cầu 0.5
Cung cấp đầy đủ thông tin trong file
chương trình

Xây dựng 02 lớp theo yêu cầu 2.0


Thực hiện nhập danh sách 2.0
Chương
Thực hiện hiện danh sách 2.0
trình
Thực hiện lưu file 1.5

Thực hiện tính tổng 2.0

TỔNG: 10đ

HẾT

You might also like