Giáo trình Ngôn ngữ lập trình Java

ĐỐI TƯỢNG VÀ LỚP

Gần như bất cứ thứ gì cũng có thể được mô hình hóa bằng một đối tượng.

Chẳng hạn, một màu, một hình vẽ, một cái nhiệt kế.

Mỗi đối tượng có một tập các thuộc tính (attribute) như các giá trị hay trạng thái

để mô hình hóa đối tượng đó. Chẳng hạn, một cái nhiệt kế có thể có thuộc tính là vị

trí hiện tại của nó và trạng thái hiện tại tắt hay bật, các thuộc tính một màu có thể là

giá trị của ba thành phần RGB của nó. Một cái ô tô có các thuộc tính như: lượng xăng

hiện có, tốc độ hiện tại, biển số.

Mỗi đối tượng có một tập các trách nhiệm mà nó thực hiện bằng cách cung cấp

dịch vụ cho các đối tượng khác. Các dịch vụ này có thể cho phép truy vấn thông tin

hoặc làm thay đổi trạng thái của đối tượng. Ví dụ, nhiệt kế cho phép truy vấn về tình

trạng tắt/bật của nó; đáp ứng các yêu cầu về nhiệt độ hiện hành mà nó đo được, yêu

cầu tắt/bật. Một cái ô tô cho phép tăng ga, giảm ga để tăng/giảm tốc độ di chuyển.

Đối với thiết kế tốt, các đối tượng bên ngoài không phải quan tâm xem một đối

tượng nào đó cài đặt một dịch vụ như thế nào, mà chỉ cần biết đối tượng đó cung

cấp những dịch vụ nào (hay nó có những trách nhiệm gì). Chẳng hạn, người lái xe

không cần biết cơ chế chuyển đổi từ lực nhấn lên chân đạp ga sang sự thay đổi về

tốc độ của ô tô.

pdf 241 trang kimcuc 7020
Bạn đang xem 20 trang mẫu của tài liệu "Giáo trình Ngôn ngữ lập trình Java", để tải tài liệu gốc về máy hãy click vào nút Download ở trên

Tóm tắt nội dung tài liệu: Giáo trình Ngôn ngữ lập trình Java

Giáo trình Ngôn ngữ lập trình Java
 1
Mục lục 
GIỚI THIỆU .............................................................................5 
Chương 1. MỞ ĐẦU ............................................................7 
1.1. KHÁI NIỆM CƠ BẢN ................................................ 12 
1.2. ĐỐI TƯỢNG VÀ LỚP................................................ 13 
1.3. CÁC NGUYÊN TẮC TRỤ CỘT ................................ 15 
Chương 2. NGÔN NGỮ LẬP TRÌNH JAVA ................... 20 
2.1. ĐẶC TÍNH CỦA JAVA .............................................. 20 
2.1.1. Máy ảo Java – Java Virtual Machine ............... 21 
2.1.2. Các nền tảng Java ............................................. 23 
2.1.3. Môi trường lập trình Java ................................ 23 
2.1.4. Cấu trúc mã nguồn Java .................................. 24 
2.1.5. Chương trình Java đầu tiên ............................. 25 
2.2. BIẾN ............................................................................. 27 
2.3. CÁC PHÉP TOÁN CƠ BẢN...................................... 28 
2.3.1. Phép gán ............................................................ 28 
2.3.2. Các phép toán số học........................................ 28 
2.3.3. Các phép toán khác .......................................... 29 
2.3.4. Độ ưu tiên của các phép toán .......................... 30 
2.4. CÁC CẤU TRÚC ĐIỀU KHIỂN ................................ 30 
2.4.1. Các cấu trúc rẽ nhánh....................................... 31 
2.4.2. Các cấu trúc lặp ................................................ 37 
2.4.3. Biểu thức điều kiện trong các cấu trúc điều khiển 43 
Chương 3. LỚP VÀ ĐỐI TƯỢNG .................................... 48 
3.1. TẠO VÀ SỬ DỤNG ĐỐI TƯỢNG ............................ 49 
3.2. TƯƠNG TÁC GIỮA CÁC ĐỐI TƯỢNG ................. 51 
Chương 4. BIẾN VÀ CÁC KIỂU DỮ LIỆU ...................... 57 
4.1. BIẾN VÀ CÁC KIỂU DỮ LIỆU CƠ BẢN ................. 58 
4.2. THAM CHIẾU ĐỐI TƯỢNG VÀ ĐỐI TƯỢNG ...... 59 
4.3. PHÉP GÁN .................................................................. 62 
4.4. CÁC PHÉP SO SÁNH ................................................ 63 
 2
4.5. MẢNG ......................................................................... 64 
Chương 5. HÀNH VI CỦA ĐỐI TƯỢNG ....................... 70 
5.1. PHƯƠNG THỨC VÀ TRẠNG THÁI ĐỐI TƯỢNG70 
5.2. TRUYỀN THAM SỐ VÀ GIÁ TRỊ TRẢ VỀ .............. 71 
5.3. CƠ CHẾ TRUYỀN BẰNG GIÁ TRỊ .......................... 73 
5.4. ĐÓNG GÓI VÀ CÁC PHƯƠNG THỨC TRUY NHẬP 75 
5.5. KHAI BÁO VÀ KHỞI TẠO BIẾN THỰC THỂ........ 79 
5.6. BIẾN THỰC THỂ VÀ BIẾN ĐỊA PHƯƠNG ........... 80 
Chương 6. SỬ DỤNG THƯ VIỆN JAVA ......................... 85 
6.1. ArrayList ..................................................................... 85 
6.2. SỬ DỤNG JAVA API ................................................. 87 
6.3. MỘT SỐ LỚP THÔNG DỤNG TRONG API ........... 88 
6.3.1. Math ................................................................... 88 
6.3.2. Các lớp bọc ngoài kiểu dữ liệu cơ bản ............ 89 
6.3.3. Các lớp biểu diễn xâu kí tự .............................. 90 
6.4. TRÒ CHƠI BẮN TÀU ................................................ 91 
Chương 7. THỪA KẾ VÀ ĐA HÌNH ............................. 103 
7.1. QUAN HỆ THỪA KẾ .............................................. 103 
7.2. THIẾT KẾ CÂY THỪA KẾ ...................................... 104 
7.3. CÀI ĐÈ – PHƯƠNG THỨC NÀO ĐƯỢC GỌI? ... 107 
7.4. CÁC QUAN HỆ IS-A VÀ HAS-A ........................... 108 
7.5. KHI NÀO NÊN DÙNG QUAN HỆ THỪA KẾ?.... 110 
7.6. LỢI ÍCH CỦA QUAN HỆ THỪA KẾ ..................... 110 
7.7. ĐA HÌNH .................................................................. 111 
7.8. GỌI PHIÊN BẢN PHƯƠNG THỨC CỦA LỚP CHA114 
7.9. CÁC QUY TẮC CHO VIỆC CÀI ĐÈ ....................... 115 
7.10. CHỒNG PHƯƠNG THỨC .................................... 116 
7.11. CÁC MỨC TRUY NHẬP ....................................... 117 
Chương 8. LỚP TRỪU TƯỢNG VÀ INTERFACE ........ 124 
8.1. MỘT SỐ LỚP KHÔNG NÊN TẠO THỰC THỂ .... 124 
8.2. LỚP TRỪU TƯỢNG VÀ LỚP CỤ THỂ ................. 126 
 3
8.3. PHƯƠNG THỨC TRỪU TƯỢNG .......................... 127 
8.4. VÍ DỤ VỀ ĐA HÌNH ................................................ 127 
8.5. LỚP Object ................................................................ 131 
8.6. ĐỔI KIỂU – KHI ĐỐI TƯỢNG MẤT HÀNH VI CỦA MÌNH 132 
8.7. ĐA THỪA KẾ VÀ VẤN ĐỀ HÌNH THOI.............. 135 
8.8. INTERFACE .............................................................. 137 
Chương 9. VÒNG ĐỜI CỦA ĐỐI TƯỢNG ................... 143 
9.1. BỘ NHỚ STACK VÀ BỘ NHỚ HEAP ................... 143 
9.2. KHỞI TẠO ĐỐI TƯỢNG ........................................ 145 
9.3. HÀM KHỞI TẠO VÀ VẤN ĐỀ THỪA KẾ ............ 149 
9.3.1. Gọi hàm khởi tạo của lớp cha ........................ 150 
9.3.2. Truyền đối số cho hàm khởi tạo lớp cha ...... 152 
9.4. HÀM KHỞI TẠO CHỒNG NHAU ........................ 153 
9.5. TẠO BẢN SAO CỦA ĐỐI TƯỢNG ....................... 154 
9.6. CUỘC ĐỜI CỦA ĐỐI TƯỢNG............................... 159 
Chương 10. THÀNH VIÊN LỚP VÀ THÀNH VIÊN THỰC THỂ 164 
10.1. BIẾN CỦA LỚP ...................................................... 164 
10.2. PHƯƠNG THỨC CỦA LỚP ................................. 165 
10.3. GIỚI HẠN CỦA PHƯƠNG THỨC LỚP ............. 167 
10.4. KHỞI TẠO BIẾN LỚP ........................................... 169 
10.5. MẪU THIẾT KẾ SINGLETON .............................. 170 
10.6. THÀNH VIÊN BẤT BIẾN – final .......................... 171 
Chương 11. NGOẠI LỆ ................................................... 174 
11.1. NGOẠI LỆ LÀ GÌ? .................................................. 175 
11.1.1. Tình huống sự cố .......................................... 175 
11.1.2. Xử lý ngoại lệ ................................................ 177 
11.1.3. Ngoại lệ là đối tượng .................................... 178 
11.2. KHỐI try/catch ........................................................ 179 
11.2.1. Bắt nhiều ngoại lệ ......................................... 179 
11.2.2. Hoạt động của khối try/catch ...................... 180 
11.2.3. Khối finally – những việc dù thế nào cũng phải làm 182 
 4
