1.1 Giới thiệu
Ngôn ngữ lập trình Java được phát triển bở Sun Microsystems vào năm 1991 như một phần của dự án xanh. Một thành viên của dự án là Jame Gosling đã không đánh giá cao ngôn ngữ lập trình C++ và đã đưa ra một ngôn ngữ mới đặt tên là Oak. Sau đó, Sun đổi tên lại là Java.
Java được chính thức công bố năm 1995 và ngay lập tức đã tạo lên một trào lưu mới trên toàn thế giới và từ đó đến nay vẫn tạo được sức cuốn hút mạnh mẽ.
Java là ngôn ngữ lập trình thuần hướng đối tượng và nó cung cấp những đặc trưng mạnh mẽ cho lập trình mạng (lập trình Internet). Ưu điểm của ngôn ngữ lập trình java thể hiện qua kiến trúc và bộ thư viện rất lớn.
1.2 Môi trường lập trình Java
Để viết một ứng dụng java và chạy được, môi trường lập trình yêu cầu cần có bộ công cụ JDK. Bộ công cụ này có thể download tại website của Sum (java.sun.com). Bộ công cụ này chứa trình biên dịch, trình thông dịch, trình gỡ rối và tất cả thư viện có sẵn hỗ trợ cho lập trình. Trong đó, có 2 tập tin chính của việc lập trình java là
· javac.exe là trình biên dịch tập tin *.java thành mã trung gian *.class.
· java.exe là trình thông dịch (thành phần máy ảo) để thông dịch chạy tập tin *.class
Để soạn thảo câu lệnh, một trình soạn thảo văn bản bất kỳ đều có thể sử dụng như Notepad, Notepad++, Editplus, Jcreator hoặc sử dụng môi trường tích hợp IDE như NetBean.
1.3 Một số ví dụ mở đầu
Ví dụ 1: Tạo chương trình Java cho phép nhập một dòng ký tự từ đối dòng lệnh và hiển thị xâu ký tự đó lên trên màn hình:
class Hello
{
public static void main(String[] args)
{
System.out.println(args[0]);
}
}
Biên dịch chương trình
C:\>javac Hello.java
Thực hiện chương trình
C:\>java Hello "Chao ngon ngu lap trinh Java"
Kết quả in ra là:
Chao ngon ngu lap trinh Java
Ví dụ 2: Tạo một applet hiển thị một xâu ký tự lên màn hình
import java.applet.*;
import java.awt.*;
public class HelloApplet extends Applet
{
public void paint(Graphics g)
{
g.drawString("Hello applet",30,30);
}
}
Biên dịch applet
C:\>javac HelloApplet.java
Tạo một trang VDApplet.html để nhúng applet
<html>
<head> </head>
<body bgcolor="#f0f0f0">
<center>
<applet code = "HelloApplet.class"
width = "500"
height = "300" >
</applet>
</center>
</body>
</html>
Thực thi applet bằng cách mở tập tin VDApplet.html trong trình duyệt. Kết quả được thể hiện ở hình dưới đây:
Hình 2‑1 Minh họa chạy chương trình applet
1.4 Các thành phần cơ bản của ngôn ngữ lập trình Java
1.4.1 Định danh
Định danh (Identifier) Tên gọi của các thành phần trong chương trình được gọi là định danh. Định danh thường được sử dụng để xác định biến, kiểu, phương thức, lớp.
Qui tắc cho định danh:
· Định danh là một dãy các ký tự gồm các chữ cái, chữ số và các ký tự khác: ‘_’, $,...
· Định danh không bắt đầu bằng chữ số.
· Độ dài của định danh không giới hạn.
· Java phân biệt chữ hoa và chữ thường.
Qui ước đặt tên
· Định danh cho các lớp: chữ cái đầu của mỗi từ trong định danh đều viết hoa
Ví dụ: MyClass, HocSinh, SocketServer, URLConnection,...
· Định danh cho các biến, phương thức, đối tượng: chữ cái đầu của mỗi từ trong định danh đều viết hoa trừ từ đầu tiên.
Ví dụ: hoTen (họ tên), namSinh (năm sinh), tinhTong (tính tổng).
1.4.2 Các kiểu dữ liệu nguyên thủy (primitive datatype)
Kiểu dữ liệu cơ bản định nghĩa sẵn được gọi là kiểu nguyên thủy. Biến thuộc kiểu dữ liệu nguyên thủy lưu giá trị. Kiểu nguyên thủy bao gồm các kiểu:
· Kiểu nguyên: char (2byte), byte(1byte), short(2byte), int(4byte), long(8byte).
· Kiểu số thực: float(4byte), double(8byte).
· Kiểu logic: bool.
Mỗi kiểu dữ liệu nguyên thủy có một lớp bao bọc(wrapper class) cung cấp các chức năng thao tác trên kiểu dữ liệu này.
Kiểu dữ liệu | Lớp gói |
char | Char |
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
1.4.3 Khai báo các biến
Cú pháp: <tên kiểu> <tên biến>;
ví dụ:
int i;
i=5;
URL u ;
HocSinh hs = new HocSinh(“Tuan Anh”);
Mỗi biến được khai báo với một kiểu xác định. Có hai kiểu biến. Biến kiểu thuộc dữ liệu nguyên thủy sẽ lưu giá trị. Biến thuộc kiểm đối tượng sẽ lưu địa chỉ tham chiếu tới đối tượng (địa chỉ đối tượng, địa chỉ định nghĩa lớp đối tượng). Cần chú ý rằng một biến khi được khai báo, cần phải thiết lập giá trị của nó trước khi sử dụng.
Qui tắc chuyển đổi kiểu trong Java
(<kieu>)<bieu_thuc>
Ví dụ
float f = (float)100.15D;
Mở rộng và thu hẹp kiểu
byte short
int long float double
char
Ví dụ mở rộng kiểu
char c = ‘A’;
int k = c;
Ví dụ thu hẹp kiểu
int k =10;
char c=(char)k;
1.4.4 Các câu lệnh cơ bản
· Khối lệnh
Khối lệnh trong Java tương tự như khối lệnh trong C/C++, là những lệnh nằm trong cặp ngoặc mở { và đóng }. Một khối lệnh là một dãy không hoặc nhiều lệnh hoặc các khai báo biến hoặc khai báo lớp theo bất kỳ thứ tự nào được đặt trong cặp ngoặc {}
{
S1;
…
Sn;
}
· Lệnh gán
int a, b, c,d;
d=b*b-4*a*c;
· Biểu thức điều kiện
Biểu thức điều kiện A?B:C trả về giá trị B nếu A có giá trị true, trả về giá trị C nếu A có giá trị false.
Ví dụ:
byte b;
int i=b>=0?b:b+255;
- Trong ví dụ trên thực hiện việc chuyển đổi các số nguyên kiểu byte có dấu về số nguyên kiểu int không có dấu. Nếu b lớn hơn hoặc bằng 0 thì I nhận giá trị là b, ngược lại I sẽ nhận giá trị là 255+b.
- Các lệnh điều khiển rẽ nhánh chương trình
· Lệnh if đơn giản
Cú pháp
if<biểu_thức_đk> <câu_lệnh>
· Lệnh if – else
Cú pháp
if <biểu_thức_đk>
<câu_lệnh_1>;
else
<câu_lệnh_2>;
Ví dụ: Viết chương trình nhập vào một dãy số nguyên từ đối dòng lệnh, sắp xếp dãy số đó và hiển thị dãy số sau khi sắp xếp lên màn hình.
class SapXep
{
public static void main(String[] args)
{
int a[]=null;
int i,j,tg;
if(args.length>0)
{
a=new int[args.length];
}
for(i=0;i<args.length;i++)
{
a[i]=Integer.parseInt(args[i]);
System.out.print(a[i]+" ");
}
System.out.println();
for(i=0;i<a.length-1;i++)
for(j=i+1;j<a.length;j++)
if(a[i]>a[j])
{
tg=a[i];
a[i]=a[j];
a[j]=tg;
}
System.out.println("Day so sau khi sap xep la:");
for(i=0;i<args.length;i++) System.out.print(a[i]+" ");
}
}
Biên dịch chương trình
C:\>javac SapXep.java
Thực hiện chương trình
C:\>java SapXep -2 3 1 4 -5 6 -10
-2 3 1 4 -5 6 -10
Day so sau khi sap xep la:
-10 -5 -2 1 3 4 6
· Lệnh switch
Lệnh này cho phép rẽ nhánh theo nhiều nhánh tuyển chọn dựa trên các giá trị nguyên của biểu thức.
Cú pháp:
switch(<biểu_thức_nguyên>)
{
case nhan_1:<câu_lệnh_1>;
case nhan_2:<câu_lệnh_2>;
case nhan_3:<câu_lệnh_3>;
...
case nhan_n:<câu_lệnh_n>;
default:<câu_lệnh>;
}
· Lệnh lặp
Lệnh lặp cho phép một khối các câu lệnh thực hiện một số lần lặp lại.
- Lệnh while
while (<Điều_kiện>) <Thân_chu_trình>
Chú ý:
Có thể <Thân_chu_trình> không được thực hiện lần nào nếu ngay từ đầu
<Điều_kiện> có giá trị false.
<Điều_kiện> là biểu thức boolean.
Ví dụ: Lập chương trình in ra dãy số Fibonaci có các giá trị nhỏ hơn 50.
class Fibonaci
{
public static void main(String[] args)
{
int lo=1;
int hi =1;
System.out.println(lo);
while(hi<50)
{
System.out.println(hi);
hi=lo+hi;
lo=hi-lo;
}
}
}
- Lệnh do – while
Cú pháp
do
{
//Các lệnh
}
while(<Điều_kiện>);
Chú ý:
Thân chu trình được thực hiện ít nhất một lần
- Lệnh for
Cú pháp
for(<Biểu_thức_bắt_đầu>;<Điều_kiện_lặp>;Biểu_thức_gia_tăng>)
<Thân_chu_trình>
- <Biểu_thức_bắt_đầu>: Khai báo và gán các giá trị khởi đầu cho các biến điều khiển quá trình lặp.
- <Điều_kiện_lặp>:Biếu thức logic.
- Sự tương đương giữa vòng for và while
<Biểu_thức_bắt_đầu>;
while(<Điều_kiện_lặp>)
{
<lệnh>;
<Biểu_thức_gia_tăng>;
}
· Các câu lệnh nhảy
Java hỗ trợ ba lệnh nhảy: break, continue, và return. Các lệnh này truyền điều khiển sang phần khác của chương trình.
- Lệnh break: Được dùng để kết thúc trình tự thực hiện lệnh trong lệnh switch hoặc được sử dụng để thoát ra khỏi một vòng lặp.
class BreakDemo
{
public static void main(String[] args)
{
for(int i=0;i<20;i++){
if(i==3)break;
System.out.println("i="+i);
}
}
}
Chương trình này in ra kết quả là:
i=0
i=1
i=2
Như chúng ta có thể thấy, vòng lặp for được thiết kế để chạy với các giá trị từ 0 đến 20, lệnh break làm cho vòng lặp kết thúc sớm khi i bằng 3.
- Lệnh continue: Lệnh continue sẽ bỏ qua không xử lý một lệnh nào đó trong vòng lặp nhưng vẫn tiếp tục thực hiện phần còn lại của vòng lặp.
class ContinueDemo
{
public static void main(String[] args)
{
for(int i=0;i<5;i++){
if(i==2)continue;
System.out.println("i="+i);
}
}
}
Kết quả thực hiện chương trình trên như sau:
i=0
i=1
i=3
i=4
Chương trình không in ra giá trị i=3.
- Lệnh return: Được sử dụng để kết thúc việc thực hiện của hàm hiện thời và chuyển điều khiển chương trình về cho chương trình đã gọi phương thức
Ví dụ
protected double giaTriKhongAm(double v)
{
if(v<0)
return 0;
else
return v;
}
1.5 Lớp đối tượng
Đơn vị cơ bản trong lập trình Java là lớp. Lớp đối tượng miêu tả đặc trưng (thuộc tính) và khả năng (phương thức) của đối tượng. Thuộc tính lưu dữ liệu về đối tượng. Phương thức là các hàm thao tác trên dữ liệu của đối tượng. Java hỗ sẵn một thư viện rất lơn các lớp đối tượng trong gói java.*, javax.* và nhiều gói khác.
1.5.1 Cú pháp định nghĩa một lớp đối tượng
[<phạm vi>] class <Tên lớp> [extends <Tên lớp cha>]
[implements <Tên giao diện>]
{
< Các thành phần lớp:
kiểu_dữ_liệu1 biến1
...
kiểu_dữ_liệun biếnn
phương_thức1()
...
phương_thứcm() >
}
1.5.2 Cú pháp định nghĩa phương thức
[<Phạm vi>] <Kiểu trả về> <Tên phương thức>
([<Danh sách tham biến hình thức>])[<Mệnh đề throws>]
{
<Nội dung phương thức>
}
Trong đó
- <Kiểu trả về> có thể là kiểu nguyên thủy, kiểu lớp hoặc không có giá trị trả lại (kiểu void)
- <Danh sách tham biến hình thức> bao gồm dãy các tham biến (kiểu và tên) phân cách với nhau bởi dấu phẩy.
- Các kiểu phạm vi
o public: Các thành phần được khai báo là public có thể được truy cập ở bất kỳ nơi nào có thể truy cập được và chúng được thừa kế bởi các lớp con của nó.
o private: Các thành phần được khai báo là private chỉ có thể được truy cập trong chính lớp đó
o protected: Các thành phần được khai báo là protected có thể được truy cập bởi mã lệnh trong lớp, lớp thừa kế và các đối tượng cùng gói.
1.5.3 Hàm khởi tạo - Constructor
Hàm khởi tạo là một phương thức đặc biệt không có giá trị trả về và có tên trùng với tên lớp. Trường hợp không có constructor nào được đưa ra trình biên dịch cung cấp constructor mặc định cho lớp đó.
Khi tạo ra một đối tượng, hàm khởi tạo ứng với bộ tham số truyền vào sẽ tự động gọi lên thực hiện. Hàm này cho phép thiết lập những giá trị ban đầu cho các thuộc tính của đối tượng vừa tạo ra.
public class Point
{
protected double x,y;
public Point(double x,double y)
{
this.x=x;
this.y=y;
}
public void move(double dx, double dy)
{
x=x+dx;
y=y+dy;
}
public void print()
{
System.out.println("x="+x+", y="+y);
}
public static void main(String[] args)
{
Point p=new Point(3.0,6.0);
System.out.println("Thong tin ve toa do diem ban
dau:");
p.print();
p.move(-1.5,2.0);
System.out.println("Thong tin ve toa do diem sau khi
tinh tien theo vec to:");
p.print();
}
}
C:\>java Point
Thong tin ve toa do diem ban dau:
x=3.0, y=6.0
Thong tin ve toa do diem sau khi tinh tien theo vec to:
x=1.5, y=8.0
1.5.4 Tham chiếu this
Thông thường, đối tượng nhận phương thức cần phải biết tham chiếu của nó.
Trong lớp Point có constructor
public Point(double x,double y)
{
this.x=x;
this.y=y;
}
Giả sử nếu sửa đổi constructor bằng cách thay đổi như sau:
public Point(double x,double y)
{
x=x;
y=y;
}
Khi biên dịch chương trình sẽ báo lỗi vì có sự nhập nhằng trong các lệnh gán. Tham chiếu this đã khắc phục được điều này, this.x và this.y muốn đề cập tới trường thông tin của lớp Point còn x, y là tham biến truyền vào của constructor.
1.5.5 Thừa kế
class Point3C extends Point2C
{
protected double z;
public Point3C(double x, double y, double z)
{
super(x,y);
this.z=z;
}
public void move(double dx, double dy, double dz)
{
super.move(dx,dy);
z+=dz;
}
public void print()
{
super.print();
System.out.print(" z="+z);
}
public static void main(String[] args)
{
Point3C p=new Point3C(3.0,4.5,5.0);
System.out.println("Toa do ban dau:");
p.print();
System.out.println();
p.move(-1.0,0.5,-1.0);
System.out.println("Toa do sau khi tinh tien:");
p.print();
System.out.println();
}
}
1.5.6 Từ khóa super
Một lớp con kế thừa đầy đủ các thuộc tính và phương thức của lớp cha. Trong đó, có một số thuộc tính và phương thức của lớp cha không truy xuất được do từ khóa phạm vi của nó hoặc do phương thức lớp cha viết đè. Để truy xuất các thành phần của lớp cha này, từ khóa super được sử dụng.
Đoạn mã thứ nhất khai báo lớp Point2C biểu diễn một đối tượng điểm hai chiều, đoạn mã thứ hai khai báo lớp Point3C biểu diễn một đối tượng điểm ba chiều. Lớp Point3C được kế thừa lớp từ lớp Point2C. Lời gọi super(x,y) trong lớp Point3C gọi tới constructor Point2C hay super.move(dx,dy) gọi tới phương thức move(dx,dy) của lớp Point2C.
Biên dịch chương trình
C:\>javac Point3C.java
Thực thi chương trình
C:\>java Point3C
Kết quả chương trình
Toa do ban dau:
x=3.0, y=4.5 z=5.0
Toa do sau khi tinh tien:
x=2.0, y=5.0 z=4.0
1.5.7 Truyền tham số trong Java
Thông thường, trong một ngôn ngữ lập trình thường có hai cách truyền tham biến cho một thủ tục: truyền theo tham trị và truyền theo tham chiếu. Các giá trị của các biến tham số trong một phương thức là các bản sao của các giá trị do người gọi xác định. Sự khác biệt là truyền tham trị thì tham số lưu giá trị thuộc kiểu dữ liệu nguyên thủy còn truyền tham chiếu thì tham số lưu giá trị là địa chỉ ô nhớ của đối tượng thuộc một kiểu nhất định.
1.5.8 Đa hình
Tính đa hình của một đối tượng được thể hiện qua kỹ thuật nạp chồng phương thức(overloaded method). Các phương thức nạp chồng là các phương thức nằm trong cùng một lớp có cùng tên nhưng khác nhau về danh sách tham số.
Ví dụ
class TinhToan
{
public static void main(String[] args)
{
Tinh c = new Tinh();
c.add(10,20);
c.add(40.0f,35.65f);
c.add("Good ","Morning");
}
}
class Tinh
{
public void add(int a, int b)
{
int c = a+b;
System.out.println("Phep cong hai so nguyen :"+c);
}
public void add(float a, float b)
{
float c = a+b;
System.out.println("Phep cong hai so dau phay dong
:"+c);
}
public void add(String a, String b)
{
String c = a+b;
System.out.println("Phep cong hai xau :"+c);
}
};
Kết quả:
C:\MyJava\Baitap>java TinhToan
Phep cong hai so nguyen :30
Phep cong hai so dau phay dong :75.65
Phep cong hai xau :Good Morning
Giải thích: Trong chương trình trên phương thức add() là phương thức được nạp chồng. Có ba phương thức có cùng tên add() nhưng có các tham số khác nhau. Khi phương thức add được gọi, dựa vào danh sách tham số truyền vào, phương thức tương ứng sẽ được triệu gọi ra thực hiện.
1.5.9 Thành phần tĩnh
Các thành phần tĩnh là thành phần độc lập của lớp. Thành phần này có thể truy cập qua tên. Mọi đối tượng trong lớp đều có thể truy cập đến các thành phần này. Các thành phần tĩnh bao gồm: biến tĩnh, phương thức tĩnh, khối tĩnh.
Ví dụ về biến static
class StaticVariable {
static int count=0;
StaticVariable(){
count++;
}
public static void main(String[] args)
{
//bien dem count se cho biet so doi tuong duoc tao ra
StaticVariable c1=new StaticVariable();
System.out.println("Bien dem count="+count);
StaticVariable c2=new StaticVariable();
System.out.println("Bien dem count="+count);
StaticVariable c3=new StaticVariable();
System.out.println("Bien dem count="+count);
}
}
Phương thức tĩnh chỉ sử dụng các thuộc tính hoặc phương thức của lớp chính nó thì các thuộc tính, phương phức này phải là tĩnh.
Ví dụ phương thức static
class StaticMethodDemo
{
static String name="Phuong thuc tinh";
public static void main(){
System.out.println("Hello" + name);
}
public static void main(String[] args)
{
main();
System.out.println("Hello World!");
}
}
Khối static được sử dụng để khởi tạo giá trị của các biến tĩnh. Khi lớp lần đầu tiên được tải vào bộ nhớ, các khối static luôn được xử lý trước.
Ví dụ khối tĩnh
class StaticDemo
{
static{
System.out.println("Khoi static 1");
}
public static void main(String[] args)
{
System.out.println("Hello World!");
}
static {
System.out.println("Khoi static 2");
}
}
Vì khối static luôn được xử lý trước nên kết quả in ra của chương trình trên sẽ là:
Khoi static 1
Hello World!
Khoi static 2
1.5.10 Các thành phần hằng (final)
Biến được khai báo với từ khóa final có nghĩa là biến có giá trị hằng, không thay đối được nội dung.
Ví dụ.
final double PI=3.1416;
Các phương thức được khai báo là final không thể được viết đè ở lớp thừa kế.
Ví dụ
class A {
final void method(){
}
}
class B extends A{
final void method(){ //lỗi
}
}
Lớp khai báo với từ khóa final không thể được thừa kế.
Ví dụ
final class A {
}
1.6 Lớp trừu tượng
Lớp trừu tượng là lớp có ít nhất một phương thức trừu tượng. Phương thức trừu tượng là phương thức chỉ khai báo khuôn dạng hàm mà không thể cài đặt chi tiết hàm.
Cú pháp khai báo phương thức trừu tượng:
[phạm vi] abstract <kieu du lieu> <tenphuongthuc>([ds tham so]);
Cú pháp khai báo lớp trừu tượng:
abstract class <ten lop>{
//có ít nhất một phương thức trừu tượng
}
Ví dụ:
abstract class Hinh2D
{
double a,b,r;
public abstract double dientich();
public abstract double chuvi();
}
class HinhTron extends Hinh2D
{
public HinhTron(double r)
{
this.r=r;
}
public double dientich()
{
return Math.PI*r*r;
}
public double chuvi()
{
return Math.PI*2*r;
}
}
class HinhChuNhat extends Hinh2D
{
public HinhChuNhat(double a,double b)
{
this.a=a;
this.b=b;
}
public double dientich()
{
return a*b;
}
public double chuvi()
{
return (a+b)*2;
}
}
class AbstractDemo
{
public static void main(String args[])
{
Hinh2D ht=new HinhTron(1);
System.out.println("Dien tich hinh tron ban kinh 1.0 la:"+ht.dientich());
System.out.println("Chu vi hinh tron ban kinh 1.0 la:"+ht.chuvi());
Hinh2D hcn=new HinhChuNhat(3,4);
System.out.println("Dien tich hinh chu nhat la:"+hcn.dientich());
System.out.println("Chu vi hinh chu nhat la
"+hcn.chuvi());
}
};
Kết quả thực hiện chương trình
C:\MyJava>java AbstractDemo
Dien tich hinh tron ban kinh 1.0 la:3.141592653589793
Chu vi hinh tron ban kinh 1.0 la:6.283185307179586
Dien tich hinh chu nhat la:12.0
Chu vi hinh chu nhat la 14.0
1.7 Giao diện (Interface)
Giao diện là sự trừu tượng hóa cao độ, nghĩa là một lớp đối tượng chỉ bao gồm tập hợp các phương thức trừu tượng hoặc thuộc tính hằng. Giao diện được sử dụng trong cơ chế liên kết muộn. Giao diện cho phép đa thừa kế.
Cú pháp khai báo giao diện
public interface <tên giao diện> [extends <tên giao diện cha>]
{
//Thân giao diện
}
Ví dụ định nghĩa một giao diện:
public interface CalculatorInterface
{
public double add(double x, double y);
public double sub(double x, double y);
public double mul(double x, double y);
public double div(double x, double y);
}
Cài đặt giao diện
Giao diện trình bày các phương thức chung của các lớp đối tượng cài đặt nó. Lớp đối tượng cài đặt giao diện có cú pháp như sau.
class <tên lớp> implements <tên lớp cha>{
//Cài đặt các phương thức của giao diện
}
Ví dụ:
class CalculatorTest implements CalculatorInterface
{
public double add(double x, double y)
{
return x+y;
}
public double sub(double x, double y)
{
return x-y;
}
public double mul(double x, double y)
{
return x*y;
}
public double div(double x, double y)
{return x/y;
}
public static void main(String[] args) throws Exception
{
CalculatorInterface cal=new CalculatorTest();
if(args.length!=2)
{
System.out.println("Cach chay chuong trinh: java
CalculatorImpl so1 so2");
return;
}
else
{
double x,y,z;
x=Double.parseDouble(args[0]);
y=Double.parseDouble(args[1]);
System.out.println(x+"+"+y+"="+cal.add(x,y));
System.out.println(x+"-"+y+"="+cal.sub(x,y));
System.out.println(x+"*"+y+"="+cal.mul(x,y));
System.out.println(x+"/"+y+"="+cal.div(x,y));
}
}
}
Kết quả thực hiện chương trình là
C:\MyJava>java CalculatorTest 12 3
12.0+3.0=15.0
12.0-3.0=9.0
12.0*3.0=36.0
12.0/3.0=4.0
1.8 Gói (Package)
Các gói gốm có các thành phần là các lớp, các giao diện và các gói con có liên quan với nhau. Việc tổ chức thành các gói có một số lợi ích sau:
- Cho phép nhóm các thành phần cùng đặc trưng, chức năng thành một đơn vị, thuận tiện cho việc quản lý.
- Tránh xung đột tên.
- Cho phép qui định phạm vi truy cập các thành phần mở mức gói.
Cú pháp truy cập tới thành phần của gói
<Tên gói>.<Tên thành phần>
Cú pháp nạp các thành phần trong gói vào trong một chương trình.
import <Tên gói>.*;//tên gói
Cú pháp khai báo nạp các thành phần trong gói con như sau:
import <Tên gói>.<Tên gói con>.*;
Cách tạo ra các gói trong Java
Cú pháp khai báo để đưa một lớp đối tượng vào một gói
package <Tên gói>;
Ví dụ:
package mypackage;
public class Calculator
{
public double cong(double a,double b)
{
return a+b;
}
public double nhan(double a, double b)
{
return a*b;
}
public double tru(double a,double b)
{
return a-b;
}
public double chia(double a,double b) throws Exception
{
return a/b;
}
}
Biên dịch
C:\>javac -d C:\MyJava Calculator.java
Lưu ý: các thành phần của gói cần được khai báo với thuộc tính public, nếu cần truy xuất chúng từ bên ngoài.
1.9 Quản lý ngoại lệ (Exception Handling)
Khi lập một chương trình thường có các lỗi xảy ra. Trong đó, lỗi trong quá trình thực thi chương trình là một loại lỗi nghiêm trọng làm cho chương trình không hoạt động bình thường hoặc ngừng hoạt động. Các lỗi này là do chương trình không kiểm soát hết các tính huống dữ liệu đầu vào khác nhau, ví dụ như tên tập tin cung cấp không tìm thấy, địa chỉ mạng không hợp lệ, vượt kích thước mảng, ...)
Ngôn ngữ lập trình Java hỗ trợ cơ chế kiểm tra lỗi chặt chẽ. Cụ thể các lớp biểu diễn lỗi như Throwable, Error, Exception,… Các thành phần trong thư viện có sẵn của Java đều được cài đặt kiểm tra lỗi và đưa ra lớp biểu diễn lỗi phù hợp. Ngoài ra, Java còn cho phép tạo ra các lớp đối tượng có kiểm tra lỗi và phát sinh ra đối tượng lỗi tương ứng.
1.9.1 Lệnh kiểm soát ngoại lệ cơ bản
Một lệnh kiểm soát ngoại lệ cơ bản gồm 2 khối lệnh chính là khối tryvà khối catch. Khối try là nơi chứa đoạn lệnh có khả năng gây ra lỗi run-time. Khối catchlà nơi chứa đoạn lệnh xử lý lỗi do khối try phát hiện. Một lệnh kiểm soát ngoại lệ có duy nhất một khối try và có thể có nhiều khối catch.
Ngoài ra còn khối tùy chọn là finally, là nơi chứa các lệnh luôn được thực thi dù có phát sinh exception hay không. Nếu trong khối catchcó lệnh thoát khỏi phương thức, như return, thì lệnh trong khối finallyvẫn được thực thi bình thường. Các lệnh này thường là những lệnh "dọn dẹp" bộ nhớ, đóng các stream,…
Cú pháp tổng quát:
try
{
// Các câu lệnh có khả năng gây ra exception
}
catch (Exception1 E1)
{
// Các câu lệnh xử lý cho exception thuộc loại Exception1
}
catch (Exception2 E2)
{
// Các câu lệnh xử lý cho exception thuộc loại Exception2
}
...
...
finally
{
// Các câu lệnh luôn được thực thi
}
Ví dụ cụ thể: Trong ví dụ này, ta sẽ cố tình phát sinh ra một ngoại lệ, đó là lỗi chia cho 0. Lỗi này chỉ được phát hiện lúc run-time.
public class Main01
{
public static void main(String[] args)
{
int x=4,y=0;
try
{
int z=x/y;
// Câu lệnh này sẽ không được thực thi
System.out.println("Hello!");
}
catch(Exception E)
{
System.out.println("Co loi run-time!");
}
}
}
Và kết quả khi chạy chương trình:
Co loi run-time!
Press any key to continue...
Nếu không xử lý exception, ta sẽ được kết quả như sau:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at Main01.main(Main01.java:8)
Press any key to continue...
Đó là exception do Java tự phát hiện và xử lý.
Ví dụ trên cho thấy rằng khi một câu lệnh phát sinh exception, các câu lệnh sau nó trong khối try sẽ không được thực thi. Khi đó, con trỏ lệnh sẽ nhảy ngay đến khối catch phù hợp (nếu có) để thực thi các lệnh trong đó.
1.9.2 Tổ chức lớp biểu diễn ngoại lệ
Trong Java, các ngoại lệ được biểu diễn ở lớp cao nhất là Throwable. Kế thừa nó là hai lớp con Exception và Error. Tất cả các lớp biểu diễn ngoại lệ trong Java đều kế thừa từ hai lớp này.
Một đối tượng phải được dẫn xuất từ Throwable mới dùng được trong câu lệnh throw để phát sinh ngoại lệ.
Lớp Exception dùng để mô tả chung cho tất cả ngoại lệ trong Java, … Trong đó, RuntimeExceptionlà một dẫn xuất quan trọng. Từ nó, các ngoại lệ như lỗi vượt phạm vi mảng, lỗi tính toán số học, lỗi ép kiểu, lỗi sử dụng đối tượng chưa khởi tạo,… được cài đặt.
Lớp Error dùng để mô tả các chung cho các loại ngoại lệ đặc biệt, không cần xử lý, ví dụ như lỗi của máy ảo, lỗi liên kết class,…
Sơ đồ tổ chức exception của Java
1.9.3 Phát sinh ngoại lệ
Các lỗi nếu có phát sinh sẽ được bắt bởi máy ảo Java và ném ra một đối tượng ngoại lệ chứa thông tin lỗi. Ngôn ngữ lập trình Java cho phép người lập trình ném ra đối tượng ngoại lệ bằng từ khóa throw.
public class Main02
{
public static void main(String[] args)
{
Object o=null;
if (o==null)
// Phát sinh exception loại NullPointerException
throw new NullPointerException();
}
}
Trong đó, NullPointerException là một exception có sẵn của Java. Khi chạy chương trình, ta sẽ nhận được thông báo sau:
Exception in thread "main" java.lang.NullPointerException
at Main02.main(Main02.java:8)
Để exception được rõ nghĩa, ta có thể throw một exception với hàm khởi tạo có tham số là chuỗi mô tả loại lỗi, sau đó dùng phương thức getMessage() để xuất câu thông báo ra màn hình.
public class Main02
{
public static void main(String[] args)
{
try
{
String S="Loi: object co gia tri null";
// Tạo ra exception bằng constructor có tham số
throw new NullPointerException(S);
}
catch(NullPointerException E)
{
System.out.println(E.getMessage());
}
}
}
Khi đó, câu thông báo lỗi sẽ trở nên thân thiện hơn:
Loi: object co gia tri null
Press any key to continue...
Trong một phương thức có ném ra ngoại lệ thì phương thức đó phải được khai báo ném ngoại lệ bằng từ khóa throws.
ví dụ:
// Từ khóa throws cho biết phương thức này có phát sinh exception
// cho khối cao hơn xử lý
void methodD(int[]a)throwsNullPointerException
{
if(a == null)
// Phát sinh exception
throw new NullPointerException("Loi: Mang null");
// ...
}
Khi đó, nếu phương thức methodC()gọi methodD() mà không đặt nó trong khối exception thì cũng phải có từ khóa throws trong phần khai báo. Khi đó exception của phương thức methodC()phải cùng loại hoặc là lớp cha của exception do methodD() phát sinh.
void methodC()throwsNullPointerException // Hoặc throws Exception,...
{
int[]a=null;
// ...
methodD(a);
// ...
}
Ví dụ bắt nhiều ngoại lệ
Scanner sn=new Scanner(System.in);
System.out.print("Nhap gia tri n (0, 1, 2, ...): ");
int n=sn.nextInt();
try
{
switch(n)
{
case0 : break; // Không phát sinh exception
case1 : throw new NullPointerException();
case2 : throw new ClassCastException();
case3 : throw new ArrayIndexOutOfBoundsException();
default:
// Phát sinh exception IllegalArgumentException
// Lưu ý: không có khối catch riêng cho exception này,
// việc catch nó sẽ do khối cach Exception thực hiện
throw new IllegalArgumentException();
}
}
catch (NullPointerException E)
{
System.out.println("Loi doi tuong null!");
// return sẽ ngăn cản việc thực thi khối lệnh ngoài finally,
// nhưng không ngăn cản việc thực thi khối lệnh finally
return;
}
catch (ClassCastException E)
{
System.out.println("Loi ep kieu!");
}
catch (ArrayIndexOutOfBoundsException E)
{
System.out.println("Loi chi so mang vuot pham vi!");
}
catch (Exception E)
{
System.out.println("Co loi!");
}
finally
{
// Khối lệnh này luôn được thực thi
System.out.println("Khoi lenh finally.");
}
//Lệnh này có khi được thực thi, có khi không, tùy vào cách xử lý
// của các khối catch ở trên
System.out.println("Lenh ngoai khoi finally.");
Khi được thực thi, tùy vào giá trị của n mà đoạn code trên sẽ phát sinh exception tương ứng. Khi đó chỉ đó chỉ có khối catch phù hợp nhất được thực thi.
Nhập n = 0: không phát sinh exception nên không thực thi khối catch nào, vẫn thực thi khối finally và lệnh ngoài khối finally.
Nhap gia tri n (0, 1, 2, ...): 0
Khoi lenh finally.
Lenh ngoai khoi finally.
Press any key to continue...
Nhập n = 1: phát sinh NullPointerException, khối catchtương ứng với exception này chứa lệnh return thoát ngay khỏi phương thức nên lệnh ngoài khối finallykhông được thực thi, tuy nhiên lệnh trong khối finallyvẫn được thực thi bình thường.
Nhap gia tri n (0, 1, 2, ...): 1
Loi doi tuong null!
Khoi lenh finally.
Press any key to continue...
Nhập n = 2: phát sinh ClassCastException, khối catchtương ứng với exception này không thoát khỏi phương thức nên lệnh ngoài khối finallyvẫn được thực thi, và dĩ nhiên lệnh trong khối finallyvẫn được thực thi bình thường.
Nhap gia tri n (0, 1, 2, ...): 2
Loi ep kieu!
Khoi lenh finally.
Lenh ngoai khoi finally.
Press any key to continue...
Mỗi loại exception sẽ ứng với một đối tượng exception trong Java. Nếu ta "catch" một exception thì ta đã "catch" luôn các exception kế thừa từ nó. Nên cần lưu ý rằng Java không cho phép ta "catch" exception "cha" trước khi "catch" exception "con", vì như vậy thì khối lệnh catchcủa exception "con" sẽ không bao giờ được thực thi.
Trong khối catchcuối cùng, ta bắt lỗi với loại lỗi là Exception. Do mọi exception thông thường trong Java đều kế thừa từ class Exception nên khối catchnày có khả năng bắt gần như mọi loại exception của Java. Do đó, như đã nói ở trên, khối catchcủa nó phải được đặt sau cùng (nếu có).
Dĩ nhiên là nếu muốn catch mọi loại exception trong Java, ta có thể catchvới loại lỗi là Throwable:
catch (Throwable T)
{
System.out.println("Co loi trong Java!");
}
1.9.4 Sự lan truyền ngoại lệ
Khi một exception được phát sinh, nó sẽ lan truyền dần từ nơi phát sinh ra các cấp cao hơn cho tới khi được catch hoặc tới phương thức main(). Khi exception truyền tới main() mà vẫn không được catch, nó sẽ được thông báo cho người dùng.
Xem ví dụ sau:
public class Main04
{
public static void main(String[] args)
{
methodA(null);
}
static void methodA(int[] a)
{
methodB(a);
}
static void methodB(int[] b)
{
System.out.println(b[0]);
}
}
Và kết quả khi chạy ví dụ trên:
Exception in thread "main" java.lang.NullPointerException
at Main04.methodB(Main04.java:13)
at Main04.methodA(Main04.java:9)
at Main04.main(Main04.java:5)
Press any key to continue...
Dựa vào thông báo, ta có thể thấy exception NullPointerExceptionđược phát sinh từ methodB(), sau đó được lan truyền về methodA()và sau cùng là main().
1.9.5 Các phương thức chính của lớp Exception
Các phương thức dưới đây đều kế thừa từ Throwable.
Exception() | Khởi tạo một Exception mặc định, câu thông báo sẽ là null. |
Exception(String msg) | Khởi tạo một Exception với câu thông báo msg |
String getMessage() | Lấy câu thông báo của Exception. |
void printStackTrace() | In ra stack lan truyền của Exception. |
Throwable fillInStackTrace() | Ghi thông tin của Exception vào stack lan truyền, sau đó trả về chính Exception this |
StackTraceElement[] getStackTrace() | Lấy ra mảng chứa các StackTraceElement, mỗi StackTraceElement là một đối tượng chứa thông tin về Exception được lan truyền (gồm dòng, file, lớp, phương thức gây lỗi). |
Ví dụ:
public static void main(String[] args)
{
StackTraceElement[]ste=null;
try
{
methodA();
}
catch(Exception E)
{
// In ra câu thong bao loi
System.out.println("Co loi: "+E.getMessage());
// Lấy ra stack lưu thông tin về sự lan truyền
// exception
ste=E.getStackTrace();
}
for(inti=0; ste!=null && i<ste.length; i++)
System.out.println (
" Noi gay loi: Tap tin " + ste[i].getFileName() +
" Dong "+ ste[i].getLineNumber() +
" Class " + ste[i].getClassName() +
" Phuong thuc: "+ ste[i].getMethodName()
);
}
static void methodA()throwsException
{
methodB();
}
static void methodB()throwsException
{
throw new ArrayIndexOutOfBoundsException("Loi chi so mang.");
}
Kết quả chạy đoạn ví dụ trên:
Co loi: Loi chi so mang.
Noi gay loi: Tap tin Main05.java Dong 34 Class Main05 Phuong thuc: methodB
Noi gay loi: Tap tin Main05.java Dong 30 Class Main05 Phuong thuc: methodA
Noi gay loi: Tap tin Main05.java Dong 11 Class Main05 Phuong thuc: main
Press any key to continue...
1.9.6 Lớp ngoại lệ tự định nghĩa
Ngoài việc dùng các lớp đối tượng ngoại lệ có sẵn của Java, ta có thể tự tạo các exception cho phù hợp với chương trình của mình. Để tạo một lớp ngoại lệ, ta chỉ cần tạo một class kế thừa từ Throwable (hoặc kế thừa từ các lớp con của Throwable), sau đó cài đặt các phương thức phù hợp.
Ví dụ: cài đặt exception LoiDiemSocho điểm trung bình của học sinh: nếu nhập điểm nhỏ hơn 0 hoặc lớn hơn 10 thì chương trình sẽ phát sinh exception này.
// Khai báo exception LoiDiemSo
// Exception này sẽ được phát sinh khi nhập điểm không hợp lệ
public class LoiDiemSo extends Exception
{
public LoiDiemSo()
{
super("Diem phai tu 0 toi 10");
}
publicLoiDiemSo(String s)
{
super(s);
}
}
Sau khi đã có lớp ngoại lệ LoiDiemSo, ta có thể dùng như sau:
// ...
public void Nhap()throwsLoiDiemSo
{
Scanner sn=newScanner(System.in);
System.out.print(" + Nhap ten hoc sinh: ");
HoTen=sn.nextLine();
System.out.print(" + Nhap dien trung binh : ");
DiemTrungBinh=sn.nextFloat();
// Neu diem khong hop le thi phat sinh exception LoiDiemSo
if(DiemTrungBinh<0 || DiemTrungBinh>10)
thrownewLoiDiemSo();
}
Trong phương thức main, khi nhập học sinh, ta sẽ bắt lỗi và xuất ra câu thông báo:
public static void main(String[] args)
{
HocSinh hs=newHocSinh();
try
{
hs.Nhap();
}
catch(LoiDiemSo L)
{
System.out.println(L.getMessage());
return;
}
System.out.println(hs);
}
1.9.7 Overriding với exception
Khi một lớp con override phương thức của lớp cha, nếu lớp cha có ném ra lỗi E (qua từ khóa throws) thì lớp con cũng phải ném ra lỗi E hoặc lỗi con của E.
class LopCha
{
public void Method1()throws Exception
{
}
public void Method2()throwsRuntimeException
{
}
public void Method3()throwsClassCastException
{
}
}
class LopCon extends LopCha
{
// OK, vì NullPointerException là con của Exception
public void Method1()throwsNullPointerException
{
}
// OK, vì cha và con ném ra cùng loại lỗi là RuntimeException
public voidMethod2()throwsRuntimeException
{
}
// Phương thức này không hợp lệ
// vì Exception là cha của ClassCastException
/*
public void Method3()throws Exception
{
}
*/
}
1.10 Bài tập
1. Cần quản lý một danh sách nhân viên của 1 cơ quan gồm 2 loại: Nhân viên biên chế và nhân viên hợp đồng.
- Các thông tin chung: họ tên, phòng.
- NVBC: hệ số lương, số năm CT.
- NVHD: lương hợp đồng, Loại HĐ(NH,DH).
Các thao tác trên danh sách nhân viên:
- Tạo lập và lưu các nhân viên
- Liệt kê danh sách nhân viên.
- Liệt kê danh sách nhân viên theo loại: HĐ, BC
- Tính tổng lương toàn bộ nhân viên.
- Liệt kê danh sách nhân viên hợp đồng dài hạn.
2. Xây dựng các lớp tính diện tích các hình: tròn, tam giác, chữ nhật. Chương trình minh họa gồm một mảng các đối tượng và tính tổng diện tích của các hình trong mảng.
3. Một thư viện gồm các loại tài liệu sau:
- Sách(Mã sách, Tên Sách, Tác giả, NXB, Năm XB, Vị trí)
- Tạp chí (Mã tạp chí, Tên tạp chí, Chuyên ngành, Số, Năm, Vị trí)
- CD(Mã CD, Tên CD, Số thứ tự, Nội dung, Vị trí)
Hãy tổ chức các lớp sao cho có thể lập trình để thực hiện được các chức năng sau:
- Lưu danh sách các tài liệu có trong thư viện.
- Liệt kê toàn bộ tài liệu có trong thư viện.
- Liệt kê từng loại tài liệu có trong thư viện.
- Xem thông tin về tài liệu khi biết mã tài liệu.
- Tìm kiếm một tài liệu theo: Tên và tác giả đối với sách; Tên tạp chí, Chuyên ngành, số, năm đối với tạp chí, Tên CD, Số thứ tự và nội dung đối với CD.
Nội Quy Khi Gửi Bình Luận: