MỤC LỤC

MỤC LỤC........................................................................................................................................1 Đề tài 0. Giới thiệu về Java..............................................................................................................6 I. Lịch sử hình thành và phát triển ngôn ngữ lập trình Java.........................................................6 I.1. Giới thiệu về Java...............................................................................................................6 I.2 Tóm tắt lịch sử hình thành của Java ...................................................................................6 II. Các đặc trưng của Java.............................................................................................................7 II.1. Tính đơn giản....................................................................................................................7 II.2. Tính hướng đối tượng.......................................................................................................7 II.3. Tính phân tán....................................................................................................................7 II.4. Tính mạnh mẽ...................................................................................................................7 II.5. Tính an toàn......................................................................................................................7 II.6. Tính trung lập....................................................................................................................8 II.7. Tính di động......................................................................................................................8 II.8. Tính thông dịch.................................................................................................................9 II.9. Tính thực thi cao...............................................................................................................9 II.10. Tính đa luồng..................................................................................................................9 II.11. Tính động .......................................................................................................................9 III. Các loại ứng dụng của Java....................................................................................................9 IV. Công cụ và môi trường lập trình Java....................................................................................9 V. Cài đặt Java ...........................................................................................................................10 Đề tài 1. Ngôn ngữ mô hình hóa UML..........................................................................................12 I. Xây dựng hệ thống phần mềm theo hướng đối tượng.............................................................12 I.1 Các khái niệm căn bản của công nghệ hướng đối tượng...................................................12 I.2 Quy trình chung phát triển hệ thống phần mềm................................................................13 I.3 Những thách thức của ngành công nghiệp phần mềm hiện nay........................................13 II. Lịch sử phát triển ngôn ngữ mô hình hóa UML....................................................................13 II.1. Tóm tắt lịch sử UML......................................................................................................13 II.2. Khái niệm về UML.........................................................................................................14 II.3 Đặc trưng của UML.........................................................................................................14 III. Ngôn ngữ UML....................................................................................................................15 III.1. Các thành phần của UML..............................................................................................15 III.2. Các hướng nhìn (view)..................................................................................................15 III.3 Ứng dụng UML trong quy trình làm phần mềm............................................................22 IV. Quy trình Rational Unified Process (RUP) phát triển phần mềm dựa trên UML................23 IV.1. Giới thiệu về RUP.........................................................................................................23 IV.2. Các nguyên tắc chính của RUP:....................................................................................23 IV.3. Vòng đời của phần mềm theo quy trình RUP...............................................................23 IV.4. Các công cụ của RUP....................................................................................................25 Bài tập.........................................................................................................................................25 Đề tài 2. Nhập môn Java.................................................................................................................26 I. Viết và thực hiện một chương trình Java ...............................................................................26 I.1 Tìm hiểu mã nguồn một chương trình đơn giản................................................................26 I.2. Thực hiện chương trình Java............................................................................................26 I.3. Một số chú ý khi lập trình Java........................................................................................27

1

I.4. Cấu trúc một chương trình Java.......................................................................................27 II. Các kiểu dữ liệu trong Java....................................................................................................28 II.1 Các kiểu dữ liệu số nguyên..............................................................................................28 II.2 Các kiểu số thực...............................................................................................................29 II.3 Kiểu ký tự (character)......................................................................................................29 II.4 Kiểu logic (boolean)........................................................................................................29 II.5 Kiểu chuỗi........................................................................................................................29 II.6 Chuyển đổi giữa các kiểu số............................................................................................29 III. Khai báo biến và hằng trong Java.........................................................................................30 III.1 Quy tắc đặt tên biến........................................................................................................30 III.2 Khai báo biến..................................................................................................................30 III.3 Biến kiểu mảng...............................................................................................................31 III.4 Hằng số (literal)..............................................................................................................32 III.5 Phạm vi hoạt động của hằng và biến:.............................................................................33 IV. Các toán tử và biểu thức.......................................................................................................33 IV.1 Các toán tử và thứ tự ưu tiên..........................................................................................33 IV.2 Biểu thức........................................................................................................................34 V. Các lệnh điều khiển rẽ nhánh.................................................................................................34 V.1 Lệnh if..............................................................................................................................34 V.2. Lệnh switch …case.........................................................................................................35 VI. Các lệnh lặp..........................................................................................................................36 VI.1. Vòng lặp for...................................................................................................................36 VI.2. Vòng lặp while..............................................................................................................37 VI.3. Vòng lặp do... while......................................................................................................38 VI.4. Phép nhảy......................................................................................................................38 VII. Vào dữ liệu từ bàn phím và xuất dữ liệu ra màn hình.........................................................39 VII.1. Lấy giá trị nhập vào từ bàn phím.................................................................................39 VII.2 Kết xuất dữ liệu ra màn hình........................................................................................40 Bài tập.........................................................................................................................................41 Đề tài 3. Lập trình hướng đối tượng trong Java.............................................................................43 I. Khái niệm lập trình hướng đối tượng (Object-Oriented Programming - OOP)......................43 I.1. Khái niệm OOP................................................................................................................43 I.2 Cơ sở lý luận của OOP......................................................................................................43 I.3 Trừu tượng hóa..................................................................................................................43 II. Tính đóng gói trong Java.......................................................................................................45 II.1 Khái niệm tính đóng gói..................................................................................................45 II.2 Mối quan hệ giữa các class..............................................................................................45 II.3 Một số gợi ý khi thiết kế class.........................................................................................45 IV. Sử dụng các Class xây dựng sẵn trong thư viện...................................................................46 V. Xây dựng Class trong Java....................................................................................................47 V.1 Cấu trúc của class............................................................................................................47 V.2 Các thuộc tính thành phần:..............................................................................................48 V.3 Các phương thức thành phần...........................................................................................49 V.4 Gọi và truyền tham số cho phương thức..........................................................................50 V.6 Các hàm và phương thức đặc biệt....................................................................................50 V.7 Khai báo chồng các phương thức....................................................................................51 V.8 Lớp lồng nhau – lớp nội...................................................................................................52 2

VI. Tính kế thừa trong Java........................................................................................................53 VI.1 Sự kế thừa các thuộc tính và phương thức.....................................................................53 VI.2 Sự kế thừa đối với các constructor.................................................................................56 VII. Tính đa hình trong Java.......................................................................................................57 VII.1 Sự ép kiểu và gán tham chiếu đối tượng.......................................................................57 VII.2 Sự ràng buộc động –Dynamic Binding ........................................................................57 VIII. Lớp Object.........................................................................................................................58 IX. Giao diện..............................................................................................................................59 IX.1 Cấu trúc của giao diện....................................................................................................59 IX.2 Các tính chất của giao diện.............................................................................................61 X. Package..................................................................................................................................61 X.1 Sử dụng các package trong thư viện Java........................................................................61 X.2 Đặt lớp vào package........................................................................................................62 Bài tập.........................................................................................................................................62 Đề tài 4. Lớp và phương thức trừu tượng.......................................................................................63 I. Khái niệm lớp trừu tượng........................................................................................................63 II. Cài đặt lớp và phương thức trừu tượng trong Java................................................................63 Bài tập.........................................................................................................................................64 Đề tài 5. Lưu trữ và xử lý đối tượng...............................................................................................65 I. Lớp Vector và giao diện Enumeration....................................................................................65 I.1 Lớp Vector........................................................................................................................65 I.2 Giao diện Enumeration......................................................................................................66 II. Mảng trong Java và lớp ArrayList.........................................................................................68 II.1 Mảng trong Java...............................................................................................................68 II.2. Các thuật toán cơ bản trên mảng.....................................................................................69 II.3 Class Arrays.....................................................................................................................70 III Danh sách trong java và giao diện Lists ...............................................................................72 Bài tập.........................................................................................................................................73 Đề tài 6. Các luồng vào ra dữ liệu với file.....................................................................................74 I. Khái niệm luồng vào ra (I/O stream)......................................................................................74 II. Lớp InputStream:...................................................................................................................75 III. Lớp OutputStream................................................................................................................76 IV. Lớp FileInputStream............................................................................................................76 V. Lớp FileOutputStream...........................................................................................................76 VI. Lớp File................................................................................................................................76 VII. Nhập xuất lọc .....................................................................................................................78 VII.1 Lớp FilterInputStream: .................................................................................................78 VII.2 Lớp FilterOutputStream................................................................................................78 VIII. Vào/ra có sử dụng bộ đệm ................................................................................................78 VIII.1 Lớp BufferedInputStream:...........................................................................................78 VIII.2 Lớp BufferedOutputStream.........................................................................................78 IX. Lớp RandomAccessFile ......................................................................................................80 X. Đối tượng System.in..............................................................................................................81 XI. Truy cập file ở chế độ tuần tự...............................................................................................81 XII. Truy cập file nhị phân.........................................................................................................85 Bài tập ........................................................................................................................................86 Đề tài 7. Xử lý ngoại lệ..................................................................................................................87 3

.........113 III........................4 JScrollPane.......110 II.................................................92 II...............123 IV................................. Xây dựng một Applet đơn giản...................................................... An ninh và khả năng của Applet.....................124 V................................ Xây dựng một ngoại lệ..................... Khái niệm và cơ sở xử lý sự kiện........................ Giới thiệu AWT .........................................................................................1 Hộp thoại thông báo........109 I..........................................................3 JDialog..................................................................................................................................................................... Sử dụng ngoại lệ được kiểm soát.......................................................................................105 IV.............................110 II................................................................... Cấu trúc cơ bản và vòng đời của một Applet....................................................................................................... lập trình đồ họa và bắt sự kiện của applet...................................................... Bài tập.................................................................................................................................................101 Bài tập.......................................113 III..............7 Ô văn bản (text field) và vùng văn bản (text areas).....103 III........................................................ Applet........................................ Các hộp thoại.. Truy cập thông tin sự kiện.................................................................................8 Thanh trượt (Scrollbar)......109 II...................... Các tình huống sử dụng ngoại lệ...........................................................................117 III..........................................................4 Nút chọn (radio button)....................91 Đề tài 8......................128 V................................................129 VI...118 III......................................................2 JPanel.........................................1 Cách trình bày FlowLayout:................................132 4 ................................ Xử lý các sự kiện trong Java.................................................90 VI..................... Xử lý các sự kiện chuột...................................................................................................................98 IV... Cơ sở quản lý ngoại lệ trong Java....... Vật chứa (Container)......................................................................................................................102 Đề tài 9................................................................................................................................................................................................................................................................................................................................106 VI.................................................................................................................................................................................................................................................89 V. Các phương thức....1 JFrame....................................................................................... Xử lý các sự kiện trên window...88 IV....3 Hộp thoại chọn màu................................................... Bộ quản lý cách trình bày (Layout Manager).....113 III................................................................................................................................................................................................................2 Cách trình bày GridLayout:.....98 V............................................................................................................................117 III...130 Đề tài 11............................103 I..............................................................................103 II...... Cấu trúc cây kế thừa các xử lý ngoại lệ.......................1 Nút nhấn .........................2 Nhãn (Label).......128 VI..... Lập trình giao diện đồ họa GUI........................................................ Các thẻ HTML của Applet..................112 II.......................6 Danh sách (Lists)........................115 III......................................................................................................................................................................105 V............3 Nút đánh dấu (checkbox)................97 III...................................................................................................................... Threading..................................................................127 V.....3 Cách trình bày BorderLayout.........................................................................................................................128 VI............... Giới thiệu về các thành phần GUI cơ bản......................2 Hộp thoại chọn File................................................. Thành phần Menu.87 III.............................................................................................................................................................................................................................................87 II..................................................................................................130 Bài tập................................................... Ứng dụng Applet với của sổ Popup...........113 III.............................................................................5 Hộp thoại Combo ..........................................................128 VI.........................................................................................128 V....120 III......................107 Đề tài 10............. Các lớp thích nghi...........110 II..........92 I..............................................I.....................

..................................................................................................................................................................3 Tạm dừng và phục hồi một thread. Các thuộc tính của thread....146 5 ........................................................................................................................141 Bài tập......................145 Tài liệu tham khảo..............2............138 IV.............................................2 Nhóm thread...........................................................................................1 Tình trạng “đua tranh”.........134 III..................................135 IV.............................................................................5 Đợi một thread kết thúc công việc...........140 V.......... Khái niệm thread..................................................... Lớp Thread.........................................................................................................................136 IV....132 I.........138 V.............139 V...........................132 I..............................................................................................................132 I..............................I................................................................2 Khóa đối tượng.......................143 Phụ lục A...134 III........3 Các bước để tạo một thread... Các từ khóa của Java..............................................................................................4 Giải phóng thời gian cho CPU..................................................................................................................................................................................................................................................................2 Dừng một thread..........137 IV...............................................................................................1 Khái niệm..............3 Quản lý các ngoại lệ của thread.................................................................1 Độ ưu tiên của thread......................... Các trạng thái của thread.....................135 III.............................................138 IV.............................................................................................................144 Phụ lục B Một số hàm hay sử dụng...................139 V..............133 III...................................................................................136 IV..................................................................132 II........... Đồng bộ thread........................................................................................1 Interrupt một thread.................. Điều khiển các thread.............................................................................................................................................................................................................3 Đối tượng điều kiện..............................................................................

1 mặc dù khá mạnh nhưng cũng còn nhiều hạn chế. Các phiên bản 1. do hãng SUN phát triển trên nền UNIX nên họ sử dụng ngôn ngữ lập trình C++ là chủ yếu. khả năng triển khai trên nhiều hệ điều hành khác nhau và nhiều tính năng ưu việt khác chúng ta sẽ xem xét trong phần sau. người lập trình được sở hữu một thư viện lớn. sự phát triển của Internet đã tạo cơ hội để Java phát triển nhanh chóng. Lịch sử hình thành và phát triển ngôn ngữ lập trình Java I. Trên thực tế. Ban đầu nhóm đặt tên cho ngôn ngữ mới là “Oak” nhưng sau đó được chuyển thành Java do Oak cũng đã là tên một ngôn ngữ lập trình khác. Để giải quyết vấn đề di động.2” ý nói tới sự có mặt đồng thời của 2 phiên bản “Standard Edition” là Micro Edition và Enterprise Edition trong Java. Các nhân viên tiếp thị của Java gọi đây là phiên bản “Java 2 Standard Edition Software Development Kit Version 1.0 của Java ra đời vào năm 1996. nhóm đã sử dụng ý tưởng của kỹ sư Niklaus Wirth – người sáng lập ngôn ngữ Pascal – về việc sử dụng cơ chế thông dịch và máy ảo (virtual machine). Khi làm việc với Java. Run Anywhere). các chương trình viết bằng Java có môi trường thực thi riêng với các tính năng bảo mật. Sau đó nhóm đã phải mất cả năm 1993 và nửa đầu 1994 để đi tiếp thị công nghệ của mình. Phiên bản 1. chạy khắp nơi” (Write once. Từ năm 1994. Ngoài ra. sau đó là phiên bản 1. Bảng sau cho thấy sự phát triển thư viện Java qua các phiên bản: 6 .1.2 Tóm tắt lịch sử hình thành của Java Năm 1991. Nhóm đã mở một dự án có tên là Green để hiện thực hóa ý tưởng này.5 (chuyển sang gọi là phiên bản 5. Do đó. Về nền tảng ngôn ngữ. Sun Fellow và James Gosling có ý tưởng phát minh ra một ngôn ngữ lập trình nhỏ gọn có thể thực thi được trên các thiết bị dạng như bộ chuyển kênh của truyền hình cáp vì các thiết bị kiểu này có bộ nhớ nhỏ. 1.0) đánh dấu sự tích hợp đầy đủ nhất các công nghệ Java. Phiên bản đầu tiên 1. Năm 1998 đánh đấu bước chuyển mình mạnh mẽ của Java với sự ra đời của phiên bản 1. Java được biết đến không chỉ là một ngôn ngữ lập trình mà là một platform – một môi trường và công nghệ phát triển – riêng biệt. dự án Green cho ra đời sản phẩm đầu tiên có tên là “*7” nhưng đã không được chào đón như mong đợi. Giới thiệu về Java I. I. Giới thiệu về Java Java là một ngôn ngữ lập trình mạnh đang được sử dụng rất rộng rãi hiện nay trên toàn thế giới.Đề tài 0. Nhóm đã phát triển một trình duyệt có tên là HotJava cho phép các chương trình Java nhúng được trong đó (applet). Năm 1992.2.2 làm cho Java tiến gần tới mục tiêu “viết một lần. Bên cạnh đó.4 là sự phát triển mở rộng tiếp theo của phiên bản 1.3. Đây chính là minh chứng rõ ràng về sức mạnh của Java đã nhanh chóng được cộng đồng người sử dụng internet biết đến và là tiền đề để Java phát triển rực rỡ như ngày hôm nay. một nhóm kỹ sư của hãng SUN bao gồm Patrick Naughton. có tính mở với một lượng mã nguồn tái sử dụng khổng lồ luôn có trên internet. ngôn ngữ mới thiên về hướng đối tượng (Object Oriented) của C++ hơn là hướng thủ tục như Pascal. do các hãng khác nhau sử dụng các chíp xử lý (CPUs) khác nhau nên một đặc tính quan trọng mà ngôn ngữ này phải có là độc lập với các dòng CPUs khác nhau – gọi là đặc tính di động.

II. Tính mạnh mẽ Việc loại bỏ con trỏ làm tăng độ tin cậy của chương trình. union.5. bộ nhớ được giải phóng tự động. • Đọc và ghi file tự do 7 .sun. Người sử dụng có thể download phiên bản mới nhất của Java tại địa chỉ: http://www.2. Các công nghệ JSP. Trong Java chỉ có thừa kế đơn mà không có tính đa thừa kế như của C++. Servlet cho phép xây dựng các website tương tác với các tính năng thực thi tối ưu II. Lập trình viên không cần quan tâm đến thao tác cấp phát và giải phóng bộ nhớ.Phiên bản Số các Class và Interface 1. II.com/download/index. II. Java đã phát triển tới phiên bản 1.3 1.4 5.0 211 477 1524 1840 2723 3270 Hiện tại. con trỏ.0 1.2 1. Tính đơn giản Java được phát triển dựa trên C++ nhưng lược bớt đi hoặc thay thế các khái niệm khó hiểu như header file.1 1. Java được phát triển từ C++ nên nó là ngôn ngữ lập trình hướng đối tượng.3. FTP bằng các phương thức như RMI hay Socket. Tính an toàn Ngôn ngữ Java được thiết kế để tránh các sự cố: • Nạp chồng stack lúc runtime. Java hoàn toàn thích hợp cho các ứng dụng Internet.jsp?cat=Java %20%26%20Technologies&tab=3&subcat=Java. structures.6 và liên tục được cập nhật. Tuy nhiên tính đa thừa kế được biểu hiện thông qua việc sử dụng các Interface. operator overloading.1. Tính hướng đối tượng Như đã trình bày ở trên. Tính phân tán Java cho phép lập trình truy cập các đối tượng từ xa thông qua các giao thức HTTP.4. Các đặc trưng của Java Java được biết đến với các đặc trưng sau: II. • Ảnh hưởng tới bộ nhớ nằm ngoài phạm vi được cấp phát. virtual base class. Với Java. II.

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 . Người ta có thể xem nó như một hệ điều hành thu nhỏ. Tính trung lập Các chương trình viết bằng Java không bị phụ thuộc vào hệ điều hành. Tính di động Không giống C++ và C. Khi đem mã Bytecode này chạy trên hệ máy tính nào thì một trình thông dịch virtual machine (Java Vitual Machine-JVM) sẽ thông dịch chúng sang mã máy tương ứng để thực thi. Mã nguồn -> ByteCodes -> machine code. 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ể. mã đã biên dịch. 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 biến cục bộ. • Các tham số truyền cho phương thức. • Các toán hạng của mã bytecode.class • Quản lý bộ nhớ • Dọn “rác”. Thiết kế này giúp cho trình biên dịch luôn có số bytecode như nhau trên mọi hệ máy và sau đó phát sinh mã máy theo khuôn dạng cố định. Trong các phiên bản đầu của Java. vấn đề giao diện đồ họa cho người sử dụng (GUI) chưa được xử lý triệt để và phụ thuộc vào hệ máy. Từ mã nguồn -> Bytecodes: Trình biên dịch Java. Điều này có được là do mã nguồn chương trình không được biên dịch thành mã máy ngay mà thành mã Bytecode. JVM thiết lập các lớp trừu tượng cho phần cứng bên dưới. II. 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.II. các kiểu dữ liệu nguyên thủy của Java được cấp phát một lượng bộ nhớ cố định. thu hồi bộ nhớ cấp cho các biến không còn được sử dụng. thư viện GUI của Java đã được viết lại 8 . Chẳng hạn kiểu dữ liệu int của Java luôn là 4 byte (32 bit) trong khi kiểu int của C++ có thể hiểu là 2 byte hoặc 4 byte tùy theo ngữ cảnh. Từ Bytecodes -> machine code: Trình thông dịch Virtual machine.7.6. IBM Bytecode Trình biên dịch Trình thông dịch Java (Java Interpreter) Sparc Macintosh Java Virtual Machine – JVM Máy ảo là một phần mềm dựa trên cơ sở máy tính ảo. hệ điều hành. Ngày nay. 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.

8. Công cụ và môi trường lập trình Java Hiện nay có rất nhiều môi trường phát triển Java (Integrated Development Environment IDE). RMI. Ví dụ như JIT có thể quản lý các đoạn mã được sử dụng thường xuyên trong chương trình.org). đặc biệt trong các ứng dụng thời gian thực. Mỗi môi trường cung cấp cho lập trình viên những tiện ích lập trình ở mức độ khác nhau. JMS: Xây dựng ứng dụng bởi nhiều thành phần ghép lại. Ngày nay. II.org/). Một số IDE thông dụng là: • Netbeans (miễn phí tại http://www. • Jcreator (thương mại). Tính thực thi cao Java sử dụng công nghệ Just-In-Time (JIT) giúp quá trình thông dịch thực hiện nhanh hơn.netbeans.eclipse. III. Các phương thức mới có thể được cài đặt thêm vào các lớp đối tượng hay các giao diện trong thư viện của chương trình đang chạy. giao tiếp từ xa. Tính đa luồng Với chương trình Java. JSP: Các file nhúng mã Java và HTML.9. tối ưu chúng để nâng cao tốc độc thực hiện. II. • Jbuilder (thương mại).10. những mã bytecode giống nhau sẽ chỉ cần thông dịch một lần. IV. Tính thông dịch Trình thông dịch Java sẽ thông dịch mã bytecode sang mã máy nơi mà nó được cài đặt. Tuy nhiên đây lại là giải pháp cho tính di động. II. II. Ứng dụng EJB. Quá trình này cũng làm các chương trình Java chạy chậm hơn. Với công nghệ này.hoàn toàn và có tính độc lập cao giúp cho chương trình Java có giao diện giống nhau trên mọi hệ máy. Servlet: Các class thực thi phía web server. Applet: Nhúng trong các trang Web. Ứng dụng đồ hoạ: Có giao diện GUI.11. Các loại ứng dụng của Java • • • • • • Ứng dụng console: Không có giao diện GUI. Điều này giúp cho việc cài đặt các thuật toán song song bằng Java trên các máy tính nhiều CPU được dễ dàng hơn. 9 . công nghệ này liên tục được cải tiến và cho kết quả vượt trội so với các trình thông dịch truyền thống. lập trình viên có thể cùng lúc quản lý nhiều tiến trình khác nhau. • Eclipse (miễn phí http://www. Tính động Các chương trình Java có thể được nâng cấp mà không ảnh hưởng tới người sử dụng.

Cú pháp:javadoc [options] sourcecodename.6. 1.com/j2se.V. Cú pháp:javap [options] classname • Công cụ sinh tài liệu.sun. jre Chứa các file lưu thông tin môi trường lúc thực thi lib Chứa các file thư viện src Chứa mã nguồn java Trong thư mục \bin có chữa các công cụ chính của Java: • Trình biên dịch. Chọn System 10 . 'java' Cú pháp:java [options] classname • Trình dịch ngược. '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 /*.0_02 (nếu phiên bản cài là jdk1.java hay jdb -host -password [options] sourcecodename. Mở Control Panel 2.java • Trình thông dịch. Sau đó cài đặt như ứng dụng bình thường.6. các phương thức của một lớp. 'jdb‘ Cú pháp:jdb [options] sourcecodename..0_02).java • Chương trình tìm lỗi . */).java Cài đặt đường dẫn mặc định.Debug. Cài đặt Java Java phiên bản Java mới nhất có thể download tại địa chỉ http://java. 'javac' Cú pháp:javac [options] sourcecodename... 'javap' javap dịch ngược bytecode và in ra thông tin về các thuộc tính (các trường). Trong đó có chứa các thư mục với ý nghĩa sau: bin Chứa các công cụ và trình biên dịch Java demo Chứa các chương trình Java Demo docs Chứa các tài liệu mô tả thư viện của Java includes Chứa các file dùng để biên dịch các đoạn mã nguồn viết bằng ngôn ngữ khác (native). Thư mục cài đặt mặc định của Java trên Windows là C:\Program Files\Java\jdk1.

0_02\bin vào biến môi trường Path . Thêm đường dẫn C:\Program Files\Java\jdk1. Chọn Tab Advanced 4.6.6.Chọn Edit và copy thêm đường dẫn “C:\Program Files\Java\jdk1.0_02\bin”.Chọn Variable Path . chọn OK để kết thúc.3. Chọn Environment Variables 5. 11 .

mỗi đơn hàng bao gồm trong nó các thông tin về khách hàng.1 Các khái niệm căn bản của công nghệ hướng đối tượng Hướng đối tượng là một công nghệ để sản sinh ra các mô hình phản ánh một cách tự nhiên các nghiệp vụ thực tế. 5. các hệ thống phần mềm theo công nghệ hướng đối tượng phản ánh một cách tự nhiên và trung thực nghiệp vụ thực tế và có khả năng đáp ứng các thay đổi dễ dàng.Đề tài 1. Phát triển một hệ thống phần mềm theo hướng đối tượng dựa trên 5 khái niệm cơ bản: Lớp (class). Đối tượng thực tế thì có vô số thuộc tính và hành vi nhưng chỉ thuộc tính và hành vi trong phạm vi nghiệp vụ là được xét đến.…cho thấy mối quan hệ dạng khác: các nhân viên làm công việc quản lý tất nhiên cũng là nhân viên của công ty nhưng có thêm các thuộc tính riêng biệt – một quan hệ kế thừa (inheritance). đối tượng (object).… Mỗi đối tượng là một biểu hiện thực tế của một lớp. Nói cách khác. thông điệp (mesage). Trong một hệ thống bán hàng. 3. Công ty duyệt hồ sơ và gửi giấy hẹn phỏng vấn tới ứng viên. Vì vậy. dễ hiệu chỉnh. thừa kế (inheritance) và đa hình (polymorphism). Trong ví dụ trên có sự tham gia của hai đối tượng “công ty” và “ứng viên”. 4. object = name + attributes + operations Hệ thống hướng đối tượng nếu được mô hình đúng sẽ rất linh hoạt. Lấy ví dụ về hệ thống quản lý sinh viên của trường ĐHBK Hà Nội cần quản lý rất nhiều đối tượng sinh viên khác nhau nhưng có thể chỉ được trừu tượng hóa thành một lớp đối tượng có tên SinhVien chẳng hạn. Một ví dụ khác là trong hệ thống quản lý nhân sự chúng ta có các đối tượng như: nhân viên. Lấy ví dụ: lớp động vật có vú bao gồm lớp động vật 4 chân. quản lý. Xây dựng hệ thống phần mềm theo hướng đối tượng I. Sự trao đổi thông tin giữa hai đối tượng này cho thấy mối quan hệ phụ thuộc giữa chúng (dependence). lớp 4 chân lại bao gồm các lớp như lớp mèo. Sự trừu tượng hóa diễn ra ở nhiều cấp độ. Ứng viên gửi hồ sơ dự tuyển tới công ty. Ví dụ như nghiệp vụ tuyển nhân sự cho một công ty có thể được tóm tắt qua một chuỗi các tương tác như sau: 1. Sự trừu tượng hóa một lớp đối tượng cho ta kết quả một tập các thuộc tính (attributes) và các hành vi (operations) đặc trưng cho bất kỳ đối tượng nào thuộc lớp đó. Xét cho cùng thì mọi quy trình nghiệp vụ trong thực tế đều là sự tương tác của các đối tượng theo một trình tự nhằm đạt được một mục đích cụ thể. các đối tượng và mối quan hệ giữa chúng phản ánh quy trình nghiệp vụ. 12 . 2. Công ty đưa ra thông báo tuyển nhân sự tới các ứng viên có nhu cầu. được cài đặt dễ dàng bằng các ngôn ngữ hướng đối tượng. Công ty ký hợp đồng với ứng viên hoặc từ chối. ngày giờ. Các hệ thống phần mềm hướng đối tượng cũng được cài đặt bởi các ngôn ngữ lập trình hướng đối tượng. …và một danh mục các mặt hàng. Sự chi tiết phụ thuộc vào phạm vi nghiệp vụ. Lớp là sự trừu tượng hóa các đối tượng thực tế theo phạm vi nghiệp vụ. lớp trâu. Khi này ta nói rằng giữa đơn hàng và mặt hàng tồn tại một quan hệ bao gồm (aggregation) Mục tiêu của công nghệ hướng đối tượng chính là thể hiện được các đối tượng và mối quan hệ giữa chúng vào trong các hệ thống phần mềm. Công ty phỏng vấn ứng viên. Ngôn ngữ mô hình hóa UML I.

Sự thay đổi các yêu cầu của người sử dụng. Đa dạng về nội dung. Thêm vào đó. lĩnh vực này vẫn cần được chuẩn hóa hơn nữa. Năm 1994. Analysis : Phân tích.Hướng đối tượng không chỉ là một lý thuyết mà đã được chứng minh bằng những ứng dụng rất thành công trong thực tế ở nhiều lĩnh vực khác nhau. 5. Vào đầu những năm 1990. Design: Thiết kế. Implementation: Cài đặt. 4. 6. 2. 4. Theo nguyên tắc chung này. Sự gia tăng về quy mô từ nhỏ đến lớn của ứng dụng. Những thách thức này có thể nói là gắn liền với mọi công ty phần mềm đặc biệt là ở Việt Nam. các công ty phần mềm đã rất khó khăn trong việc cung cấp các công cụ này. Sự phân tán về không gian làm việc. Sức ép về thời gian hoàn thành. Test: Kiểm thử. Rumbaugh và Jacobson đã làm việc độc lập và đã đề xuất các quy trình thỏa mãn yêu cầu này. Requirements : Thu thập yêu cầu. mỗi công ty lại ứng dụng những công nghệ khác nhau để phát triển ứng dụng như các mô hình water fall.OOP) để xây dựng các ứng dụng. Lịch sử phát triển ngôn ngữ mô hình hóa UML II. mô hình hướng chức năng hay mô hình hướng đối tượng v. Deployment: Triển khai. Nhiều nhà nghiên cứu phương pháp trong đó có Booch. các công ty này lại muốn sử dụng các công cụ phần mềm hỗ trợ các quy trình của họ. 3. phân tích còn bị xem nhẹ cũng như các công ty còn đang bỡ ngỡ với sự mở rộng về quy mô và thiếu nhân lực chuyên môn về phân tích thiết kế. 3. James Rumbaugh đã hợp tác cùng Grady Booch tại công ty phần mềm Rational Software Corporation để cùng xây dựng một quy trình thống nhất dựa trên kết quả của 13 .v… I. Tuy nhiên. thậm chí là các bộ phận khác nhau của cùng một công ty đã sử dụng các quy trình khác nhau. Điều này dẫn tới một đòi hỏi phải có một quy trình làm phần mềm tiếp cận theo hướng phân tích và thiết kế hướng đối tượng (Object Oriented Analyze and Design .OOAD). nơi mà vai trò của quá trình khảo sát. các công ty khác nhau.3 Những thách thức của ngành công nghiệp phần mềm hiện nay Mặc dù đã ứng dụng các công nghệ tiến tiến và quy trình phát triển chuẩn hóa nhưng ngành công nghiệp phần mềm vẫn phải đối mặt với những thách thức như: 1. Tóm tắt lịch sử UML Những năm 1980 là thời kỳ bùng nổ số lượng các công ty phần mềm sử dụng ngôn ngữ lập trình hướng đối tượng(Object Oriented Programming . II. Với quá nhiều quy trình khác nhau.1. 2. Mỗi một quy trình có một tập ký hiệu mô hình riêng để truyền đạt và diễn tả các kết quả phân tích và thiết kế. 5. I. Điều này cho thấy việc cần thiết phải có một quy trình với tập ký hiệu thống nhất.2 Quy trình chung phát triển hệ thống phần mềm Xây dựng một hệ thống phần mềm hướng đối tượng cũng tuân theo quy trình chung như mọi công nghệ khác: 1.

1.3 Đặc trưng của UML Hiện nay. II. một tổ chức có tên Object Management Group (OMG) đã mời nhóm đệ trình một ngôn ngữ mô hình. Khái niệm về UML UML – Unified Modeling Language là một ngôn ngữ dùng các sơ đồ và mô hình thống nhất để mô hình các hệ thống phần mềm. • Gắn kết giữa các chu trình phát triển.V. Hiện nay OMG đã phát hành tới phiên bản UML 2. Canon. • Mô hình triển khai (deployment diagrams) mô tả việc triển khai phần mềm trên một môi trường xác định. IBM.0 và đang nghiên cứu phiên bản 2. OMG là một tổ chức phi lợi nhuận chuyên xúc tiến việc sử dụng công nghệ hướng đối tượng trong ngành công nghiệp phần mềm thông qua việc đưa ra các hướng dẫn và đặc tả OOP. Mục đích của UML là: • Trở thành ngôn ngữ mô hình mà tất cả mọi người làm mô hình có thể sử dụng. thuật ngữ. • UML là một ngôn ngữ diễn tả. • Nâng cao tính tái sử dụng các thành phần của một hệ thống phần mềm. Philips Telecommunications N. • Gắn kết chặt chẽ các khái niệm nội tại của hệ thống. sơ đồ của UML đều theo hướng đối tượng. Hewlett-Packard.. ký hiệu. Oracle và Rational Software đã nhận thấy lợi ích của UML và đã nhận lời tài trợ cho các dự án về UML của OMG. • Mô hình tương tác (interaction diagrams). Sun Microsystems. UML không phải là một quy trình. • Tập trung hướng tới giải quyết các vấn đề tồn tại trong phát triển phần mềm. Thuật ngữ “Unified” ở đây có một ý nghĩa quan trọng. • Mô hình Use-case và mô hình hoạt động mô tả các yêu cầu và các luồng công việc trong hệ thống. UML là một ngôn ngữ đã được OMG chuẩn hóa và được đặc tả rõ ràng. Các tập đoàn lớn như HP. Microsoft. Inc. Data General.. Năm 1997. mô hình hoạt động (activity diagrams) mô tả các hành vi động của các đối tượng trong hệ thống cũng như các thông điệp giữa chúng. nó nói lên các nguyên tắc của UML: • Thống nhất phương thức. Các thành viên của OMG ban đầu là 3Com Corporation.từng người.4 ra đời. • Không phụ thuộc vào ngôn ngữ lập trình và môi trường thực hiện. Các đặc tính của UML bao gồm: • Mô hình class (class diagrams) mô tả cấu trúc tĩnh của hệ thống và mối quan hệ giữa các đối tượng. OMG tiếp tục xem xét lại UML và đến năm 2001 thì phiên bản UML 1. Năm 1996. • Các mô hình cấu trúc hỗn hợp (composite structure diagrams) mô tả sự hợp tác cũng như các đặc điểm về cài đặt. nhóm đã cho xuất bản phiên bản đầu tiên của UML tới cộng đồng phát triển phần mềm và yêu cầu phản hồi. và Unisys Corporation. Cũng cùng thời gian đó. American Airlines.2. • Không phụ thuộc vào quy trình phát triển. • Không phụ thuộc vào lĩnh vực ứng dụng. Tất cả các mô hình. mô hình trạng thái (state diagrams). 14 . II. Sau đó Ivar Jacobson cũng sớm gia nhập nhóm này. • Đơn giản nhất có thể trong khi vẫn mô hình được phần lớn các ứng dụng.

Một phần tử mô hình có thể được sử dụng trong nhiều sơ đồ nhưng chúng luôn có cùng ý nghĩa và ký hiệu giống nhau.0 bao gồm 13 loại sơ đồ khác nhau. Nhiều hướng nhìn khác nhau cho ta nhiều sơ đồ mô tả đầy đủ về hệ thống. ngữ nghĩa của các phần tử mô hình. Một hệ thống không thể chỉ được mô tả bởi một sơ đồ.2. 15 . object. • • • Các Diagrams (các sơ đồ): Các sơ đồ bao gồm các phần tử hình vẽ dùng để mô tả nội dung của các View. message (thông điệp) và mối quan hệ giữa chúng bao gồm quan hệ dependence. III.III.1. UML có đầy đủ các mô hình và sơ đồ để thể hiện hầu hết các khía cạnh của hệ thống phần mềm. Ngôn ngữ UML III. Các Model Elements (các phần tử mô hình): Các khái niệm được sử dụng trong các sơ đồ và các phần tử của sơ đồ diễn tả các khái niệm phổ biến của công nghệ hướng đối tượng như class. UML 2. Các thành phần của UML Xét trên khía cạnh ngôn ngữ diễn tả. Các hướng nhìn (view) Use-case view: Đây là hướng nhìn về mặt chức năng của hệ thống được thực hiện bởi các tác nhân bên ngoài. thuật ngữ. inheritance và aggregation. Các General Mechanisms (các đặc tả chung mở rộng): Mô tả các thông tin chú thích. Các hướng nhìn cũng liên kết ngôn ngữ mô hình với các quy trình được chọn cho việc phát triển hệ thống. Các thành phần của ngôn ngữ UML bao gồm: • Các Views (các hướng nhìn): Các view thể hiện các cách nhìn khác nhau tới hệ thống.

5.      cần           use-case (text     Mỗi mô tả   đảm bảo các thông tin sau:                    1.                                           • Các use-case cần có tính độc lập tương đối để dễ tổ chức nhóm làm việc và có tính     tái   dụng cao.  Mục tiêu của use-case. Dòng chính. người làm mô hình có thể sử dụng mô tả bằng văn bản chi tiết cho mỗi   detail). Phạm vi của use-case. Tên use-case. 7.   •  Các use-case phải đầy đủ. Dòng phụ. Tiền điều kiện.                                                 6.ud Primary Use Cases                                                                                                                           HÖthèng b¸n hµng qua m¹ng Interrnet                                                Chän hµng                                                             s¶n phÈm                                Kh¸chhµng                         Göi th«ng Xem chi tiÕ t    hµng                        CËp nhËt giá                     tin ph¶n håi                                                                                    hµng                       § ¨ng ký       LËp ® n mua                   ¬                danh môc              Qu¶n trÞhÖ                          thèng hµng hãa Tr¶ lêi Qu¶n lý kh¸ch hµng                                                                                                                                                                                                                                                  kh¸chhµng                    th«ng tin                                      Theo Nh© viªn                   dâi    n   kinh  ® n hµng ¬   doanh m t hµng Æ CËp nhËt                                                                           Các nguyên tắc cho việc xây dựng use-case view là:   •  Các use-case    hình thành trên cơ sở nhìn từ bên ngoài vào trong hệ thống         được                       (out-> in). chúngđược tổng    theo phương pháp đi từ tối đa đến                     hợp              tối thiểu (ban đầu mở rộng tối đa các use-case có thể sau đó thu hẹp lại theo nhu     cầu khách hàng).                                      sử      Bên cạnh sơ đồ.                                                                      16                                                                                    .       2.                                        3. Các tác nhân chính.                                                 4.

Phạm vi: Công ty Bảo hiểm PCM. Dòng chính 1. Trong trường hợp các use-case quá phức tạp và chưa được mô tả rõ ràng. Công ty bảo hiểm từ chối yêu cầu. (Công ty bảo hiểm sẽ làm gì trong trường hợp này???-cần trao đổi kỹ hơn) 4a. 2a1. Dòng phụ 1a. 4a1. 4b. ghi lại và kết thúc xử lý vụ việc. Actor chính: Người đòi bồi thường. Vụ tai nạn chỉ vi phạm chính sách bảo hiểm nhỏ. chúng có thể được tách ra thành các use-case nhỏ hơn theo hai dạng: • Include: use-case mới được tách ra và được bao gồm trong use-case chính một cách vô điều kiện. Ngoại lệ. 2a. Vụ tai nạn vi phạm chính sách bảo hiểm cơ bản. Sau đây là một ví dụ về use-case text detail: Use-case: Đòi tiền bồi thường. Hậu điều kiện. Không có đại lý nào rảnh rỗi. uc Use Case Model Use Case Principal «extend» Use Case Extend 17 . 1a1. 3. nhắc nhở. uc Use Case Model Use Case Include Use Case Principal «include» • Extend: use-case mới xảy ra khi một điều kiện xảy ra trong use-case chính. 4b1. Công ty bảo hiểm điều đình với người đòi bảo hiểm và đồng ý trả bảo hiểm. ghi lại và kết thúc xử lý vụ việc. Công ty bảo hiểm phân công cho một đại lý xác minh trường hợp này. Đại lý đối chiếu tất cả các chi tiết trong đơn theo chính sách bảo hiểm của công ty 5. 3a. Công ty bảo hiểm yêu cầu dữ liệu thiếu. Công ty bảo hiểm từ chối yêu cầu. nhắc nhở. 2. Bằng chứng tai nạn không đầy đủ. 9. 4. 3a1. Người đòi bồi thường gửi lại các dữ liệu thiếu. Người đòi bồi thường gửi đơn yêu cầu với các dữ liệu bằng chứng về tai nạn. Người đòi bồi thường không có chính sách bảo hiểm hợp lệ. Công ty bảo hiểm trả tiền bảo hiểm. 1a2. Công ty bảo hiểm xác nhận người viết đơn có quyền lợi bảo hiểm hợp lệ.8.

orderNumber: String  «enumeration»       +  checkForOutstandingOrders() : void                      OrderStatus property get enum             +  getDate() :Date                 -status . Các cấu trúc này được gọi là tĩnh vì chúng không phụ thuộc vào thời gian.  Author: string                       -item .String)                 property get + getBasket() : ShoppingBasket                     + getBillingAddress() : String + getClosed() : boolean   getDeliveryAddress() : String                  + + getEmailAddress() : String +   getName() :String                 + getOrder() : Order property set                    + setBasket(ShoppingBasket) : void + setBillingAddress(String) : void   setClosed(boolean): void                + + setDeliveryAddress(String) : void +   setEmailAddress(String) :void                 + setName(String) : void +   setOrder(Order): void                            -account                             + createNewBasket() : void + loadAccountHistory() : void +  deleteItem() :void                                + loadOpenOrders(): void     + processOrder() : void property get property get                              Account + getAccount() :          + getLineItem() : LineItem + getDate() : Date property set  setLineItem(LineItem) :               + getLineItem() :LineItem                void        + + getOrderNumber() : String property set                                       + setAccount(Account) : void -history + setDate(Date) : void                           + setLineItem(LineItem) :void            + setOrderNumber(String) : void                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           18                                           . Đây là sự mô hình các khái niệm trong ứng dụng.delivered: int +  getLineItem(): LineItem                             . Logical views Đây là hướng nhìn cho biết các chức năng được thiết kế vào trong hệ thống như thế nào (HOW?) thông qua việc mô tả các cấu trúc tĩnh và các hành vi động của hệ thống.dispatched: int + getOrderNumber() : String .closed: int + getDeliveryInstructions() : String .date: Date                -  deliveryInstructions: String             . catalogNumber: string  costPrice:                      number listPrice: number  title:                      string                       property get             + getItem() : StockItem                       +  getQuantity(): int          property set         +  setItem(StockItem): void           + setQuantity(int) : void                                                                                                         property get +  getAuthor(): string                + getCatalogNumber() : string +  getCostPrice() : number                  + getListPrice() : number + getTitle() : string                    property set + setAuthor(string) : void +  setCatalogNumber(string) :                 void + setCostPrice(number) : void +  setListPrice(number)  void              :   + setTitle(string) : void                                                                                                                -account                                         deliveryAddress:                      String . use-case view giúp ta trả lời câu hỏi WHAT? về hệ thống.   .emailAddress: String     name: String                      -bask et                           -                           Transaction                           date: Date orderNumber: String                                        - billingAddress: String closed: boolean                           shoppingBasketNumber: String - ShoppingBasket                        +  addLineItem() :void                -                                   + createNewAccount() : void   loadAccountDetails() :void                 + + markAccountClosed() : void   retrieveAccountDetails(): void                + + submitNewAccountDetails() : void +   validateUser(String. Sau đây là một số sơ đồ quan trọng thường được sử dụng. Các cấu trúc tĩnh (static structure): Cấu trúc tĩnh được mô hình bằng UML chính là các class diagrams.Nói chung.new: int + getStatus() : OrderStatus                   . Các khái niệm Mô hình hóa Classes Attributes Operations Object Ví dụ về mô hình class: cd Java Model                                                                   Order                                                     quantity: int LineItem                           StockItem               . packed: int        property set    + setDate(Date) : void                +  setDeliveryInstructions(String) : void              + setLineItem(LineItem) : void                +  setOrderNumber(String) : void               + setStatus(OrderStatus) : void Account   . các đặc điểm nội tại cũng như mối quan hệ giữa chúng.

Các hành vi động: State machine: Sơ đồ sau mô tả sự chuyển đổi trạng thái của một máy tính PC: Sơ đồ sau mô tả sự chuyển đổi trạng thái của một thang máy: Đây là mô hình mô tả việc chuyển đổi trạng thái của đối tượng trong quá trình tham gia các hoạt động nghiệp vụ của hệ thống. Trạng thái của đối tượng bị thay đổi bởi một hành vi nào đó. Sơ đồ hành động (activity diagrams): Đây là sơ đồ mô tả luồng nghiệp vụ trong hệ thống. 19 .

20 .Sơ đồ triển khai (Deployment Diagram): Đây là sơ đồ cho thấy các thành phần cả về phần cứng và các các gói phần mềm được triển khai như thế nào.

Các class trong hệ thống được chia thành ba loại tách biệt: M (Model) – V (View) – C (Control).Sơ đồ tương tác (interaction diagram): Đây là sơ đồ mô tả sự tương tác giữa các đối tượng theo trình tự thời gian (còn gọi là sequence diagram). các class M lưu trữ dữ liệu được mô hình hóa từ thông tin đối tượng quản lý trong khi các class C là nơi điều khiển việc dữ liệu từ M được đưa tới giao diện V như thế nào hoặc xử lý các yêu cầu từ V sau đó cập nhật vào M. Các sơ đồ sequence có thể được mô tả ở mức hệ thống (Sequence System – chỉ có user tương tác với hệ thống) hoặc mức chi tiết (Sequence Detail – Các đối tượng và thông điệp giữa chúng đã được định hình).    sd Sequence            V                                           Khach mua       DangKy               hang Page           Nhap thong tin dang ky                                                                                                                       Click "Dang Ky"       C                   M                              AccountUtilities      AccountTable                                                                               DangKyKhachHang()                                                                                                                       XacNhanThongTinDangKy()                                                          sd MuaHang                  V             C       M                                                                                                                                                                                         Chon xem san pham theo hang Khach Hang TrangChu TrangDanhMucSanPham SanPhamUtilities SanPhamTable                                                                                     Redirect                                        LayDanhSachSanPham                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 21                                                                                                                                                             HienT hi . Các class V chịu trách nhiệm hiển thị giao diện tương tác với người sử dụng.

Sơ đồ trên cho thấy một trình tự sử dụng các mô hình UML để xây dựng một ứng dụng.III. Do đó. Xuất phát từ ý tưởng ban đầu thuần túy mang tính nghiệp vụ (business). ta cần linh hoạt sử dụng các mô hình và sơ đồ để thể hiện sát đúng các yêu cầu nghiệp vụ nhằm mục tiêu cuối cùng là chương trình ứng dụng khi được triển khai sẽ gặp lỗi ít nhất. Ngoài ra. Theo quan điểm về phân tích thiết kế bằng UML thì việc lập trình rõ ràng không chỉ bắt đầu khi cài đặt các class và các sequence detail bằng một ngôn ngữ lập trình mà thực tế chúng ta đã lập trình ngay từ khi xây dựng mô hình use-case và viết text detail cho nó. Như vậy việc lập trình cài đặt chỉ được tiến hành sau khi các mô hình đã hoàn tất. Các công ty phần mềm khác nhau tuy đều ứng dụng UML nhưng có thể sử dụng các quy trình phát triển khác nhau. ta cũng cần chú ý tới tính tái sử dụng và khả năng thích ứng với các thay đổi của các mô-đun chương trình. Không nhất thiết mọi hệ thống phải sử dụng tất cả các mô hình UML nhưng quan trọng nhất là các sơ đồ đã trình bày ở trên. Trong thực tế ứng dụng UML. trong quá trình xây dựng các mô hình cần tuân thủ quy trình và liên tục tiếp xúc với khách hàng để đảm bảo tính chính xác và đầy đủ. Đến đây ta đã biết user tương tác với cụ thể đối tượng nào của system và các thông điệp giữa các đối tượng từ mô hình class. Một khi các mô hình và tài liệu đặc tả đã hoàn chỉnh. được khách hàng chấp thuận. Sau đây là một số công cụ giúp sử dụng UML trong phát triển hệ thống phần mềm: 22 . sơ đồ trạng thái và sơ đồ hành động. các bước tiếp theo cần làm song song là xây dựng mô hình use-case và vẽ phác thảo giao diện chương trình. Tiếp theo xây dựng mô hình sequence system vì thông qua giao diện ta đã biết user tương tác với system như thế nào. việc coding thực sự chỉ chiếm khoảng 20% tổng số thời gian.3 Ứng dụng UML trong quy trình làm phần mềm Như đã trình bày ở trên. UML chỉ thuần túy là một ngôn ngữ mô hình dùng cho việc mô tả mọi khía cạnh của hệ thống phục vụ cho việc xây dựng và phát triển cũng như bảo trì sau này. Sau đó xây dựng mô hình class ở mức phác thảo. Đây là cơ sở để xây dựng sequence detail và hoàn chỉnh mô hình class với các quan hệ đầy đủ.

Kết thúc mỗi quy trình cần theo dõi kết quả và kiểm tra chặt chẽ.Tuân thủ tiến trình (Adapt the process). Elaboration.Nâng cao mức độ trừu tượng (Elevate the level of abstraction). IV. Vòng đời của phần mềm theo quy trình RUP Trong một vòng đời của phần mềm.2. có 4 pha: Inception. Các nguyên tắc chính của RUP: 1. 23 . Động cơ phát triển RUP là tìm ra nguyên nhân của các lỗi phần mềm và tìm cách khắc phục chúng thông qua một quy trình.Tập trung theo dõi chất lượng liên tục (Focus continuously on quality). IV.3. 5. Lịch sử: RUP là sự phối hợp giữa cách tiếp cận công nghệ hướng đối tượng của Rational trong những năm 1980s và 1990s với công nghệ xử lý đối tượng của Ival Jarcobson.IV.Thể hiện kết quả theo quy trình lặp (Demonstrate value iteratively). 2.Cân bằng các ưu tiên của stakeholder (Balance stackeholder priorities).0 phát hành 2005. Giới thiệu về RUP Trong số các quy trình hiện nay. 6.Cộng tác giữa các nhóm (Collaborate across teams). 4. 3.1. RUP được phát triển bởi công ty Rational Software được sử dụng khá phổ biến. Stakeholder là những người đưa ra những ý kiến có ảnh hưởng lớn tới tư tưởng thiết kế hệ thống. Construction và Transition. Quy trình Rational Unified Process (RUP) phát triển phần mềm dựa trên UML IV. Phiên bản mới nhất của RUP là version 7.

• Transition: Pha chuyển giao cho khách hàng. • Inception: Đây là giai đoạn chuẩn bị.Biểu đồ trên cho biết trình tự các pha và lượng tài nguyên (resources) sử dụng cho mỗi pha. • Elaboration: Sau khi đã thu thập được yêu cầu thì đây là pha thiết kế phác thảo sử dụng các sơ đồ UML để mô hình hóa các yêu cầu. • Xác định yêu cầu (requirement): mô tả nghiệp vụ bằng phương pháp sử dụng các use-case. pha inception chủ yếu làm các công việc mang tính chất khởi động như mô hình hóa nghiệp vụ (business modeling).… • Construction: Pha xây dựng hệ thống yêu cầu sử dụng nhiều nhân lực. tài nguyên của công ty. cài đặt. • Lập trình (Implement): thực hiện các việc xây dựng chương trình bằng ngôn ngữ lập trình. các quy trình nghiệp vụ của ứng dụng. tiếp xúc với khách hàng để nắm bắt ý tưởng và thu thập yêu cầu. Tài nguyên ở đây thể hiện về nhân lực và cơ sở vật chất được huy động. vật tư kỹ thuật. 24 . • Phân tích và thiết kế (analysis & design): mô tả kiến trúc hệ thống thông qua các sơ đồ phân tích thiết kế. chuẩn bị nhân lực. Các công việc như thiết kế chi tiết. Các giai đoạn công việc của RUP bao gồm: • Mô hình hóa nghiệp vụ (business modeling): mô tả cấu trúc và quy trình nghiệp vụ. Trong biểu đồ trên. kiểm thử. Một biểu đồ khác chi tiết hơn cho ta thấy các các giai đoạn phát triển được tiến hành khi nào và mức độ sử dụng tài nguyên của chúng trong các pha theo các nguyên tắc chung. thu thập yêu cầu (requirements).…đều được tiến hành trong pha này.

triển khai. 3. Triển khai (Deployment): đưa hệ thống phần mềm vào sử dụng. Xây dựng mô hình use-case cho hệ thống quản lý việc mượn và trả sách tại thư viện. Bài tập 1. Quản trị cấu hình và quản trị thay đổi (Configuration & Change Management): kiểm soát các thay đổi và duy trì sự hợp nhất của các thành phần dự án. • Phần mềm Rational XDE: cho phép vừa xây dựng các mô hình vừa kết sinh mà nguồn chương trình song song với nhau.“Đăng nhập hệ thống” trong một hệ thống có yêu cầu xác thực account.“Mua hàng” trong hệ thống bán hàng ở siêu thị.4. xác định các tác nhân của hệ thống cùng những tình huống sử dụng. thiết kế. 2. Hãy viết text detail cho các use-case trong các hệ thống khác nhau: . IV. Hãy tiết text detail và xây dựng mô hình sequence system cho các use-case : “Mượn sách” và “Trả sách”. mà tiêu biểu và thường dùng nhất là: • Phần mềm Rational Requisite Pro: cho phép phân tích các yêu cầu. Hãy mô tả một quy trình ứng dụng UML trong phát triển hệ thống phần mềm. • Phần mềm Rational Rose: cho phép xây dựng các mô hình phân tích. 25 . Các công cụ của RUP Để áp dụng được quy trình phát triển hệ thống phần mềm của Rational thì yêu cầu không thể thiếu là hệ thống các phần mềm công cụ hỗ trợ.“Đăng ký học” trong hệ thống tuyển sinh. • Phần mềm Rational Clear Case: quản trị dự án phân tích thiết kế. tiến hành thử nghiệm hệ thống phần mềm. . xây dựng kế hoạch thực hiện. cho phép làm việc theo nhóm. .• • • • • Thử nghiệm (Test): mô tả các tình huống và kịch bản thử nghiệm. Đảm bảo môi trường (environment): đảm bảo các hạ tầng cần thiết để có thể phát triển được hệ thống. Quản trị dự án (project management): quản lý toàn bộ quá trình làm việc của dự án. Hãng Rational đã xây dựng một hệ thống công cụ như vậy.

Viết và thực hiện một chương trình Java I. Nhập môn Java I. tất cả các lệnh nằm trong cặp này đều thuộc phạm vi của lớp Vidu. } Dòng 1: Dòng chú thích trong một chương trình Java. Tuy nhiên các cặp /* và */ hay được dùng hơn vì các đoạn chú thích này sẽ được tự động đưa vào tài liệu khi ta dùng công cụ javadoc để sinh tài liệu cho mã nguồn.2. mọi chương trình nếu cần thực thi đều bắt đầu từ hàm main. Dòng 6: Câu lệnh in ra màn hình dòng chữ “Hello. Ở đây. tên file phải bắt buộc là Vidu giống như tên lớp trong chương trình. Dòng 4: Khai báo hàm main. Giả sử ghi vào thư mục C:\JavaSample. 2.. Ghi file vừa soạn với tên Vidu. trong trường hợp này. các dòng chú thích giúp ta nhanh chóng nhận ra vai trò và ý nghĩa của từng đoạn code. Các lệnh trong Java luôn được kết thúc bởi dấu . System. Dòng 5 và 7 cũng là đánh dấu mở và đóng cho một khối lệnh thuộc hàm main. Từ dấu nhắc gõ lệnh: java C:\ JavaSample\Vidu.Đề tài 2. Thực hiện chương trình Java. 3. /* Day la chuong trinh vi du*/ 2. 5.out. chọn Run và gõ vào lệnh “cmd”.1 Tìm hiểu mã nguồn một chương trình đơn giản 1. World!”. nếu chương trình không có lỗi cú pháp.java Sau lệnh này. Các chú thích trong chương trình Java được đặt trong cặp /* và */ khi cần chú thích nhiều dòng hoặc để sau cặp // khi chỉ chú thích một dòng. Cùng với dòng 8 tạo thành một cặp {} dùng để đánh dấu việc mở và đóng cho một khối lệnh. { 4.java. 7. Dòng 3. Java sẽ sinh ra một file mã bytecode có tên Vidu. Dùng một trình soạn thảo bất kỳ hoặc một IDE Java thì càng tốt để soạn chương trình. ta thực hiện theo các bước sau: 1. World!"). } 8.println("Hello. Gọi cửa sổ Command Line của Windows: Từ Menu Start. public static void main(String[] args) 5. I. Trong khi lập trình. 4. Dòng 2: Khai báo một lớp có tên Vidu. public class Vidu 3.java để trình biên dịch Java biết đây là file chứa mã nguồn Java. Để thực hiện chương trình Java trong ví dụ trên.class 26 . { 6.class mặc định cũng nằm trong thư mục C:\JavaSample. ta cần chú ý viết các dòng chú thích để mô tả về mã nguồn. Điều này rất quan trọng khi chương trình lớn và gặp lỗi. Trình thông dịch sẽ tìm hàm main làm điểm khởi phát cho một ứng dụng Java. Từ dấu nhắc gõ lệnh: javac C:\JavaSample\Vidu. Trong Java. Phần mở rộng cũng bắt buộc là .

3. Một số chú ý khi lập trình Java • Java phân biệt chữ viết hoa và viết thường. I. ta cần chú ý Windows không tự động hiểu các lệnh javac. World!”. Ở đây. /*Cac phuong thuc*/ ……………………. • Hàm main phải nằm trong file gọi thực hiện. Hàm main trong Java luôn luôn là static. • Sử dụng phương thức (method) để thay thế cho hàm và thủ tục. /*Khai bao lop chua ham main*/ public class <tên lớp> { /*Các thuoc tinh cua lop */ ……………………. Cấu trúc một chương trình Java /*Khai bao goi*/ package <tên gói>. } Các thành phần trong một chương trình Java gồm có: 1.Lệnh này sẽ thông dịch file mã bytecode Vidu. I. khi cài đặt Java ta đã đặt đường dẫn mặc định đến thư mục chứa các lệnh này là: C:\Program Files\Java\jdk1. hàm hay thủ tục bên ngoài lớp. ta phải gọi các lệnh này với đường dẫn đầy đủ của nó.6. Không được khai báo phương thức. Khai báo gói: 27 . /*Hàm main*/ public static void main(String[] args) { // Các lệnh trong hàm main } } /*Cac lop lien quan khac*/ class A { ………….4.java” • Trong Java tất cả hàm và thủ tục đều phải được đặt trong một lớp cụ thể. /*Khai bao thu vien*/ import <tên gói thư viện>. } class B { ………….0_02\bin Trường hợp chưa đặt đường dẫn mặc định. java. • Tên khai báo lớp phải trùng với tên tệp “Vidu.class và in ra màn hình dòng chữ “Hello. Tuy nhiên.

chúng đều được nhóm lại theo chức năng và mục đích sử dụng với tên gói có tính chất gợi ý. ở đây gói “java” nằm trong gói “my” và class Vidu nằm trong gói “java”. class Vidu sau khi biên dịch sẽ được đặt trong gói my. System. Nếu không làm như vậy. Trong chương trình trên.java. Ví dụ: import my. Khai báo hàm main: Không phải tất cả các class trong Java đều chứa hàm main. class Date đã được khai báo import nên không cần khai báo đầy đủ “java.println(“Hôm nay "+date).util.util.Vidu.java. 2.1 Các kiểu dữ liệu số nguyên Java có 4 kiểu số nguyên: 28 .java import my. II.*. } Ở đây. Tuy nhiên khi class đó quá phức tạp chúng ta có thể tách ra thành các class khác. 4. tất cả các class đều có phần 3. Khai báo này là không bắt buộc với một chương trình Java. Khai báo class. Tên của gói có chứa các dấu “.” chỉ sự bao gồm. hàm thành phần: Các khai báo này sẽ được bàn chi tiết trong mục “Lập trình hướng đối tượng trong Java”.java.Date. } 8. Các kiểu dữ liệu trong Java II. 5. public static void main(String[] args) { 5. Khi một chương trình Java khác muốn truy cập tới lớp Vidu.Date” tại dòng số 5. Chỉ có class được gọi thực thi đầu tiên mới cần chứa hàm main.Cú pháp: package <tên gói>. tất nhiên là bao gồm cả class Vidu. 7. Trong hàng ngàn class được Java hỗ trợ trong các gói thư viện. các phần còn lại có thể có hoặc không tùy theo nhu cầu. Date date = new Date(). //tạo biến đối tượng thuộc class Date 6. // Nhập duy nhất class Vidu trong gói my. Thực ra.out. import java. Nhập thư viện. /*Chương trình in ra ngày tháng hiện hành*/ 3. Sau đây là một chương trình ví dụ sử dụng import: 1. Cú pháp: import <tên thư viện> Nếu có khai báo này. Trong số 5 phần trên. Khai báo các lớp khác: Thông thường 1 file chương trình Java chúng ta chỉ khai báo 1 class. // Nhập tất cả các class có trong gói my.Vidu”. khi sử dụng các class nằm trong gói theo <tên thư viện> ta không cần viết đầy đủ tên gói mà chỉ cần viết tên class. ý nghĩa quan trọng của gói là việc tổ chức một cách logic các lớp vào trong các domain riêng để người phát triển ứng dụng dễ dàng truy cập. chúng ta sẽ rất khó khăn để tìm ra một class để sử dụng.java. public class Application { 4. Java dùng ký từ “*” để ngụ ý việc nhập tất cả các class trong <tên thư viện>.java. //Khai báo thư viện 2. thuộc tính. Trong trường hợp ứng dụng gồm nhiều class và cần tổ chức các class vào các gói riêng thì ta cần khai báo gói. 3. nó cần truy cập theo đường dẫn gói “my.

768 đến 32.223. II. Biến đối tượng chuỗi thường được khai báo từ lớp String nằm trong gói java. • Số 0. Chú ý: kiểu boolean không được thể hiện là 0 và 1. 647 Từ –32.147.483.40282347E+38F double 8 bytes Xấp xỉ ±1.372.648 đến 2.int short long byte 4 bytes 2 bytes 8 bytes 1 byte Từ –2. II.147.854.036.767 Từ –9.lang.2 Các kiểu số thực Java có 2 kiểu số thực dấu chấm động: float 4 bytes Xấp xỉ ±3.807 Từ –128 đến 127 II. II.854.6 Chuyển đổi giữa các kiểu số char byte short int long double float 29 . Một biến char sẽ có một giá trị là một ký tự Unicode.036. • Số âm/dương.0f).79769313486231570E+308 Số dấu chấm động có thể nhận các giá trị: • Vô cực âm/dương.808 đến 9. II.372.4 Kiểu logic (boolean) Là kiểu dữ liệu chỉ có hai giá trị true và false dùng để xác định kết quả một điều kiện.0/0.775.775.3 Kiểu ký tự (character) Là kiểu dữ liệu biểu diễn 1 ký tự unicode.5 Kiểu chuỗi Java xem chuỗi là một đối tượng.String.483. • NaN (không là một số = 0.223.

short j = 10. Các giá trị mặc định byte 0 short 0 int 0 30 . đối tượng. float y = 1. Ví dụ về khai báo biến kiểu địa chỉ: String strHello. có thể dùng các ký tự (chữ). ký tự số. short j. dấu gạch dưới. float y. Sau khi khai báo. boolean bQuit = true. Biến chỉ lưu giá trị địa chỉ đầu của một vùng nhớ được cấp phát cho đối tượng. int k = 1. • Sau ký tự đầu. // ví dụ lớp của AudioClip Khởi động giá trị cho biến Ví dụ về khởi động biến ngay lúc khai báo: byte i = 3.III. Các biến địa chỉ thường sử dụng để lưu trữ các địa chỉ mảng. long x = 1234567L. ta cần chú ý tuân thủ các điểm sau: • Chỉ bắt đầu bằng một ký tự (chữ). dấu dollard. Ví dụ khai báo cho từng kiểu biến toán học: byte i. một dấu gạch dưới (_) hay một dấu dollard ($). long x. • Không trùng với các từ khoá. Khai báo biến và hằng trong Java III. char ch. char ch = ‘T’. • Không có khoảng trống giữa tên. biến được cấp phát một vùng nhớ cố định tùy theo kích thước của kiểu dữ liệu của biến đó. con trỏ. String strHello = “Hello everybody”. boolean bQuit. III. double z = 23. • Địa chỉ: Các biến đối tượng được lưu ở dạng này.2 Khai báo biến Các biến trong Java rơi vào hai trường hợp: • Toán học: Các biến có kiểu nguyên thủy của Java đều thuộc dạng này.45d. int k.1 Quy tắc đặt tên biến Khi khai báo các biến trong chương trình Java. Ở đây cần chú ý rằng khi khởi tạo giá trị cho các kiểu số nên xác định rõ kiểu dữ liệu của giá trị. double z. //khai báo một chuỗi AudioClip music.25f.

Thông thường ta dùng kiểu khai báo thứ nhất để có thể khai báo nhiều biến mảng cùng kiểu dữ liệu: int [] intArray1. ‘b’. Truy cập các phần tử của mảng Các phần tử trong một mảng luôn được đánh số bắt đầu từ số 0. Kiểu dữ liệu của chỉ số là kiểu int. Ví dụ: int IntArray[] = {1.3 Biến kiểu mảng Khi cần làm việc với một tập các giá trị có cùng kiểu dữ liệu. 4. 5}.long 0L. double 0. intArray2. ‘c’}. Tuy nhiên nếu dùng kiểu char thì Java sẽ tự động chuyển sang mã ASCII tương ứng. //tạo mảng 10 pt Khởi tạo giá trị cho mảng Ta cũng có thể khởi tạo một mảng bằng cách liệt kê các phần tử của nó. và phần tử cuối cùng của một mảng có n phần tử là n-1. Định vị mảng Sau khi khai báo. floatArray = new float[10].//tạo mảng 100pt float floatArray[]. float 0.0d. Phần tử đầu tiên là phần tử thứ 0. for (sort i=1. Do đó.//b=1 Ta có thể gán các giá trị của mảng thông qua truy nhập vào từng phần tử của mảng. boolean false. 2. int a = IntArray[2]. bản thân mảng chưa xác định hay chưa được định vị vì chưa được cấp phát vùng nhớ . • Sử dụng cặp ngoặc vuông đặt sau kiểu dữ liệu. đều cho ta một mảng số nguyên có tên là intArray.0f. 4. ví dụ: int IntArray[] = new int[100]. Ví dụ: int [] intArray. char [] charArray = {‘a’. i<10. 5}. 2. //Phần tử thứ 0 (đầu tiên) có giá trị là 99. Khai báo: Một biến mảng được khai báo theo hai cách: • Sử dụng cặp ngoặc vuông đặt sau tên biến. ví dụ: int IntArray[] = {1. //tạo mảng 10pt intList[0] = 99. Ví dụ: int intList[] = new int[10]. i++) 31 . IntArray[] = new int[] {1. ta có thể sử dụng một biến mảng để lưu trữ chúng. Các phần tử của mảng được truy cập một cách trực tiếp bằng chỉ số của nó. intArray3. mảng cần được cấp phát vùng nhớ trước khi sử dụng. char null. hoặc int intArray[]. 4. Ví dụ b[‘a’] tương ứng với b[97]. 2. 5}. Các biến dẫn suất null III. 3. 3. Dùng từ khoá new để định vị cho một mảng trong vùng nhớ. 3.//a=3 int b = IntArray[0].

intList[i] = 1; //các phần tử còn lại bằng 1 Ví dụ: int x, y, k; x = intList[0]; //x=99 y = intList[5]; //y=1 k = intList[y+1]; //k=intList[6]=1 Mảng nhiều chiều: Khai báo mảng 2 chiều: <kiểu phần tử>[][] <tên mảng> = {<danh sách phần tử>}; Ví dụ: int[][] b = {{1,2},{3,4}}; Đây là khai báo và khởi tạo giá trị cho một mảng 2 chiều kích thước 2 x 2. {1,2} là các phần tử của hàng 1; {3,4} là các phần tử trên hàng thứ 2. Hoặc ta có thể khai báo rõ số hàng và số cột của mảng: int b[][] = new int[ 3 ][ 4 ]; Thậm chí ta có thể khai báo một mảng 3 chiều hoặc hơn. int b[][][] = {{{1,2},{3,4}},{{5,6},{7,8}}}; Ta được b[0][0][0] =1; b[0][0][1]=2;b[1][1][1]=8;b[0][1][0]=3; III.4 Hằng số (literal) Là một giá trị không đổi được sử dụng trong chương trình. Hằng số được biểu diễn như chính nó chứ không là một giá trị của biến hay một kết quả của biểu thức. Giá trị của hằng số không thể bị thay đổi. Ví dụ: Pi = 3.1415. Tên của hằng số được đặt tên như tên biến. Cách khai báo hằng cũng tương tự như biến nhưng có dùng thêm từ khóa final: <phạm vi> final <kiểu dữ liệu của hằng> <tên hằng> = <giá trị> Ví dụ: public final String mauda ="vang"; Hằng số có thể là: Hằng số nguyên: Hằng có thể được biểu diễn dưới dạng thập phân, bát phân, thập lục phân. Ví dụ: biểu diễn số 15 dạng int: 15. dạng long: 15L. dạng bát phân: 017. dạng thập lục phân: 0xF. Hằng số thực: Tương tự như hằng số nguyên, để chỉ rõ hằng là float ta thêm vĩ ngữ “ f ” hay “F”, hằng là double ta thêm “d” hay “D”. Hằng Boolean: Một hằng số kiểu boolean có giá trị là true hoặc false. Trong Java, các giá trị 0 và 1 không được dùng thay thế cho false và true như trong C hoặc C++. Hằng ký tự: Là một ký tự đơn giản hay một chuỗi ESCAPE, hằng ký tự được đặt trong hai dấu ngoặc đơn ‘’. Các chuỗi ESCAPE: ‘\b’ : Xoá lùi. ‘\n’ : Xuống dòng. ‘\t’ : Tab ngang. 32

‘\f’ : đẩy trang. ‘\r’ : dấu enter. ‘\”’ : nháy kép. ‘\’’ : nháy đơn. ‘\\’ : sổ ngược. ‘uxxxx’: ký tự unicode. Ví dụ: System.out.println(“Xin chào bạn \n Nguyễn Văn A”); Sẽ in ra màn hình kết quả: Xin chào bạn Nguyễn Văn A Hằng chuỗi ký tự: Một hằng chuỗi ký tự có thể có 0 ký tự (hằng chuỗi rỗng) hay nhiều ký tự. Ví dụ: “A String”, “” //chuỗi rỗng, “dong 1 \t\n dong 2”. III.5 Phạm vi hoạt động của hằng và biến: Khối lệnh Block 1 chứa 2 khối lệnh con Block 2, Block 3.

{ Block 1
{ Block 2 }

{
Block 3

}

}
Biến hay hằng sẽ chỉ có ý nghĩa trong phạm vi khối lệnh mà nó được khai báo.

IV. Các toán tử và biểu thức
IV.1 Các toán tử và thứ tự ưu tiên Các toán tử thường sử dụng: Toán tử Ý nghĩa = Gán != so sánh khác > so sánh lớn hơn < so sánh nhỏ hơn >= lớn hơn hoặc bằng <= nhỏ hơn hoặc bằng + cộng trừ * Nhân

Ví dụ x=10 x!=5 x>5 x<20 x>=10 x<=10 y=x+1 y=x-1 y=x*3

33

/ % ++ -+= -= *= /= ^ | & ! && || ==

Chia Lấy phần dư tăng giá trị lên 1 giảm giá trị đi 1 cộng kết hợp phép gán trừ kết hợp phép gán nhân kết hợp phép gán chia kết hợp phép gán phép XOR trên bit phép OR trên bit phép và trên bit Toán tử logic NOT Toán tử logic AND Toán tử logic OR So sánh bằng nhau

y=x/3 10%3 = 1 x++ x-x+=y tương đương x=x+y x-=y tương đương x=x-y x*=y tương đương x=x*y x/=y tương đương x=x/y x^y x|y

Thứ tự ưu tiên: ( ), *, /, %, +, -,= =, !=, &, ^, |, &&, ||, =, %=, /=, *=, -=, += IV.2 Biểu thức Biểu thức là sự kết hợp các biến số, các giá trị bởi các toán tử hoặc có thể là một phép gán giá trị một biểu thức cho một biến số. Ví dụ: (x+3)/(y-2); 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ả 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à các giá trị true hay false. Khi sử dụng câu lệnh gán kết quả của một biểu thức cho một biến, ta cần chú ý tới vấn đề đồng nhất kiểu dữ liệu giữa hai vế để tránh mất thông tin. Ví dụ: double delta = 0.0d; //khai báo một biến số thực có tên delta. delta = 1/ 100; // Gán cho delta kết quả của phép chia 1 cho 100. Trong tình huống này, ta không thu được delta = 0.01 như mong đợi mà là delta =0. Lý do là các số 1 và 100 đều được hiểu là các số nguyên và kết quả của phép chia được tự động làm tròn thành một giá trị nguyên trước khi gán cho delta. Để khắc phục tình trạng này, ta cần xác định rõ các số 1 và 100 là các số double. delta = 1d/100d;

V. Các lệnh điều khiển rẽ nhánh
V.1 Lệnh if Lệnh if...{...}: là một phép kiểm tra giá trị của một biểu thức boolean, nếu cho giá trị là true thì khối lệnh sẽ được thực hiện. Cấu trúc: if <biểu thức boolean>

34

case . case <giá trị n>: <khối lệnh n>. int y=x-1. } Nếu biểu thức boolean đúng thì <khối lệnh 1> được thực hiện.. còn nếu biểu thức đó sai thì khối lệnh sẽ bị bỏ qua. case <giá trị 2>: <khối lệnh 2>... Cấu trúc: switch <biểu thức>{ case <giá trị 1>: <khối lệnh 1>. } }} Dạng 2 của câu lệnh if: if <biểu thức boolean> { <khối lệnh 1>. } Nếu biểu thức boolean đúng.println("x<y").2.out. if (x<y) { System. . } else { <khối lệnh 2>.{ <khối lệnh>.println("x>y"). Ví dụ: public class dkIfThen { public static void main(String[] args) { int x=1. } else { System. if (x<y) { System.. break. khối lệnh sẽ được thực hiện.println("x>y"). int y=x+1. break..: Cho phép chọn nhiều trường hợp xảy ra của giá trị so sánh. default: <khối lệnh default>. break.out. break..out. }}} V. Ví dụ: public class dkIfThen { public static void main(String[] args) { int x=1. Lệnh switch …case Lệnh switch . còn nếu biểu thức boolean sai thì <khối lệnh 2> được thực hiện. } 35 .

4. [<bước nhảy>]) { <Khối lệnh>. Các lệnh lặp VI. Sau mỗi lần thực hiện xong <khối lệnh>. VI.1. Nếu biểu thức kiểm tra là true thì lại thực hiện khối lệnh. vòng lặp chấm dứt.length.1. <giá trị 2>. for (int i=0. Lưu đồ hoạt động của vòng lặp for như sau: Biểu thức biến điều khiển Biểu thức điều chỉnh theo bước nhảy Biểu thức kiểm tra true false Thực hiện khối lệnh Kết thúc vòng for Ví dụ: tính tổng 1 dãy số thực public class vdFor { public static void main(String[] args) { double accounts[]={1. Vòng lặp for Khi muốn một khối lệnh được thực hiện với một số lần biết trước. ta có thể sử dụng một vòng lặp for. } Bắt đầu với giá trị <khởi tạo> của biến đếm.i<accounts. [<biểu thức kiểm tra>]. 36 . <khối lệnh> được thực hiện. Cấu trúc lệnh: for([<khởi tạo>]. còn nếu là false.2.i++){ sum+=accounts[i].Một số chú ý khi sử dụng lệnh switch-case: Các giá trị: <giá trị 1>.6}. biến đếm thay đổi giá trị một lượng bằng <bước nhảy> và <biểu thức kiểm tra> được tính lại. double sum=0. các lệnh tiếp theo sẽ được thực hiện.1.…<giá trị n> phải là các hằng số. Nếu không sử dụng lệnh break mỗi khi kết thúc các khối lệnh thì sau khi thực hiện xong khối lệnh.

j++) { [các câu lệnh.2 Các vòng for có thể được đặt lồng nhau nếu cần Ví dụ: for(int i=0. } [các câu lệnh. Vòng lặp while Khi một khối lệnh cần được thực hiện. } }//kết quả là: 4. ta có thể sử dụng vòng lặp while. } Khối lệnh được thực hiện khi <bt boolean> còn có giá trị true.} System. Chú ý: trong khối lệnh phải có câu lệnh có tác dụng ảnh hưởng tới kết quả <bt boolean> để vòng lặp có thể dừng..println(sum). ] . Lưu đồ thực hiện: Bt boolean false true Các câu lệnh Câu lệnh tiếp theo 37 . ] } VI. thường là với một số lần không được biết trước. j<5. ] for(int j=0.out.. i++) { [các câu lệnh. Cấu trúc lệnh: while <bt boolean> { <Khối lệnh>.2. i<10.

Nếu <biểu thức boolean> có giá trị true thì tiếp tục thực hiện <khối lệnh>. } lệnh 4. việc thực hiện các vòng lặp đôi khi không theo hết vòng mà có thể dừng hoặc thoát khỏi vòng lặp.. Việc nhảy ra khỏi vòng lặp được thực hiện với lệnh break hoặc kết thúc vòng hiện tại với lệnh continue. } while <biểu thức boolean>. } } //kết quả là: 55 VI.3. Khi thực hiện vòng lặp duyệt dãy.println(sum). while Vòng lặp này có ý nghĩa tương tự như vòng lặp while nhưng <khối lệnh> được thực hiện ngay ở vòng đầu tiên mà chưa cần kiểm tra kết quả <biểu thức boolean>. Vòng lặp do. Vòng lặp này cho thực hiện <khối lệnh> rồi mới kiểm tra <biểu thức boolean>.VI. Ví dụ: Tìm một giá trị nào đó trong một dãy 1000 phần tử. nếu tìm thấy phải thôi duyệt dãy ngay. Cấu trúc lệnh: do { <khối lệnh>. System. nếu không sẽ dừng vòng lặp. lệnh 3. } while (x<11). Ví dụ: while <bt boolean 1>{ lệnh 1. so sánh các phần tử của dãy với giá trị cần tìm từ phần tử đầu tiên cho đến phần tử cuối cùng. Ví dụ: while <bt boolean 1>{ 38 . if <bt boolean 2> break.out. x++.4. Lệnh continue Cho phép chương trình bỏ qua vòng hiện tại và nhảy đến vòng tiếp theo. Ví dụ tính tổng 10 số nguyên dương đầu tiên: public class vdDoWhile { public static void main(String[] args) { int x=1. Phép nhảy Trong một số trường hợp.. Lệnh break Lệnh này kết thúc ngay vòng lặp trong cùng (nếu có nhiều vòng lồng nhau) chứa nó. sum=0. lệnh 2. do{ sum+=x.

Next year.println("Hello.nextInt().out. } lệnh 3. if <bt boolean 2> { ……. Khai báo biến thuộc lớp Scanner.Scanner nhap = new java. VII.in). // Lay gia trị nhap ho ten System.print("What is your name? "). Vào dữ liệu từ bàn phím và xuất dữ liệu ra màn hình VII.nextInt(). 2.*. ta làm theo các bước sau: 1.next(). // Khai báo một biến Scanner có tên là “nhap”.Scanner(System.*/ String name = nhap. Java. continue.in). lệnh continue được thực hiện. // In ra màn hình một câu hỏi tên /* Khai báo và gán giá trị nhập từ bàn phím cho một biến kiểu String có tên name.util. } } 39 . Nếu đọc vào một số nguyên: int Tuoi = nhap. Ví dụ: import java. int age = nhap. you'll be " + (age + 1)).util. String name = nhap. Lớp Scanner chỉ được hỗ trợ từ phiên bản Java 1. // Hien thi ket qua nhap tren man hinh System.1.nextLine(). Lấy giá trị nhập vào: System.nextLine().util.out. Để đọc 1 từ trong chuỗi nhập vào: String firstName = nhap.print("How old are you? ").print("What is your name? ").out.. Lấy giá trị nhập vào từ bàn phím Để lấy giá trị mà người sử dụng nhập từ bàn phím. // Lay gia tri nhap tiep theo System.5 và nằm trong gói java.out.util. chương trình sẽ không thực hiện tiếp <lệnh 3> mà quay lại kiểm tra <bt boolean 1>. } lệnh 4.lệnh 1. public class InputTest { public static void main(String[] args) { Scanner nhap = new Scanner(System. Tương tự cho các kiểu dữ liệu khác. Khi <bt boolean 2> có giá trị true. lệnh 2. " + name + ".

/*In ra số nguyên ở hệ cơ số 16*/ System.out.9 0x1. /*In ra ký tự đặc biệt “” */ System.printf("He 16 cua 100 duoc viet la: %x \n". }} Lưu ý rằng khi sử dụng các ký tự định dạng ta cần dùng hàm System.3f \n". 10/3).fccdp3 Hello H True 42628b2 Số thực float theo ký pháp cơ số e 1.printf() thay vì System.out.printf(“Hello.printf("Ket qua 3 so sau dau phay la %10. /*In ra số thực chiếm 10 ký tự trên màn hình trong đó phần thập phân chiếm 3 ký tự*/ System.sothuc).VII.money).print("\"Mot tram phan tram\" thi in ra the nao: 100%"). int songuyen =100. name.out.out. System.2 Kết xuất dữ liệu ra màn hình Trong các chương trình ví dụ trên.songuyen).out.print để in dữ liệu ra màn hình.printf("He 8 cua 100 duoc viet la: %o \n". trong một số trường hợp ta cần định dạng dữ liệu xuất ra chẳng hạn như hiển thị một số thực dạng thập phân với độ chính xác nhất định.out.println() như thường lệ.songuyen). public class TestFormat { public static void main(String[] argvs) { double sothuc = 10.1f”.59e+01 Sau đây là ví dụ sử dụng các ký tự định dạng khi xuất dữ liệu ra màn hình.print() hay System. Sau đây là bảng các ký tự định dạng: Ký tự định dạng D X O F E A S C B H tx % N Định dạng Số nguyên thập phân Số nguyên hệ 16 Số nguyên hệ 8 Số thực float Số thực float dạng Hexa String Ký tự Boolean Hash code Date and time Ký hiệu phần trăm Xuống dòng % Ví dụ 159 9f 237 15. Tuy nhiên. %s. ta đã biết dùng hàm System.out. 40 . /*In ra số nguyên ở hệ cơ số 8*/ System.out. You have %f VND ”.out.out.09898765.printf(“%8. System.

4. } c) Đoạn mã sau sẽ in ra các số nguyên lẻ từ 19 đến 1 ?: for ( x = 19.println(). 3. và . } } } 7. Viết chương trình tính giá trị các biểu thức (Giá trị n. Viết chương trình in ra màn hình các mẫu như sau: 41 .print( '@' ).out. do { System. x >= 1. hãy sửa lại các ký tự đầu các từ cho đúng quy định viết hoa và khoảng cách giữa các từ. } While ( counter < 100 ).println( "Odd integer" ). Tìm các lỗi trong các đoạn chương trình sau: a) For ( x = 100.println( x ). x >= 1.out. x += 2 ) System. b) Đoạn mã sau sẽ in ra các giá trị chẵn hay lẻ: switch ( value % 2 ) { case 0: System.println( counter ). case 1: System.out. Các từ cách nhau bởi dấu space.out. Cho biết số nguyên đầu tiên nhập vào sẽ chính là số các con số được nhập. System. x++ ) System. Ví dụ: nguyen van nam -> Nguyen Van Nam 5. 2.1/4! + … + 1/(2k+1)! . counter += 2. k. Đoạn chương trình sau làm gì? public class Printing { public static void main( String args[] ) { for ( int i = 1.println( x ).out. Viết chương trình đếm tần suất xuất hiện của các từ trong một chuỗi nhập từ bàn phím.Bài tập 1. j++ ) System.println( "Even integer" ).out. Nhập vào một chuỗi họ tên của một người. j <= 5. d) Đoạn mã sau sẽ in ra các số nguyên chẵn từ 2 đến 100 ?: counter = 2.. 8. Viết chương trình đếm số từ có trong một chuỗi ký tự nhập vào. Viết chương trình tìm số nhỏ nhất trong số các số được nhập vào từ bàn phím.….…nhập từ bàn phím): A = 1 + 1/2! + 1/3! + … + 1/n! B = 1/1! – 1/2! + 1/3! . 6. i++ ) { for ( int j = 1.out. i <= 10.

141. 42 .9. Tính số PI theo công thức sau: In ra 10 giá trị chính xác hơn 3.

OOP là phương thức tư duy mới để giải quyết vấn đề bằng máy tính. Khái niệm lập trình hướng đối tượng (Object-Oriented Programming . I. cách thức vận động riêng. Khái niệm OOP Lập trình hướng đối tượng là sự cài đặt một chương trình theo hướng đối tượng bằng các ngôn ngữ lập trình. Môi trường này bao gồm một thư viện được thiết kế tốt. Vậy làm thế nào để đưa chúng vào máy tính? Câu trả lời là chúng ta cần một quá trình trừu tượng hóa. Lập trình hướng đối tượng trong Java I. Thực tế thì ta không thể viết chương trình hướng đối tượng bằng các ngôn ngữ cấu trúc (như Pascal chẳng hạn) vì các ngôn ngữ này không hỗ trợ cú pháp cài đặt và kỹ thuật biên dịch các đặc tính của hướng đối tượng. Như vậy. lập trình viên phải nắm được sự tương ứng giữa các các đối tượng thực tế. Ngôn ngữ OOP cung cấp đầy đủ phương tiện để thực hiện điều này. Hơn nữa. từ nghiệp vụ thực tế chúng ta không thể ngay lập tức đem vào cài đặt trong ngôn ngữ OOP mà phải qua một quy trình phân tích và thiết kế theo hướng đối tượng như chúng ta đã thấy qua việc nghiên cứu ngôn ngữ mô hình hóa UML – một ngôn ngữ giúp chúng ta trừu tượng hóa thế giới thực. chúng sở hữu các tính chất và thuộc tính riêng. 43 . Do đó. Quan sát thế giới thực. ta thấy mọi vật đều có vị trí riêng của nó. thường là ngôn ngữ OOP. Thông tin về đối tượng và mối quan hệ giữa chúng thực tế là vô cùng. mối quan hệ giữa chúng và sự hỗ trợ của ngôn ngữ để cài đặt chúng vào máy tính. I.1. Chúng ta gọi chúng là những đối tượng. 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. Đây là một điểm mạnh của OOP và phương pháp trước đây không có được. 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. các dự án phần mềm phân tích và thiết kế theo UML bắt buộc phải sử dụng kỹ thuật OOP để cài đặt thì mới phát huy hiệu quả.2 Cơ sở lý luận của OOP Chúng ta thấy rằng thuật ngữ “hướng đối tượng” có nghĩa là lấy đối tượng làm trung tâm và tất cả nằm trong đối tượng. khai thác thông tin cũng như các mối quan hệ từ chúng hoặc thay đổi trạng thái của chúng. thuận lợi cho việc sử dụng kế thừa các đối tượng – tính tái sử dụng. nếu dùng một ngôn ngữ OOP mà chương trình không theo hướng đối tượng thì cũng không phải là lập trình OOP. Trong khi nếu dùng một ngôn ngữ không hướng đối tượng để viết một chương trình OOP (rất khó khăn) thì cũng có thể gọi là lập trình OOP. các hành vi.OOP) I. Đố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. Để đạt kết quả.3 Trừu tượng hóa Quản lý thông tin. Theo cách hiểu như vậy thì mọi nghiệp vụ thực tế suy cho cùng chỉ là việc quản lý các đố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.Đề tài 3. các mối quan hệ của các đối tượng là nhiệm vụ mà lập trình OOP phải làm. Tuy nhiên.

ta cũng rút ra nhận xét rằng quá trình trừu tượng hóa tùy theo yêu cầu nghiệp vụ sẽ cho kết quả khác nhau. Các mối quan hệ giữa các thực thể trong thế giới thực được mô hình hóa bằng các mối quan hệ giữa các lớp đối tượng. chúng ta có một mô hình trừu tượng hóa của một sinh viên: Sinh viên Họ và tên Ngày sinh Tên lớp Địa chỉ Điểm môn học Thay đổi lớp Thay đổi nơi ở Điểm quan trọng là sau khi trừu tượng hóa từ một lớp các sinh viên (tất cả các sinh viên trong phạm vi quản lý). nhóm máu. Ở đây ta không quan tâm tới giá trị cụ thể của các thuộc tính này. Một hệ thống quản lý sinh viên có thể chỉ cần quan tâm tới: Họ và tên. Trong khi đó. chúng ta có một câu hỏi: Cái gì làm cho dữ liệu này biến đối? Câu trả lời là chính hành vi của đối tượng làm cho thuộc tính của chúng bị thay đổi. các thông tin khác về sinh viên – cũng là một con người – như chiều cao.Classes Trừu tượng hóa Thế giới thực = Các đối tượng + Các mối quan hệ • • Tóm lại: Các thực thể tồn tại trong thế giới thực được mô hình hóa thành các lớp đối tượng. Một quá trình suy luận như vậy là một quá trình trừu tượng hóa dữ liệu. Cũng là một sinh viên nhưng nếu chẳng may anh ta bị ốm nằm viện. địa chỉ nơi ở.…và tất nhiên là cũng có các mô hình hành vi khác. điểm các môn học. anh ta được quản lý như một bệnh nhân. Khi quan tâm tới giá trị của các thuộc tính. Tóm lại.Giả sử đối tượng quản lý là một sinh viên. Các lớp đối tượng trong chương trình . Quá trình xác định các hành vi của đối tượng phục vụ cho nghiệp vụ quản lý cũng là một quá trình trừu tượng hóa hành vi. cân nặng. ngày sinh. cân nặng.… chúng ta không cần quan tâm. mô hình này đại diện cho tất cả sinh viên và là khuôn mẫu để tạo ra bất kỳ sinh viên nào khác. một anh sinh viên bất kỳ có thể có hành vi “xin đổi lớp học” hoặc “đổi địa chỉ nơi ở” làm cho giá trị các thuộc tính “lớp học”. huyết áp. Trong ví dụ trên. Qua đây. Một hệ thống quản lý bệnh nhân tất nhiên không thể bỏ qua các thông tin về nhóm máu. “địa chỉ nơi ở” bị thay đổi. 44 . lớp học.

II. Mỗi HoaDonThanhToanNhanh thừa kế các thuộc tính và phương thức của HoaDon và có thêm các thuộc tính. • Khởi tạo cho dữ liệu: Các thuộc tính nên được khởi tạo bằng các phương thức constructor khi một đối tượng mới được tạo ra. II. Đối tượng được sinh ra bởi class . • Bao gồm (Aggregation): Class A có quan hệ bao gồm với class B nếu đối tượng của class A chứa đối tượng của class B. Thuộc tính được cài đặt thông qua mã lệnh Java bằng các biến thành phần trong lớp. phương thức khác: Quan hệ inheritance.1 Khái niệm tính đóng gói Tính đóng gói thể hiện bởi việc thuộc tính mô tả đối tượng và hành vi của đối tượng được gắn chặt với nhau. object = attributes (các thuộc tính) + operations(các hành vi) + name (tên định danh) Như vậy tính đóng gói thể hiện việc chuyển mô hình đối tượng thực tế thành các lớp trong Java.2 Mối quan hệ giữa các class Các class trong chương trình có thể quan hệ với nhau theo 1 trong 3 dạng: • Phụ thuộc (Dependence): Class A có quan hệ phụ thuộc với class B nếu phương thức của class A có sử dụng đối tượng thuộc class B. Ví dụ: Trong hệ thống bán hàng chúng ta có: • class DanhMucMatHang • class TaiKhoan • class HoaDon • class HoaDonThanhToanNhanh Mỗi HoaDon bao gồm 1 DanhMucMatHang: Quan hệ aggregation. Tính đóng gói trong Java II. • Không sử dụng quá nhiều kiểu dữ liệu cơ bản trong 1 lớp • Không phải thuộc tính nào cũng cần mutator và accesor: Mỗi thuộc tính thường có một phương thức thiết đặt giá trị cho nó gọi là mutator (tiền tố set) và một phương 45 . Thuộc tính thể hiện trạng thái đối tượng. Khi một HoaDon được tạo ra. ngoài ra class B còn định nghĩa các phương thức và thuộc tính khác của riêng nó. private. Cấp độ public cho phép sự truy cập từ bên ngoài lớp trong khi private chỉ cho phép nội bộ lớp truy cập. hành vi làm thay đổi trạng thái đối tượng thông qua việc thay đổi giá trị các thuộc tính.II. nó cần truy cập đến class TaiKhoan để kiểm tra tình trạng thẻ tín dụng: Quan hệ dependence.một sự mô hình hóa một lớp đối tượng trong thực tế. • Thừa kế (inheritance): Class B gọi là thừa kế class A nếu class B có các phương thức và thuộc tính của class A.3 Một số gợi ý khi thiết kế class • Khai báo dữ liệu private: Điều này tránh việc truy cập tùy ý từ bên ngoài lớp. Thông tin và hành vi đối tượng được bảo vệ bằng các cấp độ truy cập: public. Hành vi được cài đặt thông qua mã lệnh Java bởi các phương thức.

lang java.com/j2se/1. Các gói thư viện quan trọng của Java 2 bao gồm: (tham khảo chi tiết tại: http://java.awt.math java.util javax. Sử dụng các Class xây dựng sẵn trong thư viện Java hỗ trợ cho lập trình viên một thư viện phong phú các lớp đối tượng đã được xây dựng và thiết kế cẩn thận. ngày tháng.font java. Tuy nhiên điều này là không bắt buộc.text java. Cung cấp các gói cho lập trình RMI – Remote Method Invocation. Hỗ trợ các giao diện và lớp liên quan đến font chữ.awt.print java. 46 .image java. Chứa các lớp liên quan tới việc phát triển các thành phần (beans) dựa trên kiến trúc của Java.awt. numbers và các thông điệp.sql java. Cung cấp các lớp và giao diện cho việc xử lý các vấn đề an ninh và bảo mật trong Java.….awt java. dates. Chứa các lớp dùng để tạo ra các giao diện người dùng và cho các thao tác vẽ các hình đồ họa và ảnh. Tách các class phức tạp. Cung cấp các lớp cho việc cài đặt các ứng dụng mạng. Cung cấp các lớp cho không gian màu.security java.color java.2/docs/api/overview-summary.net java.html ) Các gói thường dùng trong Java 2 SE java.applet java.crypto Hỗ trợ các class cần thiết cho việc tạo ra các Applet và giao tiếp giữa Applet với môi trường ngữ cảnh của nó. Cung cấp các lớp tạo và hiệu chỉnh hình ảnh.event java. Hỗ trợ các lớp và giao diện cho các thao tác mã hóa dữ liệu. Chứa đựng các lớp tiện ích thuộc nhiều loại khác nhau như sinh số ngẫu nhiên.4.rmi java. Cung cấp các lớp và giao diện cho việc quản lý text.• • thức lấy ra giá trị của nó gọi là accesor (tiền tố get).beans java.awt. Lập trình viên chỉ cần biết cách lấy chúng ra và sử dụng chúng theo kịch bản của ứng dụng.sun. Cung cấp các lớp nền tảng để thiết kế ngôn ngữ lập trình Java.awt.io java. Cung cấp các lớp và giao diện cho mục đích in ấn. IV. Hỗ trợ các lớp để thao tác và thuật toán với các số nguyên lớn BigInteger và BigDecimal. Hỗ trợ cho các thao tác vào / ra dữ liệu trên hệ thống file. Cung cấp các giao diện và các lớp cho việc giải quyết các vấn đề về xử lý các sự kiện trên các thành phần giao diện AWT. Đặt tên phương thức và thuộc tính phản ánh theo tính chất và nghiệp vụ của nó. Cung cấp các hàm API cho việc truy cập vào dữ liệu trong một nguồn dữ liệu – thường là các CSDL quan hệ.

Một đối tượng luôn được tạo ra từ một constructor của lớp đó.swing.tree javax. mặc định là public.swing javax. không được khởi tạo đối tượng của lớp này. Các vấn đề của công việc thiết kế một lớp bằng ngôn ngữ Java sẽ được đề cập dưới đây. 47 . Xác định rằng myDate là một đối tượng thực sự thuộc class Date.swing.table javax. Cung cấp các lớp và giao diện làm việc với bảng. Xác định cho ta một biến đối tượng Date nhưng không cho ta một đối tượng Date thực sự vì trong thực tế. Các lớp trừu tượng được thiết kế chỉ cho mục đích kế thừa.swing.javax. Khai báo: Date myDate. // In ra tháng hiện tại V. Hỗ trợ các lớp cho việc xử lý các tài liệu XML. • Nếu <cách truy xuất> không được xác định. Cung cấp các lớp cơ bản cho các dịch vụ in ấn qua mạng. Xây dựng Class trong Java Cài đặt các lớp là công việc thường xuyên của lập trình viên Java. Cung cấp một tập các thành phần giao diện được chấp nhận và thống nhất trên hầu hết các hệ thống máy tính. myDate chưa được cấp phát vùng nhớ. V. Câu lệnh: myDate = new Date(). Cung cấp các hàm API cho việc truy cập dữ liệu phía server. Cung cấp các lớp và giao diện làm việc với cây javax.JTree. Hỗ trợ cho các sự kiện kích hoạt bởi các thành phần của Swing.swing. } Ta sẽ lần lượt xem xét từng thành phần: <Cách truy xuất>: • public: Có thể truy cập lớp từ các lớp khác.1 Cấu trúc của class [<Cách truy xuất>] class <tên lớp> [extends <tên lớp cha>] [implements <tên giao diện>] { <các thành phần của lớp>.print javax. ta có thể áp dụng các phương thức và thuộc tính của class Date cho myDate. • abstract: Lớp trừu tượng.event javax. • final: Không cho phép kế thừa. Sau đây là hướng dẫn ví dụ về sử dụng lớp Date có sẵn trong thư viện của Java: Khai báo biến đối tượng với toán tử new Date myDate = new Date().out. System.println(myDate.xml. Date() là phương thức contructor của class Date.sql javax.getMonth()).net javax.parsers Cung cấp các lớp cho lập trình mạng.

MaSo = 10. Trong khi đó các hằng thường luôn được khai báo là public vì chúng được dùng chung và không thể bị thay đổi do từ khóa final (hằng). Truy cập vào biến Tuoi như sau: sv. các lớp đối tượng thường có các thuộc tính chung. <tên lớp cha>: Tên của lớp cha mà lớp hiện tại thừa kế. Khi truy cập.Tuoi=21. • private: Chỉ được truy cập trong chính lớp đó. Khi truy cập ta chỉ cần gọi: Math. khi chúng đã không phụ thuộc vào một đối tượng cụ thể nào thì ta cũng không cần khởi tạo một đối tượng để truy cập. Do đó. nếu <cách truy xuất > là public thì tên lớp phải trùng với tên file chứa lớp. • protected: Chỉ được truy cập trong lớp đó và các lớp kế thừa. SinhVien sv = new SinhVien(20. Hơn nữa. phụ thuộc vào biến thuộc dạng nào trong 2 dạng sau: 1. Ta sẽ lần lượt xem xét tới các thành phần này. trước hết phải khởi tạo một đối tượng thuộc lớp. Khi khai báo trong lớp chúng thường được xác định phạm vi hoạt động là một trong các dạng: • public: Biến có thể truy cập ở bất cứ lớp nào. Đây có thể là một danh sách các giao diện phân tách bởi dấu “. Biến có phạm vi lớp (biến tĩnh): Đây là biến có phạm vi tồn tại trong mọi đối tượng của lớp được tạo ra trong chương trình đang chạy. ta có thể không cần khởi tạo đối tượng mà trực tiếp thông qua tên lớp: SinhVien. Mặc định thì phạm vi truy cập của biến là public. cố định có ở mọi đối tượng. Lý do là trong thực tế. // Mọi sinh viên đều có màu da là “Vang” hoặc khái báo hằng số PI: public static final double PI = 3. ta cần thêm từ khóa static như ví dụ sau: public static int MaSo.”. Ví dụ: public int Tuoi.<tên lớp>: Tên của lớp. 48 . Ví dụ: public static final String MauDa = “Vang”. trong khi các hằng static lại rất hay được dùng. V. Khi khai báo một biến có phạm vi lớp. Là hằng số của lớp Math.PI Chú ý: Các biến rất ít khi được khai báo là public vì có thể thay đổi giá trị của nó bên ngoài lớp nên khó quản lý. private String HoVaTen. Các biến có phạm vi lớp rất ít khi được sử dụng. 2. ví dụ gán Tuoi của sinh viên này bằng 21: Sv. Giá trị của biến được dùng chung giữa các đối tượng. Biến this Biến this là biến đối tượng của lớp tồn tại ngầm trong mỗi lớp. Muốn truy cập vào biến. Cách truy cập biến rất đơn giản.14159265358979323846. <các thành phần của lớp>: đây là phần thân của lớp chứa các định nghĩa cho các thuộc tính và các phương thức thành phần. <tên giao diện>: Tên của giao diện được cài đặt tại lớp.2 Các thuộc tính thành phần: Khai báo thuộc tính chính là việc khai báo các biến.”Nguyen Van A”). ta sẽ cài đặt chúng như là các hằng static. các biến thông thường có phạm vi private. Biến có phạm vi đối tượng: Đây là biến tồn tại cùng với sự tồn tại của đối tượng.Tuoi.

khi kết thúc các luồng xử lý trong phương thức nhất thiết phải có câu lệnh return để trả về một giá trị thuộc kiểu đó. public void PrintNumber() { int number =20. <Kiểu giá trị trả về>: integer.//in bien number =10 } } V. .out. Khi xác định kiểu giá trị trả về. Ví dụ: public class TestThis { private int number = 10. Lớp có chứa phương thức abstract cũng phải được khai báo abstract.number).. • abstract: phương thức đơn giản nhất. • protected: chỉ các lớp là dẫn xuất của lớp chứa phương này mới truy xuất được nó. các phương thức sẽ có cách truy xuất mặc định là public. 49 . void: phương thức không trả về giá trị. nó có thể được gọi mà không cần khởi tạo đối tượng của lớp. float. không cài đặt gì ở trong lớp khai báo nó.out. • Nếu không khai rõ cách truy xuất.Thường dùng biến this để truy cập đến các thuộc tính của lớp bị khai báo trùng trong phạm vi các phương thức của lớp. Các phương thức khai báo chồng ở lớp dẫn xuất phải có mức độ truy cập mạnh hơn hoặc giống với mức độ truy cập ở lớp cha.3 Các phương thức thành phần Phương thức thành phần là sự cài đặt các hành vi của đối tượng. String. // khai báo trùng với biến của lớp System. • native: là phương thức được viết bằng ngôn ngữ khác java. Cú pháp khai báo một phương thức trong lớp như sau: [<Cách truy xuất> <cách cập nhật>] <Kiểu giá trị trả về> <Tên phương thức>([<danh sách biến hình thức>]) [<mệnh đề throws>] { <Nội dung của phương thức>.. char. • synchronyzed: đảm bảo dữ liệu không bị sai lạc khi cùng một lúc 2 phương thức truy cập cùng một dữ liệu.: là các kiểu dữ liệu mà phương thức trả về.println(this. • public: có thể truy xuất từ bất kỳ lớp bên ngoài nào. • final: phương thức 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. tức là nó không có phần thân. //in bien number = 20 System. < Cách cập nhật> • static: phương thức tác động không phụ thuộc vào các đối tượng cụ thể. 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 chứa nó.println(number). } <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ó.

50 .println(max(3. Vì nó được gọi khi chưa có đối tượng nào được tạo ra nên nó luôn được khai báo là static.4 Gọi và truyền tham số cho phương thức • Các tham số kiểu cơ bản được truyền theo kiểu tham trị. Tuy nhiên. V. Gọi một phương thức: Có 2 cách gọi phương thức: Nếu phương thức trả về giá trị.public static int max(int num1.println("Hello!"). 5). Phương thức khởi tạo có cùng tên với tên lớp và không có kiểu dữ liệu trả về.out. Ví dụ: int larger = max(3. • Các tham số có kiểu đối tượng được truyền theo kiểu tham chiếu. • Phương thức không thể làm cho tham số đối tượng tham chiếu tới một đối tượng mới. việc gọi phương thức là câu lệnh. nó chỉ được định nghĩa cho chính lớp cha. Mỗi lớp có thể có 1 hoặc nhiều phương thức khởi tạo. 5)). hoặc ta có thể in giá trị trả về của cuộc gọi phương thức: System.6 Các hàm và phương thức đặc biệt Phương thức khởi tạo: Phương thức khởi tạo (constructor) dùng để khởi tạo một đối tượng của lớp và đặt trạng thái ban đầu cho đối tượng bằng cách xác định giá trị cho các thuộc tính của lớp. phương thức hủy được gọi khi đối tượng được giải phóng. trong Java công việc này được làm tự động. Khi không khai báo phương thức khởi tạo. • Phương thức có thể làm thay đổi trạng thái của tham số kiểu đối tượng. lập trình viên không cần quan tâm. Ví dụ phương thức println() trả về void: System.out. else return num2. Trong trường hợp cần thiết ta có thể khai báo phương thức hủy theo cú pháp: protected void finalize() { // Body of Method } Hàm main() Đây là một hàm đặc biệt được cài đặt trong lớp được gọi thực thi đầu tiên trong chương trình. Nếu phương thức trả về void. Constructor không được kế thừa. int num2) { if(num1>num2) return num1. Các chú ý khi truyền tham số cho phương thức: • Các phương thức không thể làm thay đổi giá trị của các tham số có kiểu nguyên thủy. đối tượng được tạo ra bằng phương thức khởi tạo mặc định không tham số với các giá trị mặc định của các thuộc tính. V. } Về <mệnh đề throws> chúng ta sẽ xem xét kỹ trong phần xử lý ngoại lệ. Vấn đề sử dụng phương thức khởi tạo của lớp cha trong các lớp dẫn xuất sẽ bàn trong phần “Tính thừa kế” Phương thức hủy: Trái với phương thức khởi tạo. việc gọi phương thức thường được xử lý như một giá trị.

việc gọi hàm main() đương nhiên là diễn ra bên ngoài lớp nên nó cũng cần có mức độ truy cập là public. V. ta có một lớp SinhVien kế thừa từ lớp People trên: public class SinhVien extends People { private String Lop. protected String HoVaTen.7 Khai báo chồng các phương thức Các phương thức trong cùng một lớp có thể có cùng tên nhưng nhất định số lượng các tham số hoặc kiểu của chúng phải khác nhau." + String. HoVaTen=ht.double dtk) { super(t.MaSo=10.String l.valueOf(Tuoi). private double DiemTongKet. public static final String MauDa=”Vang”. Hàm main() thường không trả về giá trị nào nên kiểu giá trị trả về của nó là void. // Gọi phương thức khởi tạo của lớp cha cho các thuộc tính kế thừa // Các thuộc tính không kế thừa được gán tường minh Lop = l. Điều này gọi là khai báo chồng phương thức.} Sau đó. }.String ht. kiểu giá trị trả về cũng được xem như một yếu tố để phân biệt các phương thức.Hơn nữa. Hàm main() có một tham số là một mảng các chuỗi chứa nội dung các tham số dòng lệnh. DiemTongKet=dtk. Sau đây là chương trình ví dụ về xây dựng các class trong Java: abstract class People // Lớp trừu tượng { protected int Tuoi.5. // biến lớp // Phương thức khởi tạo public SinhVien(int t.ht). Từ phiên bản Java 1. } // Phương thức hiển thị tên và tuổi của một người public String toString(){ return HoVaTen + ".String ht) { Tuoi=t. 51 . //hằng số // Phương thức khởi tạo public People(int t. public static int MaSo. } // Hàm main public static void main(String[] argvs) { // Truy cập vào biến lớp không cần khởi tạo đối tượng SinhVien.

Hầu hết các lớp lồng là lớp nội bộ."Pham Anh Hoa"). SinhVien.15)."Letio3".. System. MaSo của sinh viên này sẽ là 10 SinhVien k = new SinhVien(23.toString()). inner. } } Lớp lồng chỉ được biết bên trong phạm vi của lớp bao bên ngoài."Pham Anh Thu". thậm chí nếu chúng được khai báo private.8 Lớp lồng nhau – lớp nội Có thể định nghĩa một lớp bên trong một lớp khác.print(k.out. Nó không thể tham chiếu trực tiếp đến biến hay phương thức đối tượng được định nghĩa trong lớp bao. Lớp như vậy gọi là lớp lồng (Nested Class) và được cài đặt như sau : class EnclosingClass{ // Lớp bao bên ngoài .display_x().MaSo).. mà chỉ dùng chúng thông qua đối tượng. Lớp lồng tĩnh (static nested class) được bổ sung từ khoá static."Letio3".. class Outer { int outer_x = 100.7. // Báo lỗi dòng này } } Trong chương trình trên. lớp bao không thể truy xuất các thành phần của lớp lồng. Trình biên dịch Java sẽ báo lỗi nếu một đoạn mã bất kỳ của lớp bên ngoài truy cập trực tiếp lớp lồng."Nguyen Thi Mai".MaSo=11.// Khởi tạo một đối tượng sinh viên. V. void test() { Inner inner = new Inner(). còn được gọi là lớp nội bộ (inner class).15).out. Lớp lồng phi tĩnh (nonstatic nested class) không bổ sung từ khoá static. Chúng ta sẽ trở lại vấn đề này trong phần “Tính kế thừa”. Tuy nhiên.. } class InnerClass { // Lớp lồng phi tĩnh hay lớp nội bộ . static class StaticNestedClass { // Lớp lồng tĩnh . // Khởi tạo một đối tượng sinh viên. People p = new People(20. Nó có thể truy cập trực tiếp đến các biến và phương thức đối tượng. Một lớp lồng có quyền truy cập đến các thành viên của lớp bao bên ngoài. MaSo của sinh viên này sẽ là 11 SinhVien k1 = new SinhVien(20.. Vì giới hạn này nên lớp lồng tĩnh ít được dùng. Có hai kiểu lớp lồng : tĩnh và phi tĩnh. việc khởi tạo một đối tượng thuộc lớp People sẽ bị báo lỗi do lớp này là lớp trừu tượng. System. } class Inner { // có thể truy xuất trực tiếp biến đối tượng của lớp Outer 52 .print(k..8.

53 . int month.util. import java. int day) { HoVaTen = n. } } void display_y() { // không thể truy xuất biến đối tượng của lớp Inner System.int inner_y = 10.test(). // Error } } class InnerClassDemo { public static void main(String args[]) { Outer outer = new Outer(). month . Tính kế thừa trong Java Để theo dõi tính kế thừa trong Java được cài đặt như thế nào.1. day). Luong = s. } public void windowIconified(WindowEvent e) {System.println(“display : outer_x = “ + outer_x). } } Trong Java có sử dụng một kỹ thuật cài đặt lớp nội nặc danh. đội ngũ quản lý (managers) được đối xử khác với nhân viên (employees) bình thường.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent event) { System. Ví dụ: frame. GregorianCalendar calendar = new GregorianCalendar(year. void display_x() { System.} } ). Lớp Employee được định nghĩa như sau: import java.out. khi xử lý các sự kiện. Nó được khai báo chồng 2 phương thức của WindowAdapter. VI.GregorianCalendar. double s. int year.println(“display : inner_y = “ + inner_y). tức là không có tên.util.Date.out.1 Sự kế thừa các thuộc tính và phương thức Giả sử trong công ty. trong phần này chúng ta sẽ xem xét một ví dụ về quản lý nhân sự tại một công ty.exit(0). ta có một lớp nặc danh kế thừa từ lớp WindowAdapter. outer. VI. class Employee { // Phương thức khởi tạo public Employee(String n.exit(0). Ở đây.

lớp con. 54 . } // Các thuộc tính thành phần private String HoVaTen. Lớp Manager có thêm thuộc tính TienThuong và phương thức để thiết đặt giá trị cho nó: class Manager extends Employee { . } Ta thấy rằng cả Manager và Employee đều có những điểm chung về mặt quản lý như họ cùng được trả lương. Luong += PhanTang. } // Phương thức tăng lương public void raiseSalary(double PhanTram) { double PhanTang = Luong * PhanTram / 100.. } //phương thức lấy ngày bắt đầu làm việc public Date getNgayBatDau() { return NgayBatDau.getTime(). lớp kế thừa còn được gọi là lớp dẫn xuất. class Manager extends Employee { //Các thuộc tính và phương thức bổ sung } Từ khóa extends xác định rằng chúng ta đang tạo ra một lớp mới được dẫn xuất từ một lớp đang tồn tại. private Date NgayBatDau. Các lớp dẫn xuất thường được cài đặt nhiều tính năng hơn lớp cha. Đây chính là ngữ cảnh tốt để cài đặt tính kế thừa. Tuy nhiên.. } // Phương thức lấy họ tên public String getHoVaTen() { return HoVaTen. Lớp đang tồn tại còn được gọi là lớp cha.// GregorianCalendar coi 0 là Tháng 1 NgayBatDau = calendar. } // Phương thức lấy lương public double getLuong() { return Luong. supperclass. Chúng ta sẽ thiết kế một lớp Manager nhưng kế thừa lại những gì đã viết ở lớp Employee. với Employee chỉ được trả lương theo một hợp đồng có sẵn trong khi Manager ngoài lương ra còn được hưởng một khoản tiền thưởng. hoặc lớp cơ sở (base class). private double Luong.

// vẫn không thực hiện 55 . public double getLuong() { double LuongCoBan = getLuong().. Lý do là vì sự truy cập vào Luong ở đây là không hợp lệ. } Chúng ta có thể nghĩ việc cài đặt cho phương thức mới này rất đơn giản như: public double getLuong() { return Luong + TienThuong. một số phương thức của lớp cha có thể không còn phù hợp ở lớp con. Tất nhiên là đối tượng của lớp Emplyee không thể gọi phương thức setTienThuong() vì nó không phải là phương thức được định nghĩa trong lớp Employee. ta cần định nghĩa một phương thức mới trong lớp Manager đè lên phương thức cũ: class Manager extends Employee { . Tuy nhiên điều này có thể cho phép tất cả các lớp dẫn xuất từ Employee thay đổi giá trị các thuộc tính này làm tính đóng gói của OOP bị phá vỡ. Đến đây chúng ta nghĩ rằng Luong phải được truy cập thông qua một cơ chế public khác là phương thức getLuong() được định nghĩa public trong Employee. phương thức getLuong() đối với lớp Manager phải là tổng của Luong và TienThuong. việc xác định cho các thuộc tính lớp Employee cấp độ truy cập là protected có vẻ là hợp lý. các thuộc tính HoVaTen. ta có thể gọi: boss. Đến đây ta có thể rút ra rằng khi thiết kế các lớp trong Java. } Việc sử dụng các thuộc tính và phương thức này không có gì đặc biệt. chúng ta có thể sử dụng các phương thức getHoVaTen(). Luong. getNgayBatDau() đối với các đối tượng của lớp Manager vì chúng được tự động kế thừa từ lớp Employee. Tuy nhiên. getLuong(). Nếu ta có một đối tượng Manager có tên boss. lớp con chỉ việc khai báo thêm các thuộc tính và phương thức đặc biệt. Tương tự như thế... } private double TienThuong. Theo lý thuyết. // Không thực hiện } Tuy nhiên nó không thực hiện. } . ta đặt các thuộc tính và phương thức phổ biến vào các lớp cha. public double getLuong() { . Do đó. Tuy nhiên. Ở đây.public void setTienThuong(double b) { TienThuong = b... Lớp Manager có 4 thuộc tính là HoVaTen. Luong và NgayBatDau cũng được kế thừa. NgayBatDau và TienThuong..setTienThuong(10000). Thuộc tính Luong trong Employee được khai báo là private nên chỉ các phương thức trong lớp Employee mới được phép truy cập.

TienThuong = 0. month. int year. s. Tuy nhiên ta có thể sử dụng phương thức khởi tạo của lớp cha để khởi tạo giá trị cho các thuộc tính được kế thừa ở lớp con: public Manager(String n. ta dùng từ khóa super để chỉ lớp cha. s. // OK return LuongCoBan + TienThuong. int month. year. year. year. } 56 . thay cho việc gọi constructor của Employee với 5 tham số n. day). day). ta dùng từ khóa final khi khai báo phương thức. Đến đây. } Ở đây. } // Phương thức tính lương public double getLuong() { double LuongCoBan = super.getLuong(). int day) { super(n. month và day. super(n. } Tuy nhiên.return LuongCoBan + TienThuong. các phương thức khởi tạo không được tự động kế thừa cho lớp con. month. Để gọi được phương thức getLuong() của lớp Employee. // OK return LuongCoBan + TienThuong. TienThuong = 0. VI. int day) { super(n. double s.2 Sự kế thừa đối với các constructor Như đã đề cập. Lưu ý là lệnh gọi super phải là lệnh đầu tiên trong phương thức constructor ở lớp con. s.getLuong(). int year. } Nếu không cho phép lớp con kế thừa một phương thức của lớp cha. s. } //Phương thức đặt tiền thưởng public void setTienThuong(double b) { TienThuong = b. month. int month. day). year. đoạn mã này cũng chưa thực hiện được. ta đã có một lớp Manager được định nghĩa đúng đắn: class Manager extends Employee { // Phương thức khởi tạo public Manager(String n. public double getLuong() { double LuongCoBan = super. double s. Lý do là phương thức getLuong() lúc này được coi là chính phương thức getLuong() của lớp Manager nên nó không có tác dụng.

phương thức getLuong() được định nghĩa ở cả lớp cha và lớp con.2 Sự ràng buộc động –Dynamic Binding Xét ví dụ sau: // Khai báo một đối tượng Manager Manager boss = new Manager("Phan Thanh Ha". //OK. 12. đôi khi có sự chuyển đổi vai trò của các lớp cha và con. 12. 10. Một đối tượng của lớp cha có thể được gán tham chiếu tới bất kỳ lớp con nào dẫn xuất từ nó nhưng không ép kiểu sang lớp con được. // OK you. Tính đa hình trong Java Tính đa hình là một khả năng của OOP cho phép một phương thức thực thi theo ngữ cảnh lúc chương trình đang chạy. 2000. // Chuyển kiểu OK boss1 = (Manager) me. 15). Cho dùng là cùng một tên gọi. boss. Employee you = new Employee("Nguyen Anh Tai". boss.setTienThuong(2000). hoặc: you = (Employee)boss.setTienThuong(5000). VII. 2000. 1). } VII. 81000. 80000. 1987. cơ sở của tính đa hình cũng đã được cài đặt. Đây chính là thể hiện tính đa hình của đối tượng.private double TienThuong. Ta có thể gán tham chiếu một đối tượng của lớp con cho một đối tượng của lớp cha. 50000. Employee[] staff = managers. 80000. Manager boss1 = new Manager ("Nguyen Tan Phat". // OK Tuy vậy. Trong ví dụ trên.// Không được Lý do là việc chuyển kiểu chỉ xảy ra lúc chương trình chạy nên khi biên dịch “you” vẫn là một đối tượng Employee. Manager boss = new Manager ("Nguyen Tan Minh". // Cha không chuyển kiểu sang con được Thậm chí một mảng các đối tượng Employee có thể được gán cho một mảng các đối tượng Manager mà không cần chuyển kiểu: Manager[] managers = new Manager[10]. 52000. 10.1 Sự ép kiểu và gán tham chiếu đối tượng Trong quan hệ thừa kế. boss1. chúng ta sẽ xem nó được gọi như thế nào. 15). 15). thậm chí là cùng danh sách tham số. nó không có phương thức setTienLuong(). Ví dụ: Employee me = new Employee("Nguyen Anh Minh". 1987. boss = me. 1987.setTienThuong(15000). 12. Ngược lại. VII. sự chuyển đổi này chỉ diễn ra trong thời gian chạy chương trình. Nếu khi lập trình ta viết: you = boss.setTienThuong(5000). // không gán tham chiêu được me=boss1. đối tượng lớp con không thể được gán tham chiếu tới một đối tượng lớp cha nhưng có thể chuyển kiểu sang lớp cha. 1). Trường hợp ngược lại là không thể. 57 . Trong khi chúng ta cài đặt tính chất thừa kế của OOP. phương thức vẫn được gọi theo đúng đối tượng sở hữu nó.

getHoVaTen() + " " + e. Ta gọi việc getLuong() của Manager được gọi trong tình huống này là sự ràng buộc muộn hay ràng buộc động (Dynamic Binding). Ví dụ câu lệnh là x. Trình biên dịch kiểm tra kiểu của đối tượng và tên của phương thức.getLuong()). 3. VIII. giả sử kiểu hiện tại của x là D. Kết quả in ra là: Phan Thanh Ha 85000. ví dụ f(int) và f(String). Tuy nhiên đối tượng thứ 0 đã gọi phương thức getLuong() của Manager. trình biên dịch sẽ biết chính xác phương thức cần phải gọi đó là phương thức f của lớp C. Trình biên dịch sẽ liệt kê tất cả các phương thức tên f trong lớp C và phương thức tên f có mức độ truy cập public trong các lớp cha của C. giả sử là x. 2. nó sẽ đưa ra thông báo lỗi.// Khai báo một mảng 3 đối tượng Employee Employee[] staff = new Employee[3]. 1989. nếu viết: staff[0]. Tiếp theo. staff[2] = new Employee("Pham Quyet Tan". 50000. Để kết thúc phần này ta sẽ xem xét cơ chế của việc gọi phương thức của một đối tượng trong Java được thực hiện như thế nào: 1. Điều này gọi là ràng buộc tĩnh (static binding). static và final hoặc là một constructor.println(e. Nếu trình biên dịch không thể tìm thấy phương thức có tham số phù hợp hoặc có nhiều hơn 1 phương thức phù hợp. 1). 10. 40000. 15). phương thức được gọi tùy theo kiểu hiện tại của đối tượng.0 Nguyen Hai Nam 50000. Tuy nhiên chúng ta không bao giờ phải khai báo: class Employee extends Object 58 . Trong đó x được khai báo là đối tượng của lớp C. một lớp dẫn xuất từ C (Ban đầu x là một đối tượng lớp C nhưng sau đó được gán tham chiếu tới một đối tượng của D).f(“Chao ban”) thì hàm f(String) được gọi chứ không phải f(int). Nếu lớp D không có. Nếu trong danh sách phương thức có tên f chỉ có 1 phương thức có kiểu tham số phù hợp thì phương thức này được gọi. trình biên dịch sẽ xác định kiểu của tham số của phương thức được gọi. Bây giờ. Cơ chế này gọi là ràng buộc động.0 Ở đây chúng ta thấy đối tượng thứ 1 và 2 in ra các giá trị vốn có của nó theo phương thức getLuong() của Employee. Trong lớp C có thể có nhiều phương thức có cùng tên f nhưng khác nhau ở tham số. trình biên dịch đã biết rõ phương thức nào được gọi (tên và danh sách tham số). Mặt khác. // Khởi tạo cho 2 đối tượng còn lại staff[1] = new Employee("Nguyen Hai Nam". thì không được phép khi biên dịch. Ngược lại. // Gán boss cho đối tượng thứ 0 staff[0] = boss. nó sẽ tìm lên các lớp cha của D (trong đó có lớp C). Lớp Object Lớp Object là lớp cha của mọi lớp trong Java.f(param). // Dùng vòng lặp để in ra tên và lương từng người for (Employee e : staff) System.0 Pham Quyet Tan 40000.setTienThuong(2000).out. 3. Nếu D có định nghĩa một phương thức f(String) thì phương thức này sẽ được gọi. 1990. Nếu phương thức là private. Cơ chế này gọi là nạp chồng (overloading). Đặc trưng thể hiện tính đa hình trong Java.

đối tượng thuộc lớp Object có thể được tham chiếu tới bất kỳ đối tượng nào khác. Tuy nhiên. Mở rộng hơn.Mọi lớp đều là hậu duệ của Object. // OK obj = new int[10]. } Ví dụ các lớp muốn cài đặt giao diện Comparable<Employee> phải cài đặt phương thức: int compareTo(Employee objKhac). // OK IX. Từ phiên bản Java 5. các giao diện có thể được xác định cho một kiểu tổng quát: public interface Comparable<T> { int compareTo(T objKhac). } Phương thức compareTo nhận một đối tượng khác làm tham số và là đối tượng đem ra so sánh. Tất cả các phương thức khai báo trong interface mặc định là public nên ta không cần khai báo public cho nó. Điều này dẫn đến việc thiết kế một giao diện: public interface Comparable { int compareTo(Object objKhac). Object obj = new Employee("AAA". Giao diện IX. 35000).0 (1.5). tất cả các lớp muốn sử dụng phương thức sort của Array đều phải cài đặt phương thức này trong định nghĩa của nó. Bây giờ chúng ta định nghĩa: 59 . Employee[] staff = new Employee[10]. Cấu trúc của một giao diện rất đơn giản: public interface <tên giao diện> { //Danh sách các phương thức } Tại lớp có cài đặt giao diện: public class <tên lớp> implements <tên giao diện> { //Phân thân lớp có chứa định nghĩa phương thức của giao diện } Ví dụ: Trong lớp Arrays của Java có phương thức sort dùng để sắp xếp các đối tượng trong một mảng. kết quả so sánh biểu hiện qua một số nguyên. do đó. Java hỗ trợ một kỹ thuật thay thế và rất linh hoạt. Giao diện không phải là một class nhưng nó chỉ ra các phương thức sẽ được định nghĩa trong các lớp cài đặt nó. obj = staff.1 Cấu trúc của giao diện Trong Java không hỗ trợ tính đa thừa kế. đó là các interface hay còn gọi là các giao diện. Tuy nhiên. Các lớp có sử dụng tới các phương thức này phải khai báo cài đặt giao diện bằng từ khóa implement. muốn sắp xếp được thì trong định nghĩa lớp của các đối tượng này phải có cài đặt một phương thức so sánh compareTo(Object objKhac).

Tuy nhiên nếu ta cũng khai báo chồng một phương thức compareTo() thì không được do vi phạm quy tắc chuyển kiểu: class Manager extends Employee { public int compareTo(Employee objKhac) { Manager otherManager = (Manager) objKhac. Đối với phiên bản Java 5... ta có thể cài đặt: class Employee implements Comparable<Employee> { public int compareTo(Employee objKhac) { if (Luong < objKhac.x. return 0. Trong phần sau đây chúng ta sẽ cài đặt một phương thức compareTo cho việc so sánh các đối tượng Employee. Rõ ràng là một đối tượng Manager vẫn có thể được so sánh với một đối tượng Employee về tiền lương. ta cài đặt compareTo như sau: public int compareTo(Object objKhac) { Employee other = (Employee) objKhac. // không được .. các hằng số. Tuy nhiên trong interface ta không thể khai báo các biến thành phần và không thể cài đặt nội dung của các phương thức.Luong) return -1. Các interface thường có nhiều phương thức.0. Khi đưa một đối tượng 60 . } May mắn là ta không cần làm điều này vì tính kế thừa đã đảm bảo Manager cài đặt Comparable<Employee> chứ không phải Comparable<Manager>. } Chú ý rằng các phương thức trong interface không khai báo public nhưng khi cài đặt chúng.compareTo(y) >0 nếu x > y Trong interface ta đang xem xét thì nó chỉ có một phương thức. } Đối với lớp Manager thì sao.. // Chuyển kiểu if (Luong < other. Các interface có thể xem như các lớp trừu tượng không có thuộc tính thành phần tuy rằng chúng có nhiều điểm khác biệt.Luong) return 1.compareTo(y) =0 nếu x = y x. if (Luong > other. nhất định ta phải có khai báo public. if (Luong > objKhac.compareTo(y) <0 nếu x < y x. } .Luong) return 1... } . return 0.Luong) return -1. Khai báo cài đặt Comparable cho Employee: class Employee implements Comparable Giả sử các Employee được so sánh thông qua tiêu chí Luong.

Vị trí của dấu “*” có thể là tên một class cụ thể. java. 61 . // OK • Có thể dùng toán tử instanceof để kiểm tra xem một đối tượng có được cài đặt interface hay không: if (anObject instanceof Comparable) { . . } Trong interface. Trong một số trường hợp. Trong cả hai gói này đều có lớp Date nên trong dòng lệnh: Date myDate = new Date().). // Lỗi • Có thể khai báo một biến interface. sử dụng dấu “*” có thể gây ra lỗi. } • Các interface cũng có thể được kế thừa.Date today = new java. Package X. import java.util. • Có thể khai báo các hằng số trong interface. // OK Biến interface phải tham chiếu tới một đối tượng của một lớp có cài đặt interface đó. Nếu muốn sử dụng cả hai Date trong chương trình ta phải khai báo trực tiếp: java.. .Date deadline = new java. Ví dụ: import java.*. public interface Comparable<Employee> { double greater = 1. Thì trình biên dịch báo lỗi vì không biết Date của gói nào.util. int compareTo(Employee other).*.util. Việc so sánh vì thế diễn ra thoải mái giữa các đối tượng Employee và Manager với nhau.2 Các tính chất của giao diện Khi sử dụng interface ta cần chú ý mấy điểm sau: • Giao diện không phải là class nên không dùng từ khóa new để tạo một đối tượng kiểu giao diện: x = new Comparable(.util. Khi này ta phải khai báo rõ ràng cho Date ở gói nào: import java. .Date. . Comparable x. nó tự động được ép sang kiểu Employee.. import java.sql. x = new Employee(.sql. X. ta khai báo nhập thư viện: import java.1 Sử dụng các package trong thư viện Java Để sử dụng các class nằm trong một gói thư viện của Java mà không cần viết đường dẫn đầy đủ của gói.Manager vào làm tham số so sánh. .Date(. Dấu “*” đại diện cho tất cả class. . • Một lớp chỉ có thể kế thừa từ một lớp khác trong khi có thể cài đặt nhiều giao diện.sql.Date(). Các lớp có cài đặt interface cũng tự động được thừa kế các hằng số này.util.).*.*. khai báo “double greater =1” được tự động hiểu là: public static final double greater =1. IX.sql.).

Trong đó các thành viên của lớp là các đối tượng Sinh viên có các thuộc tính như Họ và tên. giỏ hàng trong một hệ thống quản lý bán hàng ở siêu thị. Trong ví dụ trên Employee. 2)). X.myproject. danh sách lớp và các phương thức như: Thêm sinh viên. 5. ta phải có đường dẫn đầy đủ: Javac com\myproject\employee\Employee. 2. khi biên dịch hoặc chạy chương trình từ cửa sổ dòng lệnh CommandLine. thống kê học tập. } Nếu không có khai báo đó.Ta cũng có thể có một khai báo nhập thư viện với từ khóa static: import static java. Khi đó các phương thức và thuộc tính tĩnh của lớp System được truy cập mà không cần có tên lớp: out. Xem danh sách.class sẽ nằm trong thư mục: com\myproject\employee tính từ thư mục hiện thời. thống kê giới tính. tứ giác.lang. Khóa học. hình thoi. PhuongTrinhBac2 có cài đặt giao diện này. Trong hệ thống đồ họa: a. Hãy xây dựng các class điểm. 2) + pow(y. Các đối tượng sinh viên được so sánh theo tiêu chí điểm tổng kết. 3. đoạn thẳng. tam giác. c. 4.employeee. sản phẩm. Tên lớp. public class Employee { . Hãy cho biết một thứ tự phân cấp kế thừa của các lớp này. hình chữ nhật. Thực hành cài đặt các ví dụ trong đề tài trên. Các lớp trong gói sẽ tự động thuộc vào một đường dẫn đầy đủ theo tên của package. Tuổi. Xây dựng một giao diện GiaiPhuongTrinh dùng cho việc giải các phương trình bậc 1 và bậc 2 sau đó xây dựng lại các lớp PhuongTrinhBac1. Sắp xếp danh sách. Ta thường dùng phương pháp này với các hàm của class Math: sqrt(pow(x.. Xây dựng một lớp đối tượng phương trình bậc 2 sao cho ta có thể khởi tạo một phương trình bậc 2 và biết ngay các tình trạng của nó như có nghiệm hay không và giá trị nghiệm. 62 . Do đó. Phương thức toString() in ra màn hình giá trị tất cả các thuộc tính của một đối tượng.java Bài tập 1. Xây dựng một lớp đối tượng để cài đặt cho lớp đối tượng lớp học bao gồm các thuộc tính như: Sĩ số. Hãy cài đặt một phương thức toString() cho các lớp trên theo kỹ thuật ràng buộc động. Xây dựng các class trong java để cài đặt các lớp đối tượng: Khách hàng. Giới tính. Xây dựng một lớp PhuongTrinhBac1 để giải phương trình bậc 1..2 Đặt lớp vào package Để đặt một lớp vào một package. hóa đơn.print(“Khong co ten lop System”). Điểm tổng kết và các phương thức phù hợp (sinh viên tự xác định xem cần những phương thức gì).System.*. b. Xóa Sinh viên. hình vuông. 7. đa giác. 6. lớp tự động thuộc vào một package mặc định không có tên. ta phải có khai báo package ở dòng đầu tiên của chương trình: package com.

abstract String toString(). Giả sử trong chương trình có các đối tượng SinhVien. một khái niệm chung cần được làm rõ là “động vật bốn chân”. HoTen = ht. Lớp SinhVien kế thừa từ People được cài đặt như sau: 63 . Lớp và phương thức trừu tượng I.v…và có rất nhiều khái niệm dùng đến khái niệm này như động vật ăn cỏ. Ví dụ: abstract class People { private int NamSinh. ta cần một định nghĩa về “động vật bốn chân” Động vật bốn chân là động vật có bốn chân để di chuyển. public People(int ns. Đến đây ta lại bắt gặp một khái niệm trừu tượng hơn là “động vật” v.Đề tài 4. } abstract String toString(). Chúng thực sự không có một biểu hiện nào (hoặc nếu ta bắt buộc chúng có biểu hiện thì biểu hiện đó cũng không có ý nghĩa trong phạm vi đang xét). String ht) { NamSinh= ns. Các con hổ là động vật bốn chân sống trong các khu rừng. } public String getHoTen() { return HoTen. Các đối tượng này đều có một phương thức toString để trả về một chuỗi bao gồm toàn bộ thông tin về chúng. Đây là tình huống sử dụng phương thức trừu tượng một cách hiệu quả. private String HoTen. } Ta thấy rằng một lớp trừu tượng thực sự là một lớp với đầy đủ các thành phần. GiaoVien. Để cho các định nghĩa này thêm sáng tỏ. Cài đặt lớp và phương thức trừu tượng trong Java Khai báo: Lớp trừu tượng được khai báo như lớp thông thường nhưng có thêm từ khóa abstract. Các con mèo là động vật bốn chân hay bắt chuột. Trong các định nghĩa trên. Trong lập trình cũng vậy. II. động vật bò sát.…. những lớp đối tượng sinh ra chỉ để cho các lớp khác kế thừa gọi là các lớp trừu tượng. động vật ăn thịt. ……. Chú ý là các phương thức trừu tượng không có phần thân. không giống như interface. Khái niệm lớp trừu tượng Những khái niệm trừu tượng trong thế giới thực được cài đặt trong chương trình như là các lớp trừu tượng. Chúng thường làm cơ sở để giúp ta có được các định nghĩa cụ thể hơn: Ví dụ: Các con trâu là động vật bốn chân được nuôi phục vụ cày bừa.

(Gợi ý: Phương thức TinhTien ơ lớp BenhNhan khai báo trừu tượng sau đó được khai báo chồng tại các lớp thừa kế).public class SinhVien extends People { private String Lop. Ngoài ra. Khi kế thừa một lớp có chứa phương thức trừu tượng thì phương thức đó bắt buộc phải được cài đặt. 12 chỗ và 24 chỗ. Một nhà máy sửa chữa phương tiện vận chuyển có các loại xe ô tô thuộc nhiều hàng khác nhau như Honda. Mishubishi. có phương thức tính tiền phải thanh toán bằng tiền điều trị cộng với tiền giường nằm. // Phương thức khởi tạo public SinhVien(int ns. Toyota. 4 chỗ. Kia. Hãy xây dựng một lớp PHUONG_TIEN trừu tượng có phương thức trừu tượng là Xac_Dinh_Gia() trong đó việc tính giá sửa cho một phương tiện bằng giá của nhà máy trừ đi tiền khuyến mại. a. Khi sử dụng phương thức abstract cho một lớp thì nhất thiết phải có một lớp khác kế thừa và khai báo cài đặt chồng thì mới có tác dụng.valueOf(DiemTongKet) + HoTen. private double DiemTongKet. Ford. Bài tập 1.String ht.valueOf(NamSinh) + String. } // Cài đặt phương thức toString public String toString() { return String. tiền điều trị. Hãy xây dựng một giao diện trong đó có phương thức so sánh phương tiện theo tiêu chí giá sửa. 3. } } Khi một phương thức được khai báo là abstract thì lớp chứa nó cũng phải là một lớp abstract. 64 . DiemTongKet=dtk. nhà máy còn nhận bảo dưỡng cho các loại xe mô tô tay ga và xe số.ht).double dtk) { //Dùng phương thức khởi tạo của lớp cha super(ns. Mỗi hãng ô tô lại có nhiều kiểu khác nhau như 2 chỗ.String l. Sau đó xây dựng hai lớp BenhNhanNoiTru và BenhNhanNgoaiTru kế thừa lớp BenhNhan. Mercedec. c. Nhà máy có các chế độ khuyến mại và bảo hành khác nhau tùy theo xe của từng hãng. Xây dựng một lớp BenhNhan trừu tượng có các thuộc tính như họ và tên. Trong hệ thống quản lý bệnh nhân ở bệnh viện có 2 loại bệnh nhân là nội trú và ngoại trú trong đó bệnh nhân nội trú có tính tiền giường nằm. Lop = l. b. 7 chỗ. Xây dựng chương trình nhập vào dữ liệu cho 5 chiếc xe cả ô tô và mô tô và in ra màn hình theo thứ tự tăng dần của giá sửa.

valueOf(i) + " la:"). System. Lưu trữ và xử lý đối tượng Trong phần này chúng ta sẽ đề cập tới các lớp tiện ích của Java trong gói java. 15.i++) 3.capacity()). Long hay Float thay vì dùng chính kiểu đó.lang. // In ra de kiem tra 9.Integer p = new java. Vì vậy thao tác chèn một phần tử mới vào một Vector sẽ nhanh hơn khi kích thước của nó còn đủ dùng.1 Lớp Vector Lập trình viên dùng lớp Vector để lưu trữ các đối tượng có kiểu giống nhau nhưng có thể thay đổi động về kích thước tùy theo nhu cầu. • Nếu là 1 tham số thì đó là số phần tử ban đầu. } 8.Integer(nhap. lưu vào một Vector rồi in ra để kiểm tra: // Nhâp 10 doi tuong so nguyen 1.i++) 10. System. Để lưu các giá trị dữ liệu nguyên thủy.out. 5. 12. Ở đây ta đã dùng một constructor với 2 tham số là số phần tử ban đầu và số sẽ tăng khi Vector có nhu cầu tăng (mặc định sẽ gấp đôi số hiện có).println(v. Lớp Vector có 3 constructor: • Nếu dùng constructor không tham số thì Java tự động cấp cho ta số phần tử ban đầu là 10 và nhân đôi mỗi khi có nhu cầu mở rộng.nextInt()).out.util.addElement(p). System. 6. v.i<10.i<10. 65 . java. Vector lưu trữ tham chiếu của các đối tượng nên chương trình có thể dùng Vector để lưu tham chiếu đến bất kỳ đối tượng nào.println(v. • Nếu là 2 tham số thì tham số thứ nhất chỉ số phần tử ban đầu. for (int i=0. System.println(v.size()). for (int i=0. Sau đây là một ví dụ nhập vào 10 số nguyên. Chúng ta sẽ xem xét việc sử dụng interface Enumeration để cho phép duyệt lặp trên các cấu trúc như Vector.lang. Dòng 1: Khai báo một đối tượng v thuộc lớp Vector. { 4.util dùng cho việc lưu trữ và xử lý các đối tượng. System. } 14.get(i)).out.out. Kích thước của Vector được tăng theo một lượng đặt trước hoặc được tự động tăng gấp đôi khi ta cần tăng dung lượng của nó.Đề tài 5.out. java.print("Nhap so nguyen thu " + String. Dòng 2-7: Vòng lặp để nhập và lưu kết quả nhập vào Vector. { 11. tham số thứ 2 chỉ số phần tử được thêm vào mỗi khi dung lượng của Vector bị hết.util.lang như Integer.2).Vector v = new java. 13. khi cần cũng tự động nhân đôi.Vector(5. Ở đây ta phải khai báo một biến đối tượng kiểu Integer chứ không phải là một kiểu nguyên thủy int. I. 2. Sau đó dùng phương thức addElement() để thêm đối tượng này vào vị trí cuối của Vector.valueOf(i) + ":"). 7.print("So nguyen thu " + String. ta phải sử dụng các lớp trong java. Lớp Vector và giao diện Enumeration I.

indexOf(Object): Trả về chỉ số của đối tượng đầu tiên so khớp với Object.Ngoài ra ta cũng có thể sử dụng insertElementAt() để chèn phần tử vào một vị trí xác định hoặc sử dụng setElementAt() để đặt giá trị cho một phần tử tại một vị trí.2 Giao diện Enumeration Sử dụng phương thức elements() của một đối tượng Vector sẽ trả về một đối tượng Enumeration cho phép chương trình duyệt lặp trên danh sách phần tử của Vector. Đoạn chương trình sau duyệt và in ra danh sách các sinh viên: abstract class People { protected int NamSinh. } // Phuong thuc tinh tuoi protected abstract int TinhTuoi(). Dòng 15: Kích số lượng các phần tử tối đa hiện có của Vector (=11). trimToSize(): Giảm số lượng phần tử của Vector. tức là số phần tử thực sự Vector lưu trữ (=10) . public abstract String toString(). HoVaTen=ht. isEmpty(): Xác định liệu Vector là trống. Thực ra thì phương thức get(chỉ số) cho ta một tham chiếu đến đối tượng có chỉ số tương ứng được lưu trong Vector nhưng ở đây đối tượng số nguyên đã tự động in ra giá trị.//Nam Sinh protected String HoVaTen. Một số phương thức của Vector: removeElementAt: Xóa một phần tử ở một vị trí xác định. Các lớp thường khai báo chồng phương thức equals() để dùng trong việc so sánh các đối tượng của mình. • nextElement(): Trả về tham chiếu tới phần tử tiếp theo trong Vector.String ht) { NamSinh=ns. I. Đối tượng Enumeration có các phương thức quan trọng sau: • hasMoreElement(): Trả về true nếu vẫn còn phần tử trong Vector. Đối tượng key và các phần tử của Vector được so sánh với nhau bởi phương thức equals(). //Ho Va Ten //constructor public People(int ns. } // Ke thua lop People public class SinhVien extends People { 66 . Dòng 14: Phương thức trả về kích thước thực tế của Vector. Sử dụng removeElement(Object) để xóa một phần tử xuất hiện đầu tiên trong Vector có giá trị bằng với Object. Dòng 12: Dùng phương thức get(chỉ số) để in ra giá trị của phần tử có chỉ số tương ứng. firstElement(): Trả về tham chiếu tới phần tử đầu tiên. removeAllElements(): Xóa tất cả các phần tử. lastElement(): Trả về tham chiếu tới phần tử cuối cùng trong Vector. contains(key): để kiểm tra xem trong vector có phần tử so khớp với key hay không.

MaSo=1. } // Khai bao chong phuong thuc toString() public String toString() { return "Ma so:" + String.//goi constructor cua lop cha la People Lop = l.// Ma so SinhVien protected static int MaSo.valueOf(ID)+ "\n" +"Tuoi:"+ String."Letio3". } // Phuong thuc tinh tuoi protected int TinhTuoi() { java.9).valueOf(this. sv. SinhVien k4= new SinhVien(83. // Them sinh vien vao Vector SinhVien k2 = new SinhVien(81.Date homnay = new java.NamSinh +1).String ht. SinhVien k3 = new SinhVien(82. SinhVien k5= new SinhVien(84.Vector(5).addElement(k2).TinhTuoi()) + "\n" +"Diem Tong Ket:"+ String. // Id cua SinhVien duoc gan bang gia tri MaSo hien thoi cua lop ID=MaSo. SinhVien k1 = new SinhVien(80.util.5).Date().String l.8)."Letio3".Vector sv = new java.util.util.6)."Letio3".addElement(k1).valueOf(DiemTongKet)+"\n" +"Ho va ten:"+ HoVaTen. sv. // Tang ma so len 1 den gan cho SinhVien sau MaSo+=1. sv.addElement(k5).7)."Pham Thi Mai 3". 67 .getYear() ."Tran Thi Mai 2". sinh vien dau tien co ma so 1 SinhVien. DiemTongKet=dtk. return (homnay. // bien doi tuong Vector java. } // Ham main public static void main(String[] argv) { // Dat gia tr? bien static. // Diem tong ket public final String mauda ="vang".private String Lop.//Hang so private int ID.// Ten lop private double DiemTongKet."Hoang Thi Mai 5".addElement(k4)."Letio3".util. sv."Nguyen Thi Mai 1".double dtk) { super(ns.addElement(k3)."Letio3". sv."Phan Thi Mai 4".ht).// ma so chung de cap phat cho moi sinh vien // constructor public SinhVien(int ns.

} //People p = new People(20. System."Pham Anh Hoa").*.util.nextElement(). kieu Object la kieu cha cua moi kieu nen luon ep duoc SinhVien g = (SinhVien)enu. bao loi vi People là lớp trừu tượng } } Kết quả thực hiện như sau: II.println(g. Mảng trong Java và lớp ArrayList II.// Dung interface Enumeration de duyet cac phan tu cua Vector java.1 Mảng trong Java Trong phần “Ngôn ngữ Java căn bản” ta đã xem xét một biến mảng được khai báo và sử dụng như thế nào. while (enu.Enumeration enu = sv. Trong phần này ta sẽ đi sâu khai thác các đặc tính của mảng và một số thuật toán thông dụng thông qua các ví dụ.out.swing.toString()).hasMoreElements()) { // Ep kieu.elements(). public class StudentPoll { // Hàm main public static void main( String args[] ) 68 . Ví dụ: Đếm tần suất của các phần tử của một mảng: import javax.

6. 1. 10 }. // Biến trung gian để hoán đổi hold = array3[ first ].2. element + 1 ). 8. array3[ first ] = array3[ second ]. pass++ ) { // Vòng lặp so sánh và đổi chỗ for ( int element = 0. // In ra System. các câu trả lời nằm trong khoảng từ 1 đến 10 nên khai báo một mảng 11 phần tử để có thể sử dụng chính giá trị 10 làm chỉ số của mảng. rating < TanSuat. 3.length. lưu giá trị vào mảng TanSuat tại vị trí // tương ứng.length. 10. II.print(output). 4. 5. }} Trong ví dụ này. array3[ second ] = hold. 5.length. 4. 6.pass. 2. 6. 7. 6. 5. Các thuật toán cơ bản trên mảng Ví dụ: Sắp xếp tuyến tính. 6. 8. element. 8. answer++ ) ++frequency[ TraLoi[ answer ] ]. 6. 6. phần tử nào lớn nhất sẽ bị đẩy xuống cuối cùng. element < array2. 6. 3. // Với mỗi phần tử của mang TraLoi. element++ ) { // So sánh 2 phần tử liền kề và đổi chỗ nếu cần if ( array2[ element ] > array2[ element + 1 ] ) swap( array2. // Sắp xếp các phần tử của mảng public void bubbleSort( int array2[] ) { // Duyệt qua mỗi phần tử của mảng for ( int pass = 1. 10. sử dụng giá trị đó như là chỉ số của mảng TanSuat // sau đó đếm sự xuất hiện của nó trong TraLoi. 8.length . int second ) { int hold. }} } // Hàm đổi chỗ 2 phần tử của một mảng public void swap( int array3[]. for ( int answer = 0. int first. 7. 5. Đây là một ví dụ sắp xếp các phần tử của mảng tăng dần theo thuật toán “nổi bọt” .{ // Khai báo một mảng các câu trả lời int TraLoi[] = { 1. 6. 8. for ( int rating = 1.out. answer < TraLoi. 8.tức là sau mỗi vòng lặp duyệt. 7. 7. 8. Chỉ cần duyệt mảng TraLoi 1 lần ta đã có ngay kết quả. 9. // Đưa kết quả vào một chuỗi String output. rating++ ) output += rating + "\t" + TanSuat[ rating ] + "\n". 2. 69 . 6. // Mảng đếm tần suất int TanSuat[] = new int[ 11 ]. 7. 5. 6. pass < array2.

5. Ta gọi phương pháp này là tìm kiếm tuyến tính. đặt lại chỉ số dưới else low = middle + 1.3 Class Arrays Java hỗ trợ một lớp mảng trong thư viện java. ta có một phương pháp tìm kiếm hiệu quả hơn. // Nếu khóa nhở hơn phần tử giữa. Giả sử ta có một mảng: int[] b={1. Thay vì phải lập trình.util.Arrays để lập trình viên thao tác trên mảng.34. so sánh 7 với 5 thì 7>5 nên phần tử cần tìm nếu có sẽ nằm ở phần sau của nửa này gồm 2 phần tử 7. Giả sử ta cần tìm vị trí của một phần tử có giá trị 7. // Chỉ số dưới int high = array. đặt lại chỉ số trên else if ( key < array[ middle ] ) high = middle . // chỉ số của phần tử trung gian // Lặp cho đến khi chỉ số dưới lớn hơn hoặc bằng chỉ số trên while ( low <= high ) { // Xác định chỉ số phần tử giữa middle = ( low + high ) / 2. gọi là tìm kiếm nhị phân.100}. Thủ tục này được cài đặt như sau: public int binarySearch( int array2[]. ta so sánh 7 với vị trí đứng giữa của mảng là 34 thì 7 < 34 nên ta chắc chắn nếu có thì 7 sẽ nằm ở nửa trước của mảng.1.length . • sort: để sắp xếp mảng. Chủ yếu các phương thức của lớp này là static. Trước tiên. Lần phân đôi cuối cùng này cho ta kết quả.89. int key ) { int low = 0.} Ví dụ: Tìm kiếm nhị phân trên mảng đã được sắp xếp: Thông thường việc tìm kiếm diễn ra bằng phép duyệt lần lượt các phần tử của mảng. Tiếp tục làm việc này với nửa trước của mảng. // Khóa lớn hơn phần tử giữa. } return -1.56. Arrays hỗ trợ các phương thức: • fill: để nạp giá trị cho mảng.8.67. 70 . // Nếu khóa cần tìm trùng với phần tử giữa thì trả về kết quả ngay if ( key == array[ middle ] ) return middle.1. // Chỉ số trên int middle.7. đã được sắp xếp tăng dần.8. Đối với các mảng đã được sắp xếp. // Không tìm thấy } II.

4. intValuesCopy[]. count++ ) System. intValues. private int filledInt[]. for ( int count = 0.print( "doubleValues: " ). • equals: So sánh mảng. } // Tìm một giá trị trong mảng intValues 71 .out.out. 7. System.print( doubleValues[ count ] + " " ). // Sao chép mảng } // In giá trị của các mảng public void printArrays() { System.util.fill( filledInt. 5.length.length. count < doubleValues.print( intValues[ count ] + " " ). System.length ].out. 7 ).print( filledInt[ count ] + " " ). 0. 3.print( "\nintValuesCopy: " ). 3. intValuesCopy.out.2.out. Sau đây là ví dụ về sử dụng lớp Arrays: import java. private double doubleValues[] = { 8.print( intValuesCopy[ count ] + " " ).out. count < filledInt. for ( int count = 0. count++ ) System.length ).*.print( "\nintValues: " ).arraycopy( intValues. count < intValues.4 }.length. // Sắp xếp mảng doubleValues System. Arrays.9. 0. 9.sort( doubleValues ). 0.4. // Khởi tạo các mảng public UsingArrays() { filledInt = new int[ 10 ]. System. intValuesCopy = new int[ intValues. 2. count++ ) System. count++ ) System. System. for ( int count = 0.• binarySearch: Tìm kiếm nhị phân trên mảng đã được sắp. public class UsingArrays { private int intValues[] = { 1. // Nạp giá trị cho mảng filledInt với giá trị 7 Arrays. for ( int count = 0.out.3. count < intValuesCopy. 6 }.print( "\nfilledInt: " ).out.length.out.println().

out. // Thêm một đối tượng Color 72 .*.searchForInt( 5 ). System. thêm các phần tử cho nó public CollectionTest() { ArrayList list = new ArrayList(). intValuesCopy ). import java.printArrays(). System. public class CollectionTest { private String colors[] = { "red".println( ( location >= 0 ? "Tìm thấy 5 tại vị trí " + location : "Không thấy" ) + " trong mảng intValues" ). LinkedList và Vector. "blue" }.awt.equals( intValues. System.binarySearch( intValues. b = Arrays.public int searchForInt( int value ) { return Arrays. Ở đây ta đặt các đối tượng String và Color vào cùng một ArrayList sau đó xóa đi các phần tử String sử dụng một đối tượng Iterator. System. Về cơ bản thì ArrayList giống với Vector chúng ta đã xem xét ở trên. }} III Danh sách trong java và giao diện Lists Lists là một chuỗi có thứ tự các phần tử cho phép các phần tử có thể giống nhau.printEquality().util. usingArrays. Các lớp tập hợp cài đặt Lists là ArrayList. "white". } // So sánh nội dung mảng public void printEquality() { boolean b = Arrays.Color.searchForInt( 8763 ). } // Hàm main public static void main( String args[] ) { UsingArrays usingArrays = new UsingArrays(). // Thêm đối tượng cho nó list.out.equals( intValues. location = usingArrays.println( "intValues " + ( b ? "==" : "!=" ) + " intValuesCopy" ). ArrayList là một lớp tập hợp có thể thay đổi kích thước.out. int location = usingArrays.println( "intValues " + ( b ? "==" : "!=" ) + " filledInt" ).add( Color.magenta ). Sau đây là chương trình ví dụ sử dụng ArrayList. value ).out. usingArrays. // Tạo một ArrayList. import java.println( ( location >= 0 ? "Tìm thấy 8763 tại " + location : "Không thấy 8763" ) + " trong mảng intValues" ). filledInt ). Lists là một giao diện kế thừa giao diện Collections nên nó cho phép lập trình viên truy cập các phần tử qua chỉ số.

// Thêm các đối tượng String for ( int count = 0. // Xóa phần tử } // Hàm main public static void main( String args[] ) { new CollectionTest(). // Lặp trong khi tập hợp vẫn còn phần tử while ( iterator.out.iterator().hasNext() ) if ( iterator.Xóa sinh viên . for ( int count = 0. count++ ) System. 73 .Sắp xếp n số theo thứ tự tăng dần . . // output list contents System. Sau đó: . count++ ) System.Thêm sinh viên. .println( "\nArrayList: " ).size().get( count ) + " " ). for ( int count = 0. } } Bài tập 1.println( "\n\nArrayList sau khi gọi removeStrings: " ).next() instanceof String ) iterator.out. // Thêm một đối tượng Color // In ra nội dung System. list.Nhập vào từ bàn phím 1 số khác và tìm xem số đó có trong số n số vừa nhập không.add( Color. // Xóa tất cảcác đối tượng String removeStrings( list ). count < list. count < colors.out.length. } public void removeStrings( Collection collection ) { // Khai báo đối tượng iterator iterator iterator = collection. count < list.print( list.Sắp xếp danh sách theo tên 2.remove(). Viết chương trình quản lý danh sách một lớp học với các chức năng .Tính tổng của n số này.Tìm kiếm sinh viên .get( count ) + " " ).size(). n nhập từ bàn phím.out. Viết chương trình nhập vào n số nguyên và số thực.add( colors[ count ] ).print( list. count++ ) list.cyan ).

FileWriter và rất nhiều lớp khác. tệp tin. ta khai báo khối thư viện: import java. Sự phân cấp các class trong gói java.io. máy in.in: Dòng nhập chuẩn thường đến từ bàn phím và được dùng để đọc các ký tự dữ liệu. FileOutputStream.*.Đề tài 6.lang. Thư viện này cho phép ta làm việc với các luồng nhập xuất qua việc cung cấp các lớp: FileInputStrem. . Khái niệm luồng vào ra (I/O stream) Luồng là dòng chảy của dữ liệu. như màn hình..io thể hiện qua bảng sau: java. I.Object File FileDescriptor InputStream ByteArrayInputStream FileInputStream FilterInputStream BufferedInputStream DataInputStream PushbackInputStream ObjectInputStream PipedInputStream SequenceInputStream OutputStream ByteArrayOutputStream FileOutputStream FilterOutputStream BufferedOutputStream DataOutputStream PrintStream 74 . Khi cần làm việc với luồng.. Ví dụ System.err có thể đưa thông báo lỗi ra một file. đọc từ tập tin.. • Lớp System. Đối với mội luồng lại có các dòng bao gồm: • Lớp System. FileReader. Có 2 loại luồng: • Luồng nhập (input stream): là tất cả gì từ thế giới bên ngoài được đưa vào máy tính. • Luồng xuất (output stream): là tất cả những gì được gửi từ máy tính ra ngoài thông qua các thiết bị ngoại vi. như đọc từ bàn phím. Các luồng vào ra dữ liệu với file Một khả năng quan trọng mà các ngôn ngữ lập trình phải có là việc quản lý các luồng dữ liệu vào ra hệ thống máy tính giúp các chương trình có thể giao tiếp dữ liệu với thế giới bên ngoài.out: Dòng xuất chuẩn dùng để hiển thị kết quả trên màn hình. Các dòng này có thể bị đổi hướng đến nhiều nguồn khác nhau..err: Đây là dòng lỗi chuẩn cho phép một chương trình đưa ra các thông báo lỗi trên màn hình. • Lớp System.

75 . • available(): Phương pháp này trả về số lượng byte có thể đọc được mà không phải chờ. Lớp InputStream: Là một lớp trừu tượng định nghĩa cách thức nhận dữ liệu. Nó gây ra ngoại lệ IOException nếu lỗi xảy ra. • read(byte[]): Trả về số byte đọc được hay ‘-1’ nếu như đã đọc đến cuối dòng. Luôn luôn đóng dòng để chắc chắn rằng dòng xử lý được kết thúc.int): Nó cũng đọc vào một mảng byte. Nếu như không có byte dữ liệu nào. Nó trả về số byte thực sự đọc được cho đến khi kết thúc dòng. Nó gây ra ngoại lệ IOException nếu lỗi xảy ra.ObjectOutputStream PipedOutputStream RandomAccessFile Reader BufferedReader LineNumberReader CharArrayReader FilterReader PushbackReader InputStreamReader FileReader PipedReader StringReader Writer BufferedWriter CharArrayWriter FilterWriter OutputStreamWriter FileWriter PipedWriter PrintWriter StringWriter Sau đây chúng ta xem xét các class quan trọng thường được sử dụng: II. Nó dùng để giải phóng mọi tài nguyên dòng đã sử dụng. Nó trả về true nếu dòng hỗ trợ ngược lại trả về false. các luồng đang thực hiện phải tạm dừng cho đến khi có dữ liệu. Khi một phương thức phải chờ. Có các phương thức chính sau: • read(): Đọc các byte dữ liệu từ một dòng. Nó trả về số byte hiện tại có trong dòng. Nó gây ra ngoại lệ IOException nếu có lỗi xảy ra.int. Nó không phải là phương thức tin cậy để thực hiện tiến trình xử lý đầu vào. • markSupported(): Trả về giá trị boolean chỉ ra rằng dòng có hỗ trợ các khả năng mark và reset hay không. • mark(): Đánh dấu vị trí hiện tại của dòng. • reset(): Phương thức này định vị lại dòng theo vị trí được đánh lần cuối cùng. • read(byte[]. • close(): Phương thức này đóng dòng. Nó gây ra ngoại lệ IOException nếu lỗi xảy ra. nó phải chờ.

ghi và xử lý kết xuất các dòng. Nó kích hoạt IOException nếu lỗi xảy ra.txt”). Lớp OutputStream Là lớp trừu tượng định nghĩa cách ghi các kết xuất đến dòng. Các tập tin đặt tên theo qui ước đặt tên tập tin của hệ điều hành. ta dùng File trong tất cả các thao tác quản lý file và thư mục. IV. • flush(): Phương thức này xả sạch dòng. Nó được dùng để giải phóng mọi tài nguyên gắn với dòng. Đệm dữ liệu được ghi ra dòng. Ví dụ: InputStream in = new FileInputStream(“C:\\LETI\\JAVA\\Account. Lớp FileOutputStream Lớp này cung cấp khả năng ghi dữ liệu xuống tập tin. Lớp File Lớp này được sử dụng để truy cập các đối tượng tập tin và thư mục. Nó kích hoạt IOException nếu lỗi xảy ra. Dòng phải chờ cho đến khi tác vụ ghi hoàn tất. Lớp OutputStream định nghĩa ba dạng khác nhau của phương thức để có thể ghi một byte riêng lẻ. Nó gây ra ngoại lệ IOException nếu lỗi xảy ra.• skip(): Phương thức này bỏ qua ‘n’ byte dòng vào. • FileOutputStream(File f). Các phương thức bao gồm: • write(int): Phương thức này ghi một byte. • FileOutputStream(FileDescriptor fdObj) VI. Như vậy. • FileInputStream(FileDescriptor fdObj): Tham số là đối tượng FileDescriptor để tạo luồng. một mảng các byte. • close(): Phương thức đóng dòng. Nó gây ra ngoại lệ IOException nếu lỗi xảy ra. Lớp này có 3 phương thức khởi tạo sau: • FileInputStream(String name): Tham số là tên của tập tin để tạo luồng. ’-n’ chỉ định số byte được bỏ qua. Có 3 phương thức khởi tạo: • FileOutputStream(String name). Các đối tượng của lớp này được tạo ra nhờ đường dẫn tới file. Nó cung cấp một tập các phương thức trợ giúp tạo ra. • FileInputStream(File f): Tham số là đối tượng file để tạo luồng. int. • write(byte[]): Phương thức này phong toả cho đến khi một byte được ghi. V. hay một đoạn của một mảng byte. lớp này cho phép đọc vào từ một tập tin dưới dạng một stream. đối tượng File. Phương thức này sử dụng để di chuyển tới vị trí đặc biệt bên trong dòng vào. • write(byte[]. hoặc đối tượng FileDescriptor làm một đối số. Lớp FileInputStream Kế thừa từ InputStream. Lớp này cung cấp các phương thức thiết lập các tập tin và các thư mục. Có 3 cách để tạo các đối tượng từ lớp File: 76 . Tất cả các thao tác thư mục và tập tin được thực hiện thông qua các phương thức của lớp File. được dẫn xuất từ lớp cha OutputStream. int): Phương thức này ghi mảng các byte. III.

out. • File(File dir. • public boolean isDirectory(): cho biết tập tin có phải thư mục hay không (true nếu có).out. System. true nếu xoá thành công. • public String getParent(): lấy tên thư mục cha. • public boolean mkdir(): tạo một thư mục từ đối tượng file. • public boolean isFile(): cho biết tệp tin có hợp lệ hay không (true nếu có). • public String toString(): trả về đường dẫn của tập tin. • public String gePath(): lấy đường dẫn của tập tin. String name). • public String[ ] list(FilenameFilter filter): lấy danh sách tập tin thoả mãn điều kiện lọc. File dir): tạo tập tin tạm thời.java").java"). • public String toURL(): trả về đối tượng URL tương ứng với tập tin. true nếu thành công. hoặc File f = new File("C:\jdk1.println(f. // Lấy đường dẫn tuyệt đối System. • renameTo(File dest): đổi tên tập tin hiện tại sang tên mới.java"). • public boolean canRead(): cho biết tập tin được phép đọc hay không (true nếu có) • public void setReadOnly(): đặt thuộc tính chỉ đọc. Ví dụ:File f = new File("C:\jdk1. String name). • public boolean isHidden(): kiểm tra xem tập tin có ẩn hay không (true nếu có)."). Chương trình ví dụ: public class Test { public static void main(String args[]) { File f = new File("test"). // Kiểm tra sự tồn tại } } 77 . • public Boolean createNewFile(): tạo một tập tin mới. File f = new File(curDir. • public void createTempFile(String pattern. ví dụ *. • public void deleteOnExit(): yêu cầu xoá tập tin khi chương trình chấm dứt. • public booean delete(): xoá tập tin. • File(String path.getAbsolutePath()). • public long length(): cho biết kích thước tập tin (byte).println(f. "Hello.4\bin". hoặc File curDir = new File(". "hello. • public String[ ] list(): lấy danh sách các tập tin và thư mục.4\bin\hello. Các phương thức: • public String getName(): lấy tên đối tượng tập tin. • public String getAbsolutePath(): lấy đường dẫn tuyệt đối của tập tin.exists()).• File(String path).gif. • public boolean canWrite(): cho biết tin có cho phép ghi hay không (true nếu có).

Nhập xuất lọc Là một kiểu dòng có được từ việc thay đổi cách xử lý dòng hiện có. Lớp này định nghĩa chồng tất cả các phương thức của OutputStream và không đưa thêm bất kì phương thức mới nào.VII.*. VIII. VIII. Nó là lớp cha của tất cả các lớp dòng xuất lọc. một sử dụng kích cỡ vùng đệm ngầm định. // Diem tong ket public final String mauda ="vang". VIII. Chương trình sau đây đọc và ghi thông tin của đối tượng SinhVien theo một format. Dữ liệu ghi vào lớp này có thể sửa đổi theo nhu cầu để thực hiện tác vụ lọc và sau đó được chuyển tới đối tượng OutputStream. Lớp FilterInputStream được thiết kế sao cho có khả năng kết chuỗi nhiều bộ lọc.util. Một dòng có thể được đọc và đưa kết quả cho một dòng khác. public class SinhVien extends People { private String Lop. Để thực hiện điều này chúng ta dùng vài tầng lồng nhau. Nó giúp chương trình đọc/ghi lượng dữ liệu nhỏ không ảnh hưởng lớn đến hiệu năng chung của hệ thống. mỗi sinh viên nằm trên một dòng trong file: // Ke thua lop People import java. Bộ lọc nằm giữa một dòng nhập và một dòng xuất. VII. import java.//Hang so private int ID.2 Lớp FilterOutputStream Lớp này là một dạng bổ trợ cho lớp FilterInputStream. Java sử dụng cơ chế nhập/xuất có lập vùng đệm để tạm thời lập cache dữ liệu vào/ra của một dòng.// Ma so SinhVien 78 . Vào/ra có sử dụng bộ đệm Vùng đệm là kho lưu trữ dữ liệu. VII.// Ten lop private double DiemTongKet. các dòng nhập xuất lọc của java sẽ giúp ta lọc vào/ra theo một số cách. một cho phép chỉ định kích cỡ của vùng đệm xuất.1 Lớp FilterInputStream: Đây là lớp trừu tượng.2 Lớp BufferedOutputStream Lớp này định nghĩa hai phương thức thiết lập. Nhờ đó chương trình có thể đọc dữ liệu từ dòng từng byte một mà không ảnh hưởng đến tốc độ thực hiện của hệ thống. Nó là cha của tất cả các lớp dòng nhập lọc.1 Lớp BufferedInputStream: Lớp này tự động tạo ra và duy trì vùng đệm để hỗ trợ thao tác vào. Các lớp. Nó thực hiện xử lý một quá trình nào đó trên các byte được truyền từ đầu vào đến đầu ra. Các bộ lọc có thể ghép với nhau khi đó đầu ra của bộ lọc này trở thành đầu vào của bộ lọc kia.StringTokenizer. Chúng ta có thể lấy dữ liệu từ vùng đệm thay vì quay trở lại nguồn ban đầu của dữ liệu.io.

} // Ham main public static void main(String[] argv) { // Dat gia trị bien static.Date homnay = new java. MaSo = Integer. } // Ghi thông tin sinh viên vào file public void GhiData(PrintWriter out) throws IOException { out.NamSinh +1).util.readLine(). // Tang ma so len 1 den gan cho SinhVien sau MaSo+=1. } // Đọc thông tin 1 sinh viên từ bộ đệm đọc public void DocData(BufferedReader in) throws IOException { String s = in.valueOf(DiemTongKet)+"|" + HoVaTen. HoVaTen = t.getYear() .nextToken()). // Id cua SinhVien duoc gan bang gia tri MaSo hien thoi cua lop ID=MaSo. DiemTongKet=dtk.TinhTuoi()) + "|" + String.String ht. // Đọc một dòng trong bộ đệm StringTokenizer t = new StringTokenizer(s.nextToken(). } // Khai bao chong phuong thuc toString() public String toString() { return String. return (homnay. sinh vien dau tien co ma so 1 SinhVien. DiemTongKet = Double.println(this.parseDouble(t.double dtk) { super(ns. // bien doi tuong Vector lưu các sinh viên 79 .MaSo=1.parseInt(t.valueOf(ID)+ "|" + String.util.protected static int MaSo.Date().nextToken()).valueOf(this.ht). } // Phuong thuc tinh tuoi protected int TinhTuoi() { java.parseInt(t.toString()).String l.// ma so chung de cap phat cho moi sinh vien public SinhVien(int ns.//goi constructor cua lop cha la People Lop = l.nextToken()). NamSinh = Integer. "|").

toString()).5).out."Letio3".addElement(k5).close(). // Dung interface Enumeration de duyet cac phan tu cua Vector java. g."Phan Thi Mai 4"."Letio3". svs[i]."Letio3".6). sv. } } catch(IOException ep) {} for(int i=0. } out.util.0).dat")).9).addElement(k2).println(svs[i]. // Them sinh vien vao Vector SinhVien k2 = new SinhVien(81.hasMoreElements()) { // Ep kieu. sv. dữ liệu có thể đọc hoặc ghi ở vị trí ngẫu nhiên thay vì liên tục. 80 .length.dat")).i<svs. SinhVien k4= new SinhVien(83. kieu Object la kieu cha cua moi kieu nen luon ep duoc SinhVien g = (SinhVien)enu. for(int i=0."".i++) { svs[i] = new SinhVien(0.length.DocData(in)."Letio3". sv. try { PrintWriter out = new PrintWriter(new FileWriter("C:\\LETI\\JAVA\\Sinhvien."Pham Thi Mai 3".addElement(k3).GhiData(out). sv. SinhVien k1 = new SinhVien(80."Tran Thi Mai 2".7).util. SinhVien k3 = new SinhVien(82. while (enu. } catch(Exception ep) {} // Doc tu file ra SinhVien[] svs = new SinhVien[5].Vector sv = new java.0.addElement(k4). SinhVien k5= new SinhVien(84."".8).nextElement().Vector(5). Lớp RandomAccessFile Lớp RandomAccessFile cung cấp khả năng thực hiện vào/ra theo một vị trí cụ thể bên trong một tập tin.Enumeration enu = sv.addElement(k1).elements().i<svs. Trong lớp này. try { BufferedReader in = new BufferedReader(new FileReader("C:\\LETI\\JAVA\\Sinhvien. }} IX."Letio3"."Hoang Thi Mai 5".util.java. sv."Nguyen Thi Mai 1".i++) System.

lập trình viên phải đảm bảo rằng mọi biến của lớp phải có kiểu Serializable hoặc phải khai báo một biến là transient để bỏ qua trong quá trình tuần tự hóa. Mặc định thì tất cả các kiểu dữ liệu nguyên thủy đều là tuần tự hóa. Trong một lớp cài đặt Serializable. private String firstName. Đối tượng thuộc lớp RandomAccessFile có thể được khởi tạo theo hai cách: • RandomAccessFile(String name. Đối tượng System. phải kiểm tra xem định nghĩa của lớp (hoặc lớp cha) có cài đặt Serializable hay không.Lớp RandomAccessFile thực hiện cả hai việc nhập và xuất. X. public class AccountRecord implements Serializable { private int account. Điều này rất quan trọng bởi vì một đối tượng ObjectOutputStream sẽ không xuất một đối tượng trừ khi đó là một đối tượng Serializable. private String lastName. Ví dụ: RandomAccessFile file = new RandomAccessFile(“C:\\LETI\\JAVA\\Account. Nó giúp ta đọc các ký tự được người dùng gõ vào từ bàn phím. Lớp này cũng hỗ trợ các quyền cơ bản về đọc hoặc ghi tập tin. số dư tài 81 . Sau đây là một ví dụ về xây dựng một lớp đối tượng khách hàng cho một ứng dụng ngân hàng sau đó ghi chúng vào file: import java. mode = "rw" . "r"). Trong đó mode là chế độ mở tập tin: mode = "r" . Lớp này hỗ trợ một số phương thức mới khác với phương thức đã thừa kế từ các lớp DataInput và DataOutput. Truy cập file ở chế độ tuần tự Khi làm việc với Java. Để cho phép một đối tượng của một lớp có thể sử dụng với ObjectInputStrems và ObjectOutputStreams. Giao diện Serializable được biết đến như là một giao diện “đính kèm” bởi vì bản thân nó không chứa bất kỳ một phương thức nào. lớp đó phải khai báo cài đặt giao diện Serializable. Trong các ứng dụng quản lý ta thường xuyên phải đọc và ghi dữ liệu về các đối tượng lên ổ cứng.chế độ ghi và đọc. String mode). Các phương thức mới thêm vào bao gồm: • seek( ): Thiết lập con trỏ tập tin tới vị trí cụ thể bên trong tập tin.txt”. ta có thể sử dụng phương thức read() hoặc kết nối với một luồng trung gian khác. XI. Với các kiểu không nguyên thủy. tất cả đều là đối tượng. private double balance. Một class cài đặt giao diện này được gán một thông báo rằng đối tượng của lớp là một đối tượng Serializable.Serializable.in Là một đối tượng đặc biệt được tạo ra từ lớp InputStream. • getFilePointer( ): Trả về vị trí hiện hành của con trỏ tập tin. Các lớp ObjectInputStream và ObjectOutputStream cho phép chúng ta đọc và ghi đối tượng vào file. có thể thực hiện I/O bằng các kiểu dữ liệu nguyên thuỷ. // Chỉ số nắm giữ hàng hóa và dịch vụ của khách hàng. • length( ): Trả về chiều dài của tập tin tính theo byte. Do vậy.chế độ chỉ đọc. • RandomAccessFile(File f. điều này cho phép đọc tập tin theo chế độ chỉ đọc hoặc đọc-ghi.io. String mode).

} } 82 . "". 0.0 ). setLastName( last ). } public int getAccount()// Lấy số tài khoản { return account. } public void setBalance( double bal ) // Đặt giá trị cho balance { balance = bal. } public void setFirstName( String first ) // Ðặt giá trị cho phần họ đệm { firstName = first. String first. } public double getBalance()// Lấy số dư { return balance. } public String getFirstName()// Lấy phần họ đệm { return firstName. } public AccountRecord( int acct. "". } public void setLastName( String last ) // Ðặt giá trị cho tên { lastName = last. } public String getLastName()// Lấy tên { return lastName. double bal ) // Constructor có tham số { setAccount( acct ).khoản public AccountRecord()// constructor không tham số { this( 0. String last. setFirstName( first ). } public void setAccount( int acct ) // Ðặt số tài khoản { account = acct. setBalance( bal ).