11.2.4. Thứ tự cho các khối catch ............................ 183 
11.3. NÉM NGOẠI LỆ ..................................................... 184 
11.4. NÉ NGOẠI LỆ ........................................................ 185 
11.5. NGOẠI LỆ ĐƯỢC KIỂM TRA VÀ KHÔNG ĐƯỢC KIỂM TRA 189 
11.6. ĐỊNH NGHĨA KIỂU NGOẠI LỆ MỚI ................. 190 
11.7. NGOẠI LỆ VÀ CÁC PHƯƠNG THỨC CÀI ĐÈ . 191 
Chương 12. CHUỖI HÓA ĐỐI TƯỢNG VÀ VÀO RA FILE 196 
12.1. QUY TRÌNH GHI ĐỐI TƯỢNG............................ 197 
12.2. CHUỖI HÓA ĐỐI TƯỢNG ................................... 199 
12.3. KHÔI PHỤC ĐỐI TƯỢNG .................................... 202 
12.4. GHI CHUỖI KÍ TỰ RA TỆP VĂN BẢN ............... 205 
12.4.1. Lớp File .......................................................... 206 
12.4.2. Bộ nhớ đệm ................................................... 207 
12.5. ĐỌC TỆP VĂN BẢN .............................................. 207 
12.6. CÁC DÒNG VÀO/RA TRONG Java API ............. 209 
Chương 13. LẬP TRÌNH TỔNG QUÁT VÀ CÁC LỚP COLLECTION 215 
13.1. LỚP TỔNG QUÁT ................................................. 217 
13.2. PHƯƠNG THỨC TỔNG QUÁT ........................... 219 
13.3. CÁC CẤU TRÚC DỮ LIỆU TỔNG QUÁT TRONG JAVA API 220 
13.4. ITERATOR VÀ VÒNG LẶP FOR EACH ............. 222 
13.5. SO SÁNH NỘI DUNG ĐỐI TƯỢNG ................... 224 
13.5.1. So sánh bằng ................................................. 224 
13.5.2. So sánh lớn hơn/nhỏ hơn ............................. 226 
13.6. KÍ TỰ ĐẠI DIỆN TRONG KHAI BÁO THAM SỐ KIỂU 228 
Phụ lục A. DỊCH CHƯƠNG TRÌNH BẰNG JDK .......... 233 
Phụ lục B. PACKAGE – TỔ CHỨC GÓI CỦA JAVA .... 236 
Phụ lục C. BẢNG THUẬT NGỮ ANH-VIỆT ................. 239 
Tµi liÖu tham kh¶o ............................................................... 241 
 5
Giíi thiÖu 
Phần mềm ngày càng lớn và phức tạp và đòi hỏi được cập nhật liên tục để đáp 
ứng những yêu cầu mới của người dùng. Phương pháp lập trình thủ tục truyền 
thống dần trở nên không đáp ứng được những đòi hỏi đó của ngành công nghiệp 
phần mềm. Lập trình hướng đối tượng đã ra đời trong bối cảnh như vậy để hỗ trợ sử 
dụng lại và phát triển các phần mềm qui mô lớn. 
Giáo trình này cung cấp cho sinh viên các kiến thức từ cơ bản cho đến một số kỹ 
thuật nâng cao về phương pháp lập trình hướng đối tượng. Giáo trình dùng cho 
sinh viên ngành Công nghệ thông tin đã có kiến thức căn bản về lập trình. Giáo trình 
sử dụng ngôn ngữ lập trình Java để minh họa và đồng thời cũng giới thiệu một số 
kiến thức căn bản của ngôn ngữ này. 
Các nội dung chính về phương pháp lập trình hướng đối tượng được trình bày 
trong giáo trình bao gồm lớp và đối tượng, đóng gói/che giấu thông tin, kế thừa và 
đa hình, xử lý ngoại lệ và lập trình tổng quát. Ngoài ra, giáo trình cũng trình bày các 
kiến thức về Java bao gồm các đặc trưng cơ bản của ngôn ngữ, các thư viện cơ bản 
và cách thức tổ chức vào/ra dữ liệu. 
Thay vì cách trình bày theo tính hàn lâm về một chủ đề rộng, để thuận tiện cho 
giảng dạy, giáo trình chọn cách trình bày theo các bài học cụ thể được sắp xếp theo 
trình tự kiến thức từ cơ sở đến chuyên sâu. Mỗi chủ đề có thể được giảng dạy với 
thời lượng 2~3 giờ lý thuyết và giờ thực hành tương ứng. Ch-¬ng 2 và Ch-¬ng 6, với 
nội dung là các kiến thức cơ bản về ngôn ngữ lập trình Java, tuy cần thiết nhưng 
không phải nội dung trọng tâm của môn học Lập trình hướng đối tượng. Các 
chương này, do đó, nên để sinh viên tự học. Chương 9 và Chương 10 không nhất 
thiết phải được dạy thành những chủ đề độc lập mà có thể được tách rải rác các nội 
dung kiến thức và giới thiệu kèm theo các khái niệm hướng đối tượng có liên quan, 
hoặc yêu cầu sinh viên tự đọc khi cần đến các kiến thức này trong quá trình thực 
hành. 
Tuy cuốn giáo trình này không trình bày sâu về lập trình Java, nhưng kiến thức 
về lập trình Java lại là cần thiết đối với sinh viên, ngay cả với mục đích thực hành 
môn học. Do đó, ngoài mục đích thực hành các nội dung liên quan đến lập trình 
hướng đối tượng, các bài tập thực hành của môn học này nên có thêm đóng vai trò 
định hướng và gợi ý giúp đỡ sinh viên tự học các chủ đề thuần túy Java mà giáo 
viên cho là cần thiết, chẳng hạn như học về vào ra dữ liệu đơn giản ngay từ tuần đầu 
tiên của môn học. Các định hướng này có thể được thể hiện ở những bài tập thực 
hành với những đoạn chương trình mẫu, hoặc yêu cầu tìm hiểu tài liệu API về một 
số lớp tiện ích. Một số bài tập cuối chương là ví dụ của dạng bài tập này. 
 6
