Giáo Trình Lập Trình JavaGiáo Trình Lập Trình JavaGiáo Trình Lập Trình JavaGiáo Trình Lập Trình JavaGiáo Trình Lập Trình JavaGiáo Trình Lập Trình JavaGiáo Trình Lập Trình JavaGiáo Trình Lập Trình JavaGiáo Trình Lập Trình JavaGiáo Trình Lập Trình JavaGiáo Trình Lập Trình JavaGiáo Trình Lập Trình JavaGiáo Trình Lập Trình JavaGiáo Trình Lập Trình JavaGiáo Trình Lập Trình JavaGiáo Trình Lập Trình JavaGiáo Trình Lập Trình JavaGiáo Trình Lập Trình JavaGiáo Trình Lập Trình JavaGiáo Trình Lập Trình JavaGiáo Trình Lập Trình JavaGiáo Trình Lập Trình JavaGiáo Trình Lập Trình JavaGiáo Trình Lập Trình JavaGiáo Trình Lập Trình JavaGiáo Trình Lập Trình JavaGiáo Trình Lập Trình JavaGiáo Trình Lập Trình JavaGiáo Trình Lập Trình JavaGiáo Trình Lập Trình JavaGiáo Trình Lập Trình JavaGiáo Trình Lập Trình JavaGiáo Trình Lập Trình JavaGiáo Trình Lập Trình JavaGiáo Trình Lập Trình JavaGiáo Trình Lập Trình JavaGiáo Trình Lập Trình JavaGiáo Trình Lập Trình Java
NHẬP MÔN LẠP TRÌNH JAVA 1.1 Giới thiệu về ngôn ngữ lập trình J a v a
Máy ảo Java (JVM) '
Tất cả các chương trình muốn thực thi trên máy tính đều cần được biên dịch ra mã máy, và mã máy này khác nhau tùy thuộc vào kiến trúc CPU của từng máy Ví dụ, tập lệnh mã máy của CPU Intel, Solaris, hay Macintosh là khác nhau Do đó, trước đây, một chương trình sau khi biên dịch chỉ có thể chạy trên một kiến trúc CPU cụ thể Đối với CPU Intel, các hệ điều hành như Microsoft Windows, Unix, Linux, và OS/2 có thể được chạy.
Chương trình trên Windows được biên dịch dưới dạng file EXE, trong khi trên Linux là file ELF, điều này khiến cho việc chạy một chương trình Windows trên Linux gặp khó khăn và cần phải chỉnh sửa, biên dịch lại Tuy nhiên, ngôn ngữ lập trình Java và máy ảo Java (JVM) đã khắc phục vấn đề này Chương trình viết bằng Java (file java) được biên dịch thành mã byte (bytecode) và lưu dưới dạng file class Sau đó, JVM sẽ chuyển mã byte thành mã máy tương ứng (.exe) để thực thi trên nhiều hệ điều hành khác nhau.
M i c r o s y s t e m chịu trách nhiệm phát triển các máy ảo J a v a chạy trên các hệ điều hành và trên các kiến trúc CPU khác nhau.
Khả năng cơ động cùa f i l e c l a s s (m ã b y t e c o d e ) cho phép các chương trinh
Java cho phép lập trình viên viết mã một lần và chạy trên bất kỳ nền tảng nào nhờ vào máy ảo Java Khả năng này được hỗ trợ bởi cơ chế dịch mã thành mã trung gian (.class), cho phép tệp này có thể được dịch ngược (decompile) để khôi phục lại chương trình nguồn (.java).
1.2.1 M áy ảo Ja va là gì?
Máy ảo là phần mềm dựa trên công nghệ máy tính ảo, bao gồm các lệnh logic để xác định hoạt động của máy tính Nó có thể được coi là một hệ điều hành thu nhỏ, thiết lập các lớp trừu tượng cho phần cứng, hệ điều hành và mã lệnh đã biên dịch.
Trình biên dịch chuyển đổi mã nguồn thành tập lệnh bytecode, không phụ thuộc vào phần cứng cụ thể Sau đó, trình thông dịch trên máy sẽ chuyển đổi bytecode thành chương trình thực thi Máy ảo tạo ra một môi trường nội bộ để thực hiện các lệnh này.
■ Quàn lý bộ nhớ máy tính;
Việc không nhất quán của phần cứng làm cho máy ảo phải sử dụng ngăn xếp đề lưu trữ các thông tin sau:
■ Các "F ra m e " chứa các trạng thái của các phương thức;
11 Các toán hạng cùa mã b y t e c o d e ;
• Các tham số truyền cho phương thức;
Khi JVM thực thi mã b y t e c o d e ( c l a s s ) , một thanh ghi cục bộ có tên
Thanh ghi "Program Counter" được sử dụng để theo dõi lệnh đang thực hiện trong chương trình Khi cần thiết, nội dung của thanh ghi này có thể được thay đổi để điều hướng thực thi của chương trình Trong trường hợp thông thường, các lệnh sẽ được thực hiện liên tiếp một cách tuần tự.
Một khái niệm thông dụng khác trong J a v a là trình biên dịch " J u s t I n T im e -
J I T " Các trình duyệt Web thông dụng như N e t s c a p e , IE , F i r e f o x hay
Chrome và nhiều trình duyệt khác đều tích hợp JIT để tăng tốc độ thực thi chương trình Java JIT có nhiệm vụ chuyển đổi bytecode thành mã máy tương thích với từng loại CPU Các lệnh này sẽ được lưu trữ để sử dụng khi cần thiết.
1.2.2 Q uản lý bộ n hớ và dọn rác
Trong lập trình C/C++ và Pascal, lập trình viên thường sử dụng phương pháp trực tiếp để cấp phát và thu hồi bộ nhớ Heap Heap là vùng bộ nhớ lớn được phân chia cho tất cả các luồng thực hiện Để quản lý bộ nhớ Heap, bộ nhớ được theo dõi thông qua các danh sách.
* Danh sách các vùng nhớ chưa sừ dụng;
■ Danh sách các vùng đã cấp.
Khi nhận được yêu cầu cấp phát bộ nhớ, hệ thống sẽ tìm trong danh sách bộ nhớ chưa được cấp phát để xác định khối bộ nhớ đầu tiên có kích thước gần nhất với lượng bộ nhớ cần thiết.
Kỹ thuật cấp phát này giảm tối thiểu việc phân mảnh của bộ nhớ H ea p
Kỹ thuật kết hợp lại ( C o a l e s c i n g ) nhằm giảm thiều việc phân mảnh cùa bộ nhớ
Heap là phương pháp gom nhóm các vùng nhớ chưa sử dụng lại với nhau thành một khối lớn hơn Kỹ thuật sắp xếp lại các phần bộ nhớ đã sử dụng để tạo ra vùng nhớ chưa sử dụng lớn hơn được gọi là kỹ thuật nén (Compaction).
Java sử dụng hai bộ nhớ Heap riêng biệt cho việc cấp phát vùng nhớ tĩnh và động Bộ nhớ Heap tĩnh lưu trữ định nghĩa lớp, các hằng số và danh sách phương thức Trong khi đó, bộ nhớ Heap động được chia thành hai phần, một bên chứa đối tượng và bên còn lại chứa con trỏ tham chiếu đến đối tượng đó.
Handle là cấu trúc bao gồm hai con trỏ: một con trỏ trỏ đến bảng phương thức của đối tượng và con trỏ thứ hai trỏ đến chính đối tượng đó.
" c o m p a c t i o n " cần, nó cập nhật lại giá trị con trò của cấu trúc h a n d l e
Thuật toán "dọn rác" được áp dụng cho các đối tượng trong Heap động, giúp quản lý bộ nhớ hiệu quả Khi có yêu cầu về bộ nhớ, trình quản lý Heap sẽ kiểm tra danh sách bộ nhớ chưa cấp phát Nếu không tìm thấy khối bộ nhớ phù hợp về kích cỡ, quy trình dọn rác sẽ được kích hoạt khi hệ thống rảnh Tuy nhiên, nếu nhu cầu về bộ nhớ là cấp bách, trình dọn rác sẽ được khởi động ngay lập tức.
Trình dọn rác gọi phương thức f i n a l i z e () của đối tượng trước khi dọn dẹp đối tượng Hàm này sẽ dọn dẹp các tài nguyên bên ngoài như các f i l e đang mở.
1.2.3 Q uá trình kiểm tra fìle class
Việc kiểm tra tất cả các file class trước khi nạp lên bộ nhớ là cần thiết để đảm bảo an toàn thông tin Trình Class Loader sẽ giám sát và kiểm tra các file class không thuộc hệ điều hành nhằm phát hiện những file có nguy cơ gây hư hỏng cho bộ nhớ, hệ thống file cục bộ, mạng hoặc hệ điều hành Quá trình này sẽ đánh giá tổng thể tính nguyên vẹn của từng lớp.
F i l e c l a s s bao gồm ba phần logic là:
■ Thông tin về C l a s s như phương thức, giao diện và các giá trị hằng số được tập hợp trong quá trình biên dịch;
■ Các thuộc tính về lớp.
Các thông tin của f i l e c l a s s được xem xét riêng rẽ trong các bàng sau:
■ Báng F i e l d chứa các thuộc tinh;
• Báng M e th o d chứa các hàm (phương thức) của lớp;
• Bàng l n t e r f a c e chứa các nguyên mầu hàm và các hằng số.
Quá trình kiểm tra f i l e c l a s s được thực hiện ở bốn mức:
■ Mức đầu tiên, thực hiện việc kiểm tra cú pháp để đàm bảo tính cấu trúc và tính toàn vẹn cú pháp cùa f i l e c l a s s được nạp.
■ Mức thứ hai, xem xét f i l e c l a s s để đảm bảo các f i l e này không vi phạm các nguyên tắc về sự nhất quán ngữ nghĩa.
Mức thứ ba trong quy trình kiểm tra bao gồm việc xác minh các thông số được truyền vào phương thức Bước này tập trung vào khả năng phát hiện lỗi liên quan đến chỉ số của mảng, chuỗi và biểu thức.
Bộ công cụ phát triển JDK (Java Development K it)
Bộ công cụ phát triển Java (JDK) là tập hợp các công cụ phần mềm do Sun Microsystems phát triển, dành cho các lập trình viên để viết ứng dụng và applet bằng ngôn ngữ Java JDK được phát hành miễn phí và bao gồm trình biên dịch, trình thông dịch, công cụ gỡ lỗi, trình chạy applet cùng với tài liệu nghiên cứu hỗ trợ lập trình viên.
JDK bao gồm Java Plug-in, cho phép chạy trực tiếp Java Applet và Java Bean thông qua JRE, thay vì sử dụng môi trường thực thi mặc định của trình duyệt Bộ JDK được cung cấp bởi Sun tại trang web: http://java.sun.com.
M i c r o s y s t e m cung cấp nhiều công cụ, thư viện lập trình phong phú hỗ trợ cho việc phát triển nhiều loại hình ứng dụng khác nhau cụ thể như: J 2 S E (J a v a 2
S t a n d a r d E d i t i o n ) hỗ trợ phát triền những ứng dụng đơn, ứng dụng
C l i e n t - s e r v e r ; J2 E E ( J a v a 2 E n t e r p r i s e E d i t i o n ) hỗ trợ phát triển các ứng dụng thương mại; J2ME (J a v a 2 M i c r o E d i t i o n ) hỗ trợ phát triền các ứng dụng trên các thiết bị di động, không d â y ,
Hiện nay có nhiều môi trường phát triển phần mềm với J a v a như: E c l i p s e (mã nguồn mở), Ơ C r e a t o r , N e tB e a n , V i s u a l J+ + , S y m a t e c 1 s C a fe ,
Các chương trình của giáo trình này được phát triển và thực hiện với ơ c r e a t o r
Bộ JDK cung cấp các công cụ và các chương trình sau:
■ j a v a c Trình dịch chuyển mã nguồn sang mã b y t e c o d e
■ j a v a Trình thông dịch, nó thực thi các úng dụng độc lập, các tệp tin
■ a p p l e t v i e w e r Trình thông dịch, nó thực thi các ứng dụng nhúng ( J a v a
A p p l e t ) từ tệp tin HTML mà không cần sử dụng trình duyệt như N e s t c a p e , hay I n t e r n e t E x p l o r e r ,
Bộ tạo tài liệu HTML từ mã nguồn với các chú thích bên trong cho phép người dùng tạo tệp HTML dựa trên các lời giải thích trong mã chương trình, được định nghĩa trong cặp dấu /** */.
Bộ gỡ lỗi ( j a v a d e b u g e r ) cho phép thực hiện từng dòrg lệnh, đặt điểm dừng, xem giá trị của các b iế n ,
Bộ tạo lập h e a d e r cùa c và cho phép chương trình c gọi các phương thức (hàm) cùa J a v a và ngược lại.
Trinh dịch ngược A s s e m b l e r , hiển thị các phương thức, dữ liệu truy nhập được bên trong của tệp tin c l a s s đã được dịch và hiển thị nghĩa của b y t e c o d e
Các loại chương trình Java
J a v a hỗ trợ để phát triển ba loại chương trình ứng dụng:
■ Chương trình ứng dụng độc lập ( s t a n d a l o n e A p p l i c a t i o n ) ;
■ Chương trình lai ghép, chạy được cả độc lập lẫn a p p l e t
1.4.1 C h ư ơn g trình ứng dụng độc lập
• Mọi chương trình ứng dụng độc lập đều được tạo ra từ các lớp ( c l a s s )
■ Một lớp ( c l a s s ) giống như cấu trúc ( s t r u c t ) trong C /C + + , nhưng khác ở chỗ là c l a s s định nghĩa gộp chung các phương thức xử lý trên dữ liệu trong một đơn vị.
• Để tạo ra một chương trình ứng dụng độc lập trong J a v a , người lập trình phải định nghĩa một lớp có chứa hàm m a in ( )
■ Các mã lệnh trong m a i n O sẽ được thực hiện khi chương trình bắt đầu thực thi.
Quá trình phát triển chương trình ứng dụng độc J a v a với SDK ( S o f t w a r e
1 Soạn thảo chương trình nguồn ( J a v a S o u r c e C o d e ) ghi vào tệp
2 Dịch với j a v a c để tạo ra tệp lớp cùa J a v a là F ile N a m e c l a s s ở d ạn g b y t e c o d e
3 Sử dụng j a v a để thông dịch và cho kết quả cùa chương trình ( J a v a p r o g r a m o u t p u t )
Chúng ta có thể sử dụng chương trình JavaDoc để chuyển đổi tài liệu thành tệp HTML, sử dụng JavaH để chuyển đổi thành tệp đầu của C/C++, và dùng JDB để gỡ lỗi chương trình.
Quá trinh trên được inô tá như hình 1.4. ac.
Hình 1.4 Quá trình phát triển chưcmg trình với SDK
Sau đây là một chương trinh đơn giàn đầu tiên hiển thị một thông báo lên màn hình.
II Chương trình đom giàn đầu tiên P r o g l j a v a c l a s s P r o g l { p u b l i c s t a t i c v o i d m a i n ( S t r i n g a r g s [] ) {
S y s te m o u t p r i n t l n ( "Xin moi cac ban den voi lap trinh J a v a ! ") ; }
Tên file trong Java rất quan trọng vì chương trình biên dịch Java yêu cầu phần mở rộng là java Trong Java, mã lệnh được tổ chức trong các lớp, do đó tên file phải trùng với tên của lớp Ngoài ra, Java phân biệt chữ hoa và chữ thường, tức là tính nhạy cảm với chữ cái.
■ Ta có thể dùng bất kỳ một chương trình soạn thảo nào đấy, ví dụ như
N o te P a d , W ord O f f i c e hay một môi trường phát triển chương trình
J a v a như J C r e a t o r , E c l i p s e , để viết mã nguồn cho mọi chương trình J a v a và lưu lại với tên có đuôi ”.j a v a "
Để biên dịch mã nguồn, chúng ta sử dụng trình biên dịch javac, xác định tên file nguồn qua dòng lệnh Ví dụ: `c:\jdk1.6.2\bin>javac Prog1.java` Trình biên dịch javac, được cài đặt tại thư mục `C:\jdk1.6.2\bin`, sẽ biên dịch file `Prog1.java` và tạo ra file `Prog1.class` chứa mã byte code trong thư mục hiện tại, thường là nơi lưu trữ tệp nguồn Tuy nhiên, các mã này vẫn chưa thể thực thi được.
■ Để chương trình thực thi được ta cần dùng trình thông dịch " J a v a
I n t e r p r e t e r " , lệnh được thực hiện như sau: c : \ j d k l 6 2 \ b i n > j a v a P r o g l Trình thông dịch j a v a được cài đặt ờ thư mục c : \ j d k l 6 2 \ b i n sẽ thông dịch P r o g l ờ thư mục hiện thời để hiền thị thông báo lên màn hinh.
■ Ket quả sẽ hiển thị trên màn hình ( C o n s o le ) như sau:
■ Trong các môi tnrờng phát triển chương trình J a v a như Ơ C r e a to r
E c l i p s e , ta sừ dụng các biểu tượng tuơng ứng với các chức năng biên dịch, thông dịch (thực hiện) chương trình.
■ Khi dịch nếu gặp thông báo lỗi "B ad Command o f í i l e n a m e " hoặc
Tên được chỉ định không được công nhận là một chương trình nội bộ hoặc bên ngoài có thể hoạt động, có nghĩa là hệ thống không tìm thấy trình biên dịch javac Để khắc phục lỗi này, chúng ta cần cập nhật lại đường dẫn PATH của hệ thống.
Một chương trình Java có thể bao gồm nhiều lớp, và sau khi được biên dịch thành công, mỗi lớp sẽ được lưu trữ trong thư mục hiện tại với đuôi class Tên của file chương trình cần phải trùng khớp với tên của lớp chứa hàm main().
P hân tích chư ơng trìnli 1.1:
Dòng // trong chương trình đơn giản đầu tiên Progl.java được sử dụng để thuyết minh và chú thích, từ đó đến hết dòng, trình biên dịch sẽ bỏ qua nội dung này Java cũng hỗ trợ thuyết minh nhiều dòng, bắt đầu bằng /* và kết thúc bằng */, cho phép người lập trình giải thích mã nguồn một cách rõ ràng hơn.
/* Đây là chú thích nhiều dòng
Những vấn để cần chú thích,
Ngoài ra, J a v a còn có các chú thích tài liệu ( D o c u r a e n t a t i o n c o m m e n ts ), bắt đầu với /** và kết thúc với */, ví dụ:
/** Author: Doan Van lnstitute o f In/ormation Technology
Chú thích cuối cùng được trình biên dịch bỏ qua nếu nằm giữa hai dấu sao, và công cụ JavaDoc sẽ sử dụng chúng để tạo ra tài liệu HTML cho mã lệnh của chương trình.
Để khai báo một lớp trong lập trình, ta sử dụng từ khóa "class" theo sau là tên lớp, thường được viết hoa chữ cái đầu của từng từ Tên lớp cũng chính là tên file chứa lớp đó Định nghĩa lớp được đặt giữa hai dấu ngoặc nhọn '{' và '}', đánh dấu sự bắt đầu và kết thúc của khối lệnh.
Phương thức chính của một ứng dụng Java là `public static void main(String args[])`, nơi chương trình bắt đầu và kết thúc quá trình thực thi Tất cả các ứng dụng độc lập đều yêu cầu có một phương thức `main()` để hoạt động.
Từ khóa "public" trong lập trình Java định nghĩa truy xuất công khai, cho phép các thành viên của lớp được truy cập từ bất kỳ đâu trong chương trình Trong trường hợp này, phương thức "main()" được khai báo là "public", vì vậy JVM có thể truy cập và thực thi phương thức này.
Phương thức m a i n () được định nghĩa là tĩnh (s t a t i c), cho phép nó được gọi mà không cần tạo một thể hiện (i n s t a n c e) của lớp Điều này có nghĩa là bản sao của phương thức m a i n () có thể tồn tại trong bộ nhớ mà không cần đến thể hiện của lớp Sự quan trọng của điều này nằm ở chỗ JVM sẽ gọi phương thức m a i n () đầu tiên để thực thi chương trình, vì vậy nó cần phải tĩnh để không phụ thuộc vào các đối tượng của lớp.
- Từ khoá v o i d thông báo cho máy tính biết rằng, phương thức sẽ không trả lại bất cứ giá trị nào khi thực thi chương trình.
- Phương thức m a i n () sẽ thực hiện một số tác vụ của chương trình, nó là điểm mốc mà từ đó tất cả các ứng dụng J a v a được khởi động.
Tham số s t r i n g a r g s [] được sử dụng trong phương thức m a i n ( ) Các biến trong dấu ngoặc đơn nhận thông tin được truyền vào m a i n ( ) Những biến này đóng vai trò là tham số của phương thức Ngay cả khi không có thông tin nào được truyền vào m a i n ( ), phương thức vẫn có thể thực hiện với dữ liệu rỗng trong dấu ngoặc đơn.
- a r g s [] là tên một mảng kiều s t r i n g do người lập trình tự đặt, đó là các đối số ( a r g u m e n t s ) từ các dòng lệnh được lưu vào mảng.
Mã trong phương thức m a in () được đặt giữa hai dấu ngoặc móc { và } được gọi là khối lệnh Tất cả các lệnh cần thực thi trong m a in () phải được viết trong khối lệnh này.
Dòng lệnh `System.out.println("Xin moi cac ban den voi lap trinh Java !");` hiển thị thông báo "Xin moi cac ban den voi lap trinh Java !" trên màn hình khi chương trình được thực thi Phương thức `println()` của `System.out` cho phép hiển thị chuỗi được truyền vào trên màn hình Console Trong đó, `System` là một lớp đã được định nghĩa trong gói `java.lang`, cho phép truy cập vào hệ thống, và `out` là thành phần giúp xuất các chuỗi ký tự ra màn hình.
CÁC THÀNH PHẰN c ơ BẢN CỦA JAVA
Cấu trúc một chương trình J a v a
Các chương trình ứng dụng Java, bao gồm ứng dụng độc lập và Java applet, thường được tổ chức thực hiện theo các dự án Khi phát triển một dự án phần mềm, một thư mục tương ứng sẽ được tạo ra trên máy tính Do tính phức tạp của hệ thống phần mềm, quá trình phân tích và thiết kế thường áp dụng "Nguyên lý chia để trị" để chia nhỏ thành các gói, mỗi gói sẽ được thực hiện bởi một nhóm Mỗi gói được tạo thành một thư mục con và có thể chứa nhiều lớp được lưu trữ trong các tệp, với mỗi lớp bao gồm các thuộc tính và phương thức để xử lý dữ liệu Cấu trúc tổng quát của chương trình ứng dụng Java sẽ theo hình thức này.
Hình 2.1 Cấu trúc tổng quát của chương trinh Java
Phần đầu của một chương trình Java xác định các gói thư viện cần thiết để sử dụng Những gói này được nhập vào chương trình thông qua lệnh "import" Ví dụ, lệnh "import java.awt.*;" sẽ nhập gói java.awt, chứa các lớp và giao diện cần thiết để tạo các đối tượng giao diện đồ họa (GUI - Graphics User Interface) Ký hiệu "*" cho phép truy cập tất cả các lớp và giao diện thuộc gói này.
Triròĩig hợp muốn tạo ra một gói thư viện các lớp, giao diện, ví dụ gói m y P ro g , chúng ta sử dụng câu lệnh sau ờ đầu f i l e chương trình: p a c k a g e m y P r o g ;
Từ khoá package được sử dụng để nhóm các lớp và giao diện trong chương trình thành một gói có tên là myProg Phương pháp này giúp lưu trữ các lớp có đặc tính hoặc hành vi tương tự thành một khối thống nhất Người dùng có thể nhập import gói này vào đầu chương trình của mình khi cần sử dụng.
Trong Java, tất cả mã nguồn, bao gồm biến, phương thức và khai báo, phải được thực hiện trong phạm vi một lớp Do đó, các khai báo và định nghĩa lớp được thực hiện sau lệnh nhập import Một chương trình có thể chứa một hoặc nhiều lớp và giao diện, với khả năng kế thừa từ lớp khác hoặc cài đặt các giao diện Mỗi lệnh trong chương trình kết thúc bằng dấu chấm phẩy Ngoài các câu lệnh, chương trình cũng có thể bao gồm ghi chú và chỉ dẫn, và khi biên dịch, trình biên dịch sẽ tự động loại bỏ các ghi chú này.
Trong tất cả các chương trình, định danh (identifier) được sử dụng để xác định các thành phần của chương trình như biến, tên hàm, và tên trường dữ liệu Trong ngôn ngữ lập trình Java, có sáu loại tên gọi khác nhau.
■ Tên trường dữ liệu, biến thành phần dữ liệu ( f i e l d n a m e s );
■ Tên biến cục bộ kể cả tên biến tham số ( l o c a l v a r i a b l e n a m e s , i n c l u d i n g p a r a m e t e r s ) ;
Việc sử dụng các loại tên trong chương trình Java mang lại sự linh hoạt, cho phép chúng ta áp dụng cùng một tên cho nhiều loại khác nhau Những tên này được phân biệt dựa trên ngữ cảnh của chúng trong không gian tên gọi (namespaces) trong chương trình Ví dụ, trong đoạn mã sau: package Reuse; class Reuse {
Trong lập trình, việc tạo ra gói R e u s e (1) với lớp R e u s e (2) và phương thức R e u s e (3) giúp tổ chức mã nguồn hiệu quả Lớp R e u s e (4) chứa khối lệnh (Block) sẽ được thực hiện nếu điều kiện trong lệnh i f (5) được thỏa mãn Phương thức R e u s e kết thúc và trả về giá trị của tham số R e u s e Để thuận tiện cho việc lập trình, đặc biệt trong các dự án lớn với nhiều nhóm tham gia, cần thống nhất cách đặt tên trong chương trình Tên các phần tử như lớp, hàm, biến, và hằng nên ngắn gọn, đơn giản và phản ánh đúng chức năng của chúng Trong Java, việc đặt tên cần tuân theo các quy ước thống nhất để đảm bảo tính nhất quán và dễ theo dõi.
■ Chi được bắt đầu bằng chữ cái, hoặc một dấu gạch dưới, hoặc một ký lự $.
■ Không có khoảng trắng (dấu cách) giữa tên gọi.
■ Từ ký tự thứ hai, có thể dùng các chữ cái, chữ số, dấu $, dấu gạch dưới.
■ Tên gọi không được trùng với các từ khoá.
■ Có phân biệt chữ in hoa, chữ thường.
N ịp ài ra đế tiện theo dõi, chủng ta quy định thống nhất cách viết tên gọi các lớp, bien, phương thức, như sau:
■ Tên lớp: Tất cả các chữ cái đầu của các từ trong tên lớp đều được viết in hoa
Ví dụ s i n h v i e n là tên cùa lớp sinh viên.
Tên biến đối tượng và biến tham chiếu trong lập trình được quy định tương tự như tên lớp, với điều kiện từ đầu tiên được viết thường Ví dụ, biến tham chiếu đối tượng của lớp SinhVien sẽ được đặt tên là sinhvien.
Hàm (phương thức) trong lập trình tương tự như tên biến, nhưng có thêm cặp ngoặc đơn, còn được gọi là toán tứ hàm Ví dụ, hàm "sinhvien()" được sử dụng để xử lý thông tin về sinh viên Các tên hàm có thể được phân biệt dựa trên số lượng tham số và kiểu dữ liệu của các tham số, tạo thành định danh hay chữ ký hàm (function signature).
■ Tên đại lượng hằng: Tất cả các chữ cái đều viết hoa, ví dụ P I ià số n bất biến trong chương trình.
Với quy ước đặt tên thống nhất, việc phân biệt tên lớp, biến, hàm và hằng trở nên dễ dàng mà không cần thêm chú thích Hầu hết các gói thư viện trong JDK và mã nguồn mở đều tuân theo quy ước này.
Tóm lại, cấu trúc cơ bản của một tệp mã nguồn J a v a có cấu trúc như sau:
[p a c k a g e p a c k a g e N a m e ; ] // Khai báo tên gói, tuỳ chọn
[ i m p o r t j a v a a w t * ; ] // Khai báo tên thư viện sẵn có, nếu cần dùng // Khai báo và định nghĩa các lớp dạng
// Khai báo hoặc định nghĩa các hàm, phương thức
// Khai báo các giao diện dạng
[Bồ n g h ĩ a ) i n t e r í a c e I n t e r f a c e N a m e [ e x t e n d s A n y l n t e r f a c e ] { // Định nghĩa các đại lượng hằng
// Chi khai báo các hàm (prototype): chì có định danh mà không có thân hàm
• Thứ tự các câu lệnh khai báo các biến, lớp, giao diện là không quan trọng.
Cặp dấu ngoặc '[' và ']' trong cú pháp C/C++ được sử dụng để chỉ định nội dung tùy chọn, có thể có hoặc không cần thiết.
Tùy chọn [Bổ sung nghĩa] (modifier) cho phép sử dụng các từ khóa bổ trợ để xác định phạm vi của lớp và giao diện, bao gồm các từ khóa như: public và abstract Từ khóa public cho phép lớp và giao diện được sử dụng ở mọi nơi, trong khi abstract chỉ định lớp hoặc giao diện trừu tượng Đối với lớp, tùy chọn này có thể được khai báo là lớp cuối (final).
Tùy chọn [extends AnyClass] được sử dụng khi cần xây dựng một lớp kế thừa từ một lớp cha đã có trong các gói thư viện hoặc trong chương trình là AnyClass Nếu không sử dụng tùy chọn này, mặc định lớp sẽ kế thừa từ lớp Object trong gói java.lang Điều này có nghĩa là mọi lớp trong chương trình Java đều là lớp con của một lớp nào đó, tạo thành cấu trúc cây với gốc là lớp Object.
Tùy chọn [implements Interface List] cho phép cài đặt các hàm đã được khai báo nhưng chưa định nghĩa nội dung thực hiện trong danh sách các giao diện Interface List Danh sách này có thể bao gồm một hoặc nhiều giao diện, được phân cách nhau bằng dấu phẩy.
■ Tuỳ chọn [ e x t e n d s A n y l n t e r f a c e ] sừ dụng khi cần khai báo một giao diện kế thừa giao diện A n y l n t e r f a c e
Khi biên soạn chương trình, chúng ta cần chỉ rõ tên file chương trình Java, thư mục hiện tại, thư mục lưu trữ các file nguồn và thư mục lưu kết quả Thông thường, cả ba thư mục này đều được đặt chung một đường dẫn, được gọi là thư mục hiện tại.
Chương trình úmg dụng J a v a có thể có nhiều f i l e chương trình Một f i l e chương trình có thể có nhiều lớp, giao diện được dịch và lưu ở thư mục hiện thời
• Tên của f i l e chương trình J a v a phải trùng với tên một trong số các tên của lớp, giao diện của nó.
■ Mỗi f i l e chương trình J a v a chi có đúng một lớp hoặc giao diện được khai báo p u b l i c và khi đó tên cùa lớp, giao diện đó phải trùng với tên f i l e
Các kiểu dữ liệ u
Biến trong lập trình là một thành phần quan trọng, được sử dụng để lưu trữ giá trị thông qua tên gọi của nó Giá trị của biến có thể thay đổi thông qua các phép gán, cho phép lập trình viên linh hoạt trong việc xử lý dữ liệu.
Biến dữ liệu thành phần lớp là những biến được khai báo trong lớp nhằm lưu trữ thông tin đặc trưng về các thuộc tính của đối tượng Có hai loại biến thành phần chính.
1 Biến khai báo với kiểu dữ liệu nguyên tliuỷ được gọi là biến kiểu nguyên thuỷ, gọi tắt là biến nguyên thuỷ\
2 Biến khai báo với kiểu là lóp được gọi là biển tham chiếu.
• l i té rí cục bộ là bién chi có thẻ ưuy xuất trong khối lệnh nó được khui báo
Biến cục bộ thường được sử dụng trong thân phương thức để xác định nội dung công việc của chương trình Chúng có thể là biến kiểu nguyên thủy hoặc biến tham chiếu.
Cú pháp khai báo biến cục bộ là:
• Tuỳ chọn [Bổ n g h ĩ a ] có thể là f i n a l để xác định biến cục bộ v a rN a m e khi đã gán giá trị thì sẽ trở thành bất biến
■ D a t a T y p e là kiểu dữ liệu cùa biến.
■ v a r N a m e là tên biến cục bộ.
Ví dụ, biến s v khai báo trong hàm m a in () ờ chương trình 2.4 là biến tham chiếu cục bộ.
Hình 2.4 Các kiểu nguyên thuỳ (Primitive type)
Các kiểu nguyên thuỳ được định nghĩa thông qua độ dài các b i t , và phạm vi xác định như bảng 2.2.
Bàng 2 2 Các kiểu nguyên thuỷ
Kiểu dữ liệu Độ dài
(số bit) Phạm vi biểu diễn già tri Mô tả b y te 8 -12 8 đến +127
Số liệu kiểu byte là một dạng điển hình để lưu trữ giá trị bằng một byte, thường được áp dụng trong việc xử lý các tệp văn bản Giá trị mặc định của kiểu dữ liệu này là 0, với mã ký tự từ 0 đến 255.
Kiéu c h a r sử dụng đế lưu tên hoặc các dữ liệu ký tự Giá trị mặc đinh lá 0 b o o le a n 1 "true" hoặc "íalse”
Dữ liệu b o o le a n dùng để lưu các giá trị "tru e " ("Đúng”) hoặc " fa ls e " ("sai") Giá trị mặc định là "fa ls e " s h o rt 16 -32 768 đến 32 767
Kiểu short dùng để lưu các số có giá trị nhỏ dưới 32 767 Giá trị mặc đinh là 0 i n t 32 -2 147 483 648 đến
Kiểu i n t dùng đẻ lưu một số có giá trị lởn đến 2 147 483 648 Giá trị mặc định là 0 lo n g 64 -2 m đến +2m-1
Kiểu lo n g được sử dụng để lưu một số cố giá tri rất lớn đến 2 ^ - 1 Giá trị mặc định là 0L f l o a t 32 -3.40292347E+38 đến
Kiểu f l o a t dùng để lưu các số thập phân đến 3.40292347E+38 Giá trị mặc định lả 0 0F đ o u b le 64
Kiểu d o u b l e dùng để lưu cảc số thập phân có giá trị lớn đển
1,79769313486231570E+308 Giá trị mặc định là 0.0D
Tất cả các kiểu nguyên thủy đều xác định hai giá trị cực tiểu và cực đại thông qua tên lớp bao gói (Wrapper) bằng cách viết hoa chữ cái đầu tiên.
S h o r t MAX_VALUE và s h o r t MIN_VALUE. Đối với kiểu i n t giá trị cực tiếu là I n t e g e r MIN_VALUE, còn giá trị cực đại là I n t e g e r MAX_VALUE.
■ Các giá trị số thập phân trong J a v a được mặc định là kiểu d o u b l e Ví dụ: f l o a t X = 3 1 4 ;
// Sai cú pháp vì 3.14 mặc định là kiểu d o u b l e mà gán cho kiểu
// f l o a t 4 b y t e sẽ bị mất thông tin Lệnh trên phải viết như sau f l o a t X = 3 1 4 F ; // Ép 3.14 về kiểu f l o a t
> C hư ơ ng trình 2.5: Viết chương trình hiên thị tất cả các số nguyên tố < N N được nhập vào từ bàn phím.
// Chương trình P rim e j a v a i m p o r t j a v a i o * ; i m p o r t j a v a u t i l S c a n n e r ; // Sứ dụng S c a n n e r để đọc dữ liệu p u b l i c c l a s s P r i m e { p u b l i c s t a t i c v o i d p r i m e ( i n t n) { // Tìm các số nguyên tố < n i n t l i m , d, k, num; // Biến cục bộ nguyên thuỷ f o r ( k = 2 ; k < n ; k+ + ) { d = 2 ; num = 0 ; l i m = ( i n t ) Math s q r t (k); / / Tính căn bậc hai cúa k
// và ép về kiểu i n t w h i 1 o (d < — lỉ m ) { i f ( k % d = = 0 ) j n u m + + ; b r e a k ; } e l s e d + + ;
// Khai báo và định nghĩa biến cục bộ tham chiếu s c a n để đọc dữ liệu vào từ bàn phim
S y s t e m o u t p r i n t ( ' ' Cho b i e c N = ") ; i n t n = s c a n n e x t l n t () ; // n là biến nguyên thuý
'Prong J a v a , có ba kiểu tham chiếu đối tượng là:
■ a r r a y : c ấ u trúc mảng cùa các dữ liệu cùng kiểu.
■ c l a s s : Dữ liệu kiểu lớp đối tượng do người dùng định nghĩa, bao gồm các thuộc tính và phương thức.
■ i n t e r f a c e : Dữ liệu kiểu lớp giao tiếp do người dùng định nghĩa, khai báo các phương thức cùa giao tiếp.
2.3.3 Các quy tắc chuyển đổi kiểu
Khi thực hiện các phép toán hai ngôi trong Java, như phép gán, phép số học và phép so sánh, cần chuyển đổi các kiểu dữ liệu khác nhau về cùng một kiểu trước khi thực hiện phép toán Trong Java, có hai quy tắc chuyển đổi kiểu dữ liệu cần lưu ý.
Mở rộng kiểu (widening) là quá trình chuyển đổi giá trị từ kiểu dữ liệu hẹp hơn, với số lượng byte và phần tử ít hơn, sang kiểu dữ liệu rộng hơn, có số lượng byte và phần tử nhiều hơn Quy trình này được gọi là mở rộng kiểu mặc định, và quy tắc mở rộng kiểu nguyên thủy được mô tả như sau: byte -> short.
Quy tắc mở rộng kiểu mặc định cho phép các biến tham chiếu từ lớp con tự động mở rộng sang lớp cha Ví dụ, khi khởi tạo biến char a = 1 và int k = a, kiểu dữ liệu sẽ được mở rộng theo quy tắc đã nêu.
// Định nghĩa lớp về nhân sự c l a s s C a n B o e x t e n d s N h a n S u {
// Lớp C anB o kế thừa, lớp con cùa N h a n S u
// Kế thừa, bổ sung các thuộc tính về cán bộ
// N ạp chồng, viết đè hay bổ sung thêm hàm mới
N h a n S u n s = new N h a n S u ( ) ; // Tạo lập đối tượng n s
C anB o c b = n ew C an B o ( ) ; // Tạo lập đối tượng c b n s = c b ; // Mờ rộng kiểu mặc định biến tham chiếu
Thu hẹp kiểu (narrowing) là quá trình chuyển đổi từ kiểu dữ liệu rộng sang kiểu hẹp hơn, ngược lại với mở rộng kiểu Cần lưu ý rằng thu hẹp kiểu có thể dẫn đến mất thông tin, vì vậy việc thực hiện ép kiểu cần phải được thực hiện một cách tường minh để đảm bảo dữ liệu không bị mất mát.
Quy tắc ép kiểu có dạng: (< T y p e > ) < e x p >
Lúc thực hiện, hệ thống sẽ chuyển kết quả tính toán của biểu thức < e x p > sang kiểu được ép là < T y p e>
Ví dụ: l o n g n = 1 2 0 ; i n t k = ( i n t ) n ; // Ép n kiểu l o n g về kiểu i n t f l o a t f = 2 5 f ; // Ép 2.5 mặc định kiểu d o u b l e về f l o a t c b = (C anB o) n s ; // Ép ns là đối tượng cùa lớp N h a n S u về lớp C an B o
• Không cho phép chuyển đồi giữa các kiểu nguyên thuỷ với kiểu tham chiếu, ví dụ kiểu d o u b l e không thê ép sang các kiểu lóp như CanBo và ngược lại.
■ Kiểu giá trị b o o l e a n ( l o g i c ) không thể chuyển sang các kiểu dữ liệu khác và ngược lại.
• Ngũ cành phải thực hiện chuyền đối kiểu:
- Thực hiện các phép gán đối với các biến kiểu nguyên thuỷ hoặc kiểu tham chiếu;
- Thực hiện các lời gọi hàm (phương thức) với các tham biến kiểu nguyên thuỷ hay kiểu tham chiếu;
- Thực hiện tính toán các biều thức số học.
• Ghép các xâu kết hợp các đối lượng cùa lóp s t r i n g và các kiểu dữ liệu khác.
Các phép toán trong J a v a
Các phép toán (operator) kết hợp các giá trị đơn hoặc các biểu thức con để tạo ra những biểu thức mới phức tạp hơn, có khả năng trả về giá trị Java đã cài đặt nhiều phép toán để hỗ trợ các thao tác này.
Hai ngôi là khái niệm liên quan đến việc tác động vào hai đối số có kiểu tương thích với nhau Hai kiểu được coi là tương thích nếu chúng có thể chuyển đổi về cùng một kiểu một cách ngầm định Vấn đề chuyển đổi kiểu sẽ được đề cập trong phần sau.
■ Ba ngôi: Có ba đối số; gồm phép ?,
J a v a cung cấp nhiều dạng toán tử như:
2.4.1 C ác toán tử sổ học
Các toán hạng trong số học phải được biểu diễn dưới dạng số Mặc dù các toán hạng kiểu boolean không thể sử dụng, nhưng các toán hạng ký tự cho phép áp dụng loại toán tử này Một số kiểu toán tử được trình bày trong bảng 2.3.
Bàng 2.3 Các toán tử số học
Phép cộng hai ngôi cho phép xác định giá trị tổng của hai toán hạng có kiểu tương thích Ví dụ, phép tính 5 + 3 cho kết quả là 8, trong khi phép toán một ngôi +10 trả về giá trị 10.
Phép trừ trong toán học có thể được thực hiện theo hai cách: phép trừ hai ngôi và phép đối dấu một ngôi Phép trừ hai ngôi trả về hiệu của hai toán hạng có kiểu tương thích, ví dụ như 5 - 3 cho kết quả là 2 Trong khi đó, phép toán một ngôi với dấu trừ, như -10, sẽ trả về giá trị âm của số đó.
* Phép nhãn tính tich của hai toán hạng tương thích với nhau
/ Phép chia tinh thương cùa hai toán hạng tương thich với nhau
% Phép lấy modulo: Giá trị trả về là phần dư của phép chia
Vi dụ: 10 % 3 giá trị trả về là 1
+ + Phép toán một ngôi: Tăng giá tri của biến lên 1 Ví dụ: a++ tương đương với a = ã + 1
Phép toán một ngôi: Giảm giá trị của biến 1 đơn vị Vi dụ: a~ tương đương với a = a - 1
Phép cộng và gán giá trị là quá trình cộng các giá trị của toán hạng bên trái với toán hạng bên phải, sau đó gán kết quả trả về vào toán hạng bên trái.
Trừ và gán giá trị là quá trình thực hiện phép trừ giữa các giá trị của toán hạng bên trái và bên phải, sau đó gán kết quả trở lại cho toán hạng bên trái.
Ví dụ: c -= a tương đương với c = c - a
* _ Nhân và gán: Nhân các giá trị của toán hạng bên trái với toán hạng bên phải vá gán giá trị trả về vào toán hạng bên trái
Ví dụ: c *= a tương đương với c = c * a
/ - C h ia và gán: C h ia gió trị c ù a toán h ạ n g bôn trái cho to á n họng bôn phài vó gán giá trị trả về vào toán hạng bẽn trái
Ví dụ: c /= a tương đương với c = c / a
% = Lấy số dư và gán: Chia giá trị của toán hạng bẽn trái cho toán hạng bên phải và gán giá trị số dư vào toán hạng bẽn trái
Ví dụ: c %= a tương đương với c = c % a
■ Phép chia trong J a v a phân biệt phép chia nguyên và chia số thực.
— Phép chia nguyên : Khi cà hai đối số là kiểu nguyên, phép chia này sẽ không xác định (tràn ô - O v e r l o a d ) khi mẫu số là 0.
Phép chia số thực được thực hiện khi có ít nhất một đối số là kiểu số thực, và luôn cho kết quả là một số thực Nếu mẫu số bằng 0.0, kết quả sẽ là Infinity (số vô cùng), trong khi nếu cả tử số và mẫu số đều bằng 0.0, kết quả sẽ là NaN (không xác định).
■ Phép "%" cho phép lấy m o d u lo của cả số nguyên lẫn số thập phân Ví dụ: f l o a t k = 13.5 % 3.0; // Cho giá trị k là 1.5
■ Phép tăng ++, giảm - - một ngôi áp dụng cho tất cả các kiểu số (số nguyên lẫn số thực) Các phép toán ++X ( - - x ) sẽ tăng (giảm) giá trị cùa X lên
(xuống) 1 trước khi tính giá trị của biểu thức chứa nó Ngưọc lại, phép toán
Khi sử dụng toán tử tăng trước (++) trong biểu thức, giá trị của biến X sẽ được tăng lên 1 trước khi thực hiện phép toán Ví dụ, với k = 4 và n = 10, khi tính toán với int m = ++k * n, giá trị của k sẽ trở thành 5 trước khi nhân với n, dẫn đến m = 50 Ngược lại, khi sử dụng toán tử tăng sau (k++), phép nhân sẽ được thực hiện với giá trị hiện tại của k, tức là 4, và sau đó k sẽ tăng lên 1, trở thành 6, nhưng giá trị của m vẫn là 40.
> C hương trình 2.6: Chương trình sau mô tà việc sử dụng toán lừ số học.
// SoHoc j a v a p u b l i c c l a s s S o Ho c { p u b l i c s t a t i c v o i d m a i n ( s t r i n g a r g s [] ) { i n t p = 5, q = 12, r = 20, s ; // Khai báo và gán trị khới đẩu
S y s te m o u t p r i n t l n ( "Gia tri p truoc phep gia tang: " + p ) ;
S y s t e m o u t p r i n t l n í "Gia tri p sau phep gia tang: 11 + p) ;
S y s te m o u t p r i n t l n ( "Truoc khi thuc hien: s = p * ++q \ n p = "
Thực hiện chương trình cho kết quả như hình 2.6.
Hinh 2.6 Kết quà cùa chưong trình 2.6
Các phép toán trên bit, hay còn gọi là phép toán bit, cho phép thao tác riêng biệt trên từng bit trong các kiểu dữ liệu nguyên thuỷ Những phép toán này dựa trên cơ sở đại số, giúp thực hiện các tính toán và xử lý dữ liệu hiệu quả.
B o o l e Nó thực hiện phép tính trên hai b i t có vị trí tương ứng trên hai toán hạng để tạo ra một kết quả mới.
Bàng 2.4 Các phép toán trẽn bit
~ Phủ định b i t (NOT): Phép toán một ngôi
Trả vẻ giá trị âm của một số Vi dụ: a = 10 thi ~a = -10
Toán tử A N D trên 2 bit trả về giá trị 1 nếu cả hai toán hạng đều là 1, và 0 trong các trường hợp khác Hai đối số được chuyển về cùng kiểu tương thích và biểu diễn dưới dạng nhị phân, phép & thực hiện trên hai dãy bit đó Toán tử OR trên 2 bit trả về giá trị 0 nếu cả hai toán hạng đều là 0, và 1 trong các trường hợp khác Tương tự, hai đối số cũng được chuyển về cùng kiểu tương thích và biểu diễn dưới dạng nhị phân, phép | thực hiện trên hai dãy bit đó.
Toán tử XOR trên 2 bit trả về giá trị 1 nếu chỉ một trong các toán hạng là 1 và 0 trong các trường hợp khác Hai đối số, là các số nguyên, sẽ được chuyển về cùng kiểu tương thích và biểu diễn dưới dạng nhị phân Phép toán này thực hiện trên hai dãy các bit đó.
Dịch sang phải ằ là quá trình chuyển toàn bộ các bit biểu diễn nhị phân của một số nguyên (đối số thứ nhất) sang phải n vị trí (đối số thứ hai), trong đó giữ nguyên dấu của số âm Toán hạng bên trái là số bit cần dịch, còn số bên phải là chỉ số vị trí mà các bit cần dịch.
Vớ dụ: X = 31 cú biểu diễn nhị phõn là 00011111, vậy X ằ 2 sẽ kết quả dạng nhị phản là 00000111
Chuyển toàn bộ các bit biểu diễn nhị phân của một số nguyên sang phải n vị trí, trong đó n là chỉ số vị trí cần dịch, và điền bit 0 vào vị trí bit trái nhất Toán hạng bên trái là số bị dịch, còn số bên phải là chỉ số vị trí mà các bit cần dịch.
Vớ dụ: X = -120 cú biểu diễn nhi phõn lỏ 10000111, vậy X ằ > 2 sẽ kết quả dạng nhi phân lá 0100001
Dịch sang trái là quá trình chuyển toàn bộ các bit biểu diễn nhị phân của một số nguyên sang trái n vị trí, trong đó giữ nguyên dấu của số âm Toán hạng bên trái là số bị dịch, trong khi toán hạng bên phải là số chỉ vị trí mà các bit cần được dịch.
Vi dụ: X = 31 cú biểu diễn nhị phõn là 00011111, vậy X ô 2 sẽ kết quả dạng nhị phân lả 011100.
> C hương trình 2.7: Chương trình sau minh hoạ các phép toán trên b i t
Thực hiện chương trình 2.7 cho kết quả như hình 2.7.
,< i u ^ à 4 ia ỏ A , ^iwà-ôf.igMjỊggỏ^ỊaM
Hinh 2.7 Kết quá chương trình tính trên bít
2.4.3 Các toán tủ' quan hệ
HƯỚNG ĐỒI TƯỢNG TRONG JAVA 3.1 Giới th iệ u
Phạm vi và thuộc tính kiểm soát truy nhập các thành phần của lớp
Trong lập trình hướng đối tượng, lớp được sử dụng để bao gói và che giấu thông tin, tạo thành một tập hợp các đối tượng trong chương trình Java Các đối tượng này tương tác với nhau thông qua các phương thức để thực hiện yêu cầu của chương trình Do đó, việc quản lý các thành phần của lớp, bao gồm biến thành phần dữ liệu và hàm thành phần, là rất quan trọng Chúng ta sẽ xem xét các quy tắc quản lý truy cập tới những thành phần này trong Java.
3.3.1 Phạm vi của các thành phần trong chưong trình Java
Phạm vi xác định của các thành phần trong chương trình được chia thành hai loại:
■ Phạm vi lớp của các thành phần;
■ Phạm vi khối cùa các biến cục bộ ( l o c a l ) a) P hạm vi lớp
Chương trình Java bao gồm các lớp, với phạm vi lớp xác định các thành phần truy cập bên trong lớp và các lớp kế thừa Quyền truy cập này thường được quản lý thông qua các bộ điều chỉnh (modifier) như public, protected, mặc định hoặc private.
Bên trong định nghĩa của lớp, các biến tham chiếu đến chính lớp đó có quyền truy cập tất cả các thành phần của nó mà không cần quan tâm đến các bồ nghĩa của chúng.
> Cliương trình 3.3: Xây dựng lớp B o n g D e n có các thành phần được che giấu, c l a s s BongDen{
//Các biến thành phần lớp được che giấu p r o t e c t e d i n t s o V ỉ a t t s ; // số w a t t s cùa bóng đèn p r i v a t e b o o l e a n b a t T a t = f a l s e ; // t r u e - bóng sáng, mặc định f a l s e - tát p u b l i c s t r i n g v i T r i ; // Nơi đặt bóng đèn
// Các hàm thành phần p u b l i c v o i d b a t D e n () { b a t T a t = t r u e ; } // Bật đèn p u b l i c v o i d t a t D e n () { b a t T a t = f a l s e ; } // Tắt đèn p u b l i c b o o l e a n t a t H a y S a n g () {r e t u r n b a t T a t ; }
//Tạo ra bóng đèn mới bằng cách nhân đôi hay c o p y p u b l i c BongDen n h a n D o i (B ongD en bon g C u ) { // (1) BongDen b o n g M o i = n e w BongDen () ; b o n g M o i s o W a t t s = b o n g C u s o W a t t s ; // (2) b o n g M o i b a t T a t = b o n g C u b a t T a t ; // (3) b o n g M o i v i T r i = new s t r i n g ( b o n g C u v i T r i ) ; // (4) r e t u r n b o n g M o i ;
Hàm n h a n D o i 0 ở lớp B o n g D e n có tham biến b o n g C u và biến cục bộ b o n g M o i đều tham chiếu tới lớp B o n g D e n Các biến thành phần s O W a tts, b a t T a t, v i T r i mặc dù là p r i v a t e nhưng vẫn cho phép truy nhập đối với cả hai tham chiếu trên trong cùng lớp.
Luật phạm vi quy định rằng một biến được khai báo trong một khối có phạm vi xác định bên trong khối đó, trong khi phạm vi bên ngoài khối là không xác định.
■ Quan hệ lồng nhau cùa các khối lệnh có tính chất bắc cầu.
■ Trong cùng một phạm vi không thể khai báo một biến hai lần Các tham biến cũng không thể khai báo lại trong thân của hàm.
Trong các khối mã, thứ tự khai báo lệnh là linh hoạt, không bị ràng buộc, và có thể thực hiện ở bất kỳ vị trí nào Tuy nhiên, cần lưu ý rằng các lệnh phải được khai báo trước khi được sử dụng.
■ Phạm vi khối của biến được xác định kể từ chỗ khai báo bên trong khối cho đến kết thúc khối.
Có thể có nhiều khối lồng nhau, như các khối giao nhau, và các biến khai báo trong khối ngoài đều có phạm vi xác định trong mọi khối bao bên trong nó.
■ Các biến điều khiển khai báo trong chu trình lặp f o r là cục bộ ( L o c a l )
> C hư ơ n g trình 3.4: Xét một chương trình có các khối lồng nhau như sau: c l a s s K h o i L o n g { p u b l i c s t a t i c v o i d m a in ( s t r i n g [] a r g s ) {// Khối 1 c h a r c = 20 ; //(1) f o r ( i n t ỉ = 0 ; i < 1 0 ; i+ + ) { // Khối 2
Chương trình 3.4 có 5 khối Khối 2, 5 lồng trong khối 1; khối 3, 4 lồng trong khối
Trong đoạn mã, biến k không được khai báo trong cùng khối, dẫn đến lỗi ở (2) Tương tự, ở (3) và (4), biến c đã được khai báo ở (1) và biến i đã được khai báo trong khối 2 của vòng lặp for, do đó cũng gây ra lỗi Biến i được khai báo là cục bộ trong khối 2 và khối 5, vì vậy chúng không ảnh hưởng lẫn nhau.
3.3.2 Các thuộc tính kiểm soát truy nhập các thành phần của lớp
Phương pháp hướng đối tượng mang lại ưu điểm nổi bật trong việc tổ chức dữ liệu thông qua nguyên lý đóng gói và che giấu thông tin Các thuộc tính và hàm thành phần của lớp có thể được khai báo với các bổ ngữ nhằm kiểm soát quyền truy cập Khi thiết kế các thành phần của lớp đối tượng, việc sử dụng các bổ nghĩa là rất quan trọng.
■ T h â n t h i ệ n (mặc định, không sứ dụng thêm bồ nghĩa cho các thành phần của lớp);
Trong phần thảo luận này, chúng tôi sử dụng một số ký hiệu của UML (Ngôn ngữ Mô hình Hợp nhất) để minh họa Ký hiệu ' + ' đại diện cho thuộc tính public, ký hiệu ' # ' cho protected và ký hiệu ' - ' cho private Các thành phần public được thể hiện rõ ràng để người dùng dễ dàng nhận biết.
Thuộc tính public xác định tính công khai của các thành phần trong lớp Các thành phần được khai báo là public cho phép truy cập từ mọi nơi trong hệ thống, bao gồm cả các lớp trong cùng gói và các lớp ở các gói khác.
> Chương trình 3.5: Tính công khai ( p u b l i c ) của các thành phần trong lớp.
/ / Tệp S u p e r c l a s s A j a v a (I) p a c k a g e g o i A ; // Định nghĩa gói có tên g o i A p u b l i c c l a s s S u p e r c l a s s A { // Lớp cha
> c l a s s A n y C l a s s A { // Định nghĩa lớp bất kỳ
/ / Tệp: SubclassB.java (6) p a c k a g e g o i B ; // Lập g o i B im p o r t g o iA * ; // Nhập các lớp đã được định nghĩa ờ gói có tên go iA
// Định nghĩa lớp con kế thừa từ lớp ở g o iA p u b l i c c l a s s S u b c l a s s B e x t e n d s S u p e r c l a s s A { v o i d s u b c l a s s M e t h o d B ( ) { s u p e r c l a s s M e t h o d A ( ) ; } // (7) c l a s s A n y C l a s s B {}
Chương trình 3.5 có hai tệp nguồn gồm hai gói các lớp được định nghĩa ờ (1) và
Các lớp trong gói q o i B có thể truy cập các thành phần public của lớp trong gói g o i A Lớp Superclass A trong gói g o i A có hai lớp con: Subclass A trong gói g o i A và Subclass B trong gói g o i B Khả năng truy cập các thành phần public giữa hai gói này được minh họa trong hình 3.2.
Lớp con trong cùng gói có khả năng truy cập biến công khai của lớp cha, như biến super class Var A Điều này xảy ra do các biến được khai báo công khai trong lớp cha sẽ được kế thừa cho các lớp con của nó.
■ K h a c h 2 : Từ những lớp không kế thừa cùa lớp S u p e r c l a s s A , nhưng trong cùng gói thì vẫn có thề truy nhập được tới thành phần công khai s u p e r c l a s s M e t h o d A () như ở (5);
Lớp con, mặc dù không nằm trong gói, vẫn có khả năng truy cập vào phương thức công khai của lớp cha, cụ thể là hàm `superclassMethodA()` Điều này xảy ra vì các phương thức được khai báo công khai trong lớp cha được kế thừa cho tất cả các lớp con của nó.
■ K h a c h 4 : Từ những lớp không kế thừa cùa lóp S u p e r c l a s s A và ờ khác gói thì vẫn có thể truy nhập được tới thành phần công khai s u p e r c l a s s V a r A nhir ở (8). p u b l i c i n t s u p e r c l a s s V a r A ; // (2) p u b l i c v o i d s u p e r c l a s s M e t h o d A () { / * * / } //(3 )
Hình 3.2 Khả năng truy cập mọi nơi của thành phằn public
Tóm lợi: Các thành phần khai báo p u b l i c trong lớp có miền xác định rộng nhất, có thề nhìn thấy ờ mọi nơi trong chương trình. b) C ác th à n h p hần protected
Các tham số của chương trình
Giống như chương trình của C /C ++, ta có thể truyền các tham số cho hàm m a in () để thực hiện chương trình trên dòng lệnh, ví dụ: j a v a T in h T o n g 12 23 45
Chương trình j a v a thông dịch lớp T in h T o n g để tính tồng các đối số 12, 23, 45 Chương trình T in h T o n g có thể viết như sau:
> Chương trình 3.18: Truyền tham số cho chương trình.
//Chuyến dãy chữ số (xâu) thành số s += I n t e r g e r p a r s e l n t ( a r g s [ i ] ) ; // (2)
Khi thực hiện chương trình cho kết quá
■ Danh sách các tham số của chương trình là dãy các xâu (chuỗi ký tự) ờ ( I ).
■ Để chuyển một xâu ” 12" thành số 12 thì sử dụng
Danh sách các tham số của chương trình, hay còn gọi là tham số của hàm main(), được lưu trữ trong một mảng args Trong Java, mảng được xem như một đối tượng và có thuộc tính length để xác định số phần tử của mảng.
Phương thức tạo lập đối tư ợ ng
Mục đích chính cùa phương thức tạo lập ( C o n s t r u c t o r ) là thiết lập các giá trị cho các đối tượng khi một đối tượng được tạo ra bằng toán từ new.
Toán tữ tạo lập của một lớp có dạng:
// Nội dung cần thiết lập
■ Tuỳ chọn [Bổ n g h ĩ a ] có thể chọn p u b l i c , p r o t e c t e d , p r i v a t e hoặc mặc định như đã trình bày ờ phần trên đối với phương thức thành phân.
■ C la s s N a m e : Tên lớp luôn trùng với tên của toán tử tạo lập.
■ Tuỳ chọn [ P a r a m L i s t ] là danh sách các tham số hình thức cùa phương thức tạo lập.
Một số lim ỷ đối với các toán từ tạo lập;
■ Không sử dụng các bổ ngữ khác với phưong thức tạo lập.
■ Phương thức tạo lập là loại hàm đặc biệt không có kiểu trà lại, ngay cá kiểu v o i d cũng không được sử dụng.
■ Phương thức tạo lập chi sừ dụng được với toán tử new để tạo lập các đối tượng cùa lớp.
3.6.1 P h ư ơn g thức tạo lập mặc định
Phương thức lạo lập mặc định ( d e f a u l t c o n s t r u c t o r ) là phương thức tạo lập không có tham số:
Khi một lớp không định nghĩa phương thức tạo lập, hệ thống sẽ tự động cung cấp một phương thức tạo lập mặc định không tường minh Phương thức này tương đương với dạng mặc định mà hệ thống cung cấp.
C la s s N a m e 0 { } / / Khởi tạo mặc đjnh
Trong đó, các biến thành phần được gán giá trị mặc định.
Lim ý: Cách gán giá trị mặc định được quy định như sau:
■ Các biến kiểu nguyên ( b y t e , s h o r t , i n t , l o n g ) có giá trị khởi tạo mặc định lả 0.
■ Các biến kiểu số thực ( f l o a t , d o u b l e ) có giá trị khới tạo mặc định là 0.0.
• Các biến b o o l e a n có giá trị khời tạo mặc định là f a l s e
■ C á c b iến t h a m c h iế u (đ ố i tư ợ n g , m ả n g ) c ó gi á trị khởi t ạ o m ặc đ ịn h là r u i l 1,
Ví dụ dưới đây trong lớp B o n g D e n không định nghĩa toán lừ tạo lập và khi tạo lập đối tượng thì sử dụng toán tử tạo lập không tường minh. c l a s s B o n g D e n Ị
// Không định nghĩa phương thức tạo lập
B o n g D e n d e n l = n ew B ongD enO ; // Gọi phương thức tạo lập mặc định
Phương thức tạo lập mặc định không tường minh được hệ thống cung cấp:
Khi sử dụng toán tử new để tạo đối tượng, các biến kiểu nguyên thủy như s o W a t t s, b a t T a t và v i T r i sẽ được khởi tạo với các giá trị mặc định là 0, false và null.
Khi xây dựng lớp trong lập trình, chúng ta có thể định nghĩa phương thức tạo lập mặc định bằng cách gán các giá trị cụ thể cho các biến dữ liệu Ví dụ, trong lớp BóngĐèn, chúng ta có thể thiết lập các thuộc tính khởi tạo cho đối tượng.
// Định nghĩa phương thức tạo lập mặc định
// Gọi phương thức tạo lập mặc định tường minh
Khi một lớp đã định nghĩa một hoặc nhiều phương thức tạo lập, hệ thống sẽ không cung cấp phương thức tạo lập mặc định một cách tự động Do đó, để sử dụng phương thức tạo lập mặc định, bạn cần phải định nghĩa rõ ràng phương thức này Ví dụ: class BongDen {
// Định nghĩa phương thức tạo lập không mặc định
// Sai vì phương thức tạo lập mặc định chưa định nghĩa
B o n g D en d2 = n ew B on g D en (1 0 0 , t r u e , "N ha b e p " ) ; // OK.
3.6.2 Nạp chồng p h ư ơ n g thức tạo lập
Giống như các hàm thành phần, phương thức tạo lập có thể nạp chồng với nhiều nội dung thực hiện khác nhau dựa trên các tham số khác nhau Chẳng hạn, trong lớp Bóng Đèn, phương thức tạo lập Bóng Đèn có định nghĩa mặc định rõ ràng, đồng thời cũng được nạp chồng để khởi tạo đối tượng với các giá trị xác định khác.
// Định nghĩa phương thức tạo lập mặc định
// Dịnh nghĩa phương thức tạo lập không mặc định
BongDen dl= new BongDen () ; // OK.
> C hư ơ ng trình 3.19: Xây dựng lớp T im e (thời gian) có các thuộc tính h o u r
(giờ), m i n u t e (phút) và s e c o n d (giây) được che giấu Thời gian thường được hiển thị theo hai cách:
■ Thời gian phổ dụng ( u n i v e r s a l - t i m e ) có dạng h h : mm: s s
• Thời gian chuẩn ( s t a n d a r d - t i m e ) có dạng h h : mm: s s PM cho buổi chiều (sau 12 h) hoặc h h : mm: s s AM cho buồi sáng.
Dể hiến thị thời gian theo các định dạng nêu trên ta có thề sử dụng lớp j a v a t e x t D e c i m a l F o r m a t
// Phương thức tạo lập T im e thiết lập các thuộc tinh bằng 0 p u b l i c T im e () { s e t T im e ( 0 , 0 , 0 ) ; // Gọi hàm s e t T i m e () đề thiết lập thời gian
// Nạp chồng phương thức tạo lập T im e p u b l i c T im e ( i n t h) { s e t T im e (h, 0, 0 ) ; // Gọi hàm s e t T im e () để thiết lập thời gian có h
} p u b l i c T im e ( i n t h, i n t m) { s e t T im e ( h , m, 0 ) ; // Gọi hàm s e t T im e () để thiết lập thời gian có h, m
} p u b l i c T im e ( i n t h, i n t m, i n t s ) { s e t T im e ( h, m, s ) ; // Gọi hàm s e t T im e () đề thiết lập thời gian có h, m
//Tạo ra một đối tượng từ một đối tượng cho trước - c o p y p u b l i c T im e (T im e t i m e ) { s e t T i m e (t i r o e g e t H o u r ( ) , t i m e g e t M i n u t e ( ) , t i m e g e t s e c o n d ( ) ) ; }
// s e t T i m e () kiểm tra điều kiện cùa giờ, phút, giây đế gán giá trị theo các tham số // Nếu không thoả thi tất cả đều gán bằng 0 p u b l i c v o i d s e t T i m e ( i n t h, i n t m, i n t s ) { h o u r = ( (h >= 0 && h < 24)? h: 0); m i n u t e = ( (m >= 0 && m < 60)? ra: 0); s e c o n d = ( ( s >= 0 ícSc s < 6 0)? s: 0);
// Các phương thức đọc ghi các thuộc tính khai báo p r i v a t e (2) p u b l i c v o i d s e tH o u r ( i n t h) { h o u r = ( (h >= 0 && h < 24)? h: 0);
// Chuyến kết thời gian ờ dạng chuỗi ký tự sang dạng u n i v e r s a l - t i m e p u b l i c s t r i n g t o U n i v e r s a l S t r i n g () {
// Chuyến kết thời gian ờ dạng chuỗi ký tự sang dạng S t a n d a r d - tir a e >
■ Mọi lóp cùa J a v a đều là lớp con, cháu cùa lớp O b j e c t ở gói j a v a l a n g
Chúng ta có thể tạo ra một lớp kế thừa từ lớp Object, hoặc nếu không khai báo kế thừa, hệ thống vẫn tự động coi lớp đó là lớp kế thừa mặc định từ lớp Object.
■ Gói j a v a l a n g * được mặc định nhập vào chương trình J a v a nếu không chi định tường minh.
Các thuộc tính thời gian được khai báo là private, do đó để truy cập chúng từ các lớp khác, cần bổ sung thêm các phương thức công khai như getHour() để đọc giá trị và setHour() để cập nhật giá trị.
■ 0 (3) là khai báo và tạo lập đối tượng t w o D i g i t s cua lớp
D e c i m a l F o r m a t đế định dạng theo hai chữ số.
Chương trình 3.20 minh họa cách sử dụng hàm Time để thiết lập thời gian qua nhiều phương thức khác nhau, đồng thời hiển thị thời gian dưới dạng phổ dụng và chuẩn.
T im e t 6 = n ew T im e ( t 4 ) ; //12:25:42 s t r i n g o u t p u t = "— Tao lap cac doi tuong cua Time: " +
" \ n " + t l t o s t a n d a r d s t r i n g () ; o u t p u t += " \ n t 2 : hour xac dinh; minute va second mac dinh" +
" \ n " + t 2 t o s t a n d a r d s t r i n g ( ) ; o u t p u t += " \ n t 3 : hour va minute xac dinh; second mac dinh” +
"Overloaded Constructors", J O p t io n P a n e INFORMATION_MESSAGE);
Chạy chương trình trên cho kết quả như hình 3.12.
— Tao lap cac doi liKMtg cua Tuiic:
12:00:00 AM 12: hoiM x a c duili; Iiu iuito v a se cu iH l m a c tlinli
02 : 00:00 2:00:00 AM 13: hotir va miiHito Mac dinh; iacond mitc cUrth a 1134100 9:34:00 PM 14: houf mHiula va seconri Mac Ilmn 12.25:42
12:25:42 PM 15: Cac gia tri kltong thoa dieu Kien 00:00:00
12:00:00 AM 16: copy doi liiono tu 14 12:25:42 12:25:42 PM
Hình 3.12 Chương trình tạo lập vá hiển thị thời gian
Sự kết thúc của đối tư ợ n g
Một số đối tượng có thể gắn với tài nguyên như tệp hoặc kết nối mạng và đòi hỏi phải giải phóng tường minh Để giải quyết vấn đề này, cơ chế hoàn thành của đối tượng cung cấp một kế sách để thực hiện hành động trước khi bộ nhớ được giải phóng Trong Java, bộ "dọn rác" tự động (Automatic Garbage Collector) gọi hàm finalize() đã được xây dựng trong lớp Object, cho phép tập hợp rác lại trước khi tiêu hủy chúng.
Hàm này có thể được viết đè ở lớp con đế thực hiện những công việc thích trước khi huy bó đối tượng.
> C hư ư ng trình 3.21: Sừ dụng bộ f i n a l i z e r để dọn dẹp bộ nhớ.
//Tệp: F i n a l i z e r j a v a class D i e n { s t a t i c i n t dem; s t a t i c i n t c o n g C h u n g ; protected int l a n ;
} protected void f inalize () throws Throwable s u p e r f i n a l i z e ( ) ;
//(2) class T r i n h D i e n extends D i e n { int [ ] f a t ; public T r i n h D i e n (i n t n) { f a t = new i n t [n] ;
Sau khi dịch và chạy chương trình cho kết quả như hình 3.13.
Hinh 3.13 Chương trinh sử dụng s u p e r f i n a l i z e 0 để kết thúc
Ví dụ trên minh họa cách sử dụng phương thức finalize() Chương trình tạo ra một số đối tượng (s o L a n) với kích thước (t h o i G i a n) Trong hàm main(), chu trình (7) tạo ra đối tượng của lớp Trình Diễn, nhưng không được lưu trữ để truy cập tiếp Việc tạo ra đối tượng của Trình Diễn được thực hiện bởi phương thức tạo lập (4), xin cấp phát mảng các số nguyên cho fat Mỗi lần tạo ra đối tượng của lớp này đều có quy trình riêng.
T r i n h D i e n ở (4) lại in ra màn hình số l a n và : H e l l o Hàm f i n a l i z e () ỏ
Trước khi một đối tượng được đưa vào thùng rác, hàm sẽ được gọi và in ra số lần cùng với từ "Bye" Sau đó, hàm finalize() của lớp Điện sẽ được thực hiện Kết quả cho thấy có một đối tượng chưa được dọn và vẫn hoạt động trong hệ thống Lưu ý rằng kết quả in ra màn hình, bao gồm số đối tượng được tạo ra và dọn dẹp, phụ thuộc vào tham số thứ hai; nếu thời gian lớn, chỉ có một đối tượng chưa được dọn, trong khi thời gian nhỏ hơn 9000 thì cả 5 đối tượng vẫn tiếp tục hoạt động.
3.8 Hàm dệ quy Đệ quy là một kỹ thuật dùng để đơn giản hoá những bài toán ( p r o b l e m ) phức tạp bang cách phân nhỏ bài toán đó thành nhiều bài toán đồng dạng, có quy mô nhỏ hơn, gọi là bùi toán con ( s u b - p r o b l e m ) Qua việc giải những bài toán được phân nhỏ này, những lời giải sẽ được kết hợp lại để giải quyết toàn bộ bài toán lớn. Trong toán học và khoa học máy tính, các tính chất (hoặc cấu trúc) được gọi là đệ quv nếu trong đó một lớp các đối tượng hoặc phương pháp dưọc xác định bàng việc xác định một số rất ít các trường hợp hoặc phuơng pháp đơn giản (thông thirờng chi một vài) và sau đó xác định quy tấc đưa các trường hợp phức tạp về các trường hợp đơn giản.
Một chương trình con đệ quy căn bản gồm hai phần:
■ Phàn cơ sớ: Chứa các tác động cùa hàm hoặc thù tục với một số giá trị cụ thể ban dầu cùa tham số.
Phần đệ quy là quá trình xác định tác động cần thực hiện cho giá trị hiện tại của các tham số, dựa trên các hoạt động đã được định nghĩa từ trước với kích thước tham số nhỏ hơn.
Ví dụ hàm giai thừa f a c t o r i a l ( n ) = n * (n - 1) * 2 * 1 có thể viết đệ quy như sau:
> C hương trình 3.22: Viết chương trình tính dãy số F i b o n a c c i : số đàng sau bằng tổng của hai số phía trước liền kề Ví dụ: 0, 1, 1, 2, 3, 5, 8, 13, 21,
Dãy số F i b o n a c c i có thề định nghĩa đệ quy như sau:
Chương trình a p p l e t sau nhận vào m ột số nguyên n và hiền thị số F i b o n a c c i thứ n tương ứng.
// Nhặn về báng nội dung ( c o n t e n t p a n e ) và thiết lập F lo w L a y o u t (2)
// Tạo ra đối tượng n u m b e r L a b e l và đưa vào bảng nội dung n u m b e r L a b e l = n ew J L a b e l ( " N h a p v a o s o n g u y e n " ) ;
//T ạo lập đối tượng n u m b e r F i e l d và đưa vào báng nội dung n u m b e r F i e l d = n ew J T e x t F i e l d ( 1 0 ) ;
// Đăng ký a p p l e t này như là phần từ lắng nghe sự kiện A c t i o n L i s t e n e r // cùa numberField's n u m b e r F i e l d a d d A c t i o n L i s t e n e r ( t h i s ) ; // (3) // Tạo lập đối tượng r e s u l t L a b e l và đưa vào bàng nội dung r e s u l t L a b e l = new J L a b e l ( "So Fibonacci tuong ung la: ");
// Tạo lập đối tượng dê hiến thị số r e s u l t F i e l d
// và đưa vào bảng nội dung nhưng không cập nhật được (4) r e s u l t F i e l d = n ew J T e x t F i e l d ( 1 5 ) ; r e s u l t F i e l d s e t E d i t a b l e ( f a l s e ) ;
// Nhận kết quà nhập vào cùa người sứ dụng và gọi hàm f i b o n a c c i ( ) p u b l i c v o i d a c t i o n P e r f o r m e d ( A c t i o n E v e n t e v e n t ) { l o n g n u m b e r , f i b o n a c c i V a l u e ;
// Nhận kết quá nhập vào của người sứ dụng và chuyến về lo n g n u m b e r = L o n g p a r s e L o n g ( n u m b e r F i e l d g e t T e x t O ) ; //(5) s h o w S t a t u s ( "D ang t i n h // (6)
// Thõng báo chương trình tinh xong va hiển thị kết quà s h o w S t a t u s ( " D o n e " ) ; r e s u l t F i e l d s e t T e x t ( L o n g t o S t r i n g ( f i b o n a c c i V a l u e ) ) ; } / / Kết thúc a c t i o n P e r f o r m e d ( )
// Định nghĩa phương thức đệ quy f í b o n a c c i O
// Cơ sở đệ quy i f (n == 0 II n == 1) r e t u r n n ;
Chương trình dịch xong và đưa vào thè HTML a p p l e t c o d e để chạy cho kết quả như hình 3.14.
So ntsoiiacci tuong ung la: í 6 7 6 5 ị
Hinh 3.14 Chương trinh đệ quy tinh dãy số Fibonacci
Chương trình xử lý sự kiện khi người dùng nhập dữ liệu và nhấn Enter, hiển thị kết quả tính toán Để xử lý các sự kiện này, cần nhập vào java.awt.event.* để sử dụng các lớp xử lý sự kiện Đồng thời, cần lưu ý rằng gói javax.swing cung cấp các lớp như JApplet và JLabel.
J Text Field thường được sử dụng trong các trang thông tin và khung chương trình, nơi các thành phần cần được sắp xếp theo nhiều cách khác nhau Để bố trí các thành phần của applet theo kiểu Flow Layout, chúng ta cần để chúng trôi theo kích thước của applet Để đăng ký một thành phần xử lý sự kiện, sử dụng lệnh thích hợp Mọi sự kiện có thể là kết thúc nhập liệu như nhấn Enter, nhấn chuột, hoặc gõ phím Nếu muốn một thành phần hiển thị dữ liệu không được cập nhật, hãy sử dụng setEditable(false) Dữ liệu nhập vào từ trường văn bản được lấy ra bằng hàm getText() Cuối cùng, có thể sử dụng hàm showStatus() để hiển thị trạng thái của quá trình tính toán.
Quan hệ kế thừa giữa các lớ p
Kế thừa là một cơ chế quan trọng trong lập trình hướng đối tượng, cho phép tái sử dụng các đoạn chương trình Từ một lớp cơ sở được thiết kế tốt, có thể tạo ra nhiều lớp con hay lớp dẫn xuất Lớp cơ sở, còn gọi là lớp cha hoặc lớp mẹ, cung cấp các thuộc tính và phương thức cho lớp con Lớp con có khả năng bổ sung thêm thuộc tính và phương thức để định nghĩa các đặc điểm và hành vi cụ thể hơn, hoặc thay đổi các phương thức được kế thừa (public, protected) từ lớp cha.
Java hỗ trợ kế thừa đơn (tuyến tính), cho phép một lớp chỉ kế thừa từ một lớp cha duy nhất Điều này tạo ra một cấu trúc phân cấp có thứ bậc, tương tự như cấu trúc cây Lớp cơ sở nhất trong Java là lớp Object, làm nền tảng cho tất cả các lớp kế thừa khác.
Chúng ta nhắc lại là, mọi lớp cùa J a v a đểu là lớp con cháu (mặc định) cùa O b j e c t
Ví dụ, các lớp ở các chương trình 3.9, 3.10, 3.11 là lớp B ongD en, D en T u y p ,
N haK ho có thề mô tả quan hệ kế thừa theo ký pháp của UML như hình 3.15.
Hình 3.15 Quan hệ kế thừa giữa các lớp
Cú pháp quy định quan hệ kế thừa trong J a v a là sự mở rộng cùa lớp cha, có dạng:
// Các thuộc tính dữ liệu bổ sung
// Các hàm thành phần bồ sung hay viết đè
■ S u b C l a s s là lớp con cần xây dựng mới;
■ S u p e r C l a s s là lớp cha, lớp cơ sở đã xây dựng tốt.
Mọi đối tượng thuộc lớp con đều là đối tượng của lớp cha, vì vậy việc gán một đối tượng của lớp con cho biến tham chiếu của lớp cha được coi là sự mở rộng kiểu và không cần ép kiểu Tuy nhiên, điều này có thể dẫn đến việc mất thông tin.
Việc gán đối tượng của lớp cha cho biến tham chiếu thuộc lớp con yêu cầu thực hiện ép kiểu Trong Java, chỉ những đối tượng của lớp cha được tạo lập từ lớp con mới có thể được ép kiểu sang lớp con Ngược lại, đối tượng của lớp cha không được tạo lập từ lớp con sẽ không thể ép kiểu chuyển sang lớp con.
Ví dụ: c l a s s S u p e r C l a s s { / * * / } c l a s s S u b c l a s s e x t e n d s S u p e r C l a s s { / * * / } c l a s s U s e r C l a s s { // Khai báo các thành phẩn p u b l i c s t a t i c v o i d m a i n ( s t r í n g a r g s [] ) {
S u p e r C l a s s s u p e r l = n ew S u p e r C l a s s () ;// Tạo ra đối tượng lớp cha ( l )
S u b c l a s s s u b l = n ew S u b C l a s s () ; //Tạo ra đối tượng lớp con (2)
S u p e r C l a s s s u p e r 2 = s u b l ; // M ớ rộng kiểu (3) s u b l = ( S u b C l a s s ) s u p e r l ; / / Sai, do s u p e r l được khởi
// tạo từ lớp cha (4) s u b l = (S u b C la s s ) s u p e r 2 ; / / Thu hẹp kiểu nên phải ép kiều (5) }
3.9.1 Phương thức this() và super()
Các phương thức tạo lập không thể viết đè ờ các lóp dẫn xuất (lóp con) Chúng có thể được nạp chồng nhưng phải trong cùng lớp.
Trong Java, có hai phương thức tạo lập đặc biệt là this() và super() được sử dụng để thiết lập mối quan hệ giữa các lớp kế thừa Phương thức tạo lập this() cho phép gọi đến các phương thức hoặc biến của lớp hiện tại, giúp tăng tính rõ ràng và hiệu quả trong việc khởi tạo đối tượng.
Phuơng thức tạo lập này được sử dụng để tạo ra đối tượng cúa lớp hiện thời.
> Cliương trìnli 3.23: Nạp chồng phương thức tạo lập theo truyền thống.
// Định nghĩa phương thức tạo lập mặc định số I (2)
// Định nghĩa phương thức tạo lập không mặc định số 2 (3)
// Định nghĩa phương thức tạo lập không mặc định số 3 nạp chồng (4) BongDen ( i n t s o V ỉ a t t s , b o o l e a n b a t T a t , s t r i n g v i T r i ) { t h i s s o W a tts = s o W a tt s ; t h i s b a t T a t = b a t T a t ; t h i s v i T r i = new s t r i n g ( v i T r i ) ;
// Các lệnh cần thực hiện
BongDen d l = new B ongD en () ; // OK
BongDen d2 = new BongD en (100, t r u e , " N h a b e p " ) ; / / OK BongDen d3 = n ew B ongD en (10 0 t r u e ) ; / / OK
Trong lớp B o n g D e n, có ba phương thức tạo lập được nạp chồng, được đánh số (1), (2) và (3) Biến tham chiếu t h i s được sử dụng trong hàm m a in () ở (4) để xác định các đối số tương ứng với đối tượng hiện tại của phương thức tạo lập.
Khi xây dựng các phương thức tạo lập, có thể sử dụng phương thức `this()` để rút gọn chương trình, giúp giảm thiểu việc viết nhiều câu lệnh gán giá trị cho các biến Phương thức này cũng hỗ trợ việc nạp chồng các phương thức tạo lặp, tăng tính linh hoạt và hiệu quả cho mã nguồn.
> C hương trình 3.24: Sừ dụng phương thức t h i s () để rút gọn chương trình.
// Định nghĩa phương thức tạo lập mặc định số I (2)
B ongD en(){ t h i s (4 0, t r u e ) ; // Sừ dụng phương thức tạo lập t h i s ()
// Đinh nghĩa phirong thức tạo lập không mặc đinh số 2 (3)
// Định nghĩa phương thức tạo lập không mặc định số 3 nạp chồng (4)
B o n g D en d3 = n e w B ongD en (1 0 0 , t r u e ) ; // OK // Các câu lệnh cần thực hiện
Chương trình này tương tự như chương trình 3.23, nhưng khác ở chỗ trong định nghĩa hai phương thức tạo lập (1) và (2) sử dụng cấu tử `this()` để gán các đối số cho các đối tượng khi chúng được tạo ra Phương thức thứ ba để tạo lập là `super()`.
Phương thúc s u p e r () được sừ dụng trong các phương thức tạo lập cùa lóp con ( S u b c l a s s ) để gọi tới các phương thức tạo lập của lóp cha ( S u p e r c l a s s ) trực tiếp.
> C hương trình 3.25: Sừ dụng phương thức s u p e r ( )
// Định nghĩa phương thức tạo lập mặc định số 1 (2)
// Định nghĩa phurcmg thức tạo lập không mặc định số 2 (3)
// Định nghĩa phương thức tạo lập không mặc định số 3 nạp chồng (4)
' // Cỏc'cõu lệnh cần thực hiện ô
B o n g D e n là lớp cha (trực tiếp) cùa lớp D en T u y p Phương thức s u p e r () ở (6) là đụi diện cho phương thức tạo lập cùa lớp cha B ongD en.
M ột sổ lưu ý khi sứ dụng s u p e r () và t h i s 0 :
■ t h i s () được sử dụng đế móc xích với cùng lớp chứa nó, còn s u p e r () lại được sứ dụng đế gọi tới lớp cha cùa lớp đó.
3.9.2 Quan hệ kế thừa và quan hệ kết tập
Một vấn đề quan trọng trong phát triển phần mềm hướng đối tượng là xây dựng biểu đồ lớp, giúp mô tả đầy đủ mối quan hệ giữa các lớp trong hệ thống ứng dụng.
I lai lớp có thề có các quan hệ sau:
Quan hệ kế thừa và kết tập đều thể hiện mối liên hệ giữa "một bộ phận" và "tổng thể" Trong khi quan hệ kế thừa mang tính chất "is a" (là một thành viên), thì quan hệ kết tập lại mang tính chất "has a" (có một thành viên) Mặc dù có những điểm chung, hai loại quan hệ này cũng có nhiều đặc trưng khác nhau, do đó, lập trình viên cần lựa chọn quan hệ phù hợp cho từng bài toán cụ thể Biểu đồ lớp UML sẽ giúp minh họa rõ hơn cho những mối quan hệ này.
Hình 3.16 Một s ơ đồ lớp có quan hệ kế thừa và kết tập
Trong đó: Ị A Ị C hương trình 5.8: Mô tả cách sứ dụng các hàm của lớp G r a p h i c s để vẽ, tô màu các hình. i m p o r t j a v a a p p l e t * ; i m p o r t j a v a a w t * ; p u b l i c c l a s s R e c t a n g l e A p p l e t e x t e n d s A p p l e t {
// Vẽ hình chữ nhật và tô màu hình vuông g s e t C o l o r ( C o l o r o r a n g e ) ; g d r a w R e c t ( 2 5 , 1 0 , 50, 7 5) ; g f illRect (25, 110, 5 0, 50) ;
// Vẽ hình chữ nhật và tô màu hình vuông có góc tròn g s e t C o l o r ( C o l o r b l u e ) ; g đ r a w R o u n d R e c t ( 1 0 0 , 1 0 , 5 0 , 75, 30, 5 0) ; g f i l l R o u n d R e c t ( 1 0 0 , 1 1 0 , 50, 5 0 , 2 0 , 2 0 ) ;
// Vẽ hình chữ nhật và hình vuông 3D g s e t C o l o r ( C o l o r r e d ) ; g d r a w 3 D R e c t ( 1 7 5 , 1 0 , 5 0 , 75, t r u e ) ; g d r a w 3 D R e c t (1 7 5 , 110, 50, 50, f a l s e ) ; •
// Tô màu hinh chữ nhật và hlnh vuông 3D g s e t C o l o r ( C o l o r g r e e n ) ; g f i l l 3 D R e c t ( 2 5 0 , 1 0 , 50, 75, t r u e ) ; g f i l l 3 D R e c t ( 2 5 0 , 1 1 0 , 5 0 , 5 0 , f a l s e ) ;
Sau khi dịch được kết quả là R e c t a n g l e A p p l e t c l a s s , chúng ta tạo ra tệp HTML R e c t a n g l e A p p l e t h t m l bằng lệnh đơn giàn:
Thực hiện a p p l e t v i e w e r F o n t A p p l e t h t m l sẽ cho kết quả như hình 5.111.
Hình 5.11 Vẽ và tô màu hinh chữ nhặt e) Vẽ hình PolyLine
Chương trình sau lấy các điểm từ hai mảng để vẽ một loạt các đoạn thẳng.
1 5 ) )) ; Phương thức d r a w P o l y l i n e () nhận ba tham số sau:
■ M ảng lưu trữ toạ độ X của các điểm;
■ Mảng lưu trữ toạ độ y cùa các điểm;
■ Tổng số điểm cần vẽ. Đế vẽ các đường thẳng ta lấy các điểm từ hai mảng như sau:
Sổ đường thẳng vẽ được luôn nhỏ hơn số truyền vào thông số thứ ba cùa phưccm thức d r a w P o l y l i n e ()
> C hương trình 5.9: Minh hoạ cách vẽ p o l y l i n e i m p o r t j a v a a w t * ; c l a s s P o l y L i n e s e x t e n d s Fra m e{ i n t x l [] = { 5 0 , 7 5 , 9 5 , 1 1 5 , 1 3 5 } ; i n t y l [] = {50, 30, 60, 75, 6 0 } ; i n t x2 [] = {67 82, 95, 120, 135} ; i n t y 2 [] = {150, 130 , 160, 155, 1 80} ; p u b l i c P o l y L i n e s () { s u p e r ( " P o l y L i n e s " ) ; s e t s i z e ( 3 0 0 , 3 0 0 ) ; s e t v i s i b l e ( t r u e ) ;
Chương trình thực hiện và cho kết quả như hình 5.12.
0 Vẽ và tô m à u đ a giác (Polygon)
Bố trí sắp xếp các thành phần trong chương trình ứng d ụ n g
Khi thiết kế giao diện đồ hoạ cho một ứng dụng, ta phải quan tâm đến kích thước và cách bố trí ( l a y o u t ) các thành phần giao diện như: B u t t o n , C h e c k b o x ,
Java cung cấp các lớp để quản lý giao diện người dùng (GUI) một cách hiệu quả, giúp người sử dụng có trải nghiệm tiện lợi nhất Những lớp này đảm nhận việc tổ chức và sắp xếp các thành phần giao diện trong các phần tử chứa Bảng 5.5 trình bày bốn lớp quản lý layout, cho thấy cách bố trí và sắp xếp các thành phần GUI một cách hợp lý.
Báng 5.5 Các lớp quán lỷ cách tố chức các thành phần giao diện
Xếp các thành phần giao diện theo hàng từ trái qua phải và sau đó theo cột từ trên xuống dưới là cách sắp xếp mặc định.
Panel và Applet là các thành phần có khả năng tự động điều chỉnh kích thước theo khung chương trình Khi khung rộng, chúng sẽ được sắp xếp thành hàng, trong khi khi khung hẹp, chúng sẽ co lại thành một cột.
Các thành phần giao diện được bố trí trong các ô lưới hình chữ nhật, sắp xếp theo hàng từ trái sang phải và theo cột từ trên xuống dưới trong một phần tử chứa Mỗi thành phần giao diện nằm trong một ô và vị trí tương đối giữa chúng là không thay đổi.
Các thành phần giao diện, bao gồm Frame và Dialog, được sắp xếp theo các hướng: Bắc, Nam, Tây, Đông và Trung tâm Đây là cách bố trí mặc định cho lớp window.
GridBagLayout cho phép sắp xếp các thành phần giao diện trong một lưới hình chữ nhật với các ô có kích thước khác nhau, đồng thời cho phép một thành phần chiếm nhiều ô trong lưới.
C a r d L a y o u ts phân biệt với các l a y o u t khác ờ chỗ nó xếp các thánh phần chồng lên nhau và ờ mỗi thời điểm chi một thành phần hién thị
(nhin thấy) giống như tập quân bài. Để biết l a y o u t hay đề đặt lại l a y o u t cho chương trình ứng dụng, ta có thề sừ dụng hai hàm của lớp C o n t a i n e r :
Các thành phần giao diện sau khi được tạo ra cần được đưa vào một phần tử chứa Hàm add() của lớp Container được nạp chồng để thực hiện nhiệm vụ này.
Đối số "index" trong hàm "component add" được sử dụng để chỉ định vị trí của ô cần đặt thành phần giao diện "comp" Trong khi đó, đối số "constraints" xác định các hướng để đưa "comp" vào phần tử chứa.
Ngược lại, khi cần loại ra khỏi phần từ chứa một thành phần giao diện thì sử dụng các hàm sau:
Lưu ý rằng việc không sử dụng các lớp quản lý layout để bố trí các thành phần giao diện của ứng dụng theo một layout cố định có thể dẫn đến việc các thành phần bị thay đổi và xê dịch không theo thứ tự cần thiết khi kích thước của khung chương trình thay đổi Một trong những lớp quản lý layout phổ biến là lớp Flow Layout.
Lớp F lo w L a y o u t cung cấp các hàm tạo lập để sắp hàng các thành phần giao diện:
Bố cục dòng (bao gồm căn chỉnh, khoảng cách ngang và khoảng cách dọc) liên quan đến việc xác định cách sắp xếp các phần tử trong giao diện người dùng Các tùy chọn căn chỉnh bao gồm căn trái, căn phải và căn giữa Khoảng cách ngang (horizontally gap) và khoảng cách dọc (vertical gap) được tính bằng pixel, xác định khoảng cách giữa các hàng và cột Mặc định, khoảng cách giữa các hàng và cột là 5 pixel.
> C hư ơ n g trình 5.19: Minh hoạ về các thành phần có thế bị thay đổi khi thay đổi kích thước f ra m e i m p o r t j a v a a w t * ; i m p o r t j a v a a p p l e t * ; p u b l i c c l a s s F l o w L a y o u t A p p l e t e x t e n d s A p p l e t { p ú b l i c v o i d i n i t () {
Checkbox cbl = new Checkbox ( "Loai to", t r u e ) ;
Checkbox cb2 = new Checkbox ( "Loai trung", f a l s e ) ;
Checkbox cb3 = new Checkbox ("Loai be", f a l s e ) ; a d d (cbl) add(cb2) add(cb3)
Sau khi dịch dược kết q uà là F l o w L a y o u t A p p l e t c l a s s , ta tạo ra lệp HTML
Thực hiện a p p l e t v i e w e r F l o w L a y o u t A p p l e t h t m l sẽ cho kết quà: r a A p p l c t V i c w c r : I lư w l d y o u t A | ) | > ) ( ^ 3 I I ÍL o ạ i to] r ~ L o a i tru n g I L o a i be
Hinh 5.23 Các thành phần giao diện có thể thay đổi
Trong chương trình, giao diện (Button) chưa được sắp xếp theo một layout cố định, dẫn đến việc khi thay đổi kích thước của khung ứng dụng, các nút của Checkbox sẽ bị di chuyển Ví dụ, khi thu hẹp chiều rộng của hình 5.23, hình 5.24 sẽ xuất hiện với sự thay đổi vị trí của các nút.
Hình 5.24 Thay đối lại kích thước của khung chương trình b) L ó p G ridL ayout
Lớp G r i d L a y o u t cung cấp các hàm tạo lập để sắp hàng các thành phần giao diện:
Tạo một lưới hình chữ nhật với r hàng và c cột, trong đó khoảng cách giữa các hàng là h và giữa các cột là v Một trong hai tham số rows hoặc columns có thể là 0, nhưng không thể cả hai Ví dụ, Grid Layout (l, 0) sẽ tạo ra một lưới chỉ với một hàng.
> C hương trình 5.20: Mô tà cách sừ dụng G r i d L a y o u t i m p o r t j a v a a w t * ; im p o r t j a v a a p p l e t * ; p u b l i c c l a s s G r i d L a y o u t A p p l e t e x t e n d s A p p l e t { p u b l i c v o i d i n i t () {
Sau khi dịch được kết quả là G r i d L a y o u t A p p l e t c l a s s , chúng ta tạo ra tệp HTML G r i d L a y o u t A p p l e t h t m l bằng lệnh:
T hực hiện G r i d L a y o u t A p p l e t h t m l trong Web B r o w s e r sẽ ch o kết quả: Ỵ "
0 Applct Viewcr: Gridl dyoutAppl f c n f 5 Ị |5 ( ] Applet
Hình 5.2 5 Tạo ra 6 ô lưới để sắp xếp các thành phản giao diện chương trình
Lớp B o r d e r L a y o u t cho phép đặt một thành phần giao diện vào mội trong bốn hướng: bắc (NORTH), nam (SOUTH), đông (EAST), tây (WEST) và ờ giữa (CENTER)
Tạo ra một l a y o u t mặc định hoặc có khoảng cách giữa các thành phần (tính bằng p i x e l ) là h o r i z o n g a p theo hàng và v e r t i c a l g a p theo cột.
C o m p o n e n t a d d ( C o m p o n e n t com p) v o i d a d d (C o m p o n e n t com p, O b j e c t c o n s t r a i n t ) p u b l i c s t a t i c f i n a l s t r i n g NORTH p u b l i c s t a t i c f i n a l s t r i n g SOUTH p u b l i c s t a t i c f i n a l s t r i n g EAST p u b l i c s t a t i c f i n a l s t r i n g WEST p u b l i c s t a t i c f i n a l s t r i n g CENTER
Mặc định, hướng mặc định là CENTER, nhưng bạn có thể chỉ định hướng để sắp xếp các thành phần trong phần tử chứa theo constraint trên một trong các hàng.
Chương trình 5.21 bao gồm một nút B u t t o n mang tên "Vẽ" ở phía trên (NORTH), một trường văn bản "Hiển thị thông báo" ở phía dưới (SOUTH) và hai thanh trượt (SCROLLBAR) đặt ở hai bên cạnh (WEST và EAST).
T e x t F i e l d rasg = n ew T e x t F i e l d ( "Hien thi thong b a o " ) ; m s g s e t E d i t a b l e ( f a l s e ) ;
//Tạo ra vu n g Ve để vẽ tranh
C a n v a s v u n g V e = n ew C a n v a s () ; v u n g V e s e t s i z e (1 5 0 , 1 5 0 ) ;// Đặt kich thước cho vungVe vẽ tranh v u n g V e s e t B a c k g r o u n d (C o l o r w h i t e ) ; // Đặt màu nền là trắng
Xử lý các sự k iệ n
Các ứng dụng GUI thường hoạt động dựa trên các sự kiện (event), như nhấn nút, đóng cửa sổ hoặc gõ ký tự từ bàn phím Những sự kiện này được gửi đến chương trình ứng dụng và trong Java, chúng được biểu diễn dưới dạng các đối tượng Lớp cơ sở của tất cả các lớp sự kiện là lớp java.util.EventObject, và các lớp xử lý sự kiện được tổ chức thành một cấu trúc phân cấp.
Hình 5.27 Các lớp xừ lý sự kiện
5.7.1 Các lớp ngữ nghĩa a) A ctionEvent
Sự kiện này được kích hoạt bởi các hành động trên các thành phần của giao diện người dùng (GUI) Các thành phần này có khả năng gây ra các sự kiện hành động quan trọng.
■ B u t t o n - khi một nút b u t t o n được kích hoạt;
■ L i s t - khi một mục trong danh sách được kích hoạt đúp;
■ M e n u lte m - khi một mục trong thực đơn được chọn;
■ T e x t F i e l d - khi gõ phím ENTER trong trường văn bàn ( t e x t )
Cho biết tên cùa lệnh tương ứng với sự kiện xày ra, là tên cùa nút, mục hay t e x t b) A d ju s tm e n tE v e n t
Thành phần gây ra sự kiện căn chinh ( a d j u s t m e n t ) :
S c r o l l b a r - khi thực hiện một lần căn chinh trong thanh trượt S c r o l l b a r Lớp này có hàm: i n t g e t V a l u e ()
Cho lại giá trị hiện thời được xác định bời lần căn chinh sau cùng. e) Item E vent
Các thành phần của GUI gây ra các sự kiện về các mục gồm có:
■ C h e c k b o x - khi trạng thái cùa hộp kiếm tra C h e c k b o x thay đổi;
■ C h e c k b o x M e n u I te m - khi trạng thái của hộp kiểm tra C h e c k b o x ứng với mục cùa thực đơn thay đổi;
■ C h o i c e - khi một mục trong danh sách'chọn được chọn hoặc bị loại bỏ;
■ L i s t - khi một mục trong danh sách được chọn hoặc bị loại bò.
Cho lại đối tượng được chọn hay vừa bị loại bò. d) T extE ven t
Các thành phần cùa GUI gây ra các sự kiện về t e x t gồm có:
• T e x t A r e a - khi kết thúc bằng nhấn phím ENTER;
■ T e x t F i e l d - khi kết thúc bằng n hấn phím ENTER.
Bàng 5.6 Các hàm xứ lý ngữ nghĩa các sự kiện
Kiểu sự kiện Nguồn gây ra sự kiện
Các hàm đôn nhận và di dời các sự kiện
Giao diện Listener tương ủng
Button List TexField Scrollbar Choice Checkbox CheckboxMenultem List
TextArea TextField addComponentlistener removeActiontListener addAdjustmentListener removeAdjustmentListener addltemListener removoltomListener addTexListener removeT extListener
5.7.2 C ác sự kiện ở m ứ c thấp a) C o m p o n en tE v en t
Sự kiện này xuất hiện khi một thành phần bị che giấu, hiển thị hay thay đồi lại kích thirớc Lớp C o m p o n e n t E v e n t có hàm:
Cho lại đối tượng tham chiếu kiểu C o m p o n e n t. b) C o n ta in erE v en t
Sự kiện này xuất hiện khi một thành phần được bổ sung hay bị loại bỏ khỏi phần tứ chứa ( C o n t a i n e r ) c) F ocu sE ven t
Sụ kiện loại này xuất hiện khi một thành phần nhận được một phím từ bàn phím. d) K eyE vent
Lớp KeyEvent là lớp con của lớp trừu tượng InputEvent, được sử dụng để xử lý các sự kiện liên quan đến bàn phím Lớp này bao gồm nhiều hàm quan trọng phục vụ cho việc quản lý và phản hồi các thao tác từ người dùng.
Đối với các sự kiện KEY PRESSED hoặc KEY RELEASED, hàm int getKeyCode() được sử dụng để lấy giá trị nguyên tương ứng với mã của phím trên bàn phím.
Hàm chargeKeyChar() được sử dụng để xử lý các sự kiện KEY_PRESSED, giúp nhận lại giá trị nguyên tương ứng với mã Unicode của ký tự trên bàn phím.
Lóp M o u s e E v e n t là lớp con cùa lớp trừu tượng I n p u t E v e n t được sừ dụng để xử lý các tín hiệu của chuột Lớp này có các hàm:
Các hàm này được sử dụng để nhận lại toạ độ X, y cùa vị trí liên quan đến sự kiện do chuột gây ra.
Hàm t r a n s l a t e P o i n t () được sử dụng để chuyển toạ độ của sụ kiện do chuột gây ra đến (d x , dy).
Hàm g e t c i i c k C o u n t () đếm số lần kích chuột.
Giao diện M o u s e L i s t e n e r khai báo năm phương thức cho các thao tác với chuột: p u b l i c v o i d m o u s e P r e s s e d ( M o u s e E v e n t e v t ) ;
II Vẽ bàn cờ và nhấn chuột vào từng ô thì màu cùa ô đó sẽ đồi màu i m p o r t j a v a a w t e v e n t * ; i m p o r t j a v a a w t * ; i m p o r t j a v a x s w i n g * ; p ú b l i c c l a s s T e s t M o u s e E v e n t e x t e n d s J F r a m e i m p l e m e n t s
Thực hiện chương trình và nhấn một ô bất kỳ thì ô đó đổi màu.
Hình 5.28 Nhẩn chuột để đối ô trong bàn cò g) P aintE vcnt
Sự kiện này xuất hiện khi một thành phần gọi hàm p a i n t () / u p d a t e () để vẽ. h) VVindovvEvent
Sự kiện loại này xuất hiện khi thao tác với các W indow Lớp này có hàm:
Hàm này cho lại đối tượng cùa lớp W indow ứng với sự kiện liên quan đến
Bảng 5.7 mô tả các hàm xừ lý các sự kiện ở mức thấp.
Bàng 5.7 Xử lý các s ự kiện ờ mức thấp
Kiều s ự kiện Nguồn gẳy ra s ự kiện
Các hàm đón nhận và di dời các s ự kiện
Giao diện Lislener tươrg úng
MouseEvent Component addMouseListener remoMouseListener addMouseMotionListener remoMouseMotionListener
Chương trình Cliưong Irìnli 5.23 minh họa cách sử dụng nút Next shape để vẽ các hình dạng như đường thẳng, hình chữ nhật, hình chữ nhật góc tròn, hình oval, hình đa giác và tô màu cho hình đa giác Khi nhấn liên tục, chương trình sẽ lặp lại quy trình vẽ từ đầu.
// Nạp chồng hàm p a i n t 0 để vẽ các hình nguyên thuý p u b l i c v o i d p a i n t ( G r a p h i c s g ) { int X [] = {35, 150, 60, 140, 60, 150, 35} ; i n t y [] = {50, 80, 110, 140, 170, 200 , 2 30} ; i n t n u m P t s = 7 ; s w i t c h ( s h a p e ) { c a s e 0 : g d r a w L i n e ( 3 5 , 5 0 , 1 6 0 , 2 3 0 ) ; b r e a k ; c a s e 1 : g d r a w R e c t ( 3 5 , 5 0 , 1 2 5 , 1 8 0 ) ; b r e a k ; c a s e 2 : g d r a w R o u n d R e c t ( 3 5 , 5 0 , 1 2 5 , 1 8 0 , 1 5 , 1 5 ) ; b r e a k ; c a s e 3 : g d r a w O v a l ( 3 5 , 5 0 , 1 2 5 , 1 8 0 ) ; b r e a k ; c a s e 4 : g d r a w A r c ( 3 5 , 5 0 , 1 2 5 , 1 8 0 , 9 0 , 1 8 0 ) ; b r e a k ; c a s e S: g d r a w P o l y g o n ( x , y , n u m P t s ) ; b r e a k ; c a s e 6 : g f i l l P o l y g o n ( x , y , n u m P t s ) ; b r e a k ;
// Xứ lý các sự kiện khi nhấn nút N e x t S h ap e để vẽ liên tiếp 7 hình nêu trên p u b l i c b o o l e a n a c t i o n ( E v e n t e v e n t , Obj e c t a r g ) {
Sau khi dịch được kết quả là S h a p e A p p l e t c l a s s , chúng ta tạo ra tệp HTML
Thực hiện S h a p e A p p l e t h t m l trong Web B r o w s e r và sau đó nhấn nút N e x t
S h a p e bốn lần chương trình sẽ cho kết quả dạng:
Hình 5.29 Nhấn nút Next Shape để vẽ các hình nguyên thuý
Chúng ta có thể phát triển ứng dụng với giao diện đồ họa được thiết kế sẵn và xử lý các sự kiện liên quan đến những giao diện này.
> C hương trình 5.24: Xây dựng ứng dụng có giao diện đồ hoạ GUI.
Hình 5.30 Giao diện đồ hoạ của chương trình ứng dụng
Chương trình được thực hiện như sau:
■ Người sừ dụng có thể đánh dấu các nút ( B u t t o n ) có tên: hình vuông ( S q u a r e ) , hình tròn ( C i r c l e ) , hình E l l i p s e để vẽ các hình tương ứng ở vùng vẽ tranh.
■ Tại các dòng: Toạ độ X (X C o o r d i n a t e ) , Toạ độ y (Y C o o r d i n a t e ) người sử dụng có thể nhập vào toạ độ gốc của hình.
■ Trong thực đơn K í c h t h ư ớ c ( S i z e ) ; người sừ dụng có thể chọn các mục: n h ỏ ( S m a l l ) , t r u n g b ì n h ( M e d iu m ) và l ớ n ( L a r g e ) ch o các hình được hiển thị Kích thước của chúng được cho trước.
Sau khi xác định đầy đủ thông tin, hãy nhấn nút "Vẽ" để tạo hình theo yêu cầu Nếu nút "Tô màu" được chọn, hình vẽ sẽ được tô màu.
Chương trình này được phát triển dựa trên các chức năng của giao diện đồ họa GUI và AWT nhằm đáp ứng các yêu cầu đã đề ra.
/ * D e m o A p p l e t : D e m o n s t r a t i n g GUI + EVENT HANDLING*/ i m p o r t j a v a a w t * ; i m p o r t j a v a a w t e v e n t * ; i m p o r t j a v a a p p l e t * ; i n t e r í a c e I G e o m e t r ỵ C o n s t a n t s {// Định nghĩa Interface gồm các hằng cho trước i n t SQUARE = 0 ; i n t CIRCLE = 1 ; int ELLIPSE = 2;
// Định nghĩa lớp D em oA pplet kế thừa lớp A p p le t và sử dụng các hằng trong giao diện trên p u i l i c c l a s s D e r a o A p p l e t e x t e n d s A p p l e t i m p l e m e n t s
// Khai báo một Panel để chứa các Checkbox tương ứng với các loại hình shape p a n e l s h a p e P a n e l ; / / Khai báo một Panel
C h e c k b o x s q u a r e C B ; // Khai báo một Checkbox ứng với hình vuông
C h e ck b o x c i r c l e C B ; // Khai báo một Checkbox ứng với hình tròn
C h e c k b o x e l l i p s e C B ; // Khai báo một Checkbox ứng với hình ellipse // Khai báo một Panel để chứa các Label và các TextField p a n e l x y P a n e l ; // Khai báo một Panel xyPanel
L a b e l x L a b e l ; // Khai báo một Label xLabel
T e x t F i e l d x l n p u t ; // Khai báo một TextField xlnput
L a b e l y L a b e l ; // Khai báo một Label yLabel
T e x t F i e l d y l n p u t ; // Khai báo một T extField y ln p u t
// Khai báo một Panel để chứa các Label, C hoice và C heckbox panel sizePanel;
// Khai báo một Panel để chứa shape, coordinates, size and fill Panel leítPanel
// Khai báo một Panel để chứa Massage display, dravv button and canvas
// Định nghĩa lại hàm init() p u b l i c v o i d i n i t () { mctkcSliapcPâinel () ; m a k e X Y P a n e l (); m a k e S i z e P a n e l (); m a k e L e f t P a n e l (); m a k e R i g h t P a n e l ();
// Gọi hàm xử lý các sự kiện a d d L i s t e n e r s ();
// Đưa các Panel vào hệ th ố n g a d d (l e f t P a n e l ); a d d ( r i g h t P a n e l ) ;
To create a shape panel, initialize a new Panel and a CheckboxGroup Add checkboxes for different shapes, including a square, circle, and ellipse, with the square checkbox set to true by default Set the layout of the shape panel to FlowLayout and add the square and circle checkboxes to the panel.
// Đưa các thành phần về các X, y coordinates vào xyPanel v o i d m a k e X Y P a n e l () { x y P a n e l = n ew P a n e l () ; x L a b e l = new L a b e l ( "X C o o r d i n a t e : ") ; y L a b e l = new L a b e l ( " Y C o o r d i n a t e : ") ; x l n p u t = new T e x t F i e l d (5) ; y l n p u t = new T e x t F i e l d (5) ; xyPanel setLayout (new GridLayout (2,2)) ; x y P a n e l a d d ( x L a b e l ) ; x y P a n e l a d d ( x l n p u t ) ; x y P a n e l a d d ( y L a b e l ) ; x y P a n e l a d d ( y l n p u t ) ;
// Đưa các thành phần về size và fill vào sizePanel v o i d m a k e S i z e P a n e l () { s i z e P a n e l = n e w P a n e l ( ) ; s i z e L a b e l = n e w L a b e l ( " S i z e : " ) ; s i z e C h o i c e s = n e w C h o i c e () ; s i z e C h o i c e s a d d ( s i z e N a m e s [ 0 ] ) ; s i z e C h o i c e s a d d ( s i z e N a m e s [ 1 ] ) ; s i z e C h o i c e s a d d ( s i z e N a m e s [ 2 ] ) ; f i l l C B = new C h e c k b o x ( f a l s e ) ; s i z e P a n e l s e t L a y o u t (new F l o w L a y o u t () ) ; s i z e P a n e l a d d ( s i z e L a b e l ) ; s i z e P a n e l a d d ( s i z e C h o i c e s ) ; s i z e P a n e l a d d ( f i l l C B ) ;
// Đua các thành phần vào leftPanel v o i d m a k e L e f t P a n e l () { l e f t P a n e l = n e w P a n e l ( ) ; lef tPanel setLayout (new BorderLayout () ) ; l e f t P a n e l a d d ( s h a p e P a n e l , " N o r t h ” ) ; l e f t P a n e l a d d ( x y P a n e l , " C e n t e r " ) ; l e f t P a n e l a d d ( s i z e P a n e l , " S o u t h " ) ;
// Đưa các thành phần vào rightPanel v o i d r a a k e R i g h t P a n e l () { r i g h t P a n e l = n e w P a n e l () ; m e s s a g e D i s p l a y = n ew T e x t F i e l d ( "MESSAGE DISPLAY") ; m e s s a g e D i s p l a ỵ s e t E d i t a b l e ( f a l s e ) ; m e s s a g e D i s p l a y s e t B a c k g r o u n d ( C o l o r y e l l o w ) ; d r a w B u t t o n = n e w B u t t o n ( "D raw " ) ; d r a w B u t t o n s e t B a c k g r o u n d ( C o l o r l i g h t G r a y ) ; d r a w R e g i o n = n ew D r a w R e g i o n () ; d r a w R e g i o n s e t s i z e ( 1 5 0 , 1 5 0 ) ; d r a w R e g i o n s e t B a c k g r o u n d ( C o l o r w h i t e ) ; r i g h t P a n e l setLayout (new BorderLayout () ) ; shapePanel.add(ellipseCB); r i g h t P a n e l a d d ( d r a w B u t t o n , B o r d e r L a y o u t NORTH); r i g h t P a n e l a d d ( m e s s a g e D i s p l a y , B o r d e r L a y o u t SOUTH); r i g h t P a n e l a d d ( d r a w R e g i o n , B o r d e r L a y o u t CENTER);
// Xừ lý các sự kiện tương ứng với các việc thực hiện trên các thành phẩn đồ hoạ v o i d a d d L i s t e n e r s () { d r a w B u t t o n a d d A c t i o n L i s t e n e r (n ew A c t i o n L i s t e n e r () {// (1) p u b l i c v o i d a c t i o n P e r f o r m e d (A c t i o n E v e n t e v t ) { i n t s h a p e , x C o o r d , y C o o r d , w i d t h ; m e s s a g e D i s p l a y s e t T e x t ( " 11) ; i f ( s q u a r e C B g e t s t a t e ( ) ) s h a p e = SQUARE; e l s e i f ( c i r c l e C B g e t s t a t e ( ) ) s h a p e = CIRCLE; e l s e i f ( e l l i p s e C B g e t s t a t e ( ) ) s h a p e = E L L IP S E ; e l s e { m e s s a g e D i s p l a y s e t T e x t ( "Unknow s h a p e " ) ; r e t u r n ;
} s w i t c h ( s i z e C h o i c e s g e t s e l e c t e d l n d e x ( ) ) { c a s e SMALL : w i d t h = 3 0 ; b r e a k ; caseM ED IU M : w i d t h = 6 0 ; b r e a k ; c a s e L A R G E : w i d t h = 1 2 0 ; b r e a k ; d e f a u l t : m e s s a g e D i s p l a y s e t T e x t ( "Unknow s i z e ") ; r e t u r n ;
}) ; // Kết thúc câu lệnh (1) x l n p u t a d đ T e x t L i s t e n e r (n ew T e x t L i s t e n e r ( ) { / / (2) p u b l i c v o i d t e x t v a l u e c h a n g e d ( T e x t E v e n t e v t ) { c h e c k T F ( x l n p u t ) ;
} } ) ; / / Kết thúc câu lệnh (2) y l n p u t a d d T e x t L i s t e n e r (n ew T e x t L i s t e n e r () { // (3) p u b l i c v o i d t e x t V a l u e C h a n g e d ( T e x t E v e n t e v t ) { c h e c k T F ( y l n p u t ) ;
// Định nghĩa lớp DrawRegion mờ rộng lóp Canvas và sứ dụng các hàng ờ giao diện c l a s s D r a w R e g i o n e x t e n d s C a n v a s i m p l e m e n t s I G e o m e t r y C o n s t a n t s { p r i v a t e i n t s h a p e , x C o o r d , y C o o r d ; p r i v a t e b o o l e a n f i l l F l a g ; p r i v a t e i n t w i d t h ; p u b l i c D r a w R e g i o n () { s e t s i z e ( 1 5 0 , 1 5 0 ) ; s e t B a c k g r o u n d ( C o l o r w h i t e ) ;
// Định nghĩa hàm doDraw() đề vẽ public voiddoDraw(int h, int X, int ỵ, boolean f, int w) { t h i s s h a p e = h ; t h i s x C o o r d = X; t h i s y C o o r d = y ; t h i s f i l l F l a g = f ; t b i s w i d t h = w; r e p a i n t ( ) ; p u b l i c v o i d p a i n t ( G r a p h i c s g) { } s w i t c h (s h a p e ) { c a s e SQUARE: i f ( f i l l F l a g ) g f i l l R e c t ( x C o o r d , y C o o r d , w i d t h , w i d t h ) ; e l s e g d r a w R e c t ( x C o o r d , y C o o r d , w i d t h , w i d t h ) ; b r e a k ; c a s e CIRCLE: i f ( f i l l F l a g ) g f i l l O v a l ( x C o o r d , y C o o r d , w i d t h , w i d t h ) ; e l s e g d r a w O v a l ( x C o o r d , y C o o r d , w i d t h , w i d t h ) ; b r e a k ; c a s e E L L IP S E : i f ( f i l l F l a g ) g f i l l O v a l ( x C o o r d , y C o o r d , w i d t h , w i d t h / 2 ) ; e l s e g d r a w O v a l ( x C o o r d , y C o o r d , w i d t h , w i d t h / 2 ) ; b r e a k ;
> C hương trình 5.25: Viết chương trình mô phòng máy tính số học
( C a l c u l a t o r ) thực hiện được các phép: +, *, / có giao diện như hình 5.31. Để thực hiện được các phép tính +, *, / số học, người sử dụng có thề thực hiện:
■ Nhấn chuột ở các ô chữ số để nhập vào đối số thứ nhất;
■ Nhấn chuột ở các ô +, *, / tương ứng với phép các phép toán muốn thực hiện;
* Nhấn chuột ờ các ô chữ số để nhập vảo đối số thứ hai;
■ Nhấn chuột ớ có dấu '=' để biết kết quả Nhấn vào ô có chữ 'C' để xoá kết quá khỏi bộ nhớ.
Chương trình này được thiết kế để tạo ra giao diện theo mô hình hình 5.31 và xử lý các sự kiện khi người dùng nhấn chuột vào các nút tương ứng.
C a l c u l a t o r engine;//class Calculator được định nghĩa sau
// Tạo ra đối tượng của WindowAdapter xử lý các tín Window
S y s te m e x i t (0); // Thoát ra khói chương trình
B u t t o n b ; e n g i n e = e ; t o p = n ew P a n e l ( ) ; //Vùng để hiển thị số liệu t o p a d d ( d i s p l a y = n e w T e x t F i e l d (2 0 ) ) ; b o t t o m = n ew P a n e l () ; b o t t o m s e t L a y o u t ( n e w G r i d L a y o u t ( 4 , 4 ) ) ; b o t t o m a d d (b = n ew B u t t o n (" 1 " ) ) ; b a d d A c t i o n L i s t e n e r ( t h i s ) ; b o t t o m a d d (b = n ew B u t t o n ( " 2 " ) ) ; b a d d A c t i o n L i s t e n e r ( t h i s ) ; b o t t o m a d d (b = n ew B u t t o n ( "3 " ) ) ; b a d d A c t i o n L i s t e n e r ( t h i s ) ; b o t t o m a đ d (b = n ew B u t t o n (" 4 ") ) ; b a d d A c t i o n L i s t e n e r ( t h i s ) ; b o t t o m a d d ( b = n e w B u t t o n ( " 5 " ) ) ; b a d d A c t i o n L i s t e n e r ( t h i s ) ; b o t t o m a d d ( b = n ew B u t t o n ( " 6 " ) ) ; b a d d A c t i o n L i s t e n e r (t h i s ) ; b o t t o m a d d ( b = n e w B u t t o n ( " 7 " ) ) ; b a d d A c t i o n L i s t e n e r ( t h i s ) ; b o t t o m a d d ( b = n ew B u t t o n ( " 8 " ) ) ; b a d d A c t i o n L i s t e n e r ( t h i s ) ; b o t t o m a d d ( b = n ew B u t t o n ( " 9 " ) ) ; b a d d A c t i o n L i s t e n e r ( t h i s ) ; b o t t o m a d d ( b = n ew B u t t o n (" + " ) ) ; b a d d A c t i o n L i s t e n e r ( t h i s ) ; b o t t o m a d d ( b = n ew B u t t o n b a d d A c t i o n L i s t e n e r ( t h i s ) ; b o t t o m a d d ( b = n ew B u t t o n ( " * " ) ) ; b a d d A c t i o n L i s t e n e r ( t h i s ) ; b o t t o m a d d ( b = new B u t t o n ( " / " ) ) ; b a d d A c t i o n L i s t e n e r ( t h i s ) ; b o t t o m a d d ( b = new B u t t o n (" = " ) ) ; b a d d A c t i o n L i s t e n e r (t h ì s ) ; b o t t o m a d d ( b = new B u t t o n ( "C" ) ) ; b a d d A c t i o n L i s t e n e r (t h i s ) ; b o t t o m a d d ( b = n ew B u t t o n { " 0 " ) ) ; b a d d A c t i o n L i s t e n e r ( t h i s ) ;
// Đật layout cho chương trình s e t L a y o u t (n ew B o r d e r L a y o u t ( ) ) ; a d d ( " N o r t h " , t o p ) ; a d d ( " S o u t h 11, b o t t o m ) ; a d d W i n d o w L i s t e n e r ( l i s t e n e r ) ; s e t s i z e (1 8 0 , 1 6 0 ) ; sh o w () ;
// Xử lý các sự kiện khi nhấn chuột vào các n ú t p u b l i c v o i d a c t i o n P e r f o r m e d ( A c t i o n E v e n t e ) { c h a r c = e g e t A c t i o n C o m m a n d () c h a r A t ( 0 ) ; i f ( c == ' + ' ) e n g i n e a d d () ; e l s e i f ( c == ' - 1 ) e n g i n e s u b t r a c t () ; e l s e i f ( c == ' * ' ) e n g i n e m u l t i p l y () ; e l s e i f ( c == ' / ' ) e n g i n e d e v i d e () ; e l s e i f (c >= ' 0 ' £c& c C hương trình 6.1: Sừ dụng lớp B y t e A r r a y l n p u t S t r e a m và
Thực hiện chương trình và nhập vào "N h ap v a o m o t m a n g c a c b y t e " , kết quả hiên thị như hình 6.2.
Nhap luong vao Nhap vaú ằot iang cac byte Luong ra la Nhap vaó aot mang cac byte
So byte cua luong ra 26
So byte cua luong vao :26
Do la Nhap vao Mot nang cac byte
Lớp F ile
Lớp F i l e cung cấp giao diện chung cho việc xử lý hệ thống tệp, độc lập với môi trường máy tính Ứng dụng có thể sử dụng các chức năng chính của lớp F i l e để thao tác với tệp và thư mục trong hệ thống tệp Để xử lý nội dung của các tệp, người dùng cần sử dụng các lớp F i l e l n p u t s t r e a m, F i l e O u t p u t S t r e a m và R a n d o m A c c e s s F i l e.
Lớp F i l e định nghĩa các thuộc tính phụ thuộc vào môi trường (platform), giúp xử lý tệp và tên gọi các đường dẫn trong thư mục một cách độc lập với môi trường.
Ký hiệu phân cách trong đường dẫn là yếu tố quan trọng giúp xác định cấu trúc và thành phần của đường dẫn Trong hệ điều hành Unix, ký hiệu '/' được sử dụng để ngăn cách các thư mục, trong khi đó, trong Windows, ký hiệu '\' được sử dụng cho mục đích tương tự Việc hiểu rõ các ký hiệu này giúp người dùng dễ dàng điều hướng và quản lý hệ thống tập tin hiệu quả hơn.
Trong Windows, đường dẫn như c:\book\chuong1 được sử dụng để xác định vị trí của các tệp và thư mục Để định nghĩa các ký hiệu hoặc chuỗi dùng để phân cách tệp và tên thư mục trong danh sách đường dẫn, ta sử dụng các ký hiệu ngăn cách Các ký hiệu này giúp tổ chức và quản lý các đường dẫn một cách hiệu quả.
U n i x , đ ư ợ c sử dụng để phân cách các đường dẫn trong W indow.
Ví dụ: C : \ b o o k ; C : \ J a v a ; D : \ U s e r s \ L a n ; A : \ T e x t là danh sách các đường dẫn trong W indow.
Gán đường dẫn p a th N a m e cho đối tượng lớp F i l e, có thể là đường dẫn tuyệt đối hoặc đường dẫn tương đối Đường dẫn tuyệt đối bao gồm tên ổ đĩa và cấu trúc thư mục đầy đủ, trong khi đường dẫn tương đối bắt đầu từ thư mục hiện tại.
Gán tệp có tên f i l e n a m e ở thư mục d i r e c t cho đối tượng cùa lớp
F i l e Nếu d i r e c t là n u l l thỉ f i l e n a m e được xử lý ở thư mục hiện thời, ngược lại tên đường dẫn sẽ là đối tượng d i r e c t ghép với s e p a r a t o r và f i l e n a m e Ví dụ:
Lóp F i l e có thể sử dụng để truy vấn vào các hệ thống tệp để biết được các thông tin về tệp và các thư mục.
Lớp F i l e cung cấp các hàm để nhận được các biểu diễn phụ thuộc vào môi trường cùa đường dẫn và các thành phần cùa đường dẫn s t r i n g g e t N a m e ()
Hàm g e tN a m e () cho lại tên cùa tệp trong thư mục chi định Ví dụ, tên cùa
Hàm g e t P a t h () cho lại tên của đường dẫn (tuyệt đối hoặc tương đối) chứa tệp chỉ định. s t r i n g g e t A b s o l u t e P a t h ()
Hàm g e t A b s o l u t e P a t h () cho lại tên của đường dẫn tuyệt đối chứa tệp chi định. l o n g l a s t M o d i f i e d ()
Hàm này cho lại thời gian dạng số l o n g của lần sửa đổi tệp lần cuối cùng, l o n g l e n g t h O
Hàm này cho lại kích thước của tệp tính theo b y t e b o o l e a n e q u a l s ( O b j e c t o b j )
Hàm này so sánh tên các đường dẫn của các đối tượng tệp, cho kết quà t r u e nếu chúng đồng nhất với nhau.
Hai hàm này cho kết quà t r u e nếu tệp đó tồn tại trên đường dẫn hiện thời.
Hàm này cho kết quả t r u e nếu thư mục đó tồn tại trên ồ đĩa hiện thời.
Một tệp mới là rỗng được tạo ra ở thư mục hiện thời chi khi tệp này chưa có.
Tạo ra các đường dẫn được xác định trong đối tượng của F i l e
Hàm này đổi tên tệp hiện thời thành d e s t
Hàm này hiển thị danh sách các tệp ờ thư mục hiện thời.
Hàm này xoá tệp hiện thời.
> C hương trìnlì 6.2: Viết chương trình để đọc và hién thị các tệp trong một tlnr mục. i m p o r t j a v a i o * ; i m p o r t j a v a u t i l * ; p u b l i c c l a s s D i r e c t o r y L i s t e r { p u b l i c s t a t i c v o i d m a i n ( s t r i n g a r g s [] ) {
// Sứ dụng lớp Scanner để đọc
// Đọc tên của thư mục hay tên f i l e e n t r y = new F i l e (d irN a m e) ; / / Tạo ra đối tượng cùa f i l e lấy tên nhập vào l i s t D i r e c t o r y ( e n t r y ) ; // Hiển thị các mục trong danh mục chì định } p u b l i c s t a t i c v o i d l i s t D i r e c t o r y ( F i l e e n t r y ) { t r y { i f ( ! e n t r y e x i s t s ( ) ) {
// Nếu đối số cùa chương trình là một tệp thi hiển thị tệp đó
// Nếu đối số cùa chương trinh là một danh mục thi đọc ra ( l i s t ( ) ) s t r i n g [] f i l e N a m e = e n t r y l i s t () ; i f ( f i l e N a m e == n u l l ) r e t u r n ; f o r ( i n t i = 0 ; i < f i l e N a m e l e n g t h ; i + + ) {
//Tạo ra đối tượng của f i l e để xử lý từng mục
F i l e i t e m = n ew F i l e ( e n t r y g e t P a t h ( ) , f i l e N a r a e [ i ] ) ; // Gọi đệ quy hàm l i s t D i r e c t o r y () để hiển thị từng tệp l i s t D i r e c t o r y ( i t e m ) ;
Chạy chương trình và nhập vào một thư mục, ví dụ: "D: \ M a s t e r " thì tất cà các f i l e trong thư mục này sẽ được hiển thị có dạng như hình 6.3.
Hình 6.3 Hiển thị nội dung của thư mục
> C hương trình 6.3: Nhập vào một f i l e hoặc một thư mục ( D i r e c t o r y ) , chuông trình kiểm tra và hiển thị các thông tin liên quan đến f i l e hoặc thư mục. i m p o r t j a v a a w t * ; i m p o r t j a v a a w t e v e n t * ; i m p o r t j a v a i o * ; i m p o r t j a v a x s w i n g * ; p u b l i c c l a s s F i l e T e s t e x t e n d s J F r a m e i m p l e m e n t s A c t i o n L i s t e n e r { p r i v a t e J T e x t F i e l d e n t e r F i e l d ; p r i v a t e Ơ T e x t A r e a o u t p u t A r e a ;
// Thiết lập GUI p u b l i c F i l e T e s t ( ) { s u p e r ( "N hap t e n f i l e h o a c t h u m u c : ") ; e n t e r F i e l d = new J T e x t F i e l d (1 5 ) ; e n t e r F i e l d a d d A c t i o n L i s t e n e r ( t h i s ) ; o u t p u t A r e a = new J T e x t A r e a () ;
Container.add(scrollPane, BorderLayout.CENTER); s e t s i z e (4 00, 4 0 0 ) ; s e t v i s i b l e ( t r u e ) ;
II Hiển thị các thông tin đặc tá f i l e p u b l i c v o i d a c t i o n P e r f o r m e d ( A c t i o n E v e n t a c t i o n E v e n t ) { s t r i n g naraeF = a c t i o n E v e n t g e t A c t i o n C o m m a n d () ;
// Nếu có f i l e trong thư mục hiện thời thì hiển thị các thông tin về f i l e đó i f ( n a m e e x i s t s ( ) ) { o u t p u t A r e a s e t T e x t ( n a m e g e t N a m e ()
// Đưa nội dung cùa f i l e vào o u t p u t A r e a t r y {
// Xử lý các trường hợp ngoại lệ cùa f i l e c a t c h ( I O E x c e p t i o n i o E x c e p t i o n ) {
// Hiển thị nội dung cùa thư mục e l s e i f ( n a m e i s D i r e c t o r y ( ) ) { s t r i n g d i r e c t o r y [] = name l i s t () ; o u t p u t A r e a a p p e n d ( " \ n \ n N o i d u n g c u a t h u muc : \ n " ) ; f o r ( i n t ỉ - 0 ; i < d i r e c t o r y l e n g t h ; i + + ) o u t p u t A r e a a p p e n d ( d i r e c t o r y [ i ] + " \ n " ) ;
// Thông báo lỗi nếu dữ liệu nhập vào không phái là f i l e và thư mục e l s e {
Nhập tên file hoặc thư mục hiện tại, hoặc tên file cùng đường dẫn, hoặc tên thư mục bất kỳ, sau đó nhấn Enter để chương trình hiển thị thông tin và nội dung tương ứng Ví dụ, khi bạn nhập "FileTest.java" và nhấn Enter, chương trình sẽ cung cấp thông tin và nội dung của file đó.
PlleTest Java la flle k h o n g co th u m uc k h o n g p h a i d u o n g d an
D u o n g d an tuyet ơoi: E :\O V B a n \ 8 ac h L T Ja v a (N X B O D )X FileTest java
Im p o rt Ja va.aw t*; im p o rt Jav a a w tô v s n t.*;
The Java import statement "import javax.swing.*;" is crucial for enabling the use of Swing components in Java applications The public class "FileTest" extends the "JFrame" class, allowing it to inherit properties and methods necessary for creating a graphical user interface Additionally, the implementation of an ActionListener enables the class to respond to user interactions effectively The private fields "textField" and "outputArea" are essential for capturing user input and displaying output within the application.
Hình 6.4 Các thông tin vẻ FileTest.java
6.4 Các lớp xử lý tệp
Dữ liệu đầu vào và kết quả tính toán trong chương trình thường cần được ghi vào tệp trên bộ nhớ ngoài Gói java.io cung cấp các lớp hỗ trợ việc đọc và ghi dữ liệu vào tệp, như được trình bày trong hai bảng 6.5 và 6.6.
Bảng 6.5 Các lớp dọc dữ liệu từ tệp
Tên các lớp đọc d ữ liệu theo byte
Nội dung (Dữ liệu được đọc từ m ảng các b y t e phải đ ư ợ c x á c định)
Filelnputstreara Dữ liệu được đọc dưới dạng byte từ đối tượng file và tên tệp kiểu string.
Pilterlnputstreara Lớp cơ sờ của tất cả các lớp làm nhiệm vụ như là các bộ lọc
(f ilterj của các luồng input.
Bufteredlnputstream Lớp được sử dụng đẻ chửa các byte đọc dược vá đưa vảo vùng đệm (buf fer/
Datalnputstream Lớp được sử dụng để đọc các giá trj kiểu nguyên thuỷ được biểu diễn dưới dạng nhj phân
Lớp ObjectInputStream được sử dụng để đọc các đối tượng trong Java cùng với các giá trị kiểu nguyên thủy được biểu diễn dưới dạng nhị phân Trong khi đó, lớp SequenceInputStream cho phép tuần tự hóa từ hai hoặc nhiều luồng vào khác nhau.
Bảng 6.6 Các lớp ghi dữ liệu lên tệp
Tên các lớp ghi d ữ liệu theo byte
Nội dung (Dữ liệu được ghi vào m ảng các b y t e )
F i l e o u t p u t s t r e a m Dữ liệu từ đối tượng f i l e và tên tệp dạng s t r i n g được ghi vào dưới dạng các by te.
F i l t e r O u t p u t S t r e a m Lớp cơ sờ cùa tất cả các lớp làm nhiệm vụ như là các bộ lọc
Buf f e r e d o u t p u t s t r e a m Lớp được sử dụng để ghi các b y t e từ vùng đệm (b u f f e r ^ vào tệp
DataOutpuCStream Lớp được sử dụng để ghi các giá trị kiéu nguyên thuỳ được biểu diễn dưới dạng nhị phân
Lớp ObjectOutputStream trong Java được sử dụng để ghi các đối tượng và các giá trị kiểu nguyên thủy dưới dạng nhị phân Bên cạnh đó, lớp SequenceOutputStream cho phép ghi tuần tự từ hai hoặc nhiều hơn các luồng vào, giúp quản lý dữ liệu hiệu quả hơn.
Các lớp F i l e l n p u t s t r e a m , F i l e O u t p u t S t r e a m định nghĩa các luồng cùa các b y t e vào/ra cho các tệp Chúng có các toán tử tạo lập như sau:
Tạo một tệp với tên "name" và khởi tạo đối tượng tệp "file" hoặc "fdObj" từ File Descriptor để đọc từng byte Nếu tệp không tồn tại, hãy xử lý ngoại lệ "File Not Found" để đảm bảo ứng dụng có thể phản hồi phù hợp với từng ngữ cảnh.
Tạo một tệp có tên n am e, sử dụng đối tượng tệp f i l e hoặc đối tượng f d O b j của F i l e D e s c r i p t o r để ghi từng byte dữ liệu Nếu tệp không tồn tại trên đĩa, hệ thống sẽ tự động tạo một tệp mới tại thư mục hiện tại.
> C hương trìn h 6.4: Viết một chương trình C o p y F i l e để sao một tệp sang tệp khác được thực hiện theo lệnh dạng: j a v a C o p y F i l e < T e p _ c u > < T e p _ m o i >
Thực hiện theo câu lệnh: j a v a C o p y F ile < fro m f i l e > < t o f i l e > i m p o r t j a v a i o * ; c l a s s C o p y F i l e { p u b l l c s t a t i c v o i d m a i n ( s t r i n g a r g s [] ) {
// Lấy các đối số từ chương trinh m a in () và gán cho các tệp t r y { f r o m F i l e = new F i l e l n p u t s t r e a m ( a r g s [0] ) ; //(1) t o F i l e = new F i l e O u t p u t S t r e a m ( a r g s [1] ) ; //(2) } c a t c h ( F i l e N o t F o u n d E x c e p t i o n e) {
// Sao từng byte từ fromFile sang toFile t r y { i n t i = f r o m F i l e r e a d () ; // Đọc một byte từ f r o m F i l e w hi 1 e ( i ! = - 1 ) { // Kiểm tra xem đã cuối tệp chưa? t o F ỉ l e w j r i t e ( i ) ; / / Ghi một b y t e vào t o F i l e i = f r o m F i l e r e a d () ; // Đọc một b y t e từ f r o m F i l e }
} c a t c b ( I O E x c e p t i o n e ) { // Xử lý ngoại lệ khi gặp
} c a t c h ( IO E x c e p tio n e) { // Xừ lý ngoại lệ khi không đóng được tệp
Câu lệnh (1) tạo ra đối tượng là biến tệp f r o m F i l e , có tên lấy từ đối số a g r s [ 0 ] ; lệnh (2) tạo ra đối tượng là biến tệp t o F i l e , cỏ tên lấy từ đối số a g r s [ 1 ].
6.4.1 Các lớp đọc ghi dữ liệu kiểu nguyên thuỷ
Gói java.io cung cấp hai giao diện DataInput và DataOutput để cài đặt các hàm đọc/ghi dạng nhị phân cho các giá trị nguyên thuỳ như boolean, char, byte, short, int, long, float, và double Các hàm đọc bắt đầu bằng read, trong khi các hàm ghi bắt đầu bằng write, theo sau là tên của các kiểu nguyên thuỳ với chữ cái đầu tiên viết hoa Đặc biệt, hai hàm readUTF() và writeUTF() được sử dụng để đọc và ghi các xâu ký tự, với UTF là chuẩn để xử lý Unicode.
Các ký tự U n ic o d e thường sử dụng mã UTF-8 là chuẩn u c s T r a n s f o r m a t i o n
F o r m a t (ucs- U n i v e r s a l C h a r a c t e r S e t ) , cùng loại với A S C II.
■ Đế ghi dạng nhị phân cùa các giá trị nguyên thuý lên tệp ta thực hiện như sau:
1 Tạo ra một đối tượng outFile cùa FileOutputStream:
// M ờ f i l e có tên là " p r i m i t i v e s d a t a " để ghi dữ liệu kiểu nguyên thuý
2 Tạo ra một đối tượng cùa D a t a O u t p u t S t r e a m để ghép với o u t F i l e :
3 Ghi các giá trị nguyên thuỷ vào o u t s t r e a m : o u t s t r e a m w r i t e B o o l e a n ( t r u e ) ;
// Ghi giá trị t r u e vào o u t s t r e a m o u t s t r e a m w r i t e C h a r (' A ') ; // Ghi ký tự 'A' vào o u t s t r e a m o u t s t r e a m w r i t e B y t e ( B y t e MAX_VALUE) ;
// Ghi B y t e MAX_VALUE vào o u t s t r e a m o u t s t r e a m w r i t e S h o r t ( S h o r t MIN_VALUE);
//G hi S h o r t MIN_VALUE vào o u t s t r e a m o u t s t r e a m w r i t e l n t ( 4 1 ) ; //G h i giá trị 41 vào o u t s t r e a m o u t s t r e a m w r i t e L o n g ( L o n g MAX_VALUE) ;
// Ghi L on g MAX_VALUE vào o u t s t r e a m o u t s t r e a m w r i t e F l o a t ( F l o a t MIN_VALUE);
• Để đọc dạng nhị phân cùa các giá trị nguyên thuỷ từ tệp chúng ta thực hiện như sau:
1 Tạo ra một đối tượng i n F i l e của F i l e l n p u t s t r e a m :
// M ở f i l e có tên là " p r i m i t i v e s d a t a " để đọc dữ liệu kiểu nguyên thuý
2 Tạo ra một đối tượng của D a t a l n p u t s t r e a m để ghép với i n F i l e :
3 Đọc các giá trị nguyên thuỷ từ i n S t r e a m : b o o l e a n b = i n S t r e a m r e a d B o o l e a n () ; c h a r c = i n S t r e a m r e a d c h a r () ; b y t e b t = i n S t r e a m r e a d B y t e () ; s h o r t s = i n S t r e a m r e a d s h o r t () ; i n t i = i n S t r e a m r e a d l n t ( ) ; l o n g 1 = i n S t r e a m r e a d L o n g () ; f l o a t f = i n S t r e a m r e a d F l o a t ( F l o a t MIN_VALUE) ; d o u b l e d = i n S t r e a m r e a d D o u b l e ( M a t h P I ) ;
6.4.2 Đ ọc, ghi dữ liệu thông qua bộ đệm buffer
Lớp Buffered Input Stream và Buffered Output Stream cho phép đọc và ghi dữ liệu theo từng khối byte, giúp tăng tốc độ thực hiện so với hai lớp Data Input Stream và Data Output Stream, vốn chỉ xử lý từng byte một Việc đưa dữ liệu vào bộ đệm (buffering) không chỉ tối ưu hóa hiệu suất mà còn cải thiện tốc độ truyền tải dữ liệu.
• Sao chép ( c o p y ) các kết quả vào vùng bộ nhớ đệm được gọi là b u f f e r
■ Toàn bộ kết quả b u f f e r có thể đổ ra đĩa ( d i s k ) trong một lần thực hiện.
• Đề ghi theo b u f f e r các b y t e chúng ta phải tạo ra biến tệp o u t B u f f e r :
Sau đó sir dụng cốc hàm tương ứng như trên để ghi w r i t e X ( ) ) các giá trị kiểu nguyên thuỷ vào o u t s t r e a m
■ Đe đọc theo b u f f e r c á c b y t e ta phải tạo ra biến tệp i n b u f f e r
D a t a I n p u t S t r e a m ( i n B u f f e r ) ; Sau đó sử dụng các hàm tương ứng như trên để đọc ( r e a d x () ) các giá trị kiểu nguyên thuỷ từ i n S t r e a m
> Chương trình 6.5: Mô tả cách dùng các luồng nhập/xuất có lập vùng đệm i m p o r t j a v a i o B u f f e r e d l n p u t s t r e a m ; im p o r t j a v a i o B u f f e r e d 0 u t p u t s t r e a r a ; im p o r t j a v a i o F i l e l n p u t s t r e a m ; i m p o r t j a v a i o S e q u e n c e l n p u t S t r e a m ; im p o r t j a v a i o I O E x c e p t i o n ; p u b l i c c l a s s B u f f e r T e s t { p u b l i c s t a t i c v o i d r a a i n ( s t r i n g a r g s [ ] ) t h r o w s I O E x c e p t i o n { // Định nghĩa luồng i n p u t
//Tạo lập luồng i n p u t và o u t p u t sử dụng bộ đệm
// Đóng tất cà các luồng (f i l e s ) vào/ra i n s t c l o s e ( ) ; o u s t c l o s e ( ) ;
Mở f i l e F i s l là chưong trình chính hiện thời (1) và F i s 2 là một f i l e đã có sẵn ờ thư mục hiện thời là f i l e " T h u j a v a " (2) Tạo ra một vùng đệm để đọc
(3) và một vùng đệm để ghi (4) Đọc ra cho đến khi kết thúc f i l e (E n d Of
F i l e ) (5), đến khi e o f là f a l s e và in ra màn hình (6)'
6.4.3 Đ ọc, ghi các ký tự: R eader, VVriter
Các chương trình cúa J a v a sử dụng mã U n i c o d e để biểu diễn cho tập các ký tự
Trong các ứng dụng của bạn, khi chạy trên những máy khác nhau, có thể sử dụng các mã ký tự khác nhau, chẳng hạn như mã ASCII Hầu hết các tập mã này chỉ là tập con của Unicode.
J a v a cung cấp các lớp trừu tượng R e a d e r , W r i t e r làm cơ sở để mở rộng thành các lớp con làm nhiệm vụ đọc, ghi các ký tự cùa U n ic o d e
Lớp R e a d e r sử dụng những hàm sau để đọc các ký tự U n ic o d e :
■ i n t r e a đ ( c h a r c b u f [ ] , i n t o f f , i n t l e n ) t h r o w s I O E x c e p t i o n Đọc các ký tự U n i c o d e có mã trong khoảng 0 - 65535 (0x0000 - 0xFFFF) Các hàm này nhận giá trị -1 khi ở cuối tệp.
Chuyển đầu đọc đi n ký tự.
Lớp V í r i t e r sử dụng những hàm sau để ghi các ký tự U n ic o d e :
Ghi lên tệp 16 b i t thấp của giá trị c kiểu i n t (32 bit).
Ghi các ký tự từ mảng các ký tự hay xâu ký tự lên tệp. a) G hi các tệp văn bản
Khi viết văn bản ( t e x t ) vào tệp mà sừ dụng các mã ký tự mặc định, ta có thề sử dụng một trong căc cách sau:
■ Khởi tạo đối tư ợng của P r i n t V ỉ r i t e r dựa trên O u t p u t S t r e a r a W r i t e r và được kết nối với F i l e O u t p u t S t r e a m :
1 Tạo ra đối tư ợ ng cù a F i l e O u t p u t S t r e a m có tên tệp i n f o t x t :
2 Tạo ra đối tượng cùa O u t p u t S t r e a m W r i t e r để liên kết với o u t F i l e :
3 Tạo ra đối tư ợ n g P r i n t W r i t e r để liên kết với o u t s t r e a m :
1 Tạo ra đối tượng của F i l e O u t p u t S t r e a m :
2 T ạo ra đối tư ợ n g cùa P r i n t W r i t e r để kết nối với o u t F i l e :
■ Khởi tạo đối tượng cùa P r i n t W r i t e r dựa trên lóp con cùa
1 Tạo ra đối tượng cùa F i l e W r i t e r , lóp con cùa O u t p u t S t r e a m W r i t e r :
2 Tạo ra đối tư ợ n g P r i n t W r i t e r đế liên kết với f i l e W r i t e r :
P r i n t W r i t e r ( f i l e W r i t e r , t r u e ) Khi đọc văn bản ( t e x t ) từ tệp mà sử dụng các mã ký tự mặc định, chúng ta có thể sứ dụng một trong các cách sau:
■ Khởi tạo đối tượng của I n p u t S t r e a m R e a d e r để kết nối với
1 Tạo ra đối tượng cùa F i l e l n p u t s t r e a m có tên tệp i n f o t x t :
2 Tạo ra đối tượng cùa I n p u t S t r e a m R e a d e r để liên kết với i n F i l e :
■ Khời tạo đối tượng cùa F i l e R e a d e r dựa trên lớp con cùa
Tạo ra đối tượng cùa F i l e R e a d e r , lớp con cùa I n p u t S t r e a m R e a d e r :
^ C hư ơ n g trình 6.6: Sứ dụng các lớp R e a d e r và W r i t e r đẻ dọc, ghi cấc ký tự theo các mã chuấn. i m p o r t j a v a i o * ; p u b l i c c l a s s C h a r E n c o d i n g D e m o {
// Ghi lên tệp các ký tự theo mã chuẩn IS08859 1
S y s t e m o u t p r i n t l n ( "Ghi len tep theo ma chuan: " + w r i t e r g e t E n c o d i n g ( ) ) ; // Ghi các giá trị nguyên thuý lèn tệp theo từng dòng p r i n t v ỉ r i t e r p r i n t l n ( t r u e ) ; p r i n t w r i t e r p r i n t l n ( ' A ' ) ; p r i n t w r i t e r p r i n t l n ( B y t e MAX_VALUE); p r i n t v ỉ r i t e r p r i n t l n ( s h o r t MIN_VALUE); p r i n t W r i t e r p r i n t l n ( I n t e g e r MAX_VALUE); p r i n t W r i t e r p r i n t l n ( L o n g MIN_VALUE); p r i n t W r i t e r p r i n t l n ( F l o a t MAX_VALUE); p r i n t w r i t e r p r i n t l n ( M a t h P I ) ;
// Tạo ra đối tượng cùa BufferedReader sứ dụng mã IS08859 1
// Đọc ra các giá trị nguyên thuỷ tò tệp b o o l e a n V = b u f f e r e d R e a d e r r e a d L i n e () e q u a l s (" t r u e " ) ? t r u e : f a l s e ; c h a r c = b u f f e r e d R e a d e r r e a d L i n e () c h a r A t ( 0 ) ; b y t e b = ( b y t e ) I n t e g e r p a r s e l n t ( b u f Ẽ e r e d R e a d e r r e a d L i n e ( ) ) ; s h o r t s = ( s h o r t ) I n t e g e r p a r s e l n t ( b u f f e r e d R e a d e r r e a d L i n e () ) ; i n t i = I n t e g e r p a r s e l n t ( b u f f e r e d R e a d e r r e a d L i n e ( ) ) ; l o n g 1 = L o n g p a r s e L o n g ( b u f f e r e d R e a d e r r e a đ L i n e ( ) ) ; f l o a t f = F l o a t p a r s e F l o a t ( b u f f e r e d R e a d e r r e a d L i n e ( ) ) ; d o u b l e d = D o u b l e p a r s e D o u b l e ( b u f f e r e d R e a d e r r e a d L i n e ( ) ) ; // Đóng tệp mờ ra đề đọc b u f f e r e d R e a d e r c l o s e ( ) ;
// Hiển thị các giá trị ra màn hinh
S y s t e m o u t p r i n t l n ( d ) ; b) V ào/ra trên các thiết bị chuẩn
Thiết bị chuẩn để đưa dữ ỉiệu ra là màn hình thường được thực hiện bởi đối tượng
Truy nhập tệp tuần tự theo đối tư ợ n g
Sự tuần tự hoá đối tượng cho phép chuyển đổi một đối tượng thành dãy các byte, từ đó có thể tái tạo lại đối tượng gốc một cách chính xác.
Lớp ObjectOutputStream cài đặt giao diện ObjectOutput, cung cấp các hàm ghi đối tượng dưới dạng byte, text và các giá trị nguyên thủy Tương tự, lớp ObjectInputStream cài đặt giao diện ObjectInput, cung cấp các hàm đọc đối tượng từ tệp dưới dạng byte, text và các giá trị nguyên thủy.
6.6.1 L ớp O b jectO u tp u tS tream
Lớp Ob j e c t o u t p u t s t r e a m có toán tử tạo lập:
Ví dụ, để lưu trữ các đối tượng vào tệp có tên " k h o D T d a t " thì trước tiên phái mờ tệp:
Để ghi các đối tượng vào tệp đã được mờ, ta sử dụng hàm `final void writeObject(Object obj) throws IOException` Hàm `writeObject()` cho phép ghi một đối tượng bất kỳ, bao gồm cả mảng và xâu ký tự.
■ Lớp Obj e c t l n p u t s t r e a m có toán tử tạo lập:
Ví dụ, để đọc các đối tượng từ tệp có tên "khoD T.dai" thì trước tiên phải mở tệp:
■ Đề đọc các đối tượng từ tệp đã được mở, ta sử dụng: f i n a l O b j e c t r e a d O b j e c t ( ) t h r o w s I O E x c e p t i o n ,
O p t i o n a l D a t a E x c e p t i o n , I O E x c e p t i o n Hàm r e a d O b j e c t () được sứ dụng đé đọc một đối tượng bất kỷ, kẻ cá mảng hay xâu ký tự.
> C hương trình 6.9: Mở tệp để đọc, ghi các đối tượng tuần tự im p o r t j a v a i o * ; p u b l i c c l a s s O b j e c t S e r i a l i z a t i o n D e m o { v o i d w r i t e D a t a () { t r y {
// Mớ tệp để ghi theo đối tượng
// Ghi dữ liệu lên tệp s t r i n g [ ] h o T e n = { " H a " , " L a n " , " A n h " }; l o n g soBD = 2 0 4 5 2 ; i n t [] n g a y N a m S i n h = {19, 1, 1984} ; f l o a t d i e m = 7 5 f ;
// Đóng tệp đã mở để ghi o u t p u t s t r e a m f ĩ u s h ( ) ; o u t p u t s t r e a m c l o s e ( ) ;
S y ste m , e r r p r i n t l n (ex);// Nêu gặp ngoại lệ thì thông báo
// Đọc dữ liệu theo các đối tuợng v o i d r e a d D a t a () { t r y {
// Mờ tệp để dọc dữ liệu
// Đọc dữ liệu s t r i n g t ] h o T e n = ( s t r i n g t l ) i n p u t s t r e a m r e a d O b j e c t ( ) ; l o n g soBD = i n p u t s t r e a m r e a d L o n g () ; i n t [] n g a y S in h = ( i n t [ ] ) i n p u t s t r e a m r e a d O b j e c t ( ) ; s trin g ra o n H o c = ( s t r i n g ) i n p u t s t r e a m r e a d O b j e c t ( ) ; f l o a t d ie m = ( f l o a t ) i n p u t s t r e a m r e a d F l o a t ( ) ;
// Hiển thị thông tin ra màn hình
// Đóng tệp đã mở để đọc i n p u t s t r e a m c l o s e ( ) ; Ị c a t c h ( E x c e p t i o n e x ) {
Chương trình ghi thông tin về đối tượng lên f i l e và đọc tuần tự bhư hình 6 6
H o va ten Ha Lan Ành
Mon hoc Lap trinh Java'
Hình 6.6 Chương trinh đọc/ghi thõng tin cúa đổi tượng
Chương trình 6.10 bao gồm hai lớp là BankUI và AccountRecord, được thiết kế với giao diện đồ họa nhằm tạo ra bản ghi thông tin về tài khoản của người gửi tiền tiết kiệm Hai lớp này được lưu trữ trong gói chương 6.
// F i l e B a n k U I j a v a thiết lập giao diện đồ hoạ p a c k a g e c h u o n g õ ; i m p o r t j a v a a w t * ; i m p o r t j a v a x s w i n g * ; p u b l i c c l a s s B a n k U I e x t e n d s J P a n e l {
// Các nhãn cho G U I p r o t e c t e đ f i n a l s t a t ỉ c s t r i n g nam es [) = { " So t a i k h o a n " ,
" Ho ", " T e n " , " B a l a n c e " , " T o n g s o g i a o d i c h " } ; // Các thành phần GUI được bào vệ ( p r o t e c t e d ) để dùng cho các lớp con sau này //truy cập p r o t e c t e d J L a b e l l a b e l s [] ; p r o t e c t e d J T e x t F i e l d f i e l d s [] ; p r o t e c t e d Ơ B u t t o n d o T a s k l , d o T a s k 2 ; p r o t e c t e d J P a n e l i n n e r P a n e l C e n t e r , i n n e r P a n e l S o u t h ; p r o t e c t e d i n t s i z e ; // s ố trường t e x t trong GUI
// Các hằng tương ứng trong G U I p u b l i c s t a t i c f i n a l i n t ACCOUNT = 0, FIRSTNAME = 1, LASTNAME,= 2,
// Tạo lập các nhãn f o r ( i n t c o u n t = 0 ; c o u n t < l a b e l s l e n g t h ; c o u n t ++) l a b e l s [ c o u n t ] = n e w J L a b e l (n araes [ c o u n t ] );
// Tạo ra các trường t e x t f o r ( i n t c o u n t = 0 ; c o u n t < f i e l d s l e n g t h ; c o u n t ++) f i e l d s [ c o u n t ] = n ew J T e x t F i e l d () ;
// Tạo ra p a n e l để sắp xếp các nhẫn và các trường C ext i n n e r P a n e l C e n t e r = n ew J P a n e l ( ) ; i n n e r P a n e l C e n t e r s e t L a y o u t ( n e w G r i d L a y o u t ( s i z e , 2) ) ;
//Tạo r a p a n e l để sáp xếp b u t t o n s i n n e r P a n e l S o u t h = new J P a n e l () ; i n n e r P a n e l S o u t h a d d ( d o T a s k l ) ; i n n e r P a n e l S o u t h a d d ( d o T a s k 2 ) ;
// Thiết lập bộ chứa C o n t a i n e r và đưa các p a n e l vào đó s e t L a y o u t (new B o r d e r L a y o u t () ); a d d ( i n n e r P a n e l C e n t e r , B o r d e r L a y o u t CENTER); a d d ( i n n e r P a n e l S o u t h , B o r d e r L a y o u t SOUTH); v a l i d a t e () ; // Kiểm tra l a y o u t
/* Đặt giá trị cho t e x t f i e l d ; t h r o w I l l e g a l A r g u m e n t E x c e p t i o n nếu số các xâu không chính xác ở đối số */
/ / Lớp biểu diễn bản ghi thông tin ( r e c o r d o f i n f o r m a tio n ) p a c k a g e c h u o n g 6 ; i m p o r t j a v a i o S e r i a l i z a b l e ; p u b l i c c l a s s A c c o u n t R e c o r d i m p l e m e n t s S e r i a l i z a b l e { p r i v a t e i n t a c c o u n t ; p r i v a t e s t r i n g f i r s t N a m e ; p r i v a t e s t r i n g l a s t N a m e ; p r i v a t e d o u b l e b a l a n c e ; p u b l i c A c c o u n t R e c o r d () { t h i s (0, 0 0) ;
// Sử dụng O b je c tO u tp u tS tr e a m để ghi các thông tin nhập vào về các đối tượng tuần // tự lên tệp. i m p o r t j a v a i o * ; i m p o r t j a v a a w t * ; i m p o r t j a v a a w t e v e n t * ; i m p o r t j a v a x s w i n g * ; i m p o r t c h u o n g 6 B an k U I ; i m p o r t c h u o n g 6 A c c o u n t R e c o r d ; p u b l i c c l a s s C r e a t e S e q u e n t i a l F i l e e x t e n d s J F r a m e { p r i v a t e O b j e c t O u t p u t S t r e a m o u t p u t ; p r i v a t e BankU I u s e r l n t e r f a c e ; p r ỉ v a t e Ơ B u t t o n e n t e r B u t t o n , o p e n B u t t o n , -
//Tạo ra đối tượng giao diện sừ dụng lại cho u s e r i n t e r f a c e u s e r l n t e r f a c e = new B a n k U I (4) ; //4 trườ n g vãn bàn t e x t f i e l d s g e t C o n t e n t P a n e () a đ d ( u s e r l n t e r f a c e , B o r d e r L a y o u t CENTER) ; // Cấu hình b u t t o n d o T a s k l để sử dụng trong chương trình này o p e n B u t t o n = u s e r l n t e r f a c e g e t D o T a s k l B u t t o n ( ) ; o p e n B u t t o n s e t T e x t ( " S a v e i n t o F i l e ");
// Đãng ký nghe ( r e g i s t e r l i s t e n e r ) để mở tệp o p e n F i l e khi b u t t o n nãy // dược nhấn o p e n B u t t o n a d d A c t i o n L i s t e n e r (naw A c t i o n L i s t e n e r () {
// Định nghTa một đối tượng bên trong để xử lý sự kiện o p e n B u tto n e v e n t - // Gọi o p e n F i l e () khi b u t t o n được nhấn p u b l i c v o i d a c t i o n P e r f o r m e d ( A c t i o n E v e n t e v e n t ) { o p e n F i l e ( ) ; }
} // Kết thúc lớp bên trong
// Cấu hình b u t t o n đ o T ask 2 để sù dụng trong chương trinh này e n t e r B u t t o n = u s e r l n t e r f a c e g e t D o T a s k 2 B u t t o n ( ) ; e n t e r B u t t o n s e t T e x t ( " E n t e r "); e n t e r B u t t o n s e t E n a b l e d ( f a l s e ) ;
// Đăng ký nghe đề gọi a d d R e c o r đ () khi b u t t o n này được nhấn e n t e r B u t t o n a d d A c t i o n L i s t e n e r (new A c t i o n L i s t e n e r () {
// Định nghĩa một đối tượng bên trong để xử lý sự kiện e n t e r B u t t o n e v e n i t p u b l i c v o i d a c t i o n P e r í o r m e d ( A c t i o n E v e n t e v e n t ) { a d d R e c o r d ( ) ;
} // Kết thúc lớp bên trong
V Đãng ký nghe đề đóng cửa sổ ( w in d o w c l o s i n g e v e n t ) a d d W i n t ì o w L i s t e n e r (n ew W i n d o w A d a p t e r () {
// Định nghĩa một đối tượng bên trong để xứ lý sự kiện w in d o w C lo s in g e v e n t // Đưa r e c o r d h i ệ n thời ớ GUI vào f i l e , rồi đóng lại ( c l o s e f i l e ) p u b l i c v o i d w i n d o w C l o s i n g ( W i n d o w E v e n t e v e n t ) { i f ( o u t p u t ! = n u l l ) a d d R e c o r d ( ) ; c l o s e F i l e ( ) ;
} // Kết thúc lớp bên trong
/ / Đặc tả tên tệp ( f i l e nam e) p r i v a t e v o i d o p e n F i l e () {
// Hiển thị hộp thoại về f i l e d i a l o g và u s e r có thế lựa chọn f i l e đé mờ
// Neu nhấn C a n c e l b u t t o n ớ d i a l o g thì r e t u r n i f ( r e s u l t == J F i l e C h o o s e r CANCEL_OPTION) r e t u r n ;
F i l e f i l e N a m e = f i l e C h o o s e r g e t S e l e c t e d F i l e () ; //Nhận f i l e đã chọn // Hiền thị lỗi nếu xuất hiện i f ( f i l e N a m e == n u l l I I f i l e N a m e g e t N a m e () e q u a l s C " ) )
// Mớ file t r y { o u t p u t = n ew Obj e c t o u t p u t s t r e a m ( new F i l e O u t p u t S t r e a m ( f i l e N a m e ) ) ; o p e n B u t t o n s e t E n a b l e d ( f a l s e ) ; e n t e r B u t t o n s e t E n a b l e d (t r u e ) ;
/ / Xử lý ngoại lệ khi o p e n i n g f i l e c a t c h ( I O E x c e p t i o n i o E x c e p t i o n ) {
// Đóng f i l e và kết thúc chương trinh p r i v a t e v o i d c l o s e F i l e () { t r y { o u t p u t c l o s e ( ) ;
// Xử lý ngoại lệ khi đóng f i l e c a t c h ( I O E x c e p t i o n í o E x c e p t i o n ) {
A c c o u n t R e c o r d r e c o r d ; s t r i n g f i e l d v a l u e s [] = u s e r l n t e r f a c e g e t F i e l d V a l u e s () ; / / Neu có số tài khoàn ( i f a c c o u n t f i e l d v a l u e i s n o t e m p t y ) i f (! f i e l d v a l u e s [ B a n k U I ACCOUNT ] e q u a l s (" ")) {
//Tạo ra r e c o rd m ớ i r e c o r d = n e w A c c o u n t R e c o r d ( a c c o u n t N u m b e r , f i e l d V a l u e s [ B a n k U I FIRSTNAME ], f i e l d V a l u e s [ B a n k U I LASTNAME ],
D o u b l e p a r s e D o u b l e ( f i e l d V a l u e s [ B a n k U I BALANCE]) ) ; // Ghi r e c o r d và làm mới b u f f e r ( f l u s h b u f f e r ) o u t p u t w r i t e O b j e c t ( r e c o r d ) ; o u t p u t f l u s h ( ) ; e l s e {} Ơ O p t i o n P a n e s h o w M e s s a g e D i a l o g ( t h i s ,
// Xoá các trường văn bản t e x t f i e l d s u s e r l n t e r f a c e c l e a r F i e l d s () ;
// Xử lý ngoại lệ khi a c c o u n t n u m b e r hoặc b a l a n c e f o r m a t sai c a t c h ( N u m b e r F o r m a t E x c e p t i o n f o r m a t E x c e p t i o n ) { Ơ O p t i o n P a n e s h o w M e s s a g e D i a l o g ( t h i s ,
"Bad a c c o u n t nu m b er o r b a l a n c e " , " I n v a l i d N u m b e r F o r m a t ", Ơ O p t i o n P a n e ERROR_MESSAGE) ;
// Xử lý ngoại lệ khi ghi lên tệp ( f i l e o u t p u t ) c a t c b ( I O E x c e p t i o n i o E x c e p t i o n ) { Ơ O p t i o n P a n e s h o w M e s s a g e D i a l o g ( t h i s ,
Thực hiện chương trình và nhập thông tin về người gửi tiền như hình 6.7. closeFile() ; n ĩd o ra d d y c đ c d o i t u o n g P— Ị [ p | [ * x 1
Hình 6.7 Nhập thông tin vào các trường text
" S a c h LT J a v a (NXB GD) " và đặt tên file " b a n k d a t" rồi nhấn " S a v e " để ghi thông tin đã nhập lên tệp (hình 6.8). r f i Sdvc I V 1
Q ClHi ic=3 CO.M ịl_3 NIỊIUI ịd J JavaPi 01*1 ain ỉl *1 s ic li 1 T J W e b -t> a s e d thường xây dựng Ilieo mô hỉnh ba tàng như hình 7.2.
Hinh 7 2 Kiến trúc ba táng ứng dụng JDBC
Các lớp JDBC được tổ chức trong gói j a v a s q l Các lớp JDBC và các chương trình ứng dụng A p p l e t hay ứng dụng độc lập cùa J a v a có thề:
■ Hoặc cũng có thể nạp xuống từ mạng.
Tốt nhất là nên để các lớp JDBC ở máy khách, trong khi các hệ quản trị cơ sở dữ liệu (DBMS) và nguồn dữ liệu nên được đặt trên máy chủ ở một vị trí nào đó trên mạng.
Để kết nối các cơ sở dữ liệu qua JDBC, một chương trình cần sử dụng bộ điều khiển dữ liệu gốc phù hợp với từng hệ quản trị cơ sở dữ liệu (DBMS) Ứng dụng Java có khả năng giao tiếp với máy chủ hoặc các ứng dụng khác thông qua các giao thức RPC hoặc HTTP.
Mỗi cơ sở dữ liệu (CSDL) đều có một API riêng, vì vậy để tương tác hiệu quả với CSDL, người dùng cần hiểu kiến trúc của chúng Để khai thác thông tin và dữ liệu từ nhiều CSDL trên mạng, việc sử dụng các giao diện lập trình ứng dụng (API) là cần thiết để kết nối và thực hiện truy vấn vào các CSDL.
JDBC, tương tự như ODBC, được phát triển bởi Sun để tạo ra giao diện trung gian giữa cơ sở dữ liệu và Java Với API JDBC, người dùng có thể thực hiện các chức năng cơ bản như kết nối, truy vấn và cập nhật dữ liệu trong cơ sở dữ liệu.
■ Thực hiện các truy vấn vào một CSDL;
■ Xù lý kết quà từ truy vấn;
■ Xác định các thông tin về cấu hình hệ thống.
Các lóp trong JDBC A P I được sử dụng để thực hiện những chức năng trên được tổ chức theo kiến trúc như trong hình 7.1.
JDBC định nghĩa các đối tượng API và hàm để tương tác với các cơ sở dữ liệu đã được chỉ định Chương trình ứng dụng Java có thể kết nối với các cơ sở dữ liệu thông qua các đối tượng và phương thức của JDBC.
■ Trước tiên là tạo ra đối tượng kết nối vào một CSDL;
■ Tạo ra đối tượng để xử lý các câu lệnh.
Truyền tham số cho các lệnh SQL trong các hệ quản trị CSDL (DBMS) và các đối tượng xử lý các câu lệnh đó;
■ Tìm kiếm các thông tin là các kết quả truy vấn.
J a v a S o f t cung cấp bộ điều khiển JDBC để truy nhập vào các nguồn dữ liệu dựa vào ODBC, tức là tạo ra cầu nối giữa chúng.
Cầu nối JDBC - ODBC được tồ chức thành lớp J d b c O d b c và thành thư viện ngoại để truy nhập theo bộ điều khiến ODBC (thư viện động JDBCODBC.DLL).
JDBC, với cầu nối JDBC - ODBC, nổi bật với khả năng truy cập hầu hết các cơ sở dữ liệu phổ biến, tương tự như các bộ điều khiển của ODBC.
C á c lớp và giao diện củ a JDBC A PI
Các lớp và giao diện cơ bàn trong JDBC A P I được xây dựng theo kiến trúc như sau:
Chương trình ứng dụng DriverManager
Hình 7.3 Mô hình các lớp, giao diện của JDBC API
7.4.1 J D B C D river Đe có thể tiến hành truy nhập đến các hệ quản trị CSDL sử dụng kỹ thuật JDBC, ta cần phải có trình điều khiển JDBC của hệ quản trị CSDL mà ta đang sừ dụng Trình điều khiển JDBC là đoạn chương trình, do chính nhà xây dựng hệ quản trị CSDL hoặc do nhà cung ứng thứ ba cung cấp, có khả năng yêu cầu hệ quàn trị CSDL cạ thể thực hiện các câu lệnh SQL.
Danh sách các trình điều khiển JDBC cho các hệ quàn trị CSDL khác nhau được
S u n cung cấp và cập nhật liên tục tại địa chi: http://industrv.iava.sun.com/products/idbc/drivers.
Các trình điều khiền JDBC được phân làm bốn loại khác nhau:
Trình điều khiển loại 1, gọi là Bridge Driver, kết nối với các hệ CSDL thông qua cầu nối ODBC và từng là lựa chọn phổ biến trong những ngày đầu của Java Tuy nhiên, do nhiều hạn chế, loại trình điều khiển này hiện nay không còn được ưa chuộng Bridge Driver thường được cung cấp kèm theo bộ J2SE với tên gọi sun.jdbc.odbc.JdbcOdbcDriver.
Trình điều khiển loại 2, hay còn gọi là Native API Driver, chuyển đổi các lời gọi của JD BCA API thành các hàm tương ứng trong thư viện APX cho từng hệ CSDL cụ thể Loại trình điều khiển này thường được cung cấp bởi nhà xây dựng hệ CSDL Để thực thi chương trình mã lệnh với hệ CSDL, cần phải có chương trình đi kèm.
■ Loại 3: JD B C -N e t D r i v e r , điều khiển loại này sẽ chuyển các lời gọi
JDBC API là một chuẩn độc lập với các hệ quản trị cơ sở dữ liệu (CSDL), cho phép chuyển đổi các lệnh gọi thành các lệnh tương ứng của từng hệ CSDL cụ thể thông qua một chương trình trung gian Các trình điều khiển của nhà cung cấp thứ ba thường thuộc loại này, mang lại lợi ích lớn vì không cần cung cấp mã lệnh kèm theo, đồng thời cho phép sử dụng một trình điều khiển duy nhất để truy cập nhiều hệ CSDL khác nhau.
Trình điều khiển loại 4, hay còn gọi là Native Protocol Driver, chuyển đổi các lệnh gọi JDBC API thành mã lệnh của hệ quản trị cơ sở dữ liệu (CSDL) cụ thể Đây là các trình điều khiển thuần Java, cho phép thực thi chương trình mà không cần mã lệnh của hệ CSDL cụ thể, giúp tăng tính linh hoạt và khả năng tương thích trong việc kết nối với các CSDL khác nhau.
7.4.2 JD B C URL Để có thể kết nối với CSDL, ta cần xác định nguồn dữ liệu cùng với các thông số liên quan dưới dạng một URL như sau: j d b c : s u b p r o t o c o l : d s n : o t h e r s
■ s u b p r o t o c o l : được dùng để xác định trình điều khiển để kết nổi với CSDL.
• d s n : địa chỉ CSDL Cú pháp cùa d s n phụ thuộc vào từng trình điều khiển cụ thể.
Ví dụ: j đ b c : o d b c : d b n a m e là URL để kết nối với CSDL tên d b n a m e sử dụng cầu nối ODBC; còn j đ b c : m i c r o s o f t : s q l s e r v e r : / / h o s t n a m e : 1 4 3 3 là
URL đề kết nối với CSDL M i c r o s o f t SQL S e r v e r
Trong đó, h o s t n a m e là tên máy chủ cài đặt SQL S e r v e r
Kết nối cơ sờ dữ liệu qua J D B C
Việc kết nối với CSDL bằng JDBC được thực hiện qua hai bước:
1 Đăng ký trình điều khiển JDBC;
2 Thực thi phương thức g e t C o n n e c t i o n () cùa lớp D r i v e r M a n a g e r
Trình điều khiển JDBC được nạp khi mã b y t e c o d e cùa nó được nạp vào JVM Một cách đơn giản để thực hiện công việc này là thực thi phương thức
C la s s f o r N a m e ( " J D B C D r i v e r " ) Ví dụ, để nạp trình điều khiến sử dụng cầu nối ODBC-ƠDBC do S u n cung cấp, ta sử dụng câu lệnh sau:
Sau khi nạp trình điều khiển JDBC, việc kết nối với cơ sở dữ liệu (CSDL) có thể thực hiện qua các phương thức trong lớp DriverManager Phương thức đầu tiên, `public static Connection getConnection(String url)`, sẽ ném ra ngoại lệ SQLException và thực hiện kết nối với CSDL theo yêu cầu Bộ quản lý trình điều khiển sẽ tự động chọn trình điều khiển phù hợp đã được nạp Phương thức thứ hai, `public static Connection getConnection(String url, String user, String pass)`, cũng ném ra ngoại lệ SQLException và cho phép kết nối đến CSDL bằng tài khoản người dùng và mật khẩu đã chỉ định.
P r o p e r t i e s i n f o ) t h r o w s S Q L E x c e p t i o n tương tự như hai phương thức trên, ngoài ra cung cấp thêm các thông tin quy định thuộc tính kết nối thông qua đối tượng cùa lớp P r o p e r t i e s
Kết quả trá về cùa các phương thức trên là một đối tượng của lớp j a v a s q l C o n n e c t i o n được dùng để đại diện cho kết nối đến CSDL.
Chương Irìnli 7.1: Trong phần này, chúng ta sẽ khám phá các phương pháp khác nhau để kết nối với cơ sở dữ liệu Access có tên "movies.mdb", bao gồm bảng "Movies" Bảng này chứa các cột như number, title và category, được trình bày theo hình 7.4.
1 File Ẹdit y|ew Ịnsert Rrmôt Records Tods Window Ịjdp t Ê ■ u V & ó 7 ị ô e ô : % ế i ỉ i ^ 1 V 1 M M (X n u m b e r 1 title categ o ry ío rm at
] S la i VVars A N e w H ope S c ie n c e Fiction D V D
5 S ta r W a r s A tta c k o f th e C lon es S c ie n c e P ictio n D V D
Hinh 7.4 Báng CSDL Access Đê có thể tiến hành kết nối với M i c r o s o f t A c c e s s thông qua cầu nối ODBC, sau khi đà tạo tập tin CSDL m o v ie s m đ b , ta cần phải tạo D a t a S o u r c e Name cho CSDL bằng cách vào C o n t r o l P a n e l và chọn ODBC D a t a S o u r c e (hình 7.5). j r igpac p * > a S o u r c ô À d m ĩ n l d r a i l o r LỊ1Q u*ôô DSN I System DSN I Filô DSN I Drivằrô I Trocmo I C o n n ec tio n Pooling I A boul I
M icroớoll Excel Diivôi (■ k I*J R a mo ve
An ODBC U ser d a ta t o u c e 1 ( 0 ( 0 * irằ/ofrTVằừor> a b o u l how to c o n n e e l (o (ho indicatad d a t a providoi A U t* ( d * ta l o u c e 1 ô only viabl* to you
•rtd c a n on|y b a u i e d on Ih* curren* machin*.
Hình 7.5 Bảng quản trị các nguòn dử liệu của ODBC
Nhấn vào nút "Add" để hiển thị danh sách các trình điều khiển CSDL hiện có Chọn trình điều khiển mà bạn muốn thiết lập dữ liệu để sử dụng.
Driver da Microsott para atquivos texto (■ txí “ csv) Duver do Mic>osoft Access (■ mdb)
Duvai do Mằciosoft dBase ( dbf) Oiiver do Microsoít ExceK' xls) Dnvei do Microsoít Paiadox (■ db ) Duvei M Iô o Mtcrosoớt Visual FoxPio
Micro*oft Acce**-Treiber (" mdb) Miciosoít dBase Dover (- dbf)
Hình 7.6 Tạo lặp nguồn CSDL
Chọn M i c r o s o f t A c c e s s D r i v e r (* m db) và nhấn F i n i s h Cừa sổ cấu hình cho tập tin A c c e s s sẽ xuất hiện và nhập m o v iesD S N vào ô D a t a S o u r c e Name (hỉnh 7.7).
D ata S outo* tlam *: ImovtatO sN( I OK ]
Hình 7.7 Lập CO' ché truy nhập ODBCNhấn nút S e l e c t và chọn tập tin CSDL cần tạo d a t a s o u r c e n am e, sau đó nhấn OK để kết thúc (hình 7.8).
Dalabase N jm e ^ireclone* OK I movies mdb c: \wiley\chôpjaua Te:;tConnect ion nouieiỉDSN
Lo C hương trình 7.2: Truy vấn vào CSDL Trong ví dụ này chúng ta muốn liệt kê tất cả họ (FNam e) và tên sinh viên (LName) từ bảng s t u d e n t trong CSDL
S t u d e n t D B bằng lệnh SELECT của SQL.
// Một ví dụ đơn giản sứ dụng JDBC để đọc dữ liệu từ CSDL: ƠDBCSample j a v a i m p o r t j a v a s q l * ; p u b l i c c l a s s JD BCSam ple{ p ú b l i c s t a t i c v o i d m a i n ( s t r i n g [] a r g s ) { t r y { / / N ạ p D r i v e r J d b c O d b c D r i v e r
} t r y { / / Mọi truy nhập vào CSDL đều thực hiện trong khtìi t r y - c a t c h
// Xác định tên cùa CSDL, tên người sử dụng và mật khấu
" j d b c : õ d b c : S t u d e n t D B " , " " ) ; // T h iế t lập v à th ự c hiện các lệnh cũ a SQL s t a t e m e n t s t m t = c o n c r e a t e S t a t e m e n t () ;
ResultSet rs = s t m t executeQuery ( "SELECT FName,
LName FROM s t u d e n t " ) ; // lliổn thị kél quà sau khi đa sù dụng các lệnh cùa SQL đẻ truy ván w h ỉ l e ( r s n e x t ( ) ) {
System.out.println(rs.getstring("LName"));
// Đóng lại các nguồn dữ liệu đã được mớ r s c l o s e ( ) ; s t m t c l o s e ( ) ; c o n c l o s e ( ) ;
Chương trình Java đơn giản này sử dụng JDBC API để truy cập vào các bảng dữ liệu Nó minh họa các bước cơ bản cần thiết để lấy thông tin và liệt kê một số trường dữ liệu từ các bảng này.
Sau đây chúng ta xét một số giao diện, một số lớp trong gói j a v a s q l và một số hàm chính của chúng.
Trước khi sừ dụng một bộ điều khiển ( D r i v e r ) thì nó phái được đăng ký với
D r i v e r M a n a g e r Điều này thực hiện được bằng cách sừ dụng hàm f o rN a m e () của lớp C l a s s : t r y {
// Xir lý ngoại lệ khi không nạp được
Sau đó chương trình phái sừ dụng:
D r i v e r M a n a g e r g e t C o n n e c t i o n ( S t r i n g u r l ) để tạo ra từng kết nối với CSDL ở u r l
Bộ điều khiển JDBC sử đụng lớp JDBC URL ( U n i f o r m R e s o u r c e L o c a t o r ) để xác định và kết nối với một CSDL Dạng tổng quát cùa nó là j d b c : d r i v e r : d a t a b a s e N a m e
Giao diện C o n n e c t i o n phục vụ cho việc kết nối các CSDL Đối tượng cùa các lớp s t a t e m e n t , P r e p a r e d s t a t e m e n t , C a l l a b l e S t a t e m e n t có thế sừ dụng hàm D r i v e r M a n a g e r g e t C o n n e c t i o n () để thiết lập một kết nối:
■ " u r l" là đối tượng của JDBC URL xác định tên của CSDL cần truy nhập;
■ " u s e rN a m e " là tên cùa người sử dụng;
Mật khẩu được định nghĩa là "p a s s w o r d" Đối với các cơ sở dữ liệu không yêu cầu khai báo tên người sử dụng và mật khẩu, các tham biến này có thể để trống.
Sau khi đã thiết lập được đổi tượng c o n để kết nối, ta có thể sử dụng các câu lệnh của SQL để truy vấn vào CSDL. p u b l i c a b s t r a c t v o i d c o m m i t () t h r o w s S Q L E x c e p t i o n p u b l i c a b s t r a c t b o o l e a n g e t A u t o C o m m i t () t h r o w s S Q L E x c e p t i o n p u b l i c a b s t r a c t v o i d g e t A u t o C o m m i t ( b o o l e a n a u t o C o m m i t ) t h r o w s S Q L E x c e p t i o n p u b l i c a b s t r a c t s t r i n g g e t M e t a D a t a () t h r o w s S Q L E x c e p t i o n p u b l i c a b s t r a c t v o i d s e t C a t a l o g ( S t r i n g c a t a l o g ) t h r o w s S Q L E x c e p t i o n p u b l i c a b s t r a c t v o i d s e t R e a d O n l y ( b o o l e a n r e a d O n l y ) t h r o w s S Q L E x c e p t i o n p u b l i c a b s t r a c t b o o l e a n i s R e a d O n l y () t h r o w s S Q L E x c e p t i o n
Giao diện s t a t e m e n t đại diện cho các lệnh của SQL Chúng ta sừ dụng đối tượng cùa lớp s t a t e m e n t để tạo ra khả năng xử lý các câu lệnh cùa SQL:
Sau đó có thể sử dụng câu lệnh SELECT cùa SQL để truy vấn và thao tác trên những dữ liệu nhận được.
Giao diện statement cung cấp các hàm execute(), executeQuery(), executeUpdate() và executeBatch() để thực hiện các câu lệnh SQL như CREATE, DROP, INSERT, UPDATE, DELETE, và hỗ trợ xử lý theo lô Trước khi thực hiện xử lý theo lô với cơ sở dữ liệu, cần thực hiện uỷ quyền (Commit) để đảm bảo khả năng khôi phục dữ liệu khi có thao tác thất bại Sau khi gọi addBatch() nhiều lần, cần gọi executeBatch() để thực hiện các lệnh SQL theo lô, và lệnh này sẽ trả về kết quả là số dòng đã được cập nhật.
7.7.4 G iao diện P rep ared S tatem en t
Giao diện PreparedStatement đại diện cho chương trình thực hiện tiền xử lý các câu truy vấn SQL nhằm tăng hiệu quả xử lý Đối tượng của PreparedStatement có thể được nhận thông qua hàm preparedStatement() của Connection Tham số của hàm này là câu lệnh SQL, trong đó có thể sử dụng ký tự '?' ở các trường dữ liệu.
Để chuẩn bị các câu lệnh SQL, ta sử dụng câu lệnh `prepared statement` với cú pháp `con.prepared_statement("INSERT INTO student values (?, ?, ?)")` Sau đó, ta có thể cập nhật từng trường dữ liệu của đối tượng `stmt` bằng cách sử dụng các phương thức như `stmt.setInt(1, 20)` để đặt giá trị 20 vào cột đầu tiên, `stmt.setString(2, "Nguyen Van")` để thay đổi tên ở cột thứ hai thành "Nguyen Van", và `stmt.setString(3, "Dong A")` để thay đổi giá trị ở cột thứ ba thành "Dong A" Cuối cùng, ta sử dụng `stmt.addBatch()` để gộp các lệnh lại và thực hiện xử lý theo lô với `int inputCounts = stmt.executeBatch()`, sau đó gọi `con.commit()` để xác nhận các thay đổi.
Kết quả các câu lệnh xử lý với SQL được lưu trữ và xừ lý thông qua đối tượng cùa
R e s u l t S e t Các đối tượng của R e s u l t S e t có thể được tạo ra nhờ các lệnh: e x e c u t e ( ) , e x e c u t e Q u e r y ( ) , e x e c u t e U p d a t e () và một sổ lệnh cùa
Khi thực hiện truy vấn với e x e c u t e Q u e r y () thì viết:
R e s u l t S e t r s = s t m t e x e c u t e Q u e r y ( "S E L E CT * FROM STUDENT" ) ; sẽ chọn ra tất cả các dòng của bảng STUDENT và gán cho đối tượng r s cùa
BẢO MẠT VÀ AN NINH THÔNG TIN 8.1 Giới thiệu về vấn đề bảo mật, an toàn hệ thống thông tin
Bộ nạp lớp và kiểm tra byte code
Chương trình Java chuyển đổi mã nguồn sang ngôn ngữ máy thông qua máy ảo JVM Mỗi lớp trong Java được tạo thành tệp lớp với đuôi class Để thực thi, các tệp lớp này cần được thông dịch, nhằm chuyển đổi lệnh trong JVM thành mã máy của các máy đích.
Chương trình thông dịch của JVM chỉ nạp những lớp cần thiết khi thực hiện ứng dụng Ví dụ, khi bắt đầu chạy chương trình M y P r o g r a m c l a s s, JVM sẽ thực hiện các bước cụ thể để đảm bảo quá trình diễn ra suôn sẻ.
1 JVM có cơ chế để nạp các tệp lớp liên quan, đọc từ đĩa hay tải xuống từ những W e b s i t e chứa các lớp đó Nó sừ dụng cơ chế này để nạp
2 Nếu lớp M y P ro g ra m có các trường dữ liệu hoặc kế thừa từ một lóp cha khác thì những lóp đó cũng được nạp về.
3 JVM sẽ thực hiện phương thức m a in () trong M y P ro g ram , vì phương thức này là tĩnh nên không cần phải tạo ra đối tượng để gọi nó.
4 Nếu trong m a in () lại yêu cầu những đối tượng lớp khác thì chúng sẽ được nạp bồ sung theo yêu cầu.
Để đảm bảo an toàn cho hệ thống, việc xây dựng bộ kiểm soát nạp lớp riêng là cần thiết Bộ kiểm soát này giúp kiểm tra tính toàn vẹn của mã byte trước khi nạp vào JVM, mặc dù hệ thống tự động nạp và kiểm soát các lớp đã được tải xuống mà không cần can thiệp.
8.2.1 V iết bộ nạp lớp C lassL oader riêng
Mọi bộ nạp lớp đều cài đặt Class Loader, với phương thức load class xác định cách nạp lớp ở mức đỉnh Khi một lớp được nạp, tất cả các lớp mà nó tham chiếu sẽ được nạp bởi cùng một bộ nạp Để tạo ra một bộ nạp, chẳng hạn như My Class Loader, cần viết đè phương thức loadClass (string className, boolean resolve) theo các bước cụ thể.
1 K iế m tra xom b ộ n ạp lớ p n ày đ ã đ ư ợ c n ạ p h ay ch ư a, M ụ c đ íc h là b ộ n ạ p lớp cúa ta phải lưu lại một bản ghi về những lớp mà nó đã nạp.
2 Nếu là lớp mới thì kiểm tra xem nó có phải là lớp hệ thống hay không Trường hợp không phải là lớp hệ thống, các mã b y t e c o d e của lớp đó được nạp từ các hệ thống tệp hoặc từ những nguồn khác.
3 Gọi phương thức d e f i n e C l a s s () của C l a s s L o a d e r để giới thiệu các b y t e c o d e cho JVM.
Thông thường, bộ nạp lớp sừ dụng một phép ánh xạ (thường là bàng băm) để lưu giữ các tham chiếu tới các lớp đã được nạp.
> Cliương trình 8.1: Xây dựng bộ nạp lớp để nạp những tệp lớp đã được mã hoá
Người sử dụng cần nhập tên lớp chính (chứa hàm main()), ứng dụng cần thực hiện và khóa mật mã Chương trình sử dụng bộ nạp lớp riêng để tải các lớp chỉ định và gọi hàm main() Bộ nạp lớp sẽ giải mã các lớp được tải về Người dùng chỉ định tên tệp lớp chính, chẳng hạn như chương trình TicTacToe.class, xác định lại khóa (mặc định là 3) và nhấn nút Load Sau khi nạp, hai người chơi có thể tham gia trò chơi cờ ca rô như hình 8.1.
Hình 8.1 Chirơng trinh nạp và kiẻm soát lớp
G r i d B a g C o n s t r a i n t s g b c = n ew G r i d B a g C o n s t r a i n t s ( ) ; g b c w e i g h t x = 0 ; g b c w e i g h t y = 1 0 0 ; g b c f i l l = G r i d B a g C o n s t r a i n t s NONE; g b c a n c h o r = G r i d B a g C o n s t r a i n t s EAST; a d d (new J L a b e l ( " C l a s s " ), g b c , 0, 0, 1, 1) ; a d d (new J L a b e l ( "Key" ), g b c , 0, 1, 1, 1) ; g b c V í e i g h t x = 1 0 0 ; g b c f i l l = G r i d B a g C o n s t r a i n t s H0RIZ0NTAL; g b c a n c h o r = G r i d B a g C o n s t r a i n t s WEST; a d d ( n a r a e F i e l d , g b c , 1, 0, 1, 1) ; a d d ( k e y F i e l d , g b c , 1 , 1 , 1 , 1 ) ; g b c f i l l = G r i d B a g C o n s t r a i n t s NONE; g b c a n c h o r = G r i d B a g C o n s t r a i n t s CENTER; Ơ B u t t o n l o a d B u t t o n = n ew J B u t t o n ( " L o a d " ) ; a d d d o a d B u t t o n , g b c , 0, 2, 2, 1) ; l o a d B u t t o n a d d A c t i o n L i s t e n e r ( new A c t i o n L i s t e n e r ( ) {
// Xây dựng lớp nạp riêng c l a s s C r y p t o C l a s s L o a d e r e x t e n d s C l a s s L o a d e r { p r i v a t e Map c l a s s e s = n ew H ashM ap () ; p r i v a t e i n t k e y ; p u b l i c C r y p t o C l a s s L o a d e r ( i n t k ) { k e y = k ;
// Kiểm tra xem lớp đã được nạp chưa? c l a s s c l = ( C l a s s ) c l a s s e s g e t ( n a m e ) ; i f ( c l == n u l l ) {
// Kiểm tra xem có phải lớp hệ thống không? r e t u r n f i n d S y s t e m C l a s s (na m e ) ;
// Nạp lớp theo từng b y te , tuỳ vào từng bộ nạp lớp b y t e [ ] c l a s s B y t e s = l o a d C l a s s B y t e s ( n a m e ) ; i f ( c l a s s B y t e s == n u l l ) t h r o w new
C l a s s N o t F o u n d E x c e p t i o n ( n a m e ) ; c l = d e f i n e C l a s s ( n a m e , c l a s s B y t e s , 0, c l a s s B y t e s l e n g t h ) ; i f ( c l = = n u l l ) t h r o w n ew C l a s s N o t F o u n d E x c e p t i o n ( n a m e ) ; c l a s s e s p u t (name, c l ) ; // Ghi nhớ lớp được nạp i f ( r e s o l v e ) r e s o l v e C l a s s ( c l ) ; } r e t u r n c l ;
// Nạp từng b y t e và mã hoá chúng theo thuật toán " c a e s a r " s t r i n g cname = n a m e r e p l a c e • c a e s a r " ;
Trong lớp j a v a l a n g C l a s s L o a d e r có các hàm:
Lớp `defineClass(String name, byte data[], int offset, int length)` cho phép thêm một lớp mới vào JVM, với các tham số gồm: `name`, là tên lớp có thể bao gồm tên gói, nhưng không cần chỉ rõ phần đuôi `.class`; `data`, là mảng chứa mã byte của lớp; `offset`, là vị trí bắt đầu trong mảng byte; và `length`, là độ dài của mảng.
Hàm `void loadClass(String name, boolean resolve)` được sử dụng để nạp lớp vào JVM, trong đó `name` là tên lớp có thể bao gồm cả tên gói, nhưng không cần chỉ rõ phần đuôi `.class` Tham số `resolve` có giá trị `true` nếu cần gọi `resolveClass()` để kiểm tra sau khi lớp được nạp.
Tìm lớp hệ thống được nạp vào.
■ v o i d r e s o l v e C l a s s ( C l a s s c ) Được gọi thực hiện khi cờ r e s o l v e là t r u e
Khi một bộ nạp lớp giới thiệu bytecode cho JVM, bytecode này phải được kiểm định qua bộ kiểm tra trước Bộ kiểm tra đảm bảo rằng các lệnh được nạp vào không gây ra thiệt hại Tất cả các ngoại lệ của các lớp hệ thống sẽ được kiểm tra và thông báo khi chúng xuất hiện.
Bộ kiểm tra có thể thẩm định:
■ Các biến phải được khởi tạo giá trị trước khi chúng được sừ dụng.
• Trong các lời gọi hàm, các kiều tham chiếu phải phù hợp, tương thích với các tham số hình thức.
* D àm bào các luật truy cập vào các thành phân riỗng không bị vi pliạni
■ Đảm bảo chương trình khi thực hiện không bị tràn bộ n h ớ ,
Một khi phát hiện ra một sai sót bất kỳ thì lóp đó được xem là không hợp lệ và sẽ không được nạp vào JVM.
Trong thế giới mở của Internet, việc bảo vệ hệ thống khỏi những hành vi phá hoại là vô cùng quan trọng Các mối đe dọa có thể đến từ việc thay đổi kết quả tính toán của chương trình, can thiệp vào các trường dữ liệu riêng của đối tượng trong hệ thống, hoặc thậm chí là việc một chương trình bị ngắt bởi hệ thống bảo mật của trình duyệt.
Trong Java, chương trình biên dịch thực hiện việc kiểm tra chặt chẽ, không cho phép tạo ra các tệp lớp với biến chưa được khởi tạo giá trị hoặc biến riêng (private) bị truy cập từ các đối tượng của lớp khác Điều này giải thích tại sao không có bộ kiểm tra đặc biệt cho những vấn đề này, vì các quy tắc kiểm soát trong Java không được đảm bảo ở các ngôn ngữ khác như C/C++.
P a s c a l Tuy nhiên, dạng b y t e c o d e sử dụng trong tệp lớp là dạng tài liệu hoá và việc sửa nó không có gì khó khăn đối với những người lập trình A s s e m b l y có
315 kinh nghiệm cho thấy rằng người dùng có thể sử dụng các hệ soạn thảo hex và thực hiện chỉnh sửa thủ công để tạo ra các tệp lớp hợp lệ Tuy nhiên, việc này có thể dẫn đến việc sử dụng các lệnh không an toàn trong JVM.
Ví dụ sau đây chi ra khả năng thay đổi tệp lớp và có thể dẫn đến những kết quả không mong muốn.
> Chương trình 8.2: Chương trình đơn giản chạy được cả độc lập lẫn A p p l e t
// Sử dựng hệ soạn thào như Hex V ỉorkshop thay đổi "n = 2" bằng "m = 2" i n t r = m + n ; r e t u r n r ;
Chương trình thực hiện sẽ hiển thị kết quà lên màm hình:
1 + 2 = 3 Nếu ta thay đổi hàm f u n 0 ở ví dụ trên thành: s t a t i c i n t f u n ( ) { i n t n, m ; m = 1 ; m = 2 ; i n t r = m + n ; r e t u r n r ;
Trong trường hợp này, biến n chưa được khởi tạo giá trị, dẫn đến việc nó có thể nhận giá trị ngẫu nhiên từ bộ nhớ, điều này thường xảy ra trong các ngôn ngữ lập trình như C hoặc C++.
Lớp SecurityManager và Perm ission
Một lớp trong JVM được nạp thông qua bộ nạp lớp và được kiểm định bởi bộ kiếm tra Cơ chế an ninh thứ ba trong môi trường Java được thực hiện bởi bộ quản lý bảo mật thông qua lớp Security Manager, có nhiệm vụ kiểm tra xem các thao tác chỉ định có được phép thực hiện hay không Các thao tác cần kiểm tra tính an ninh bao gồm nhiều hành động quan trọng.
• Luồng hiện thời có thể tạo ra một bộ nạp lớp mới;
■ Luồng hiện thời có thể tạo ra một tiến trình con;
■ Luồng hiện thời có thế dừng JVM;
■ Luồng hiện thời có thề truy cập vào các thành phần cùa lớp khác;
■ Luồn£ hiện thời có thể truy cập hoặc làm thay đổi các thuộc tính cùa hệ thống;
■ Luồng hiện thời có thể đọc hoặc ghi vào một tệp;
■ Luồng hiện íhời có thề xoá một tệp;
• Luồng hiện thời có thể kết nối với một S o c k e t từ một máy xác định thông qua số hiệu của cổng;
■ Luồng hiện thời có thể phải chờ, hay mờ kết nối với mộl S o c k e t từ một máy xác định thông qua số hiệu cùa cổng;
■ Luồng hiện thời có thể gọi các phương thức: s t o p ( ), s u s p e n d ( ) , r e sum ( ) , s e t P r i o r i t y ( ) , s e tN a m e ( ) , s e tD a e m o n () cúa một luồng hoặc cùa một nhóm luồng;
■ Luồng hiện thời có thể bất đầu in một tệp;
■ Luồng hiện thời có thế truy cập vào vùng nhớ giành riêng của hệ thống;
Khi chạy ứng dụng Java, mặc định không có quản lý an ninh Để cài đặt tính năng này trong ứng dụng, cần gọi phương thức setSecurityManager() của lớp System.
8.3.1 Vấn đề bảo m ật trong Java 2 Platform
Các JDK 1.0 và 1.1 có mô hình bảo mật đơn giản, trong đó các đối tượng trong ứng dụng có quyền truy cập đầy đủ vào tài nguyên cục bộ, trong khi bộ quản lý an ninh của Applet ngăn chặn mọi truy cập đến các tài nguyên này.
Nền tảng Java 2 có cơ chế quản lý an ninh linh hoạt, sử dụng chính sách bảo mật để cấp quyền thực hiện cho từng chương trình khác nhau.
Hình 8.2 Chính sách cấp quyền đưực thực hiện cho các chirơng trinh
Quyền là một đặc tính được cấp phép và quản lý bởi bộ phận an ninh, thường được gọi là đặc quyền JD K 1.2 hỗ trợ việc tạo ra các lớp để thiết lập quyền cho chương trình.
" r e a d , w r i t e " ) ; cho phép đọc, ghi một tệp bất kỳ ờ thư mục / tm p
Các lớp quản lý quyền thao tác trong JDK 1 2 tạo ra một cấu trúc phân cấp như hình 8.3.
Hình 8.3 Cấu trúc phản cẩp của các lớp P erm isio n trong JDK 1 2
JDK cung cấp mô hình chuẩn để kiểm tra quyền thao tác dựa trên hai lớp là:
Mô hình chuẩn dựa vào đối tượng của lớp Policy để cấp quyền thao tác cho các chương trình nguồn, đảm bảo rằng tại mỗi thời điểm chỉ có một đối tượng duy nhất được sử dụng.
P o l i c y được quyền vận dụng Ta có thể sử dụng
P o l i c y c u r e n t P o l i c y = P o l i c y g e t P o l i c y () để xác định chính sách hiện thời được phép thực hiện cùa chương trinh.
Bảo mật trong Java, đặc biệt là mô hình bảo mật cơ bản của Java, đóng vai trò quan trọng trong việc phát triển các hệ thống nhúng và thiết bị thông minh Để tìm hiểu chi tiết về vấn đề này, bạn có thể truy cập vào trang web http://www.securingjava.com Lớp java.lang.SecurityManager cung cấp các hàm quan trọng hỗ trợ quản lý bảo mật trong ứng dụng Java.
■ v o i d c h e c k P e r m i s s i o n ( P e r m i s s i o n p , O b j e c t c o n t e x t ) Kiểm tra xem chính sách bảo mật hiện thời có cho phép hay không.
Xác định chính sách hiện thời.
■ P e r m i s s i o n C o l l e c t i o n g e t P e r m i s s i o n s ( C o d e S o u r c e s o u r c e ) Lấy lại quyền được thao tác đổi với s o u r c e cho trước.
Bồ sung thêm quyền p vào tuyển tập các quyền cấp trước.
Lấy ra dãy liệt kê các quyền trong tuyển tập. b) Lớp java.lang.C odeS ource có các hàm:
Xác định các chứng chi đối với tệp lớp ứng với nguồn gốc của chương trình.
Xác định vị trí (địa chi) cùa các tệp lớp ứng với nguồn gốc của chương trình.
8.3.2 C ác tệp chính sách bảo mật
Security Class Loader cấp quyền thao tác cho các lớp nạp vào JVM thông qua đối tượng của lớp Policy Người dùng có thể thiết lập một lớp Policy riêng để cấp quyền cho chương trình, sử dụng tệp chính sách (.policy) để truy cập từ xa vào máy tính trên mạng Ví dụ, tệp MyApp.policy có thể bao gồm cấu hình như: grant CodeBase "www.horstmann.com/classes" permission java.io.FilePermission "/tmp/*".
Cấp quyền đọc và ghi cho tất cả các mã được nạp từ trang web www.horstmann.com/classes vào thư mục /tmp Người dùng có thể sử dụng bất kỳ hệ soạn thảo nào như Notepad, Office Word, Jcreator để soạn thảo các tệp chính sách dưới dạng tệp văn bản.
1 Lớp chính sách mặc định được đặt trong tệp j a v a s e c u r i t y ở thư mục con / j r e / l i b của JDK Theo mặc định, tệp này chứa dòng p o l i c y p r o v i d e r = s u n s e c u r i t y p r o v i d e r p o l i c y F i l e
2 Ta có thể thay đổi các vị trí của các tệp chính sách trong j a v a s e c u r i t y Tệp chính sách của j a v a : j a v a p o l i c y được đặc tả mặc định !à: p o l i c y u r l l = f i l e : $ { j a v a h o m e } / l i b / s e c u r i t y / j a v a p o l i c y p o l i c y u r l 2 = f i l e : $ { u s e r h o m e } / j a v a p o l i c y Người quán trị hệ thống có thể thay đổi tệp j a v a p o l i c y và chi rõ những địa chỉ URL thường trực trên những S e r v e r khác.
Thực hiện MyApp với quyền được cấp trong tệp M y A p p p o lic y nêu trên như sau: j a v a - D j a v a s e c u r i t y p o l i c y = M y A p p p o l i c y MyApp
Tương tự đối với A p p l e t , ta thực hiện a p p l e t v i e w e r - J - D j a v a s e c u r i t y p o l i c y = M y A p p l e t p o l i c y
M y A p p l e t h t m l Tệp chính sách chứa một dãy các mục được đảm bảo.
Mỗi mục có dạng như sau: g r a n t c o d e s o u r c e { p e r m i s s i o n - 1 ; p e r m i s s i o n - 2 ;
Cơ sở của mã lệnh Code Base là code source, có thể không cần khai báo nếu mục đầu vào áp dụng cho tất cả các nguồn Tên của những người ký giấy chứng nhận cũng có thể bỏ qua nếu không có yêu cầu về người ký xác nhận.
C o d e B a s e xác định nơi chứa các lớp sẽ được tài về: C o d e B a s e " u r l
Neu URL kết thúc bằng nghĩa là nó chi tới một thư mục, ngược lại là tên của một tệp JAR Ví dụ: g r a n t C o d e B a s e "w w w h o r s t m a n c o m / c l a s s e s / " { } g r a n t C o d e B a s e "w w w h o r s t m a n c o m / c l a s s e s / M y A p p j a r "
C o d e B a s e là một địa chi URL và chứa phần tử ngăn cách '/' giữa các tệp, ngay cà đồi với URL trong W indow , ví dụ: g r a n t C o d e B a s e " f i l e : d : u s e r s / m y a p p s / c l a s s e s " { }
■ Các đặc quyền p e r m i s s i o n có dạng cấu trúc như sau: p e r m i s s i o n c l a s s N a m e t a r g e t N a m e , a c t i o n L i s t
- c l a s s N a m e là tên đầy đù cùa lớp đặc quyền thực hiện, ví dụ như , j a v a n e t N e t P e r m m i s s i o n , j a v a n e t S o c k e t P e r m i s s i o n , j a v a i o P i l e P e r m i s s i o n , j a v a s e c u r i t y S e c u r i t y P e r m i s s i o n , j a v a u t i l P r o p e r t y P e r m i s s i o n , j a v a a w t A W T P e r m ìs s io n , j a v a s e c u r i t y A l l P e r r a i s s i o n
- t a r g e t N a m e là tên tệp hay thư mục được đặc quyền thực hiện, có dạng: f i l e N a m e Một tệp d i r e c t o r y / Một thư mục d i r e c t o r y / * Tất cả các tệp của thư mục d i r e c t o r y
Tất cả các tệp trong thư mục hiện tại và các thư mục con của nó đều được liệt kê, bao gồm tất cả các tệp trong hệ thống.
- a c t i o n L i s t là danh sách các hành động như: r e a d , w r i t e , d e l e t e , e x e c u t e , a c c e p t , c o n n e c t , l i s t e n , r e s o l v e
Lưu ý: Một số lớp đặc quyền không cần chi ra t a r g e t N a m e và a c t i o n L i s t , ví dụ: j a v a s e c u r i t y A l l P e r m i s s i o n
Lớp đặc quyền j a v a n e t N e t P e r m m i s s i o n yêu cầu tên và cồng cùa máy kết nối dạng: h o s t n a m e h o ặ c I P a d d r e s s Máy chù l o c a l h o s t hoặc xâu rỗng Máy khách
* d o m a i n S u f f i x Hậu tố miền cùa máy thực hiện
* Cho tất cả các máy.
Các cổng kết nối có thể liệt kê theo dãy:
: n - Tất cà được đánh số từ n trở lên
: - n Tất cả được đánh số từ n trờ xuống
: n l - n 2 Tất cả được đánh số từ n l đến n2.
Lóp đặc quyền java.util.PropertyPermission khai báo các thuộc tính cần thực hiện với hai dạng chính: property chỉ rõ một đặc tính và propertyPrefix Tất cả các đặc tính có cùng tiếp đầu ngữ sẽ được áp dụng theo dạng propertyPrefix.
" j a v a h o m e " hay " j a v a v m j a v a u t i l P r o p e r t y P e r m i s s i o n " j a v a v m * ", " r e a d " ; cho phép chương trình đọc tất cả các thuộc tính bắt đầu bằng j a v a m
Chúng ta có thể tận dụng các thuộc tính của hệ thống trong các tệp chính sách Dấu hiệu ${property} có thể được thay thế bằng các giá trị cụ thể để tối ưu hóa hiệu quả.
$ {u s e r h o m e } được thay thế bằng thư mục cùa người sử dụng. p e r m i s s i o n j a v a i o F i l e P e r m i s s i o n "$ { u s e r h o r a e } " ,
Để tạo ra các tệp chính sách độc lập với các nền, cần sử dụng thuộc tính file.separator thay thế cho dấu '/' Đồng thời, có thể sử dụng ký hiệu rút gọn để đơn giản hóa quá trình này.
$ { / } thay thế cho $ {f i l e s e p a r a t o r } Ví dụ: p e r m i s s i o n j a v a i o F i l e P e r m i s s i o n
" $ { u s e r h o m e } $ { / } - " , " r e a d , w r i t e " ; cho phép đọc, ghi tất cả các tệp cùa thư mục của người sử dụng và bất kỳ mội thư mục con của thư mục đó.
Ta phải sừ dụng "\\" thay cho "\" trong W in d o w : p e r m i s s i o n j a v a i o F i l e P e r m i s s i o n " d : \ \ m y a p p s \ \ - " ,