AccountRecord record2= new AccountRecord( 12346.12)."Phan Tien ".Chương trình sau đây sẽ ghi các đối tượng vào file C:\LETI\JAVA\Account. public class GhiFile { ObjectOutputStream output. } catch ( IOException ioException ) { System. } } // Hàm main public static void main(String[] argvs) { AccountRecord record1= new AccountRecord( 12345.openFile().txt") ).flush().12).-5. 83 ."Minh".*. g.close()."Nguyen Van ". } // Nếu có lỗi đóng file catch ( IOException ioException ) { System. public void openFile() { try { output = new ObjectOutputStream(new FileOutputStream( "C:\\LETI\\JAVA\\Account.5.io.writeObject( record ).print("Loi mo file"). } catch(IOException ex) { System. System.out.exit( 1 ).txt import java. output. } } public void addRecord(AccountRecord record) // Phương thưc thêm 1 bản ghi vào file { try { output.out. } } public void closeFile() // Phương thức đóng file { try { output.print("Loi ghi file"). GhiFile g = new GhiFile().exit( 0 )."Hai".

g.out.io.addRecord(record1). try { AccountRecord a = (AccountRecord)input.valueOf( a.io. } catch ( IOException ioException ) { System.close(). public void openFile() // Mở file { try { input = new java.ObjectInputStream(new FileInputStream("C:\\LETI\\JAVA\\Account.io. } catch(Exception p){} finally {return account. public class DocFile { java.exit( 0 ). account =String. } } // Phương thức đọc 1 bản ghi public String readFile() { String account="". } catch(IOException e) { System.ObjectInputStream input. } } public void closeFile() //Đóng file { try { input. g.readObject().} 84 .getLastName() + "\n " + String.print("Loi mo file").addRecord(record2).exit( 1 ).getAccount() ) + "\n " + a.txt")).closeFile().getBalance()). System.getFirstName() + "\n " + a. g. }} Chương trình sau đây đọc ra 2 bản ghi vừa được ghi ở chương trình trên và in ra màn hình: import java.*.valueOf( a.

io. Tất nhiên là các file văn bản cũng có thể đọc ghi ở chế độ nhị phân.readFile()).doc")).write(data).available(). System.DataOutputStream out.DataOutputStream(new FileOutputStream("C:\\G.out.close(). public class BinaryAccess { public static void main(String[] argvs) { java.read(data). int bytesAvailable = in.io. // Đọc các byte ra một mảng byte out. Truy cập file nhị phân Ngoài các công cụ thao tác trên file văn bản. d.println(d.doc: import java.openFile().} public static void main(String[] argvs) { DocFile d = new DocFile(). }} XII.println(d. • DataInputStream: Hỗ trợ đọc file ở chế độ nhị phân. // Ghi mảng byte này vào một file khác } in. in.*.out. d.io.DataInputStream(new FileInputStream("C:\\P. // Luồng ra hỗ trợ ghi file nhị phân java. Java hỗ trợ cả các thao tác với file nhị phân dùng các đối tượng: • DataOutputStream: Hỗ trợ ghi file ở chế độ nhị phân tức là từng byte. // số byte của file if (bytesAvailable > 0) { byte[] data = new byte[bytesAvailable]. } catch (Exception ex) {} }} 85 .doc")).close().closeFile(). out. Chương trình sau đây copy dữ liệu giữa hai file dạng .io.readFile()).io. System. out = new java.DataInputStream in. // Luồng vào hỗ trợ đọc file nhị phân try { in = new java.

98. 2. Họ và tên. Viết một chương trình nhập vào một chuỗi từ bàn phím sau đó ghi chuỗi ra file. Phan Anh Thu. 1. 4. chiều cao. Ha Nam 009. Cho một file có dữ liệu về thí sinh thi hoa hậu như sau: 001. 1. Ha Tay 002.89. Viết một chương trình đọc dữ liệu của file ra và gán mỗi dòng cho một đối tượng HOAHAU. 3. Tran Thi Mong Mo.Bài tập 1. Nguyen Thu Thuy. 1. Quê quán. Viết chương trình copy dữ liệu từ một file ảnh GIF sang một file ảnh GIF khác.78. Bùi Thị Thanh Nhàn. 1. Thanh Hoa Các dữ liệu lần lượt mô tả về: Mã số. Viết một chương trình copy dữ liệu từ một file văn bản sang một file văn bản khác. Ha Noi 003.70. 86 .

lỗi có thể xảy ra với rất nhiều lý do. Xử lý ngoại lệ Khi viết một chương trình nói chung và trong Java nói riêng. nó có thể “quăng. Cơ sở quản lý ngoại lệ trong Java Khi một phương thức không thể hoàn thành nhiệm vụ của nó.Đề tài 7. Khi lỗi xảy ra. • Lỗi phần cứng như thiếu ổ cứng hay bộ nhớ. Mỗi khối catch xác định một kiểu exception mà nó có thể bắt và chứa đoạn code xử lý trong trường hợp tương ứng. đưa vào các xử lý ngoại lệ để xử lý theo một cách riêng thống nhất. Tuy nhiên điều này là rất khó khăn bởi lỗi có thể đến do một trong các nguyên nhân: • Người dùng nhập dữ liệu sai.đoạn code xử lý khi lỗi xảy ra – thì Exception này sẽ bị “bắt” (catch) và “được quản lý”(handled). Java cho phép người lập trình quản lý các lỗi theo cách khi nó xảy ra. try{ 87 . • Ghi lại các dữ liệu hiện thời và kết thúc chương trình. • Xử lý các ngoại lệ từ một thành phần chương trình chưa được quản lý ngoại lệ • Trong các dự án lớn. I. người sử dụng chương trình muốn rằng chương trình có thể: • Quay lại trạng thái an toàn trước đó và cho phép người dùng thực hiện các công việc khác. II. chúng ta gọi đó là một ngoại lệ (exception) – những điều xảy ra khác thường. ném”(throws) ra một Exception. Cú pháp để thực hiện điều này như sau: try { // Đoạn chương trình có thể gây ra exception } catch (<Kiểu exception> <tên biến>) { // Đoạn code chạy khi exception xảy ra } finally { // Đoạn code luôn được thực hiện bất kể exception có xảy ra hay không } Một khối try có thể không có hoặc có nhiều khối catch. chương trình sẽ thực hiện những việc do chính lập trình viên đặt ra. gọi là exception handling. nếu có một Exception handler . Các tình huống sử dụng ngoại lệ Việc quản lý các ngoại lệ nên được sử dụng khi: • Một phương thức không thể hoàn thành nhiệm vụ của nó vì một lý do rằng nó không thể điều khiển được mọi chuyện. Trong một đoạn chương trình mà lập trình viên không thể biết trước được liệu có chuyện gì xảy ra làm cho đoạn chương trình đó gây ra lỗi hay không. • Lỗi thiết bị.

ExceptionType2. Ví dụ: int functionName( parameterList ) throws ExceptionType1. sử dụng phương thức getMessage() của các lớp Exception. Tại điểm quăng ra ngoại lệ (throw point). ExceptionType3.. ví dụ: e3.. Cấu trúc cây kế thừa các xử lý ngoại lệ Trong Java có hàng trăm lớp ngoại lệ để “bắt” các lỗi tương ứng như lỗi vào/ra file. Các ngoại lệ này được quăng ra bởi các lệnh throw hoặc việc gọi một phương thức khác trong phương thức này. lỗi truy cập CSDL SQL. { // Thân phương thức } III. chương trình sẽ tìm đến khối catch có kiểu đối tượng Exception phù hợp để thực hiện. Khi lỗi xảy ra. Mỗi khối try bắt buộc phải có một khối catch hoặc finally. Trong một phương thức ta có thể khai báo một mệnh đề throws để phương thức “quăng” ra các ngoại lệ. Java sử dụng cơ chế kết thúc chương trình thay vì cơ chế quay trở lại điểm xảy ra ngoại lệ và tiếp tục.getMessage().…Các ngoại lệ trong Java đều kế thừa từ lớp Throwable theo cấu trúc như sau: 88 . Để lấy được thông báo từ hệ thống về lỗi.//code có thể throw exceptions } catch (MalformedURLException e1) { //code xử lý } catch (UnknownHostException e2) { //code xử lý } catch (IOException e3) { //code xử lý } Sau khối catch cuối cùng. có thể có hoặc không một khối finally chứa code xử lý bất kể exception có xảy ra hay không.

Sử dụng ngoại lệ được kiểm soát Trong phần trên đã bàn về cách sử dụng các exception để bắt các lỗi không được kiểm soát. Khi truy cập đối tượng null. Ví dụ trong phương thức khởi tạo sau: public FileInputStream(String name) throws FileNotFoundException Ở đây phương thức nhận một tham số kiểu String như là tên file. chương trình sẽ tìm tới vị trí định nghĩa exception handler để quản lý lỗi này. Các ngoại lệ dạng này được khai báo ở phần đầu các phương thức. Khi gặp lỗi như vậy. Cơ chế bảo mật không cho phép thực hiện. Trong phần này chúng ta sẽ xem cách sử dụng ngoại lệ để quản lý các tình huống có thể kiểm soát được. Khi một luồng bị ngắt. Không thể nạp lớp yêu cầu. Đối số không hợp lệ. Ngoại lệ về AWT Lớp cha của các lớp ngoại lệ I/O Không thể định vị tập tin Kết thúc một tập tin. IV. Việc chuyển đối từ chuỗi sang số thực không thành công. ví dụ như ‘chia cho 0’. Một vấn đề là lập trình viên không biết throws ra ngoại lệ nào hoặc không thể khai báo hết tất cả các ngoại lệ.Danh sách các ngoại lệ thường dùng trong Java Ngoại lệ RuntimeException ArthmeticException IllegalAccessException IllegalArgumentException ArrayIndexOutOfBoundsExeption NullPointerException SecurityException ClassNotFoundException NumberFormatException AWTException IOException FileNotFoundException EOFException NoSuchMethodException InterruptedException Ý nghĩa Lớp cơ sở cho nhiều ngoại lệ java. Tuy nhiên. Phương thức yêu cầu không tồn tại. Lớp không thể truy cập. chẳng hạn như FileInputStream. tuy nhiên rất có thể file không tồn tại hoặc là một file rỗng và không có gì để đọc. 89 . Lỗi tràn mảng.lang Lỗi về số học. có 4 tình huống để đưa ra ngoại lệ: • Khi gọi một phương thức có throw một ngoại lệ. • Khi ta xác định được một lỗi và throws một exception bằng một lệnh throw.

} } Các ngoại lệ bắt lỗi nội bộ của Java thường không nên được khai báo. chúng kế thừa từ lớp RuntimeException cũng vậy. Ví dụ: class MyAnimation { . Các class ngoại lệ này được kế thừa từ lớp Exception hoặc lớp con của nó như IOException chẳng hạn. ta không nên khai báo chúng. } } Phương thức có thể throws nhiều ngoại lệ nếu cần: class MyAnimation { . Một phương thức cần khai báo ngoại lệ phù hợp: class MyAnimation { .. • Khi một lỗi bên trong hệ thống như trong JVM hoặc các thư viện động. sẽ dẫn đến việc kích hoạt một ngoại lệ. nếu chúng ta có kế hoạch để khai báo nó thì tốt nhất là tìm cách để khắc phục không cho chúng xảy ra.......Khi viết một chương trình bị lỗi.. void drawImage(int i) throws ArrayIndexOutOfBoundsException // Không phù hợp { . MalformedURLException { . chẳng hạn ở đây là ArrayIndexOutOfBoundsException.. } } Đối với các ngoại lệ dạng RuntimeException. chẳng hạn a[-1] = 0.. Xây dựng một ngoại lệ Chúng ta có thể tự xây dựng một ngoại lệ để throws trong những trường hợp cụ thể.. public Image loadImage(String s) throws EOFException. 90 .. đó là các ngoại lệ kế thừa từ lớp Error vì chúng vượt khỏi tầm kiểm soát của chúng ta. public Image loadImage(String s) throws IOException { . Đối với các ngoại lệ không được kiểm soát. Ví dụ: class FileFormatException extends IOException { public FileFormatException() {} public FileFormatException(String gripe) { super(gripe). • V.

} return s. .. } . } VI.) { if (ch = = -1) // Điểm cuối file { if (n < len) throw new FileFormatException(). . Chú ý dùng các ngoại lệ để kiểm soát tất cả các tình huống có thể. Viết chương trình đọc một file trên ổ đĩa và in ra màn hình. 3. while (. 91 .. ta có thể sử dụng ngoại lệ này trong chương trình: String readData(BufferedReader in) throws FileFormatException { . 2. Bài tập 1.} } Sau đó... Bắt ngoại lệ khi người dùng nhập vào ký tự hoặc số thực có phần thập phân. Viết chương trình nhập một số nguyên từ bàn phím. Khai báo một lớp ngoại lệ để kiểm soát tình huống điểm một sinh viên vượt quá 10 hay tuổi của sinh viên vượt quá 100 trong ứng dụng quản lý sinh viên ở đề tài “Lập trình hướng đối tượng trong Java”.

Trong Java sử dụng một cách tiếp cận dựa trên các khái niệm: . Đối với một ngôn ngữ OOP như Java thì toàn bộ thông tin về sự kiện được đóng gói trong một lớp event. chúng có các phương thức để lập trình viên đăng ký các bộ lắng nghe cho chúng.Các nguồn của sự kiện (event source). Sau đây là cây phân cấp chỉ sự kế thừa giữa các lớp sự kiện trong Java: 92 . Các nguồn sự kiện chính là các đối tượng điều khiển. Khái niệm và cơ sở xử lý sự kiện Bất kỳ chương trình có giao diện đồ họa nào thường hỗ trợ việc kích hoạt các sự kiện từ con chuột hoặc bàn phím. Khi một sự kiện xảy ra đối với một nguồn sự kiện. Tất cả các lớp event đều dẫn xuất từ lớp java. Xử lý các sự kiện trong Java I.EventObject. Môi trường điều hành sẽ gửi các sự kiện này tới chương trình đang chạy.util. nó sẽ gửi thông báo này tới tất cả các bộ lắng nghe sự kiện được đăng ký cho sự kiện đó. chẳng hạn như ActionEvent và WindowEvent. Mỗi loại sự kiện tương ứng với một lớp dẫn xuất.Đề tài 8. Lập trình viên được hoàn toàn quyết định điều gì sẽ xảy ra khi các sự kiện này được kích hoạt.Các bộ lắng nghe sự kiện (event listener). .

add<sự kiện>Listener(<đối tượng lắng nghe sự kiện>) Ví dụ: ActionListener listener = . v. Sơ đồ sequence cho đoạn code trên như sau: 93 . public void actionPerformed(ActionEvent event) { // Đoạn mã xử ký sự kiện đặt ở đây . một sự kiện được quản lý dựa trên các khái niệm: 1. Nguồn sự kiện gửi đối tượng sự kiện tới tất cả các đối tượng lắng nghe được đăng ký cho sự kiện đó. Một đối tượng lắng nghe là một biểu hiện của một lớp có cài đặt giao diện lắng nghe sự kiện 2.v. } } Bất cứ khi nào người dùng click chuột vào đối tượng JButton trên màn hình. Một nguồn sự kiện là một đối tượng mà có thể đăng ký các đối tượng lắng nghe và gửi cho chúng các đối tượng sự kiện. Mỗi loại sự kiện cũng có giao diện lắng nghe tương ứng. một sự kiện ActionEvent được phát sinh và gửi cho đối tượng lắng nghe listener. . Có thể có nhiều bộ lắng nghe được đăng ký cho một nguồn sự kiện. Đối tượng lắng nghe sẽ sử dụng thông tin trong các đối tượng sự kiện để phản ứng với các sự kiện đó. Ví dụ một button (nút bấm) thì phát sinh sự kiện ActionEvent trong khi một cửa sổ lại phát sinh sự kiện WindowEvent.addActionListener(listener). 3. lấy đối số là đối tượng ActionEvent nhận được... vấn đề còn lại là đối tượng lắng nghe sự kiện phải có một phương thức để nhận về sự kiện từ nguồn sự kiện đăng ký nó và xử lý. // đăng ký đối tượng lắng nghe sự kiện Trong đoạn code trên. ... // Nguồn sự kiện button. Đối tượng này có cài đặt một phương thức để xử lý sự kiện là actionPerformed.Các giao diện lắng nghe sự kiện bao gồm: AdjustmentListener MouseWheelListener FocusListener WindowListener ItemListener WindowFocusListener KeyListener WindowStateListener MouseListener Các nguồn sự kiện khác nhau có thể phát sinh các sự kiện khác nhau. Ở đây.. Cú pháp để đăng ký các đối tượng lắng nghe cho các nguồn sự kiện theo cú pháp sau: <nguồn sự kiện>. 4.. // đối tượng lắng nghe JButton button = new JButton("Ok"). khi đó sự kiện cũng được gửi tới tất cả các bộ lắng nghe và tới phương thức actionPerformed của chúng.. Tóm lại. Trong giao diện này có khai báo một phương thức actionPerformed để nhận về một sự kiện ActionEvent: class MyListener implements ActionListener { . đối tượng listener phải thuộc một lớp có cài đặt giao diện ActionListener.Các sự kiện trên được gửi cho các đối tượng lắng nghe tương ứng như: ActionListener MouseMotionListener.

JButton blueButton = new JButton("Blue").gif")). } } 94 . JButton blueButton = new JButton(new ImageIcon("blue-ball. JButton redButton = new JButton("Red"). Thêm 3 Button vào 1 panel như sau: Class ButtonPanel extends JPanel { public ButtonPanel() { JButton yellowButton = new JButton("Yellow"). add(yellowButton). add(blueButton).Sau đây là một ví dụ về xử lý sự kiện click cho 3 đối tượng Jbutton: Một Button được tạo ra như sau bằng cách gọi constructor của JButton với một chuỗi nhãn hoặc một ảnh hay cả hai: JButton yellowButton = new JButton("Yellow"). add(redButton).

} } Một vấn đề đặt ra là phương thức setBackground() không được định nghĩa trong lớp ColorAction mà chỉ được định nghĩa cho lớp Panel. ta có thể truy cập các phương thức của lớp Panel (được ButtonPanel kế thừa) như setBackground chẳng hạn. add(redButton). JButton redButton = new JButton("Red"). blueButton. ColorAction yellowAction = new ColorAction(Color. ColorAction blueAction = new ColorAction(Color. redButton.addActionListener(blueAction).addActionListener(redAction). Class ButtonPanel extends JPanel { public ButtonPanel() { JButton yellowButton = new JButton("Yellow"). yellowButton.Red). add(yellowButton). JButton blueButton = new JButton("Blue").Yellow). // Thay đổi màu nền của panel khi Button được click } private Color backgroundColor.addActionListener(yellowAction).Blue). } public void actionPerformed(ActionEvent e) { setBackground(backgroundColor).Bây giờ chúng ta định nghĩacác bộ lắng nghe cho các Button này gọi là ColorAction như sau: public class ColorAction implements ActionListener { public ColorAction(Color c) { backgroundColor =c. } Mỗi đối tượng Button được đăng ký cho bộ lắng nghe này: Class ButtonPanel extends JPanel { public ButtonPanel() { JButton yellowButton = new JButton("Yellow"). Giải pháp ở đây là đưa lớp ColorAction thành lớp nội của lớp ButtonPanel. JButton blueButton = new JButton("Blue"). add(blueButton). khi đó trong lớp ColorAction. 95 . ColorAction redAction = new ColorAction(Color.

this. } private class ColorAction implements ActionListener { public ColorAction(Color c) { backgroundColor =c.Red). add(yellowButton).swing.JFrame. // Thay đổi màu nền của panel khi Button được click } private Color backgroundColor.JButton redButton = new JButton("Red").Yellow). add(redButton). ColorAction redAction = new ColorAction(Color. p.setVisible(true).setSize(300. } } Chương trình sau đây kiểm tra sự thực hiện đáp ứng các sự kiện vừa thiết kế ở trên: import javax. ColorAction blueAction = new ColorAction(Color.addActionListener(blueAction). add(blueButton).add(pn). } public static void main(String[] argvs) { testPanel p = new testPanel().addActionListener(yellowAction). yellowButton. // Đăng ký bộ lắng nghe sự kiện blueButton.Blue). } } 96 . ColorAction yellowAction = new ColorAction(Color. redButton. } public void actionPerformed(ActionEvent e) { setBackground(backgroundColor). p. public class testPanel extends JFrame { public testPanel() { ButtonPanel pn = new ButtonPanel().addActionListener(redAction).400).

public ButtonPanel() { yellowButton = new JButton("Yellow").BLUE). lớp chứa các nguồn sự kiện phải cài đặt giao diện ActionListener. public class ButtonPanel extends JPanel implements ActionListener { JButton yellowButton. phương thức actionPerformed sẽ có sự hành xử khác nhau. Do đó.swing. import java. II.*. if (event.*. } } Trong ví dụ trên. Tùy theo thông tin về sự kiện nhận được.YELLOW). if (event.Thông thường. bản thân lớp component ButtonPanel đóng vai trò là lớp lắng nghe sự kiện vì nó có cài đặt giao diện ActionListener. JButton redButton.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent event) { setBackground(Color. Làm như vậy ta không cần thiết kế riêng một lớp ColorAction.YELLOW). Các đối tượng Button bây giờ cũng phải khai báo là biến thành phần của lớp vì 97 .getSource()==yellowButton) setBackground(Color. redButton = new JButton("Red").RED).addActionListener(this). } public void actionPerformed(ActionEvent event) { if (event. Muốn vậy. ta chỉ việc sử dụng biến this. blueButton = new JButton("Blue"). yellowButton. import javax.getSource()==blueButton) setBackground(Color.addActionListener(this). các lớp lắng nghe sự kiện có thể được cài đặt ngay trong phương thức addActionListener như sau: yellowButton. khi đăng ký đối tượng lắng nghe cho các Button.addActionListener(this). redButton. add(redButton).event. JButton blueButton. add(blueButton). } }).awt. add(yellowButton).getSource()==redButton) setBackground(Color. Truy cập thông tin sự kiện Một phương pháp khác để lập trình sự kiện đó là gán cho tất cả các đối tượng nguồn sự kiện chung một đối tượng lắng nghe. blueButton. đại diện cho đối tượng ngầm định của chính lớp ButtonPanel.

. ta cũng qua các bước căn bản sau: WindowListener listener = new ..chúng được truy cập trong 2 phương thức khác nhau. Các lớp thích nghi Ta thấy rằng việc khai báo đầy đủ 7 phương thức. Các lớp có vai trò trung gian như vậy 98 . III. Xử lý các sự kiện trên window Phần trên đã cho thấy cách thức chúng ta làm việc với các nguồn sự kiện là các đối tượng nằm trong một window. Phần này ta sẽ xem xét các sự kiện xảy ra đối với bản thân một window. khai báo cài đặt giao diện WindowListener với đầy đủ 7 phương thức nhưng các phương thức này cũng không làm gì cả. void windowIconified(WindowEvent e). void windowActivated(WindowEvent e). là đối tượng nguồn sự kiện phát sinh các sự kiện WindowEvent. frame. Tuy nhiên phương pháp này sẽ trở nên khó dùng khi trên panel có nhiều đối tượng nguồn sự kiện. } Do đó các lớp cài đặt giao diện này phải khai báo định nghĩa tất cả các phương thức trên. Đối tượng listener bắt buộc phải thuộc một lớp có cài đặt giao diện WindowListener. Các lớp muốn cài đặt nội dung cho một sự kiện chỉ việc khai báo kế thừa lớp này và định nghĩa chồng phương thức cần thiết. void windowClosed(WindowEvent e).exit(0). Tuy nhiên. // thu nhỏ của sổ void windowDeiconified(WindowEvent e). } public void windowOpened(WindowEvent e) {} public void windowClosed(WindowEvent e) {} public void windowIconified(WindowEvent e) {} public void windowDeiconified(WindowEvent e) {} public void windowActivated(WindowEvent e) {} public void windowDeactivated(WindowEvent e) {} } IV. void windowClosing(WindowEvent e)..addWindowListener(listener). ta chỉ viết code cho phương thức nào ta xử lý mà thôi. Muốn bắt các sự kiện của window. có những phương thức không xử lý gì cả làm cho chương trình không được tối ưu. Giải pháp ở đây sẽ là định nghĩa một lớp trung gian.. void windowDeactivated(WindowEvent e). Trong đó frame là một đối tượng của lớp JFrame. Cấu trúc của giao diện này như sau: public interface WindowListener { void windowOpened(WindowEvent e). ví dụ: class Terminator implements WindowListener { public void windowClosing(WindowEvent e) { System.

exit(0).addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent event) { System. Gửi đối tượng này cho phương thức addWindowListener. Ví dụ: WindowListener có lớp thích nghi WindowAdapter. ta có một lớp thích nghi tương ứng. Lúc này.addWindowListener(new Terminator()). Với mỗi giao diện lắng nghe. 3. } public void windowIconified(WindowEvent e) {System. kỹ thuật định nghĩa lớp nội nặc danh được phát huy: frame. Đoạn code này thực hiện các công việc sau: 1. 2. đối tượng cũng không có tên. Tạo ra một đối tượng của lớp đó. 4. Ta có thể định nghĩa chồng nhiều hơn một phương thức của WindowAdapter. Các lớp thích nghi thường dùng là: FocusAdapter MouseMotionAdapter KeyAdapter WindowAdapter MouseAdapter class Terminator extends WindowAdapter { public void windowClosing(WindowEvent e) { System. Một cách làm khác là khai báo một lớp (thường là lớp nội) dạng như class Terminator ở trên. } } Vấn đề là các lớp window thường phải khai báo kế thừa từ JFrame rồi nên không thể khai báo kế thừa thêm lớp WindowAdapter. MouseListener có MouseAdapter.exit(0). sau đó đăng ký lắng nghe sự kiện cho frame mà không cần một đối tượng có tên rõ ràng của Terminator: frame. Để kết thúc đề tài này ta liệt kê các phương thức xử lý cho các loại sự kiện như bảng sau: Interface ActionListener Methods actionPerformed Parameter/Accessors ActionEvent • Nguồn sự kiện AbstractButton JComboBox JTextField Timer getActionCommand 99 .} } ). Thêm 2 phương thức windowClosing và windowIconified cho lớp nặc danh đó.exit(0). 5.gọi là các lớp thích nghi. Tất nhiên là không phải khi nào ta cũng phải sử dụng lớp nội nặc danh. Kế thừa 5 phương thức còn lại từ WindowAdapter. Định nghĩa một class nặc danh kế thừa lớp WindowAdapter.