Các thuật ngữ hướng đối tượng nguyên gốc tiếng Anh đã được chuyển sang 
tiếng Việt theo những cách khác nhau tùy các tác giả. Sinh viên cần biết thuật ngữ 
nguyên gốc tiếng Anh cũng như các cách dịch khác nhau đó để tiện cho việc sử 
dụng tài liệu tiếng Anh cũng như để liên hệ kiến thức giữa các tài liệu tiếng Việt. Vì 
lí do đó, giáo trình này cung cấp bảng thuật ngữ Anh-Việt với các cách dịch khác 
nhau tại Phụ lục C, bên cạnh Phụ lục A về công cụ lập trình JDK và Phụ lục B về tổ 
chức gói của ngôn ngữ Java. 
Các tác giả chân thành cảm ơn PGS. TS. Nguyễn Đình Hóa, TS. Trương Anh 
Hoàng, TS. Cao Tuấn Dũng, TS. Đặng Đức Hạnh, cũng như các đồng nghiệp và sinh 
viên tại Khoa Công nghệ thông tin, Trường Đại học Công nghệ đã đọc bản thảo giáo 
trình và có các góp ý quí báu về nội dung chuyên môn cũng như cách thức trình bày. 
Tuy vậy, giáo trình vẫn còn nhiều khiếm khuyết, các tác giả mong tiếp tục nhận 
được góp ý để hoàn thiện trong tương lai. 
 7
Ch−¬ng 1. më ®Çu 
Lập trình là công đoạn quan trọng chủ chốt và không thể thiếu để tạo ra sản 
phẩm phần mềm. Phần mềm càng trở nên đa dạng và ngành công nghiệp phần mềm 
càng phát triển thì người ta càng thấy rõ tầm quan trọng của phương pháp lập trình. 
Phương pháp lập trình tốt không chỉ đảm bảo tạo ra phần mềm tốt mà còn hỗ trợ 
thiết kế phần mềm có tính mở và hỗ trợ khả năng sử dụng lại các mô đun. Nhờ đó 
chúng ta có thể dễ dàng bảo trì, nâng cấp phần mềm cũng như giảm chi phí phát 
triển phần mềm. 
Trong những thập kỷ 1970, 1980, phương pháp phát triển phần mềm chủ yếu là 
lập trình có cấu trúc (structured programming). Cách tiếp cận cấu trúc đối với việc 
thiết kế chương trình dựa trên chiến lược chia để trị: Để giải một bài toán lớn, chúng 
ta tìm cách chia nó thành vài bài toán nhỏ hơn và giải riêng từng bài; để giải mỗi bài, 
hãy coi nó như một bài toán mới và có thể tiếp tục chia nó thành các bài toán nhỏ 
hơn; cuối cùng, ta sẽ đi đến những bài toán có thể giải ngay được mà không cần phải 
chia tiếp. Cách tiếp cận này được gọi là lập trình từ trên xuống (top-down 
programming). 
Lập trình từ trên xuống là một phương pháp tốt và đã được áp dụng thành công 
cho phát triển rất nhiều phần mềm. Tuy nhiên, cùng với sự đa dạng và phức tạp của 
phần mềm, phương pháp này bộc lộ những hạn chế. Trước hết, nó hầu như chỉ đáp 
ứng việc tạo ra các lệnh hay là các quy trình để giải quyết một bài toán. Dần dần, 
người ta nhận ra rằng thiết kế các cấu trúc dữ liệu cho một chương trình có tầm 
quan trọng không kém việc thiết kế các hàm/thủ tục và các cấu trúc điều khiển. Lập 
trình từ trên xuống không quan tâm đủ đến dữ liệu mà chương trình cần xử lý. 
Thứ hai, với lập trình từ trên xuống, chúng ta khó có thể tái sử dụng các phần 
của chương trình này cho các chương trình khác. Bằng việc xuất phát từ một bài toán 
cụ thể và chia nó thành các mảnh sao cho thuận, cách tiếp cận này có xu hướng tạo 
ra một thiết kế đặc thù cho chính bài toán đó. Chúng ta khó có khả năng lấy một 
đoạn mã lớn từ một chương trình cũ lắp vào một dự án mới mà không phải sửa đổi 
lớn. Việc xây dựng các chương trình chất lượng cao là khó khăn và tốn kém, do đó 
những nhà phát triển phần mềm luôn luôn muốn tái sử dụng các sản phẩm cũ. 
Thứ ba, môi trường hoạt động trong thực tế của các ứng dụng luôn thay đổi. 
Dẫn đến việc yêu cầu phần mềm cũng phải liên tục thay đổi theo để đáp ứng nhu 
cầu của người dùng nếu không muốn phần mềm bị đào thải. Do đó, một thiết kế 
linh hoạt mềm dẻo là cái mà các nhà phát triển phần mềm mong muốn. Phương 
pháp tiếp cận từ dưới lên (bottom-up) hỗ trợ tốt hơn cho tính linh hoạt mềm dẻo đó. 
Trong thực tế, thiết kế và lập trình từ trên xuống thường được kết hợp với thiết 
kế và lập trình từ dưới lên. Trong tiếp cận từ dưới lên, từ các vấn đề mà ta đã biết 
 8
