Tập bài giảng Lập trình Java (Phần 1)

pdf 146 trang Gia Huy 17/05/2022 2330
Bạn đang xem 20 trang mẫu của tài liệu "Tập bài giảng Lập trình Java (Phần 1)", để tải tài liệu gốc về máy bạn click vào nút DOWNLOAD ở trên

Tài liệu đính kèm:

  • pdftap_bai_giang_lap_trinh_java_phan_1.pdf

Nội dung text: Tập bài giảng Lập trình Java (Phần 1)

  1. LỜI NÓI ĐẦU Hiện nay có nhiều ngôn ngữ lập trình được sử dụng để viết các ứng dụng trên máy tính như: C++, C#, VB, VB.Net . Mỗi ngôn ngữ đều có một thế mạnh riêng, nếu biết lựa chọn một ngôn ngữ phù hợp để xây dựng ứng dụng sẽ giúp cho các chuyên gia lập trình tích kiệm được thời gian, công sức và giúp xử lý kỹ thuật lập trình đơn giản và thuận tiện hơn. Java là ngôn ngữ lập trình hướng đối tượng thuần túy với nhiều đặc trưng ưu việt so với các ngôn ngữ lập trình hướng đối tượng khác như tính độc lập với nên, Tính Đa nhiệm - đa luồng tính bảo mật, khả năng đóng gói, giao tiếp . Khác với các ngôn ngữ lập trình hướng đối tượng khác như c++ hay c# là ngay từ khi ra đời mục tiêu của java là phát triển một ngôn ngữ đơn giản, nhỏ nhẹ và có thể chạy trên nhiều môi trường khác nhau, do đó Java đặc biệt thích hợp để viết chương trình cho các ứng dụng trên mạng, trên các thiết bị di động, , việc việt các ứng dụng này bằng Java dễ dàng hơn nhiều so với các ngôn ngữ khác. Chính vì vậy trong rất nhiều ngôn ngữ lập trình đang được các chuyên gia sử dụng để viết nên các ứng dụng trên máy tính, trong doanh nghiệp, trên các thiết bị cầm tay Java luôn là ngôn ngữ được các chuyên gia lựa chọn ở mức ưu tiên số 1. Java đã được ứng dụng rộng rãi và trở thành một ngôn ngữ lập trình được ưa chuộng bậc nhất hiện nay. Ở Việt Nam, Java đang rất phát triển các doanh nghiệp đã sử dụng Java trong các sản phẩm Game, phần mềm, ngân hàng, thiết bị cầm tay, ứng dụng web, Những chuyên gia thành thạo ngôn ngữ này luôn đứng trước sự săn đón của hàng trăm nghìn việc làm và cơ hội thăng tiến. Tập bài giảng này được xây dựng gồm có 6 chương trình bày chi tiết về lập trình Java cơ bản, bám sát theo khung chương trình môn lập trình Java của Trường Đại học Sư phạm Kỹ thuật Nam Định. Nhằm trang bi cho sinh viên những kiến thức cơ bản về lập trình Java tạo nền tảng để sinh viên tiếp cận với ngôn ngữ này cũng như học các học phần khác trong chương trình như thực tập lập trình trên thiết bị di động. Tập bài giảng được sử dụng làm tài liệu giảng dạy cho các giáo viên, giảng viên và tài liệu học tập cho học sinh – sinh viên thuộc Trường Đại học Sư phạm Kỹ thuật Nam Định. Ngoài ra có thể làm tài liệu tham khảo cho mọi đối tượng quan tâm đến lập trình Java. NHÓM TÁC GIẢ i
  2. MỤC LỤC CHƢƠNG 1: LẬP TRÌNH JAVA CƠ BẢN 1 1.1. Giới thiệu về Java và cài đặt 1 1.1.1. Lịch sử Java 1 1.1.2. Đặc trưng của Java 1 1.1.3. Các kiểu chương trình Java 5 1.1.4. Máy ảo Java 6 1.1.5. Bộ công cụ phát triển JDK 8 1.1.6. Cài đặt JDK 11 1.2. Ngôn ngữ lập trình Java 17 1.2.1. Mở đầu lập trình với Java 17 1.2.2. Cấu trúc chương trình Java 17 1.2.3. Kiểu dữ liệu cơ sở, hằng, biến 20 1.2.4. Kiểu dữ liệu Mảng (Array) 27 1.2.5. Toán tử và biểu thức 29 1.2.6. Các cấu trúc điều khiển 32 1.2.7. Hàm – Phương thức (Function – Method) 38 1.2.8. Nhập xuất dữ liệu 39 Câu hỏi và bài tập chƣơng 1 43 CHƢƠNG 2: LẬP TRÌNH HƢỚNG ĐỐI TƢỢNG TRONG JAVA 45 2.1. Giới thiệu về lập trình hƣớng đối tƣợng 45 2.2. Trừu tƣợng hoá dữ liệu 47 2.3. Lớp và định nghĩa lớp trong Java 50 2.4. Đối tƣợng 62 2.5. Thiết lập và hủy 63 2.5.1. Thiết lập 63 2.5.2. Hủy 65 2.6. Các đặc tính của lớp 66 2.6.1. Tính bền vững 66 ii
  3. 2.6.2. Tính thừa kế 68 2.6.3. Tính đa thừa kế 72 2.6.4. Tính đa hình 73 2.6.6. Lớp trừu tượng 76 2.7. Xử lý ngoại lệ 80 Câu hỏi và bài tập chƣơng 2 84 CHƢƠNG 3: CÁC GÓI VÀ LẬP TRÌNH VÀO RA 92 3.1. Các gói trong Java 92 3.1.1. Giới thiệu 92 3.1.2. Các giao diện 92 3.1.3. Các gói 95 3.1.4. Gói và điều khiển truy xuất 98 3.1.5. Gói Java.lang 99 3.2. Các dòng (Stream) 115 3.3. Gói Java.io 115 3.3.1. Lớp InputStream 115 3.3.2. Lớp OutputStream 117 3.3.3. Vào ra mảng byte 117 3.3.4. Vào ra tập tin 119 3.3.5. Nhập xuất lọc 121 3.3.6. Vào ra có sử dụng bộ đệm 122 3.3.7. Lớp Reader và Writer 125 3.3.8. Nhập xuất chuỗi 125 3.3.9. Lớp PrinterWriter 128 3.3.10. Giao diện DataInput 129 3.3.11. Giao diện DataOutput 129 3.3.12. Lớp RandomAccessFile 130 3.4. Gói java.awt.print 132 Câu hỏi và bài tập chƣơng 3 133 iii
  4. CHƢƠNG 4: LẬP TRÌNH ĐỒ HOẠ AWT 136 4.1. Giới thiệu về AWT 136 4.2. Container (vật chứa) 137 4.2.1. Giới thiệu 137 4.2.2. Frame 137 4.2.3. Panel 138 4.2.4. Dialog 139 4.3. Thành phần (Component) 140 4.3.1. Giới thiệu 140 4.3.2. Nhãn 140 4.3.3. Ô văn bản 142 4.3.4. Vùng văn bản 144 4.3.5. Nút 145 4.3.6. Checkbox và Radio Button 147 4.3.7. Danh sách lựa chọn 149 4.4. Quản lý cách trình bày 151 4.4.1. FlowLayout manager 152 4.4.2. BorderLayout Manager 153 4.4.3. Card Layout Manager 154 4.4.4. GridLayout Manager 156 4.4.5. GridBagLayout Manager 158 4.5. Xử lý các sự kiện 163 4.6. Thực đơn 169 Câu hỏi và bài tập chƣơng 4 173 CHƢƠNG 5: JAVA APPLET VÀ SWING 175 5.1. Java Applet 175 5.1.1. Giới thiệu về Applet 175 5.1.2. Cấu trúc của một Applet 175 5.1.3. Chu trình sống của một Applet 178 iv
  5. 5.1.4. Truyền tham số cho Applet 179 5.1.5. Lớp Graphics 181 5.1.6. Điều khiển màu 190 5.1.7. Điều khiển Font 191 5.1.8. Lớp FontMetrics 192 5.1.9. Chọn chế độ để vẽ 196 5.2. Java Swing 198 5.2.1 Giới thiệu về Swing 198 5.2.2. Các biểu tượng và nhãn 199 5.2.3. Các trường văn bản 200 5.2.4. Nút nhấn 201 5.2.5. Lớp JButton 202 5.2.6. Hộp kiểm tra 202 5.2.7. Radio Button 203 5.2.8. ComboBox 203 5.2.9. Tabbed Pane 203 5.2.10. Scroll Pane 204 5.2.11. Cây 205 5.2.12. Bảng 207 Câu hỏi và bài tập chƣơng 5 210 CHƢƠNG 6: LẬP TRÌNH ĐA LUỒNG 224 6.1. Giới thiệu về lập trình luồng 224 6.2. Luồng và đa luồng 224 6.3. Tạo và quản lý luồng 225 6.4. Vòng đời của luồng 228 6.5. Trạng thái của luồng và các phƣơng thức của lớp Thread 228 6.6. Thời gian biểu luồng 229 6.7. Luồng chạy ngầm 231 6.8. Đa luông với Applet 232 v
  6. 6.9. Nhóm luồng 233 6.10. Sự đồng bộ luồng 234 6.10.1. Đồng bộ mã 235 6.10.2. Sử dụng khối đồng bộ (Synchronized Block) 237 6.10.3. Ưu điểm của các phương thức đồng bộ 240 6.11. Cơ chế đợi thông báo 240 6.12. Khoá chết (Deadlock) 244 6.13. Thu dọn rác 246 Câu hỏi và bài tập chƣơng 6 250 TÀI LIỆU THAM KHẢO 254 vi
  7. DANH MỤC CÁC HÌNH VẼ Bảng 1.1. Bảng các ký hiệu ghi chú 18 Bảng 1.2. Các từ khóa của Java 20 Bảng 1.3. Các kiểu số nguyên 21 Bảng 1.4. Các phép toán trên kiểu số nguyên 21 Bảng 1.5. Các loại số thực 22 Bảng 1.6. Các phép toán trên kiểu số thực 22 Bảng 1.7. Giá trị mặc định 23 Bảng 1.8. Hằng số nguyên 25 Bảng 1.9. Các hằng số thực 26 Bảng 1.10. Toán tử 2 ngôi 30 Bảng 1.11. Danh sách các toán tử đơn 30 Bảng 1.12. Danh sách các toán tử gán 31 Bảng 1.13. Danh sách các toán tử trên kiểu số thực 31 Bảng 1.14. Danh sách các phép toán logic 31 Bảng 2.1. Một ví dụ về hai phương pháp giải quyết OOP và Structured 47 Bảng 2.2. Sử dụng các bổ nghĩa 54 Bảng 2.3. Các exception thường gặp 83 Bảng 2.4. Các phương thức thông dụng của Throwable 84 Bảng 3.1. Truy cập đến các thành phần của lớp 99 Bảng 3.2. Các lớp trình bao bọc cho các kiểu dữ liệu nguyên thủy. 99 Bảng 3.3. Lớp Runtime 110 Bảng 3.4. Lớp System. 111 Bảng 3.5. Lớp Object. 114 Bảng 3.6. Các phương thức của lớp InputStream 116 Bảng 3.7. Các phương thức lớp OutputStream 117 Bảng 3.8. Các phương thức của giao diện DataInput 129 Bảng 3.9. Các phương thức của giao diện DataOutput 130 Bảng 4.1. Các phương thức của Label 141 vii
  8. Bảng 4.2. Các phương thức của TextField 143 Bảng 4.3. Các phương thức của TextArea 144 Bảng 4.4. Các biến thành viên của lớp GridBagConstraints 159 Bảng 4.5. Các biến thành viên dữ liệu tĩnh của biến fill 159 Bảng 4.6. các sự kiện của AWT 164 Bảng 5.1. Các phương thức của một applet 176 Bảng 5.2. Phạm vi giá trị của các thành phần màu 190 Bảng 5.3. Các giá trị RGB 190 Bảng 5.4. Các màu thường gặp 191 Bảng 5.5. Các lớp thành phần Swing 199 Bảng 5.6. Các hàm sử dụng của JLabel 200 Bảng 5.7. Các hằng số 205 Bảng 6.1. Các phương thức của một lớp luồng 229 viii
  9. DANH MỤC CÁC HÌNH VẼ Hình 1.1. Cách biên dịch truyền thống 3 Hình 1.2. Dịch chương trình Java 3 Hình 1.3. Trang web tải bộ công cụ Java 12 Hình 1.4. Biểu tượng Java Download 12 Hình 1.5. Lựa chọn bản quyền 12 Hình 1.6. Bộ JDK cho Windows bản 64 bit 12 Hình 1.7. Màn hình cài đặt đầu tiên 13 Hình 1.8. Màn hình Custom Setup 13 Hình 1.9. Màn hình Description Folder 13 Hình 1.10. Màn hình Description Folder 14 Hình 1.11. Đường dẫn của thư mục cài đặt Java 14 Hình 1.12. Màn hình Computer Properties 15 Hình 1.13. Màn hình System Properties 15 Hình 1.14. Màn hình Environment Variables 16 Hình 1.15. Màn hình Edit System Variable 16 Hình 1.16. Màn hình cửa sổ run 16 Hình 1.17. Màn hình Command Prompt 16 Hình 3.1. Minh họa khái niệm của String Pool. 101 Hình 3.2. Kết quả chạy ví dụ 3.22 112 Hình 3.3. Kết quả chạy ví dụ 3.23 114 Hình 3.4. Kết quả chạy ví dụ 3.25 119 Hình 3.5. Kết quả chạy ví dụ 3.26 121 Hình 3.6. Kết quả chạy ví dụ 3.27 125 Hình 3.7. Kết quả chạy ví dụ 3.28 127 Hình 3.8. Kết quả chạy ví dụ 3.29 128 Hình 3.9. Kết quả chạy ví dụ 3.30 132 Hình 4.1. Hệ thống cây phân cấp lớp AWT 137 Hình 4.2. Kết quả chạy ví dụ 4.1 138 ix
  10. Hình 4.3. Kết quả chạy ví dụ 4.2 139 Hình 4.4. Các lớp thành phần 140 Hình 4.5. Kết quả chạy ví dụ 4.3 142 Hình 4.6. Kết quả chạy ví dụ 4.4 143 Hình 4.7. Kết quả chạy ví dụ 4.5 145 Hình 4.8. Kết quả chạy ví dụ 4.6 147 Hình 4.9. Kết quả chạy ví dụ 4.7 149 Hình 4.10. Kết quả chạy ví dụ 4.8 151 Hình 4.11. Kết quả chạy ví dụ 4.9 153 Hình 4.12. BorderLayout 154 Hình 4.13. Kết quả chạy ví dụ 4.10 156 Hình 4.14. Kết quả chạy ví dụ 4.10 158 Hình 4.15. Kết quả chạy ví dụ 4.12 162 Hình 4.16. Kết quả chạy ví dụ 4.13 167 Hình 4.17. Gói Event 167 Hình 4.18. Event Listener 168 Hình 4.19. Action Listener 168 Hình 4.20. Item Listener 168 Hình 4.21. Window Listener 169 Hình 4.22. Các Component 169 Hình 4.23. Kết quả chạy ví dụ 4.14 172 Hình 4.24. Pop-up menu 173 Hình 5.1. Kết quả chạy ví dụ 5.1 178 Hình 5.2. Chu trình sống của một applet 178 Hình 5.3. Kết quả chạy ví dụ 5.2 180 Hình 5.4. Kết quả chạy ví dụ 5.3 184 Hình 5.5. Kết quả chạy ví dụ 5.4 188 Hình 5.6. Kết quả chạy ví dụ 5.5 189 Hình 5.7. Kết quả chạy ví dụ 5.6 194 x
  11. Hình 5.8. Kết quả chạy ví dụ 5.7 196 Hình 5.9. Kết quả chạy ví dụ 5.8 198 Hình 6.1. Kết quả thực hiện ví dụ 6.2 227 Hình 6.2. Vòng đời của luồng 228 Hình 6.3. Kết quả chạy ví dụ 6.3 231 Hình 6.4. Kết quả chạy ví dụ 6.4 233 Hình 6.5. Kết quả chạy ví dụ 6.5 237 Hình 6.6. Kết quả hiển thị của ví dụ 6.5 không có sự đồng bộ 237 Hình 6. 7. Kết quả sau mỗi lần kích chuột 243 Hình 6.8. Kết quả thực hiện ví dụ 6.8 246 Hình 6. 9. Kết quả chạy ví dụ 6.9 249 xi
  12. CHƢƠNG 1: LẬP TRÌNH JAVA CƠ BẢN 1.1. Giới thiệu về Java và cài đặt 1.1.1. Lịch sử Java Java là ngôn ngữ lập trình hướng đối tượng (tựa C++) doSun Microsystem đưa ra vào giữa thập niên 90. Chương trình viết bằng ngôn ngữ lập trình Java có thể chạytrên bất kỳ hệ thống nào có cài máy ảo Java (Java VirtualMachine). Ngôn ngữ lập trình Java do James Gosling và các công sựcủa Công ty Sun Microsystem phát triển. Đầu thập niên 90, Sun Microsystem tập hợp các nhà nghiêncứu thành lập nên nhóm đặt tên là Green Team. Nhóm GreenTeam có trách nhiệm xây dựng công nghệ mới cho ngành điệntử tiêu dùng. Để giải quyết vấn đề này nhóm nghiên cứu pháttriển đã xây dựng một ngôn ngữ lập trình mới đặt tên là Oaktương tự như C++ nhưng loại bỏ một số tính năng nguy hiểmcủa C++ và có khả năng chạy trên nhiều nền phần cứng khácnhau. Cùng lúc đó WorldWide Web bắt đầu phát triển và Sun đãthấy được tiềm năng của ngôn ngữ Oak nên đã đầu tư cải tiếnvà phát triển. Sau đó không lâu ngôn ngữ mới với tên gọi làJava ra đời và được giới thiệu năm 1995. Đến quý II năm 1995, Sun Microsystems công bố chính thức Java và nó trở thành một công cụ mạnh mẽ cho việc phát triển các ứng dụng trên Internet. Java được xây dựng chủ yếu trong bộ công cụ phát triển JDK (Java Development Kit) nó gồm các trình biên dịch, thông dịch, giúp đỡ, soạn tài liệu, thư viện chuẩn sau đó các nhà phát triển phần mềm đã xây dựng thêm rất nhiều nhánh mới như Java Mail (Java-Thư tín), Java TAPI (Java-Viễn thông) Bắt đầu với JDK 1.0 vào 1995, đến năm 1996 Sun đưa ra phiên bản JDK 1.1, năm 1998 ra đời phiên bản JDK 1.2 và hiện nay đã có phiên bản JDK 1.7. Java là tên gọi của một hòn đảo ở Indonexia, Đây là nơinhóm nghiên cứu phát triển đã chọn để đặt tên cho ngôn ngữlập trình Java trong một chuyến đi tham quan và làm việc trênhòn đảo này. Hòn đảo Java này là nơi rất nổi tiếng với nhiềukhu vườn trồng cafe, đó chính là lý do chúng ta thường thấybiểu tượng ly cafe trong nhiều sản phẩm phần mềm, công cụ lậptrình Java của Sun cũng như một số hãng phần mềm khác đưara. 1.1.2. Đặc trƣng của Java  Đơn giản 1
  13.  Hướng đối tượng  Độc lập phần cứng và hệ điều hành  Mạnh  Bảo mật  Phân tán  Đa luồng  Động a) Đơn giản Những người thiết kế mong muốn phát triển một ngôn ngữ dễ học và quen thuộc với đa số người lập trình. Do vậy Java loại bỏ các đặc trưng phức tạp của C và C++ như thao tác con trỏ, thao tác định nghĩa chồng toán tử (operator overloading), Java không sử dụng lệnh “goto” cũng như file header (.h). Cấu trúc “struct” và “union” cũng được loại bỏ khỏi Java. b) Hƣớng đối tƣợng Java được thiết kế xoay quanh mô hình hướng đối tượng. Vì vậy trong Java, tiêu điểm là dữ liệu và các phương pháp thao tác lên dữ liệu đó. Dữ liệu và các phương pháp mô tả trạng thái và cách ứng xử của một đối tượng trong Java. c) Độc lập phần cứng và hệ điều hành Đây là khả năng một chương trình được viết tại một máy nhưng có thể chạy được bất kỳ đâu. Chúng được thể hiện ở mức mã nguồn và mức nhị phân. Ở mức mã nguồn, người lập trình cần mô tả kiểu cho mỗi biến. Kiểu dữ liệu trong Java nhất quán cho tất cả các hệ điều hành và phần cứng khác nhau. Java có riêng một thư viện các lớp cơ sở. Vì vậy chương trình Java được viết trên một máy có thể dịch và chạy trơn tru trên các loại máy khác mà không cần viết lại. Tính độc lập ở mức nhị phân, một chương trình đã biên dịch có thể chạy trên nhiều nền (phần cứng, hệ điều hành) khác mà không cần dịch lại mã nguồn. Tuy vậy cần có phần mềm máy ảo Java (sẽ đề cập đến ở phần sau) hoạt động như một trình thông dịch tại máy thực thi. 2
  14. Hình 1.1. Cách biên dịch truyền thống Đối với các chương trình viết bằng C, C++ hoặc một ngôn ngữ nào khác, trình biên dịch sẽ chuyển tập lệnh thành mã máy (Machine code),hay lệnh của bộ vi xử lý. Những lệnh này phụ thuộc vào CPU hiện tại trên máy bạn. Nên khi muốn chạy trên loại CPU khác, chúng ta phải biên dịch lại chương trình. Hình 1.2 thể hiện quá trình để thực thi chương trình viết bằng C++ trên các loại máy khác nhau. Hình 1.2 Quá trình thực thi chương trình viết bằng Java trên các loại máy khác nhau. Hình 1.2. Dịch chương trình Java Môi trường phát triển của Java được chia làm hai phần: Trình biên dịch và trình thông dịch. Không như C hay C++, trình biên dịch của Java chuyển mã nguồn thành dạng bytecode độc lập với phần cứng mà có thể chạy trên bất kỳ CPU nào. Nhưng để thực thi chương trình dưới dạng bytecode, tại mỗi máy cần phải có trình thông dịch của Java hay còn gọi là máy ảo Java. Máy ảo Java chuyển bytecode thành mã lệnh mà CPU thực thi được. d) Mạnh mẽ Java là ngôn ngữ yêu cầu chặt chẽ về kiểu dữ liệu. Phải khai báo kiểu dữ liệu tường minh khi viết chương trình. Java kiểm tra lúc biên dịch và cả trong thời gian thông dịch vì vậy Java loại bỏ một số loại lỗi lập trình nhất định. 3
  15. Java không sử dụng con trỏ và các phép toán con trỏ. Java kiểm tra tất cả các truy nhập đến mảng, chuỗi khi thực thi để đảm bảo rằng các truy nhập đó không ra ngoài giới hạn kích thước. Java kiểm tra sự chuyển đổi kiểu dữ liệu từ dạng này sang dạng khác lúc thực thi. Trong các môi trường lập trình truyền thống, lập trình viên phải tự mình cấp phát bộ nhớ. Trước khi chương trình kết thúc thì phải tự giải phóng bộ nhớ đã cấp. Vấn đề nảy sinh khi lập trình viên quên giải phóng bộ nhớ đã xin cấp trước đó. Trong chương trình Java, lập trình viên không phải bận tâm đến việc cấp phát bộ nhớ. Quá trình cấp phát, giải phóngđược thực hiện tự động, nhờ dịch vụ thu nhặt những đối tượng không còn sử dụng nữa (garbage collection).Cơ chế bẫy lỗi của Java giúp đơn giản hóa quá trình xử lý lỗi và hồi phục sau lỗi. e) Bảo mật Viruses là nguyên nhân gây ra sự lo lắng trong việc sử dụng máy tính. Trước khi có Java, các lập trình viên phải quétVirus các tệp trước khi tải về hay thực hiện chúng. Thông thường việc này cũng không loại trừ hoàn toàn Virus. Ngoài ra chương trình khi thực thi có khả năng tìm kiếm và đọc các thông tin nhạy cảm trên máy của người sử dụng mà người sử dụng không hề hay biết. Java cung cấp một môi trường quản lý thực thi chương trình. Nó cho rằng không có một đoạn mã nào là an toàn cả. Vì vậy Java không chỉ là ngôn ngữ lập trình thuần tuý mà còn cung cấp nhiều mức để kiểm soát tính an toàn khi thực thi chương trình. Ở lớp đầu tiên, dữ liệu và các phương thức được đóng gói bên trong lớp. Chúng chỉ được truy xuất thông qua các giao diện mà lớp cung cấp. Java không hỗ trợ con trỏ vì vậy không cho phép truy xuất bộ nhớ trực tiếp. Nó cũng ngăn chặn không cho truy xuất thông tin bên ngoài kích thước của mảng bằng kỹ thuật tràn và cũng cung cấp kỹ thuật dọn rác trong bộ nhớ. Các đặc trưng này tạo cho Java an toàn tối đa và có khả năng cơ động cao. Trong lớp thứ hai, trình biên dịch kiểm soát để đảm bảo mã là an toàn, và tuân theo các nguyên tắc của Java. Lớp thứ ba được đảm bảo bởi trình thông dịch. Chúng kiểm tra xem bytecode có đảm bảo các qui tắc an toàn trước khi thực thi. Lớp thứ tư kiểm soát việc nạp các lớp vào bộ nhớ để giám sát việc vi phạm giới hạn truy xuất trước khi nạp vào hệ thống. f) Phân tán 4
  16. Java có thể dùng để xây dựng các ứng dụng có thể làm việc trên nhiều phần cứng, hệ điều hành và giao diện đồ họa. Java được thiết kế hỗ trợ cho các ứng dụng chạy trên mạng. Vì vậy chúng được sử dụng rộng rãi như là công cụ phát triển trên Internet, nơi sử dụng nhiều nền tảng khác nhau. g) Đa luồng Chương trình Java đa luồng(Multithreading) để thực thi các công việc đồng thời. Chúng cũng cung cấp giải pháp đồng bộ giữa các luồng. Đặc tính hỗ trợ đa luồngnày cho phép xây dựng các ứng dụng trên mạng chạy hiệu quả. h) Động Java được thiết kế như một ngôn ngữ động để đáp ứng cho những môi trường mở. Các chương trình Java chứa rất nhiều thông tin thực thi nhằm kiểm soát và truy nhập đối tượng lúc chạy. Điều này cho phép khả năng liên kết động mã. 1.1.3. Các kiểu chƣơng trình Java Chúng ta có thể xây dựng các loại chương trình Java như sau: a) Applets Applet là chương trình được tạo ra để sử dụng trên Internet thông qua các trình duyệt hỗ trợ Java như IE hay Netscape. Bạn có thể dùng Java để xây dựng Applet. Applet được nhúng bên trong trang Web. Khi trang Web hiển thị trong trình duyệt, Applet sẽ được tải về và thực thi tại trình duyệt. b) Ứng dụng thực thi qua dòng lệnh Các chương trình này chạy từ dấu nhắc lệnh và không sử dụng giao diện đồ họa. Các thông tin nhập xuất được thể hiện tại dấu nhắc lệnh. c) Ứng dụng đồ họa Đây là các chương trình Java chạy độc lập cho phép người dùng tương tác qua giao diện đồ họa. d) Servlet Java thích hợp để phát triển ứng dụng nhiều lớp. Applet là chương trình đồ họa chạy trên trình duyệt tại máy trạm. Ở các ứng dụng Web, máy trạm gửi yêu cầu tới máy chủ. Máy chủ xử lý và gửi kết quả trở lại máy trạm. Các Java API chạy trên máy chủ chịu trách nhiệm xử lý tại máy chủ và trả lời các yêu cầu của máy trạm. Các Java API chạy trên máy chủ này mở rộng khả năng của các ứng dụng Java API chuẩn. Các ứng dụng trên máy chủ này được gọi là các Servlet. hoặc Applet tại máy chủ. Xử lý Form của HTML là cách sử dụng đơn giản nhất của Servlet. Chúng còn có thể được 5
  17. dùng để xử lý dữ liệu, thực thi các giao dịch và thường được thực thi thông qua máy chủ Web. e) Ứng dụng cơ sở dữ liệu Các ứng dụng này sử dụng JDBC API để kết nối tới cơ sở dữ liệu. Chúng có thể là Applet hay ứng dụng, nhưng Applet bị giới hạn bởi tính bảo mật. 1.1.4. Máy ảo Java Máy ảo là một phần mềm mô phỏng một máy tính thật. Nó có tập hợp các lệnh logic để xác định các hoạt động của máy tính và có một hệ điều hành ảo. Người ta có thể xem nó như một máy tính thật. Nó thiết lập các lớp trừu tượng cho: Phần cứng bên dưới, hệ điều hành, mã đã biên dịch. Trình biên dịch chuyển mã nguồn thành tập các lệnh của máy ảo mà không phụ thuộc vào phần cứng cụ thể. Trình thông dịch trên mỗi máy sẽ chuyển tập lệnh này thành chương trình thực thi. Máy ảo tạo ra một môi trường bên trong để thực thi các lệnh bằng cách:  Nạp các file .class  Quản lý bộ nhớ  Dọn “rác” Việc không nhất quán của phần cứng làm cho máy ảo phải sử dụng ngăn xếp để lưu trữ các thông tin sau:  Các “Frame” chứa các trạng thái của các phương thức.  Các toán hạng của mã bytecode.  Các tham số truyền cho phương thức.  Các biến cục bộ. Khi máy ảo Java(JVM) thực thi mã, một thanh ghi cục bộ có tên “Program Counter” được sử dụng. Thanh ghi này trỏ tới lệnh đang thực hiện. Khi cần thiết, có thể thay đổi nội dung thanh ghi để đổi hướng thực thi của chương trình. Trong trường hợp thông thường thì từng lệnh một nối tiếp nhau sẽ được thực thi. Một khái niệm thông dụng khác trong Java là trình biên dịch “Just In Time- JIT”. Các trình duyệt thông dụng như Netscape hay IE đều có JIT bên trong để tăng tốc độ thực thi chương trình Java. Mục đích chính của JIT là chuyển tập lệnh bytecode thành mã máy cụ thể cho từng loại CPU. Các lệnh này sẽ được lưu trữ và sử dụng mỗi khi gọi đến. a) Quản lý bộ nhớ và dọn rác Trong C, C++ hay Pascal người lập trình sử dụng phương pháp trực tiếp để cấp phát và thu hồi bộ nhớ ở vùng “Heap”. Heap là vùng bộ nhớ lớn được phân chia cho tất cả các luồng. 6
  18. Để quản lý Heap, bộ nhớ được theo dõi qua các danh sách sau:  Danh sách các vùng nhớ chưa sử dụng.  Danh sách các vùng đã cấp. Khi có một yêu cầu về cấp phát bộ nhớ, hệ thống xem xét trong danh sách chưa cấp phát để lấy ra khối bộ nhớ đầu tiên có kích cỡ sát nhất với lượng bộ nhớ cần thiết . Kỹ thuật cấp phát này giảm tối thiểu việc phân mảnh của heap. “Coalescing” là kỹ thuật khác cũng giảm thiểu việc phân mảnh của heap bằng cách gom lại các vùng nhớ chưa dùng liền nhau thành một khối lớn hơn. Còn kỹ thuật sắp xếp lại các phần đã dùng để tạo vùng nhớ chưa sử dụng lớn hơn gọi là “Compaction”. Java sử dụng hai heap riêng biệt cho cấp phát vùng nhớ tĩnh và vùng nhớ động. Một heap (heap tĩnh) chứa các định nghĩa về lớp, các hằng và danh sách các phương thức. Heap còn lại (heap động) được chia làm hai phần được cấp phát theo hai chiều ngược nhau. Một bên chứa đối tượng còn một bên chứa con trỏ trỏ đến đối tượng đó. “Handle” là cấu trúc bao gồm hai con trỏ. Một trỏ đến bảng phương thức của đối tượng, con trỏ thứ hai trỏ đến chính đối tượng đó. Chú ý rằng khi “Compaction” cần cập nhật lại giá trị con trỏ của cấu trúc “handle”. Thuật toán dọn rác có thể áp dụng cho các đối tượng đặt trong heap động. Khi có yêu cầu về bộ nhớ, trình quản lý heap trước tiên kiểm tra danh sách bộ nhớ chưa cấp phát. Nếu không tìm thấy khối bộ nhớ nào phù hợp (về kích cỡ) thì trình dọn rác sẽ được kích hoạt khi hệ thống rỗi. Nhưng khi đòi hỏi bộ nhớ cấp bách thì trình dọn rác sẽ được kích hoạt ngay. Trình dọn rác gọi phương thức finalize của đối tượng trước khi dọn dẹp đối tượng. Hàm này sẽ dọn dẹp các tài nguyên bên ngoài như các file đang mở. Công việc này không được trình dọn rác thực thi. b) Quá trình kiểm tra file .class Việc kiểm tra được áp dụng cho tất cả các file .class sắp được nạp lên bộ nhớ để đảm bảo tính an toàn. Trình “Class Loader” sẽ kiểm tra tất cả các file .class không thuộc hệ điều hành với mục đích giám sát sự tuân thủ các nghi thức để phát hiện các file .class có nguy cơ gây hư hỏng đến bộ nhớ, hệ thống file cục bộ, mạng hoặc hệ điều hành. Quá trình kiểm tra sẽ xem xét tổng thể tính nguyên vẹn của một lớp. File .class bao gồm ba phần logic là:  Bytecode  Thông tin về Class như phương thức, giao diện và các giá trị hằng số được tập hợp trong quá trình biên dịch. 7
  19.  Các thuộc tính về lớp. Các thông tin của file .class được xem xét riêng rẽ trong các bảng sau:  Bảng Field chứa các thuộc tính  Bảng Method chứa các hàm của class  Bảng Interface và các hằng số. Quá trình kiểm tra file .class được thực hiện ở bốn mức:  Mức đầu tiên thực hiện việc kiểm tra cú pháp để đảm bảo tính cấu trúc và tính toàn vẹn cú pháp của file .class được nạp.  Mức thứ hai sẽ xem xét file .class để đảm bảo các file này không vi phạm các nguyên tắc về sự nhất quán ngữ nghĩa.  Mức thứ ba sẽ kiểm tra bytecode. Trong bước này sẽ kiểm tra số thông số truyền vào phương thức, khả năng truy xuất sai chỉ số của mảng, chuỗi, biểu thức.  Mức thứ tư sẽ kiểm tra trong thời gian thực thi để giám sát các việc còn lại mà ba bước trên chưa làm. Ví dụ như liên kết tới các lớp khác trong khi thực thi, hay kiểm tra quyền truy xuất. Nếu mọi điều thỏa mãn, lớp sẽ được khởi tạo. 1.1.5. Bộ công cụ phát triển JDK Sun Microsystem đưa ra ngôn ngữ lập trình Java qua sản phẩm có tên là Java Development Kit (JDK). Từ khi phát triển phiên bản đầu tiên từ năm 1995 đến nay, bộ công cụ Java đã được phát triển qua nhiều phiên bản và cũng có nhiều sự thay đổi, sau đây là một số phiên bản đã được phát hành: JDK 1.0 JDK 1.1 (19 tháng 2, 1997) JDK 1.1.5 (Pumpkin) 03 tháng 12, 1997 JDK 1.1.6 (Abigail) 24 tháng 4, 1998 JDK 1.1.7 (Brutus) 28 tháng 9, 1998 JDK 1.1.8 (Chelsea) 08 tháng 4, 1999 J2SE 1.2 (Playground) 08 tháng 12, 1998 J2SE 1.2.1 (không có) 30 tháng 3, 1999 J2SE 1.2.2 (Cricket) 08 tháng 7, 1999 J2SE 1.3 (Kestrel) 08 tháng 5, 2000 8
  20. J2SE 1.3.1 (Ladybird) 17 tháng 5, 2001 J2SE 1.4.0 (Merlin) 06 tháng 02, 2002 J2SE 1.4.1 (Hopper) 16 tháng 9, 2002 J2SE 1.4.2 (Mantis) 26 tháng 6, 2003 J2SE 5 (1.5.0) (Tiger) 30 tháng 9, 2004 Java SE 6(còn gọi là Mustang), được công bố 11 tháng 12 năm 2006. Các bản cập nhật 2 và 3 được đưa ra vào năm 2007, bản cập nhật 4 đưa ra tháng 1 năm 2008. JDK 6.18, 2010 Java SE 7(còn gọi là Dolphin), được bắt đầu từ tháng 8 năm 2006 và công bố ngày 28 tháng 7 năm 2011. Hiện tại đang phát triển và thử nghiệm bản Java JDK 8. JDK bao gồm Java Plug-In, chúng cho phép chạy trực tiếp Java Applet hay JavaBean bằng cách dùng JRE thay cho sử dụng môi trường thực thi mặc định của trình duyệt. JDK chứa các công cụ sau: Trình biên dịch, 'javac' Cú pháp: javac [options] sourcecodename.java Trình thông dịch, 'java' Cú pháp: java [options] classname Trình dịch ngƣợc, 'javap' javap dịch ngược bytecode và in ra thông tin về các thuộc tính (các trường), các phương thức của một lớp. Cú pháp: javap [options] classname Công cụ sinh tài liệu, 'javadoc' Tiện ích này cho phép ta tạo ra tệp HTML dựa trên các lời giải thích trong mã chương trình (phần nằm trong cặp dấu /* */). Cú pháp: 9
  21. javadoc [options] sourcecodename.java Chƣơng trình tìm lỗi - Debug, „jdb‟ Cú pháp: jdb [options] sourcecodename.java hay jdb -host -password [options] sourcecodename.java Chƣơng trình xem Applet , „appletviewer‟ Cú pháp: appletviewer [options] url Java Core API Nhân Java API được thay thế bởi phiên bản JFC 1.1. Một số package thông dụng được: java.lang Chứa các lớp quan trọng nhất của ngôn ngữ Java. Chúng bao gồm các kiểu dữ liệu cơ bản như ký tự, số nguyên, Chúng cũng chứa các lớp làm nhiệm vụ xử lý lỗi và các lớp vào ra chuẩn. Một vài lớp quan trọng khác như String hay StringBuffer. java.applet Đây là package nhỏ nhất chứa một mình lớp Applet. Các Applet nhúng trong trang Web hay chạy trong appletviewer đều thừa kế từ lớp này. java.awt Package này được gọi là Abstract Window Toolkit (AWT). Chúng chứa các lớp dùng để tạo giao diện đồ họa. Một số lớp bên trong là: Button, GridBagLayout, Graphics. java.io Cung cấp thư viện vào ra chuẩn. Chúng cho phép tạo và quản lý dòng dữ liệu theo nhiều cách. java.util Package này cung cấp một số công cụ hữu ích. Một vài lớp của package này là: Date, Hashtable, Stack, Vector và StringTokenizer. java.net 10
  22. Cung cấp khả năng giao tiếp với máy từ xa. Cho phép tạo và kết nối tới Socket hoặc URL. java.awt.event Chứa các lớp, giao diện dùng để xử lý các sự kiện trong chương trình như chuột, bàn phím. java.rmi Công cụ để gọi hàm từ xa. Chúng cho phép tạo đối tượng trên máy khác và sử dụng các đối tượng đó trên máy cục bộ. java.security Cung cấp các công cụ cần thiết để mã hóa và đảm bảo tính an toàn của dữ liệu truyền giữa máy trạm và máy chủ. java.sql Package này chứa Java DataBase Connectivity (JDBC), dùng để truy xuất cơ sở dữ liệu quan hệ như Oracle, SQL Server, 1.1.6. Cài đặt JDK Để cài đặt bộ công cụ Java Development Kit (JDK) thực hiện theo 3 bước sau: 1) Tải bộ công cụ về máy tính cá nhân Bộ công cụ JDK của Sun System là một bộ công cụ miễn phí, có thể download trực tiếp từ hãng về qua địa chỉ website: Tùy theo cấu hình của máy tính và phiên bản hệ điều hành mà có thể lựa chọn gói phần mềm phù hợp, rồi download về máy tính. Ví dụ 1.1: Máy tính chạy hệ điều hành Windows 7 bản 64 bit ta thực hiện như sau: Bước 1: Mở trình duyệt Web và truy nhậpvào địa chỉ sau: 11
  23. Hình 1.3. Trang web tải bộ công cụ Java Bước 2: Kích chọn biểu tượng Java Download như hình sau: Hình 1.4. Biểu tượng Java Download Bước 3: Kích chọn AcceptLicense Agreement Hình 1.5. Lựa chọn bản quyền Bước 4: Lựa chọn góijdk-7u45-windows-x64.exe rồi tải về máy như hình sau: Hình 1.6. Bộ JDK cho Windows bản 64 bit 2) Cài đặt JDK Sau khi đã tải được file chương trình về máy tính, chạy file chương trình đãdownload được và thực hiện theo các chỉ dẫn của chương trình cho đến khi hoàn thành thì sẽ được chương trình JDK cài trên máy tính. Ví dụ 1.2: Hướng các bước cài đặt JDK cho Windows 7 64 bit Bước 1: Chạy file jdk-7u45-windows-x64.exe đã tải về máy tính được màn hình Setup như sau: 12
  24. Hình 1.7. Màn hình cài đặt đầu tiên Bước 2: Kích chuột vào Next để tiếp tục cài đặt, khi đó được màn hình custom setup như hình sau: Hình 1.8. Màn hình Custom Setup Bước 3:Lựa chọn các thành phần cài đặt trong Feature và lựa chọn thư mục chứa chương trình cài đặt trong mục Install to, sau đó chọn Next để tiếp tục cài đặt sẽ được màn hình Description Folder Hình 1.9. Màn hình Description Folder 13
  25. Bước 4: Trong màn hình này có thể thay đổi thư mục cài đặt trong change của mục Install to theo mặc định đường dẫn thư mục cài đặt sẽ là c:\Program Files\Java, chọn Next để tiếp tục, khi đó được màn hình Progress Hình 1.10. Màn hình Progress Bước 5: Cho đến khi tiến trình cài đặt hoàn thành và kích chọn Finish để hoàn thành. 3) Cấu hình JDK Sau khi đã cài đặt thành công JDK, người lập trình nên cấu hình class path để thiết lập biến môi trường cho Java có thể chạy được trên bất kỳ thư mục chứa chương trình nào. Tùy theo hệ điều hành được cài đặt trên máy tính mà có cách vào chế độ cấu hình khác nhau. Trong ví dụ 1.3 dưới đây sẽ hướng dẫn cách cài đặt và cấu JDK trên hệ điều hành Windows 7 bản 64 bit. Ví dụ1.3: Cấu hình JDK trên Windows 7 bản 64 bit. Bước 1: Mở Explore trên Windows và copy tên đường dẫn đến thư mục chứa chương trình cài đặt của Java như hình sau: Hình 1.11. Đường dẫn của thư mục cài đặt Java Bước 2: Kích chuột phải vào My Computer chọn Properties được màn hình sau: 14
  26. Hình 1.12. Màn hình Computer Properties Bước 3: Chọn Avanced system settings trong cửa sổ trên sẽ được cửa sổ màn hình System Properties như sau: Hình 1.13. Màn hình System Properties Bước 4: ChọnEnvironment Variables khi đó được màn hình: 15
  27. Hình 1.14. Màn hình Environment Variables Bước 5: Trong mục System Avariables chọn Path rồi chọn edit được màn hình Edit System Variable. Dán (Pate) đường dẫn đã copy ở bước 1 vào phần cuối của mục Variable value rồi chọn ok Hình 1.15. Màn hình Edit System Variable Bước 6: Kiểm tra quá trình cấu hình bằng cách vào run nhận lệnh cmd để mở cửa số Command Prompt, trong cửa sổ này ở thư mục bất kỳ nhập lệnh java – version nếu xuất hình như hình 1.7. dưới đây là quá trình cài cấu hình thành công. Hình 1.16. Màn hình cửa sổ run Hình 1.17. Màn hình Command Prompt 16
  28. 1.2. Ngôn ngữ lập trình Java 1.2.1. Mở đầu lập trình với Java Java là một ngôn ngữ lập trình hướng đối tượng. Tất cả các lớp trong Java đều dựa trên lớp Object, là cha của tất cả các lớp. Các lớp có liên quan được tổ chức thành các gói (packages). Các gói cũng có thể chứa các gói khác hoặc các giao diện. Một giao diện là một loạt các phương pháp mà các lớp Java có thể thực thi. Các chương trình mã nguồn Java (*.java) đầu tiên được biên dịch thành các file bytecode (tập tin mã nhị phân) (*.class). Sau đó trình thông dịch Java sẽ chuyển đổi các bytecode thành các mã máy theo bộ xử lý cụ thể. 1.2.2. Cấu trúc chƣơng trình Java Về cơ bản cấu trúc chung của một chương trình Java có dạng như sau: import packages //chỉ định các gói hay lớp sẽ được dùng trong chương trình class Classname { /* Đây là dòng chú thích */ int num1, num2; //khai báo biến Methodname() { // Thân phương thức statements; // kết thúc lệnh bằng dấu ; } } Trong đó phần đầu của một chương trình Java, “import packages” xác định thông tin môi trường. Để làm được việc này, chương trình được chia thành các lớp hoặc các gói riêng biệt. Những gói này sẽ được chỉ dẫn trong chương trình. Thông tin này được chỉ ra với sự trợ giúp của lệnh nhập “import”. Mỗi chương trình có thể có nhiều hơn một lệnh nhập. Dưới đây là một ví dụ về lệnh nhập: import java. awt.*; Lệnh này nhập gói „awt‟. Gói này dùng để tạo các đối tượng GUI. Ở đây java là tên của thư mục chứa gói „awt‟. Ký hiêu “*” chỉ tất cả các lớp thuộc gói này. Trong java, tất cả các mã, bao gồm các biến và cách khai báo nên được thực hiện trong phạm vi một lớp. Bởi vậy, từng khai báo lớp được tiến hành sau lệnh nhập. Một chương trình đơn giản có thể chỉ có một vài lớp. Những lớp này có thể mở rộng thành các lớp khác. Mỗi lệnh đều được kết thúc bởi dấu chấm phảy “;”. Chương trình còn có thể bao gồm các ghi chú, chỉ dẫn. Khi dịch, chương trình dịch sẽ tự loại bỏ các ghi chú này. 17
  29. Các ghi chú dùng để gợi nhớ lại quá trình suy nghĩ, kiểm nghiệm các lập luận hoặc khi cần bổ sung, sửa chữa, nâng cấp chương trình. Java hỗ trợ 3 cách ghi chú sau: Bắt đầu Kết thúc Mục đích /* */ Nội dung ở giữa là phần ghi chú // (không có) Phần dòng còn lại là ghi chú / */ Nội dung ở giữa là phần ghi chú dùng cho JavaDoc Bảng 1.1. Bảng các ký hiệu ghi chú Có thể phân chia các thành phần trong một chương trình Java làm 5 loại sau: - Các tên định danh (identifiers): là tên các biến, các phương thức và các lớp để trình biên dịch định danh duy nhất. Tên định danh gồm các mẫu tự, dấu _ hoặc dấu $, các ký tự đặc biệt không khác được dùng. - Các từ khoá (keywords): là các tên định danh sẵn được Java dành riêng, không được dùng các từ khóa để dùng làm các tên định danh. Các từ khoá của Java gồm: Từ khóa Ý nghĩa abstract dùng để thông báo một phương thức trừu tượng, cần có một phương thức con không trừu tượng lấp lên. Một phương thức là trừu tượng sẽ không có phần mã lệnh (MethodBody) boolean kiểu biến logic, chỉ có hai giá trị đúng, sai (TRUE, FALSE). Chúng khác với C/C++ biến kiểu này chỉ chiếm 1 bit trong bộ nhớ. break từ khoá dùng để thoát ra khỏi vòng lặp byte kiểu dữ liệu có giá trị 8 bit case một trường hợp trong cấu trúc switch catch sử dụng khi nhận về các kết quả lỗi, được sử dụng trong xử lý ngoại lệ char kiểu dữ liệu ký tự class Khai báo Lớp const khai báo hằng continue dùng để nhảy về đầu vòng lặp default giá trị mặc định trong cấu trúc lựa chọn 18
  30. do nằm trong câu lệnh vòng lặp (do while) else nằm trong cấu trúc lựa chọn (if else ) extends dẫn xuất, được sử dụng để khai báo một lớp được kế thừa từ một lớp khác final Dùng để khai báo hằng số, phương thức không thể ghi đè, hoặc lớp không thể kế thừa finally phương thức kết thúc float kiểu số thực for dùng để thực hiện một vòng lặp xác định if nằm trong cặp lệnh điều khiển if then else implements cài đặt, dùng để khai báo một lớp là cài đặt của một giao diện import cho biết dùng các thư viện nào instanceof dùng trong kiểu định danh thời gian chạy(Runtime Type Identification) kiểm tra một đối tượng có phải là một thể hiện của lớp hay không int kiểu biến nguyên interface giao diện, sử dụng để khai báo giao diện long kiểu số nguyên native nguồn, gốc: Khai báo phương thức được viết bằng ngôn ngữ biên dịch C++ new dùng để tạo một đối tượng mới package gói, đóng gói private từ khóa khai đối tượng tiếp sau là cục bộ protected không bị chồng, sử dụng trong các lớp dẫn xuất public đối tượng khai báo tiếp theo sau là biến toàn cục return trở về lệnh gọi short kiểu biến nguyên statictis đối tượng khai báo tiếp theo sau là tĩnh father đối tượng cha 19
  31. swith dùng trong cấu trúc lựa chọn (switch case) synchronized đồng bộ, sử dụng để khai báo một phương thức độc quyền truy xuất trên một đối tượng this đối tượng hiện đang xét throw trả về lỗi throws cho biết phương thức hay biến sẽ trả về (báo) khi có lỗi (dùng trong khai báo phương thức) transient Giá trị của biến được khai báo kiểu này sẽ không được lưu giữ như trước khi một đối tượng (chứa biến đó) được lưu trữ try Sử dụng để bắt ngoại lệ void Dùng để khai báo một phương thức không trả về giá trị volatile Giá trị của biến được khai báo kiểu này có thể được thay đổi đột xuất bởi các phần khác của chương trình while dùng trong cặp lệnh vòng lặp Bảng 1.2. Các từ khóa của Java - Các dấu cách (separators): thông báo cho trình biên dịch java cách xác định các thành phần ngữ nghĩa của chương trình. - Các hằng (literals): là các giá trị bất biến trong một chương trình. Các hằng có thể là các số, các chuỗi, các ký tự, hoặc các giá trị Boolean. - Các toán tử (operators): chỉ định một đánh giá hoặc một phép toán được thực hiện trên dữ liệu hay các đối tượng. Ví dụ : +, -, *, /, % 1.2.3. Kiểu dữ liệu cơ sở, hằng, biến a) Các kiểu dữ liệu cơ sở: Java cung cấp các kiểu dữ liệu cơ sở. Các kiểu dữ liệu này được dùng để tạo các kiểu dữ liệu dẫn xuất - Kiểu số nguyên, Java có bốn loại số nguyên: byte, short, int, long Kiểu Kích thước Giá trị nhỏ nhất Giá trị lớn nhất byte 7 bits -128 127 Short 16 bits -32768 32767 int 30 bits -2.147.483.648 2.147.483.647 20
  32. long 62 bits -9.223.372.036.854 9.223.372.036.854 Bảng 1.3. Các kiểu số nguyên Các phép tính trên biến số nguyên gồm: Toán Phép toán tử == Bằng nhau != Không bằng > Lớn hơn = Lớn hơn hoặc bằng > Dịch chuyển sang phải n bit >>> Dịch chuyển sang phải và điền 0 vào bit trống Bảng 1.4. Các phép toán trên kiểu số nguyên Nếu hai toán hạng đều dạng long thì kết quả sẽ là dạng long 64 bits. Nếu có một toán hạng không phải dạng long thì sẽ được chuyển sang dạng long trước khi thực hiện 21
  33. phép toán. Nếu cả hai toán hạng không phải là long (byte, short) thì sẽ được đổi sang int trước khi thực hiện phép toán. Trong Java không thể chuyển biến boolean sang int như các ngôn ngữ khác. -Kiểu số thực, Java có 2 loại số thực là: float và double Kiểu Kích cỡ Giá trị nhỏ nhất Giá trị lớn nhất float 32 bits -3.40292347E+38 3.40292347E+38 double 64 bits -1.79769313486231570E+308 1.79769313486231570E+308 Bảng 1.5. Các loại số thực Các phép toán trên kiểu số thực gồm: Toán tử Phép toán == Bằng nhau != Không bằng > Lớn hơn = Lớn hơn hoặc bằng <= Nhỏ hơn hoặc bằng + Cộng - Trừ * Nhân / Chia % Lấy phần dư ++ Tăng 1 Giảm 1 Bảng 1.6. Các phép toán trên kiểu số thực Biến kiểu float và double có thể được chuyển sang các kiểu dữ liệu số khác nhưng không thể chuyển sang kiểu dữ liệu boolean.Khi thực hiện phép tính java sẽ chuyển các toán hạng về kiểu dữ liệu cao nhất rồi mới tính toán. Java đưa ra một số thực NaN (Not a Number) dùng cho các giá trị không thể xác định được trong khoảng từ vô cực âm đến vô cực dương. Nó giải quyết lỗi phép chia cho 0. -Kiểu dữ liệu char: 22
  34. Char là kiểu dữ liệu về ký tự, một biến char sẽ có giá trị là một ký tự Unicode, có kích thước 16 bits từ „\u0000‟ đến „\uFFFF‟. -Kiểu dữ liệu boolean: Boolean là kiểu dữ liệu chỉ có hai giá trị là True và False dùng để xác định kết quả một điều kiện và có kích thước là một bit. Do đó ta không thể chuyển kiểu giữa boolean sang int hay ngược lại . Giá trị mặc định: Một lỗi hay gặp phải khi lập trình là sử dụng những biến chưa khởi tạo. Điều này tạo ra những lỗi không thể đoán trước (như định dạng lại đĩa, chép đè lên CMOS), bởi vì chúng có thể nhận bất kỳ giá trị nào trong vùng nhớ khi chương trình bắt đầu chạy. Java đã tránh được lỗi trên bằng cách luôn khởi tạo giá trị mặc định cho các biến. Các giá trị được xác định phụ thuộc vào kiểu của biến theo bảng sau: Kiểu Giá trị mặc định Byte 0 Short 0 Int 0 Long 0L float 0.0f double 0.0d char null boolean false Các biến dẫn xuất null Bảng 1.7. Giá trị mặc định -Chuyển kiểu (type casting): Trong một biểu thức của chương trình không phải lúc nào các biến cũng thuộc về cùng một kiểu dữ liệu. Vì vậy để các biến thuộc về cùng một kiểu dữ liệu nào đó Java cho phép chuyển kiểu đối với một biến ở 2 hướng: chuyển kiểu hẹp (Narrowing conversion – từ kiểu lớn về kiểu nhỏ) và chuyển kiểu nới rộng (Widening conversion - từ kiểu nhỏ về kiểu lớn) Ví dụ 1.4: class TypeCast { public static void main (String args[]) { float a = (float) 12; //chuyển kiểu số nguyên 12 sang float 23
  35. System.out.println (“a = “+a); // a = 12.0 float b = 15.682f; int c = (int) b + 20; System.out.println (“c = “+c); // c = 35 } } chuyển kiểu mở rộng(Widening) – quá trình làm tròn số theo hướng mở rộng không làm mất thông tin về độ lớn của mỗi giá trị.Biến đổi theo hướng mở rộng chuyển một giá trị sang một dạng khác có độ rộng phù hợp hơn so với nguyên bản. Biến đổi theo hướng lại thu nhỏ lại (Narrowing) làm mất thông tin về độ lớn của giá trị được chuyển đổi. Chúng không được thực hiện khi thực hiện phép gán. Ở ví dụ trên giá trị thập phân sau dấu phảy sẽ bị mất. b) Đặt tên (Identifier) Một tên là một chuỗi các ký tự gồm các chữ, số, dấu gạch dưới (_), và dấu dollar ($). Việc đặt tên cho một hằng và biến cần theo những quy tắc sau: - Ký tự đầu phải là ký tự chữ, dấu _, hay dấu $.Không thể bắt đầu bởi một số - Sau ký tự đầu, có thể dùng các ký tự chữ, ký số, dấu _, dấu $ - Không được có khoảng trắng - Không được trùng với các từ khóa c) Hằng (literal): Hằng là một giá trị thực được sử dụng trong chương trình, được biểu diễn như chính nó chứ không phải là một giá trị của một biến hay một kết quả của một biểu thức. Ví dụ hằng 3.14159 thay cho số Pi. -Khai báo hằng: Để khai báo hằng ta dùng từ khoá final đặt trước kiểu dữ liệu và tên hằng cú pháp như sau: Cú pháp: final datatype identifier =value [, identifier=value[, ] ]; Trong đó - datatype là kiểu dữ liệu - identifier là tên hằng - value là giá trị của hằng Ví dụ sau sẽ khai báo một hằng tên PI thuộc kiểu số thực (float) có giá trị là 3.14159 24
  36. final float PI = 3.14159; - Có các loại hằng sau: Hằng số nguyên: Hằng số nguyên có thể được biểu diễn dưới dạng thập phân (decimal), bát phân (octal), thập lục phân (hexadecimal). Integer Long Octal Hexadecimal 0 0L 0 0x0 1 1L 01 0x1 10 10L 012 0xA 15 15L 017 0xF 16 16L 020 0x10 100 100L 0144 0x64 Bảng 1.8. Hằng số nguyên Hằng số thực: Các hằng thực có thể biểu diễn bằng dạng thập phân như 5.1693 hay dạng mũ như 6.2e23. Để chỉ rõ hằng kiểu float ta thêm “f” hay “F” phía sau hằng, hoặc hằng thực ta thêm “d” hay “D”. Hằng ký tự: Một hằng ký tự là một ký tự đơn hay một chuỗi ESCAPE, được đặt trong hai dấu nháy đơn. Chuỗi ESCAPE được dùng để biểu diễn các ký tự đặc biệt như tab („\t‟) hay một động tác đặc biệt như xuống dòng („\n‟). Ta có bảng liệt kê các chuỗi ESCAPE thường dùng: Chuỗi Ý nghĩa \b Xóa lùi \t Tab ngang \n Xuống hàng \f Đẩy trang \r Dấu enter \” Dấu nháy kép 25
  37. \‟ Dấu nháy đơn \\ Dấu sổ ngược \uxxxx Ký tự Unicode Bảng 1.9. Các hằng số thực Hằng chuỗi ký tự: Mặc dù Java không cung cấp kiểu dữ liệu cơ sở string, ta vẫn có thể khai báo một hằng chuỗi trong chương trình. Một hằng chuỗi được đặt giữa 2 dấu nháy kép, nó có thể là hằng chuỗi rỗng hay có nhiều ký tự. Khi sử dụng một hằng chuỗi ký tự, ta xem như đã tạo ra một đối tượng của lớp String và không cần chú ý đến các thao tác về bộ nhớ như tạo và xóa các vùng nhớ cho các hằng chuỗi ký tự. Java có một hệ thống quản lý vùng nhớ tự động làm việc này. d. Biến Các ứng dụng sử dụng các biến để lưu trữ các dữ liệu cần thiết hoặc các dữ liệu được tạo ra trong quá trình thực thi chương trình. Các biến được xác định bởi một tên biến và có một phạm vi tác động. Phạm vi tác động của biến được xác định một cách rõ ràng trong chương trình. Việc khai báo một biến bao gồm 3 thành phần: kiểu biến, tên của nó và giá trị ban đầu được gán cho biến (không bắt buộc). Để khai báo nhiều biến ta sử dụng dấu phẩy để phân cách các biến. Khi khai báo biến, luôn nhớ rằng Java phân biệt chữ thường và chữ in hoa (case -sensitive). Cú pháp: Datatype identifier [=value] [, identifier[=value] ]; Để khai báo một biến nguyên (int) có tên là counter dùng để lưu giá trị ban đầu là 1, ta có thể thực hiện như sau: int counter = 1; Java có những yêu cầu hạn chế đặt tên biến mà bạn có thể gán giá trị vào. Những hạn chế này cũng giống các hạn chế khi đặt tên cho các định danh mà ta đã thảo luận ở các phần trước của chương này. Java cho phép khai báo biến khá linh hoạt như sau: char ch; //khai báo một biến kiểu char int count, num ; //khai báo hai biến trên cùng dòng int count =10; char ch =‟A‟; //khai báo và khởi tạo biến int num = 012; //gán giá trị bát phân int num = 0x18; // gán giá trị thập lục phân float dec=1.0F; //khai báo và gán giá trị cho biến kiểu float 26
  38. char ch=‟\u0020‟; //khai báo và khởi tạo một giá trị Unicode cho biến ch int a=5, b=10; //khai báo và khởi tạo nhiều biến cùng lúc int c=a+b; //khởi tạo biến bằng biểu thức e) Phạm vi hoạt động của hằng và biến Tất cả các biến trong ứng dụng Java đều có một phạm vi (scope), hay là các đặc trưng xác định nơi có thể truy cập biến chỉ bằng tên của nó. Nếu biến nằm trong vùng phạm vi, thì có thể tương tác với nó bằng tên. Nếu biến nằm ngoài vùng phạm vi thì điều này là không thể. Có nhiều mức phạm vi trong ngôn ngữ Java, được xác định bởi vị trí khai báo của biến ở đâu. Đoạn mã dưới đây chỉ ra vị trí khai báo các biến: public class SomeClass { member variable scope public void SomeMethod(parameters ) { method parameter scope local variable declaration(s) local scope someStatementWithACodeBlock { block scope } } } Phạm vi của một biến trải rộng từ đầu đoạn (hoặc đầu khối) cho đến cuối đoạn (hoặc cuối khối) mã lệnh mà nó được khai báo trong đó. 1.2.4. Kiểu dữ liệu Mảng (Array) Mảng được dùng để lưu trữ các khoản mục (items) cùng kiểu dữ liệu liền kề nhau trong bộ nhớ. Mỗi lần ta khai báo kích thước của một mảng, nó sẽ không thể thay đổi. Dữ liệu trên mảng có thể là kiểu dữ liệu nguyên thủy hoặc đối tượng. Cũng như các biến, ta có thể gán các giá trị vào mảng tại các phần tử được tạo ra trong mảng. Nếu không, Java sẽ gán giá trị mặc định vào tất cả các phần tử của mảng, giá trị mặc định phụ thuộc vào kiểu dữ liệu. Ví dụ nếu kiểu dữ liệu là nguyên (int) thì giá trị mặc định ban đầu sẽ là 0. Khai báo mảng 27
  39. Đặc trưng của mảng là một cặp dấu ngoặc vuông ([]), một mảng được khai báo bằng hai cách : Cặp ngoặc vuông đặt sau tên biến Cặp ngoặc vuông đặt sau kiểu dữ liệu Cú pháp như sau: Datatype identifier[]; hoặc Datatype[] identifier; Ví dụ 1.5: int arrInt[]; hoặc int[] arrInt; int[] arrInt1, arrInt2, arrInt3; Cấp phát bộ nhớ cho mảng Sau khi khai báo, bản thân mảng chưa được xác định (chưa được cấp phát bộ nhớ), bởi vì Java không cho phép chỉ định số phần tử khi khai báo. Để định vị cho một mảng trong bộ nhớ ta cần dùng từ khóa new. Cú pháp như sau: Identifier = new datatype[n]; Trong đó Identifier là tên biến mảng đã được khai báo, datatype là kiểu dữ liệu của mảng, n là số phần tử của mảng. Ví dụ 1.6: để cấp phát một vùng nhớ cho một mảng arrInt đã khai báo ở trên gồm 100 phần tử kiểu int ta thực hiên như sau: int arrInt = new int[100]; Tuy nhiên Java cũng cho phép thực hiện việc cấp phát vùng nhớ cho mảng trong khi khai báo theo cú pháp như sau: Datatype identifier[] = new Datatype[n]; Ví dụ 1.7: char ch[] = new char [10]; // khai báo và cấp phát bộ nhớ bằng từ khóa new Lệnh này sẽ tạo ra mảng ch có 10 phần tử kiểu char được đánh số từ 0 đến 9. Khởi tạo mảng Chúng ta có thể khởi tạo giá trị ban đầu cho các phần tử của mảng khi nó được khai báo. Ví dụ 1.8: 28
  40. int arrInt[] = {1, 2, 3}; chararrChar[] = {„a‟, „b‟, „c‟}; string arrStrng[] = {“ABC”, “EFG”, „GHI‟}; Truy cập mảng Chỉ số mảng trong Java bắt đầu tư 0. Vì vậy phần tử đầu tiên có chỉ số là 0, và phần tử thứ n có chỉ số là n-1. Các phần tử của mảng được truy xuất thông qua chỉ số của nó đặt giữa cặp dấu ngoặc vuông ([]). Ví dụ 1.9: khai báo mảng int arrInt[] = {1, 2, 3}; int x = arrInt[0]; // x sẽ có giá trị là 1. int y = arrInt[1]; // y sẽ có giá trị là 2. int z = arrInt[2]; // z sẽ có giá trị là 3. 1.2.5. Toán tử và biểu thức a) Toán tử Toàn tử là các ký hiệu sử dụng cho các phép toán, thường được tham gia vào việc thành lập các biểu thức. Trong Java có các loại toán tử sau: Toán tử hai ngôi: lớn hơn a > b a lớn hơn b >= lớn hơn hoặc bằng a >= b a lớn hơn hoặc bằng b + phép cộng a + b a cộng b – phép trừ a – b a trừ b * phép nhân a * b a nhân b / phép chia a / b a chia b % phép tính modulo a % b a modulo b > dịch chuyển bit sang a >> b dịch số a sang phải n bit 29
  41. phải >>> dịch chuyển bit a >>> b dịch a sang phải n bit và sang phải và điền 0 điền 0 vào các bit trống vào các bit trống & Phép AND trên bit a & b 4 & 2 = 0 | Phép OR trên bit a | b 4 | 2 = 6 ^ Phép XOR trên bit a ^ b 4 ^ 2 = 1 Bảng 1.10. Toán tử 2 ngôi Toán tử đơn: Toán tử Phép toán Ví dụ Ghi chú – đổi dấu – a a =10, –a = –10 ~ phép đảo bit ~ a a =6, ~a = 1 ++ Tăng a++ gán a = a+1 –– giảm a––/– gán a= a–1 – Bảng 1.11. Danh sách các toán tử đơn Toán tử gán : Toán tử gán Ví dụ Ý nghĩa += a += 3 a = a+3 –= a –= 4 a = a – 4 *= a *= 2 a = (a*2) /= a /= 5 a = (a/5) &= a &= b a = (a&b) |= a |= b a = (a | b) ^= a ^= b a = (a ^ b) %= a %= b a = (a % b) >= a >>= n a = (a >> n) >>>= a >>>= n a = (a >>> n) 30
  42. Bảng 1.12. Danh sách các toán tử gán Toán tử trên số thực: Toán tử Phép toán Ví dụ Ghi chú = Phép gán a = 10 Gán cho a giá trị 10 == So sánh bằng a == b a bằng b != Không bằng a != b a khác b lớn hơn a > b a lớn hơn b >= lớn hơn hoặc a >= b a lớn hơn hoặc bằng bằng + phép cộng a + b a cộng b – phép trừ a – b a trừ b * phép nhân a * b a nhân b / phép chia a / b a chia b Bảng 1.13. Danh sách các toán tử trên kiểu số thực Toán tử trên kiểu Boolean: Toán tử Phép toán Ví dụ Ghi chú ! phép đảo !a lấy giá trị ngược lại với a && điều kiện a && b thỏa đồng thời 2 điều kiện a và AND b || điều kiện OR a || b thoả a hay ba3 hai == phép bằng a == b xét a có bằng b không != phép not a != b xét a có khác b không ?: chuỗiđiềukiện a ? expr1 nếu a đúng thì lấy kết quả : expr2 expr1, ngược lại lấy expr2 Bảng 1.14. Danh sách các phép toán logic b)Biểu thức: 31
  43. Biểu thức là một sự kết hợp giữa các toán tử và các toán hạng theo đúng một trật tự nhất định, để diễn đạt một công thức toán học nào đó. Mỗi biểu thức có sẽ có một giá trị. Mỗi toán hạng có thể là một hằng, một biến hoặc một biểu thức khác. Trong trường hợp, biểu thức có nhiều toán tử, ta dùng cặp dấu ngoặc tròn () để chỉ định toán tử nào được thực hiện trước Như vậy hằng, biến, phần tử mảng và hàm cũng được xem là biểu thức. Ví dụ 1.10: sum = 5 + 4; Có 3 loại biểu thức chính là: Biểu thức số liên kết các biến số, các hằng bằng các phép toán số, kết quả của loại biểu thức này là một giá trị số. Biểu thức gán dùng để gán giá trị cho một biến, một hằng. Biểu thức logic chỉ cho ra kết quả là true hay false. Các biểu thức phức tạp là do lồng ghép các biểu thức đơn giản vào nhau ta có thể phân tích chúng dựa vào dấu ngoặc tròn (()). 1.2.6. Các cấu trúc điều khiển Cấu trúc điều khiển là các lệnh kiểm tra và điều khiển quá trình thực hiện các câu lệnh sao cho chương trình thực hiện đúng và đạt được yêu cầu đặt ra. a) Cấu trúc lựa chọn if: Câu lệnh if kiểm tra kết quả của một điều kiện và thực thi một thao tác phù hợp trên cơ sở kết quả đó. Lệnh if có các dạng sau: Dạng 1: Cú pháp: if ( ) Trong đó: - Biểu thứ điều kiện là một biểu thức logic - Câu lệnh là một câu lệnh nào đó muốn thực hiện khi biểu thức logic trả về kết quả là true. Ý nghĩa của câu lệnh là: nếu biểu thức logic đúng thì thực hiện câu lệnh Trong trường hợp muốn có nhiều câu lệnh cùng thực hiện khi biểu thức logic đúng (true) thì các lệnh này được bao trong một khối lệnh. Cú pháp như sau: if ( ){ } 32
  44. Ví dụ 1.11: import java.util.Date; Date today = new Date(); if (today.getDay == 0) System.out.println(“It is Sunday.”); Dạng 2: Cú pháp: if ( ) else Trong đó: - biểu thứ điều kiện là một biểu thức logic - Câu lệnh 1 là một câu lệnh nào đó muốn thực hiện khi biểu thức logic trả về kết quả là đúng. - Câu lệnh 2 là một câu lệnh nào đó muốn thực hiện khi biểu thức logic trả về kết quả là sai. Ý nghĩa của câu lệnh là nếu biểu thức logic đúng thì thực hiện câu lệnh 1 trong trường hợp ngược lại (biểu thức logic sai) thì thực hiện lệnh 2. Trong trường hợp muốn có nhiều câu lệnh cùng thực hiện khi biểu thức logic đúng (true) hoặc sai (false) thì các lệnh này phải là một khối lệnh. Trong trường hợp đầy đủ ta có thể viết lệnh theo cú pháp như sau: if ( ){[ ]} else {[ ]} Ví dụ 1.12: import java.util.Date; Date today = new Date(); if (today.getDay == 0) System.out.println(“It is Sunday.”); else System.out.println(“It is not Sunday.”); Ta cũng có thể dùng các cấu trúc if lồng nhau if else if else if else ; Ví dụ 1.13: import java.util.Date; Date today = new Date(); 33
  45. if (today.getDay == 0) System.out.println(“It is Sunday.”); else if (today.getDay ==1) System.out.println(“It is Monday.”); else if (today.getDay ==2) System.out.println(“It is Tuesday.”); else if (today.getDay ==3) System.out.println(“It is Wednesday.”); else if (today.getDay ==4) System.out.println(“It is Thursday.”); else if (today.getDay ==5) System.out.println(“It is Friday.”); else System.out.println(“It must be Saturday.”); Cấu trúc lựa chọn Switch: Switch { case : ; case : ; case : ; default : ; } Ví dụ 1.14: import java.util.Date; Date today = new Date(); Switch (today.getDay) { case 0: //Sunday case 3: //Wednesday case 6: //Saturday System.out.println(“It‟s Football day!”); break; case 2: //Tuesday System.out.println(“It‟s Tennis day!”); case 1: //Monday case 4: //Thursday case 5: //Friday System.out.println(“It‟s Golf day!”); break; } b) Cấu trúc lặp: Vòng lặp for: Câu lệnh for cho phép thực hiện lặp lại công việc cho đến khi biểu thức điều kiện sai. for ([ ];[ ];[ ]) Trong đó: 34
  46. - Khởi tạo: là một biểu thức dùng để gán giá trị khởi tạo cho một biến điều khiển lặp - Biểu thức kiểm tra: là một biểu thức logic dùng để kiểm tra việc lặp nếu biểu thức đúng thì cho phép lặp lại ngược lại sẽ kết thúc vòng lặp. - Bước nhảy: dùng để thiết lập bước nhảy cho mỗi lần lặp Ví dụ 1.15: for (int count = 0; count ; ; ) {[ ]} Vòng lặp While: Cú pháp: while ; Trong đó: - biểu thức boolean: là một biểu thức logic trả lại một trong 2 giá trị đúng (true) hoặc sai (false) - khối lệnh: là tập các câu lệnh sẽ được thực hiện trong vòng lặp Ý nghĩa của câu lệnh như sau: Trong khi biểu thức logic còn đúng thì lặp lại các công việc trong khối lệnh. Ví dụ 1.16: int count = 0; while (count ; } while ( ) Ví dụ 1.17: public void ShowYears(int year) { do {System.out.println(“Year is “+ year); 35
  47. } while (year { lệnh 1; lệnh 2; if break; lệnh 3; } lệnh 4; Ví dụ 1.18: xét đoạn chương trình tìm số nguyên x trong một mảng số nguyên cho trước như sau: class BreakExam { public static void main (String args[]) throws Exception { char ch[] = {'h','e','l','l','o',' ','w','o','r','l','d'}; char c = ' '; int i=0; boolean flag=false; System.out.print("Nhap ky tu can tim: "); c = (char)System.in.read(); for (i=0; i { lệnh 1; lệnh 2; 36
  48. if continue; lệnh 3; } lệnh 4; Ví dụ 1.19: xét đoạn chương trình in ra các số từ 0 đến 9 như sau: class Continue { public static void main(String args[]) { for (int i=0; i<10; i++) { System.out.print(i++" "); if ((i%2)==0) continue; System.out.println(""); } } } Nhãn (Label): Java không hỗ trợ lệnh goto, mặc dù lệnh goto có trong bộ từ khóa. Java thực hiện việc kết hợp lệnh break hay continue với nhãn để thay thế lệnh goto trong việc xử lý lặp như sau: Ví dụ 1.20: public void paint (Graphics g) { int line=1; outsideLoop: for (int out =0; out<3; out ++) { g.drawString(“out = “+ out, 5, line * 20); line ++; for (int inner=0; inner < 5; inner++) { // tạo biến ngẫu nhiên double randNum = Math.random(); g.drawString(Double.toString(randNum), 15, line * 20); line++; if (randNum < 0.1 { g.drawString(“break to outsideLoop”, 25, line * 20); line++; break outsideLoop; } 37
  49. if (randNum ( , , ) { } Cách truy xuất private : phương thức này chỉ được truy xuất bên trong lớp chứa nó. public : có thể truy xuất từ bất kỳ lớp bên ngoài nào. protected : chỉ các lớp dẫn xuất của lớp chứa phương thức này mới truy xuất được nó. Cách cập nhật static: là phương thức có thể được gọi mà không cần đến đối tượng. Nó chỉ được sử dụng đối với các dữ liệu và các phương thức tĩnh khác. absttract : phương thức đơn giản nhất, không cài đặt gì ở trong lớp khai báo nó. Nhưng phương thức này sẽ được phát triển trong các lớp là dẫn xuất của lớp hiện hành. final: phương thức loại này được bảo vệ không cho các lớp dẫn xuất khai báo và cài đặt lại. (overriding). 38
  50. native : là phương thức được viết bằng ngôn ngữ khác Java. Giống như phương thức abstract, phương thức native chỉ có tên gọi và khối lệnh rỗng. Nhưng khác với abstract nó được cài đặt trong các thư viện dùng chung viết bằng ngôn ngữ khác. synchronized: phương thức loại này đảm bảo dữ liệu sẽ không bị sai lạc khi cùng một lúc hai phương thức truy cập cùng một dữ liệu, thường được sử dụng trong kỹ thuật luồng (thread). Giá trị trả về void : là loại phương thức không trả về giá trị nào. integer, boolean, float, : kiểu dữ liệu của giá trị mà phương thức trả về. Gọi một phƣơng thức Khi muốn một phương thức được thực hiện, ta chỉ cần gọi tên của phương thức và gán các đối số là các giá trị hay các biến có cùng kiểu với các đối số đã được khai báo. Ví dụ 1.21: class CallMethod { static public int hinhvuong(int x) { return (x*x); } public static void main(String args[]) { int canh = 0, len = 0; String chuoi = ""; char buff[] = new char[10]; System.out.print("Nhap canh hinh vuong : "); try { len = System.in.read(buff); String s = String(buff, 0, len-1); chuoi = s; canh = Integer(chuoi).intValue(); } catch(Exception e) {} System.out.println("Dien tich hinh vuong: "+hinhvuong(canh)); } } 1.2.8. Nhập xuất dữ liệu Việc nhập xuất dữ liệu với java sẽ được đề cập chi tiết trong chương 3 của tài liệu này. Tuy nhiên để ứng dụng lý thuyết của chương vào giải quyết bài toán cũng như cài đặt các thử nghiệm để hiểu sau hơn về lý thuyết thì ta cần phải biết những thủ tục nhập xuất cơ bản với java. Vì vậy trong phần này sẽ trình bày một số cách thức để nhập xuất dữ liệu với java qua cửa số lệnh (console). 39
  51. Nhập dữ liệu là tác vụ đưa các dữ liệu cụ thể vào cho biến trong chương trình. Như vậy, phải có một nguồn chứa dữ liệu (bàn phím, tập tin, biến khác). Xuất dữ liệu là tác vụ đưa trị cụ thể của biến trong chương trình ra một nơi chứa (màn hình hay file hay biến khác). Nhập/xuất dữ liệu là các phương tiện mà chương trình tương tác với người dùng và thường không thể thiếu trong đa số các ứng dụng. Thường có hai cơ chế nhập xuất dữ liệu có tương tác với người dùng là:  Nhập xuất dữ liệu trong các ứng dụng console application  Nhập/xuất dữ liệu thông qua các phần tử trên GUI. Cách 1 thường dùng trong các ứng dụng chạy theo cơ chế tuần tự còn cách 2 được áp dụng trong các ứng dụng hướng cửa sổ. Việc nhập/xuất dữ liệu với java sẽ được đề cập chi tiết trong chương 3 của tài liệu này. Trong phần này chỉ trình bày một số cách thức đơn giản để nhập xuất dữ liệu trong các ứng dụng console application. a) Xuất dữ liệu Java cung cấp class System mô tả hệ thống trong đó có chứa 2 đối tượng mặc định dùng để nhập và xuất dữ liệu đó là System.in và System.out. Để xuất dữ liệu ra màn ta hình dùng 2 phương thức của đối tượng System.out đó là:  System.out.print( )  System.out.println([Dữ liệu xuất]); Trong đó dữ liệu xuất có thể là : ký tự, số, chuỗi, print là xuất ra màn hình mà không xuống dòng, còn println là xuất ra màn hình và con trỏ sẽ tự động xuống dòng. Ví dụ 1.22: sau đây sẽ xuất ra màn hình một xâu và giá trị của biến class OutputExam{ public static void main(String args[]) { int a=10,b=30; System.out.print(“Tong cua ” + a + “ + ” + b + “ = ” + (a+b)); } } Kết quả chạy chương trình là: Tong cua 10 + 30 = 40 40
  52. b) Nhập dữ liệu Nhập dữ liệu từ bàn phím khá phức tạp vì với mỗi dữ liệu có cách nhập khác nhau: Ký tự thì chỉ cần 1 phím, số nguyên, số thực có thể nhập với nhiều phím nên các phím nhập cần giữ lại bộ đệm (Buffer), có thể cần kiểm tra phím nhập. Java cung cấp 2 gói dữ liệu java.io và java.util chứa các lớp cho việc nhập xuất Gói dữ liệu java.io có các lớp Reader, BufferedReader, InputStream, OutputStrean, , có chứa các phương thức cho việc nhập dữ liệu (chi tiết sẽ được nghiên cứu ở chương 3). Ví dụ 1.23: Sau sẽ giúp nhập xuất với các kiểu dữ liệu khác nhau sử dụng các đối tượng của gói java.io import java.io.*; // file InOutDemo.java class InOutDemo { public static void main(String args []) throws java.io.IOException { Reader inputChar_Obj = new InputStreamReader(System.in); System.out.print("Input a character:"); char c = (char)inputChar_Obj.read() ; System.out.println(" character read :" + c); BufferedReader input_Obj= new BufferedReader(new InputStreamReader( System.in)); System.out.print("Input an Integer:"); int n= Integer.valueOf( input_Obj.readLine()).intValue() ; System.out.println(" integer read :" + n); System.out.print("Input a Double:"); double x= Double.valueOf( input_Obj.readLine()).doubleValue() ; System.out.println(" Double read :" + x); System.out.print("Input a string:"); String s = input_Obj.readLine(); System.out.println(" String read :" + s); System.out.print("Input a character:"); int m = System.in.read() ; 41
  53. System.out.println(" Code of this character :" + m); } } Kết quả thực hiện chương trình Input a character:r character read :r Input an Integer:123 integer read :123 Input a Double:12.908 Double read :12.908 Input a string:Hello String read :Hello Input a character:A Code of this character:65 Gói java.util cũng cung cấp lớp Scanner cũng có các phương thức cho việc nhập xuất các loại dữ liệu như: nextLine, next, nextInt, nextFloat, nextDouble, , Ví dụ 1.24:Sau đây sử dụng lớp Scanner để nhập dữ liệu import java.util.Scanner; public class InOutScan { public static void main(String[] args) { int tuoi; String ten; Scanner nhapDuLieu = new Scanner(System.in); System.out.print("Nhập Tên: "); ten = nhapDuLieu.nextLine(); System.out.print("Nhập Tuổi: "); tuoi = nhapDuLieu.nextInt(); System.out.println("\nTên Vừa Nhập:" + ten+"\n"); System.out.println("Tuổi Vừa Nhập: " + tuoi); } 42
  54. } Kết quả chạy chương trình: Câu hỏi và bài tập chƣơng 1 1. Viết chương trình thực hiện các công việc sau: a. Nhập vào 3 số nguyên dương a, b, c b. Kiểm tra nếu a, b, c, là 3 cạnh của một tam giác thì tính diện tích, chu vi của tam giác tạo thành bởi 3 cạnh a, b, c đó. Ngược lại thông báo không phải 3 cạnh của tam giác. 2. Viết chương trình thực hiện các công việc sau: a. Nhập vào một số nguyên n b. Kiểm tra xem có phải n>0 không, nếu đúng thì tính n! và in kết quả ra màn hình, ngược lại thì thông báo ra màn hình n <0. 3.Viết chương trình thực hiện các công việc sau: a. Nhập vào từ bàn phím 2 số thực a, b và một ký tự là một phép toán (pheptoan) b. Kiểm tra phép toán nhập vào có phải là một trong các phép toán: +, -, *, / không. Nếu đúng tính giá trị của biểu thức a pheptoan b (ví dụ phép toán là + thì tính a+b) và hiển thị kết quả ra màn hình ngược lại thông báo lỗi (chú ý yêu cầu kiểm soát cả lỗi chia cho 0). 4.Viết chương trình thực hiện các công việc sau: a. Nhập vào từ bàn phím 2 số nguyên là tử số và mẫu số của một phân số. b. Thực hiện tính toán để tìm phân số tối giản của phân số đã nhập và in kết quả ra màn hình. 5. Viết chương trình thực hiện các công việc sau: a. Nhập vào từ bàn phím 2 số nguyên a và b. b. Tìm nghiệm của phương trình bậc nhất ax+b=0 và in kết quả ra màn hình 43
  55. 6. Viết chương trình thực hiện các công việc sau: a. Nhập vào từ bàn phím 3 số nguyên a, b và c. b. Tìm nghiệm của phương trình bậc hai ax2+bx +c=0 và in kết quả ra màn hình 7. Viết chương trình thực hiện các công việc sau: a. Nhập vào từ bàn phím một số nguyên dương n. b. Tính tổng s = 1/2+1/4+ +1/2*n và in kết quả s ra màn hình. 8. Viết chương trình thực hiện các công việc sau: a. Nhập vào từ bàn phím một số nguyên dương n. b. Tính tổng s = 1+1/3+ +1/(2*n+1) và in kết quả s ra màn hình. 9. Viết chương trình thực hiện các công việc sau: a. Nhập vào từ bàn phím một số nguyên dương n. b. Tính tổng s = 1+1/2-1/3+ +(-1)n*1/n và in kết quả s ra màn hình. 10. Viết chương trình thực hiện các công việc sau: a. Nhập vào từ bàn phím một số nguyên n (0<n<100) và một mảng gồm n số nguyên. b. Hiển thị mảng đã nhập ra màn hình c. Tìm phần tử lớn nhất trong mảng và in vị trí của phần tử đó ra màn hình. d. Sắp xếp mảng theo thứ tự tăng dần rồi in mảng sau sắp xếp ra màn hình. 11. Viết chương trình thực hiện các công việc sau: a. Nhập vào từ bàn phím một số nguyên n (0<n<100) và một mảng gồm n số nguyên. b. Hiển thị mảng đã nhập ra màn hình c. Tìm phần tử lớn nhất trong mảng và in vị trí của phần tử đó ra màn hình. d. Sắp xếp mảng theo thứ tự giảm dần rồi in mảng sau sắp xếp ra màn hình. 44
  56. CHƢƠNG 2: LẬP TRÌNH HƢỚNG ĐỐI TƢỢNG TRONG JAVA 2.1. Giới thiệu về lập trình hƣớng đối tƣợng Lập trình hướng đối tượng (OOP) là một phương pháp thiết kế và phát triển phần mềm. Những ngôn ngữ OOP không chỉ bao gồm cú pháp và một trình biên dịch (compiler) mà còn có một môi trường phát triển toàn diện. Môi trường này bao gồm một thư viện được thiết kế tốt, thuận lợi cho việc sử dụng các đối tượng. Đối với một ngôn ngữ lập trình hỗ trợ OOP thì việc triển khai kỹ thuật lập trình hướng đối tượng sẽ dễ dàng hơn. Kỹ thuật lập trình hướng đối tượng cải tiến việc phát triển các hệ thống phần mềm. Kỹ thuật ấy đề cao nhân tố chức năng (functionality) và các mối quan hệ dữ liệu. OOP là phương thức tư duy mới để giải quyết vấn đề bằng máy tính. Để đạt kết quả, lập trình viên phải nắm vấn đề thành một thực thể quen thuộc với máy tính. Cách tiếp cận hướng đối tượng cung cấp một giải pháp toàn vẹn để giải quyết vấn đề. Hãy xem xét một tình huống cần được triển khai thành một hệ thống trên máy vi tính: việc mua bán xe hơi. Vấn đề vi tính hóa việc mua bán xe hơi bao gồm những gì? Những yếu tố rõ ràng nhất liên quan đến việc mua bán xe hơi là: 1) Các kiểu xe hơi (model). 2) Nhân viên bán hàng. 3) Khách hàng. Những hoạt động liên quan đến việc mua bán: 1) Nhân viên bán hàng đưa khách hàng tham quan phòng trưng bày. 2) Khách hàng chọn lựa một xe hơi. 3) Khách hàng đặt hóa đơn. 4) Khách hàng trả tiền. 5) Chiếc xe được trao cho khách hàng. Mỗi vấn đề được chia ra thành nhiều yếu tố, được gọi là các Đối tượng (Objects) hoặc các Thực thể (Entities). Chẳng hạn như ở ví dụ trên, khách hàng, xe hơi và nhân viên bán hàng là những đối tượng hoặc thực thể. Lập trình viên luôn luôn cố gắng tạo ra những kịch bản (scenarios) thật quen thuộc với những tình huống thực tiễn. Bước thứ nhất trong phương pháp này là làm cho máy tính liên kết với những đối tượng thế giới thực. Tuy nhiên, máy tính chỉ là một cỗ máy. Nó chỉ thực hiện những công việc được lập trình mà thôi. Vì thế, trách nhiệm của lập trình viên là cung cấp cho máy tính những thông tin theo cách thức mà nó cũng nhận thức được cùng những thực thể như chúng ta nhận thức. 45
  57. Đó chính là vai trò của kỹ thuật hướng đối tượng. Chúng ta sử dụng kỹ thuật hướng đối tượng để ánh xạ những thực thể chúng ta gặp phải trong đời sống thực thành những thực thể tương tự trong máy tính. Phát triển phần mềm theo kỹ thuật lập trình hướng đối tượng có khả năng giảm thiểu sự lẫn lộn thường xảy ra giữa hệ thống và lĩnh vực ứng dụng. Lập trình hướng đối tượng đề cập đến dữ liệu và thủ tục xử lý dữ liệu theo quan điểm là một đối tượng duy nhất. Lập trình hướng đối tượng xem xét dữ liệu như là một thực thể hay là một đơn vị độc lập, với bản chất riêng và những đặc tính của thực thể ấy. Bây giờ chúng ta hãy khảo sát những thuật ngữ „đối tượng‟ (object), „dữ liệu‟ (data) và „phương thức‟ (method). Có nhiều loại đối tượng khác nhau. Chúng ta có thể xem các bộ phận khác nhau trong một cơ quan là các đối tượng. Điển hình là một cơ quan có những bộ phận liên quan đến việc quản trị, đến việc kinh doanh, đến việc kế toán, đến việc tiếp thị Mỗi bộ phận có nhân sự riêng, các nhân sự được giao cho những trách nhiệm rõ ràng. Mỗi bộ phận cũng có những dữ liệu riêng chẳng hạn như thông tin cá nhân, bảng kiểm kê, những thể thức kinh doanh, hoặc bất kỳ dữ liệu nào liên quan đến chức năng của bộ phận đó. Rõ ràng là một cơ quan được chia thành nhiều bộ phận thì việc quản trị nhân sự và những hoạt động doanh nghiệp dễ dàng hơn. Nhân sự của cơ quan điều khiển và xử lý dữ liệu liên quan đến bộ phận của mình. Chẳng hạn như bộ phận kế toán chịu trách nhiệm về lương đối với cơ quan. Nếu một người ở đơn vị tiếp thị cần những chi tiết liên quan đến lương của đơn vị mình, người ấy chỉ cần liên hệ với bộ phận kế toán. Một người có thẩm quyền trong bộ phận kế toán sẽ cung cấp thông tin cần biết, nếu như thông tin ấy có thể chia sẻ được. Một người không có thẩm quyền từ một bộ phận khác thì không thể truy cập dữ liệu, hoặc không thể thay đổi làm hư hỏng dữ liệu. Ví dụ này minh chứng rằng các đối tượng là hữu dụng trong việc phân cấp và tổ chức dữ liệu. Khái niệm về đối tượng có thể được mở rộng đến hầu hết các lãnh vực đời sống, và hơn nữa, đến thế giới lập trình. Bất kỳ ứng dụng nào đều có thể được định nghĩa theo thuật ngữ thực thể hoặc đối tượng để tạo ra tiến trình xử lý mô phỏng theo tiến trình xử lý mà con người nghĩ ra. Phương pháp giải quyết „top-down‟ (từ trên xuống) cũng còn được gọi là „lập trình hướng cấu trúc‟ (structured programming). Nó xác định những chức năng chính của một chương trình và những chức năng này được phân thành những đơn vị nhỏ hơn cho đến mức độ thấp nhất. Bằng kỹ thuật này, các chương trình được cấu trúc theo hệ thống phân cấp các module. Mỗi một module có một đầu vào riêng và một đầu ra 46
  58. riêng. Trong mỗi module, sự điều khiển có chiều hướng đi xuống theo cấu trúc chứ không có chiều hướng đi lên. Phương pháp OOP cố gắng quản lý việc thừa kế phức tạp trong những vấn đề thực tế. Để làm được việc này, phương pháp OOP che giấu một vài thông tin bên trong các đối tượng. OOP tập trung trước hết trên dữ liệu. Rồi gắn kết các phương thức thao tác trên dữ liệu, việc này được xem như là phần thừa kế của việc định nghĩa dữ liệu. Bảng 2.1 minh họa sự khác biệt giữa hai phương pháp: Phương pháp Top-Down OOP Chúng ta sẽ xây dựng một khách Chúng ta sẽ xây dựng một tòa nhà 10 tầng sạn. với những dãy phòng trung bình, sang trọng, và một phòng họp lớn. Chúng ta sẽ thiết kế các tầng lầu, các Chúng ta sẽ xây dựng một khách sạn với phòng và phòng họp. những thành phần trên. Bảng 2.1. Một ví dụ về hai phương pháp giải quyết OOP và Structured 2.2. Trừu tƣợng hoá dữ liệu Khi một lập trình viên phải phát triển một chương trình ứng dụng thì không có nghĩa là người ấy lập tức viết mã cho ứng dụng ấy. Trước hết, người ấy phải nghiên cứu ứng dụng và xác định những thành phần tạo nên ứng dụng. Kế tiếp, người ấy phải xác định những thông tin cần thiết về mỗi thành phần. Hãy khảo sát chương trình ứng dụng cho việc mua bán xe hơi nói trên. Chương trình phải xuất hóa đơn cho những xe hơi đã bán cho khách hàng. Để xuất một hóa đơn, chúng ta cần những thông tin chi tiết về khách hàng. Vậy bước thứ nhất là xác định những đặc tính của khách hàng. Một vài đặc tính gắn kết với khách hàng là:  Tên.  Địa chỉ.  Tuổi.  Chiều cao.  Màu tóc. Từ danh sách kể trên, chúng ta xác định những đặc tính thiết yếu đối với ứng dụng. Bởi vì chúng ta đang đề cập đến những khách hàng mua xe, vì thế những chi tiết thiết yếu là:  Tên.  Địa chỉ. 47
  59. Còn những chi tiết khác (chiều cao, màu tóc ) là không quan trọng đối với ứng dụng. Tuy nhiên, nếu chúng ta phát triển một ứng dụng hỗ trợ cho việc điều tra tội phạm thì những thông tin chẳng hạn như màu tóc là thiết yếu. Bên cạnh những chi tiết về khách hàng, những thông tin sau cũng cần thiết:  Kiểu xe được bán.  Nhân viên nào bán xe. Bên cạnh những đặc tính của khách hàng, xe hơi và nhân viên bán hàng, chúng ta cũng cần liệt kê những hành động được thực hiện. Công việc xuất hóa đơn đòi hỏi những hành động sau:  Nhập tên của khách hàng.  Nhập địa chỉ của khách hàng.  Nhập kiểu xe.  Nhập tên của nhân viên bán xe.  Xuất hóa đơn với định dạng đòi hỏi. Khung thông tin bên dưới cho thấy những thuộc tính và những hành động liên quan đến một hóa đơn: Các thuộc tính Tên của khách hàng Địa chỉ của khách hàng Kiểu xe bán Nhân viên bán xe Các hành động Nhập tên Nhập địa chỉ Nhập kiểu xe Nhập tên nhân viên bán xe Xuất hóa đơn Định nghĩa 48
  60. Sự trừu tƣợng hóa dữ liệu là quá trình xác định và nhóm các thuộc tính và các hành động liên quan đến một thực thể cụ thể, xét trong mối tương quan với ứng dụng đang phát triển. Tiếp theo, chúng ta muốn ứng dụng tính toán tiền hoa hồng cho nhân viên bán hàng. Những thuộc tính liên kết với nhân viên bán hàng có tương quan với ứng dụng này là:  Tên.  Số lượng xe bán được.  Tiền hoa hồng. Những hành động đòi buộc đối với công việc này là:  Nhập tên nhân viên bán xe.  Nhập số lượng xe bán được.  Tính tiền hoa hồng kiếm được. Những thuộc tính Tên Số lượng xe bán được Tiền hoa hồng Những hành động Nhập tên Nhập số lượng xe bán được Tính tiền hoa hồng Như thế, việc trừu tượng hóa dữ liệu tra đặt ra câu hỏi „Đâu là những thuộc tính và những hành động cần thiết cho một vấn đề đặt ra?‟ Những ƣu điểm của việc trừu tƣợng hóa Những ưu điểm của việc trừu tượng hóa là:  Tập trung vào vấn đề.  Xác định những đặc tính thiết yếu và những hành động cần thiết.  Giảm thiểu những chi tiết không cần thiết. 49
  61. Việc trừu tượng hóa dữ liệu là cần thiết, bởi vì không thể mô phỏng tất cả các hành động và các thuộc tính của một thực thể. Vấn đề màu chốt là tập trung đến những hành vi cốt yếu và áp dụng chúng trong ứng dụng. Chẳng hạn như khách hàng hoặc nhân viên bán hàng cũng có thể thực hiện những hành động sau:  Người ấy đi lại.  Người ấy nói chuyện. Tuy nhiên, những hành động này không liên quan đến ứng dụng. Việc trừu tượng hóa dữ liệu sẽ loại bỏ chúng. 2.3. Lớp và định nghĩa lớp trong Java Lớp được xem là một khuôn mẫu (template) của đối tượng. Lớp bao gồm các vùng dữ liệu của đối tượng và các phương thức tác động lên các dữ liệu đó. Lớp có tính kế thừa (inheritance); một lớp (subclass) có thể thứa kế tất cả các vùng dữ liệu và các phương thức của một lớp khác (superclass). Lớp còn có tính đa hình (polymorphism) cho phép cài đặt các lớp dẫn xuất rất khác nhau từ cùng một lớp nguồn. Bạn còn có thể định nghĩa một lớp bên trong một lớp khác. Đây là lớp xếp lồng nhau, các thể hiện (instance) của lớp này tồn tại bên trong thể hiện của một lớp che phủ chúng. Nó chi phối việc truy nhập đến các thành phần của thể hiện bao phủ chúng. Định nghĩa lớp: Một lớp được định nghĩa theo dạng sau: [ ] [ ] class [extends ] [implements ] { } Trong đó: - Phần đầu của lớp là phần khai báo cho một lớp bao gồm: + dùng để thiết lập mức truy xuất cho lớp, trong Java có nhiều mức truy xuất khác nhau như public, private , là một thành phần lựa chọn có thể khai báo hoặc không, trong trường hợp không khai báo cụ thể thì lớp sẽ được gán mức truy xuất mặc định. 50
  62. + là dùng để khai báo một số chức năng cho lớp như lớp tượng abstract, hay lớp hoàn tất việc cài đặt cho một lớp đã có Final. là một thành phần lựa chọn có thể khai báo hoặc không. + class là từ khóa bắt buộc + là tên của một lớp cần tạo, tên lớp phải được đặt là một tên chuẩn như đã trình bày ở trên. + extends dùng để khai báo lớp là được kế thừa từ một lớp cha. + implements ] dùng để khai báo khi muốn lớp là một thể hiện từ một lớp nào đó. - Phần thân của lớp nằm trong cặp ngoặc nhọn “{}”, trong đó là dùng để định nghĩa các thành phần như: Các trường, các phương thức của lớp đó. Các thuộc tính Các thuộc tính (properties) hãy các vùng dữ liệu của lớp (field) bản chất chúng là các biến được khai báo ở mức lớp, các thuộc tính được khai báo theo cú pháp sau: [ ] [=value]; Trong đó: - Access Modifier dùng để khai báo giới hạn phạm vi của thuộc tính, có 3 dạng giới hạn phạm vi cho thuộc tính là :public, private và protected. Thành phần này là một lựa chọn có thể khai báo hoặc không. - Datatype là kiểu dữ liệu của thuộc tính - identifier là tên của thuộc tính, phải được đặt theo quy định về tên của java - value là giá trị khởi tạo cho thuộc tính, thành phần này là một lựa chọn có thể có hoặc không. Phƣơng thức Phương thức được định nghĩa như một hành động hoặc một tác vụ thật sự của đối tượng. Nó còn được định nghĩa như một hành vi mà trên đó các thao tác cần thiết được thực thi. Trong mỗi lớp có thể định nghĩa phương thức theo cú pháp như sau: [ ] [ ] ([ ]) { 51
  63. //body of method } Trong đó: - Access Modifier dùng để khai báo giới hạn phạm vi của thuộc tính, có 3 dạng giới hạn phạm vi cho thuộc tính là : public, private và protected. Thành phần này là một lựa chọn có thể khai báo hoặc không. - None Access Modifier: cho phép thiết lập các thuộc tính của phương thức. Java cung cấp các bổ nghĩa sau: static, abstract, final, native, synchronized, volatile. - datatype: Kiểu dữ liệu mà phương thức trả về. Nếu không có một giá trị nào được trả về, kiểu dữ liệu có thể là void. - method_name: Tên của phương thức - parameter_list: Chứa tên của tham số được sử dụng trong phương thức và kiểu dữ liệu. Dấu phẩy được dùng để phân cách các tham số. - Thân của phương thức nằm trong cặp dấu ngoặc nhọn “{}” là nơi viết đoạn mã chương trình xử lý của phương thức đó. Đoạn mã sau đây định nghĩa lớp Temp chứa một giá trị nguyên (int). Lớp này chứa hai phương thức là: show() và main(). Cả hai phương thức đều có khả năng truy cập bên ngoài lớp khi chúng được khai báo như public. Nếu chúng không trả về một giá trị nào, kiểu dữ liệu trả về được định nghĩa như kiểu void. Phương thức show() hiển thị một giá trị của biến x. Ở phương thức main(), hai thí dụ của đối tượng thuộc lớp Temp được khai báo. Đối tượng thứ nhất gồm giá trị mặc định của biến x. Nó được hiển thị ngay khi gọi phương thức show() lần đầu tiên. Giá trị của xđược thay đổi dùng cho đối tượng thứ hai. Nó được hiển thị khi ta gọi phương thức show() lần thứ hai. Ví dụ 2.1: Định nghĩa lớp Temp chứa hai phương thức là: show() và main() class Temp { static int x=10;//variable public static void show()//method { System.out.println(x);} public static void main(String args[]) { Temp t = new Temp();// object 1 t.show();//method call Temp t1=new Temp();// object 2 52
  64. t1.x=20; t1.show(); } } Các chỉ định truy xuất(Access Modifier) Các chỉ định truy xuất dùng để giới hạn khả năng truy nhập vào một phương thức, một thuộc tính hoặc một lớp đối tượng. Java cung cấp các chỉ định truy xuất sau đây:  Công cộng (Public): Chỉ định truy xuất public có thể được nhìn thấy từ mọi gói hoặc mọi lớp.  Bảo vệ (Protected): Các lớp mở rộng từ lớp hiện hành trong cùng một gói, hoặc tại các gói khác nhau có thể truy cập các phương thức, thuộc tính loại này.  Riêng tư (Private): Phương thức, thuộc tính riêng tư chỉ có thể được truy cập trực tiếp từ một phương thức trong cùng lớp hoặc truy cập gián tiếp qua phương thức công cộng trong cùng một lớp. Các bổ nghĩa phƣơng thức (None Access Modifier) Các bổ nghĩa phương thức cho phép ta thiết lập các thuộc tính của phương thức. Java cung cấp các bổ nghĩa sau:  Tĩnh (static): phương thức có thể được gọi mà không cần đến đối tượng. Nó chỉ được sử dụng đối với các dữ liệu và các phương thức tĩnh khác.  Trừu tƣợng (abstract): Ngụ ý rằng phương thức không có một mã (code) và nó sẽ được bổ sung ở các lớp con (subclass). Loại phương thức này được sử dụng trong các lớp kế thừa.  Kết thúc (final): Phương thức không thể được thừa kế hoặc ghi đè (Overridden).  Tự nhiên (native): Chỉ ra rằng phần thân của phương thức được viết trên các ngôn ngữ khác Java ví dụ C, hoặc C++.  Đồng bộ (synchronized): Sử dụng với phương thức trong quá trình thực thi threads. Nó cho phép chỉ một thread được truy cập vào khối mã tại một thời điểm.  Linh hoạt (volatile): Được sử dụng với các biến để thông báo rằng giá trị của biến có thể được thay đổi vài lần khi thực thi chương trình và giá trị của nó không được đặt vào thanh ghi. Bảng dưới đây chỉ ra nơi mà các bổ nghĩa được sử dụng: 53
  65. Bổ nghĩa Phƣơng thức Biến Lớp public Yes Yes Yes private Yes Yes Yes (Nested class) protected Yes Yes Yes (Nested class) abstract Yes No Yes final Yes Yes Yes native Yes No No volatile No Yes No Bảng 2.2. Sử dụng các bổ nghĩa Từ khóa this Thông thường bên trong thân của một phương thức ta có thể tham chiếu đến các thuộc tính của đối tượng đó, tuy nhiên trong một số tình huống đặc biệt như tên của tham số trùng với tên của thuộc tính, lúc đó để chỉ các thành viên của đối tượng đó ta dùng từ khoá this, từ khoá this dùng để chỉ đối tượng này. Ví dụ2.2: sau chỉ ra cho ta thấy trong tình huống này bắt buộc phải dùng từ khoá this vì tên tham số của phương thức tạo dựng lại trùng với tên của thuộc tính class HSBColor { int hue, saturation, brightness; HSBColor (int hue, int saturation, int brightness) { this.hue = hue; this.saturation = saturation; this.brightness = brightness; } } Ở ví dụ trên có các biên hue, saturation, brightness trung tên vì vậy để phân biệt chúng là thuộc tính hay tham số thì ta phải dùng từ khóa this. Getter và setter 54
  66. Trong Java cũng như các ngôn ngữ lập trình hướng đối tượng khác thường thì các thuộc tính không được thiết lập ở chế độ truy cập public vì làm như vậy sẽ làm mất tính bao đóng của các lớp đối tượng và khả năng proteced sẽ bị hạn chế. Chính vì vậy thông thường các thuộc tính được khai báo là private. Tuy nhiên điều này làm cho việc lấy giá trị, cũng như thiết lập các giá trị cho thuộc tính không thể được thực hiện từ các lớp khác ngoài nó. Để giải quyết vấn đề này chúng ta dùng các phương thức getter và setter gọi là các phương thức truy cập. Các phương thức truy cập là các phương thức giống như những phương thức khác nhưng chúng thường tuân thủ theo một quy ước đặt tên riêng. Để cung cấp giá trị một biến cá thể cho đối tượng khác, hãy tạo ra một phương thức có tên là getVariableName(). Tương tự như thế, để cho phép các đối tượng khác thiết đặt các biến cá thể của đối tượng của bạn, hãy tạo ra phương thức setVariableName(). Trong cộng đồng Java, các phương thức truy cập này thường được gọi là các getter và các setter vì tên chúng bắt đầu bằng get và set. Đây là một số đặc tính chung của các getter và setter: - Định tố truy cập của các getter và setter điển hình là public. - Các getter điển hình là không nhận tham số nào. - Các setter điển hình là chỉ nhận một tham số, đó là giá trị mới cho biến cá thể mà chúng thiết đặt. - Kiểu trả về của getter điển hình là cùng kiểu với biến cá thể mà nó báo lại giá trị. - Kiểu trả lại của setter điển hình là void, nghĩa là chúng không trả lại gì hết (chúng chỉ đặt giá trị cho biến cá thể). Ví dụ 2.3:Định nghĩa một lớp học sinh và xây dựng các phương thức getter và setter để truy cập vào các thuộc tính của lớp này. class HocSinh { private String hoTen; private String lop; private float diemTb; public void setHoTen(String hoTen1) { //hoTen1 là biến cục bộ nhập vào, thường để trùng tên thuộc tính như các hàm setter phía dưới this.hoTen = hoTen1; } public void setLop(String lop) { this.lop = lop; 55
  67. } public String getHoTen() { return hoTen; } public String getLop() { return lop; } public float getDiemTb() { return diemTb; } public void setDiemTb(float diemTb) { this.diemTb = diemTb; } } public class JavaDemo{ public static void main(String[] args) { HocSinh a = new HocSinh(); a.setHoTen("Vu Van T"); a.setLop("At7a"); a.setDiemTb(7.5f); System.out.println("Họ tên: " + a.getHoTen()); System.out.println("Lớp: " + a.getLop()); System.out.println("Điểm Tb: " + a.getDiemTb()); } } Supper Khi một lớp được kế thừa từ lớp cha trong cả lớp cha và lớp con đều có mô phương thức trùng tên nhau, thế thì làm thế nào có thể gọi phương thức trùng tênđó của lớp cha, java cung cấp cho ta từ khoá Super dùng để chỉ đối tượng của lớpcha ví dụ 2.4:Xây dựng 2 lớp, một lớp cha và một lớp con có cùng một phương thức và sử dụng Supper để phân biệt giữa các phương thứ này. class ASillyClass { boolean aVariable; void aMethod() { aVariable = true; } } 56
  68. class ASillierClass extends ASillyClass { boolean aVariable; void aMethod() { aVariable = false; super.aMethod(); System.out.println(aVariable); System.out.println(super.aVariable); } } trong ví dụ trên ta thấy trong lớp cha có phương thức tên là aMethod trong lớp concũng có một phương thức cùng tên, ta còn thấy cả hai lớp này cùng có một thuộc tính tên aVariable để có thể truy cập vào các thành viên của lớp cha ta phải dùngtừ khoá super. Trả về giá trị từ phƣơng thức Khai báo kiểu giá trị trả về từ lúc khai báo phương thức, bên trongthân của phương thức ta phải sử dụng phát biểu return value; để trả về kết quả,nếu hàm được khai báo kiểu void thì ta chỉ sử dụng phát biểu return; mệnh đềreturn đôi khi còn được dùng để kết thúc một phương thức. Truyền tham số cho phương thức Khi ta viết các phương thức, một số phương thức yêu cầu phải có một sốtham số, các tham số của một phương thức được khai báo trong lời khai báophương thức, chúng phải được khai báo chi tiết có bao nhiêu tham số, mỗi tham sốcần phải cung cấp cho chúng một cái tên và kiểu dữ liệu của chúng. Ví dụ 2.5: Tạo một phương thức dùng để tính tổng của hai số, phương thức này được khai báo như sau: public double tongHaiSo(double a, double b){ return (a + b); } Truyền theo tham trị Khi gọi một phương thức mà tham số của phương thức có kiểu nguyênthủy, thì bản sao giá trị của tham số thực sự sẽ được chuyển đến phương thức, đâylà đặc tính 57
  69. truyền theo trị ( pass- by – value ), nghĩa là phương thức không thể thayđổi giá trị của các tham số truyền vào. Ví dụ 2.6: Truyền theo tham trị public class TestPassByValue { public static void test(int t) { t++; System.out.println("Gia tri cua cac bien trong ham sau khi tang len 1 la " + t); } public static void main(String[] args) { int t = 10; System.out.println("Gia tri cua t truockhi goi ham = " + t); test(t); System.out.println("Gia tri cua t sau khi goi ham = " + t); } } ta se nhận được kết quả ra như sau: Gia tri của t truoc khi gọi ham = 10 Gia tri của t bên trong ham sau khi tang len 1 la 11 Gia tri của t sau khi gọi ham = 10 Như vậy giá trị của t trước và sau khi gọi là như nhau, mặc dù ta đã thay đổi giá trị của t trong chương trình nhưng khi thoát khỏi chương trình giá trị của t không thay đổi Truyền theo tham biến Trong Java không hỗ trợ việc truyền tham biến cho các tham số thuộc các kiểu dữ liệu nguyên thủy. Để truyền theo tham biến thì tham số phải thuộc về một kiểu dữ liệu tham chiếu nào đó như mảng, đối tượng Ví dụ 2.7: Sẽ truyền theo tham biến cho tham số là một mảng package example; publicclass Start { publicstaticvoid example(int m[], int n) { for(int i = 0; i < 10; ++i) { 58
  70. m[i] = 1; } n = n + 1; } Publicstaticvoid main(String[] args) { int n = 10; int m[] = newint[10]; for(int i = 0; i < 10; ++i){ m[i] = i; } example(m, n); System.out.print(“n = ” + n +”\n”); for(int i = 0; i < 10; ++i){ System.out.print(“m[" + i + "] = ” + m[i] + “\n”); } } } Kết quả như sau: n = 10 m[0] = 1 m[1] = 1 m[2] = 1 m[3] = 1 m[4] = 1 m[5] = 1 m[6] = 1 m[7] = 1 m[8] = 1 m[9] = 1 59
  71. Qua kết quả cho thấy giá trị của các phần tử của mảng đã bị thay đổi sau khi ta thay đổi trong phương thức example(m, n) Nạp chồng (overloading) và ghi đè (overriding) phƣơng thức Những phương thức được nạp chồng (overload) là những phương thức trong cùng một lớp, có cùng một tên song có danh sách các tham số khác nhau. Sử dụng việc nạp chồng phương thức để thực thi các phương thức giống nhau đối với các kiểu dữ liệu khác nhau.Ví dụ phương thức swap() có thể bị nạp chồng (overload) bởi các tham số của kiểu dữ liệu khác nhưinteger, double và float Phương thức được ghi đè (overriden) là phương thức có mặt ở lớp cha (superclass) cũng như ở các lớp kế thừa. Phương thức này cho phép một lớp tổng quát chỉ định các phương thức sẽ là phương thức chung trong các lớp con.Ví dụ lớp xác định phương thức tổng quát „area()‟. Phương thức này có thể được hiện thực trong một lớp con để tìm diện tích một hình cụ thể như hình chữ nhật, hình vuông Phương thức nạp chồng là một hình thức đa hình (polymorphism) trong quá trình biên dịch (compiler). Còn phương thức ghi đè là một hình thức đa hình trong quá trình thực thi (runtime). Đoạn chương trình sau mô tả nạp chồng phương thức được thực hiện như thế nào //defined once protected void perfomTask(double salary){ . System.out.prinln(“Salary is : ” + salary); . } //overloaded –defined the second time with different parameters protected void performTask(double salary, int bonus){ System.out.println(“Total Salary is: ” + salary+bonus); . } Phương thức khởi tạo (Contructor) của lớp có thể bị nạp chồng (overload) 60
  72. Phương thức ghi đè (Overriden) được định nghĩa lại ở các lớp con. Đoạn mã sau đây mô tả phương thức ghi đè. Ở đây ta dùng từ khoá “this” biểu thị đối tượng hiện hành, trong khi đó „super‟ được sử dụng để chỉ đối tượng lớp cha. Phương thức ghi đè không phải là phương thức tĩnh (static). Nó là loại non-static. Các đoạn mã sau đây mô tả việc thực thi ghi đè phương thức trong Java. class SupperClass // Tạo lớp cơ bản { int a; SupperClass() // constuctor { } SupperClass(int b) //overloaded constructor { a=b; } public void message() { System.out.println("In the super class"); } } class SubClass Extends SupperClass {// derriving a class int a; SubClass(int a){//subclass constructor this.a; } public void message(){ // overiding the base class message() System.out.prinln(“In the sub class”); } } Bây giờ tạo ra một đối tượng lớp cha và gán một lớp nhỏ tham chiếu đến nó như sau: SuperClasss spObj=new SubClass(22); Câu lệnh „spObj.message()‟ thuộc phương thức lớp của SubClass.Ở đây kiểu đối tượng được gán cho „spObj‟ sẽ chỉ được xác định khi chương trình thực thi. Điều này được biết dưới khái niệm „liên kết động‟ (dynamic binding). 61
  73. 2.4. Đối tƣợng Như đã biết một lớp đối tượng được xây dựng từ một tập các đối tượng có cùng chung thuộc tính và phương thức hay lớp đối tượng một thiết kế của các đối tượng, vì vậy về cơ bản một đối tượng được tạo ra từ một lớp đối tượng. Ta có thể tạo được những đối tượng của lớp này bằng câu lệnh: ClassName ObjectName = new ClassName(); Trong đó: - ClassName tên của lớp đối tượng - ObjectName tên của đối tượng muốn tạo - new từ khóa dùng để tạo đối tượng - ClassName() hàm tạo của lớp đối tượng đó Như vậy trong khai báo trên thấy rằng tạo một đối tượng gồm 3 phần - Phần khai báo (Declaration): phần này khai báo một biến tham chiếu kiểu đối tượng. Cũng có thể tách riêng phần này để tạo ra các biến tham chiếu kiểu đối tượng như sau: ClassName ObjectName1, ObjectName2, ; Trong đó ObjectName1,ObjectName2 là tên của các biến đối tượng muốn tạo từ lớp đối tượng ClassName. - Phần tạo (Instantiation): Sử dụng từ khóa newlà một phép toán trong Java để tạo ra đối tượng. - Phần khởi tạo (Initialization):Phép toán new cho phép gọi đến một hàm tạo để khởi tạo giá trị cho một đối tượng. Phần tạo và khởi tạo cũng có thể tách riêng để tạo các đối tượng như sau: ObjectName = new ClassName(); Ví dụ 2.8:Tạo ra một lớp Point và tạo ra một đối tượng từ lớp đó public class Point { public int x = 0; public int y = 0; public Point(int a, int b) { x = a; y = b; 62
  74. } } Tạo một đối tượng point1 từ lớp Point như sau Point point1 = new Point(23,34); Hoặc Point point1; Point1 = new Point(23,34); 2.5. Thiết lập và hủy 2.5.1. Thiết lập Phương thức tạo dựng là một phương thức của lớp 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ựchiệ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. Đặc điểm của phƣơng thức tạo (Construtor)  Hàm tạo có tên trùng với tên của lớp  Phương thức tạo không bao giờ trả về kết quả  Phương thức tạo được java gọi tự động khi một đối tượng của lớp được tạo ra  Phương thức 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 phương thức Ví dụ 2.9: Tạomột lớp phép tính và sử dụng 2 hàm tạo public class PhepTinh { private int ToanHang1; private int ToanHang2; private char ToanTu; public void setToanHang1(int ToanHang1) { this.ToanHang1 = ToanHang1; } public void setToanHang2(int ToanHang2) { this.ToanHang2 = ToanHang2; } 63
  75. public void setToanTu(char ToanTu) { this.ToanTu = ToanTu; } public int getToanHang1() { return ToanHang1; } public int getToanHang2() { return ToanHang2; } public char getToanTu() { return ToanTu; } public PhepTinh() { this.ToanHang1=0; this.ToanHang2=0; this.ToanTu='+'; } public PhepTinh(int ToanHang1, int ToanHang2, char ToanTu) { this.ToanHang1 = ToanHang1; this.ToanHang2 = ToanHang2; this.ToanTu = ToanTu; } public double TinhToan() { double giatri; switch(ToanTu) { case '+': giatri = ToanHang1 + ToanHang2 ; break; 64
  76. case '-': giatri = ToanHang1 - ToanHang2 ; break; case '*': giatri = ToanHang1 * ToanHang2 ; break; default: giatri = (double)ToanHang1 / ToanHang2 ; break; } return giatri; } } Bây giờ tạo ra 2 đối tượng như sau: PhepTinh pt1 = new PhepTinh(); double a = pt1.TinhToan(); PhepTinh pt2 = new PhepTinh(7,6,‟-‟); double b = pt2.TinhToan(); System.out.print(“a =” + a + “b=” +b); Chạy chương trình cho kết quả là: a=0 b=1 Hàm tạo mặc định (default constructor) Nếu như trong class không có hàm khởi tạo thì máy ảo java sẽ làm nhiệm vụ gọi ra một default constructor để tạo ra một đối tượng thể hiện của class. Hàm tạo 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ạora. 2.5.2. Hủy Java không có phương thức hủy bỏ. Phương thức finalize tương tự nhưphương thức hủy bỏ của C++, tuy nhiên nó không phải là phương thức hủy bỏ. Sởdĩ nó không phải là phương thức hủy bỏ vì khi đối tượng được hủy bỏ thì phươngthức này chưa chắc đã được gọi đến. Phương thức này được gọi đến chỉ khi bộ thurác của Java được 65
  77. khởi động và lúc đó đối tượng không còn được sử dụng nữa. Dovậy phương thức finalize có thể không được gọi đến Người lập trình C++ thường sử dụng toán tử new để cấp phát động một đốitượng, nhưng lại thường quên gọi toán tử delete để giải phóng vùng nhớ này khikhông còn dùng đến nữa, điều này làm rò rỉ bộ nhớ đôi khi dẫn đến chương trìnhphải kết thúc một cách bất thường, quả thật đâu là một điều tồi tệ. Trong java takhông cần quan tâm đến điều đó, java có một cơ chế thu rác tự động, nó đủ thôngminh để biết đối tượng nào không dùng nữa, rồi nó tự động thu hồi vùngnhớ dành cho đối tượng đó. Trong ngôn ngữ C++ khi một đối tượng bị hủy, sẽ có một hàm đượcgọi tự động, hàm này được gọi là huy tử hay còn gọi là hàm huy, thông thườnghàm hủy mặc định là đủ để dọn dẹp, tuy nhiên trong một số trường hợpthì hàm hủy mặc định lại không thể đáp ứng được, do vậy người lập trình C++,phải viết ra hàm hủy riêng để làm việc đó, tuy nhiên java lại không có khái niệmhàm hủy. 2.6. Các đặc tính của lớp 2.6.1. Tính bền vững Cơchế đóng gói trong lập trình hướng đối tượng giúp chocác đối tượng dấu đi một phần các chi tiết cài đặt, cũng nhưphần dữ liệu cục bộ của nó, và chỉ công bố ra ngoài những gìcần công bố để trao đổi với các đối tượng khác. Hay có thể nói đối tượng là một thành tố hỗ trợ tính đóng gói. Đơn vị đóng gói cơ bản của ngôn ngữ java là class. Mộtclass định nghĩa hình thức của một đối tượng. Một class định rõnhững thành phần dữ liệu và các đoạn mã cài đặt các thao tácxử lý trên các đối tượng dữ liệu đó. Java dùng class để xâydựng những đối tượng. Những đối tượng là những thể hiện(instances) của một class. Một lớp bao gồm thành phần dữ liệu và thành phần xử lý.Thành phần dữ liệu của một lớp thường bao gồm các biến thànhviên và các biến thể hiện của lớp. Thành phần xử lý là các thaotác trên các thành phần dữ liệu, thường trong java người gọi làphương thức. Ví dụ 2.10: Tạo ra một lớp mà các thuộc tính của nó là private, nghĩa là các thuộc tính không thể được truy xuất trực tiếp từ bất kỳ đối tượng nào thuộc các lớp nằm ngoài nó. public class EncapTest{ private String name; private String idNum; private int age; 66