Interface

Methods

Parameter/Accessors

Nguồn sự kiện

getModifiers

AdjustmentListener

adjustmentvalueChanged AdjustmentEvent
• • •

JScrollbar

getAdjustable getAdjustmentType getValue AbstractButton JComboBox

ItemListener

ItemstateChanged

ItemEvent
• • •

getItem getItemSelectable getStateChange Component

FocusListener

FocusGained focusLost keyPressed keyReleased keyTyped

FocusEvent

isTemporary Component

KeyListener

KeyEvent
• • • • •

getKeyChar getKeyCode getKeyModifiersText getKeyText isActionKey Component

MouseListener

mousePressed mouseReleased mouseEntered mouseExited mouseClicked

MouseEvent
• • • • •

getClickCount getX getY getPoint TRanslatePoint Component

MouseMotionListener

mouseDragged mouseMoved mousewheelMoved

MouseEvent

MouseWheelListener

MouseWheelEvent

Component

100

Interface

Methods

Parameter/Accessors
• •

Nguồn sự kiện

getWheelRotation getScrollAmount Window

WindowListener

windowClosing windowOpened windowIconified windowDeiconified windowClosed windowActivated windowDeactivated

WindowEvent

getWindow

WindowFocusListener windowGainedfocus windowlostFocus WindowStateListener WindowStateChanged