cách giải và có thể đã có sẵn các thành phần tái sử dụng được chúng ta xây dựng 
dần theo hướng lên trên, hướng đến một giải pháp cho bài toán tổng. 
Các thành phần tái sử dụng được nên có tính mô-đun hóa cao nhất có thể. Mỗi 
mô-đun là một thành phần của một hệ thống lớn hơn, nó tương tác với phần còn lại 
của hệ thống theo một cách đơn giản và được quy ước chặt chẽ. Ý tưởng ở đây là 
một mô-đun có thể được "lắp vào" một hệ thống. Chi tiết về những gì xảy ra bên 
trong mô-đun không cần được xét đến đối với hệ thống nói chung, miễn là mô-đun 
đó hoàn thành tốt vai trò được giao. Đây gọi là che giấu thông tin (information 
hiding), một trong những nguyên lý quan trọng nhất của công ngh ...  
sau đó sẽ chạy không có lỗi. 
Hình 13.10: Cài interface Comparable. 
2. Sử dụng phương thức chồng có lấy tham số kiểu Comparator. Ta viết thêm lớp 
ContactCompare theo interface Comparator và dùng nó trong chương trình 
TestTreeSet như những dòng in đậm trong Hình 13.11. Theo đó, ContactCompare là 
một loại Comparator được thửa riêng dành cho việc so sánh các đối tượng Contact. 
Còn danh bạ là đối tượng TreeSet được tạo kèm với loại Comparator đặc biệt đó để 
 228
nó biết cách đối xử với các phần tử trong danh bạ (cContact là đối số khi gọi hàm 
khởi tạo TreeSet). 
Hình 13.11: Sử dụng Comparator. 
Cả hai cách trên đều áp dụng được cho phương thức sort() của Collection cũng 
như các tiện ích tổng quát tương tự trong thư viện Java. 
13.6. KÍ TỰ ĐẠI DIỆN TRONG KHAI BÁO THAM SỐ KIỂU 
Quan hệ thừa kế giữa hai lớp không có ảnh hưởng gì đến quan hệ giữa các cấu 
trúc tổng quát dùng cho hai lớp đó. Chẳng hạn, Dog và Cat là các lớp con của 
Animal, ta có thể đưa các đối tượng Dog và Cat vào một ArrayList, và tính 
chất đa hình giữa Dog, Cat, và Animal vẫn hoạt động như bình thường (xem ví dụ 
trong Hình 13.12). Tuy nhiên, ArrayList, ArrayList lại không có quan hệ 
gì với ArrayList. Vậy cho nên, nếu dùng một ArrayList làm đối số 
cho phương thức yêu cầu đối số kiểu ArrayList, như ví dụ trong Hình 
13.13, trình biên dịch sẽ báo lỗi sai kiểu dữ liệu. 
 229
Hình 13.12: Đa hình bên trong mỗi cấu trúc tổng quát. 
Hình 13.13: Không có đa hình giữa các cấu trúc tổng quát. 
Tóm lại, nếu ta khai báo một phương thức lấy đối số kiểu ArrayList, 
nó sẽ chỉ có thể lấy đối số kiểu ArrayList chứ không thể lấy kiểu 
ArrayList hay ArrayList. 
Ta không hài lòng với lắm với việc thỏa hiệp, nghĩa là dùng ArrayList 
thay vì ArrayList cho danh sách chỉ được chứa toàn Dog. Vì nếu vậy trình 
biên dịch sẽ không kiểm tra kiểu dữ liệu để ngăn chặn những tình huống chẳng hạn 
như trong danh sách chó nghiệp vụ của lính cứu hỏa lại có một con mèo. 
 230
Hình 13.14: Nguy cơ cho mèo vào danh sách chó. 
Vậy làm thế nào để làm cho một phương thức có thể nhận đối số thuộc kiểu 
ArrayList, ArrayList,nghĩa là ArrayList dành cho kiểu bất kì là lớp 
con của Animal? Giải pháp là sử dụng kí tự đại diện (wildcard). 
Ta sửa phương thức makeASymphony() như sau, và chương trình trong Hình 
13.13 sẽ chạy được và chạy đúng. 
? extends Animal có nghĩa là kiểu gì đó thuộc loại Animal. Nhớ rằng từ khóa 
extends ở đây có nghĩa "là lớp con của" hoặc "cài đặt", tùy vào việc theo sau từ khóa 
extends là tên một lớp hay tên một interface. Vậy nên nếu muốn makeASymphony() 
lấy đối số là một ArrayList của loại nào cài interface Pet, ta khai báo nó như sau: 
Nhưng ArrayList thì khác gì với ArrayList? 
makeASymphony() thì an toàn vì nó không thêm/sửa danh sách mà tham số a chiếu 
tới. Nhưng liệu có tránh được chuyện cho mèo vào danh sách chó ở một phương 
thức khác hay không? Câu trả lời là Có. 
Khi ta dùng kí tự đại diện tại khai báo, trình biên dịch sẽ không cho ta thêm 
cái gì vào trong danh sách mà tham số của phương thức chiếu tới. Ta có thể gọi 
phương thức của các phần tử trong danh sách, nhưng ta không thể thêm phần tử 
mới vào danh sách. Do đó, ta có thể yên tâm khi chương trình chạy. Ví dụ, 
makeASymphony() với nội dung ở trên thì không gặp lỗi biên dịch, nhưng 
takeAnimals() với nội dung như trong Hình 13.14 sẽ không biên dịch được. 
 231
