Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (8.59 MB, 204 trang )
<span class="text_page_counter">Trang 1</span><div class="page_container" data-page="1">
Sự ra đời và phát triển của máy tính điện tử kéo theo sự phát triển của các phương pháp lập trình cho máy tính điện tử. Bắt đầu từ phương pháp sơ khai, đơn giản nhất là lập trình tuần tự, tiếp đến là lập trình có cấu trúc và hiện nay, được sử dụng rộng rãi trong các môi trường hiện đại là phương pháp lập trình hướng đối tượng (Object-Oriented Programming, viết tắt là OOP).
Phương pháp lập trình có cấu trúc dựa trên cách thức giải quyết bài toán theo hướng chức năng. Theo đó, để giải quyết một bài tốn lớn chúng ta phân rã (theo chức năng) thành nhiều bài toán nhỏ, cứ tiếp tục như vậy để đạt được những bài tốn đơn giản và có thể triển khai lập trình dễ dàng. Quá trình này gọi là phân tích từ trên xuống “top-down”. Phương pháp này dựa trên ngơn ngữ mơ tả bài tốn, chủ yếu chúng ta phải tìm ra các “động từ” để đưa ra các chức năng cần giải quyết trong quá trình phân tích. Mỗi bài tốn con thu được trong phương pháp này sẽ được lập trình để thực hiện dưới dạng một chương trình con, như vậy để giải quyết bài tốn lớn chúng ta sẽ có nhiều mơ-đun chương trình con trong một hệ thống chương trình. Hiện nay, trong hầu hết các mơi trường lập trình đều cung cấp phương pháp lập trình hướng đối tượng. Các nguyên lý và việc áp dụng phương pháp này được khởi nguồn từ những năm 1960, sau đó vào những năm 1980, các ngôn ngữ lập trình hướng đối tượng được phát triển như Smalltalk, Eiffel, C++ và đặc biệt vào những năm 1990, ngôn ngữ Java được phát triển rất mạnh bởi hãng Sun Microsystems, cho đến nay được sử dụng rộng rãi.
Phương pháp lập trình hướng đối tượng dựa trên cách thức giải quyết bài toán theo hướng các đối tượng. Theo đó, chúng ta sẽ xem xét về sự tồn tại của các đối tượng trong bài toán, mối quan hệ tương tác giữa chúng để thực hiện mục tiêu đặt ra
</div><span class="text_page_counter">Trang 2</span><div class="page_container" data-page="2">cho bài tốn, từ đó áp dụng phương pháp phân tích và thiết kế từ dưới lên up”). Trong tài liệu này không đi sâu trình bày về phương pháp phân tích và thiết hướng đối tượng, chúng ta sẽ làm quen với phương pháp thơng qua ví dụ minh họa so sánh giữa phương pháp dựa trên chức năng và phương pháp dựa trên đối tượng như sau.
(“bottom-Để minh họa, chúng ta xem xét bài toán quản lý sinh viên chẳng hạn.
Hình vẽ 1.1: Minh họa bài toán quản lý sinh viên
Rõ ràng, theo hướng chức năng chúng ta đơn giản có thể liệt kê các công việc thực hiện gồm: cập nhật hồ sơ sinh viên; lên kế hoạch đào tạo; tổ chức thi và lên điểm;.... Ở đây chúng ta đã phân rã bài tốn cần làm thành các cơng việc (hay chức năng) nhỏ, như vậy về phía lập trình cơ bản xây dựng các mơ-đun chương trình con để giải quyết từng công việc này. Đối với phương pháp giải quyết dựa trên đối tượng, chúng ta xem xét bài tốn này cần có các đối tượng sinh viên, các đối tượng giáo viên, các đối tượng người quản lý, các đối tượng môn học,.... Trong đó, mỗi loại có thể có nhiều đối tượng khác nhau như sinh viên có thể lên đến hàng nghìn đối tượng. Số lượng cho mỗi loại đối tượng là khác nhau và phụ thuộc vào từng bài toán cụ thể. Sau đó sẽ xem xét mối quan hệ tương tác giữa các đối tượng này để thực hiện các mục tiêu của bài toán đặt ra.
Phương pháp lập trình hướng đối tượng phát sinh nhiều khái niệm mới, yêu cầu người lập trình cần nắm vững và chúng sẽ được trình bày ở phần tiếp sau.
- Đối tượng (objects): là các thể hiện trên bộ nhớ của một gói gồm các biến và hàm trong chương trình phần mềm. Trong thực tế khái niệm này rất rộng, nó ám chỉ đến mọi sự vật, hiện tượng của thế giới thực. Tuy nhiên, khái niệm đối tượng trong lập trình (hay còn gọi là đối tượng phần mềm – software objects) sẽ hạn hẹp hơn nhiều, chủ yếu đề cập đến khía cạnh thơng tin của các đối tượng. Do đó, chúng ta sẽ có các đối tượng trong khơng gian thực của bài tốn, tương ứng là các đối tượng trong khơng gian của chương trình.
Ví dụ về các đối tượng như các sinh viên, giáo viên, môn học, lớp học, hay đối tượng là những chiếc xe máy, xe ơ-tơ, thậm chí là các bánh xe, cánh quạt,...
Chúng ta có thể phân loại gồm đối tượng vơ hình và hữu hình. Trong ví dụ trên thì mơn học, lớp học là các đối tượng vơ hình, cịn sinh viên, giáo viên,… là các đối tượng hữu hình.
- Thuộc tính (properties): là các thành phần (dưới dạng các biến - variables) trong đối tượng để mô tả thông tin dữ liệu hay trạng thái (states) của đối tượng (Hình vẽ 1.2). Ví dụ các đối tượng sinh viên có thuộc tính là họ và tên, ngày-tháng-năm sinh, quê quán,... hay các đối tượng môn học có tên mơn học, số tín chỉ, điều kiện tiên quyết,...
- Phương thức (methods): là các thành phần (dưới dạng các hàm) trong đối tượng để mô tả hành vi (behavior) hay khả năng xử lý của đối tượng (Hình vẽ 1.2). Các phương thức khi thực hiện sẽ xử lý trên các thuộc tính và có thể sẽ làm biến đối trạng thái của đối tượng, tức làm thay đổi giá trị trong các thuộc tính. Ví dụ các đối tượng xe ơ-tơ có phương thức khởi động máy, tăng/giảm ga, chuyển số,... hay các đối tượng sinh viên có phương thức nhận bài kiểm tra, làm bài kiểm tra, tham dự buổi học...
Hình vẽ 1.2: Đối tượng và các thành phần của đối tượng.
- Thông điệp (messages): Chúng ta thấy rằng, các đối tượng phần mềm sẽ quan hệ và tương tác với nhau nhằm để thực hiện mục tiêu của bài toán đặt ra. Khi một đối tượng A muốn một đối tượng B thực hiện một phương thức trên B, thì đối tượng A phải gửi một thông điệp tương ứng đến đối tượng B. Thực chất ở đây là việc đối
</div><span class="text_page_counter">Trang 4</span><div class="page_container" data-page="4">tượng A gọi thực hiện một phương thức trên đối tượng B. Hình vẽ 1.3 sau minh họa cho thơng điệp F(x) được gọi bởi đối tượng A đến đối tượng B.
+ Tên phương thức (method) cần gọi: trong Hình vẽ 1.3 có tên phương thức là “F”.
+ Các tham số truyền cho phương thức (parameters): trong Hình vẽ 1.3 có tham số là “x” được truyền cho lời gọi phương thức “F” trên đối tượng B.
- Lớp đối tượng (classes, hay gọi tắt là lớp): Trong chương trình hướng đối tượng, có thể xuất hiện nhiều đối tượng có cùng kiểu (hay cùng đặc trưng) như các hình chữ nhật, các cơng nhân,... Do đó, một lớp đối tượng được xem như là một bản thiết kế chi tiết để định nghĩa các thành phần (thuộc tính và phương thức) cho tất cả các đối tượng cùng một kiểu.
Lớp là một khái niệm trừu tượng, nó đóng vai trị như bản mẫu cho việc tạo lập hay xây dựng (tức các thể hiện - instance) các đối tượng trong chương trình. Hình vẽ 1.4 sau minh họa cho lớp “Dog” và một đối tượng “Rayne” của “Dog”. Lớp “Dog” có các thuộc tính gồm Color (màu), Eye Color (màu mắt), Height (chiều cao), Length (chiều dài), Weight (cân nặng) và đối tượng “Rayne” có các giá trị thuộc tính tương ứng màu xám, mắt xanh, cao 18 inc, dài 36 inc và nặng 30 pound. Các phương thức của “Dog” gồm Sit (ngồi), Lay Down (nằm xuống), Shake (lắc mình), Come (đi).
</div><span class="text_page_counter">Trang 5</span><div class="page_container" data-page="5">Hình vẽ 1.4: Lớp “Dog” và đối tượng “Rayne”
Hình vẽ 1.5 sau minh họa cho lớp “Student” và các đối tượng sinh viên tương ứng.
Hình vẽ 1.5: Lớp “Student” và các đối tượng
<b>2.2. Các đặc trưng của lập trình hướng đối tượng </b>
Cho đến nay, các nhà phát triển ứng dụng cũng như các tác giả nghiên cứu về phương pháp lập trình hướng đối tượng đều đề cập đến 4 đặc trưng cơ bản của phương pháp lập trình hướng đối tượng. Các vấn đề chi tiết cũng như phương pháp lập trình khai thác các đặc trưng này sẽ được đề cập ở những chương sau, trong phần này chúng ta điểm qua khái niệm về chúng.
- Tính đóng gói (encapsulation): như khái niệm đối tượng đã được đề cập, mỗi đối tượng bao gồm các thành phần thuộc tính để mô tả thông và và các phương thức thể hiện hành vi xử lý thông tin. Như vậy, chúng ta đã đóng gói các thành phần này lại với nhau nhằm phản ánh toàn bộ nội dung của đối tượng (minh họa Hình vẽ 1.6). Xem xét từ góc độ lập trình chúng ta thấy trong chương trình gồm các biến chứa dữ liệu, các đơn vị xử lý (hàm) thao tác trên các biến nhằm xử lý và tính tốn
</div><span class="text_page_counter">Trang 6</span><div class="page_container" data-page="6">để thực hiện yêu cầu đặt ra của bài tốn. Vì thế, các kết quả đóng gói từ các biến và các hàm để hình thành các lớp đối tượng sẽ đem lại hiệu quả thực hiện chương trình tốt hơn. Mục tiêu đặt ra là đóng gói sao cho phản ánh được nội dung thông tin và
hành vi xử lý thông tin của các lớp đối tượng mà chương trình cần có.
Hình vẽ 1.6: Minh họa sự đóng gói các thành phần
Tính đóng gói cịn làm đơn giản hóa quá trình tương tác xử lý giữa các đối tượng, bởi vì nó che đi sự phức tạp cố hữu nội tại bên trong một đối tượng. Các đối tượng khác tương tác xử lý thơng qua những giao tiếp bên ngồi mà khơng cần phải quan tâm đến sự phức tạp bên trong của đối tượng đó. Chẳng hạn, một máy tính cá nhân bản thân bên trong nó chứa những các bộ phận chi tiết, vi mạch phức tạp nhưng chúng ta sử dụng chỉ cần vài thao tác bấm nút là có thể tương tác với nó.
Hình vẽ 1.6: Đóng gói nhằm che đi những chi tiết phức tạp bên trong - Tính che giấu thông tin (data-hiding): các thành phần sau khi được đóng gói chúng ta có thể thiết lập cơ chế về khả năng truy xuất xử lý đến các thành phần đó hay được gọi là phạm vi tác động (scope). Rõ ràng, tính chất này có được là nhờ sự đóng gói (Hình vẽ 1.8).
</div><span class="text_page_counter">Trang 7</span><div class="page_container" data-page="7">
Hình vẽ 1.8: Minh họa cơ chế che dấu thơng tin
- Tính kế thừa (inheritance): là khái niệm quan trọng trong lập trình hướng đối tượng. Thực tế, các đối tượng khơng hồn tồn tách rời nhau mà chúng có những quan hệ nhất định. Chẳng hạn, con mèo và con chó có chung một số đặc điểm và chúng đều được gọi vật ni, hay sinh viên và giáo viên có những đặc điểm chung vì đều là con người... Như vậy, nếu các lớp đối tượng có chung một số đặc điểm và được xem như có quan hệ “là” (is a) với lớp đối tượng khác thì chúng ta nói có sự kế thừa giữa chúng.
Hình vẽ 1.9: Minh họa sự kế thừa giữa các lớp đối tượng
Trong Hình vẽ 1.9, đối tượng “oHuman” và “oPet” đều kế thừa các đặc điểm từ “oAnimal” tức chúng đều có não bộ (brain = true) và đều có chân, nhưng số chân giữa “oHuman” và “oPet” khác nhau, tương tự giữa “oDog” và “oCat” với “oPet”.
- Tính đa hình (polymorphism): là một khái niệm khá phức tạp trong lập trình hướng đối tượng, nó cho phép nhiều đối tượng xử lý, phản hồi cho cùng một thơng điệp. Một khía cạnh khác, đa hình tức là cùng một đối nhưng được khai thác, xử lý dưới nhiều hình thức khác nhau. Tính đa hình được gắn liền với ngữ cảnh trong chương trình, mỗi ngữ cảnh sẽ cho ra một hình thức khai thác, xử lý cụ thể phù hợp. Chẳng hạn, Hình vẽ 1.9 cho thấy một con mèo có thể xem như là một vật ni, hoặc một động vật, phụ thuộc vào ngữ cảnh khai thác.
Bốn tính chất của phương pháp lập trình hướng đối tượng là những tính chất rất đặc trưng, các vấn đề về kỹ thuật và phương pháp sử dụng, khai thác những tính chất này sẽ được trình bày kỹ ở những chương tiếp theo. Phần sau chúng ta xem xét về ngơn ngữ lập trình hướng đối tượng.
<b>3.1. Sự phát triển của các ngơn ngữ lập trình hướng đối tượng </b>
</div><span class="text_page_counter">Trang 8</span><div class="page_container" data-page="8">Về cơ bản, một ngơn ngữ lập trình được gọi là hướng đối tượng nếu nó cung cấp đủ 4 đặc trưng đã xem xét ở trên: tính đóng gói, tính che dấu thơng tin, tính kế thừa và tính đa hình.
Ngơn ngữ lập trình hướng đối tượng được phát triển cùng với sự hình thành và phát triển của phương pháp lập trình hướng đối tượng (Hình vẽ 1.10). Phương pháp này được khởi xướng vào những năm 1960 tại Na-uy, sau đó được các nhà nghiên cứu, ứng dụng phát triển rất mạnh mẽ. Có thể xem ngơn ngữ Simula của Christian Nygaard và cộng sự tại đại học Oslo là ngôn ngữ đầu tiên hỗ trợ hướng đối tượng. Sau đó những năm 1970 và 1980 tiếp theo là sự phát triển các ngôn ngữ Smalltalk, Eiffel và C++.
Ngôn ngữ Java được xây dựng và phát triển bởi James Gosling và cộng sự tại hãng Sun Microsystems, nó trở nên phổ biến vào cuối những năm 1990. Khác với C++ có sự kết hợp của cả lập trình cấu trúc và hướng đối tượng, Java là ngôn ngữ thuần hướng đối tượng, tức mọi thành phần của chương trình đều phải được đóng gói thành các lớp đối tượng, mọi hành động (actions) đều được thực hiện trên các đối tượng và các lớp. Đặc điểm thứ hai của Java khác C++ đó là các đối tượng không cần đến việc giải phóng bộ nhớ sau khi khai thác xử lý xong của người lập trình do cơ chế tự động “thu gom rác” (garbage collection) được cung cấp sẵn bởi Java, điều này giống với 2 ngôn ngữ Smalltalk và Eiffel.
Hình vẽ 1.10: Lịch sử phát triển các ngơn ngữ hướng đối tượng
Trong khuôn khổ tài liệu này, chúng ta tập trung khai thác sử dụng ngôn ngữ Java để thể hiện cho các vấn đề của phương pháp lập trình hướng đối tượng. Các phần tiếp sau sẽ trình bày cụ thể hơn về ngơn ngữ lập trình Java.
<b>3.2. Ngơn ngữ lập trình Java </b>
Java là ngơn ngữ lập trình được sử dụng khá phổ biến hiện nay, nó khơng chỉ được dùng để phát các ứng dụng cho máy tính mà cịn sử dụng để phát triển các ứng dụng cho các thiết bị di động như điện thoại di động, điện thoại thông minh,... đặc biệt là lập trình trên hệ điều hành Android.
Một số đặc điểm của ngôn ngữ Java:
- Cấu trúc cú pháp lệnh của ngôn ngữ hầu hết kế thừa từ C/C++ nên dễ tiếp cận nếu đã biết ngôn ngữ C/C++, mềm dẻo và linh hoạt trong sử dụng nhưng cũng rất chặt chẽ về cú pháp.
- Là ngơn ngữ lập trình thuần hướng đối tượng như đã đề cập ở trên.
- Java áp dụng cơ chế bộ nhớ động cho mọi đối tượng trong chương trình. Do đó, một khai báo biến bất kỳ có kiểu lớp đều dưới dạng tham chiếu (con trỏ), tức là một biến chứa địa chỉ của đối tượng.
Về phía hệ thống, các đối tượng khi tạo sẽ được cấp phát bộ nhớ trên vùng heap (trên RAM), do đó mỗi đối tượng có một địa chỉ tương ứng. Để truy cập xử lý các đối tượng này chúng ta phải khai báo các biến tham chiếu để lưu giữ địa chỉ của đối tượng (Hình vẽ 1.11).
Hình vẽ 1.11: Minh họa tham chiếu và 02 đối tượng
- Độc lập với môi trường thực hiện. Đây là đặc điểm nổi bật của Java, tức một chương trình bằng ngơn ngữ Java sau khi được biên dịch có thể chạy được trên các hệ nền khác nhau (hệ nền được hiểu bao gồm hệ điều hành và hệ thống phần cứng). Hình vẽ 1.12 minh họa điều này, chương trình sau khi viết và biên dịch có thể chạy trên hệ điều hành Windows, Unix, hoặc MacOS.
</div><span class="text_page_counter">Trang 10</span><div class="page_container" data-page="10">
Hình vẽ 1.12: Sự độc lập với hệ nền của chương trình Java
Với đặc điểm này, giới lập trình Java thường sử dụng khẩu hiệu thể hiện là “write one, run anywhere” để ám chỉ rằng chương trình Java được viết một lần và chạy ở khắp mọi nơi.
Sự độc lập này được thực hiện nhờ cơ chế máy ảo (Java Virtual Machine - JVM) để thực hiện chương trình. JVM là một hệ thống phần mềm được xây dựng và đóng gói sẵn, sau đó cài đặt trên các thiết bị, máy tính với chức năng dùng để thơng dịch các câu lệnh của chương trình Java khi thực hiện. Quá trình lập trình, biên dịch và chạy chương trình Java được thể hiện qua sơ đồ sau.
Hình vẽ 1.13: Quá trình biên dịch và chạy chương trình Java
Trong đó, chương trình Java được lập trình và lưu bằng tệp tin mã nguồn phần mở rộng *.java (gọi là Java Source). Sau khi biên dịch (compiler) sẽ tạo thành
</div><span class="text_page_counter">Trang 11</span><div class="page_container" data-page="11">chương trình mã byte (Java Bytecodes) và lưu trữ thành tệp tin có phần mở rộng *.class, phân phối đến các máy ứng dụng. Việc chạy chương trình Java trên một hệ nền nào đó sẽ nhờ máy ảo (Java Virtual Machine) thơng dịch các lệnh mã byte về mã máy để thực thi.
<b>3.3. Lập trình bằng ngơn ngữ Java </b>
Để lập trình bằng Java, trước hết chúng ta phải cài đặt phần mềm phát triển ứng dụng có tên là JDK (Java Development Kit) được cung cấp miễn phí tại địa chỉ “http:// www.oracle.com/ technetwork/ java/ javase/ downloads/ index.html”. Sau khi cài đặt thường có thư mục “Java” với hai thư mục con là “jdk<số hiệu phiên bản>” chứa trình biên dịch và “jre<phiên bản>” chứa hệ thống thư viện và máy ảo Java.
Java được cung cấp khá nhiều môi trường phần mềm để lập trình như JCreator, Eclipse, NetBean... song để thuận tiện trong tài liệu chúng ta sẽ thực hiện trên môi trường Eclipse, đây là phần mềm miễn phí và thuận tiện, chỉ cần copy vào máy để chạy, khơng cần cài đặt hay cấu hình phức tạp (giao diện có dạng sau).
Hình vẽ 1.14: Giao diện làm việc với Eclipse
Tuy nhiên, chúng ta có thể khơng dùng mơi trường mà biên soạn chương trình trên một phần mềm nào đó, lưu lại tệp tin *.java và sử dụng lệnh trực tiếp của JDK để biên dịch và chạy thử. Lệnh biên dịch và chạy thử chương trình Java sử dụng 2 tệp tin “javac.exe” và “java.exe” trong thư mục “BIN” của thư mục đã cài đặt JDK. Cú pháp thực hiện lệnh biên dịch là:
<i><small> javac tên_tệp_chương_trình.java </small></i>
Lệnh để chạy thử chương trình là:
</div><span class="text_page_counter">Trang 12</span><div class="page_container" data-page="12"><i><small> java tệp_chương_trình </small></i>
Quy tắc chung của một tệp chương trình bằng Java gồm các phần sau:
<i><small>/*Phần 1: Khai báo thư viện*/ import tên_thư_viện1; import tên_thư_viện2; ... </small></i>
<i><small>/*Phần 2: Lớp chương trình chính*/ public class tên_lớp { </small></i>
<i><small> //các_nội_dung_của_lớp_chương_trình public static void main(String[] ts){ //nội_dung_chương_trình_chính } </small></i>
<i><small>} </small></i>
<i><small>/*Phần 3: Các lớp đối tượng khác*/ </small></i>
Trong đó, phần khai báo thư viện có thể khơng dùng vì một số thư viện được mặc định sẵn. Tên lớp chứa chương trình chính (hàm “main”) phải trùng với tên tệp chương trình vì nó là lớp “public”. Nhắc lại, các chú thích được viết trong bộ cặp ký tự /* và */ nếu viết trên nhiều dòng, còn trên một dòng sử dụng ký hiệu //.
Ví dụ một chương trình Java đơn giản (có tên tệp là “vidu.java”):
Kết quả dịch và chạy thử chương trình trên Eclipse (cửa sổ màn hình “Console” để chứa kết quả chạy và các thông báo khi chạy chương trình) là:
</div><span class="text_page_counter">Trang 13</span><div class="page_container" data-page="13">
Một số quy tắc/quy ước cần ghi nhớ khi lập trình Java:
- Sử dụng toán tử “new” để sinh đối tượng từ lớp cho việc sử dụng, khai thác và xử lý, cụ thể: biến = new tên_lớp( tham_số_nếu_có );
- Các từ khóa lệnh viết thường, ví dụ: import, for, if, while, case, return, break, continue...;
- Các tên lớp đối tượng viết dạng chuẩn (chữ cái đầu từ viết HOA, sau đó chữ thường, các từ ghép thành tên hoặc viết tắt cũng theo quy ước này), ví dụ: Scanner, System, JButton, JOptionPane...;
- Các tên hằng được viết chữ hoa, ví dụ: EXIT_ON_CLOSE, PI, CLOSE_OPTION, QUESTION_MESSAGE...;
- Các tên biến (thuộc tính) viết chữ thường;
- Các tên hàm (phương thức) viết từ đầu (động từ) bằng chữ thường, các từ sau đó theo dạng chuẩn, ví dụ: print, showMessageDialog, setText...
- Các lệnh không đứng độc lập, bắt buộc một lệnh cần thực hiện phải trên một đối tượng hoặc trên một lớp nào đó, và thậm chí có thể trên nhiều lớp và đối tượng khi chúng bao nhau. Quy tắc chung được viết theo kiểu phân cấp (dùng dấu chấm) như sau:
hoặc lệnh sau sẽ in một dòng chữ lên màn hình,
<i><small> System.out.print(“Xin chao ban. Toi dang hoc JAVA.”); </small></i>
- Các phép toán, kiểu dữ liệu chuẩn (đơn)... đều kế thừa từ C/C++ nên khơng trình bày chi tiết ở đây, coi như người đọc đã biết C/C++.
<i><b>Chúc các Anh/Chị học tập tốt! </b></i>
</div><span class="text_page_counter">Trang 14</span><div class="page_container" data-page="14">Cũng giống như ngôn ngữ C/C++, các toán tử của Java để viết biểu thức tính tốn trong chương trình được giới thiệu ở bảng sau:
nhân, chia, chia dư *, /, % cộng, trừ, kết nối +, -, + dịch bít <<, >>, >>>
so sánh <, <=, >, >=, ==, !=, instanceof tác động bít &, |, ^
kết nối lơgíc &&, ||
</div><span class="text_page_counter">Trang 15</span><div class="page_container" data-page="15"><small> int x=140276; </small>
<small> short y = (short) x; /*khi hiện kết quả sẽ có y=9204, dữ liệu bị mất*/ </small>
Thơng thường việc ép kiểu được dùng trong các tham chiếu, trình bày ở phần sau.
- Phép tốn chia (/) sẽ cho kết quả phần nguyên nếu hai dữ liệu là số nguyên, nếu một dữ liệu số thực sẽ cho kết quả chính xác của phép chia. Phép chia dư (%) chỉ thực hiện trên số nguyên. Ví dụ:
<small> 9/2 sẽ cho kết quả 4, </small>
<small> 9.0/2 hoặc 9/2.0 sẽ cho kết quả 4.5 </small>
Tốn tử dịch bít sang trái <<, sang phải >>, và sang phải không dấu >>> tác động lên từng bít của dữ liệu. Ví dụ:
</div><span class="text_page_counter">Trang 16</span><div class="page_container" data-page="16">- Tốn tử lơgíc (&&, ||) để kết nối các biểu thức lơgíc, thường được dùng trong các điều kiện của lệnh rẽ nhánh, lệnh lặp.
- Phép toán ba ngôi (?:) sẽ tác động lên ba dữ liệu, cú pháp như sau:
Máy sẽ thực hiện cho kết quả <biểu thức 1> nếu <điều kiện> đúng, ngược lại cho kết quả <biểu thức 2>. Ví dụ:
<small> x = (a>b)? a-b : b-a; </small>
sẽ cho kết quả số lớn – số bé giữa hai số a và b.
- Đặc biệt phép toán nối (+) để thực hiện nối hai xâu ký tự, nối xâu ký tự với một ký tự, nối xâu ký tự với số nguyên, số thực. Ví dụ:
<small> “Ha” + “noi”, hoặc “Hano” + ‘i’ cho kết quả là “Hanoi”, 45 + “ABC” cho kết quả là “45ABC”, </small>
<small> “ABC” + 45 cho kết quả là “ABC45”. </small>
Vì trong Java dữ liệu ký tự có thể được xử lý như là số nguyên (theo mã của ký tự) nên phép nối giữa số và ký tự sẽ thực hiện như phép cộng, ví dụ:
</div><span class="text_page_counter">Trang 17</span><div class="page_container" data-page="17"><small> 45 + ‘A’ </small>
cho kết quả là 110, vì mã của ký tự ‘A’ là 65.
- Biểu thức: biểu thức là kết hợp giữa các phép toán tác động lên dữ liệu thực hiện tính tốn và xử lý. Trong biểu thức có thể dùng dấu mở đóng ngoặc để ưu tiên thực hiện phép toán cao nhất, nếu không máy sẽ theo thứ tự ưu tiên mặc định (nhân chia trước, cộng trừ sau). Ví dụ:
<small> x = 7+8*2; sẽ cho kết quả x=23, nhưng y = (7+8)*2; sẽ cho kết quả y=30. </small>
- Câu lệnh: câu lệnh (statements) là kết hợp các từ khóa, biểu thức để yêu cầu máy thực hiện một thao tác tính tốn, xử lý nào đó. Kết thúc một câu lệnh phải có dấu chấm phẩy (;), trên một dịng có thể viết nhiều câu lệnh và một lệnh có thể được viết trên nhiều dịng.
- Khối lệnh: khối lệnh (nhóm lệnh) được đóng khung bởi cặp dấu { và }, nếu một hành động xử lý nào đó cần đến nhiều lệnh thì phải sử dụng khối lệnh. Kết thúc khối lệnh (sau dấu }) khơng cần dấu chấm phẩy (;).
- Chú thích trong Java: có 2 cách viết chú thích, đó là viết sau cặp dấu // để chú thích một dịng hoặc viết trong cặp dấu /* và */ để chú thích trên nhiều dịng.
Tuy nhiên có thể viết chú thích trong cặp /** và */ và thường được sử dụng cho trong công cụ sinh mã HTML của Java.
Trong bất kỳ một ngơn ngữ lập trình nào của máy tính, ngồi cấu trúc thực hiện lệnh tuần tự là đặc trưng của máy tính điện tử hiện nay đều cung cấp hai cấu trúc điều khiển cơ bản đó là rẽ nhánh và lặp. Cũng vậy, trong Java quy tắc thực hiện các cấu trúc đó như sau.
<b>2.1. Lệnh rẽ nhánh (if, switch) </b>
Lệnh rẽ nhánh cho phép điều khiển máy thực hiện một hoặc một vài trong các trường hợp đã đưa ra, có 2 lệnh if và switch với cách viết như sau:
<i><small> if ( điều-kiện ) nhóm-lệnh-1; else </small></i>
<i><small> nhóm-lệnh-2; </small></i>
</div><span class="text_page_counter">Trang 18</span><div class="page_container" data-page="18"><i><small>và: </small></i>
<i><small> switch ( biểu-thức ) { case giá-trị-1: nhóm-lệnh-1; break; </small></i>
<i><small> case giá-trị-2: nhóm-lệnh-2; break; </small></i>
<i><small> … </small></i>
<i><small> case giá-trị-n: nhóm-lệnh-n; break; </small></i>
<i><small> default: </small></i>
<i><small> nhóm-lệnh-n+1; } </small></i>
Lệnh if thực hiện <nhóm-lệnh-1> nếu <điều-kiện> có giá trị đúng, ngược lại thực hiện <nhóm-lệnh-2>. Tuy nhiên có thể lệnh if không sử dụng trường hợp ngược lại (khơng có else và <nhóm-lệnh-2>) thì máy sẽ bỏ qua nếu <điều-kiên> sai. Lệnh switch thực hiện so sánh giá trị của <biểu-thức> với các <giá-trị-1> đến <giá-trị-n>, nếu bằng ở <giá-trị-k> nào (với k=1,2,…,n) thì thực hiện <nhóm-lệnh-k> tương ứng cho đến khi gặp lệnh break.
Ví dụ hiện số lớn trong hai số a và b:
<i><small>if ( a>b ) </small></i>
<i><small>System.out.println(“Số lớn là : ” + a); else </small></i>
</div><span class="text_page_counter">Trang 19</span><div class="page_container" data-page="19"><i><small> System.out.println(“Số lớn là : ” + b); else </small></i>
<i><small> System.out.println(“Hai số bằng nhau”); </small></i>
hoặc hiện ngày trong tuần bằng tiếng anh theo số ngày tương ứng:
<i><small> switch ( a ){ case 1: </small></i>
<i><small> System.out.println(“Sunday”); break; </small></i>
<i><small> case 2: </small></i>
<i><small> System.out.println(“Monday”); break; </small></i>
<i><small> case 3: </small></i>
<i><small> System.out.println(“Tuesday”); break; </small></i>
<i><small> case 4: </small></i>
<i><small> System.out.println(“Wednesday”); break; </small></i>
<i><small> case 5: </small></i>
<i><small> System.out.println(“Thursday”); break; </small></i>
<i><small> case 6: </small></i>
<i><small> System.out.println(“Friday”); break; </small></i>
<i><small> case 7: </small></i>
</div><span class="text_page_counter">Trang 20</span><div class="page_container" data-page="20"><i><small> System.out.println(“Saturday”); break; </small></i>
Nếu trong một nhóm có nhiều lệnh thì phải đóng khối bằng cặp ký tự { và }, ví dụ:
<i><small> if ( a>b ) { </small></i>
<i><small> x=a-b; b=a; a=x; } </small></i>
<i><small> else { x=a+b; </small></i>
<i><small> System.out.println(“Tổng hai số là : ” + x); } </small></i>
</div><span class="text_page_counter">Trang 21</span><div class="page_container" data-page="21"><b>2.2. Lệnh lặp (for, while, do-while) </b>
Lệnh lặp cho phép thực hiện một nhóm lệnh nhiều lần trên máy, mặc dù chúng ta chỉ viết một lần trong chương trình. Trong Java có 3 cách viết lệnh lặp gồm for, while, do-while được trình bày chi tiết sau đây.
Cách viết lệnh for:
<i><small> for ( nhóm-lệnh-1 ; điều-kiện ; nhóm-lệnh-2 ) { </small></i>
<i><small> nhóm-lệnh-lặp; } </small></i>
Cách viết lệnh while:
<i><small>while ( điều-kiện ) { </small></i>
<i><small> nhóm-lệnh-lặp; } </small></i>
Cách viết lệnh do-while:
<i><small> do { </small></i>
<i><small> nhóm-lệnh-lặp; } while ( điều-kiện ); </small></i>
Lệnh for máy thực hiện <nhóm-lệnh-1> đầu tiên, tiếp theo kiểm tra kiện>, nếu đúng máy thực hiện <nhóm-lệnh-lặp>, xong thực hiện <nhóm-lệnh-2> và lặp lại kiểm tra <điều-kiện> cho đến khi có giá trị sai.
<điều-Lệnh while máy sẽ kiểm tra <điều-kiện> và thực hiện <nhóm-lệnh-lặp>, q trình lặp lại cho đến khi <điều-kiện> có giá trị sai.
Lệnh do-while máy thực hiện <nhóm-lệnh-lặp> trước, sau đó kiểm tra kiện> nếu đúng sẽ lặp lại thực hiện <nhóm-lệnh-lặp> cho đến khi sai.
<điều-Ví dụ hiện các số nguyên lẻ từ 50 đến 100 bằng lệnh for,
<i><small>for ( i=50; i<=100; i++ ) </small></i>
</div><span class="text_page_counter">Trang 22</span><div class="page_container" data-page="22"><i><small>{ </small></i>
<i><small> if ( i%2!=0 ) </small></i>
<i><small>{ System.out.println(“ ” + i ); } </small></i>
<i><small>} </small></i>
Ví dụ tìm ước số chung lớn nhất của hai số a và b bằng lệnh while,
<i><small> while ( a!=b ) { </small></i>
<i><small> if ( a>b ) a = a-b; else b = b-a; } </small></i>
Ví dụ tính tổng các chữ số của một số nguyên n bằng lệnh do-while,
<i><small>tong = 0; do { </small></i>
<i><small> tong += n%10; n = n/10; } while (n>0); </small></i>
Hai lệnh lặp for và while có thể viết thay thế nhau tương đương, với lệnh while khác với hai lệnh trên: nó thực hiện nhóm lặp trước rồi mới kiểm tra điều kiện lặp, còn lệnh for/while kiểm tra điều kiện lặp nếu đúng mới thực hiện nhóm lặp. Vì vậy lệnh do-while sẽ thực hiện nhóm lặp ít nhất một lần, ngược lại lệnh for/while có thể khơng thực hiện nhóm lặp.
<b>do-2.3. Lệnh break và continue </b>
Lệnh break để dừng vịng lặp vơ điều kiện, thường dùng trong nhóm lệnh lặp và lệnh “switch” như trên. Khi máy gặp lệnh này sẽ kết thúc lệnh lặp cho dù điều kiện lặp có đúng hay sai. Cũng như trong lệnh switch ở trên, máy sẽ kết thúc thực
</div><span class="text_page_counter">Trang 23</span><div class="page_container" data-page="23">Ví dụ sử dụng lệnh continue trong lệnh lặp để hiện các số từ 1 đến 10 và tính tổng các số lẻ như sau:
<i><small> for ( i=1; i<=10; i++ ) { </small></i>
<i><small> System.out.print( i + “ , ” ); if ( i%2 == 0 ) continue; t = t + i; </small></i>
<i><small> } </small></i>
<i><small> System.out.print( “\n Tong cac so le la : ” + t ); </small></i>
Các cấu trúc lệnh lặp (for, while, do-while) trên có thể sử dụng theo cơ chế “lồng nhau”, tức là trong nhóm lặp của lệnh này có chứa một lệnh lặp khác. Ví dụ hai lệnh lặp for như sau:
<i><small> for ( i=1; i<5; i+=2 ) { </small></i>
<i><small> for ( j=i+1; j<5; j++) </small></i>
<i><small> System.out.print( “\n (” + i + “ , ” + j + “)” ); } </small></i>
Ví dụ trên sẽ hiện các cặp số (1,2); (1,3); (1,4); (3,4).
Khác với lập trình C/C++ trong cách tổ chức chương trình, C/C++ cho phép lập trình các hàm độc lập, cịn Java bắt buộc các hàm phải được gói trong các lớp, gọi là phương thức, trình bày chi tiết ở phần sau.
Nhập và xuất dữ liệu là hai thao tác cơ bản của mọi chương trình phần mềm để tương tác thơng tin giữa người dùng với máy tính, do đó chúng thường xuyên được sử dụng. Các thao tác nhập/xuất (hay còn gọi là vào/ra) dữ liệu thực hiện chủ yếu với bàn phím, màn hình và ổ đĩa lưu trữ. Các dữ liệu đưa vào từ các thiết bị này gọi là dữ liệu nguồn (Data Source).
</div><span class="text_page_counter">Trang 24</span><div class="page_container" data-page="24">
Hình vẽ 2.1: Minh họa nhập/xuất dữ liệu của chương trình
Java cung cấp cơ chế vào/ra dữ liệu theo dòng (stream) ở hai cấp độ, thứ nhất là mức thấp dữ liệu được mã hóa dưới dạng byte và làm việc trực tiếp với các thiết bị, thứ hai là mức cao dữ liệu được định dạng theo từng kiểu để dễ dàng xử lý trong chương trình.
Hình vẽ 2.2: Cơ chế vào/ra dữ liệu theo dòng
Mỗi dòng mức thấp hay mức cao đều có hai loại đối tượng, đó là dòng nhập dữ liệu (input stream) cung cấp thao tác đọc dữ liệu (read) từ các thiết bị nhập vào chương trình và dịng xuất (output stream) cung cấp thao tác ghi dữ liệu (write) từ chương trình ra các thiết bị.
Hình vẽ 2.3: Hai thao tác cơ bản đọc/ghi dữ liệu
Chúng ta thường sử dụng hai dòng này ở chế độ bao nhau, tức đối tượng dòng mức cao bao đối tượng dòng mức thấp. Các dòng mức thấp làm việc kết nối trực tiếp với các thiết bị và thực hiện đọc/ghi dữ liệu dưới dạng byte. Còn dòng mức cao khi đọc sẽ nhận dữ liệu các byte từ dịng mức thấp chuyển hóa thành các dữ liệu
Dòng mức thấp Dòng mức
cao Chư
ơng trình phần mềm
Các thiết bị màn hình, bàn phím, ổ
</div><span class="text_page_counter">Trang 25</span><div class="page_container" data-page="25">theo từng kiểu phù hợp với nhu cầu xử lý trong chương trình, khi xuất thì các dữ liệu sẽ được chuyển hóa thành các byte đưa lên dịng mức thấp để xuất ra các thiết bị vật lý (hình vẽ sau minh họa điều này).
Hình vẽ 2.4: Cơ chế bao nhau của các dòng mức cao/thấp
Java cung cấp hệ thống khá phong phú dưới dạng các lớp đối tượng. Sau đây là danh sách một số lớp đối tượng cơ bản hay dùng.
<b>Stt Tên lớp đối tượng </b>
<b>Thuộc thư viện </b>
<b>Chức năng </b>
1 InputStream java.io Nhập dữ liệu mức thấp 2 FileInputStream java.io Đọc dữ liệu tệp tin mức thấp 3 DataInputStream java.io Nhập dữ liệu có định kiểu 4 ObjectInputStream java.io Nhập dữ liệu dạng đối tượng 5 ByteArrayInputStream java.io Đọc dữ liệu dựa trên mảng byte 6 BufferedInputStream java.io Nhập dữ liệu theo vùng nhớ đệm 7 OutputStream java.io Xuất dữ liệu mức thấp
8 FileOutputStream java.io Ghi dữ liệu ra tệp tin mức thấp 9 DataOutputStream java.io Xuất dữ liệu có định kiểu 10 ObjectOutputStream java.io Xuất dữ liệu dạng đối tượng
Chương trình
</div><span class="text_page_counter">Trang 26</span><div class="page_container" data-page="26">11 ByteArrayOutputStream java.io Xuất dữ liệu dạng mảng byte 12 BufferedOutputStream java.io Xuất dữ liệu theo vùng nhớ đệm
14 Scanner java.util Xử lý nhập dữ liệu đơn giản 15 System java.lang Cung cấp các đối tượng, tham số 16 PrintStream java.io Xuất dữ liệu có thêm các định
dạng
Các thiết bị thường sử dụng để nhập/xuất dữ liệu hiện nay gồm màn hình, bàn phím, ổ đĩa và giao tiếp mạng máy tính. Tất cả các thiết bị đều có thể áp dụng các lớp đối tượng trên để thực hiện. Sau đây chúng ta xem xét nhập/xuất dữ liệu đối với các thiết bị chuẩn.
<b>3.1 . In dữ liệu ra màn hình </b>
Sử dụng đối tượng “out” thuộc lớp “PrintStream” cung cấp chức năng in dữ liệu ra màn hình dạng Console (là một cửa sổ dạng text để hiển thị các dòng ký tự). Các lệnh thực hiện gồm:
<i><small> System.out.print( D ); System.out.println( D ); System.out.printf( F, D ); </small></i>
Trong đó “D” là dữ liệu cần in gồm một biểu thức xác định giá trị dữ liệu. Lệnh “println” sẽ xuống dòng sau khi in xong, lệnh “printf” sẽ in dữ liệu có định dạng quy định bởi “F” gồm các thành phần sau:
<i><small> %[argument_index$][flags][width][.precision]conversion </small></i>
Phần trong cặp dấu ngoặc [ và ] là tùy chọn, như vậy bắt buộc là dấu “%” và phần “conversion” để quy định chuyển dữ liệu gồm các kiểu hay dùng như “%d”, “%f”, “%s”, “%x”, “%td”, “%tm”, “%tY”, “%tH”, “%tM”, “%tS”... tương ứng dữ liệu in ra là số nguyên, số thực, xâu ký tự, số hexa, ngày, tháng, năm, giờ, phút, giây...
“argument_index” cho biết quy định này dành cho dữ liệu thứ mấy trong “D”.
</div><span class="text_page_counter">Trang 27</span><div class="page_container" data-page="27">“flags” quy định trạng thái in dữ liệu như “-”, “0”, “+”, “(” tương ứng để căn trái dữ liệu, thêm số 0 vào bên trái các số, ln có dấu trước các số, thêm cặp dấu ngoặc ( và ) trước số âm.
“width” và “precision” quy định độ rộng dữ liệu in và độ chính xác số thực (số lượng chữ số thập phân).
Ví dụ các lệnh in sau:
<i><small>System.out.print(“Hello WORLD.”); /*in dịng chữ*/ </small></i>
<i><small>System.out.println(2012); /*in ra số 2012 và xuống dòng*/ </small></i>
<i><small>System.out.printf(“Two numbers: %d and %f”, 10, 11.0); /*in định dạng số nguyên và số thực*/ </small></i>
sẽ cho kết quả là
Đối với lệnh in có định dạng chúng ta quy định thêm độ rộng (width - “w”) dữ liệu in, độ chính xác thập phân (precision - “p”) của số thực bằng cách chèn thêm “w” hay “w.p” vào giữa cặp ký tự định dạng. Mặc định máy sẽ căn phải dữ liệu, tức chèn thêm các khoảng trắng bên trái dữ liệu theo đủ độ rộng quy định. Để căn trái chúng ta quy định độ rộng là số âm. Ví dụ sau
</div><span class="text_page_counter">Trang 29</span><div class="page_container" data-page="29">3.2 . Nhập dữ liệu từ bàn phím
Chúng ta sử dụng đối tượng lớp “Scanner” để nhập dữ liệu từ bàn phím, đối tượng này bao đối tượng mức thấp là “System.in” được định nghĩa trong Java để kết nối đến bàn phím. Quy tắc tạo đối tượng để nhập như sau:
<i><small> Scanner </small></i><i><small> = new Scanner(System.in); </small></i>
Sau đó sử dụng các lệnh nhập trên đối tượng vừa tạo gồm:
.nextLine() Nhập một xâu ký tự .nextInt() Nhập một số nguyên .nextFloat() Nhập một thực,...
Ví dụ minh họa sau sẽ nhập một số nguyên và một số thực, sau đó in ra tổng của chúng,
<i><small>Scanner obj = new Scanner(System.in); int a; float b; </small></i>
<i><small>System.out.print(“Nhap a:”); a = obj.nextInt(); System.out.print(“Nhap b:”); b = obj.nextFloat(); System.out.printf(“\nKet qua tong: %f”, a+b); </small></i>
và kết quả chạy thử trên màn hình là,
<b>3.3. Đọc và ghi dữ liệu trên tệp </b>
Các tệp tin trên ổ đĩa được xử lý thông qua đối tượng lớp “File”, tuy nhiên để đơn giản chúng ta có thể dùng trực tiếp đối tượng “FileInputStream” hoặc “FileOutputStream”. Sau đó sử dụng các đối tượng là dòng nhập/xuất mức cao để bao bên ngoài đối tượng này cho việc đọc/ghi dữ liệu có định kiểu. Các đối tượng
</div><span class="text_page_counter">Trang 30</span><div class="page_container" data-page="30">có thể dùng như “DataInputStream” để đọc dữ liệu và “DataOutputStream” để ghi dữ liệu có định kiểu, dùng “Scanner” để đọc dữ liệu đơn giản và “PrintStream” để ghi dữ liệu theo định dạng (dạng text).
Chúng ta sẽ làm quen với một phương pháp đọc/ghi dữ liệu trên tệp tin dạng đơn giản (xử lý dạng tệp text).
Hình vẽ 2.5: Phương pháp đọc/ghi tệp dạng đơn giản - Ghi dữ liệu vào tệp (dạng văn bản):
<i><small>/*Bước 1: Tạo đối tượng ghi tệp*/ PrintStream </small></i><i><small> = new PrintStream( </small></i>
<i><small> new FileOutputStream(“tên-tệp”)); /*Bước 2: Thực hiện lệnh ghi tệp*/ </small></i>
<i><small> </small></i><i><small>.print( D ); </small></i><i><small>.println( D ); </small></i><i><small>.printf( F, D ); /*Bước 3: Đóng tệp*/ </small></i><i><small>.close(); </small></i>
Các lệnh ghi dữ liệu giống với in ra màn hình vì đây là xử lý dạng tệp text (“D” là dữ liệu cần lưu, “F” là định dạng cho dữ liệu). Tên tệp có thể bao gồm cả đường dẫn đầy đủ.
Trường hợp muốn ghi thêm dữ liệu nếu tệp đã có nội dung chúng ta chỉ cần thêm giá trị “true” vào lệnh tạo đối tượng “FileOutputStream” ở bước 1. Cụ thể bước 1 sẽ là,
<i><small> PrintStream </small></i><i><small> = new PrintStream( </small></i>
<b><small>G</small></b>
</div><span class="text_page_counter">Trang 31</span><div class="page_container" data-page="31"><i><small> new FileOutputStream(“tên-tệp”,true)); </small></i>
- Sau đây là 3 bước để đọc dữ liệu từ tệp (dạng văn bản):
<i><small>/*Bước 1: Tạo đối tượng ghi tệp*/ Scanner </small></i><i><small> = new Scanner( </small></i>
<i><small> new FileInputStream(“tên-tệp”)); /*Bước 2: Thực hiện lệnh đọc tệp*/ </small></i>
<i><small> </small></i><i><small> = </small></i><i><small>.nextLine(); /*đọc một xâu*/ </small></i><i><small> = </small></i><i><small>.nextInt(); /*đọc số nguyên*/ </small></i><i><small> = </small></i><i><small>.nextFloat(); /*đọc số thực*/ /*Bước 3: Đóng tệp*/ </small></i>
<i><small> </small></i><i><small>.close(); </small></i>
Các lệnh đọc dữ liệu giống với lệnh nhập dữ liệu từ bàn phím.
Q trình đọc/ghi tệp có thể phát sinh lỗi, đặc biệt ở bước 1 (tạo đối tượng xử lý tệp) sẽ gặp lỗi nếu tên tệp đưa vào không hợp lệ. Các lỗi này được gọi là ngoại lệ (Exception), do đó các bước đọc/ghi tệp được đặt trong cấu trúc xử lý ngoại lệ (sẽ trình bày chi tiết ở phần sau) như sau,
<i><small> try{ </small></i>
<i><small> /*Các bước xử lý tệp*/ }catch(Exception e){} </small></i>
hoặc đơn giản sau khai báo chương trình chính (hàm main) có mệnh đề “throws Exception”, cụ thể:
<i><small> public static void main(String[]ts) throws Exception { /*nội dung chương trình chính*/ </small></i>
<i><small> } </small></i>
Ví dụ sau sẽ ghi dữ liệu chuỗi họ tên có xuống dịng, hai số năm sinh và tiền lương của một nhân viên vào tệp “staff.txt” trên thư mục “F:\”,
</div><span class="text_page_counter">Trang 32</span><div class="page_container" data-page="32"><i><small>PrintStream o = new PrintStream( </small></i>
Ví dụ thứ 2 sẽ thực hiện đọc dữ liệu từ tệp vừa tạo và in ra màn hình kết quả,
<i><small>Scanner o = new Scanner( </small></i>
<i><small> new FileInputStream("f:\\staff.txt")); String t = o.nextLine(); </small></i>
<i><small>int y = o.nextInt(); float s = o.nextFloat(); o.close(); </small></i>
<i><small>System.out.printf("Ket qua doc:\n%s \n%d %10.2f", t,y,s); </small></i>
sẽ cho kết quả trên màn hình đúng như các dữ liệu đã lưu trước đó,
Trường hợp cần đọc/ghi dữ liệu có định kiểu và thậm chí là các đối tượng phức tạp chúng ta làm việc với tệp tin dạng nhị phân, sử dụng các lớp đối tượng “DataInputStream”, “ObjectInputStream” và “DataOutputStream”, “ObjectOutputStream”. Các lệnh đọc/ghi dữ liệu trên các đối tượng này gồm:
</div><span class="text_page_counter">Trang 33</span><div class="page_container" data-page="33"><small>.readInt() Đọc một số nguyên .readFloat() Đọc một số thực </small>
<small>.readUTF() Đọc một xâu ký tự dạng UTF .readObject() Đọc một đối tượng </small>
<small>.writeInt( ) Lưu một số nguyên .writeFloat( ) Lưu một số thực </small>
<small>.writeUTF( ) Lưu một xâu ký tự dạng UTF .writeObject() Lưu một đối tượng,... </small>
Ví dụ sau đây sẽ thực hiện lưu 100 số đầu của dãy Fibonaci (có dạng 1,1,2,3,5,8,... số sau bằng tổng 2 số kế trước) vào tệp có tên “fibonaci.txt”,
<i><small> DataOutputStream o = new DataOutputStream( new FileOutputStream("fibonaci.txt")); int a=1,b=1,c; </small></i>
<i><small> o.close(); </small></i>
Như đã trình bày, java cung cấp cơ chế bộ nhớ động hoàn toàn nên các khai báo mảng đều có dạng tham chiếu (là dạng con trỏ) chứa địa chỉ của vùng nhớ mảng. Ví dụ sau sẽ khai báo 2 tham chiếu mảng một chiều và hai chiều,
</div><span class="text_page_counter">Trang 34</span><div class="page_container" data-page="34"><i><small> int a[]; /*tham chiếu mảng một chiều*/ float b[][]; /*tham chiếu mảng hai chiều*/ </small></i>
Lệnh tạo mảng được thực hiện bởi phép toán “new” và xác định kích thước của mảng, ví dụ
<i><small> a = new int[100]; /*tạo mảng 100 phần tử gán*/ b = new float[10][20]; /*tạo mảng 10 hàng, 20 cột*/ </small></i>
Việc truy cập xử lý mảng theo chỉ số phần tử (tính từ 0,1,2,...) và trên mảng có phép toán “length” để xác định số phần tử hiện tại, ví dụ
<i><small> a.length /*để xác định số phần tử của mảng được tham chiếu bởi a*/ b.length /*để xác định số hàng*/ </small></i>
<i><small> int a[] = {1,1,2,3,5,8,13}; /*một chiều*/ </small></i>
<i><small> float b[][] = {{5,3,2},{6,3,7},{3,2,4}}; /*hai chiều*/ </small></i>
Mảng hai chiều thực chất là mảng của mảng một chiều, tức chiều hàng là một mảng mà mỗi phần tử là một tham chiếu đến mảng một chiều khác. Do đó mỗi hàng của mảng hai chiều khơng nhất thiết có độ dài (số phần tử) giống nhau.
Độ dài mảng 10
Phần tử đầu
Try nhập phần tử 8 viết là a[8]
Các chỉ số phần tử
</div><span class="text_page_counter">Trang 35</span><div class="page_container" data-page="35">
Hình vẽ 2.7: Minh họa tổ chức mảng hai chiều
Ví dụ sau sẽ tạo một mảng hai chiều 3 hàng, mỗi hàng có số phần tử khác nhau,
<i><small> int a[][] = new int[3][]; /*mảng hai chiều có 3 hàng*/ a[0] = new int[5]; /*hàng 0 có 5 phần tử*/ </small></i>
<i><small> a[1] = new int[10]; /*hàng 1 có 10 phần tử*/ a[2] = new int[3]; /*hàng 2 có 3 phần tử*/ </small></i>
Với cơ chế quản lý bộ nhớ động nên Java cung cấp hệ thống gom rác (garbage collection) một cách tự động, tuy nhiên khi cần giải phóng vùng nhớ chúng ta có thể thực hiện trực tiếp bằng hai bước sau:
<i><small> Bước 1: Đặt các tham chiếu về giá trị null </small></i>
<i><small> Bước 2: Sử dụng lệnh System.gc(); để giải phóng bộ nhớ </small></i>
Kiểu dữ liệu “Date” dùng để xử lý ngày tháng và thời gian, các thành phần cơ bản của “Date” gồm:
Các hàng (mảng một chiều)
</div><span class="text_page_counter">Trang 36</span><div class="page_container" data-page="36">.equals( d ) So sánh 2 ngày bằng nhau .getDay(), getMonth(),
getYear()
Lấy ngày, tháng, năm
.getHours(),
getMinutes(), getSeconds()
Lấy giờ, phút, giây
Ví dụ sau sẽ tạo đối tượng kiểu Date theo thời gian hiện tại của máy và hiện kết quả ra màn hình,
<i><small>Date d = new Date(System.currentTimeMillis()); </small></i>
<i><small>System.out.printf("Hien tai la %1$tH:%1$tM:%1$tS - ngay %1$td/%1$tm/%1$tY", d); </small></i>
có kết quả như sau,
<i><small> String s = “Hạ Long” + “:” + “Quảng Ninh”; </small></i>
thậm chí nối các dữ liệu số (kết quả biểu thức) tạo thành xâu,
</div><span class="text_page_counter">Trang 37</span><div class="page_container" data-page="37">.trim() Cắt bỏ khoảng cách ở hai đầu xâu .charAt( i ) Lấy ký tự thứ i trong xâu (bắt đầu từ 0) .substring( i , j ) Lấy xâu con từ i đến j-1 trong xâu .equals( s ) So sánh bằng với xâu ký tự khác
.startsWith( s ) Kiểm tra có là đoạn con bắt đầu của xâu .endsWith( s ) Kiểm tra có là đoạn con kết thúc của xâu .replaceAll ( s, t ) Thay thế đoạn con t cho s trong xâu .getBytes() Chuyển xâu về mảng byte
.indexOf( s ) Cho biết vị trí xuất hiện đầu của đoạn con s
.lastIndexOf( s ) Cho biết vị trí xuất hiện cuối của đoạn con s
.toLowerCase() Chuyển xâu ký tự về dạng chữ thường .toUpperCase() Chuyển xâu ký tự lên dạng chữ hoa
.compareTo( s ) So sánh với một ký tự khác, trả về >0, <0 nếu nó lớn hơn, nhỏ hơn xâu s theo thứ tự từ điển
String.format( F, D ) Chuyển dữ liệu theo định dạng về xâu
Trong đó lệnh “format” có tham số “F” quy định các định dạng chuyển dữ liệu “D” về chuỗi, hai tham số này giống như trong lệnh “printf” đã đề cập ở phần trên. Ví dụ sau sẽ chuyển dữ liệu thời gian hiện tại của máy có kiểu “Date” về dạng chuỗi “dd/mm/yyyy”,
<i><small> Date a = new Date(System.currentTimeMillis()); String s = String.format(“ %1$td / %1$tm / %1$tY ”, a); </small></i>
</div><span class="text_page_counter">Trang 38</span><div class="page_container" data-page="38">Ngoài ra, Java cung cấp lớp “Character” để làm việc xử lý trên dữ liệu ký tự gồm một số lệnh cơ bản sau,
<i><small> Character.isDigit( ký_tự ); Character.isLetter( ký_tự ); Character.toUpperCase( ký_tự ); Character.toLowerCase( ký_tự ); </small></i>
tương ứng để kiểm tra ký tự có là chữ số (Digit) hay chữ cái (Letter) không, để chuyển ký tự về dạng chữ hoa (UpperCase), chữ thường (LowerCase).
<b>5.3. Xử lý số ngẫu nhiên - Random </b>
Java cung cấp lớp đối tượng “Random” để xác định số ngẫu nhiên, cách dùng như sau:
<i><small>/*Bước 1: Tạo đối tượng Random*/ Random a = new Random(); </small></i>
<i><small>/*Bước 2: Dùng lệnh để lấy số ngẫu nhiên*/ a.nextInt(); /*lấy số nguyên*/ </small></i>
<i><small> a.nextInt( g ); /*lấy số nguyên từ 0 đến g-1*/ a.nextFloat(); /*lấy số thực từ 0 đến 1*/ </small></i>
Ví dụ sau sẽ lấy một mảng 2 chiều các số 0,1 ngẫu nhiên sau đó hiện ra màn hình kết quả lấy được,
<i><small>Random d = new Random(); </small></i>
<i><small>int a[][] = new int[1+d.nextInt(20)][1+d.nextInt(20)]; for(int i=0;i<a.length;i++) </small></i>
<i><small>for(int j=0;j<a[i].length;j++) a[i][j] = d.nextInt(2); </small></i>
<i><small>System.out.print("Mang ngau nhien vua lay la"); for(int i=0;i<a.length;i++){ </small></i>
</div><span class="text_page_counter">Trang 39</span><div class="page_container" data-page="39"><i><small>System.out.println(); for(int j=0;j<a[i].length;j++) </small></i>
<i><small> System.out.printf("%3d", a[i][j]); } </small></i>
sẽ có kết quả một lần chạy như sau:
<b>5.4. Tính tốn tốn học - Math </b>
Java cung cấp lớp xử lý các phép toán học cơ bản, chúng được sử dụng dưới dạng trực tiếp trên (theo cơ chế “static” sẽ trình bày sau) gồm các lệnh sau:
<small>Math.sqrt(x) Tính căn bậc hai Math.pow(x,y) Tính lũy thừa xy Math.sin( x ), cos, asin, </small>
<small>acos,... </small>
<small>Tính lượng giác sin, cos, asin, acos... </small>
<small>Math.abs( x ) Tính giá trị tuyệt đối Math.exp( x ) Tính lũy thừa cơ số E Math.log( x ) Tính logarit tự nhiên Math.min( x, y ), max Tính min, max Math.round( x ) Làm tròn số </small>
<small>Math.ceil( x ) Lấy số nguyên cận trên </small>
</div><span class="text_page_counter">Trang 40</span><div class="page_container" data-page="40"><small>Math.floor( x ) Lấy số nguyên cận dưới Math.PI, E Lấy số PI, cơ số E </small>
Ví dụ sau sẽ nhập tọa độ x,y của một điểm trên mặt phẳng, tính khoảng cách từ điểm đó đến gốc tọa độ hiện ra màn hình và lấy cận trên, dưới của nó.
<i><small>float x,y; double kc; </small></i>
<i><small>Scanner n = new Scanner(System.in); System.out.print("Nhap toa do x,y:"); x=n.nextFloat(); y=n.nextFloat(); </small></i>
<b>5.5. Chuyển đổi dữ liệu </b>
Thơng thường trong q trình xử lý nhu cầu chuyển đổi kiểu dữ liệu là khá cần thiết, chẳng hạn ta có dữ liệu số thực kiểu “double” nhưng giá trị của nó lại chỉ là số nguyên (kiểu “int”) và để thực hiện phép chia dư chắc chắn cần phải chuyển kiểu từ “double” sang “int”. Trường hợp này chúng ta sử dụng cơ chế ép kiểu theo cú pháp:
<i><small> (kiểu_mới)dữ_liệu_kiểu_cũ </small></i>
Ví dụ:
<i><small> double x = Math.sqrt(16); int a = (int)x; </small></i>
sẽ ép kiểu “double” của giá trị trong biến “x” thành giá trị kiểu “int”.
</div>