WindowEvent

Window

getOppositeWindow Window

WindowEvent
• •

getOldState getNewState

V. Xử lý các sự kiện chuột
Các sự kiện với chuột được xử lý bởi giao diện MouseListener. Khi một nguồn sự kiện được kích hoạt bởi việc click chuột, các phương thức xử lý cho các sự kiện tương ứng được liệt kê trong bảng trên, đặc biệt hay dùng là mouseClicked(). Thông thương ta cũng không cài đặt xử lý cho tất cả các sự kiện này nên ta không cài đặt giao diện MouseListener mà khai báo một lớp nội nặc danh kế thừa từ lớp thích nghi MouseAdapter. Giả sử có một đối tượng JFrame tên là frame, sau đây là một ví dụ quản lý sự kiện click chuột trên nó: frame. addMouseListener( new MouseAdapter() { public void mouseClicked(MouseEvent e) // Mac dinh la chuot trai { // Kiem tra neu la chuot phai duoc click if( (e.getModifiers() & InputEvent.BUTTON3_MASK)== InputEvent.BUTTON3_MASK) // hien thi mot popup menu tai vi tri click jp.show(getContentPane(),e.getX(),e.getY()); } } ); Tham khảo thêm tại: http://java.sun.com/docs/books/tutorial/uiswing/events/handling.html và http://java.sun.com/docs/books/tutorial/uiswing/events/mouselistener.html

101

Bài tập
1. Viết chương trình xử lý sự kiện chuột click trên các Botton, nếu là chuột trái thì thông báo là “Bạn vừa click chuột trai”, nếu là chuột phải thì thông báo “Bạn vừa click chuột phải”. 2. Viết chương trình sau khi chọn một Button trên màn hình, nhấn phím x thì chương trình kết thúc.

102

Đề tài 9. Applet
Applet là một trong những kỹ thuật vượt trội của Java so với các ngôn ngữ khác. Một Applet là một chương trình Java được nhúng vào trong các trang web, nó đứng một vị trí độc lập bên cạnh các phần khác của trang web.

I. Xây dựng một Applet đơn giản
1. Soạn thảo một tệp có tên “Hello.java” như sau: import java.applet.Applet; //khai báo thư viện import java.awt.Graphics; //Khai báo đồ hoạ public class Hello extends Applet { //cài đặt phương thức cho Applet public void paint(Graphics g){ g.drawString("Hello!", 50, 25); } 2. Biên dịch tệp Hello.java 3. Soạn thảo một trang HTML có tên hello.htm <html><body> <applet> <applet code="Hello.class" width=150 height=25> </applet> </body></html> 4. Đặt file Hello.class và hello.htm vào trong cùng một thư mục 5. Mở file hello.htm. Tuy nhiên để các applet có thể chạy được, nó cần một JVM trên máy cục bộ. Để có được JVM cho các trình duyệt ta cần cài phiên bản Java lên máy tính cục bộ và tích hợp vào trình duyệt như một plug-in. Trong các phiên bản Java gần đây, người lập trình có thể sử dụng thư viện swing nằm trong gói javax.swing để có được giao diện GUI thống nhất trên mọi hệ thống. Các lớp trong swing có tên gọi khác so với các lớp trong awt bởi thêm ký tự đầu tiên “J”.

II. Cấu trúc cơ bản và vòng đời của một Applet
Một chương trình Applet đầy đủ sẽ bao gồm các thành phần như sau: import java.applet.Applet; public class myApplet extends Applet{ public void init(){ ...... } public void start(){ ...... } public void stop() { ...... } public void destroy() { ...... } .... //Các phương thức khác } Nếu dùng JApplet thì ta có khai báo phần đầu như sau: import javax.swing.JApplet; public class myApplet extends JApplet{…}

103

Vòng đời của một Applet được đánh dấu bởi các sự kiện diễn ra ở mỗi giai đoạn, lập trình viên cần nắm được ý nghĩa của từng giai đoạn để có thể viết code điều khiển Applet: 1. Giai đoạn init: Thực hiện các công việc khởi tạo một Applet. Giai đoạn này được bắt đầu ngay sau khi thẻ <param> nằm trong thẻ <applet> được xử lý. Các hành động như thêm các thành phần giao diện người dùng GUI được thực hiện ở đây. 2. Giai đoạn start: Được thực hiện ngay sau khi giai đoạn init được thực hiện xong. Nó cũng được gọi bất cứ khi nào người dùng chuyển sang một trang web khác rồi quay lại trang có applet. Do đó, code nằm trong start có thể được thực hiện nhiều lần trong khi code trong init chỉ được thực hiện 1 lần. 3. Giai đoạn stop: Được thực hiện khi người dùng rời khỏi trang web chứa applet. Do đó, code nằm trong stop cũng có thể được thực hiện nhiều lần. 4. Giai đoạn destroy: Được thực hiện khi người sử dụng tắt trình duyệt. Khi viết một applet, chúng ta không phải khi nào cũng cài đặt đầy đủ 4 phương thức mà tùy theo nhu cầu. Ví dụ sau xây dựng một applet cho phép vẽ liên tiếp bắt đầu từ vị trí giữa applet. import java.applet.*; import java.awt.*; import java.awt.event.*; public class AppletSample extends Applet { Point curentPoint; // Lưu tọa độ điểm hiện tại public void init() { curentPoint = new Point(this.getWidth()/2,this.getHeight()/2); this.setBackground(Color.CYAN); // đặt màu nền của applet } public void start() { this.addMouseListener( new MouseAdapter() { public void mouseClicked(MouseEvent e) { drawOnApplet(curentPoint,e.getPoint()); curentPoint = e.getPoint(); } } ); } public void drawOnApplet(Point p1, Point p2) { Graphics g = this.getGraphics(); g.drawLine(p1.x,p1.y,p2.x,p2.y); } }

104

addActionListener(new ActionListener() { 105 . calcButton. Applet không thể tìm thấy các thông tin cá nhân như email. trừ các thông tin như phiên bản Java. An ninh và khả năng của Applet Vì applet được download từ xa và thực hiện trên máy tính cụ bộ nên vấn đề về an ninh được quan tâm đặc biệt. Ứng dụng Applet với của sổ Popup Với Applet chúng ta hoàn toàn có thể có thêm các cửa sổ pop-up để mở rộng không gian làm việc. 200).… • Tất cả các cửa sổ trình duyệt có applet được tải về đều có thông báo. • Các applet được nạp từ hệ thống tập tin cục bộ sẽ không bị các giới hạn của các applet được nạp từ mạng xuống. Những yêu cầu về an ninh của applet là rất quan trọng. Applet có thẻ giao tiếp với các applet khác trên trang web cũng như với các đối tượng khác trên trang web thông qua cơ chế riêng. Sau đây là một Japplet có thể mở một Frame mới. • Có thể gọi đến các phương thức toàn cục của các applet khác trên cùng trang web.*. frame. ký tự phân tách file. import java.III.swing. • Applet dễ dàng dùng các siêu văn bản hiển thị. • Applet không thể đọc và ghi dữ liệu lên máy tính cục bộ • Applet không thể tìm thấy thông tin gì về máy tính cuc bộ. Trong một số trường hợp ta có thể cấu hình để applet được tin cậy và có thể truy cập vào máy tính cục bộ giống như một chương trình đang chạy trên máy tính đó. add(calcButton). • Không nhất thiết là các applet sẽ ngừng lại khi ta thoát khỏi các trang web chứa nó.awt. password. // Thêm một Button để ẩn/ hiện frame pop-up JButton calcButton = new JButton("Calculator"). frame.setTitle("Calculator"). import javax. import java. Các nguyên tắc về an ninh của một applet là: • Applet không bao giờ thực hiện một chương trình của máy cục bộ. Applet cũng có những khả năng như: • Tạo kết nối đến máy đang chạy nó.*.setSize(200.awt.event.*. • Applet không thể giao tiếp với các máy tính khác trên mạng trừ máy tính mà nó được download về. tên và phiên bản hệ điều hành. đường dẫn. public class PopupCalculatorApplet extends JApplet { public void init() { // Tạo một frame với một cửa sổ panel final JFrame frame = new JFrame(). IV.

absbottom. . absmiddle..mycompany thì đường dẫn phải là: code="com/mycompany/MyApplet. hoặc: code="com. Các giá trị của align có thể là: left.class" archive="CalculatorClasses.codebase: Là một thuộc tính tùy chọn để xác định đường dẫn tuyệt đối nơi chứa class ở giá trị code. Các applet không thể thay đổi kích thước khi đã chạy. texttop.class" width="200" height="200"> <param name="font" value="Helvetica"/> <param name="size" value="24"/> 106 . Ví dụ: nếu applet có tên MyApplet. Khi đó applet cần có tên để truy cập. vspace và hspace.corejava/CoreJavaClasses.mycompany. Các thuộc tính về chương trình nguồn. top.public void actionPerformed(ActionEvent event) { frame. Đường dẫn phải phù hợp với đường dẫn gói của class applet. archive: Chứa tên các gói chương trình hoặc tài nguyên khác được tải về kèm theo applet. Các thẻ HTML của Applet Một khai báo applet trong trang HTML thường có dạng: <applet code="NotHelloWorldApplet. } } V. Các gói chương trình được nén ở dạng file JAR và được đặt cách nhau bởi dấu . Tên này là tương đối so với giá trị codebase hoặc với thư mục hiện hành nếu không có codebase. Ngoài ra Java cho phép ta định nghĩa các tham số cho applet thông qua các thẻ <param> Ví dụ: <applet code="FontParamApplet. } }). bottom.class". Trong các trình duyệt của Netscape hoặt Windows đều cho phép applet giao tiếp với các đối tượng javascript khác trên trang web. baseline. Ví dụ: <applet code="CalculatorApplet. name: Tên của applet.jar.class" cũng được chấp nhận.isVisible()).MyApplet. right. middle. • width: Chiều rộng của applet • align: Xác định vị trí của applet so với các văn bản xung quanh nó.class" width="300" height="100"> Thong tin duoc hien thi khi applet khong hien thi </applet> Sau đây ta sẽ tìm hiểu các thuộc tính của applet: Các thuộc tính về vị trí: • height: Chiều cao của applet.code: code : Thuộc tính này cho biết tên của class chứa chương trình applet.setVisible(!frame.jar" width="100" height="150"> object: Chứa tên file đã được tuần tự hóa của một applet.class được đặt trong gói com.

. ta có thể lấy ra để sử dụng: public class FontParamApplet extends JApplet { public void init() { String fontName = getParameter("font"). height là Chiều cao của hình. int height): Vẽ hình chữ nhật đặc. int yCoor): xuất các byte ra.parseInt(getParameter("size")). • getCodeBase(): Cho biết địa chỉ dạng URL của thư mục chứa tập tin . • fillOval(int xCoor. • getDocumentBase(): cho biết địa chỉ dạng URL của thư mục chứa tập tin HTML chứa applet. length: Số các ký tự cần được vẽ. int x2.}: là phương thức ta dùng sau khi thực hiện pain() nhằm làm tăng hiệu quả vẽ. int archeight): Vẽ hình chữ nhật có bo góc. • drawRoundRect(int xCoor. String name): trả về một đối tượng ảnh hiển thị trên nền. • showStatus(String st): hiển thị xâu st trên thanh trang thái. nơi các ký tự cần được vẽ. • getLocale(): Xác định vị trí applet. offset: Vị trí bắt đầu. int height): Vẽ hình chữ nhật. int yCoor. • drawLine(int x1. • drawChars(char array[ ].. int offset. • drawRect(int xCoor. int height. int y2): Vẽ đường thẳng từ A(x1. int width. int yCoor): xuất các ký tự.CLASS của applet. int yCoor.. int height): Vẽ đường oval. Chú thích các tham số: array: Mảng các ký tự. int xCoor. • getImage(URL url. • public void update(Graphics g) {. int width. int arcwidth...Trong đó: width là Chiều rộng của hình. int yCoor... String name): cho đối tuợng audio. int xCoor. y1) đến B(x2. thường các applet dùng paint() để biểu diễn các hoạt động của mình trên trang web. int length.Trong đó array: Mảng các byte. • drawBytes(byte array[ ]. Phương thức này chỉ cần một tham số là đối tượng của lớp Graphics. int length. • drawOval(int xCoor. int yCoor. int yCoor. int fontSize = Integer. } } VI. int width. Ngoài ra Applet còn thừa hưởng các phương thức từ lớp AWT.}: Là phương thức hiển thị cơ bản. yCoor: Toạ độ Y. • getAudioClip(URL url.. int height): Vẽ hình oval đặc. xCoor: Toạ độ X..</applet> Khi đó trong chương trinh applet. y2). yCoor: Toạ độ Y. nơi các ký tự được vẽ. int y1. int width. int offset. xCoor: Toạ độ X. int width. nơi các ký tự cần được vẽ.Vị trí offset hay vị trí bắt đầu. lập trình đồ họa và bắt sự kiện của applet public void paint(Graphics g) {. • Phương thức repaint() được dùng khi cửa sổ cần cập nhật lại. • fillRect(int xCoor. length: Số byte cần vẽ. Các phương thức. • 107 .

y[ ]: Mảng lưu trữ toạ độ y của các điểm.BOLD. int numPoints): Vẽ đa giác đặc. • fillArc(int xCoord. int y[ ]. • draw3Drect(int xCoord.darkgray Color. int arcwidth.fillRoundRect(int xCoor.orange Color. int arcwidth. • drawArc(int xCoord.cyan Color. width: Chiều rộng của cung được vẽ. • drawPolyline(int xArray[ ]. Ví dụ. Font. int totalPoints): Vẽ nhiều đường thẳng Trong đó: xArray: Mảng lưu trữ toạ độ x của các điểm. int yCoord. • setFont(new Font(“Times Roman”.red Color. int height.magenta • 108 .pink Color.black Color. Font.PLAIN. (Font. archeight: Độ rộng của cung (góc của cung) so với góc ban đầu. int width. numPoints: Tổng số điểm cần vẽ. int yArray[ ]. arcwidth: Góc bắt đầu. int height. totalPoints: Tổng số điểm cần vẽ. Trong đó: arcwidth: làm tròn góc trái và góc phải của hình chữ nhật. int width.green Color. boolean raised): Vẽ hình chữ nhật 3D. Trong đó: x[ ]: Mảng lưu trữ toạ độ x của các điểm. height: Chiều cao của cung được vẽ. int y[ ]. yCoord: Toạ độ y.blue Color. int yCoord. int height. int height. int archeight): Vẽ hình cung đặc.lightgray Color. int numPoints):Vẽ đa giác. • fillPolygon(int x[ ]. setColor(Color c): Đặt màu vẽ. arcwidth = 20 có nghĩa là hình chữ nhật được làm tròn cạnh trái và cạnh phải mỗi cạnh 10 pixel. int width. archeight: làm tròn góc trên đỉnh và góc đáy của hình chữ nhật. int arcwidth. int archeight): vẽ hình chữ nhật bo góc đặc. int yCoord. 15)): Đặt Font cho chữ. int width. Bảng một số màu cơ bản: Color.yellow Color. Trong đó: xCoord: Toạ độ x.BOLD. yArray: Mảng lưu trữ toạ độ y của các điểm.white Color. int yCoor.ITALIC) • drawPolygon(int x[ ]. int archeight): Vẽ hình cung. Font.gray Color.

Java phát triển một thư viện mở rộng swing mới với đa số các lớp GUI kế thừa từ AWT nhưng có khả năng di động tốt hơn. chúng ta sẽ xét các thành phần GUI trong swing. AWT cung cấp các thành phần khác nhau để tạo GUI hiệu quả. Xác định sự xuất hiện ban đầu của đối tượng.awt. 4. Thêm phần tử vào giao diện trên màn hình. Các lớp GUI trong swing có thêm tiền tố “J” so với các lớp trong AWT. Sơ đồ phân cấp thừa kế các đối tượng GUI trong swing như sau: 109 . Chỉ ra nó nằm ở đâu.Đề tài 10. Lập trình giao diện đồ họa GUI I. 3. 2. • Đồ hoạ (Graphics) và các tính năng vẽ (draw). Tạo đối tượng. • Trình quản lý cách trình bày (Layout manager). • Sự kiện (Event). • Phông chữ (Font).GUI) thân thiện. Giới thiệu AWT Abstract Windows Toolkit – AWT: Là thư viện của Java cung cấp cho lập trình viên các giải pháp giao diện người dùng đồ hoạ (Graphical User Interface . Từ phiên bản 1. • Thành phần (Component). Để làm việc với các đối tượng GUI chúng ta cần nhập gói java. Một giao diện người dùng được hình thành từ các phần tử của GUI.4. các thành phần này có thể là: • Vật chứa (Container). Một phần tử GUI được thiết lập bằng cách sử dụng các thủ tục: 1. Sau đây.*.

JFrame frame2 = new JFrame("Cua so Frame"). Tạo Frame với tiêu đề bên trên: void JFrame(String FrameTitle).*.swing. • Thay đổi biểu tượng JFrame: public setIconImage(Image img). int height).show(). Ví dụ sau tạo một đối tượng JPanel và đặt vào nó một đối tượng nút bấm JButton. • Thay đổi tiêu đề cho JFrame: frame1. • JScrollPanel .dispose(). trong đó: b = true cho hiển thị.là một cửa sổ như mọi ứng dụng của windows.1 JFrame Tạo đối tượng khung chứa JFrame bằng phương thức khởi tạo: void JFrame(). Một vật chứa có thể chứa nhiều phần tử. f. • Co dãn JFrame: public void setResizable(boolean b). để tạo các ứng dụng windows. II. • Lấy tiêu đề của JFrame: public String getTitle(). import javax.khung chứa như Panel nhưng có hai thanh trượt. import javax. • Xác định JFrame đang ở tình trạng nào: public boolean isResizable(). nó là đối tượng dùng để chứa các thành phần GUI trên màn hình. public class FrameSample { public static void main(String[] argvs) { JFrame f = new JFrame().setVisible(true). . Do đó chúng ta cần gắn JPanel vào đối tượng nào đó như: JFrame.*.setSize(400. • Đưa cửa sổ hiện ra màn hình: frame1. II.setVisible(boolean b). Tạo khung chứa JPanel bằng phương thức khởi tạo: JPanel panel1 = new JPanel(). Vật chứa (Container) Là vùng mà ta có thể đặt các thành phần (component) của giao diện. • JDialogs .setTitle(String newTitle). b = false cho ẩn. • Bỏ hoàn toàn đối tượng JFrame: frame1. frame1.là cửa sổ nhưng không đầy đủ chức năng như Frame. f. JApplet.II. Vật chứa thường được sử dụng là: • JPanel .2 JPanel JPanel không thể nhìn thấy trực tiếp. nó là cửa sổ hộp thoại đưa ra những lời thông báo. • JFrame . để nhóm các đối tượng con lại và sắp xếp theo cách thích hợp..setSize(int width.khung chứa đơn giản nhất. 110 . trong đó: b = true thì Frame có thể thay đổi kích thước. b = false thì không đổi. Ví dụ: JFrame frame1 = new JFrame().swing.. } } Một số phương thức hay sử dụng: • Đặt lại kích thước cho JFrame: frame1.400).

f.setSize(400. } } 111 .add(new JButton("OK")).setVisible(true).public class FrameSample { public static void main(String[] argvs) { JFrame f = new JFrame(). // gắn JPanel vào JFrame f. JPanel p = new JPanel(). p.400).add(p). f.

"Day la Jdialog".isVisible()). Các đặc điểm thường sử dụng với đối tượng JDialog thể hiện tương tự với JFrame.*. boolean isModal) JDialog không thể gắn với Applet. public class FrameSample extends JFrame { private JDialog d. String title. boolean isModal). JButton b = new JButton("Xem/Tat mot JDialog").false).3 JDialog Như JFrame. Cách tạo khung chứa JDialog từ phương thức khởi tạo: public JDialog(JFrame parentWindow. Xác minh một JDialog đang thuộc dạng nào ta gọi phương thức: public boolean isModal() Chương trình sau đây sẽ ẩn hoặc hiện một JDialog mỗi khi nhấn vào một nút bấm: import javax.setSize(100. d. b. Ẩn hiện JDialog ta còn có phương thức: setVisible(boolean). nhưng ít chức năng hơn. • non-modal: ngược lại với modal.awt. JPanel p = new JPanel(). import java. } } ).awt.swing. cửa sổ này thích ứng với các thao tác mang tính tuỳ biến.100).setVisible(!d. true) Tạo JDialog có tiêu đề định trước: public JDialog(Frame parentWindow. String getTitle(). còn được gọi là popup-window.quyết định xem JDialog được tạo ra ở dạng nào: isModal = true cho modal còn isModal = false cho non-modal. import java. Ví dụ: JDialog myDialog = new JDialog(myWindow.*. 112 . boolean isResizable() Đặt và lấy tiêu đề của JDialog: void setTitle(String). trong đó: isModal .*. Đưa đối tượng JDialog ra màn hình bằng phương thức show(). Lấy và thay đổi kích thước JDialog: public setResizable(boolean).II. Cửa sổ này thường yêu cầu một tác vụ nào đó cần phải hoàn thành ngay. public FrameSample() // Constroctor { d = new JDialog(this.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { d. muốn đưa ra một JDialog từ JApplet ta phải tạo ra một JFrame giả tạo. Ta có thể tạo JDialog dưới hai hình thức: • modal: là cửa sổ JDialog khi thực hiện sẽ khoá chặt các cửa sổ khác. Giấu cửa sổ JDialog ta dùng phương thức: hide().event.

p. III. Để xem tên nhãn hiện tại của nút nhấn. fs. JcomboBox: Đối tượng ComboBox Jlist: Danh sách JPanel: Nơi đặt các thành phần GUI nói trên.LEFT. Tính chất khác là khi đối tượng nó chứa quá lớn thì JScrollPane sẽ xuất hiện thanh trượt đứng và ngang ở hai bên viền để ta có thể xem được toàn bộ. JtextField: Chỉ một đối tượng cho phép nhập dữ liệu từ bàn phím.setSize(400.1 Nút nhấn Cách tạo nút nhấn Ta gọi phương thức khởi dựng: public Button(String label) label là tên nhãn của nút nhấn Ví dụ: Button nutOK = new Button("OK"). Label.400). nutOK. 113 .RIGHT: những giá trị căn lề. Label.setVisible(true). ta gọi phương thức public String getLabel() Ví dụ: Button nutOK = new Button(). } } II.4 JScrollPane Đây không phải là một cửa sổ nhưng có tính chất như khung chứa JPanel dùng để chứa các đối tượng. hoặc thêm chế độ căn lề: pubic Label(String name. } public static void main(String[] argvs) { FrameSample fs = new FrameSample().2 Nhãn (Label) Tạo nhãn không có nội dung gì: public Label() hoặc tạo nhãn có nội dung: public Label(String nameLabel).CENTER.add(b). JScrollPane được ứng dụng trong các danh sách chọn hay các vùng nhập văn bản. JButton: Đối tượng nút bấm JcheckBox: Đối tượng nút chọn. Để đổi tên nhãn cho nút nhấn ta gọi phương thức public void setLabel(String newLabel). Đư nút nhấn vào Applet hay cửa sổ chương trình bằng lệnh: add(nutOK). fs. Sử dụng nút nhấn Khi kích chuột vào nút nhấn sẽ thực hiện một công việc nào đó. add(p). Label.setLabel("OK"). Giới thiệu về các thành phần GUI cơ bản • • • • • • • Jlabel: Chỉ một vùng hiển thị văn bản hoặc các icon. III. Vấn đề này chúng ta đã xem xét trong phần xử lý các sự kiện III. int align) Một số phương thức hay sử dụng: setText(String nameLabel): Đặt lại nội dung mới cho nhãn.