Hai cú pháp sau là tương đương: 
public void foo( ArrayList a) 
public void foo( ArrayList a) 
Cách thứ hai, dùng "T", thường được sử dụng khi ta còn muốn T xuất hiện ở các 
vị trí khác. Ví dụ, cách viết sau quá dài: 
public void bar( ArrayList a1, ArrayList<? extends 
Animal> a2) 
thay vào đó, ta viết: 
public void bar(ArrayList a1 , ArrayList a2) 
 232
Bài tập 
1. Các phát biểu dưới đây đúng hay sai? nếu sai, hãy giải thích. 
a) Một phương thức generic không thể trùng tên với một phương thức không 
generic. 
b) Có thể chồng một phương thức generic bằng một phương thức generic khác 
trùng tên nhưng khác danh sách tham số 
c) Một tham số kiểu có thể được khai báo đúng một lần tại phần tham số kiểu 
nhưng có thể xuất hiện nhiều lần tại danh sách tham số của phương thức 
generic 
d) Các tham số kiểu của các phương thức generic khác nhau phải không được 
trùng nhau. 
2. Trong các dòng khai báo sau đây, dòng nào có lỗi biên dịch? 
3. Viết một phương thức generic sumArray với tham số là một mảng gồm các phần 
tử thuộc một kiểu tổng quát, phương thức này tính tổng các phần tử của mảng 
rồi trả về kết quả bằng lệnh return. 
Viết một đoạn code ngắn minh họa cách sử dụng hàm sumArray 
 233
Phụ lục A. DÞch ch−¬ng tr×nh b»ng JDK 
Phụ lục này hướng dẫn những bước cơ bản nhất trong việc biên dịch và chạy 
một chương trình Java đơn giản bằng công cụ JDK tại môi trường Windows. 
A.1. Soạn thảo mã nguồn chương trình 
Có thể chọn một chương trình soạn thảo văn bản đơn giản, chẳng hạn như 
Notepad. Hoặc để thuận tiện, ta có thể chọn một chương trình có tính năng tự động 
hiển thị màu theo cú pháp nhưng vẫn đơn giản, chẳng hạn như Notepad++. 
Mã nguồn chương trình cần được lưu vào file có tên trùng tên lớp (chính xác cả 
chữ hoa và chữ thường) và phần mở rộng .java. Chẳng hạn lớp HelloWorld được 
lưu trong file có tên HelloWorld.java. 
A.2. Biên dịch mã nguồn thành file .class 
Mở một cửa sổ lệnh (console) bằng cách lần lượt chọn Start menu, Run..., rồi gõ 
lệnh cmd. Cửa sổ hiện ra sẽ có dạng như trong Hình 13.15. 
Hình 13.15: Cửa sổ lệnh 
Tại cửa sổ lệnh, dấu nhắc cho biết thư mục hiện tại. Để dịch file mã nguồn, ta 
cần thay đổi thư mục hiện tại về thư mục nơi ta đã lưu file đó. Ví dụ, nếu thư mục 
mã nguồn của ta là C:\java, ta gõ lệnh sau tại dấu nhắc và nhấn Enter 
cd C:\java 
Kết quả là dấu nhắc sẽ chuyển thành C:\java>. 
Khi chạy lệnh dir tại dấu nhắc, ta sẽ thấy danh sách các file mã nguồn đặt tại thư 
mục hiện tại như trong Hình 13.16. 
 234
Hình 13.16: Danh sách các file mã nguồn. 
Để dịch chương trình HelloWorld, ta gõ lệnh sau tại dấu nhắc: 
javac HelloWorld.java 
Nếu thành công, trình biên dịch sẽ sinh ra một file bytecode có tên 
HelloWorld.class. Khi dùng lệnh dir lần nữa, ta sẽ thấy file đó được liệt kê trên 
màn hình như hình dưới đây. Chương trình đã được dịch xong và sẵn sàng chạy. 
Hình 13.17: File . class kết quả của biên dịch. 
Nếu không thành công, ta có thể đã gặp một trong những tình huống sau đây: 
1. Lỗi cú pháp: dựa theo thông báo lỗi được trình biên dịch hiển thị ra màn 
hình, ta cần quay lại trình soạn thảo để sửa lỗi trước khi chạy lệnh javac 
lần nữa để dịch lại. 
2. Thông báo lỗi 'javac' is not recognized as an internal or external 
command, operable program or batch file. Nguyên nhân là Windows 
không tìm thấy chương trình javac. 
Cách giải quyết thứ nhất cho tình huống thứ hai là: khi gọi javac ta cần gõ đầy 
đủ đường dẫn tới chương trình này, chẳng hạn: 
"C:\Program Files\Java\jdk1.6.0_26\bin\javac" HelloWorld.java 
 235
Chú ý rằng đường dẫn trên có chứa dấu trắng (Program Files) nên ta cần có cặp 
nháy kép bọc đầu cuối. 
Cách giải quyết thứ hai là sửa biến môi trường của hệ điều hành để đặt đường 
dẫn tới javac. Hướng dẫn cài đặt JDK cho mỗi hệ điều hành đều có hướng dẫn chi 
tiết cách làm. 
A.3. Chạy chương trình 
Ngay tại thư mục chứa mã nguồn, ta gõ lệnh sau tại dấu nhắc (chú ý không kèm 
đuôi .class): 
java HelloWorld 
Kết quả là chương trình chạy như trong hình dưới đây: 
Hình 13.18: Kết quả chạy chương trình. 
 236
