Professional Documents
Culture Documents
1
I.4. Cấu trúc một chương trình Java ................................................................................... 28
II. Các kiểu dữ liệu trong Java ............................................................................................... 29
II.1 Các kiểu dữ liệu số nguyên ......................................................................................... 29
II.2 Các kiểu số thực.......................................................................................................... 30
II.3 Kiểu ký tự (character) ................................................................................................. 30
II.4 Kiểu logic (boolean) ................................................................................................... 30
II.5 Kiểu chuỗi .................................................................................................................. 30
II.6 Chuyển đổi giữa các kiểu số ........................................................................................ 30
III. Khai báo biến và hằng trong Java .................................................................................... 31
III.1 Quy tắc đặt tên biến ................................................................................................... 31
III.2 Khai báo biến ............................................................................................................ 31
III.3 Biến kiểu mảng .......................................................................................................... 32
III.4 Hằng số (literal) ......................................................................................................... 33
III.5 Phạm vi hoạt động của hằng và biến: ......................................................................... 34
IV. Các toán tử và biểu thức .................................................................................................. 34
IV.1 Các toán tử và thứ tự ưu tiên ...................................................................................... 34
IV.2 Biểu thức ................................................................................................................... 35
V. Các lệnh điều khiển rẽ nhánh ............................................................................................ 35
V.1 Lệnh if ........................................................................................................................ 35
V.2. Lệnh switch …case .................................................................................................... 36
VI. Các lệnh lặp .................................................................................................................... 37
VI.1. Vòng lặp for ............................................................................................................. 37
VI.2. Vòng lặp while ......................................................................................................... 38
VI.3. Vòng lặp do... while ................................................................................................. 38
VI.4. Phép nhảy................................................................................................................. 39
VII. Vào dữ liệu từ bàn phím và xuất dữ liệu ra màn hình ..................................................... 40
VII.1. Lấy giá trị nhập vào từ bàn phím ............................................................................. 40
VII.2 Kết xuất dữ liệu ra màn hình .................................................................................... 41
Bài tập .................................................................................................................................. 42
Đề tài 3. Lập trình hướng đối tượng trong Java ......................................................................... 44
I. Khái niệm lập trình hướng đối tượng (Object-Oriented Programming - OOP) .................... 44
I.1. Khái niệm OOP ........................................................................................................... 44
I.2 Cơ sở lý luận của OOP ................................................................................................. 44
I.3 Trừu tượng hóa ............................................................................................................ 44
II. Tính đóng gói trong Java .................................................................................................. 46
II.1 Khái niệm tính đóng gói.............................................................................................. 46
II.2 Mối quan hệ giữa các class.......................................................................................... 46
II.3 Một số gợi ý khi thiết kế class ..................................................................................... 46
IV. Sử dụng các Class xây dựng sẵn trong thư viện ............................................................... 47
V. Xây dựng Class trong Java ............................................................................................... 48
V.1 Cấu trúc của class ....................................................................................................... 48
V.2 Các thuộc tính thành phần:.......................................................................................... 49
V.3 Các phương thức thành phần....................................................................................... 50
V.4 Gọi và truyền tham số cho phương thức ...................................................................... 51
V.6 Các hàm và phương thức đặc biệt ............................................................................... 51
V.7 Khai báo chồng các phương thức ................................................................................ 52
V.8 Lớp lồng nhau – lớp nội.............................................................................................. 53
2
VI. Tính kế thừa trong Java ................................................................................................... 54
VI.1 Sự kế thừa các thuộc tính và phương thức.................................................................. 54
VI.2 Sự kế thừa đối với các constructor ............................................................................. 57
VII. Tính đa hình trong Java .................................................................................................. 58
VII.1 Sự ép kiểu và gán tham chiếu đối tượng ................................................................... 58
VII.2 Sự ràng buộc động –Dynamic Binding ..................................................................... 58
VIII. Lớp Object ................................................................................................................... 59
IX. Giao diện ........................................................................................................................ 60
IX.1 Cấu trúc của giao diện ............................................................................................... 60
IX.2 Các tính chất của giao diện ........................................................................................ 62
X. Package ............................................................................................................................ 62
X.1 Sử dụng các package trong thư viện Java .................................................................... 62
X.2 Đặt lớp vào package ................................................................................................... 63
Bài tập .................................................................................................................................. 63
Đề tài 4. Lớp và phương thức trừu tượng .................................................................................. 64
I. Khái niệm lớp trừu tượng ................................................................................................... 64
II. Cài đặt lớp và phương thức trừu tượng trong Java ............................................................. 64
Bài tập .................................................................................................................................. 65
Đề tài 5. Lưu trữ và xử lý đối tượng .......................................................................................... 66
I. Lớp Vector và giao diện Enumeration ................................................................................ 66
I.1 Lớp Vector ................................................................................................................... 66
I.2 Giao diện Enumeration................................................................................................. 67
II. Mảng trong Java và lớp ArrayList ..................................................................................... 69
II.1 Mảng trong Java ......................................................................................................... 69
II.2. Các thuật toán cơ bản trên mảng ................................................................................ 70
II.3 Class Arrays ............................................................................................................... 71
III Danh sách trong java và giao diện Lists ............................................................................ 73
Bài tập .................................................................................................................................. 74
Đề tài 6. Các luồng vào ra dữ liệu với file ................................................................................. 75
I. Khái niệm luồng vào ra (I/O stream) .................................................................................. 75
II. Lớp InputStream: .............................................................................................................. 76
III. Lớp OutputStream ........................................................................................................... 77
IV. Lớp FileInputStream ....................................................................................................... 77
V. Lớp FileOutputStream ...................................................................................................... 77
VI. Lớp File .......................................................................................................................... 77
VII. Nhập xuất lọc................................................................................................................. 78
VII.1 Lớp FilterInputStream: ............................................................................................. 79
VII.2 Lớp FilterOutputStream ........................................................................................... 79
VIII. Vào/ra có sử dụng bộ đệm ............................................................................................ 79
VIII.1 Lớp BufferedInputStream: ...................................................................................... 79
VIII.2 Lớp BufferedOutputStream..................................................................................... 79
IX. Lớp RandomAccessFile .................................................................................................. 81
X. Đối tượng System.in ......................................................................................................... 82
XI. Truy cập file ở chế độ tuần tự .......................................................................................... 82
XII. Truy cập file nhị phân .................................................................................................... 86
Bài tập .................................................................................................................................. 86
Đề tài 7. Xử lý ngoại lệ ............................................................................................................. 88
3
I. Các tình huống sử dụng ngoại lệ ........................................................................................ 88
II. Cơ sở quản lý ngoại lệ trong Java ..................................................................................... 88
III. Cấu trúc cây kế thừa các xử lý ngoại lệ ............................................................................ 89
IV. Sử dụng ngoại lệ được kiểm soát ..................................................................................... 90
V. Xây dựng một ngoại lệ ..................................................................................................... 91
VI. Bài tập ............................................................................................................................ 92
Đề tài 8. Xử lý các sự kiện trong Java ....................................................................................... 93
I. Khái niệm và cơ sở xử lý sự kiện ....................................................................................... 93
II. Truy cập thông tin sự kiện ................................................................................................ 98
III. Xử lý các sự kiện trên window ........................................................................................ 99
IV. Các lớp thích nghi ..........................................................................................................100
V. Xử lý các sự kiện chuột ...............................................................................................102
Bài tập .................................................................................................................................103
Đề tài 9. Applet ........................................................................................................................104
I. Xây dựng một Applet đơn giản .........................................................................................104
II. Cấu trúc cơ bản và vòng đời của một Applet ....................................................................104
III. An ninh và khả năng của Applet .....................................................................................106
IV. Ứng dụng Applet với của sổ Popup ................................................................................106
V. Các thẻ HTML của Applet...............................................................................................107
VI. Các phương thức, lập trình đồ họa và bắt sự kiện của applet ...........................................108
Đề tài 10. Lập trình giao diện đồ họa GUI ................................................................................110
I. Giới thiệu AWT ................................................................................................................110
II. Vật chứa (Container) .......................................................................................................111
II.1 JFrame .......................................................................................................................111
II.2 JPanel ........................................................................................................................111
II.3 JDialog ......................................................................................................................112
II.4 JScrollPane ................................................................................................................113
III. Giới thiệu về các thành phần GUI cơ bản .......................................................................113
III.1 Nút nhấn ...................................................................................................................113
III.2 Nhãn (Label) ............................................................................................................114
III.3 Nút đánh dấu (checkbox) ..........................................................................................115
III.4 Nút chọn (radio button).............................................................................................117
III.5 Hộp thoại Combo .....................................................................................................118
III.6 Danh sách (Lists) ......................................................................................................119
III.7 Ô văn bản (text field) và vùng văn bản (text areas) ...................................................121
III.8 Thanh trượt (Scrollbar) .............................................................................................123
IV. Thành phần Menu ..........................................................................................................124
V. Bộ quản lý cách trình bày (Layout Manager) ...................................................................127
V.1 Cách trình bày FlowLayout:.......................................................................................128
V.2 Cách trình bày GridLayout: .......................................................................................128
V.3 Cách trình bày BorderLayout .....................................................................................128
VI. Các hộp thoại .................................................................................................................128
VI.1 Hộp thoại thông báo .................................................................................................128
VI.2 Hộp thoại chọn File ..................................................................................................129
VI.3 Hộp thoại chọn màu .................................................................................................130
Bài tập .................................................................................................................................130
Đề tài 11. Threading ................................................................................................................132
4
I. Khái niệm thread...............................................................................................................132
I.1 Khái niệm: ..................................................................................................................132
I.2. Lớp Thread ................................................................................................................132
I.3 Các bước để tạo một thread .........................................................................................132
II. Các trạng thái của thread..................................................................................................133
III. Các thuộc tính của thread ...............................................................................................134
III.1 Độ ưu tiên của thread ................................................................................................134
III.2 Nhóm thread .............................................................................................................135
III.3 Quản lý các ngoại lệ của thread ................................................................................135
IV. Điều khiển các thread .....................................................................................................136
IV.1 Interrupt một thread ..................................................................................................136
IV.2 Dừng một thread ......................................................................................................137
IV.3 Tạm dừng và phục hồi một thread ............................................................................138
IV.4 Giải phóng thời gian cho CPU ..................................................................................138
IV.5 Đợi một thread kết thúc công việc ............................................................................138
V. Đồng bộ thread ................................................................................................................139
V.1 Tình trạng “đua tranh” ...............................................................................................139
V.2 Khóa đối tượng ..........................................................................................................140
V.3 Đối tượng điều kiện ...................................................................................................141
Bài tập .................................................................................................................................143
Phụ lục A. Các từ khóa của Java ..............................................................................................144
Phụ lục B Một số hàm hay sử dụng ..........................................................................................145
Tài liệu tham khảo ...................................................................................................................146
5
Đề tài 0. Giới thiệu về Java
I. Lịch sử hình thành và phát triển ngôn ngữ lập trình Java
6
1.0 211
1.1 477
1.2 1524
1.3 1840
1.4 2723
5.0 3270
7
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.
Từ mã nguồn -> Bytecodes: Trình biên dịch Java.
Từ Bytecodes -> machine code: Trình thông dịch Virtual machine.
IBM
Trình
thông
Bytecode dịch
Java Sparc
Trình
biên dịch (Java
Interpreter)
Macintosh
8
II.8. 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.
Quá trình này cũng làm các chương trình Java chạy chậm hơn. Tuy nhiên đây lại là giải pháp cho
tính di động.
9
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).
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, 'javac'
Cú pháp:javac [options] sourcecodename.java
Trình thông dịch, 'java'
Cú pháp:java [options] classname
Trình dịch ngược, 'javap'
javap dịch ngược bytecode và in ra thông tin về các thuộc tính (các trường), các phương
thức của một lớp.
Cú pháp:javap [options] classname
Công cụ sinh tài liệu, 'javadoc'
Tiện ích này cho phép ta tạo ra tệp HTML dựa trên các lời giải thích trong mã chương
trình (phần nằm trong cặp dấu /*.... */).
Cú pháp:javadoc [options] sourcecodename.java
Chương trình tìm lỗi - Debug, 'jdb„
Cú pháp:jdb [options] sourcecodename.java
hay
jdb -host -password [options] sourcecodename.java
Cài đặt đường dẫn mặc định.
1. Mở Control Panel
2. Chọn System
10
3. Chọn Tab Advanced
4. Chọn Environment Variables
5. Thêm đường dẫn C:\Program Files\Java\jdk1.6.0_02\bin vào biến môi trường Path
- Chọn Variable Path
- Chọn Edit
11
Đề tài 1. Ngôn ngữ mô hình hóa UML
I. Xây dựng hệ thống phần mềm theo hướng đối tượng
I.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ế. 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ể. Nói cách khác,
các đối tượng và mối quan hệ giữa chúng phản ánh quy trình nghiệp vụ. 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. 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
2. Ứng viên gửi hồ sơ dự tuyển tới công ty
3. Công ty duyệt hồ sơ và gửi giấy hẹn phỏng vấn tới ứng viên
4. Công ty phỏng vấn ứng viên
5. Công ty ký hợp đồng với ứng viên hoặc từ chối
Trong ví dụ trên có sự tham gia của hai đối tượng “công ty” và “ứng viên”. 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).
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, quản lý,…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).
Trong một hệ thống bán hàng, mỗi đơn hàng bao gồm trong nó các thông tin về khách
hàng, ngày giờ, …và một danh mục các mặt hàng. 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. Vì vậy, 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.
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 (object), thông điệp (mesage), thừa kế (inheritance) và đa hình
(polymorphism).
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ấ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.
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 đó. Đố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. Sự chi tiết phụ thuộc vào phạm vi nghiệp vụ.
Sự trừu tượng hóa diễn ra ở nhiều cấp độ. Lấy ví dụ: lớp động vật có vú bao gồm lớp
động vật 4 chân, lớp 4 chân lại bao gồm các lớp như lớp mèo, lớp trâu,…
Mỗi đối tượng là một biểu hiện thực tế của một lớp.
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, dễ hiệu chỉnh, được
cài đặt dễ dàng bằng các ngôn ngữ hướng đối tượng. 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.
12
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. Tuy nhiên, lĩnh vực này vẫn cần
được chuẩn hóa hơn nữa.
I.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:
1. Sự gia tăng về quy mô từ nhỏ đến lớn của ứng dụng
2. Sức ép về thời gian hoàn thành
3. Sự phân tán về không gian làm việc
4. Đa dạng về nội dung
5. Sự thay đổi các yêu cầu của người sử 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, nơi mà vai trò của quá trình khảo sát, 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ế.
13
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. Cũng
cùng thời gian đó, 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. 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. Các thành viên của OMG ban đầu là 3Com Corporation; American Airlines;
Canon, Inc.; Data General; Hewlett-Packard; Philips Telecommunications N.V.; Sun
Microsystems; và Unisys Corporation. Các tập đoàn lớn như HP, IBM, Microsoft, 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. Năm 1997, OMG tiếp tục xem xét lại UML và đến năm 2001 thì phiên bản UML 1.4 ra
đời. Hiện nay OMG đã phát hành tới phiên bản UML 2.0 và đang nghiên cứu phiên bản 2.1.
14
III. Ngôn ngữ UML
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. UML 2.0 bao gồm 13 loại sơ đồ khác nhau.
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, object, message (thông điệp) và mối quan hệ giữa
chúng bao gồm quan hệ dependence, inheritance và aggregation. 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.
Các General Mechanisms (các đặc tả chung mở rộng): Mô tả các thông tin chú
thích, ngữ nghĩa của các phần tử mô hình, thuật ngữ.
15
••••••••••••••••••••••••••
ud Primary Use Cases ••••••••••••••••••••••••••
• • • • • • • • • • • • • • • • HÖ
• •thèng
• • • b¸n
• • hµng
• • • qua• m¹ng
• • • Interrnet
••••••••••••••••••••••
• • • • • • • • • • • • •Chän
• • •hµng
•••••••••• ••••••••••••••••••••••••••
Xem chi tiÕt
• • • • • • • • • • • • • • • • • • • • • • s¶n
• • phÈm
•• ••••••••••••••••••••••••••
CËp nhËt giá
•Kh¸ch
• • • •hµng
••••••••••••••••••••• • • • hµng
•••••••••••••••••••••••
Göi th«ng
• • • • • • • • • • • • • • • • • • • • •tin• ph¶n
• • •håi
• ••••••••••••••••••••••••••
•••••••••••••••••••••••••• ••••••••••••••••••••••••••
• • • • • • • • • • • • • • • • • • • • • • §¨ng
• • • ký
• • • • • • • •LËp
• •®¬n
• •mua
•••••••••••••••
kh¸ch hµng hµng
Qu¶n lý
• • • • • • • • • • • • • danh
• • • môc
•••••••••• ••••••••••••••••••••••••••
hµng hãa
•Qu¶n
• • •trÞ• hÖ
••••••••••••••••••••• ••••••••••••••••••••••••••
thèng
Tr¶ lêi
• • • • • • • • • • • • • • • • • • • kh¸ch
• • • •hµng
••• ••••••••••••••••••••••••••
CËp nhËt
• • • • • • • • • • • • • •th«ng
• • •tin
••••••••• ••••••••••••••••••••••••••
mÆt hµng
•••••••••••••••••••••••••• ••••••••••••••••••••••••••
•••••••••••••••••••••••••• ••••••••••••••••••••••••••
Các nguyên tắc cho việc xây dựng use-case view là:
• • • •Cá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
••••••••
(out-> in).
• • • •Các • • • • •phải
• • use-case • • •đầy
• •đủ,
• •chúng
• • • •được
• • •tổng
• hợp• • •theo
• • •phương
• • • •pháp
• • •đi• từ
• •tối
• •đa•đến
•••••••
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).
•••••••••••••••• ••••••••••••••••••••••••••
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
• sử
• •dụng
• • •cao.
•••••••••••••••• ••••••••••••••••••••••••••
Bên cạnh sơ đồ, 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
use-case •(text
• • detail).
• • • • •Mỗi
• •mô• •tả• cần
• • •đảm
• • bảo
• • •các
• •thông
• • •tin •sau:
•••••••••••••••••••••••••
1. Tên use-case
• • • • • •2.• •Mục
• • •tiêu
• •của
• •use-case
••••••••••• ••••••••••••••••••••••••••
3. Phạm vi của use-case
• • • • • •4.• •Các
• • tác
• •nhân
• • •chính
••••••••••• ••••••••••••••••••••••••••
5. Tiền điều kiện
• • • • • •6.• •Dòng
• • •chính
••••••••••••••• ••••••••••••••••••••••••••
7. Dòng phụ
•••••••••••••••••••••••••• ••••••••••••••••••••••••••
•••••••••••••••••••••••••• • • • • • • • • • • • • • • • • • • • •16
••••••
•••••••••••••••••••••••••• ••••••••••••••••••••••••••
8. Ngoại lệ
9. Hậu điều kiện
Sau đây là một ví dụ về use-case text detail:
Use-case: Đòi tiền bồi thường
Phạm vi: Công ty Bảo hiểm PCM
Actor chính: Người đòi bồi thường
Dòng chính
1. 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
2. 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ệ
3. 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
4. Đạ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. Công ty bảo hiểm trả tiền bảo hiểm
Dòng phụ
1a. Bằng chứng tai nạn không đầy đủ
1a1. Công ty bảo hiểm yêu cầu dữ liệu thiếu
1a2. Người đòi bồi thường gửi lại các dữ liệu thiếu
2a. Người đòi bồi thường không có chính sách bảo hiểm hợp lệ
2a1. Công ty bảo hiểm từ chối yêu cầu, nhắc nhở, ghi lại và kết thúc xử lý vụ việc
3a. Không có đại lý nào rảnh rỗi
3a1. (Công ty bảo hiểm sẽ làm gì trong trường hợp này???)
4a. Vụ tai nạn vi phạm chính sách bảo hiểm cơ bản
4a1. Công ty bảo hiểm từ chối yêu cầu, nhắc nhở, ghi lại và kết thúc xử lý vụ việc
4b. Vụ tai nạn chỉ vi phạm chính sách bảo hiểm 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
Trong trường hợp các use-case quá phức tạp và chưa được mô tả rõ ràng, chúng có thể
được tác 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
uc Use Case Model
«include»
Use Case Principal
Extend: use-case mới xảy ra khi một điều kiện xảy ra trong use-case chính.
17
uc Use Case Model
«extend»
Use Case Extend
Nói chung, use-case view giúp ta trả lời câu hỏi WHAT? về hệ thống.
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. 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. Đây là sự mô hình các khái niệm trong ứng dụng, các đặc điểm nội tại cũng như
mối quan hệ giữa chúng.
Attributes Operations
Object
Ví dụ về mô hình class:
18
cd Jav a Model
•••••••••••••••••••••••••• •••••••••••••••••••••••••• •••••••••••••••••••••••••• •••••••••
LineItem StockItem
Order
•••••••••••••••••••••••••• •••••••••••••••••••••••••• •••
- • Author:
• • • • string
•••••••••••••••••• •••••••••
- quantity: int
- date: Date - catalogNumber: string
• • • • • • • • • • • • • • •- • deliveryInstructions:
• • • • • • • • • • String
• • • • • • • • • • • •property
••••• •••••••••
get •••
-item - • costPrice:
• • • • • •number
•••••••••••••••• •••••••••
- orderNumber: String + getItem() : StockItem - listPrice: number
«enumeration» - • title:
• • • • • • • • • • • • • • •+ • checkForOutstandingOrders()
• • • • • • • • • • • • • • :•void
•• • • • • •+• •getQuantity()
••••••• : int
••••• ••• • • •string
••••••••••••••••••• •••••••••
OrderStatus property set
property get property get
enum + setItem(StockItem) : void
• • • • • • • • • • • • •-status
• •+ • getDate()
• • • • • :•Date
•••• ••••••• ••••••••••••••••••• •• •
+ • getAuthor()
• • • • • •: •string
••••••••• •••••• •••••••••
- closed: int + getDeliveryInstructions() : String + setQuantity(int) : void
+ getCatalogNumber() : string
- delivered: int
• •- • •dispatched: • • • • •+ • getLineItem()
• • • • • • int • • • • • • • :•LineItem
•• ••••••• ••••••••••••••••••• •• + • getCostPrice()
• • • • • • • • •: number
•••••••• •••••• •••••••••
+ getOrderNumber() : String + getListPrice() : number
- new: int + getStatus() : OrderStatus + getTitle() : string
• •- • •packed:
• • • • int
• • • • • • •property
• • • •set
••••••• ••••••• ••••••••••••••••••• •• •••••••••••••••••• •••••• •••••••••
property set
+ setDate(Date) : void + setAuthor(string) : void
• • • • • • • • • • • • • • •+ • setDeliveryInstructions(String)
• • • • • • • • • • • • • • :•void
•• ••••••••••••••••••• •• •
+ • setCatalogNumber(string)
• • • • • • • • • • • • • :•void
•• •••••• •••••••••
+ setLineItem(LineItem) : void + setCostPrice(number) : void
• • • • • • • • • • • • • • •+ • setOrderNumber(String)
•••••••••• •• : void
••••• ••••••••••••••••••• •• •
+ • setListPrice(number)
• • • • • • • • • • •: • ••••
void •••••• •••••••••
+ setStatus(OrderStatus) : void + setTitle(string) : void
• • • • • • • • • • • • • •-account
•••••••••••• •••••••••••••••••••••••••• •••••••••••••••••••••••••• •••••••••
Account ShoppingBasket
•••••••••••••••••••••• • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • Transaction •••••••••••••••• ••••••••• •••••••••
- billingAddress: String - shoppingBasketNumber: String
- closed: boolean - date: Date
• • -• •deliveryAddress:
• • • • • • • • •String
••••••••• • • • • + •addLineItem()
• • • • • • •: •void
• • • • • • • • • • • • • -• •orderNumber:
• • • • • • String
••••••••••••• ••••••••• •••••••••
- emailAddress: String -basket + createNewBasket() : void
+ loadAccountHistory() : void
• • -• •name:
• • • •String
•••••••••••••• • • • • + •deleteItem()
• • • • • •: •void
• • • • • • • • • • • • • • +• •loadOpenOrders()
• • • • • • • • :•void
•••••••••• ••••••••• •••••••••
+ processOrder() : void
+ createNewAccount() : void property get
property get
• • +• •loadAccountDetails()
• • • • • • • • • • •: void
•••••• • • • • • • • • • • • • • • • • • • • • • • • • • • • +• •getAccount()
•• •••• •••••••••••••
: Account ••••••••• •••••••••
+ getLineItem() : LineItem
+ markAccountClosed() : void + getDate() : Date
property set
• • +• •retrieveAccountDetails()
• • • • • • • • • • • • :•void
•••• • • • • • + •setLineItem(LineItem) • • • • • • • • • • +• •getLineItem()
• • • • • • • • • • •: void • • • • • •: LineItem
••••••••••••• ••••••••• •••••••••
+ submitNewAccountDetails() : void + getOrderNumber() : String
+ validateUser(String, String) property set
• •••••••••••••••••••• • •••• •••••••••••••••••••••••••• ••••••••••••••••• ••••••••• •••••••••
property get -account -history
+ setAccount(Account) : void
+ getBasket() : ShoppingBasket + setDate(Date) : void
• •••••••••••••••••••• • • • • • • • • • • • • • • • • • • • • • • • • • • • +• •setLineItem(LineItem)
• • • • • • • • • •: void
••••••••• ••••••••• •••••••••
+ getBillingAddress() : String
+ getClosed() : boolean + setOrderNumber(String) : void
• • +• •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
•••••••• ••••• •••••••••••••••••••••••••• •••••••••••••••••••••••••• •••••••••
State machine:
•••••••••••••••••••••••••• •••••••••••••••••••••••••• •••••••••••••••••••••••••• •••••••••
19
Đâ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.
20
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 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
••••••• • • • • • • •C
• • • • • • • • • • • • • •M••••• •••••
•••••••••••••••••••••••••• • • • • • • • • DangKyKhachHang()
•••••••••••••••••• •••••
••MuaHang
• • • sd ••••••••••••••••••• •• •• •• •• •• •• •• •• •
• •• ••V
•• • •• •• •• • •••••••••••••••••C
•••• •• •• •• •• •• •• •• •• •• •• •• • •• •• •• •• •
M
• • • ••••••••••••••••••••• •• •• •• •• •• •• •• •• •
• •• •• •• • •• •• •• • ••••••••••••••••••••• •• •• •• •• •• •• •• •• •• •• •• • •• •• •• •• •
Khach Hang TrangChu TrangDanhMucSanPham SanPhamUtilities SanPhamTable
• • • ••••••••••••••••••••• •• •• •• •• •• •• •• •• •
• •• •• •• • •• •• •• • ••••••••••••••••••••• •• •• •• •• •• •• •• •• •• •• •• • •• •• •• •• •
Chon xem san pham theo hang
• • • ••••••••••••••••••••• •• •• •• •• •• •• •• •• •
• •• •• •• • •• •• •• • ••••••••••••••••••••• •• •• •• •• •• •• •• •• •• •• •• • •• •• •• •• •
Redirect
• • • ••••••••••••••••••••• •• •• •• •• •• • • • • • • •• • •• •• •• •LayDanhSachSanPham
••••••••••••••••••••• •• •• •• •• •• • • • • • • • •• •• •• •• •
• • • ••••••••••••••••••••• •• •• •• •• •• • • • • • • •• • •• •• •• • ••••••••••••••••••••• •• •• •• •• •• • • • • • • • •• •• •• •• •
• • • ••••••••••••••••••••• •• •• •• •• •• • • • • • • •• • •• •• •• • ••••••••••••••••••••• •• •• •• •• •• • • • • • • • •• •• •• •• •
HienThi
• • • ••••••••••••••••••••• •• •• •• •• •• • • • • • • •• • •• •• •• • ••••••••••••••••••••• •• •• •• •• •• • • • • • • • •• •• •• •• •
• • • ••••••••••••••••••••• •• •• •• •• •• •• •• •• •
• •• •• •• • •• •• •• • ••••••••••••••••••••• •• •• •• •• •• •• •• •• •• •• •• • •• •• •• •• •
• • • ••••••Các•••••class
••••••trong
•••• ••hệ•• •thống
• •• •• ••được
•• •• ••chia
•• •• thành
•• • •• •ba
• ••loại
• •••tách
•••••biệt:
•••••M• •••(Model)
•••• •• •• –•• V
• •• •• •• ••– ••C•• • •• •• •• •• •
• ••(View)
(Control). 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, 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.
•• •(Deployment
• •• •• •• •• •• •• •• •• •• •• •• • •• •• •• • ••••••••••••••••••••• •• •• •• •• •• •• •• •• •• •• •• • •• •• •• •• •
Sơ đồ triển khai Diagram):
•••••••••••••••••••••••••• •••••••••••••••••••••••••• •••••
•••••••••••••••••••••••••• ••••••••••••••••••••••••••
•••••••••••••••••••••••••• •••••••••••••••••••••••••• •••••
• • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • 21
•••••••
•••••••••••••••••••••••••• •••••••••••••••••••••••••• •••••
•••••••••••••••••••••••••• ••••••••••••••••••••••••••
III.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. 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.
22
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.
Xuất phát từ ý tưởng ban đầu thuần túy mang tính nghiệp vụ, 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.
Sau đó xây dựng mô hình class ở mức phác thảo, sơ đồ trạng thái và sơ đồ hành động. Đế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. Đâ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 đủ.
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 cac mô hình đã hoàn tất. Trong quá trình xây dựng các
mô hình cần liên tục tiếp xúc với khách hàng để đảm bảo tính chính xác của mô hình. Một khi
các mô hình và tài liệu đặc tả đã hoàn chỉnh, việc coding thực sự chỉ chiếm khoảng 20% tổng số
thời gian.
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:
IV. Quy trình Rational Unified Process (RUP) phát triển phần mềm dựa trên UML
23
4- Thể hiện kết quả theo quy trình lặp (Demonstrate value iteratively). Kết thúc mỗi quy
trình cần theo dõi kết quả và kiểm tra chặt chẽ.
5- Nâng cao mức độ trừu tượng (Elevate the level of abstraction)
6- Tập trung theo dõi chất lượng liên tục (Focus continuously on quality)
IV.3. 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, có 4 pha: Inception, Elaboration, Construction và
Transition.
Biểu đồ trên cho biết trình tự các pha và lượng tài nguyên sử dụng cho mỗi pha.
Inception: Đây là giai đoạn chuẩn bị, tiếp xúc với khách hàng để nắm bắt ý tưởng
và thu thập yêu cầu, chuẩn bị nhân lực, vật tư kỹ thuật.
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, các quy trình nghiệp vụ của
ứng dụng,…
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ác công việc như thiết kế chi tiết, cài đặt, kiểm thử,…đều được tiến
hành trong pha này.
Transition: Pha chuyển giao cho khách hàng.
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.
24
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ụ.
Xác định yêu cầu (requirement): mô tả nghiệp vụ bằng phương pháp “tình huống
sử dụng” (use case base method)
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ế.
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.
Thử nghiệm (Test): mô tả các tình huống và kịch bản thử nghiệm, tiến hành thử
nghiệm hệ thống phần mềm.
Triển khai (Deployment): đưa hệ thống phần mềm vào sử dụng.
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.
Quản trị dự án: quản lý toàn bộ quá trình làm việc của dự án.
Đảm bảo môi trường: đảm bảo các hạ tầng cần thiết để có thể phát triển được hệ
thống.
25
Phần mềm Rational Rose: cho phép xây dựng các mô hình phân tích, thiết kế, triển
khai.
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.
Phần mềm Rational Clear Case: quản trị dự án phân tích thiết kế, cho phép làm
việc theo nhóm.
Bài tập
1. 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.
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”.
2. 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.
26
Đề tài 2. Nhập môn Java
I. Viết và thực hiện một chương trình Java
27
Lệnh này sẽ thông dịch file mã bytecode Vidu.class và in ra màn hình dòng chữ “Hello,
World!”.
Ở đây, ta cần chú ý Windows không tự động hiểu các lệnh javac, java. Tuy nhiên, 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.6.0_02\bin
Trường hợp chưa đặt đường dẫn mặc định, ta phải gọi các lệnh này với đường dẫn đầy đủ
của nó.
28
Cú pháp: package <tên gói>.
Khai báo này là không bắt buộc với một chương trình Java. 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. Trong chương
trình trên, class Vidu sau khi biên dịch sẽ được đặt trong gói my.java. Tên của gói có chứa các
dấu “.” chỉ sự bao gồm, ở đây gói “java” nằm trong gói “my” và class Vidu nằm trong gói “java”.
Khi một chương trình Java khác muốn truy cập tới lớp Vidu, nó cần truy cập theo đường dẫn gói
“my.java.Vidu”.
Thực ra, ý 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. Trong hàng ngàn class được Java hỗ
trợ trong các gói thư việ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 ý. Nếu không làm như vậy, chúng ta sẽ rất khó khăn để tìm ra một class để sử
dụng.
2. Nhập thư viện.
Cú pháp: import <tên thư viện>
Nếu có khai báo này, 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. Java dùng ký từ “*” để ngụ ý việc nhập tất cả
các class trong <tên thư viện>. Ví dụ:
import my.java.Vidu; // Nhập duy nhất class Vidu trong gói my.java
import my.java.*; // Nhập tất cả các class có trong gói my.java, tất nhiên là bao gồm cả
class Vidu.
Sau đây là một chương trình ví dụ sử dụng import:
import java.util.Date; //Khai báo thư viện
/*Chương trình in ra ngày tháng hiện hành*/
public class Application {
public static void main(String[] args) {
Date date = new Date(); //tạo biến đối tượng thuộc class Date
System.out.println(“Hôm nay "+date);
}
}
Ở đây, class Date đã được khai báo import nên không cần khai báo đầy đủ
“java.util.Date” tại dòng số 5.
3. Khai báo class, thuộc tính, 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”.
4. Khai báo hàm main: Không phải tất cả các class trong Java đều chứa hàm main. Chỉ có
class được gọi thực thi đầu tiên mới cần chứa hàm main.
5. 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. 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.
Trong số 5 phần trên, tất cả các class đều có phần 3, các phần còn lại có thể có hoặc
không tùy theo nhu cầu.
29
int 4 bytes Từ –2,147,483,648 đến 2,147,483, 647
float
30
III. Khai báo biến và hằng trong Java
31
long 0L;
float 0.0f;
double 0.0d;
char null;
boolean false;
Các biến dẫn suất null
32
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;
33
„\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”.
{ 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.
34
% Lấy phần dư 10%3 = 1
++ tăng giá trị lên 1 x++
-- giảm giá trị đi 1 x--
+= cộng kết hợp phép gán x+=y tương đương x=x+y
-= trừ kết hợp phép gán x-=y tương đương x=x-y
*= nhân kết hợp phép gán x*=y tương đương x=x*y
/= chia kết hợp phép gán x/=y tương đương x=x/y
^ phép XOR trên bit x^y
| phép OR trên bit x|y
& 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
Thứ tự ưu tiên:
( ), *, /, %, +, -,= =, !=, &, ^, |, &&, ||, =, %=, /=, *=, -=, +=
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>
{
<khối lệnh>;
35
}
Nếu biểu thức boolean đúng, khối lệnh sẽ được thực hiện, còn nếu biểu thức đó sai thì
khối lệnh sẽ bị bỏ qua.
Ví dụ:
public class dkIfThen {
public static void main(String[] args) {
int x=1;
int y=x+1;
if (x<y) {
System.out.println("x>y");
} }}
36
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, các lệnh tiếp theo sẽ được thực hiện.
true
Thực hiện khối lệnh
37
}//kết quả là: 4.2
Các vòng for có thể được đặt lồng nhau nếu cần
Ví dụ:
for(int i=0; i<10; i++) {
[các câu lệnh; ]
for(int j=0; j<5; j++) {
[các câu lệnh; ]
...
}
[các câu lệnh; ]
}
Bt false
boolean
true
38
Cấu trúc lệnh:
do {
<khối lệnh>;
} while <biểu thức boolean>;
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>. Nếu <biểu
thức boolean> có giá trị true thì tiếp tục thực hiện <khối lệnh>, nếu không sẽ dừng vòng lặp.
Ví dụ tính tổng 10 số đầu tiên:
public class vdDoWhile {
public static void main(String[] args) {
int x=1, sum=0;
do{
sum+=x;
x++;
}
while (x<11);
System.out.println(sum);
}
} //kết quả là: 55
39
{
……..
continue;
}
lệnh 3;
}
lệnh 4;
Khi <bt boolean 2> có giá trị true, lệnh continue được thực hiện, 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>.
40
VII.2 Kết xuất dữ liệu ra màn hình
Trong các chương trình ví dụ trên, ta đã biết dùng hàm System.out.print để in dữ liệu ra
màn hình. Tuy nhiê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.
System.out.printf(“%8.1f”, 10/3);
System.out.printf(“Hello, %s. You have %f VND ”, name,money);
Sau đây là bảng các ký tự định dạng:
Ký tự định dạng Định dạng Ví dụ
D Số nguyên thập phân 159
X Số nguyên hệ 16 9f
O Số nguyên hệ 8 237
F Số thực float 15.9
E Số thực float theo ký pháp cơ số e 1.59e+01
A Số thực float dạng Hexa 0x1.fccdp3
S String Hello
C Ký tự H
B Boolean True
H Hash code 42628b2
tx Date and time
% Ký hiệu phần trăm %
N Xuống dòng
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.
public class TestFormat
{
public static void main(String[] argvs)
{
double sothuc = 10.09898765;
/*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.out.printf("Ket qua 3 so sau dau phay la %10.3f \n",sothuc);
int songuyen =100;
/*In ra số nguyên ở hệ cơ số 16*/
System.out.printf("He 16 cua 100 duoc viet la: %x \n",songuyen);
/*In ra số nguyên ở hệ cơ số 8*/
System.out.printf("He 8 cua 100 duoc viet la: %o \n",songuyen);
/*In ra ký tự đặc biệt “” */
System.out.print("\"Mot tram phan tram\" thi in ra the nao: 100%");
}}
41
Lưu ý rằng khi sử dụng các ký tự định dạng ta cần dùng hàm System.out.printf() thay vì
System.out.print() hay System.out.println() như thường lệ.
Bài tập
1. Viết chương trình tính giá trị các biểu thức (Giá trị n, k,…nhập từ bàn phím):
A = 1 + 1/2! + 1/3! + … + 1/n!
B = 1/1! – 1/2! + 1/3! - 1/4! + … + 1/(2k+1)! - ….
2. Viết chương trình đếm số từ có trong một chuỗi ký tự nhập vào. Các từ cách nhau bởi
dấu space,. và ;
3. 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.
4. Nhập vào một chuỗi họ tên của một người, 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ừ. Ví dụ: nguyen van nam -> Nguyen Van Nam
5. Tìm các lỗi trong các đoạn chương trình sau:
a)
For ( x = 100, x >= 1, x++ )
System.out.println( x );
b) Đoạn mã sau sẽ in ra các giá trị chẵn hay lẻ:
switch ( value % 2 ) {
case 0:
System.out.println( "Even integer" );
case 1:
System.out.println( "Odd integer" );
}
c) Đoạn mã sau sẽ in ra các số nguyên lẻ từ 19 đến 1 ?:
for ( x = 19; x >= 1; x += 2 )
System.out.println( x );
d) Đoạn mã sau sẽ in ra các số nguyên chẵn từ 2 đến 100 ?:
counter = 2;
do {
System.out.println( counter );
counter += 2;
} While ( counter < 100 );
42
8. Viết chương trình in ra màn hình các mẫu như sau:
43
Đề tài 3. Lập trình hướng đối tượng trong Java
I. Khái niệm lập trình hướng đối tượng (Object-Oriented Programming - OOP)
44
Giả sử đối tượng quản lý là một sinh viên. 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, ngày sinh, lớp học, địa chỉ nơi ở, điểm các môn học. Trong khi đó, các
thông tin khác về sinh viên – cũng là một con người – như chiều cao, cân nặng, nhóm
máu,…chúng ta không cần quan tâm. 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. Ở đây ta không quan tâm tới giá trị cụ thể của các thuộc tính này.
Khi quan tâm tới giá trị của các thuộc tính, 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. Trong ví dụ trên, 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”, “địa chỉ nơi ở” bị thay đổi. 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.
Tóm lại, 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ý), 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.
Qua đây, 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ũng là một sinh viên nhưng nếu chẳng may anh ta bị ốm nằm viện,
anh ta được quản lý như một bệnh nhân. 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, cân nặng, huyết áp,…và tất nhiên là cũng có các mô hình hành vi
khác.
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.
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.
45
II. Tính đóng gói trong Java
46
Đặ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ó.
IV. 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. 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.
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.sun.com/j2se/1.4.2/docs/api/overview-summary.html )
Các gói thường dùng trong Java 2 SE
Hỗ trợ các class cần thiết cho việc tạo ra các Applet và giao tiếp giữa
java.applet
Applet với môi trường ngữ cảnh của nó.
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
java.awt
vẽ các hình đồ họa và ảnh.
java.awt.color Cung cấp các lớp cho không gian màu.
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ý
java.awt.event
các sự kiện trên các thành phần giao diện AWT.
java.awt.font Hỗ trợ các giao diện và lớp liên quan đến font chữ.
java.awt.image Cung cấp các lớp tạo và hiệu chỉnh hình ảnh.
java.awt.print Cung cấp các lớp và giao diện cho mục đích in ấn.
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
java.beans
kiến trúc của Java.
java.io Hỗ trợ cho các thao tác vào / ra dữ liệu trên hệ thống file.
java.lang Cung cấp các lớp nền tảng để thiết kế ngôn ngữ lập trình Java.
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à
java.math
BigDecimal.
java.net Cung cấp các lớp cho việc cài đặt các ứng dụng mạng.
java.rmi Cung cấp các gói cho lập trình RMI – Remote Method Invocation.
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
java.security
trong Java.
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ữ
java.sql
liệu – thường là các CSDL quan hệ.
Cung cấp các lớp và giao diện cho việc quản lý text, dates, numbers và các
java.text
thông điệp.
Chứa đựng các lớp tiện ích thuộc nhiều loại khác nhau như sinh số ngẫu
java.util
nhiên, ngày tháng,….
javax.crypto Hỗ trợ các lớp và giao diện cho các thao tác mã hóa dữ liệu.
javax.net Cung cấp các lớp cho lập trình mạng.
javax.print Cung cấp các lớp cơ bản cho các dịch vụ in ấn qua mạng.
47
javax.sql Cung cấp các hàm API cho việc truy cập dữ liệu phía server.
Cung cấp một tập các thành phần được chấp nhận trên hầu hết các hệ thống
javax.swing
máy tính.
javax.swing.event Hỗ trợ cho các sự kiện kích hoạt bởi các thành phần của Swing.
javax.swing.table Cung cấp các lớp và giao diện làm việc với bảng.
javax.swing.tree Cung cấp các lớp và giao diện làm việc với cây javax.swing.JTree.
javax.xml.parsers Hỗ trợ các lớp cho việc xử lý các tài liệu XML.
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:
48
<tên giao diện>: Tên của giao diện được cài đặt tại lớp. Đây có thể là một danh sách các
giao diện phân tách bởi dấu “,”.
<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. Ta sẽ lần lượt xem xét tới các thành phần này.
49
public class TestThis
{
private int number = 10;
public void PrintNumber()
{ int number =20; // khai báo trùng với biến của lớp
System.out.println(number); //in bien number = 20
System.out.println(this.number);//in bien number =10
}
}
50
return num1;
else
return num2;
}
Về <mệnh đề throws> chúng ta sẽ xem xét kỹ trong phần xử lý ngoại lệ.
51
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.
// 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.MaSo=10;
// Khởi tạo một đối tượng sinh viên, MaSo của sinh viên này sẽ là 10
SinhVien k = new SinhVien(23,"Nguyen Thi Mai","Letio3",7.15);
System.out.print(k.MaSo);
52
SinhVien.MaSo=11;
// Khởi tạo một đối tượng sinh viên, MaSo của sinh viên này sẽ là 11
SinhVien k1 = new SinhVien(20,"Pham Anh Thu","Letio3",8.15);
System.out.print(k.toString());
People p = new People(20,"Pham Anh Hoa"); // Báo lỗi dòng này
}
}
Trong chương trình trên, 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. Chúng ta sẽ trở lại vấn đề này trong phần “Tính kế thừa”.
class Outer {
int outer_x = 100;
void test() {
Inner inner = new Inner();
inner.display_x();
}
class Inner { // có thể truy xuấ t trực tiế p biế n đố i tươ ̣ng của lớp Outer
int inner_y = 10;
void display_x() {
System.out.println(“display : outer_x = “ + outer_x);
53
}
}
void display_y() { // không thể truy xuất biến đối tượng của lớp Inner
System.out.println(“display : inner_y = “ + inner_y); // Error
}
}
class InnerClassDemo {
public static void main(String args[]) {
Outer outer = new Outer();
outer.test();
}
}
Trong Java có sử dụng một kỹ thuật cài đặt lớp nội nặc danh, tức là không có tên, khi xử
lý các sự kiện. Ví dụ:
frame.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent event)
{
System.exit(0);
}
public void windowIconified(WindowEvent e) {System.exit(0);}
} );
Ở đây, ta có một lớp nặc danh kế thừa từ lớp WindowAdapter. Nó được khai báo chồng 2
phương thức của WindowAdapter.
54
// Phương thức lấy họ tên
public String getHoVaTen()
{
return HoVaTen;
}
// Phương thức lấy lương
public double getLuong()
{
return Luong;
}
//phương thức lấy ngày bắt đầu làm việc
public Date getNgayBatDau()
{
return NgayBatDau;
}
// Phương thức tăng lương
public void raiseSalary(double PhanTram)
{
double PhanTang = Luong * PhanTram / 100;
Luong += PhanTang;
}
// Các thuộc tính thành phần
private String HoVaTen;
private double Luong;
private Date NgayBatDau;
}
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. Tuy nhiên, 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. Đây chính là ngữ
cảnh tốt để cài đặt tính kế thừa.
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.
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. Lớp đang tồn tại còn được gọi là lớp cha, supperclass, hoặc lớp cơ sở (base
class), lớp kế thừa còn được gọi là lớp dẫn xuất, lớp con. 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.
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
{
...
55
TienThuong = b;
}
private double TienThuong;
}
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. Nếu ta có một đối
tượng Manager có tên boss, ta có thể gọi:
boss.setTienThuong(10000);
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.
Tuy nhiên, chúng ta có thể sử dụng các phương thức getHoVaTen(), getLuong(),
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. Tương tự như thế, các thuộc tính HoVaTen, Luong và NgayBatDau cũng được kế
thừa. Lớp Manager có 4 thuộc tính là HoVaTen, Luong, NgayBatDau và TienThuong.
Đến đây ta có thể rút ra rằng khi thiết kế các lớp trong Java, ta đặt các thuộc tính và
phương thức phổ biến vào các lớp cha, 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.
Tuy nhiên, một số phương thức của lớp cha có thể không còn phù hợp ở lớp con. Ở đây,
phương thức getLuong() đối với lớp Manager phải là tổng của Luong và TienThuong. Do đó, 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
{
...
public double getLuong()
{
...
}
...
}
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; // Không thực hiện
}
Tuy nhiên nó không thực hiện. Lý do là vì sự truy cập vào Luong ở đây là không hợp lệ.
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. Theo lý thuyết, 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ý. 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.
public double getLuong()
{
double LuongCoBan = getLuong(); // vẫn không thực hiện
return LuongCoBan + TienThuong;
}
56
Tuy nhiên, đoạn mã này cũng chưa thực hiện được. 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.
Để gọi được phương thức getLuong() của lớp Employee, ta dùng từ khóa super để chỉ lớp
cha.
public double getLuong()
{
double LuongCoBan = super.getLuong(); // OK
return LuongCoBan + TienThuong;
}
Nếu không cho phép lớp con kế thừa một phương thức của lớp cha, ta dùng từ khóa final
khi khai báo phương thức.
57
VII. 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. Cho dùng là cùng một tên gọi, thậm chí là cùng danh sách tham số,
phương thức vẫn được gọi theo đúng đối tượng sở hữu nó.
Trong khi chúng ta cài đặt tính chất thừa kế của OOP, cơ sở của tính đa hình cũng đã
được cài đặt. Trong ví dụ trên, phương thức getLuong() được định nghĩa ở cả lớp cha và lớp con,
chúng ta sẽ xem nó được gọi như thế nào.
58
staff[0] = boss;
// Khởi tạo cho 2 đối tượng còn lại
staff[1] = new Employee("Nguyen Hai Nam", 50000, 1989, 10, 1);
staff[2] = new Employee("Pham Quyet Tan", 40000, 1990, 3, 15);
// Dùng vòng lặp để in ra tên và lương từng người
for (Employee e : staff)
System.out.println(e.getHoVaTen() + " " + e.getLuong());
Kết quả in ra là:
Phan Thanh Ha 85000.0
Nguyen Hai Nam 50000.0
Pham Quyet Tan 40000.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. Tuy nhiên đối tượng thứ 0 đã gọi phương thức getLuong() của
Manager. Mặt khác, nếu viết:
staff[0].setTienThuong(2000); thì không được phép khi biên dịch.
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). Đặc trưng thể hiện tính đa hình trong Java.
Để 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. 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, giả sử là
x.f(param). Trong đó x được khai báo là đối tượng của lớp C. 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ố, ví dụ f(int) và f(String). 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.
2. Tiếp theo, 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. 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. Ví dụ câu lệnh là x.f(“Chao ban”) thì hàm f(String) được gọi chứ không phải
f(int). Cơ chế này gọi là nạp chồng (overloading). 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, nó sẽ đưa ra thông báo lỗi.
Bây giờ, 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ố).
3. Nếu phương thức là private, static và final hoặc là một constructor, 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. Điều này gọi là ràng
buộc tĩnh (static binding). Ngược lại, phương thức được gọi tùy theo kiểu hiện tại của đối tượng,
giả sử kiểu hiện tại của x là D, 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). 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. Nếu lớp D không có, nó sẽ tìm lên các lớp cha của D
(trong đó có lớp C). Cơ chế này gọi là ràng buộc động.
59
obj = staff; // OK
obj = new int[10]; // OK
60
Trong interface ta đang xem xét thì nó chỉ có một phương thức. Các interface thường có
nhiều phương thứ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. 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.
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.
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, ta cài đặt compareTo như
sau:
public int compareTo(Object objKhac)
{
Employee other = (Employee) objKhac; // Chuyển kiểu
if (Luong < other.Luong) return -1;
if (Luong > other.Luong) return 1;
return 0;
}
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, nhất định ta phải có khai báo public.
Đối với phiên bản Java 5.0, ta có thể cài đặt:
class Employee implements Comparable<Employee>
{
public int compareTo(Employee objKhac)
{
if (Luong < objKhac.Luong) return -1;
if (Luong > objKhac.Luong) return 1;
return 0;
}
...
}
Đối với lớp Manager thì sao. 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. 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; // không được
...
}
...
}
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>. Khi đưa một đối tượng
Manager vào làm tham số so sánh, nó tự động được ép sang kiểu Employee. 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.
61
IX.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(. . .); // Lỗi
Có thể khai báo một biến interface
Comparable x; // 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 đó.
x = new Employee(. . .); // 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) { . . . }
Các interface cũng có thể được kế thừa
Có thể khai báo các hằng số trong interface
public interface Comparable<Employee>
{
double greater = 1;
int compareTo(Employee other);
}
Trong interface, khai báo “double greater =1” được tự động hiểu là:
public static final double greater =1;
Các lớp có cài đặt interface cũng tự động được thừa kế các hằng số này.
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.
X. Package
62
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.print(“Khong co ten lop System”);
Ta thường dùng phương pháp này với các hàm của class Math: sqrt(pow(x, 2) + pow(y,
2)).
Bài tập
1. Thực hành cài đặt các ví dụ trong đề tài trên.
2. Xây dựng các class trong java để cài đặt các lớp đối tượng: Khách hàng, sản phẩm, hóa
đơn, giỏ hàng trong một hệ thống quản lý bán hàng ở siêu thị.
3. Trong hệ thống đồ họa:
a. Hãy xây dựng các class điểm, đoạn thẳng, hình vuông, đa giác, tứ giác, hình chữ nhật,
tam giác, hình thoi.
b. Hãy cho biết một thứ tự phân cấp kế thừa của các lớp này.
c. 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.
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.
4. Xây dựng một lớp PhuongTrinhBac1 để giải phương trình bậc 1.
5. 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.
5. 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, PhuongTrinhBac2 có cài đặt giao diện
này.
6. 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ố, Tên lớp, Khóa học, danh sách lớp và các phương thức như: Thêm sinh viên, Xóa
Sinh viên, Sắp xếp danh sách, Xem danh sách, thống kê học tập, thống kê giới tính. 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, Tuổi, Giới tính,
Đ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ì). Các đối tượng sinh viên được so sánh theo tiêu chí điểm tổng kết.
63
Đề tài 4. Lớp và phương thức trừu tượng
I. 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.
Các con hổ là động vật bốn chân sống trong các khu rừng.
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, một khái niệm chung cần được làm rõ là “động vật bốn chân”.
Để cho các định nghĩa này thêm sáng tỏ, 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.
Đế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.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ỏ, động vật ăn thịt, động vật bò sát,….
Trong lập trình cũng vậy, 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. 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.)
II. 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. Ví dụ:
abstract class People
{
private int NamSinh;
private String HoTen;
public People(int ns, String ht)
{
NamSinh= ns;
HoTen = ht;
}
public String getHoTen()
{
return HoTen;
}
abstract String toString();
}
Ta thấy rằng một lớp trừu tượng thực sự là một lớp với đầy đủ các thành phần, không
giống như interface.
Giả sử trong chương trình có các đối tượng SinhVien, GiaoVien. Các đối tượng này đều
có một phương thức toString để trả về một chuỗi bao gồm toàn bộ thông tin về chúng. Đây là tình
huống sử dụng phương thức trừu tượng một cách hiệu quả.
abstract String toString();
Chú ý là các phương thức trừu tượng không có phần thân.
Lớp SinhVien kế thừa từ People được cài đặt như sau:
64
public class SinhVien extends People
{
private String Lop;
private double DiemTongKet;
// Phương thức khởi tạo
public SinhVien(int ns,String ht,String l,double dtk)
{
//Dùng phương thức khởi tạo của lớp cha
super(ns,ht);
Lop = l;
DiemTongKet=dtk;
}
// Cài đặt phương thức toString
public String toString()
{
return String.valueOf(NamSinh) + String.valueOf(DiemTongKet) + HoTen;
}
}
Khi một phương thức được khai báo là abstract thì lớp chứa nó cũng phải là một lớp
abstract. Khi sử dụng phương thức abstract cho một lớp thì nhất thiết phải có một lớp khác kế
thừa và khai báo cài đặt chồng thì mới có tác dụng. Khi kế thừa một lớp có chứa phương thức
trừu tượng thì phương thức đó bắt buộc phải được cài đặt.
Bài tập
1. 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. 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, tiền điều trị, 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. Sau đó xây dựng hai lớp BenhNhanNoiTru và
BenhNhanNgoaiTru kế thừa lớp BenhNhan. (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ế).
3. Một nhà máy sử 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, Toyota, Mishubishi, Mercedec, Ford, Kia. Mỗi hãng ô tô lại có nhiều kiểu
khác nhau như 2 chỗ, 4 chỗ, 7 chỗ, 12 chỗ và 24 chỗ. Ngoài ra, nhà máy còn nhận bảo dưỡng cho
các loại xe mô tô tay ga và xe số. 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.
a. 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.
b. 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.
c. 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.
65
Đề tài 5. 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.util dùng
cho việc lưu trữ và xử lý các đối tượng.
66
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í.
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.
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ị.
Dòng 14: Phương thức trả về kích thước thực tế của Vector, tức là số phần tử thực sự
Vector lưu trữ (=10) .
Dòng 15: Kích số lượng các phần tử tối đa hiện có của Vector (=11).
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.
removeAllElements(): Xóa tất cả các phần tử.
firstElement(): Trả về tham chiếu tới phần tử đầu tiên.
lastElement(): Trả về tham chiếu tới phần tử cuối cùng trong Vector.
isEmpty(): Xác định liệu Vector là trống.
contains(key): để kiểm tra xem trong vector có phần tử so khớp với key hay không. Đối
tượng key và các phần tử của Vector đươck so sánh với nhau bởi phương thức equals(). 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.
indexOf(Object): Trả về chỉ số của đối tượng đầu tiên so khớp với Object.
trimToSize(): Giảm số lượng phần tử của Vector.
67
private String Lop;// Ten lop
private double DiemTongKet; // Diem tong ket
public final String mauda ="vang";//Hang so
private int ID;// Ma so SinhVien
protected static int MaSo;// ma so chung de cap phat cho moi sinh vien
// constructor
public SinhVien(int ns,String ht,String l,double dtk)
{
super(ns,ht);//goi constructor cua lop cha la People
Lop = l;
DiemTongKet=dtk;
// Id cua SinhVien duoc gan bang gia tri MaSo hien thoi cua lop
ID=MaSo;
// Tang ma so len 1 den gan cho SinhVien sau
MaSo+=1;
}
// Phuong thuc tinh tuoi
protected int TinhTuoi()
{
java.util.Date homnay = new java.util.Date();
return (homnay.getYear() - NamSinh +1);
}
// Khai bao chong phuong thuc toString()
public String toString()
{
return "Ma so:" + String.valueOf(ID)+ "\n"
+"Tuoi:"+ String.valueOf(this.TinhTuoi()) + "\n"
+"Diem Tong Ket:"+ String.valueOf(DiemTongKet)+"\n"
+"Ho va ten:"+ HoVaTen;
}
// Ham main
public static void main(String[] argv)
{
// Dat gia tr? bien static, sinh vien dau tien co ma so 1
SinhVien.MaSo=1;
// bien doi tuong Vector
java.util.Vector sv = new java.util.Vector(5);
SinhVien k1 = new SinhVien(80,"Nguyen Thi Mai 1","Letio3",5);
sv.addElement(k1); // Them sinh vien vao Vector
SinhVien k2 = new SinhVien(81,"Tran Thi Mai 2","Letio3",6);
sv.addElement(k2);
SinhVien k3 = new SinhVien(82,"Pham Thi Mai 3","Letio3",7);
sv.addElement(k3);
SinhVien k4= new SinhVien(83,"Phan Thi Mai 4","Letio3",8);
sv.addElement(k4);
SinhVien k5= new SinhVien(84,"Hoang Thi Mai 5","Letio3",9);
sv.addElement(k5);
68
// Dung interface Enumeration de duyet cac phan tu cua Vector
java.util.Enumeration enu = sv.elements();
while (enu.hasMoreElements())
{
// Ep kieu, kieu Object la kieu cha cua moi kieu nen luon ep duoc
SinhVien g = (SinhVien)enu.nextElement();
System.out.println(g.toString());
}
//People p = new People(20,"Pham Anh Hoa"); bao loi vi People là lớp trừu
tượng
}
}
69
{
// Khai báo một mảng các câu trả lời
int TraLoi[] = { 1, 2, 6, 4, 8, 5, 9, 7, 8, 10, 1, 6, 3, 8, 6, 10, 3, 8, 2, 7, 6, 5, 7, 6, 8, 6, 7, 5,
6, 6, 5, 6, 7, 5, 6, 4, 8, 6, 8, 10 };
// Mảng đếm tần suất
int TanSuat[] = new int[ 11 ];
// Với mỗi phần tử của mang TraLoi, 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, lưu giá trị vào mảng TanSuat tại vị trí tương ứng.
for ( int answer = 0; answer < TraLoi.length; answer++ )
++frequency[ TraLoi[ answer ] ];
// Đưa kết quả vào một chuỗi
for ( int rating = 1; rating < TanSuat.length; rating++ )
output += rating + "\t" + TanSuat[ rating ] + "\n";
// In ra
System.out.print(out);
}}
Trong ví dụ này, 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. Chỉ cần duyệt mảng TraLoi 1 lần
ta đã có ngay kết quả.
70
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. Ta
gọi phương pháp này là tìm kiếm tuyến tính.
Đối với các mảng đã được sắp xếp, ta có một phương pháp tìm kiếm hiệu quả hơn, gọi là
tìm kiếm nhị phân.
Giả sử ta có một mảng: int[] b={1,5,7,8,34,56,67,89,100};
Đã được sắp xếp tăng dần.
Giả sử ta cần tìm vị trí của một phần tử có giá trị 7. Trước tiên, 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. Tiếp
tục làm việc này với nửa trước của mảng, 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,8. Lần phân đôi cuối cùng này cho ta kết quả.
Thủ tục này được cài đặt như sau:
public int binarySearch( int array2[], int key )
{
int low = 0; // Chỉ số dưới
int high = array.length - 1; // Chỉ số trên
int 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;
// 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;
// Nếu khóa nhở hơn phần tử giữa, đặt lại chỉ số trên
else if ( key < array[ middle ] )
high = middle - 1;
// Khóa lớn hơn phần tử giữa, đặt lại chỉ số dưới
else
low = middle + 1;
}
return -1; // Không tìm thấy
}
71
equals: So sánh mảng
Sau đây là ví dụ về sử dụng lớp Arrays:
import java.util.*;
public class UsingArrays {
private int intValues[] = { 1, 2, 3, 4, 5, 6 };
private double doubleValues[] = { 8.4, 9.3, 0.2, 7.9, 3.4 };
private int filledInt[], intValuesCopy[];
System.out.println();
}
72
{
return Arrays.binarySearch( intValues, value );
}
// So sánh nội dung mảng
public void printEquality()
{
boolean b = Arrays.equals( intValues, intValuesCopy );
System.out.println( "intValues " + ( b ? "==" : "!=" ) + " intValuesCopy" );
b = Arrays.equals( intValues, filledInt );
System.out.println( "intValues " + ( b ? "==" : "!=" ) + " filledInt" );
}
// Hàm main
public static void main( String args[] )
{
UsingArrays usingArrays = new UsingArrays();
usingArrays.printArrays();
usingArrays.printEquality();
int location = usingArrays.searchForInt( 5 );
System.out.println( ( location >= 0 ? "Tìm thấy 5 tại vị trí " + location : "Không thấy" ) +
" trong mảng intValues" );
location = usingArrays.searchForInt( 8763 );
System.out.println( ( location >= 0 ? "Tìm thấy 8763 tại " + location : "Không thấy 8763"
) + " trong mảng intValues" );
}}
73
for ( int count = 0; count < colors.length; count++ )
list.add( colors[ count ] );
list.add( Color.cyan ); // Thêm một đối tượng Color
// In ra nội dung
System.out.println( "\nArrayList: " );
for ( int count = 0; count < list.size(); count++ )
System.out.print( list.get( count ) + " " );
// Xóa tất cảcác đối tượng String
removeStrings( list );
// output list contents
System.out.println( "\n\nArrayList sau khi gọi removeStrings: " );
for ( int count = 0; count < list.size(); count++ )
System.out.print( list.get( count ) + " " );
}
public void removeStrings( Collection collection )
{
// Khai báo đối tượng iterator
iterator iterator = collection.iterator();
// Lặp trong khi tập hợp vẫn còn phần tử
while ( iterator.hasNext() )
if ( iterator.next() instanceof String )
iterator.remove(); // Xóa phần tử
}
// Hàm main
public static void main( String args[] )
{
new CollectionTest();
}
}
Bài tập
1. 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ìm kiếm sinh viên
- Thêm sinh viên.
- Xóa sinh viên
- Sắp xếp danh sách theo tên
2. Viết chương trình nhập vào n số nguyên và số thực, n nhập từ bàn phím. Sau đó:
- Tính tổng của n số này.
- Sắp xếp n số theo thứ tự tăng dần
- 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.
74
Đề tài 6. 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.
75
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:
76
III. 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. Nó cung cấp một tập các
phương thức trợ giúp tạo ra, ghi và xử lý kết xuất các dòng. Các phương thức bao gồm:
write(int): Phương thức này ghi một byte.
write(byte[]): Phương thức này phong toả cho đến khi một byte được ghi. Dòng
phải chờ cho đến khi tác vụ ghi hoàn tất. Nó gây ra ngoại lệ IOException nếu lỗi
xảy ra.
write(byte[], int, int): Phương thức này ghi mảng các byte. 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ẻ, một
mảng các byte, hay một đoạn của một mảng byte.
flush(): Phương thức này xả sạch dòng. Đệm dữ liệu được ghi ra dòng. Nó kích
hoạt IOException nếu lỗi xảy ra.
close(): Phương thức đóng dòng. Nó được dùng để giải phóng mọi tài nguyên gắn
với dòng. Nó kích hoạt IOException nếu lỗi xảy ra.
V. Lớp FileOutputStream
Lớp này cung cấp khả năng ghi dữ liệu xuống tập tin, được dẫn xuất từ lớp cha
OutputStream.
Có 3 phương thức khởi tạo:
FileOutputStream(String name);
FileOutputStream(File f);
FileOutputStream(FileDescriptor fdObj)
77
hoặc
File f = new File("C:\jdk1.4\bin", "hello.java");
hoặc
File curDir = new File(".");
File f = new File(curDir, "Hello.java");
Các phương thức:
public String getName(): lấy tên đối tượng tập tin.
public String gePath(): lấy đường dẫn của tập tin.
public String getAbsolutePath(): lấy đường dẫn tuyệt đối của tập tin.
public String getParent(): lấy tên thư mục cha.
public Boolean createNewFile(): tạo một tập tin mới.
public void createTempFile(String pattern, File dir): tạo tập tin tạm thời.
public void deleteOnExit(): yêu cầu xoá tập tin khi chương trình chấm dứt.
public boolean canWrite(): cho biết tin có cho phép ghi hay không (true nếu có).
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.
public boolean isFile(): cho biết tệp tin có hợp lệ hay không (true nếu có).
public boolean isDirectory(): cho biết tập tin có phải thư mục hay không (true nếu
có).
public boolean isHidden(): kiểm tra xem tập tin có ẩn hay không (true nếu có).
public long length(): cho biết kích thước tập tin (byte).
public boolean mkdir(): tạo một thư mục từ đối tượng file, true nếu thành công.
renameTo(File dest): đổi tên tập tin hiện tại sang tên mới.
public String[ ] list(): lấy danh sách các tập tin và thư mục.
public String[ ] list(FilenameFilter filter): lấy danh sách tập tin thoả mãn điều kiện
lọc, ví dụ *.gif.
public booean delete(): xoá tập tin, true nếu xoá thành công.
public String toString(): trả về đường dẫn của tập tin.
public String toURL(): trả về đối tượng URL tương ứng với tập tin.
Chương trình ví dụ:
public class Test
{
public static void main(String args[])
{
File f = new File("test");
System.out.println(f.getAbsolutePath()); // Lấy đường dẫn tuyệt đối
System.out.println(f.exists()); // Kiểm tra sự tồn tại
}
}
78
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.
79
DiemTongKet=dtk;
// Id cua SinhVien duoc gan bang gia tri MaSo hien thoi cua lop
ID=MaSo;
// Tang ma so len 1 den gan cho SinhVien sau
MaSo+=1;
}
// Phuong thuc tinh tuoi
protected int TinhTuoi()
{
java.util.Date homnay = new java.util.Date();
return (homnay.getYear() - NamSinh +1);
}
// Khai bao chong phuong thuc toString()
public String toString()
{
return String.valueOf(ID)+ "|"
+ String.valueOf(this.TinhTuoi()) + "|"
+ String.valueOf(DiemTongKet)+"|"
+ HoVaTen;
}
// Ghi thông tin sinh viên vào file
public void GhiData(PrintWriter out) throws IOException
{
out.println(this.toString());
}
// Đọc thông tin 1 sinh viên từ bộ đệm đọc
public void DocData(BufferedReader in) throws IOException
{
String s = in.readLine(); // Đọc một dòng trong bộ đệm
StringTokenizer t = new StringTokenizer(s, "|");
MaSo = Integer.parseInt(t.nextToken());
NamSinh = Integer.parseInt(t.nextToken());
DiemTongKet = Double.parseDouble(t.nextToken());
HoVaTen = t.nextToken();
}
// Ham main
public static void main(String[] argv)
{
// Dat gia trị bien static, sinh vien dau tien co ma so 1
SinhVien.MaSo=1;
// bien doi tuong Vector lưu các sinh viên
java.util.Vector sv = new java.util.Vector(5);
SinhVien k1 = new SinhVien(80,"Nguyen Thi Mai 1","Letio3",5);
sv.addElement(k1); // Them sinh vien vao Vector
SinhVien k2 = new SinhVien(81,"Tran Thi Mai 2","Letio3",6);
sv.addElement(k2);
80
SinhVien k3 = new SinhVien(82,"Pham Thi Mai 3","Letio3",7);
sv.addElement(k3);
SinhVien k4= new SinhVien(83,"Phan Thi Mai 4","Letio3",8);
sv.addElement(k4);
SinhVien k5= new SinhVien(84,"Hoang Thi Mai 5","Letio3",9);
sv.addElement(k5);
// Dung interface Enumeration de duyet cac phan tu cua Vector
java.util.Enumeration enu = sv.elements();
try
{
PrintWriter out = new PrintWriter(new FileWriter("C:\\LETI\\JAVA\\Sinhvien.dat"));
while (enu.hasMoreElements())
{
// Ep kieu, kieu Object la kieu cha cua moi kieu nen luon ep duoc
SinhVien g = (SinhVien)enu.nextElement();
g.GhiData(out);
}
out.close();
} catch(Exception ep) {}
// Doc tu file ra
SinhVien[] svs = new SinhVien[5];
try
{
BufferedReader in = new BufferedReader(new
FileReader("C:\\LETI\\JAVA\\Sinhvien.dat"));
for(int i=0;i<svs.length;i++)
{
svs[i] = new SinhVien(0,"","",0.0);
svs[i].DocData(in);
}
}
catch(IOException ep)
{}
for(int i=0;i<svs.length;i++)
System.out.println(svs[i].toString());
}}
81
RandomAccessFile(File f, String mode);
Trong đó mode là chế độ mở tập tin:
mode = "r" - chế độ chỉ đọc.
mode = "rw" - chế độ ghi và đọc.
Ví dụ:
RandomAccessFile file = new RandomAccessFile(“C:\\LETI\\JAVA\\Account.txt”, "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.
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.
getFilePointer( ): Trả về vị trí hiện hành của con trỏ tập tin.
length( ): Trả về chiều dài của tập tin tính theo byte.
82
public AccountRecord( int acct, String first, String last, double bal ) // Constructor có
tham số
{
setAccount( acct );
setFirstName( first );
setLastName( last );
setBalance( bal );
}
public void setAccount( int acct ) // Ðặt số tài khoản
{
account = acct;
}
public int getAccount()// Lấy số tài khoản
{
return account;
}
public void setFirstName( String first ) // Ðặt giá trị cho phần họ đệm
{
firstName = first;
}
public String getFirstName()// Lấy phần họ đệm
{
return firstName;
}
public void setLastName( String last ) // Ðặt giá trị cho tên
{
lastName = last;
}
public String getLastName()// Lấy tên
{
return lastName;
}
public void setBalance( double bal ) // Đặt giá trị cho balance
{
balance = bal;
}
public double getBalance()// Lấy số dư
{
return balance;
}
}
Chương trình sau đây sẽ ghi các đối tượng vào file C:\LETI\JAVA\Account.txt
import java.io.*;
public class GhiFile
83
{
ObjectOutputStream output;
public void openFile()
{
try {
output = new ObjectOutputStream(new FileOutputStream(
"C:\\LETI\\JAVA\\Account.txt") );
}
catch ( IOException ioException ) {
System.out.print("Loi mo file");
}
}
public void closeFile() // Phương thức đóng file
{
try {
output.close();
System.exit( 0 );
}
// Nếu có lỗi đóng file
catch ( IOException ioException )
{
System.exit( 1 );
}
}
public void addRecord(AccountRecord record) // Phương thưc thêm 1 bản ghi vào file
{
try
{
output.writeObject( record );
output.flush();
}
catch(IOException ex)
{
System.out.print("Loi ghi file");
}
}
// Hàm main
public static void main(String[] argvs)
{
AccountRecord record1= new AccountRecord( 12345,"Nguyen Van ","Hai",5.12);
AccountRecord record2= new AccountRecord( 12346,"Phan Tien ","Minh",-5.12);
GhiFile g = new GhiFile();
g.openFile();
g.addRecord(record1);
g.addRecord(record2);
g.closeFile();
}}
84
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.io.*;
public class DocFile
{
java.io.ObjectInputStream input;
public void openFile() // Mở file
{
try
{
input = new java.io.ObjectInputStream(new FileInputStream("C:\\LETI\\JAVA\\Account.txt"));
} catch(IOException e)
{
System.out.print("Loi mo file");
}
}
public void closeFile() //Đóng file
{
try {
input.close();
System.exit( 0 );
}
catch ( IOException ioException )
{
System.exit( 1 );
}
}
// Phương thức đọc 1 bản ghi
public String readFile()
{
String account="";
try {
AccountRecord a = (AccountRecord)input.readObject();
account =String.valueOf( a.getAccount() ) + "\n "
+ a.getFirstName() + "\n "
+ a.getLastName() + "\n "
+ String.valueOf( a.getBalance());
}
catch(Exception p){}
finally {return account;}
}
public static void main(String[] argvs)
{
DocFile d = new DocFile();
85
d.openFile();
System.out.println(d.readFile());
System.out.println(d.readFile());
d.closeFile();
}}
import java.io.*;
public class BinaryAccess
{
public static void main(String[] argvs)
{
java.io.DataOutputStream out; // Luồng ra hỗ trợ ghi file nhị phân
java.io.DataInputStream in; // Luồng vào hỗ trợ đọc file nhị phân
try
{
in = new java.io.DataInputStream(new FileInputStream("C:\\P.doc"));
out = new java.io.DataOutputStream(new FileOutputStream("C:\\G.doc"));
int bytesAvailable = in.available(); // số byte của file
if (bytesAvailable > 0)
{
byte[] data = new byte[bytesAvailable];
in.read(data); // Đọc các byte ra một mảng byte
out.write(data); // Ghi mảng byte này vào một file khác
}
in.close();
out.close();
}
catch (Exception ex)
{}
}}
Bài tập
1. 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.
2. Cho một file có dữ liệu về thí sinh thi hoa hậu như sau:
001, Tran Thi Mong Mo, 1.98, Ha Tay
002, Bùi Thị Thanh Nhàn, 1.89, Ha Noi
003, Nguyen Thu Thuy, 1.70, Ha Nam
86
009, Phan Anh Thu, 1.78, Thanh Hoa
Các dữ liệu lần lượt mô tả về: Mã số, Họ và tên, chiều cao, Quê quán.
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. 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.
4. Viết chương trình copy dữ liệu từ một file ảnh GIF sang một file ảnh GIF khác.
87
Đề tài 7. Xử lý ngoại lệ
Khi viết một chương trình nói chung và trong Java nói riêng, lỗi có thể xảy ra với rất
nhiều lý do. Khi lỗi xảy ra, 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
Ghi lại các dữ liệu hiện thời và kết thúc chương trình
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
Lỗi thiết bị
Lỗi phần cứng như thiếu ổ cứng hay bộ nhớ.
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 , chúng ta gọi đó là một ngoại lệ
(exception) – những điều xảy ra khác thường. Java cho phép người lập trình quản lý các lỗi xảy
ra theo cách khi nó xảy ra, 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.
88
}
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.
Mỗi khối try bắt buộc phải có một khối catch hoặc finally.
Khi lỗi xảy ra, 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. Để lấy được thông báo từ hệ thống về lỗi, sử dụng phương thức getMessage() của
các lớp Exception, ví dụ:
e3.getMessage();
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ệ. 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. Tại điểm quăng ra ngoại lệ (throw point), Java sử dụng cơ chế
kết thúc chương trình thay vì cơ chế qua trở lại điểm xảy ra ngoại lệ và tiếp tục.
Ví dụ:
int functionName( parameterList ) throws ExceptionType1, ExceptionType2,
ExceptionType3,..
{
// Thân phương thức
}
89
Danh sách các ngoại lệ thường dùng trong Java
Ngoại lệ Ý nghĩa
RuntimeException Lớp cơ sở cho nhiều ngoại lệ java.lang
ArthmeticException Lỗi về số học, ví dụ như „chia cho 0‟.
IllegalAccessException Lớp không thể truy cập.
IllegalArgumentException Đối số không hợp lệ.
ArrayIndexOutOfBoundsExeption Lỗi tràn mảng.
NullPointerException Khi truy cập đối tượng null.
SecurityException Cơ chế bảo mật không cho phép thực hiện.
ClassNotFoundException Không thể nạp lớp yêu cầu.
NumberFormatException Việc chuyển đối từ chuỗi sang số thực không thành công.
AWTException Ngoại lệ về AWT
IOException Lớp cha của các lớp ngoại lệ I/O
FileNotFoundException Không thể định vị tập tin
EOFException Kết thúc một tập tin.
NoSuchMethodException Phương thức yêu cầu không tồn tại.
InterruptedException Khi một luồng bị ngắt.
90
class MyAnimation
{
...
public Image loadImage(String s) throws EOFException, MalformedURLException
{
...
}
}
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, đó 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. Đối với các ngoại lệ không
được kiểm soát, chúng kế thừa từ lớp RuntimeException cũng vậy, ta không nên khai báo chúng.
Ví dụ:
class MyAnimation
{
...
void drawImage(int i) throws ArrayIndexOutOfBoundsException // Không phù hợp
{
...
}
}
Đối với các ngoại lệ dạng RuntimeException, 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.
91
...
}
return s;
}
92
Đề tài 8. Xử lý các sự kiện trong Java
I. 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. 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. 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.
Trong Java sử dụng một cách tiếp cận dựa trên các khái niệm:
- Các nguồn của sự kiện (event source)
- Các bộ lắng nghe sự kiện (event listener)
Các nguồn sự kiện chính là các đối tượng điều khiển, 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. Khi một sự kiện xảy ra đối với một nguồn sự
kiện, 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 đó.
Đố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. Tất cả các lớp event đều dẫn xuất từ lớp java.util.EventObject. Mỗi loại sự kiện
tương ứng với một lớp dẫn xuất, chẳng hạn như ActionEvent và WindowEvent. 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:
93
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
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. 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.
Tóm lại, một sự kiện được quản lý dựa trên các khái niệm:
1. 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. 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.
3. 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 đó.
4. Đố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 đó.
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>.add<sự kiện>Listener(<đối tượng lắng nghe sự kiện>)
Ví dụ:
ActionListener listener = . . .; // đối tượng lắng nghe
JButton button = new JButton("Ok"); // Nguồn sự kiện
button.addActionListener(listener); // đăng ký đối tượng lắng nghe sự kiện
Trong đoạn code trên, 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ý. Ở đây, đối tượng listener phải
thuộc một lớp có cài đặt giao diện ActionListener. 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
{
...
public void actionPerformed(ActionEvent event)
{
// Đoạn mã xử ký sự kiện đặt ở đây
...
}
}
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 sự kiện
ActionEvent được phát sinh và gửi cho đối tượng lắng nghe listener. Đối tượng này có cài đặt
một phương thức để xử lý sự kiện là actionPerformed, lấy đối số là đối tượng ActionEvent nhận
được.
Có thể có nhiều bộ lắng nghe được đăng ký cho một nguồn sự kiện, 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.
Sơ đồ sequence cho đoạn code trên như sau:
94
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");
JButton blueButton = new JButton(new ImageIcon("blue-ball.gif"));
Thêm 3 Button vào 1 panel như sau:
Class ButtonPanel extends JPanel
{
public ButtonPanel()
{
JButton yellowButton = new JButton("Yellow");
JButton blueButton = new JButton("Blue");
95
JButton redButton = new JButton("Red");
add(yellowButton);
add(blueButton);
add(redButton);
}
}
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;
}
public void actionPerformed(ActionEvent e)
{
setBackground(backgroundColor); // Thay đổi màu nền của panel khi Button được click
}
private Color backgroundColor;
}
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");
JButton blueButton = new JButton("Blue");
JButton redButton = new JButton("Red");
add(yellowButton);
add(blueButton);
add(redButton);
ColorAction yellowAction = new ColorAction(Color.Yellow);
ColorAction blueAction = new ColorAction(Color.Blue);
ColorAction redAction = new ColorAction(Color.Red);
yellowButton.addActionListener(yellowAction);
blueButton.addActionListener(blueAction);
redButton.addActionListener(redAction);
}
}
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. Giải pháp ở đây là đưa lớp ColorAction
96
thành lớp nội của lớp ButtonPanel, khi đó trong lớp ColorAction, 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.
Class ButtonPanel extends JPanel
{
public ButtonPanel()
{
JButton yellowButton = new JButton("Yellow");
JButton blueButton = new JButton("Blue");
JButton redButton = new JButton("Red");
add(yellowButton);
add(blueButton);
add(redButton);
ColorAction yellowAction = new ColorAction(Color.Yellow);
ColorAction blueAction = new ColorAction(Color.Blue);
ColorAction redAction = new ColorAction(Color.Red);
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.swing.JFrame;
public class testPanel extends JFrame
{
public testPanel()
{
ButtonPanel pn = new ButtonPanel();
this.add(pn);
}
public static void main(String[] argvs)
97
{
testPanel p = new testPanel();
p.setSize(300,400);
p.setVisible(true);
}
}
Thông thường, 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.addActionListener(
new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
setBackground(Color.YELLOW);
}
});
Làm như vậy ta không cần thiết kế riêng một lớp ColorAction.
98
if (event.getSource()==blueButton) setBackground(Color.BLUE);
}
}
Trong ví dụ trên, 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. Do đó, khi đăng ký đối tượng lắng nghe cho các
Button, ta chỉ việc sử dụng biến this, đại diện cho đối tượng ngầm định của chính lớp
ButtonPanel. 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ì
chúng được truy cập trong 2 phương thức khác nhau. 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.
99
IV. Các lớp thích nghi
Ta thấy rằng việc khai báo đầy đủ 7 phương thức, 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,
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ả. 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. Các lớp có vai trò trung gian như vậy
gọi là các lớp thích nghi. Với mỗi giao diện lắng nghe, ta có một lớp thích nghi tương ứng. Ví dụ:
WindowListener có lớp thích nghi WindowAdapter, MouseListener có MouseAdapter. Các lớp
thích nghi thường dùng là:
FocusAdapter MouseMotionAdapter
KeyAdapter WindowAdapter
MouseAdapter
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. Lúc này, kỹ thuật định nghĩa lớp nội nặc danh được phát
huy:
frame.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent event)
{
System.exit(0);
}
public void windowIconified(WindowEvent e) {System.exit(0);}
} );
Đoạn code này thực hiện các công việc sau:
1. Định nghĩa một class nặc danh kế thừa lớp WindowAdapter
2. Thêm 2 phương thức windowClosing và windowIconified cho lớp nặc danh đó
3. Kế thừa 5 phương thức còn lại từ WindowAdapter
4. Tạo ra một đối tượng của lớp đó, đối tượng cũng không có tên
5. Gửi đối tượng này cho phương thức addWindowListener
Ta có thể định nghĩa chồng nhiều hơn một phương thức của WindowAdapter.
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. 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, 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.addWindowListener(new Terminator());
Để kết thúc đề tài này ta liệt kê các phương thức xử lý sự kiện như bảng sau:
100
Interface Methods Parameter/Accessors Nguồn sự kiện
ActionListener actionPerformed ActionEvent AbstractButton
JComboBox
getActionCommand JTextField
getModifiers Timer
getAdjustable
getAdjustmentType
getValue
101
Interface Methods Parameter/Accessors Nguồn sự kiện
MouseWheelListener mousewheelMoved MouseWheelEvent Component
getWheelRotation
getScrollAmount
getOldState
getNewState
102
và http://java.sun.com/docs/books/tutorial/uiswing/events/mouselistener.html
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.
103
Đề 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.
104
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);
}
}
105
III. 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. 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 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ề.
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ộ, trừ các thông tin như
phiên bản Java, tên và phiên bản hệ điều hành, ký tự phân tách file, đường dẫn.
Applet không thể tìm thấy các thông tin cá nhân như email, password,…
Tất cả các cửa sổ trình duyệt có applet được tải về đều có thông báo.
Những yêu cầu về an ninh của applet là rất quan trọng. 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 đó.
Applet cũng có những khả năng như:
Tạo kết nối đến máy đang chạy nó.
Applet dễ dàng dùng các siêu văn bản hiển thị.
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.
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.
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.
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ó.
106
public void actionPerformed(ActionEvent event)
{
frame.setVisible(!frame.isVisible());
}
});
}
}
107
</applet>
Khi đó trong chương trinh applet, ta có thể lấy ra để sử dụng:
public class FontParamApplet extends JApplet
{
public void init()
{
String fontName = getParameter("font");
int fontSize = Integer.parseInt(getParameter("size"));
...
}
}
VI. Các phương thức, lập trình đồ họa và bắt sự kiện của applet
public void paint(Graphics g) {...}: Là phương thức hiển thị cơ bản, 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.
public void update(Graphics g) {...}: 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ẽ.
Ngoài ra Applet còn thừa hưởng các phương thức từ lớp AWT.
Phương thức repaint() được dùng khi cửa sổ cần cập nhật lại. Phương thức này chỉ
cần một tham số là đối tượng của lớp Graphics.
getDocumentBase(): cho biết địa chỉ dạng URL của thư mục chứa tập tin HTML
chứa applet.
getCodeBase(): Cho biết địa chỉ dạng URL của thư mục chứa tập tin .CLASS của
applet.
getImage(URL url, String name): trả về một đối tượng ảnh hiển thị trên nền.
getLocale(): Xác định vị trí applet.
getAudioClip(URL url, String name): cho đối tuợng audio.
showStatus(String st): hiển thị xâu st trên thanh trang thái.
drawChars(char array[ ], int offset, int length, int xCoor, int yCoor): xuất các ký
tự. Chú thích các tham số: array: Mảng các ký tự; offset: Vị trí bắt đầu, nơi các ký
tự được vẽ.; length: Số các ký tự cần được vẽ; xCoor: Toạ độ X, nơi các ký tự cần
được vẽ; yCoor: Toạ độ Y, nơi các ký tự cần được vẽ.
drawBytes(byte array[ ], int offset, int length, int xCoor, int yCoor): xuất các byte
ra.Trong đó array: Mảng các byte.;Vị trí offset hay vị trí bắt đầu; length: Số byte
cần vẽ; xCoor: Toạ độ X; yCoor: Toạ độ Y.
drawLine(int x1, int y1, int x2, int y2): Vẽ đường thẳng từ A(x1, y1) đến B(x2,
y2).
drawOval(int xCoor, int yCoor, int width, int height): Vẽ đường oval.
fillOval(int xCoor, int yCoor, int width, int height): Vẽ hình oval đặc.Trong đó:
width là Chiều rộng của hình, height là Chiều cao của hình.
drawRect(int xCoor, int yCoor, int width, int height): Vẽ hình chữ nhật.
fillRect(int xCoor, int yCoor, int width, int height): Vẽ hình chữ nhật đặc.
drawRoundRect(int xCoor, int yCoor, int width, int height, int arcwidth, int
archeight): Vẽ hình chữ nhật có bo góc.
108
fillRoundRect(int xCoor, int yCoor, int width, int height, int arcwidth, int
archeight): vẽ hình chữ nhật bo góc đặc.
Trong đó: arcwidth: làm tròn góc trái và góc phải của hình chữ nhật.
archeight: làm tròn góc trên đỉnh và góc đáy của hình chữ nhật.
Ví dụ, 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.
draw3Drect(int xCoord, int yCoord, int width, int height, boolean raised): Vẽ hình
chữ nhật 3D.
drawArc(int xCoord, int yCoord, int width, int height, int arcwidth, int archeight):
Vẽ hình cung.
fillArc(int xCoord, int yCoord, int width, int height, int arcwidth, int archeight):
Vẽ hình cung đặc.
Trong đó: xCoord: Toạ độ x; yCoord: Toạ độ y.
width: Chiều rộng của cung được vẽ; height: Chiều cao của cung được vẽ.
arcwidth: Góc bắt đầu; archeight: Độ rộng của cung (góc của cung) so với góc ban đầu.
drawPolyline(int xArray[ ], int yArray[ ], int totalPoints): Vẽ nhiều đường thẳng
Trong đó: xArray: Mảng lưu trữ toạ độ x của các điểm; yArray: Mảng lưu trữ toạ độ y của
các điểm; totalPoints: Tổng số điểm cần vẽ.
setFont(new Font(“Times Roman”, Font.BOLD, 15)): Đặt Font cho chữ,
(Font.BOLD, Font.PLAIN, Font.ITALIC)
drawPolygon(int x[ ], int y[ ], int numPoints):Vẽ đa giác.
fillPolygon(int x[ ], int y[ ], int numPoints): Vẽ đa giác đặc.
Trong đó: x[ ]: Mảng lưu trữ toạ độ x của các điểm; y[ ]: Mảng lưu trữ toạ độ y của các
điểm; numPoints: Tổng số điểm cần vẽ; setColor(Color c): Đặt màu vẽ.
Bảng một số màu cơ bản:
Color.white Color.black
Color.orange Color.gray
Color.lightgray Color.darkgray
Color.red Color.green
Color.blue Color.pink
Color.cyan Color.magenta
Color.yellow
109
Đề tài 10. Lập trình giao diện đồ họa GUI
I. 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 - GUI) thân thiện.
Một giao diện người dùng được hình thành từ các phần tử của GUI. Một phần tử GUI
được thiết lập bằng cách sử dụng các thủ tục:
1. Tạo đối tượng.
2. Xác định sự xuất hiện ban đầu của đối tượng.
3. Chỉ ra nó nằm ở đâu.
4. Thêm phần tử vào giao diện trên màn hình.
Để làm việc với các đối tượng GUI chúng ta cần nhập gói java.awt.*.
AWT cung cấp các thành phần khác nhau để tạo GUI hiệu quả, các thành phần này có thể
là:
Vật chứa (Container).
Thành phần (Component).
Trình quản lý cách trình bày (Layout manager).
Đồ hoạ (Graphics) và các tính năng vẽ (draw).
Phông chữ (Font).
Sự kiện (Event).
Từ phiên bản 1.4, Java phát triển một thư viện mở rộng 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. Các lớp GUI trong swing có thêm tiền tố “J” so
với các lớp trong AWT. Sau đây, chúng ta sẽ xét các thành phần GUI trong swing.
Sơ đồ phân cấp thừa kế các đối tượng GUI trong swing như sau:
110
II. 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. Một vật chứa có thể
chứa nhiều phần tử. Vật chứa thường được sử dụng là:
JPanel - khung chứa đơn giản nhất, để nhóm các đối tượng con lại và sắp xếp theo
cách thích hợp.
JFrame - là một cửa sổ như mọi ứng dụng của windows, để tạo các ứng dụng
windows.
JDialogs - là cửa sổ nhưng không đầy đủ chức năng như Frame, nó là cửa sổ hộp
thoại đưa ra những lời thông báo.
JScrollPanel - khung chứa như Panel nhưng có hai thanh trượt.
II.1 JFrame
Tạo đối tượng khung chứa JFrame bằng phương thức khởi tạo: void JFrame();
Tạo Frame với tiêu đề bên trên: void JFrame(String FrameTitle);
Ví dụ:
JFrame frame1 = new JFrame();
JFrame frame2 = new JFrame("Cua so Frame");
import javax.swing.*;
public class FrameSample {
public static void main(String[] argvs)
{
JFrame f = new JFrame();
f.setSize(400,400);
f.setVisible(true);
}
}
II.2 JPanel
JPanel không thể nhìn thấy trực tiếp, nó là đối tượng dùng để chứa các thành phần GUI
trên màn hình. Do đó chúng ta cần gắn JPanel vào đối tượng nào đó như: JFrame, JApplet, ...
Tạo khung chứa JPanel bằng phương thức khởi tạo: JPanel panel1 = new JPanel();
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.
111
import javax.swing.*;
public class FrameSample {
public static void main(String[] argvs)
{
JFrame f = new JFrame();
JPanel p = new JPanel();
p.add(new JButton("OK"));
f.add(p); // gắn JPanel vào JFrame
f.setSize(400,400);
f.setVisible(true);
}
}
II.3 JDialog
Như JFrame, nhưng ít chức năng hơn, còn được gọi là popup-window.
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. 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.
non-modal: ngược lại với modal, cửa sổ này thích ứng với các thao tác mang tính
tuỳ biến.
Cách tạo khung chứa JDialog từ phương thức khởi tạo:
public JDialog(JFrame parentWindow, boolean isModal);
trong đó: isModal - quyết định xem JDialog được tạo ra ở dạng nào: isModal = true cho
modal còn isModal = false cho non-modal.
Ví dụ: JDialog myDialog = new JDialog(myWindow, true)
Tạo JDialog có tiêu đề định trước:
public JDialog(Frame parentWindow, String title, boolean isModal)
JDialog không thể gắn với Applet, muốn đưa ra một JDialog từ JApplet ta phải tạo ra một
JFrame giả tạo.
Đưa đối tượng JDialog ra màn hình bằng phương thức show().
Giấu cửa sổ JDialog ta dùng phương thức: hide().
Ẩn hiện JDialog ta còn có phương thức: setVisible(boolean).
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.
Lấy và thay đổi kích thước JDialog: public setResizable(boolean), boolean isResizable()
Đặt và lấy tiêu đề của JDialog: void setTitle(String), String getTitle();
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ất vào một nút bấm:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class FrameSample extends JFrame
{ private JDialog d;
public FrameSample() // Constroctor
{
112
d = new JDialog(this,"Day la Jdialog",false);
d.setSize(100,100);
JPanel p = new JPanel();
JButton b = new JButton("Xem/Tat mot JDialog");
b.addActionListener( new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
d.setVisible(!d.isVisible());
}
}
);
p.add(b);
add(p);
}
public static void main(String[] argvs)
{
FrameSample fs = new FrameSample();
fs.setSize(400,400);
fs.setVisible(true);
}
}
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. 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ộ. JScrollPane được ứng dụng
trong các danh sách chọn.
113
Ví dụ: Button nutOK = new Button(); nutOK.setLabel("OK");
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 đó. Vấn đề này chúng ta đã
xem xét trong phần xử lý các sự kiện
114
// JLabel không tham số
label3 = new JLabel();
label3.setText( "Label with icon and text at bottom" );
label3.setIcon( bug );
label3.setHorizontalTextPosition( SwingConstants.CENTER );
label3.setVerticalTextPosition( SwingConstants.BOTTOM );
label3.setToolTipText( "This is label3" );
container.add( label3 );
application.setDefaultCloseOperation(
JFrame.EXIT_ON_CLOSE );
}
}
115
// Java extension packages
import javax.swing.*;
public class CheckBoxTest extends JFrame {
private JTextField field;
private JCheckBox bold, italic;
// Thiết lập GUI
public CheckBoxTest()
{
super( "JCheckBox Test" );
// lấy pane
Container container = getContentPane();
container.setLayout( new FlowLayout() );
// Đặt ô nhập và font chữ
field = new JTextField( "Theo dõi font chữ thay đổi", 20 );
field.setFont( new Font( "Serif", Font.PLAIN, 14 ) );
container.add( field );
// execute application
public static void main( String args[] )
{
CheckBoxTest application = new CheckBoxTest();
application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
}
// Lớp nội lắng nghe sự kiện
private class CheckBoxHandler implements ItemListener {
private int valBold = Font.PLAIN;
private int valItalic = Font.PLAIN;
// Đáp ứng sự kiện chọn ô
public void itemStateChanged( ItemEvent event )
{
// xử lý chọn ô chữ đậm
if ( event.getSource() == bold )
116
if ( event.getStateChange() = = ItemEvent.SELECTED )
valBold = Font.BOLD;
else
valBold = Font.PLAIN;
117
III.5 Hộp thoại Combo
Java hỗ trợ hộp thoại Combo thông qua đối tượng của class JComboBox. Đây là một danh
sách xổ xuống, đưa ra một danh sách các mục và ta chỉ được chọn 1 mục trong đó. JComboBox
cũng phát sinh sự kiện ItemEvent giống như JRadioButton và JCheckBox.
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.
// Đặt layout
Container container = getContentPane();
container.setLayout( new FlowLayout() );
container.add( imagesComboBox );
118
container.add( label );
// hàm main
public static void main( String args[] )
{
ComboBoxTest application = new ComboBoxTest();
aplication.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
}}
119
Để xử lý được tình huống nhấp đôi chuột, ta cài đặt giao tiếp ActionListener và gắn nó
vào danh sách.
Phương thức getActionCommand() trong ActionEvent sẽ trả về tên của phần tử bị nhấp.
// Java core packages
import java.awt.*;
// Java extension packages
import javax.swing.*;
import javax.swing.event.*;
private String colorNames[] = { "Black", "Blue", "Cyan", "Dark Gray", "Gray", "Green",
"Light Gray", "Magenta", "Orange", "Pink", "Red", "White", "Yellow" };
// lấy layout
container = getContentPane();
container.setLayout( new FlowLayout() );
120
}
// hàm main
public static void main( String args[] )
{
ListTest application = new ListTest();
application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
}}
III.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();
Tạo một ô văn bản hiển thị tối thiểu numCols ký tự: public TextField(int
numCols);
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);
Tạo ô văn bản kết hợp: public TextField(String initText, int numCols);
Tạo vùng văn bản:
Tạo vùng văn bản rỗng, kích thước bất kỳ: public TextArea();
Tạo một vùng văn bản với nội dung cho trước: public TextArea(String initiaText);
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,
int cols);
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, int rows, 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);
Lấy nội dung văn bản trong các đối tượng: public String getText();
Lấy nội dung văn bản được đánh dấu: public String getSelectedText();
Để 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(); //đầu
public int getSelectionEnd(); //cuối
Đánh dấu toàn bộ văn bản: public void selectAll();
Cho phép soạn thảo được: public void setEditable(boolean canEdited); canEdited = false:
chỉ đọc.
canEdited = true: thêm, sử được.
Xác định đối tượng đang ở trang thái nào: public boolean isEditable();
Đặ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); ví dụ:
myTextField.setEchoChar('*'); //mã mKhẩu
Xác định xem ký tự làm ký tự hiển thị: public char getEchoChar();
Xác định chiều dài của ô văn bản theo ký tự: public int getColums();
Đặ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);
121
Chèn một chuỗi văn bản vào vị trí bất kỳ: public void insertText(String newText, int pos);
Xác định kích thước hiển thị: public int getRows(); public int getColums();
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, ta thiết lập ActionListener để gắn đối tượng xử
lý tình huống vào văn bản TextField. Khi người dung nhấn Enter thì tình huống được gọi.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TextFieldTest extends JFrame {
private JTextField textField1, textField2, textField3;
private JPasswordField passwordField;
// ô nhập không cho phép nhập, chỉ hiên thị thông tin
textField3 = new JTextField( "Uneditable text field", 20 );
textField3.setEditable( false );
container.add( textField3 );
// ô nhập password
passwordField = new JPasswordField( "Hidden text" );
container.add( passwordField );
// hàm main
public static void main( String args[] )
122
{
TextFieldTest application = new TextFieldTest();
application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
}
// 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 = "";
// khi người dùng ấn enter
if ( event.getSource() == textField1 )
string = "textField1: " + event.getActionCommand();
123
Tạo thanh trượt đứng hay ngang ta dùng: public Scrollbar(int orienttation); orienttation
nhận giá trị Scrollbat.VERTICAL - cho đứng, Scrollbar.HORIZONTAL cho nằm ngang.
Tạo thanh trượt có đầy đủ thông số ban đầu:
public Scrollbar(int orienttation,
int pos, //vị trí khởi đầu
int pageUnit, //bước nhảy
int minValue, //giá trị min
int maxValue); //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);
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);
Muốn biết hiện thời đơn vị thay đổi là bao nhiêu: public int getBlockIncrement();
Lấy giá trị lớn nhất và nhỏ nhất: public int getMaximum(); public int getMinimum();
Đặt lại vị trí hiện hành cho thanh trượt: public void setValue(int newPos);
Cho ta vị trí hiện hành: public int getValue();
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.HORIZONTAL.
Thiết lập lại các thông số cho thanh trượt: public void setValues(int position, int
pageUnit, int minimum, int maximum);
ví dụ: myScrollbar.setValues(75, 10, 0, 500);
Sử dụng thanh trượt:
Ta nhờ đối tượng xử lý tình huống xử lý: public void
adjustmentValueChanged(AdjustmentEvent evt);
Có 3 trạng thái: line, page và absolute. Ta sử dụng hàm getAdjustmentType() để xác định
xem tình huống nào đang xảy ra.
AdjustmentEvent.UNIT_INCREMENT: tình huống line xảy ra, vị trí thanh trượt tăng 1
đơn vị.
AdjustmentEvent.UNIT_DECREMENT: tình huống line xảy ra, vị trí thanh trượt giảm 1
đơn vị.
AdjustmentEvent.BLOCK_INCREMENT: tình huống page xảy ra, vị trí hiện hành tăng 1
đv.
AdjustmentEvent.Track: tình huống absolute xảy ra, ta lấy vị trí thanh trượt bằng hàm
getValue().
124
Sau đó thì thêm nó vào JMenuBar: menuBar.add(file);
Bây gời là lúc ta cài đặt các mục chọn trong một JMenu. Java dùng lớp JMenuItem định
nghĩa từng mục của thực đơn.
JMenuItem open = new JMenuItem(“Open”,‟O‟);
Ở đây ta đã gọi một constructor với một tham số là nhãn của mục chọn, một tham số là ký
tự phím tắt. Sau đó ta add vào JMenu:
file.add(open);
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.addSeparator();
Lớp JPopUpMenu biểu diễn cho thực đơn pop-up. 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.
Lớp JCheckBoxMenuItem chứa các mục được chọn để kiểm tra trong các mục thực đơn.
Tạo thanh trình đơn: JMenuBar myMenubar = new JMenuBar();
Đặt trạng thái cho mỗi mục chọn sử dụng enable() hoặc disable():
Vi dụ: openItem.enable(); //được chọn
openItem.disable(); //mờ mục chọn
Ta có thể dùng đường phân cách để tách các mục chọn:
FileMenu.addSeparator();
Tạo mục chọn có chứa menu con khác, ta tạo một menu bình thường rồi đưa vào
menu đã có.
Ví dụ:
//tạo mục chọn có menu con
JMenu printItem = new JMenu("Print");
//tạo các mục chọn cho menu con
printItem.add("Print preview");
printItem.add("to preview");
//đưa mục chọn có menu con vào menu chính
FileMenu.add(printItem);
Tạo một mục chọn có khả năng đánh dấu (check Item), 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.add(Autosave);
Xác định xem mục chọn Autosave đang ở trạng thái nào, ta dùng: Autosave.getState();
Khi sử dụng, để 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.
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.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class MenuBarSample extends JFrame {
//Khai bao mot hop thoai
JOptionPane op = new JOptionPane();
// Khai bao mot thuc don pop-up
JPopupMenu jp;
public MenuBarSample()
125
{
// Lay ve doi tuong chua cua Frame hien tai
Container pane = this.getContentPane();
// Dat kieu trinh bay
pane.setLayout(new FlowLayout(FlowLayout.LEADING));
// Khai bao mot thanh menu
JMenuBar menuBar= new JMenuBar();
// Khai bao muc File trong thanh menu
JMenu menuFile= new JMenu("File");menuBar.add(menuFile);
// Dat ky tu kich hoat tat cung Alt
menuFile.setMnemonic('F');
// Khai bao mot muc chon voi phim tat O
JMenuItem fileOpen = new JMenuItem("Open",'O');
// Them muc chon vao muc File
menuFile.add(fileOpen);
// Them mot muc chon khac voi phim tat N
menuFile.add(new JMenuItem("New",'N'));
// Them dong ngan cach
menuFile.addSeparator();
// Them mot muc chon co ten Save
menuFile.add("Save");
// Xu ly su kien chon muc Open
fileOpen.addActionListener( new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
// Hien thi thong bao, getContentPane() de lay Container cua Frame
op.showMessageDialog(getContentPane(),"Ban vua chon Open");
}
} );
// Xu ly su kien chon New
menuFile.getItem(1).addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
op.showMessageDialog(getContentPane(),"Ban vua chon New");
}
} );
// Xu ly su kien chon Save
menuFile.getItem(3).addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
op.showMessageDialog(getContentPane(),"Ban vua chon Save");
}
} );
// Khai bao mot muc chon kieu checkbox
126
JCheckBoxMenuItem chk = new JCheckBoxMenuItem("is editting");
// Them phan xu ly su kien chon hay khong chon cho no
chk.addActionListener( new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
// Lay ve doi tuong nguon su kien va ep kieu
JCheckBoxMenuItem ck = (JCheckBoxMenuItem)e.getSource();
if (ck.isSelected())
//Neu duoc chon
op.showMessageDialog(getContentPane(),"Ban vua chon is editting");
else
// Neu khong duoc chon
op.showMessageDialog(getContentPane(),"Ban vua bo chon is editting");
}
} );
// Them muc chon checkbox vao menu File
menuFile.add(chk);
// Dat thanh Menu cho Frame la doi tuong menuBar
this.setJMenuBar(menuBar);
// Cap phat bo nho cho popup menu
jp = new JPopupMenu("Popup");
jp.add("Create");
jp.addSeparator();
jp.add("New Document");
this.addMouseListener( new MouseAdapter()
{
public void mouseClicked(MouseEvent e)
{
if( (e.getModifiers() & InputEvent.BUTTON3_MASK)== InputEvent.BUTTON3_MASK)
jp.show(getContentPane(),e.getX(),e.getY());
}
}
);
}
public static void main(String[] argvs)
{
MenuBarSample m = new MenuBarSample();
m.setSize(300,400);
m.setVisible(true);
}
}
127
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. Các đối
tượng giữ nguyên kích thước.
GridLayout: tạo một khung lưới vô hình với các ô bằng nhau, các đối tượng sẽ đặt
vừa kích thước với các ô đó.
BorderLayout: Các đối tượng được đặt theo đường viền của khung chứa theo các
cạnh West, East, South, Nort và Center.
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.
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, kích thước các đối tượng không nhất thiết phải vừa một
ô.
Muốn áp dụng ta tạo ra đối tượng trên rồi chuyển nó cho khung chứa.
Ví du: FlowLayout objectsLayout = new FlowLayout();
myWindow.setLayout(objectsLayout);
hay có thể viết gọn hơn:
myWindow.setLayout(new FlowLayout());
128
showMessageDialog Không có Hiển thị một thông báo và đợi ấn OK
showConfirmDialog Số int Hiển thị thông báo và đợi xác nhận Ok hay Cancel
showOptionDialog Số int Hiển thị thông báo và nhận về trả lời từ một danh sách chọn
showInputDialog Chuỗi Hiển thị thông báo và nhận về một dòng do user nhập vào
129
return "GIF Image";
}
}
Sau đó gán cho hộp thoại: chooser.setFileFilter(new GifFilter());
6- Mặc định thì chỉ cho phép chọn file, 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.DIRECTORIES_ONLY hoặc
JFileChooser.FILES_AND_DIRECTORIES.
7- Hiển thị hộp thoại bằng lệnh gọi:
int result = chooser.showOpenDialog(parent);
hoặc
int result = chooser.showSaveDialog(parent);
Các giá trị trả về là JFileChooser.APPROVE_OPTION,
JFileChooser.CANCEL_OPTION, or JFileChooser.ERROR_OPTION
8- Lấy vè file hoặc các file được chọn dùng: getSelectedFile() hoặc getSelectedFiles().
Neus chỉ muốn lấy tên file thì ta dùng phương thức getPath().
String filename = chooser.getSelectedFile().getPath();
Bài tập
1. Hãy thiết kế một giao diện có nội dung như sau:
130
2. 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.
3. Viết chương trình giải phương trình bậc 2 với giao diện GUI. Yêu cầu chương trình có các ô
nhập các hệ số a, b, c và cho phép xem kết quả. 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”.
131
Đề tài 11. 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. 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.
132
1. 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. Tạo một đối tượng của lớp
Runnable r = new MyRunnable();
3. Tạo một đối tượng Thread từ đối tượng Runable trên:
Thread t = new Thread(r);
4. Gọi phương thức start()
t.start();
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,3 và 4 để thực hiện thread.
133
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.
134
Các thread có độ ưu tiên càng cao thì khả năng thực hiện càng cao.
135
Bộ xử lý này phải thuộc một lớp có cài đặt giao diện Thread.UncaughtExceptionHandler
chỉ với 1 phương thức:
void uncaughtException(Thread t, Throwable e);
Từ phiên bản Java 1.5, 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(). 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.
Nếu không cài bộ xử lý ngoại lệ cho một thread thì mặc định là null. Tuy nhiên, các
thread riêng lại phụ thuộc vào bộ xử lý của nhóm thread chứa nó. Khi này, phương thức
uncaughtException sẽ làm các việc sau:
1- Nếu nhóm thread có cài đặt uncaughtException thì phương thức đó được gọi.
2- Ngược lại, nếu phương thức Thread.getDefaultExceptionHandler trả về một bộ xử lý
không phải là null thì bộ xử lý này được gọi.
3- Nếu là null, nếu Throwable là một đối tượng của TheadDead, không có gì xảy ra.
4- Nếu không, tên của thread và stack trace được gửi tới System.err và đưa ra màn hình.
136
// bắt đầu thread
sleepy.start();
// Nhắc người dùng để dừng thread
System.out.println ("Nhấn Enter để ngưng thread");
System.in.read();
// Ngắt thread
sleepy.interrupt();
}}
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ủ. Ở đây, thread chính- hàm main- sẽ đợi cho người dùng ấn enter, sau đó gửi một thông
điệp ngắt tới thread đang ngủ.
137
IV.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. 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 đó.
138
V. Đồng bộ thread
Trong hầu hết các chương trình đa luồng, các thread có thể cần phải truy cập đến cùng
một đối tượng. Đ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. 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. Tình trạng này gọi là “đua tranh”.
139
Giả sử đây là một hành vi đơn vị (atomic- hành vi chỉ chiếm một chu kỳ thực hiện lệnh
của CPU), 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, CPU cũng chỉ phục vụ được cho một thread.
Tuy nhiên, phép tính này lại không phải là atomic, công việc có thể phải làm là:
1- Load giá trị account[to] vào thanh ghi
2- Cộng với account
3- 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. Thread_1
thực hiện xong bước 1 và 2 thì bị ngắt, 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ị. Tiếp theo, thread_1 thức dậy và làm tiếp bước 3,
account[to] lúc này đã ghi đè giá trị do thread_2 cập nhật. Điều này dẫn tới việc tổng số tiền bị
thay đổi, phần tiền do thread_2 chuyển cho account[to] đã bị mất.
140
}
finally
{
bankLock.unlock();
}
}
...
private Lock bankLock = new ReentrantLock(); // ReentrantLock là một lớp cài đặt giao
diện lock.
}
141
{
...
sufficientFunds = bankLock.newCondition();
}
...
private Condition sufficientFunds;
}
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.await();Lúc này nó sẽ nằm chờ thread khác chuyển tiền.
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(). 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(). Một thread thực hiện xong
việc chuyển tiền, nó nên 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. Một khi thread đã thoát khỏi tình trạng đợi do await() gây ra, 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 đó - vị trí
gọi phương thức await() và kiểm tra lại điều kiện.
Một phương thức await() nên được gọi trong một vòng lặp đợi:
while (!(đủ tiền))
condition.await();
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. Nếu tất cả các thread khác đều đang bị chặn, 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, chương trình sẽ bị treo.
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(). Ở đây, sau khi cộng tiền vào cho tài
khoản nhận và thì signalAll() sẽ được gọi. 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.
public void transfer(int from, int to, int amount)
{
bankLock.lock();
try
{
while (accounts[from] < amount)
sufficientFunds.await();
// Chuyển tiền
...
sufficientFunds.signalAll();
}
finally
{
bankLock.unlock();
}
}
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. 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ệ. 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ả. Một
thread chỉ có thể gọi các phương thức signalAll(), sign() và await() trong vùng được bảo vệ.
142
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, 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, người được gửi tiền sẽ được vào
trong ngân hàng và giữ khóa cổng, 9 người khác phải chờ ngoài cổng. Nếu chẳng may người
đang thực hiện chuyển số tiền lớn hơn anh ta có, 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. Một trong số 9 người ngoài cổng sẽ được đi vào
trong ngân hàng, thực hiện việc chuyển tiền. Sau khi chuyển xong, 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, sau đó những người đang đợi cũng quay ra cổng để đợi đến lượt vào.
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.
2. 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.
143
Phụ lục A. Các từ khóa của Java
Từ khóa Ý nghĩa
abstract Một lớp hoặc phương thức trừu tượng
assert Được sử dụng để định vị lỗi nội bộ chương trình
boolean Kiểu boolean
break Thoát khỏi lệnh switch hoặc các vòng lặp
byte Số nguyên 1 byte
case Một lựa chon của switch
catch Một mệnh đề của khối Try để bắt một ngoại lệ
char Kiểu ký tự Unicode
class Định nghĩa một class
const Không được sử dụng
continue Tiếp tục tại vị trí cuối vòng lặp hiện thời
default Mệnh đề mặc định của switch
do Phần trên của vòng lặp do/while
double Kiểu số thực floating-number 8 byte
else Mệnh đề else của một lệnh if
extends Xác định lớp cha của một lớp
final Một hằng số, hoặc một lớp hay phương thức không thể bị khai báo chống.
finally Một phần của khối try mà luôn được thực hiện
float Số thực 4 byte
for Một kiểu vòng lặp
goto Không sử dụng
if Một lệnh điều khiển rẽ nhánh
implements Chỉ ra các interfaces mà lớp sẽ cài đặt.
import Nhập một package
instanceof Kiểm tra xem đối tượng có phải là biểu hiện của một lớp
int Số nguyên 4 byte
interface 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
144
Từ khóa Ý nghĩa
long Sô nguyên 8 byte
Native a method implemented by the host system
new Cấp phát vùng nhớ cho một đối tượng hoặc mảng mới
null Một tham chiếu null
package Một gói các lớp
private a feature that is accessible only by methods of this class
protected a feature that is accessible only by methods of this class, its children, and other
classes in the same package
public a feature that is accessible by methods of all classes
return returns from a method
short the 16-bit integer type
static a feature that is unique to its class, not to objects of its class
strictfp Use strict rules for floating-point computations
super the superclass object or constructor
switch a selection statement
synchronized a method or code block that is atomic to a thread
this the implicit argument of a method, or a constructor of this class
throw throws an exception
tHRows the exceptions that a method can throw
transient marks data that should not be persistent
try a block of code that traps exceptions
void denotes a method that returns no value
volatile ensures that a field is coherently accessed by multiple threads
while a loop
145
7. exp(double x) = ex.
8. log(double x) = Ln(x).
9. max(number x, number y) = max{x, y}, trong đó x, y có thể là kiểu int, float,
double, long.
10. min(number x, number y) = min{x, y}, trong đó x, y có thể là kiểu int, float,
double, long.
11. pow(double x, double y) = xy.
12. random(): cho một số ngẫu nhiên trong [0.0, 1.0].
13. round(number x): làm tròn số x, nếu x là kiểu double thì thành kiểu long, nếu x là
kiểu float thì thành kiểu int.
14. sin(double x) = sin(x).
15. sqrt(double x) =
16. tan(double x) = tg(x).
Khi sử dụng ta phải dùng Math.tên_hàm.
b) Lớp String, khai báo java.lang.String;
1. String() : Khởi động một đối tượng chuỗi.
2. String(String s) : Khởi động một chuỗi bằng chuỗi s.
3. length() : trả về giá trị int là độ dài một chuỗi.
4. charAt(int i): trả về một ký tự thứ sau i.
5. indexOf(int ch): trả về vị trí trước của ký tự ch đầu tiên tìm thấy.
6. concat(String str): nối thêm chuỗi str vào sau.
7. toLowerCase(): thay đổi chuỗi thành chữ thường.
8. toUpperCase(): chuyển đổi chuỗi thành chữ HOA.
Lớp Date khai báo java.util.Date;
1. Date(): cho thứ, tháng, ngày, giờ, năm.
2. getDate(): trả về giá trị của ngày trong tháng.
3. getDay(): trả về giá trị int là thứ trong tuần, 0 = CN, 1 = mon, ..., 6 = Sat.
4. getMonth(): trả về giá trị int là tháng trong năm (0..11).
5. getYear(): trả về giá trị int là năm. Lấy mốc là 1900, năm thực =
date.getYear()+1900.
6. getTime(): trả về là một số được tính theo giây đồng hồ.
7. getHours(): trả về giá trị int chỉ giờ trong ngày.
8. getMinutes(): trả về giá trị int chỉ phút trong giờ.
9. getSeconds(): trả về giá trị int chỉ giây đồng hồ trong phút.
10. setDate(int date) đặt lại ngày trong biến. date lấy giá trị từ 1..31
11. setMonth(int month): thay đổi giá trị tháng trong biến date. month có giá trị 0..11.
12. setYear(int year): thay đổi giá trị năm trong biến date. (year + 1900).
13. setHours(int hour): thay đổi giá trị giờ trong biến date.
14. setMinutes(int i): thay đổi giá trị phút trong biến date.
15. setSeconds(int i): thay đổi giá trị giây trong biến date.
146