setToolTipText( "This is label3" ). label3. label2.awt.event. label1. // hiển thị khi di chuột đến container.setToolTipText( "This is label1" ). 170 ). label3. label3.setIcon( bug ).LEFT ). // constructor của JLabel label1 = new JLabel( "Label with text" ).*.setHorizontalTextPosition( SwingConstants.setVerticalTextPosition( SwingConstants. setSize( 275. container. container. Thiết lập lại chế độ căn lề: public void setAlignment(int IlligalArgumentException Sau đây là ví dụ sử dụng JLabel: // Minh họa về JLabel // Nhập các gói thư viện import java.swing.BOTTOM ).add( label1 ). label3. public class LabelTest extends JFrame { private JLabel label1. import java.setLayout( new FlowLayout() ). container. // JLabel không tham số label3 = new JLabel().CENTER ). // thêm vào container align) throws // Tạo Jlabel với icon hoặc text Icon bug = new ImageIcon( "bug1.*. label3. bug. Xem nhãn đang được căn lề ở chế độ nào: public int getAlignment().gif" ). } 114 .*. // Gói Java mở rộng import javax.awt. // Tạo giao diện GUI public LabelTest() { super( "Testing JLabel" ).setText( "Label with icon and text at bottom" ). label2 = new JLabel( "Label with text and icon".setToolTipText( "This is label2" ). setVisible( true ).add( label3 ). label2. label3. SwingConstants. // Contructor của JFrame // Lấy đối tượng pane của một JFrame Container container = getContentPane().Lấy nội dung hiện hành của nhãn: public String getText().add( label2 ).

application. Nhóm các ô đánh dấu trở thành nút chọn. • public Checkbox(String cbLabel): tạo ô đánh dấu với một nhãn cbLabel gắn kèm. • public Checkbox(String cbLabel. • public Checkbox(String cbLabel . } } III. Ta có thể tạo nút đánh dấu theo 5 phương thức khởi dựng: • public Checkbox(): tạo ô đánh dấu không có nhãn. • public Checkbox(String cbLabel.3 Nút đánh dấu (checkbox) Một nút đánh dấu có hai phần: nhãn và dấu biểu hiện trạng thái. CheckboxGroup g). ta dùng phương thức: setState(boolean state). boolean state. ta dùng phương thức: addItemListener(ItemListener L) Để loại bỏ lắng nghe đó ta dùng phương thức: removeItemListener(ItemListener L) 115 . Kiểm tra và thiết lập trạng thái: Để kiểm tra một ô có được đánh dấu không ta dùng phương thức: public boolean getState(). Xử lý tình huống khi ô đánh dấu thay đổi trạng thái: Để lắng nghe ô đánh dấu. boolean state): dùng để tạo ô đánh dấu có nhãn với trạng thái đánh dấu ban đầu.// hàm main public static void main( String args[] ) { LabelTest application = new LabelTest(). CheckboxGroup g. boolean state): Tạo ô đánh dấu với một nhãn cbLabel gắn kèm với trạng thái ban đầu của ô đó.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ). nút tạo ra được nhóm trong nhóm g. Nếu muốn thiết lập trạng thái.

// Thiết lập GUI public CheckBoxTest() { super( "JCheckBox Test" ). // Đặt ô nhập và font chữ field = new JTextField( "Theo dõi font chữ thay đổi".setFont( new Font( "Serif".BOLD.EXIT_ON_CLOSE ).getSource() == bold ) if ( event. application.*.*. container. Font.// Java core packages import java. 116 // Chọn ô chứ nghiêng if ( event. // Đáp ứng sự kiện chọn ô public void itemStateChanged( ItemEvent event ) { // xử lý chọn ô chữ đậm if ( event.*. 20 ). } // execute application public static void main( String args[] ) { CheckBoxTest application = new CheckBoxTest().awt. // tạo đối tượng checkbox bold = new JCheckBox( "Bold" ).addItemListener( handler ). setVisible( true ).event. italic = new JCheckBox( "Italic" ).setLayout( new FlowLayout() ).PLAIN.add( bold ).getStateChange() = = ItemEvent. } // Lớp nội lắng nghe sự kiện private class CheckBoxHandler implements ItemListener { private int valBold = Font.swing. field.PLAIN. // Java extension packages import javax. container.getSource() == italic ) . // lấy pane Container container = getContentPane(). container. import java.setDefaultCloseOperation( JFrame. bold. private int valItalic = Font.PLAIN. italic.addItemListener( handler ). private JCheckBox bold. // Đăng ký đối tượng lắng nghe CheckBoxHandler handler = new CheckBoxHandler(). container. italic.add( italic ). setSize( 275. else valBold = Font. 100 ).awt.PLAIN. 14 ) ). public class CheckBoxTest extends JFrame { private JTextField field.SELECTED ) valBold = Font.add( field ).

event.*. radioGroup.4 Nút chọn (radio button) Tạo nút chọn: Đây là trường hợp đặc biệt của ô đánh dấu. III. private JLabel label. plainButton.gif" }. Phương thức getItemSelectable sẽ trả về đối tượng nơi mà tình huống phát sinh: public ItemSelectable getItemSelectable().gif". boldItalicButton. Đặt lựa chọn ta dùng: setSelectedCheckbox(). Sau đây là ví dụ về sử dụng ô chọn: // Đăng ký đối tượng lắng nghe cho mỗi ô chọn radio RadioButtonHandler handler = new RadioButtonHandler(). Với một nhóm các nút ta có thể lấy ra đối tượng hiện tại đang được chọn bằng cách gọi phương thức getSelectedCheckbox().add( boldButton ). Ta tạo ra ô đánh dấu và đặt nó vào một nhóm.III. // Nhóm các ô lại radioGroup = new ButtonGroup().gif". italicButton. JComboBox cũng phát sinh sự kiện ItemEvent giống như JRadioButton và JCheckBox. // Java extension packages import javax.awt.addItemListener( handler ).addItemListener( handler ). 117 . "bug2.addItemListener( handler ). private String names[] = { "bug1. "buganim.swing.*. Về bắt các sự kiện cũng tương tự ô đánh dấu. đưa ra một danh sách các mục và ta chỉ được chọn 1 mục trong đó.5 Hộp thoại Combo Java hỗ trợ hộp thoại Combo thông qua đối tượng của class JComboBox. public class ComboBoxTest extends JFrame { private JComboBox imagesComboBox. radioGroup.add( italicButton ).add( plainButton ). // Java core packages import java.addItemListener( handler ).gif". Cách sử dụng nút chọn: Ta tạo một đối tượng giao tiếp ItemListener để lắng nghe tình huống. import java.*. radioGroup.add( boldItalicButton ). Phương thức getItem của đối tượng ItemEvent sẽ cho ta biết giá trị nút chọn: public Object getItem(). Chương trình sau đây minh họa việc sử dụng JComboBox với các phần tử là các ảnh GIF. Đây là một danh sách xổ xuống. "travelbug. radioGroup. ta có phương thức sau: public CheckboxGroup(). boldButton.awt.

SELECTED ) label. } } ). // Thiết lập GUI public ComboBoxTest() { super( "Testing JComboBox" ). imagesComboBox. new ImageIcon(names[2]).getSelectedIndex() ] ).setDefaultCloseOperation( JFrame. container. }} III.addItemListener( new ItemListener() { // bắt sự kiện public void itemStateChanged( ItemEvent event ) { // liệu có phần tử được chọn if ( event. imagesComboBox.setLayout( new FlowLayout() ). new ImageIcon(names[3])}. } // hàm main public static void main( String args[] ) { ComboBoxTest application = new ComboBoxTest().add( imagesComboBox ). new ImageIcon(names[1]). // khởi tạo combo imagesComboBox = new JComboBox( names ). container.EXIT_ON_CLOSE ).private Icon icons[] = { new ImageIcon(names[0]). // đặt một JLabel hiển thi ImageIcons tương ứng label = new JLabel( icons[ 0 ] ). setSize( 350. aplication.6 Danh sách (Lists) Lớp List cho phép ta tạo một danh sách các phần tử cho ta lựa chọn Tạo một danh sách: 118 . container. setVisible( true ).getStateChange() == ItemEvent. 100 ).setMaximumRowCount( 3 ).add( label ). // Đặt layout Container container = getContentPane().setIcon( icons[imagesComboBox.

public class ListTest extends JFrame { private JList colorList. Nếu được chọn nhiều thì dùng: int[] getSelectedIndex() Lấy ra phần tử được chọn: getSelectedItem(). Color.lightGray. private String colorNames[] = { "Black".pink. "Dark Gray".darkGray.*.red. Phương thức getActionCommand() trong ActionEvent sẽ trả về tên của phần tử bị nhấp.Phương thức khởi dựng mặc định: public List(). Sử dụng đối tượng danh sách: Cài đặt giao tiếp ItemListener để tạo đối tượng biết lắng nghe sự thay đổi trạng thái của các phần tử trong danh sách.black. nếu không có phần tử nào được chọn thì giá trị sẽ là -1: getSelectedIndex(). Color.yellow }. "Cyan". "Pink". hoặc để chỉ định bao nhiêu phần tử sẽ được hiển thị cùng một lúc trong danh sách: public List(int rows) hoặc tạo một danh sách cho phép lựa chọn nhiều phần tử cùng một lúc: public List(int rows.*. "Yellow" }. "Green".cyan. private Container container. "Magenta". Color. Color. ta cài đặt giao tiếp ActionListener và gắn nó vào danh sách. Color.replaceItem("Xanh". Trả về vị trí của phần tử được chọn.orange. Để chọn một phần tử mà ta biết vị trí: select(int index) Nếu phần tử đang ở trạng thái chọn chuyển sang trạng thái bình thường: deselect(int index) Trạng thái của một phần tử: isSelected(int index) Chuyển chế độ đơn chọn sang đa chọn: setMultiplesSelections(boolean bl) Cho biết một danh sách là đơn chọn hay đa chọn: boolean isMultipleMode().magenta. 4). "Gray". Color.*. Color.awt.blue. vd: List list = new List().swing. int pos) vd: list.green. "Red". Color. Loại bỏ hết danh sách: removeAll().white. private Color colors[] = { Color. Để xử lý được tình huống nhấp đôi chuột. Thay thế một phần tử ở vị trí pos bằng phần tử mới: replaceItem(String newItem.vd: list. 119 . Sử dụng đối số ItemEvent trong phương thức itemStateChange để biết được chỉ số của phần tử đang thay đổi trạng thái. "Blue". boolean multiMode) Sử dụng danh sách chọn: Đưa từng phần vào danh sách bằng lệnh add(String item). index là vị trí phần tử mà ta muốn chèn. Color. Color. int index). // Java extension packages import javax.add("Mau do"). "Orange".gray. import javax. Loại bỏ một phần tử trong danh sách ta dùng phương thức remove(int pos). Chọn nhiều thì dùng: String[] getSelectedItem(). Color.event. // Java core packages import java. Color.swing. "Light Gray". Chèn một phần tử vào danh sách bằng phương thức add(String item. "White".

int numCols).setSelectionMode(ListSelectionModel.// Thiết lập GUI public ListTest() { super( "List Test" ).setVisibleRowCount( 5 ). } } ). • Tạo một ô văn bản với nội dung là một chuỗi cho trước: public TextFiled(String initText). container. • Tạo một ô văn bản hiển thị tối thiểu numCols ký tự: public TextField(int numCols).7 Ô văn bản (text field) và vùng văn bản (text areas) Tạo ô văn bản: • Khởi tạo một ô văn bản không xác định kích thước: public TextField(). setVisible( true ). 150 ).setLayout( new FlowLayout() ). setSize( 350. // Tạo danh sách colorList = new JList( colorNames ). // lấy layout container = getContentPane().setDefaultCloseOperation( JFrame.setBackground( colors[ colorList.addListSelectionListener( new ListSelectionListener() { public void valueChanged( ListSelectionEvent event ) { container. application. }} III.getSelectedIndex() ] ). • Tạo ô văn bản kết hợp: public TextField(String initText. // đặt lắng nghe sự kiện colorList. // Không cho chọn nhiều colorList. 120 . colorList.SINGLE_SELECTION ).EXIT_ON_CLOSE ). // thêm một JScrollPane chứa danh sách container.add( new JScrollPane( colorList ) ). } // hàm main public static void main( String args[] ) { ListTest application = new ListTest().

// Thiết lập giao diện GUI public TextFieldTest() { super( "Testing JTextField and JPasswordField" ). Cho phép soạn thảo được: public void setEditable(boolean canEdited).swing. import java. Khi người dung nhấn Enter thì tình huống được gọi. //cuối Đánh dấu toàn bộ văn bản: public void selectAll(). sử được. //mã mKhẩu Xác định xem ký tự làm ký tự hiển thị: public char getEchoChar(). • Tạo một vùng văn bản với số dòng số cột và nội dung cho trước: public TextArea(String st. Lấy nội dung văn bản được đánh dấu: public String getSelectedText(). ví dụ: myTextField.*. Chèn một chuỗi văn bản vào vị trí bất kỳ: public void insertText(String newText. public int getColums(). //đầu public int getSelectionEnd(). Tạo một vùng văn bản với nội dung cho trước: public TextArea(String initiaText).event. int pos). int cols).Tạo vùng văn bản: Tạo vùng văn bản rỗng.setLayout( new FlowLayout() ). canEdited = true: thêm. public class TextFieldTest extends JFrame { private JTextField textField1. kích thước bất kỳ: public TextArea().setEchoChar('*'). container.awt. Tạo một vùng văn bản với số cột và số dòng định trước: public TextArea(int rows. Xác định kích thước hiển thị: public int getRows(). // constructor của JFrame Container container = getContentPane(). Xác định đối tượng đang ở trang thái nào: public boolean isEditable(). private JPasswordField passwordField. textField2. Lấy nội dung văn bản trong các đối tượng: public String getText().awt. int cols) Đặc điểm chung của các thành phần văn bản: Hai lớp này được dẫn xuất từ lớp TextComponent Muốn đưa nội dung văn bản vào các đối tượng này ta sử dụng phương thức setText: public void setText(String newText).*. Đặc điểm riêng của đối tượng TextArea: Đưa thêm một dòng văn bản vào đối tượng: public void appendText(String newText). textField3. Để xác định xem vị trí đánh dấu khối văn bản bắt đầu và kết thúc ở đâu: public int getSelectionStart(). Sử dụng đối tượng TextField và TextArea: Muốn lấy nội dung văn bản của đối tượng. • • • • 121 . import javax. int rows. Xác định chiều dài của ô văn bản theo ký tự: public int getColums(). import java. Đặc điểm riêng của TextField: Đặt ký tự hiển thị cho ký tự nhập vào: public void setEchoChar(Char ch). canEdited = false: chỉ đọc. ta thiết lập ActionListener để gắn đối tượng xử lý sự kiện vào văn bản TextField.*.

getActionCommand().addActionListener( handler ). // ô nhập password passwordField = new JPasswordField( "Hidden text" ).add( passwordField ). setVisible( true ). // ô nhập với văn bản có sẵn textField2 = new JTextField( "Enter text here" ). application. 100 ). // khi người dùng ấn enter if ( event. passwordField. textField2. chỉ hiên thị thông tin textField3 = new JTextField( "Uneditable text field".getActionCommand().add( textField1 ).// ô nhập với kích thước mặc định textField1 = new JTextField( 10 ).getSource() == textField2 ) string = "textField2: " + event. textField3.setDefaultCloseOperation( JFrame. textField3. container.addActionListener( handler ).add( textField3 ).addActionListener( handler ). // Đăng ký bộ lắng nghe sự kiện TextFieldHandler handler = new TextFieldHandler(). setSize( 325. // user pressed Enter in JTextField textField2 else if ( event. container.setEditable( false ). 20 ).addActionListener( handler ). textField1. 122 . container. } // hàm main public static void main( String args[] ) { TextFieldTest application = new TextFieldTest(). container.getSource() == textField1 ) string = "textField1: " + event. // ô nhập không cho phép nhập.EXIT_ON_CLOSE ).add( textField2 ). } // Lớp nội cho bộ lắng nghe sự kiện private class TextFieldHandler implements ActionListener { // phương thức xử lý sự kiện public void actionPerformed( ActionEvent event ) { String string = "".

//vị trí khởi đầu int pageUnit. //giá trị min int maxValue). Khi người dùng kích chuột vào mũi tên ở hai đầu thì tình huống line nảy sinh. thanh trượt sẽ tự động cộng thêm hay trừ đi một đơn vị. orienttation nhận giá trị Scrollbat. int pos. Tình huống page nảy sinh khi người dùng kích chuột vào khoảng giữa thanh trượt. } JOptionPane. Tạo thanh trượt đứng hay ngang ta dùng: public Scrollbar(int orienttation).getPassword() ). vị trí hiện hành sẽ thay đổi. public int getMinimum(). 123 . // user pressed Enter in JTextField passwordField else if ( event. Scrollbar. Đặt lại vị trí hiện hành cho thanh trượt: public void setValue(int newPos). Muốn biết thanh trượt đứng hay ngang: public int getOrientation() trả về giá trị là một trong hai hằng số Scrollbar.VERTICAL và Scrollbar. Tạo thanh trượt: Phương thức khởi tạo: public Scrollbar().cho đứng. Tạo thanh trượt có đầy đủ thông số ban đầu: public Scrollbar(int orienttation.HORIZONTAL cho nằm ngang.getActionCommand(). Muốn biết hiện thời đơn vị thay đổi là bao nhiêu: public int getBlockIncrement().showMessageDialog( null. Cho ta vị trí hiện hành: public int getValue().getSource() == textField3 ) string = "textField3: " + event.getSource() == passwordField ) { JPasswordField pwd = ( JPasswordField ) event. //bước nhảy int minValue. string ). Đối tượng Scrollbar chỉ chịu trách nhiệm di chuyển và cung cấp cho ta giá trị thay đổi. Muốn biết hiện thời tăng giảm bao nhiêu: public int getUnitIncrement() Chỉ định con số khi tình huống page xảy ra: pubic void setBlockIncrement(int b). Lấy giá trị lớn nhất và nhỏ nhất: public int getMaximum().8 Thanh trượt (Scrollbar) Ta có thể đặt thanh trượt các giá trị giới hạn tối thiểu (min) và tối đa (max) cùng với vị trí hiện tại trên thanh trượt.getSource(). string = "passwordField: " + new String( passwordField.// user pressed Enter in JTextField textField3 else if ( event.HORIZONTAL. Tình huống absolute nảy sinh khi người dùng nắm vào vị trí hiện hành của thanh trượt và kéo nó đi.VERTICAL . //giá trị max Một số phương thức hay dùng: Thay đổi giá trị tăng giảm (mặc định là 1): public void setUnitIncrement(int increment). // Hiên thị cửa sổ thông báo } } } III.

0. Java dùng lớp JMenuItem định nghĩa từng mục của thực đơn.setValues(75. Tạo thanh trình đơn: JMenuBar myMenubar = new JMenuBar(). AdjustmentEvent. JMenuItem open = new JMenuItem(“Open”.UNIT_DECREMENT: tình huống line xảy ra. Các JMenuBar được tạo ra để gắn vào một của sổ JFrame bằng một lệnh gọi: JMenuBar menuBar = new JMenuBar().setJMenuBar(menuBar). Thành phần Menu Lớp JMenuBar cài đặt thanh thực đơn và trong đó có thể chứa các thực đơn pull-down.add(file).addSeparator(). vị trí thanh trượt giảm 1 đơn vị.’O’). int maximum). 10. int pageUnit. Sử dụng thanh trượt: Ta nhờ đối tượng xử lý tình huống xử lý: public void adjustmentValueChanged(AdjustmentEvent evt). • AdjustmentEvent. JMenu file = new JMenu(“File”). int minimum. Những thực đơn này có thể xuất hiện bất cứ vị trí nào trong cửa sổ hiện tại.enable(). ta cần thêm vào đó các JMenu là các mục trên thanh Menu. vị trí thanh trượt tăng 1 đơn vị. • AdjustmentEvent. vị trí hiện hành tăng 1 đv. ví dụ là ‘F’ để khi ấn Alt + F thì JMenu này được kích hoạt: file. ví dụ: myScrollbar.setMnemonic('F').BLOCK_INCREMENT: tình huống page xảy ra. Lớp JCheckBoxMenuItem chứa các mục được chọn để kiểm tra trong các mục thực đơn.UNIT_INCREMENT: tình huống line xảy ra. Sau đó ta add vào JMenu: file. //được chọn openItem.disable().Track: tình huống absolute xảy ra. khi người dùng chọn vào đó sẽ sổ xuống danh sách các mục chọn khác. Lớp JPopUpMenu biểu diễn cho thực đơn pop-up. ta lấy vị trí thanh trượt bằng hàm getValue().add(open). Ở đây ta đã gọi một constructor với một tham số là nhãn của mục chọn. • AdjustmentEvent. JFrame frm = new JFrame(“Day la mot Frame”). Ta sử dụng hàm getAdjustmentType() để xác định xem tình huống nào đang xảy ra. Ta đặt cho nó một phím tắt. Đặt trạng thái cho mỗi mục chọn sử dụng enable() hoặc disable(): Vi dụ: openItem. Sau đó thì thêm nó vào JMenuBar: menuBar. 500). Bây gời là lúc ta cài đặt các mục chọn trong một JMenu. IV. Nếu ta cần biểu diễn các dòng kẻ ngang để phân tách các mục chọn thì ta có thể gọi phương thức addSeparator() của một đối tượng JMenu: file. frm. //mờ mục chọn Ta có thể dùng đường phân cách để tách các mục chọn: 124 . Có 3 trạng thái: line. page và absolute. // MenuBar này chưa có phần tử nào Sau khi có MenuBar.Thiết lập lại các thông số cho thanh trượt: public void setValues(int position. một tham số là ký tự phím tắt.

ta tạo một menu bình thường rồi đưa vào menu đã có.add(Autosave).add("to preview").*.setLayout(new FlowLayout(FlowLayout. một dấu kiểm tra (check mark) sẽ hiện bên trái mục chọn: Mục đánh dấu: CheckboxMenuItem Autosave = new CheckboxMenuItem("Auto save").*. FileMenu. // Them dong ngan cach 125 . Ví dụ: //tạo mục chọn có menu con JMenu printItem = new JMenu("Print").FileMenu.add(menuFile).*.setMnemonic('F'). Tạo một mục chọn có khả năng đánh dấu (check Item).awt.awt. Xác định xem mục chọn Autosave đang ở trạng thái nào. để mục chọn tương tác và nhận được sự kiện ta cần cài đặt giao diện ActionListener và gắn vào từng mục chọn.swing. printItem.'O').menuBar. // Khai bao mot thanh menu JMenuBar menuBar= new JMenuBar(). // Them mot muc chon khac voi phim tat N menuFile. Tạo mục chọn có chứa menu con khác.add("Print preview").add(printItem). // Khai bao muc File trong thanh menu JMenu menuFile= new JMenu("File"). class MenuBarSample extends JFrame { //Khai bao mot hop thoai JOptionPane op = new JOptionPane(). import javax.'N')). import java. public MenuBarSample() { // Lay ve doi tuong chua cua Frame hien tai Container pane = this. import java. Sau đây là một ví dụ xây dựng một JFrame với thanh menu và các mục chọn trong đó có cài đặt xử lý các sự kiện. ta dùng: Autosave.getState().getContentPane().add(fileOpen). //tạo các mục chọn cho menu con printItem. Khi sử dụng.event. //đưa mục chọn có menu con vào menu chính FileMenu. // Dat kieu trinh bay pane. // Dat ky tu kich hoat tat cung Alt menuFile.add(new JMenuItem("New".LEADING)). // Khai bao mot thuc don pop-up JPopupMenu jp. // Them muc chon vao muc File menuFile. // Khai bao mot muc chon voi phim tat O JMenuItem fileOpen = new JMenuItem("Open".addSeparator().

} } ).addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { op. } } ). // Xu ly su kien chon Save menuFile."Ban vua bo chon is editting").add(chk). // Them mot muc chon co ten Save menuFile.addSeparator().addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { // Lay ve doi tuong nguon su kien va ep kieu JCheckBoxMenuItem ck = (JCheckBoxMenuItem)e.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent event) { // Hien thi thong bao. } } ). // Xu ly su kien chon New menuFile.showMessageDialog(getContentPane(). getContentPane() de lay Container cua Frame op.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { op.add("Save"). } } ).showMessageDialog(getContentPane()."Ban vua chon is editting"). // Them muc chon checkbox vao menu File menuFile. // Khai bao mot muc chon kieu checkbox JCheckBoxMenuItem chk = new JCheckBoxMenuItem("is editting").getItem(3).getItem(1).isSelected()) //Neu duoc chon op. 126 .showMessageDialog(getContentPane().getSource()."Ban vua chon New"). // Them phan xu ly su kien chon hay khong chon cho no chk. else // Neu khong duoc chon op.showMessageDialog(getContentPane().showMessageDialog(getContentPane()."Ban vua chon Save"). // Xu ly su kien chon muc Open fileOpen."Ban vua chon Open"). if (ck.menuFile.

} public static void main(String[] argvs) { MenuBarSample m = new MenuBarSample(). 127 .BUTTON3_MASK)== InputEvent.setSize(300. } } ).e. South.getX(). Ví du: FlowLayout objectsLayout = new FlowLayout(). kích thước các đối tượng không nhất thiết phải vừa một ô. Các đối tượng giữ nguyên kích thước.400). jp. jp.setJMenuBar(menuBar). hay có thể viết gọn hơn: myWindow. Nort và Center. m.show(getContentPane().getY()). myWindow. các đối tượng sẽ đặt vừa kích thước với các ô đó. • CardLayout: Các đối tượng được đặt vừa vặn với khung chứa và nằm chồng lên nhau như các lá bài.setLayout(objectsLayout). • BorderLayout: Các đối tượng được đặt theo đường viền của khung chứa theo các cạnh West. Muốn áp dụng ta tạo ra đối tượng trên rồi chuyển nó cho khung chứa. m. Có 5 cách trình bày: • FlowLayout: sắp xếp các đối tượng từ trái qua phải và từ trên xuống dưới. this.add("New Document").setLayout(new FlowLayout()).getModifiers() & InputEvent.addSeparator().BUTTON3_MASK) jp.// Dat thanh Menu cho Frame la doi tuong menuBar this.setVisible(true). Bộ quản lý cách trình bày (Layout Manager) Dùng để sắp xếp chỗ và định vị cho các đối tượng GUI.addMouseListener( new MouseAdapter() { public void mouseClicked(MouseEvent e) { if( (e. • GridLayout: tạo một khung lưới vô hình với các ô bằng nhau. } } V. • GridBadLayout: các đối tượng trong khung chứa cũng được đưa vào các ô của một khung lưới vô hình. // Cap phat bo nho cho popup menu jp = new JPopupMenu("Popup").e. jp.add("Create"). East.