Phụ lục B. Package – tæ chøc gãi cña java 
Mỗi lớp trong thư viện Java API thuộc về một gói (package) trong đó chứa một 
nhóm các lớp có liên quan với nhau. Khi các ứng dụng trở nên ngày càng phức tạp, 
việc tổ chức chương trình thành các gói giúp lập trình viên quản lí được các thành 
phần của ứng dụng. Các gói còn hỗ trợ việc tái sử dụng phần mềm bằng cách cho 
phép chương trình import lớp từ các gói khác (như ta vẫn làm ở hầu hết các chương 
trình ví dụ). Một lợi ích khác của tổ chức gói là cơ chế đặt tên lớp không trùng nhau. 
Điều này giúp tránh xung đột tên lớp. Phụ lục này giới thiệu cách tạo gói của chính 
mình. 
Các bước khai báo một lớp tái sử dụng được: 
1. Khai báo public cho lớp đó. Nếu không, nó sẽ chỉ được sử dụng bởi các lớp trong 
cùng một gói. 
2. Chọn một tên gói và đặt khai báo gói vào đầu file mã nguồn của lớp. Trong mỗi 
file mã nguồn chỉ có tối đa một khai báo gói và nó phải được đặt trước tất cả các 
lệnh khác. 
3. Dịch lớp đó sao cho nó được đặt vào đúng chỗ trong cấu trúc thư mục của gói 
Sau ba bước trên, lớp đó đã sẵn sàng cho việc import và sử dụng trong một 
chương trình. 
Sau đây là chi tiết về cách biên dịch các lớp trong một gói. 
Ngữ cảnh: 
Hướng dẫn này viết cho môi trường Windows và dùng một trình biên dịch 
tương đương với javac, có thể dễ dàng chuyển đổi sang nội dung tương đương cho 
môi trường Unix/Linux. 
Giả sử ta có hai gói, com.mycompanypackage chứa các lớp CompanyApp và 
BusinessLogic; và org.mypersonalpackages.util chứa các lớp Semaphore và 
HandyBits. BusinessLogic cần truy nhập tới HandyBits 
Viết mã và biên dịch 
Việc đầu tiên: tổ chức mã nguồn. Ta cần chọn một thư mục "gốc" cho cây thư 
mục chứa mã nguồn của mình. (Từ đây ta sẽ gọi nó đơn giản là gốc.) Ta sẽ dùng 
c:\java cho các ví dụ ở đây. 
Ta cần có 4 file mã nguồn sau: 
c:\java\com\mycompanypackage\CompanyApp.java 
c:\java\com\mycompanypackage\BusinessLogic.java 
c:\java\org\mypersonalpacakges\util\Semaphore.java 
 237
c:\java\org\mypersonalpacakges\util\HandyUtil.java 
Lưu ý rằng các file mã nguồn được tổ chức giống như cấu trúc gói. Điều này rất 
quan trọng, nó giúp trình biên dịch tìm thấy các file nguồn - nó cũng giúp ta trong 
hoàn cảnh y hệt. 
Tại đầu mỗi file nguồn (trước tất cả các lệnh import hay bất cứ gì không phải 
chú thích), ta cần có một dòng khai báo gói. Ví dụ, CompanyApp.java sẽ bắt đầu 
bằng: 
package com.mycompanypackage; 
Nếu lớp của ta cần import gì đó từ các gói khác, các dòng import có thể đặt sau 
đó. Ví dụ, BusinessLogic.java có thể bắt đầu bằng: 
package com.mycompanypackage; 
import org.mypersonalpackages.util.*; 
hoặc 
package com.mycompanypackage; 
import org.mypersonalpackages.util.HandyUtil; 
Một số người thích dùng import-on-demand (cách đầu), người khác thì không. 
Thật ra đây chủ yếu chỉ là vấn lười biếng. Ta hiểu rằng cách này có thể gây ra các sự 
bất tương thích nếu sau này các class bị trùng tên, nhưng bên trong các gói chuẩn 
của Java mà ta sự dụng, chuyện đó hiếm khi xảy ra. (Một phần là vì ta không dùng 
GUI mấy. Nếu dùng các gói java.awt và java.util trong cùng một class, ta sẽ phải 
thận trọng hơn.) 
Đến lúc biên dịch các class. Ta thường biên dịch tất cả các file, để chắc chắn là 
mình luôn dùng phiên bản mới nhất của tất cả các class. Trong Java có một số sự 
phụ thuộc không dễ thấy, chẳng hạn như các hằng đối tượng thuộc một class được 
nhúng trong một class khác (chẳng hạn nếu HandyUtil tham chiếu tới 
Semaphore.SOME_CONSTANT - một hằng String loại static final, giá trị của nó sẽ 
được nhúng vào trong HandyUtil.class.) Có hai cách để biên dịch tất cả. Hoặc là 
dùng lệnh một cách tường minh: 
c:\java> javac -d . com\mycompanypackage\*.java 
org\mypersonalpackage\util\*.java 
hoặc tạo một danh sách các file và chuyển nó cho javac: 
c:\java> dir /s /b *.java > srcfiles.txt 
c:\java> javac -d . @srcfiles.txt 
Lưu ý rằng ta biên dịch nó từ thư mục gốc, và ta dùng tùy chọn -d . để bảo trình 
biên dịch xếp các file .class vào một cấu trúc gói xuất phát từ gốc (dấu chấm theo sau 
có nghĩa rằng thư mục gốc là thư mục hiện tại). Một số người không thích để các file 
.class và các file nguồn cùng một chỗ - trong trường hợp đó, ta có thể dùng tùy chọn 
-d classes, nhưng ta phải tạo thư mục classes từ trước. (Ta cũng sẽ cần hoặc là lần 
nào cũng dịch tất cả hoặc đặt classes vào phần classpath cho trình biên dịch bằng tùy 
chọn -classpath.) Nếu chưa thực sự thành thạo, ta nên làm theo cách đầu và kiểm tra 
 238
