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ô.
Tóm tắt nội dung tài liệu: 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:
- giao_trinh_ngon_ngu_lap_trinh_java.pdf