FlowLayout. FlowLayout. int hgap.RIGHT. int hgap. Lớp JOptionPane có 4 phương thức tĩnh sau: Tên phương thức Giá trị trả về Ý nghĩa showMessageDialog Không có showConfirmDialog Số int showOptionDialog showInputDialog Số int Chuỗi Hiển thị một thông báo và đợi ấn OK Hiển thị thông báo và đợi xác nhận Ok hay Cancel Hiển thị thông báo và nhận về trả lời từ một danh sách chọn Hiển thị thông báo và nhận về một dòng do user nhập vào icon hiển thị phụ thuộc vào loại thông báo: ERROR_MESSAGE : Thông báo lỗi INFORMATION_MESSAGE : Thông tin WARNING_MESSAGE :Cảnh báo QUESTION_MESSAGE: Hỏi 128 .LEFT. int vgap). Java hỗ trợ lớp JOptionPane để ta thực hiện công việc này. "Center".3 Cách trình bày BorderLayout Đối tượng được đặt theo đường viền khung chứa.add("North". Ví dụ: GridLayout layout = new GridLayout(3. ta sử dụng phương thức: public FlowLayout(). VI. Ví dụ: myWindow.V.setLayout(new BorderLayout()). int Cols).CENTER hoặc chỉ ra khoảng các giữa các đối tượng trên cùng một hàng: public FlowLayout(int align. "South". V. ta phải định hình trước đối tượng đó đặt ở đâu: myWindow. ta dùng hộp thoại thông báo. align là FlowLayout. new Button("on Top")).1 Hộp thoại thông báo Khi cần đưa ra thông báo hay hỏi người dùng một vấn đề gì đó và nhận về câu trả lời. "East". int vgap).2 Cách trình bày GridLayout: Phương thức khởi tạo: public GridLayout(int Rows. int Cols. có 5 kiểu: "North". hoặc chỉ định luôn cách căn lề bằng phương thức khởi tạo: public FlowLayout(int align). "West". theo các cạnh của khung. Các hộp thoại VI. Xác định khoảng cách giữa các đối tượng quản lý: public GridLayout(int Rows. V. Tạo bộ quản lý kiểu BorderLayout: public BorderLayout(). 2). Khi đưa đối tượng vào khung chứa.1 Cách trình bày FlowLayout: Tạo đối tượng FlowLayout.

ERROR_OPTION 8.Hiển thị hộp thoại bằng lệnh gọi: int result = chooser.Lấy vè file hoặc các file được chọn dùng: getSelectedFile() hoặc getSelectedFiles().setSelectedFile(new File(filename)).gif") || f.setMultiSelectionEnabled(true). JFileChooser. Để dùng được bộ lọc file ta phải thiết kế một lớp kế thừa từ lớp javax.DIRECTORIES_ONLY hoặc JFileChooser. if (selection == JOptionPane. 6.swing.Để cho phép chọn nhiều file: chooser. . VI.FileFilter. Hai phương thức quan trọng là: .")). 7. nếu muốn cho phép chọn thư mục dùng phương thức: setFileSelectionMode() với các tham số: JFileChooser.OK_OPTION) . } public String getDescription() { return "GIF Image". JOptionPane. có thể đặt: chooser.Nếu muốn giới hạn kiểu file.OK_CANCEL_OPTION. hoặc int result = chooser. } } Sau đó gán cho hộp thoại: chooser.Đặt thư mục cho hộp thoại: chooser.showConfirmDialog(parent. 129 . 5. 2.CANCEL_OPTION.showSaveDialog: Để hiện thị hộp thoại chọn ghi file Sau đây là các bước để làm việc với hộp thoại chọn file: 1. 4.filechooser. Swing hỗ trợ một lớp JFileChooser để ta thực hiện công việc này.Tạo một đối tượng JFileChooser: JFileChooser chooser = new JFileChooser().toLowerCase().WARNING_MESSAGE).getSelectedFile().APPROVE_OPTION.setFileFilter(new GifFilter()). Các giá trị trả về là JFileChooser. 3. JOptionPane. or JFileChooser. Ví dụ: int selection = JOptionPane.isDirectory().Nếu định chọn trước một file.endsWith(".FILES_AND_DIRECTORIES.PLAIN_MESSAGE: Giải thích Các hằng số này được truy cập qua JOptionPane.getName(). Neus chỉ muốn lấy tên file thì ta dùng phương thức getPath().getPath().showOpenDialog(parent). "Message". String filename = chooser. Ví dụ bộ lọc file Gif: public class GifFilter extends FileFilter { public boolean accept(File f) { return f.2 Hộp thoại chọn File Khi viết ứng dụng ta gặp các tình huống mở file để đọc hoặc ghi.setCurrentDirectory(new File(". .showOpenDialog: Để hiện thị hộp thoại chọn mở file . "Title".showSaveDialog(parent). dùng bộ lọc file.Mặc định thì chỉ cho phép chọn file.

Yêu cầu chương trình có các ô nhập các hệ số a. Khi làm việc với hộp thoại chọn màu ta cần cung câp: . Bài tập 1. false /* not modal */.getColor()).3 Hộp thoại chọn màu Swing hỗ trợ lớp JColorChooser để người dùng chọn màu. 4. Viết chương trình giải phương trình bậc 2 với giao diện GUI.bộ lắng nghe cho nút bấm Ok và Cancel. . Hãy thiết kế một giao diện có nội dung như sau: 2.title: Tiêu đề hộp thoại. null /* Không có lắng nghe cho Cancel */). chooser. . Viết chương trình trình bày một màn hình như sau: 130 . dialog = JColorChooser.showDialog(parent. Cú pháp sử dụng như sau: Color selectedColor = JColorChooser. c và cho phép xem kết quả. 3.title. initialColor). chooser = new JColorChooser(). Trường hợp không có nghiệm sẽ hiển thị một hộp thoại thông báo “chương trình vô nghiệm”. b. Hãy lập trình để xử lý sự kiện click chuột phải lên nền của sổ sẽ hiện một menu Popup.createDialog(parent.VI. } }.một đối tượng chọn màu . . new ActionListener() // Lắng nghe cho OK { public void actionPerformed(ActionEvent event) { setBackground(chooser.chế độ hộp thoại modal hay modeless.parent: một companent cha."Background Color".

131 .

• Phương thức joint đợi (wait) một phản hổi của một thông điệp được gửi đi trước khi thực hiện thread. • Phương thức isAlive() trả về true nếu start() đã được gọi và phương thức run() vẫn đang thực hiện.3 Các bước để tạo một thread Sau đây là các bước đơn giản để thực hiện một nhiệm vụ trong một thread riêng: 132 . Các câu lệnh trong hàm main() nếu không được đưa vào một luồng riêng thì sẽ được thực hiện tuần tự. • Phương thức tĩnh sleep của Thread được gọi với một tham số xác định rằng một thread đang chạy sẽ dừng lại trong bao lâu theo đơn vị phần nghìn giây. I.1 Khái niệm Thread – luồng chỉ một đơn vị chương trình có thể tách khỏi các phần khác của chương trình để thực hiện song song với các phần khác ở từng khoảng thời gian hoặc trong toàn bộ quá trình nó thực hiện. Lớp Thread Lớp Thread trong gói java. Sau khi start() thực hiện xong.lang có một số constructor: Public Thread (<tên thread>) Public thread(): Khi này thread sẽ có tên là Thread_1. getName() lấy tên một thread. Phương thức này trả về true nếu ngắt thành công. • Phương thức setName() đặt tên cho một thread. có một luồng chính được bắt đầu bằng việc gọi hàm main(). Lập trình viên xác định số lượng các thread được chạy trong chương trình và chúng được thực hiện song song với nhau ở những giai đoạn nào. Khả năng này của Java gọi là tính đa luồng. độ ưu tiên và nhóm của thread. Thread_2. I.Đề tài 11. • Phương thức static currentThread() trả về tham chiếu tới thread hiện hành đang thực hiện. Threading Java là ngôn ngữ thông dụng duy nhất hỗ trợ cho lập trình viên các giải pháp lập trình song song. Các công việc của một thread được đặt trong phương thức run(). phương thức start() sau đó sẽ gọi run().…. Phương thức này có thể được khai báo chồng trong lớp khai báo kế thừa Thread hoặc khai báo cài đặt giao diện Runable. nó sẽ không tiêu tốn tài nguyên CPU và thread khác có thể chạy. Phương thức toString() trả về tên phương thức. I. • Phương thức start() sẽ ném ra một ngoại lệ IllegalThreadStateException nếu thread cần bắt đầu đã bắt đầu rồi. nó trả về điều khiển cho chương trình gọi nó. Phương thức isInterrupted() dùng để kiểm tra xem thread có bị ngắt hay không.2. Do đó. • Phương thức interrupt() được gọi để để ngắt một thread. các luồng khác có thể phát sinh từ luồng chính này. Khái niệm thread I. chương trình gọi nó và thread được thực hiện một cách đồng thời. Trong khi một thread “sleep”. Trong mỗi chương trình Java. Người lập trình bắt đầu một thread bằng các gọi phương thức start().

Trạng thái running: Một Thread ở trạng thái ready có quyền ưu tiên cao nhất sẽ được chuyển sang trạng thái này. Nếu đang ở trạng thái sleep mà gọi phương thức interrupt(). Tạo một đối tượng của lớp Runnable r = new MyRunnable(). • • • 133 . Khai báo một lớp có cài đặt giao diện Runable với phương thức run() được định nghĩa: class MyRunnable implements Runnable { public void run() { // code thực hiện } } 2. một thread running cũng có thể bị chặn (blocked) trong các thao tác vào ra. Các trạng thái của thread. • Trạng thái sleep: Khi Thread gọi phương thức sleep. tread sẽ thoát khỏi trạng thái sleep và chuyển sang trạng thái ready. Tạo một đối tượng Thread từ đối tượng Runable trên: Thread t = new Thread(r).1.start().3 và 4 để thực hiện thread. Sau đây là sơ đồ trạng thái của một thread. Trạng thái ready: Khi phương thức start() được gọi. Trạng thái born: Khi thread chưa gọi start(). Gọi phương thức start() t. Lúc này nó cũng không sử dụng tài nguyên CPU. 3. • Trạng thái dead: Khi một Thread ngưng hoặc hoàn thành nhiệm vụ của nó. Một thread cũng có thể được tạo ra bằng cách xây dựng một lớp con của lớp Thread: class MyThread extends Thread { public void run() { // code của thread } } Sau đó ta cũng làm theo các bước 2. II. 4. Ngoài ra.

III. Ta có thể tăng hoặc giảm độ ưu tiên của bất kỳ thread nào với phương thức setPriority() bằng một giá trị nằm giữa MIN_PRIORITY(1) và MAX_PRIORITY (10).Khi một thread đang chạy gọi phương thức wait(). thread sẽ rơi vào một trạng thái wait để đợi một đối tượng mà nó đã gọi.1 Độ ưu tiên của thread Mỗi Thread có một độ ưu tiên.là thread đã gọi nó. Các thuộc tính của thread III. Trình từ thực hiện của các thread theo độ ưu tiên của nó được minh họa như sau: 134 . Mặc định thì thread thừa kế độ ưu tiên từ thread cha của nó.

. ThreadGroup g = new ThreadGroup(groupName) Sau đó.interrupt().Các thread có độ ưu tiên càng cao thì khả năng thực hiện càng cao. III. Các thread có cùng độ ưu tiên sẽ được xếp vào một hàng đợi. .2 Nhóm thread Các thread có thể được đưa vào cùng một nhóm để có thể đồng thời làm việc với cả nhóm thread này. Không có mệnh đề catch nào được thực hiện mà 135 . với mỗi thread được tạo ra ta dùng constructor có khai báo nhóm thread: Thread t = new Thread(g. Để ngắt tất cả các thread trong nhóm g ta gọi: g. activeCount(). Khai báo một nhóm Thread: String groupName = . Để kiểm tra xem có thread nào trong nhóm g còn hoạt động không. threadName). III.. ta dùng phương thức: g.3 Quản lý các ngoại lệ của thread Phương thức run() không thể ném ra một ngoại lệ được kiểm soát mà bị kết thúc bởi một ngoại lệ không kiểm soát được mỗi khi có lỗi.

sleep( 1000 * 60 * 60 * 8 ).sleep(int) thì chương trình thường phải bắt các ngoại lệ để xử lý. IV..Nếu không. ngoại lệ này sẽ được gửi cho một bộ xử lý ngoại lệ không được kiểm soát.Nếu là null.Nếu nhóm thread có cài đặt uncaughtException thì phương thức đó được gọi.out.println ("Chỉ mới được hơn 5 phút thôi.UncaughtExceptionHandler chỉ với 1 phương thức: void uncaughtException(Thread t. Điều khiển các thread Sau khi đã khởi động được một thread rồi. Hãy đánh thức nó").err. Tuy nhiên. trước khi thread bị dead. Tuy nhiên. 3. nếu phương thức Thread.thay vào đó.. public class SleepyHead extends Thread { // Phương thức được chạy khi thread khởi động lần đầu public void run() { System.out. tên của thread và stack trace được gửi tới System. các thread riêng lại phụ thuộc vào bộ xử lý của nhóm thread chứa nó. 2.err và đưa ra màn hình.getDefaultExceptionHandler trả về một bộ xử lý không phải là null thì bộ xử lý này được gọi. Nếu không cài bộ xử lý ngoại lệ cho một thread thì mặc định là null. ta có thể cài bộ xử lý ngoại lệ cho bất cứ thread nào bằng phương thức: setUncaughtExceptionHandler().. phương thức uncaughtException sẽ làm các việc sau: 1. không có gì xảy ra.5.IOException { 136 . 4. Bộ xử lý này phải thuộc một lớp có cài đặt giao diện Thread.println ("Thread đang ngủ. } catch (InterruptedException ie) { System. Lý do là thread bị dừng lại trong một khoảng thời gian lâu và trong khoảng thời gian đó nó không thể tự đánh thức nó được."). vấn đề tiếp theo sẽ là điều khiển thread. IV. Mgoaif ra ta có thể cài bộ xử lý ngoại lệ mặc định cho tất cả các thread bằng cách gọi phương thức setDefaultUncaughtExceptionHandler của lớp Thread.Ngược lại.1 Interrupt một thread Khi sử dụng phương thức Thread. nếu Throwable là một đối tượng của TheadDead.io. Từ phiên bản Java 1. nếu một thread cần phải được đánh thức sớm hơn. } } // Phương thức main tạo và bắt đầu thread public static void main(String args[]) throws java. ta có thể ngắt nó dùng phương thức interrupt(). try { // Ngủ trong 8 tiếng Thread. System.println ("Đó là một giấc ngủ trưa"). Throwable e). Khi này.

start().. System. System.out. // bắt đầu thread sleepy. // Nhắc người dùng System. // Ngủ nửa giây try { Thread.hàm main.out. System.io. Điều này yêu cầu thread điều khiển phải giữ một tham chiếu tới thread muốn dừng.// Tạo một thread Thread sleepy = new SleepyHead(). // Nhắc người dùng để dừng thread System.out.stop().stop(). public class StopMe extends Thread { // Phương thức được thực hiện khi thread khởi động lần đầu public void run() { int count = 1.sẽ đợi cho người dùng ấn enter.in.) { // In ra biến count và tăng giá trị cho nó System.2 Dừng một thread Đôi khi ta muốn một thread dừng lại trước khi nhiệm vụ của nó hoàn thành. } catch (InterruptedException ie) {} }} // phương thức main public static void main(String args[]) throws java. thread chính. Ở đây.sleep(500).print (count++ + " ").read().println ("Thread đếm!"). // Ngắt thread sleepy. counter. sau đó gửi một thông điệp ngắt tới thread đang ngủ. for (.start(). // Dừng thread counter.IOException { // Tạo và bắt đầu thread Thread counter = new StopMe().in.interrupt(). Một thread (gọi là thread điều khiển) có thể gửi một thông điệp dừng tới một thread khác bằng việc gọi phương thức Thread. }} Cách thực hiện ở đây là gửi một thông điệp từ một thread khác để đánh thức một thread đang ngủ. }} 137 .out. IV.read().println ("Nhấn Enter để dừng đếm").println ("Nhấn Enter để ngưng thread").

dying.println ("Đợi cho thread kết thúc"). // Nhắc user System.sleep(5000). Tuy nhiên. // Nghỉ trong 5 giây try { Thread.…Ta dùng phương thức isAlive() để xác định thread còn chạy không. nếu thường xuyên dùng phương thức này để kiểm tra sau đó dùng sleep() hoặc yield() thì hiệu quả sử dụng CPU sẽ rất thấp. IV.out. Trong trường hợp này. Một cách hiệu quả là gọi phương thức joint() để đợi một thread kết thúc công việc.5 Đợi một thread kết thúc công việc Đôi khi ta cần đợi cho một thread kết thúc một công việc nào đó như gọi một phương thức hay đọc một thuộc tính thành phần. System. } catch (InterruptedException ie) {} } // phương thức main public static void main(String args[]) throws java.. Ta không thể giải phóng thời gian CPU của bất kỳ thread nào mà chỉ đối với thread hiện thời.4 Giải phóng thời gian cho CPU Khi một thread rơi vào trạng thái đợi một sự kiện xảy ra hoặc đi vào một vùng mã lệnh mà nếu giải phóng thời gian cho CPU sẽ nâng cao hiệu quả của hệ thống. thread nên giải phóng thời gian hệ thống hơn là dùng sleep() để nghỉ trong thời gian dài. IV. Để làm điều này ta dùng phương thức static yield() của Thread để giải phóng thời gian CPU cho thread hiện thời.3 Tạm dừng và phục hồi một thread Các phương thức suspend() dùng để tạm dừng một thread trong khi resume() dùng để tiếp tục một thread đã bị suspend.out.IV. dying. public class WaitForDeath extends Thread { // Phương thức run() public void run() { System.join().out..println ("thread chuẩn bị nghỉ.InterruptedException { // Tạo thread Thread dying = new WaitForDeath().. Tuy nhiên sử dụng các thread này rất hay gây ra tình trạng deadlock do thread bị suspend đang chiếm giữ một tài nguyên và không giải phóng trong khi nhiều thread khác có thể đang đợi sử dụng tài nguyên đó.").start().}} 138 .lang.println ("Thread đã dừng").

} catch(InterruptedException e) {} } } Khi chương trình chạy.1 Tình trạng “đua tranh” Trong phần tiếp theo.out. public void run() { try { int toAccount = (int) (bank. toAccount.random().currentThread()). accounts[to] += amount.size() * Math. amount). System. tức là cùng thực hiện câu lệnh: account[to] += amount. Kết quả có thể là các thread bị ảnh hưởng lẫn nhau và không đạt được kết quả mong muốn. Mỗi giao dịch thực hiện việc chuyển tiền từ account sang một account ngẫu nhiên khác.transfer(fromAccount.out.sleep((int) (DELAY * Math.printf(" Số dư: %10. Điều gì xảy ra nếu cả hai thread cùng truy cập đến đối tượng và làm thay đổi thuộc tính đối tượng. getTotalBalance()). chúng ta mô phỏng một ngân hàng có rất nhiều tài khoản khách hàng..V. double amount = maxAmount * Math. Chúng ta thử thiết kế một chương trình để chuyển tiền ngẫu nhiên giữa các tài khoản. from. 139 . Ta có một class Bank với phương thức transfer để chuyển tiền. đó là khi có nhiều hơn một tài khoản cùng chuyển tiền đến một tài khoản khác. trong một số tình huống chương trình trên có thể gây lỗi và in ra tổng số tiền khác nhau.printf(" %10. Nếu account chuyển không đủ tiền. double amount) { System. Đồng bộ thread Trong hầu hết các chương trình đa luồng. Chương trình trên chạy và không bao giờ dừng lại.2f%n". public void transfer(int from. các thread có thể cần phải truy cập đến cùng một đối tượng.print(Thread. System. } Sau đây là đoạn code cho class transferRunnable: class TransferRunnable implements Runnable { . giao dịch kết thúc ngay. amount. V. int to.random())).random()).2f from %d to %d".. to). Thread. Mỗi tài khoản có một thread riêng. Tuy nhiên.out. ta phải ấn Ctrl + C để dừng nó. bank. accounts[from] -= amount. Tình trạng này gọi là “đua tranh”. ta không biết được trong mỗi tài khoản còn bao nhiêu tiền nhưng tổng số tiền của tất cả các tài khoản là không đổi.

Cộng với account 3. Khi một thread đầu tiên đã gọi lock thì không một thread nào sau đó có thể vượt qua lệnh lock(). Cấu trúc đoạn lệnh căn bản để sử dụng cơ chế này là: myLock. account[to] lúc này đã ghi đè giá trị do thread_2 cập nhật.out. System. System.printf(" %10. phép tính này lại không phải là atomic. int amount) { bankLock. Thread_1 thực hiện xong bước 1 và 2 thì bị ngắt.out.2f%n". System. // đối tượng ReentrantLock try { //Đoạn lệnh cần bảo vệ } finally { myLock.0 có hỗ trợ hai cơ chế để bảo vệ một khối lệnh khỏi sự truy cập đồng thời. accounts[from] -= amount.currentThread()). phần tiền do thread_2 chuyển cho account[to] đã bị mất.unlock(). nếu ta đảm bảo rằng phương thức transfer() được thực hiện thành công trước khi thread bị ngắt thì sẽ không có vấn đề gì xảy ra. thread_1 thức dậy và làm tiếp bước 3. getTotalBalance()). Điều này dẫn tới việc tổng số tiền bị thay đổi.out. Tuy nhiên. công việc có thể phải làm là: 1. khi đó mỗi thread sẽ thực hiện phép tính này một cách tuần tự mà không gây ảnh hưởng vì trong một thời điểm. accounts[to] += amount.Giả sử đây là một hành vi đơn vị (atomic.printf(" Total Balance: %10. Các phiên bản trước của Java sử dụng từ khóa synchronized.2 Khóa đối tượng Trong ví dụ trên. V.hành vi chỉ chiếm một thao tác thực hiện lệnh của CPU). amount. 140 . trong một thời điểm sẽ chỉ có một thread được truy cập vào một đoạn mã lệnh nào đó. to).lock(). int to.lock(). try { if (accounts[from] < amount) return. sau đó thread_2 sẽ thực hiện câu lệnh trên với đầy đủ 3 bước tức là account[to] đã bị thay đổi giá trị.Load kết quả ngược trả lại cho account[to] Giả sử có 2 thread là thread_1 và thread_2 cùng thực hiện đến dòng lệnh này. from. Từ phiên bản Java 5. Có nghĩa là. Bây giờ chúng ta sẽ khóa phương thức transfer() trong lớp Bank: public class Bank { public void transfer(int from. Java 5.2f from %d to %d". // đảm bảo khóa được mở kể cả khi exception xảy ra } Đoạn lệnh này đảm bảo rằng chỉ có một thread tại một thời điểm có thể đi vào vùng được bảo vệ.Load giá trị account[to] vào thanh ghi 2. Tiếp theo.0 giới thiệu thêm lớp ReentrantLock cho mục đích này.print(Thread. CPU cũng chỉ phục vụ được cho một thread.

lock().. Tuy nhiên. } finally { bankLock. Khi có điều kiện này. } V. ta có thể nghĩ ra một giải pháp là để thread đợi cho đến khi nó có đủ tiền để chuyển: public void transfer(int from.. Đến đây. } } Việc đợi ở đây sẽ kết thúc khi một thread khác chuyển tiền vào cho nó. try { while (accounts[from] < amount) // Đợi cho đến khi tài khoản của nó có đủ tiền { // đợi .getBalance(from) >= amount) bank. Tuy nhiên ta thấy rằng vùng chứa lệnh chuyển tiền lại đang bị khóa bởi chính thread này nên các thread khác không thể chuyển tiền được. int to. nó cần hoàn thành công việc để có thể mở khóa cho các thread khác đi vào.unlock(). private Lock bankLock = new ReentrantLock(). Đây là tình huống mà ta phải sử dụng đối tượng điều kiện: class Bank { public Bank() 141 .. to.3 Đối tượng điều kiện Trong trường hợp thread đi vào vùng bảo vệ.. một thread có thể không thỏa mãn và nó không thực hiện việc chuyển tiền. việc gọi transfer() để chuyển tiền chỉ được thực hiện khi số tiền của account gửi lớn hơn số tiền được gửi: if (bank. amount). chẳng hạn ở đây. int amount) { bankLock. chương trình rơi vào deadlock.transfer(from. } } ..} finally { bankLock. nếu trong đó công việc chính cần thực hiện bị giới hạn bởi một điều kiện nào đó.. // ReentrantLock là một lớp cài đặt giao diện lock. Kết quả là thread này không bao giờ thoát khỏi tình trạng đợi.unlock(). tức là công việc của nó là không hữu ích. } // Chuyển tiền .

await().signalAll().lock(). sufficientFunds = bankLock.vị trí gọi phương thức await() và kiểm tra lại điều kiện.. int to. } . nó sẽ được chạy tiếp và cố gắng đi vào vùng khóa và bắt đầu từ vị trí mà nó chờ đợi trước đó .. } } Chú ý là việc gọi signalAll() không phải là kích hoạt thread bị chặn ngay lập tức. sign() và await() trong vùng được bảo vệ.await(). Nó chỉ giải phóng tình trạng bị chặn của các thread khác cho đến khi nó kết thúc đoạn chương trình được bảo vệ. sufficientFunds. Có một sự khác nhau căn bản giữa một thread đang đợi để khóa (gọi phương thức lock() để đi vào vùng bảo vệ) và thread gọi phương thức await(). chương trình sẽ bị treo.unlock().. Một phương thức await() nên được gọi trong một vòng lặp đợi: while (!(đủ tiền)) condition. int amount) { bankLock. 142 . Nếu tất cả các thread khác đều đang bị chặn. public void transfer(int from.{ . } Nếu phương thức transfer() kiểm tra và thấy rằng nó chưa đủ tiền để chuyển thì nó sẽ gọi: sufficientFunds.signalAll() để mở khóa cho các thread đang nằm đợi thỏa mãn điều kiện đủ tiền.. try { while (accounts[from] < amount) sufficientFunds.Lúc này nó sẽ nằm chờ thread khác chuyển tiền.await(). } finally { bankLock. Một phương thức khác là sign() chỉ trao khóa cho một thread xác định thay vì tất cả. Ở đây.. private Condition sufficientFunds. Một khi thread đã thoát khỏi tình trạng đợi do await() gây ra. nó nên gọi: sufficientFunds. Nó sẽ không thể mở khóa khi đang nằm trong vùng khóa cho đến khi một thread khác gọi signalAll(). sau khi cộng tiền vào cho tài khoản nhận và thì signalAll() sẽ được gọi. thread gọi await() không giả phóng tình trạng này cho một thread nào đó thì bản thân nó cũng bị chặn. Vấn đề là khi nào thì gọi signalAll()? Nguyên tắc chung là khi một thread hoàn thành việc thay đổi trạng thái đối tượng thì nó nên gọi signalAll().. Một thread thực hiện xong việc chuyển tiền.newCondition(). Một thread chỉ có thể gọi các phương thức signalAll(). Việc gọi này sẽ giúp các thread cũng đang trong tình trạng chờ đợi này không bị chặn nữa và tiếp tục công việc với một giá trị tài khoản có thể đã bị thay đổi. Nếu không có thread nào gửi signalAll() thì thread đang đợi không có cách nào chạy tiếp được. // Chuyển tiền .

Sau khi chuyển xong. thực hiện việc chuyển tiền. Viết chương trình song song với 10 thread để cộng 10000 số tự nhiên liên tiếp từ 1 đến 10000. mỗi người chuyển cho một người khác trong số 9 người còn lại. Mỗi thời điểm ngân hàng chỉ chuyển tiền cho một người. Nếu chẳng may người đang thực hiện chuyển số tiền lớn hơn anh ta có. Một trong số 9 người ngoài cổng sẽ được đi vào trong ngân hàng. Bài tập 1. Viết một chương trình tạo một thread thực hiện việc giải một phương trình bậc 2 với các hệ số cho trước. 143 . sau đó những người đang đợi cũng quay ra cổng để đợi đến lượt vào. anh ta thông báo cho tất cả các anh khác đang phải đợi trong ngân hàng là mình vừa chuyển tiền (gọi signalAll()) rồi đi ra ngoài. 9 người khác phải chờ ngoài cổng.Chúng ta có thể kết thúc phần này bằng một câu chuyện minh họa: Có 10 người cùng đến ngân hàng để chuyển tiền cho nhau. người được gửi tiền sẽ được vào trong ngân hàng và giữ khóa cổng. 2. anh ta sẽ đợi ở trong ngân hàng (gọi await()) và ném khóa ra ngoài cổng cho tất cả 9 người kia.

hoặc một lớp hay phương thức không thể bị khai báo chồng. Nhập một package Kiểm tra xem đối tượng có phải là biểu hiện của một lớp Số nguyên 4 byte Một kiểu trừu tượng với các phương thức được cài đặt tại các class Số nguyên 8 byte 144 . Một phần của khối try mà luôn được thực hiện Số thực 4 byte Một kiểu vòng lặp Không sử dụng Một lệnh điều khiển rẽ nhánh Chỉ ra các interfaces mà lớp sẽ cài đặt.Phụ lục A. Các từ khóa của Java Từ khóa abstract assert boolean break byte case catch char class const continue default do double else extends final finally float for goto if implements import instanceof int interface long Ý nghĩa Một lớp hoặc phương thức trừu tượng Được sử dụng để định vị lỗi nội bộ chương trình Kiểu boolean Thoát khỏi lệnh switch hoặc các vòng lặp Số nguyên 1 byte Một lựa chọn của switch Một mệnh đề của khối Try để bắt một ngoại lệ Kiểu ký tự Unicode Định nghĩa một class Không được sử dụng Tiếp tục tại vị trí cuối vòng lặp hiện thời Mệnh đề mặc định của switch Phần trên của vòng lặp do/while Kiểu số thực floating-number 8 byte Mệnh đề else của một lệnh if Xác định lớp cha của một lớp Một hằng số.

Cấp phát vùng nhớ cho một đối tượng hoặc mảng mới Một tham chiếu null Một gói các lớp Giới hạn phạm vi truy cập chỉ trong lớp Giới hạn phạm vi truy cập trong lớp.lang.. 2. acos(double x) = arccos(x). 6. asin(double x) = arcsin(x). double. exp(double x) = ex. log(double x) = Ln(x). x có thể là các kiểu long. ceil(double x): làm cận trên hoặc cận dưới của số x.. Một giá trị tồn tại ở phạm vi lớp Use strict rules for floating-point computations Đối tượng hoặc constructor lớp cha Câu lện lựa chọn đối tượng ngầm định của một lớp quăng ra một ngoại lệ Các exceptions mà một phương thức có thể quăng Đánh dấu dữ liệu không cố định Khối lệnh bắt lỗi Ký hiệu cho một phương thức không trả về giá trị ensures that a field is coherently accessed by multiple threads Vòng lặp synchronized Một phương thức hoặc khối lệnh chỉ thuộc về một thread Phụ lục B Một số hàm hay sử dụng a) Hàm toán học. x từ -PI/2 . int. x là radian. abs(number x): lấy |x|.Từ khóa Native new null package private protected public return short static strictfp super switch this throw tHRows transient try void volatile while Ý nghĩa phương thức được cài đặt bằng ngôn ngữ khác. Trả về giá trị trong một phương thức Kiểu số nguyên 2 byte. {java. 145 . các lớp dẫn xuất và các lớp trong cùng gói Không giới hạn phạm vi truy cập. 7. PI/2 4. atan(double x) = arctag(x)..*.0 . lớp java. PI 3. x từ 0.} 1. 5. 8.Math. float.. cos(double x) = cos(x).math.

0 = CN. 15.. String() : Khởi động một đối tượng chuỗi. y}. “Writing Effective Use Cases”. 3. 146 . getMinutes(): trả về giá trị int chỉ phút trong giờ. charAt(int i): trả về một ký tự thứ sau i. 1 = mon.Date. 8. Lấy mốc là 1900. trong đó x. khai báo java. 4. Khi sử dụng ta phải dùng Math. 15. 2. setSeconds(int i): thay đổi giá trị giây trong biến date. float. double. tháng.. 7.2. number y) = max{x. getDate(): trả về giá trị của ngày trong tháng. setDate(int date) đặt lại ngày trong biến. 14. 7. Prentice Hall PTR. setYear(int year): thay đổi giá trị năm trong biến date.getYear() +1900. nếu x là kiểu float thì thành kiểu int. 6. Michael Reilly (2002). float.tên_hàm. 14. giờ. setMinutes(int i): thay đổi giá trị phút trong biến date. round(number x): làm tròn số x. sin(double x) = sin(x). “Java. y có thể là kiểu int. Horstmann. fourth edition. date lấy giá trị từ 1.11.. 12.11). 1. 10. Tài liệu tham khảo [1] Alistair Cockburn (2000). min(number x. double. sqrt(double x) = 16. 6 = Sat. tan(double x) = tg(x).. getSeconds(): trả về giá trị int chỉ giây đồng hồ trong phút. ngày. 6.. năm thực = date. 5. getYear(): trả về giá trị int là năm. .0. getHours(): trả về giá trị int chỉ giờ trong ngày. 13.0]. getMonth(): trả về giá trị int là tháng trong năm (0. y có thể là kiểu int. random(): cho một số ngẫu nhiên trong [0.lang.9. concat(String str): nối thêm chuỗi str vào sau. b) Lớp String. Lớp Date khai báo java. [3] David Reilly. 11. Addison Wesley. setHours(int hour): thay đổi giá trị giờ trong biến date. Gary Cornell (2004). double y) = xy. trong đó x. 2. 9. 4.util. volume 1. getDay(): trả về giá trị int là thứ trong tuần. pow(double x. 3. month có giá trị 0. 1. 8. How to program”. indexOf(int ch): trả về vị trí trước của ký tự ch đầu tiên tìm thấy. setMonth(int month): thay đổi giá trị tháng trong biến date. “Network Programming and Distributed Computing”. toUpperCase(): chuyển đổi chuỗi thành chữ HOA. năm. toLowerCase(): thay đổi chuỗi thành chữ thường. 1.. long. String(String s) : Khởi động một chuỗi bằng chuỗi s. y}.String. [2] Cay S. nếu x là kiểu double thì thành kiểu long. long. max(number x. 12. (year + 1900). Date(): cho thứ.. 10. “Core Java™ 2”. getTime(): trả về là một số được tính theo giây đồng hồ. length() : trả về giá trị int là độ dài một chuỗi. Addison-Wesley Longman. [4] Deitel & Associates (2001). number y) = min{x. 5. 13.31 11.

Sign up to vote on this title
UsefulNot useful