chắc chắn là ta không đặt classpath . Nếu vì lý do nào đó mà ta nhất định phải dùng 
một classpath, hãy đảm bảo là . (thư mục hiện hành) nằm trong classpath. 
Chạy ứng dụng 
Nhiều người "tình cờ" đặt được các file .class của mình vào đúng chỗ, do may 
mắn chẳng hạn, nhưng rồi lại gặp phải những lỗi như: 
java.lang.NoClassDefFoundError: MyCompanyApp (wrong name: 
com/mycompanypackage/MyCompanyApp. Tình huống đó xảy ra nếu ta cố chạy 
chương trình bằng một lệnh kiểu như: 
c:\java\com\mycompanypackage> java MyCompanyApp 
Đây là cách để tránh: 
Hãy đứng yên ở thư mục "gốc" của mình, ví dụ c:\java 
Luôn luôn dùng tên đầy đủ của class. Ví dụ: 
c:\java> java com.mycompanypackage.MyCompanyApp 
Máy ảo Java biết cách tìm file .class trong thư mục com\mycompanypackage 
(lưu ý, đây là một quy ước của máy ảo, hầu hết các máy ảo dùng cách này - không có 
chỗ nào trong đặc tả ngôn ngữ nói rằng gói phải được lưu trữ theo kiểu đó; máy ảo 
Java đơn giản là phải biết cách tìm và nạp một class), nhưng trong file .class có ghi 
tên đầy đủ của nó - và máy ảo dùng thông tin đó để kiểm tra xem cái class mà nó 
được yêu cầu nạp có phải cái mà nó tìm thấy hay không. 
 239
Phụ lục C. B¶ng thuËt ng÷ anh viÖt 
Tiếng Anh Tiếng Việt Các cách dịch khác 
abstract class lớp trừu tượng 
abstract method phương thức trừu tượng 
abstraction trừu tượng hóa 
aggregation quan hệ tụ hợp quan hệ kết tập 
argument đối số tham số thực sự 
association quan hệ kết hợp 
attribute thuộc tính 
behavior hành vi 
chain stream dòng nối tiếp 
class lớp, lớp đối tượng 
class variable 
/ class attribute 
biến lớp, biến của lớp, 
thuộc tính của lớp 
biến static 
class method phương thức của lớp phương thức static 
composition quan hệ hợp thành 
concrete class lớp cụ thể 
connection stream dòng kết nối 
constructor hàm khởi tạo hàm tạo, cấu tử 
copy constructor hàm khởi tạo sao chép hàm tạo sao chép, 
cấu tử sao chép 
encapsulation đóng gói 
exception ngoại lệ 
information hiding che giấu thông tin 
inheritance thừa kế 
instance thực thể thể hiện 
instance variable biến thực thể, biến của 
thực thể 
trường, thành viên 
dữ liệu 
message thông điệp 
 240
method / 
member function 
phương thức, hàm hàm thành viên 
object đối tượng 
object serialization chuỗi hóa đối tượng 
overload cài chồng hàm trùng tên 
override cài đè ghi đè, định nghĩa lại 
package gói 
parameter tham số tham số hình thức 
pass-by-value truyền bằng giá trị 
polymorphism đa hình 
reference tham chiếu 
state trạng thái 
stream dòng 
subclass / 
derived class 
lớp con, lớp dẫn xuất 
superclass / 
base class 
lớp cha, lớp cơ sở 
top-down 
programming 
lập trình từ trên xuống 
variable biến 
virtual machine máy ảo 
 241
Tµi liÖu tham kh¶o 
[1]. Deitel & Deitel, Java How to Program, 9th edition, Prentice Hall, 2012. 
[2]. Kathy Sierra, Bert Bates, Head First Java, 2nd edition, O'Reilly, 2008. 
[3]. Oracle, JavaTM Platform Standard Ed.6, URL: 
[4]. Oracle, JavaTM Platform Standard Ed.7, URL: 
[5]. Oracle, The JavaTM Tutorials, URL:  
[6]. Ralph Morelli, Ralph Walde, Java, Java, Java – Object-Oriented Problem Solving, 
3th edition, Prentice Hall, 2005. 
[7]. Joshua Bloch, Effective Java, 2nd edition, Addison-Wesley, 2008. 

File đính kèm:

  • pdfgiao_trinh_ngon_ngu_lap_trinh_java.pdf