Lớp và định nghĩa lớp trong Java

Một phần của tài liệu Bài giảng lập trình java phần 1 đh sư phạm kỹ thuật nam định (Trang 61 - 73)

Lớp được xem là một khuôn mẫu (template) của đối tượng. Lớp bao gồm các vùng dữ liệu của đối tượng và các phương thức tác động lên các dữ liệu đó.

Lớp có tính kế thừa (inheritance); một lớp (subclass) có thể thứa kế tất cả các vùng dữ liệu và các phương thức của một lớp khác (superclass).

Lớp còn có tính đa hình (polymorphism) cho phép cài đặt các lớp dẫn xuất rất khác nhau từ cùng một lớp nguồn.

Bạn còn có thểđịnh nghĩa một lớp bên trong một lớp khác. Đây là lớp xếp lồng nhau, các thể hiện (instance) của lớp này tồn tại bên trong thể hiện của một lớp che phủ chúng. Nó chi phối việc truy nhập đến các thành phần của thể hiện bao phủ chúng.

Định nghĩa lớp:

Một lớp được định nghĩa theo dạng sau:

[<Truy xuất>] [<cập nhật>] class <Tên lớp> [extends <Tên lớp cha>] [implements <Tên giao diện>] {

<Danh sách các thành phần> }

Trong đó:

- Phần đầu của lớp là phần khai báo cho một lớp bao gồm:

+ <Truy xuất> dùng để thiết lập mức truy xuất cho lớp, trong Java có nhiều mức truy xuất khác nhau như public, private…, <Truy xuất> là một thành phần lựa chọn có thể khai báo hoặc không, trong trường hợp không khai báo cụ thể thì lớp sẽđược gán mức truy xuất mặc định.

51

+<cập nhật>là dùng để khai báo một số chức năng cho lớp như lớp tượng abstract, hay lớp hoàn tất việc cài đặt cho một lớp đã có Final.<cập nhật> là một thành phần lựa chọn có thể khai báo hoặc không.

+ class là từ khóa bắt buộc

+ <Tên lớp> là tên của một lớp cần tạo, tên lớp phải được đặt là một tên chuẩn như đã trình bày ở trên.

+ extends <Tên lớp cha> dùng để khai báo lớp là được kế thừa từ một lớp cha.

+ implements <Tên giao diện>] dùng để khai báo khi muốn lớp là một thể hiện từ một lớp nào đó.

- Phần thân của lớp nằm trong cặp ngoặc nhọn “{}”, trong đó <Danh sách các thành phần>là dùng để định nghĩa các thành phần như: Các trường, các phương thức của lớp đó.

Các thuộc tính

Các thuộc tính (properties) hãy các vùng dữ liệu của lớp (field) bản chất chúng là các biến được khai báo ở mức lớp, các thuộc tính được khai báo theo cú pháp sau:

[<Access Modifier>] <Datatype><identifier> [=value]; Trong đó:

- Access Modifier dùng để khai báo giới hạn phạm vi của thuộc tính, có 3 dạng giới hạn phạm vi cho thuộc tính là :public, private và protected. Thành phần này là một lựa chọn có thể khai báo hoặc không.

- Datatype là kiểu dữ liệu của thuộc tính

- identifier là tên của thuộc tính, phải được đặt theo quy định về tên của java - value là giá trị khởi tạo cho thuộc tính, thành phần này là một lựa chọn có thể có hoặc không.

Phƣơng thức

Phương thức được định nghĩa như một hành động hoặc một tác vụ thật sự của đối tượng. Nó còn được định nghĩa như một hành vi mà trên đó các thao tác cần thiết được thực thi. Trong mỗi lớp có thểđịnh nghĩa phương thức theo cú pháp như sau:

[<Access Modifier>] [< None Access

Modifier>]<Datatype><method_name>([<parameter_list>]) {

52 //body of method

}

Trong đó:

- Access Modifier dùng để khai báo giới hạn phạm vi của thuộc tính, có 3 dạng giới hạn phạm vi cho thuộc tính là : public, private và protected. Thành phần này là một lựa chọn có thể khai báo hoặc không.

- None Access Modifier: cho phép thiết lập các thuộc tính của phương thức. Java cung cấp các bổnghĩa sau: static, abstract, final, native, synchronized, volatile.

- datatype: Kiểu dữ liệu mà phương thức trả về. Nếu không có một giá trị nào được trả về, kiểu dữ liệu có thể là void.

- method_name: Tên của phương thức

- parameter_list: Chứa tên của tham số được sử dụng trong phương thức và kiểu dữ liệu. Dấu phẩy được dùng để phân cách các tham số.

- Thân của phương thức nằm trong cặp dấu ngoặc nhọn “{}” là nơi viết đoạn mã chương trình xử lý của phương thức đó.

Đoạn mã sau đây định nghĩa lớp Temp chứa một giá trị nguyên (int). Lớp này chứa hai phương thức là: show() và main(). Cả hai phương thức đều có khảnăng truy cập bên ngoài lớp khi chúng được khai báo như public. Nếu chúng không trả về một giá trị nào, kiểu dữ liệu trả vềđược định nghĩa như kiểu void.

Phương thức show() hiển thị một giá trị của biến x. Ở phương thức main(), hai

thí dụ của đối tượng thuộc lớp Temp được khai báo. Đối tượng thứ nhất gồm giá trị mặc định của biến x. Nó được hiển thị ngay khi gọi phương thức show() lần đầu tiên. Giá trị của xđược thay đổi dùng cho đối tượng thứ hai. Nó được hiển thị khi ta gọi phương thức show() lần thứ hai.

Ví dụ 2.1: Định nghĩa lớp Temp chứa hai phương thức là: show() và main()

class Temp

{ static int x=10;//variable

public static void show()//method { System.out.println(x);}

public static void main(String args[]) { Temp t = new Temp();// object 1

t.show();//method call

53

t1.x=20; t1.show(); }

}

Các chỉđịnh truy xuất(Access Modifier)

Các chỉ định truy xuất dùng để giới hạn khả năng truy nhập vào một phương thức, một thuộc tính hoặc một lớp đối tượng. Java cung cấp các chỉ định truy xuất sau đây:

 Công cộng (Public): Chỉ định truy xuất public có thể được nhìn thấy từ mọi gói hoặc mọi lớp.

 Bảo vệ (Protected): Các lớp mở rộng từ lớp hiện hành trong cùng một gói, hoặc tại các gói khác nhau có thể truy cập các phương thức, thuộc tính loại này.

 Riêng tư (Private): Phương thức, thuộc tính riêng tư chỉ có thểđược truy cập trực tiếp từ một phương thức trong cùng lớp hoặc truy cập gián tiếp qua phương thức công cộng trong cùng một lớp.

Các bổnghĩa phƣơng thức (None Access Modifier)

Các bổnghĩa phương thức cho phép ta thiết lập các thuộc tính của phương thức. Java cung cấp các bổnghĩa sau:

Tĩnh (static): phương thức có thểđược gọi mà không cần đến đối tượng. Nó chỉđược sử dụng đối với các dữ liệu và các phương thức tĩnh khác.

Trừu tƣợng (abstract): Ngụ ý rằng phương thức không có một mã (code) và nó sẽđược bổ sung ở các lớp con (subclass). Loại phương thức này được sử dụng trong các lớp kế thừa.

Kết thúc (final): Phương thức không thể được thừa kế hoặc ghi đè (Overridden).

Tự nhiên (native): Chỉ ra rằng phần thân của phương thức được viết trên các ngôn ngữ khác Java ví dụ C, hoặc C++.

Đồng bộ (synchronized): Sử dụng với phương thức trong quá trình thực thi threads. Nó cho phép chỉ một thread được truy cập vào khối mã tại một thời điểm.

Linh hoạt (volatile): Được sử dụng với các biến để thông báo rằng giá trị của biến có thểđược thay đổi vài lần khi thực thi chương trình và giá trị của nó không được đặt vào thanh ghi.

54

Bổnghĩa Phƣơng thức Biến Lớp

public Yes Yes Yes

private Yes Yes Yes (Nested

class)

protected Yes Yes Yes (Nested

class)

abstract Yes No Yes

final Yes Yes Yes

native Yes No No

volatile No Yes No

Bảng 2.2. Sử dụng các bổnghĩa

Từ khóa this

Thông thường bên trong thân của một phương thức ta có thể tham chiếu đến các thuộc tính của đối tượng đó, tuy nhiên trong một số tình huống đặc biệt như tên của tham số trùng với tên của thuộc tính, lúc đó để chỉ các thành viên của đối tượng đó ta dùng từ khoá this, từkhoá this dùng để chỉđối tượng này.

Ví dụ2.2: sau chỉ ra cho ta thấy trong tình huống này bắt buộc phải dùng từ khoá this vì tên tham số của phương thức tạo dựng lại trùng với tên của thuộc tính

class HSBColor {

int hue, saturation, brightness;

HSBColor (int hue, int saturation, int brightness) { this.hue = hue;

this.saturation = saturation; this.brightness = brightness; }

}

Ở ví dụ trên có các biên hue, saturation, brightness trung tên vì vậy để phân biệt chúng là thuộc tính hay tham số thì ta phải dùng từ khóa this.

55

Trong Java cũng như các ngôn ngữ lập trình hướng đối tượng khác thường thì các thuộc tính không được thiết lập ở chếđộ truy cập public vì làm như vậy sẽ làm mất tính bao đóng của các lớp đối tượng và khảnăng proteced sẽ bị hạn chế. Chính vì vậy thông thường các thuộc tính được khai báo là private. Tuy nhiên điều này làm cho việc lấy giá trị, cũng như thiết lập các giá trị cho thuộc tính không thểđược thực hiện từ các lớp khác ngoài nó. Để giải quyết vấn đề này chúng ta dùng các phương thức getter và setter gọi là các phương thức truy cập.

Các phương thức truy cập là các phương thức giống như những phương thức khác nhưng chúng thường tuân thủ theo một quy ước đặt tên riêng. Để cung cấp giá trị một biến cá thể cho đối tượng khác, hãy tạo ra một phương thức có tên là getVariableName(). Tương tự như thế, để cho phép các đối tượng khác thiết đặt các biến cá thể của đối tượng của bạn, hãy tạo ra phương thức setVariableName().

Trong cộng đồng Java, các phương thức truy cập này thường được gọi là các

getter và các setter vì tên chúng bắt đầu bằng get và set. Đây là một sốđặc tính chung của các getter và setter:

- Định tố truy cập của các getter và setter điển hình là public. - Các getter điển hình là không nhận tham số nào.

- Các setter điển hình là chỉ nhận một tham số, đó là giá trị mới cho biến cá thể mà chúng thiết đặt.

- Kiểu trả về của getter điển hình là cùng kiểu với biến cá thể mà nó báo lại giá trị.

- Kiểu trả lại của setter điển hình là void, nghĩa là chúng không trả lại gì hết (chúng chỉđặt giá trị cho biến cá thể).

Ví dụ 2.3:Định nghĩa một lớp học sinh và xây dựng các phương thức getter và setter để truy cập vào các thuộc tính của lớp này.

class HocSinh {

private String hoTen; private String lop; private float diemTb;

public void setHoTen(String hoTen1) {

//hoTen1 là biến cục bộ nhập vào, thường để trùng tên thuộc tính như các hàm setter phía dưới

this.hoTen = hoTen1; }

public void setLop(String lop) { this.lop = lop;

56

}

public String getHoTen() { return hoTen;

}

public String getLop() { return lop;

}

public float getDiemTb() { return diemTb;

}

public void setDiemTb(float diemTb) { this.diemTb = diemTb;

} }

public class JavaDemo{

public static void main(String[] args) { HocSinh a = new HocSinh();

a.setHoTen("Vu Van T"); a.setLop("At7a");

a.setDiemTb(7.5f);

System.out.println("Họ tên: " + a.getHoTen()); System.out.println("Lớp: " + a.getLop());

System.out.println("Điểm Tb: " + a.getDiemTb()); }

}

Supper

Khi một lớp được kế thừa từ lớp cha trong cả lớp cha và lớp con đều có mô phương thức trùng tên nhau, thế thì làm thế nào có thể gọi phương thức trùng tênđó của lớp cha, java cung cấp cho ta từ khoá Super dùng để chỉ đối tượng của lớpcha

ví dụ 2.4:Xây dựng 2 lớp, một lớp cha và một lớp con có cùng một phương thức và sử dụng Supper để phân biệt giữa các phương thứ này.

class ASillyClass { boolean aVariable; void aMethod() { aVariable = true; } }

57

class ASillierClass extends ASillyClass { boolean aVariable; void aMethod() { aVariable = false; super.aMethod(); System.out.println(aVariable); System.out.println(super.aVariable); } }

trong ví dụ trên ta thấy trong lớp cha có phương thức tên là aMethod trong lớp concũng có một phương thức cùng tên, ta còn thấy cả hai lớp này cùng có một thuộc tính tên aVariable để có thể truy cập vào các thành viên của lớp cha ta phải dùngtừ khoá super.

Trả về giá trị từphƣơng thức

Khai báo kiểu giá trị trả về từ lúc khai báo phương thức, bên trongthân của phương thức ta phải sử dụng phát biểu return value; để trả về kết quả,nếu hàm được khai báo kiểu void thì ta chỉ sử dụng phát biểu return; mệnh đềreturn đôi khi còn được dùng để kết thúc một phương thức.

Truyền tham sốcho phương thức

Khi ta viết các phương thức, một sốphương thức yêu cầu phải có một sốtham số, các tham số của một phương thức được khai báo trong lời khai báophương thức, chúng phải được khai báo chi tiết có bao nhiêu tham số, mỗi tham sốcần phải cung cấp cho chúng một cái tên và kiểu dữ liệu của chúng.

Ví dụ 2.5: Tạo một phương thức dùng để tính tổng của hai số, phương thức này được

khai báo như sau:

public double tongHaiSo(double a, double b){ return (a + b);

}

Truyền theo tham trị

Khi gọi một phương thức mà tham số của phương thức có kiểu nguyênthủy, thì bản sao giá trị của tham số thực sự sẽ được chuyển đến phương thức, đâylà đặc tính

58

truyền theo trị ( pass- by – value ), nghĩa là phương thức không thểthayđổi giá trị của các tham số truyền vào.

Ví dụ 2.6: Truyền theo tham trị

public class TestPassByValue { public static void test(int t) { t++;

System.out.println("Gia tri cua cac bien trong ham sau khi tang len 1 la " + t); }

public static void main(String[] args) { int t = 10;

System.out.println("Gia tri cua t truockhi goi ham = " + t); test(t);

System.out.println("Gia tri cua t sau khi goi ham = " + t); }

}

ta se nhận được kết quả ra như sau: Gia tri của t truoc khi gọi ham = 10

Gia tri của t bên trong ham sau khi tang len 1 la 11 Gia tri của t sau khi gọi ham = 10

Như vậy giá trị của t trước và sau khi gọi là như nhau, mặc dù ta đã thay đổi giá trị của t trong chương trình nhưng khi thoát khỏi chương trình giá trị của t không thay đổi

Truyền theo tham biến

Trong Java không hỗ trợ việc truyền tham biến cho các tham số thuộc các kiểu dữ liệu nguyên thủy. Để truyền theo tham biến thì tham số phải thuộc về một kiểu dữ liệu tham chiếu nào đó như mảng, đối tượng …

Ví dụ 2.7: Sẽ truyền theo tham biến cho tham số là một mảng

package example; publicclass Start {

publicstaticvoid example(int m[], int n) { for(int i = 0; i < 10; ++i) {

59

m[i] = 1; }

n = n + 1; }

Publicstaticvoid main(String[] args) { int n = 10; int m[] = newint[10]; for(int i = 0; i < 10; ++i){ m[i] = i; } example(m, n); System.out.print(“n = ” + n +”\n”); for(int i = 0; i < 10; ++i){ System.out.print(“m[" + i + "] = ” + m[i] + “\n”); } } } Kết quảnhư sau: n = 10 m[0] = 1 m[1] = 1 m[2] = 1 m[3] = 1 m[4] = 1 m[5] = 1 m[6] = 1 m[7] = 1 m[8] = 1 m[9] = 1

60

Qua kết quả cho thấy giá trị của các phần tử của mảng đã bị thay đổi sau khi ta thay đổi trong phương thức example(m, n)

Nạp chồng (overloading) và ghi đè (overriding) phƣơng thức

Những phương thức được nạp chồng (overload) là những phương thức trong cùng một lớp, có cùng một tên song có danh sách các tham số khác nhau. Sử dụng việc nạp chồng phương thức để thực thi các phương thức giống nhau đối với các kiểu dữ liệu khác nhau.Ví dụphương thức swap() có thể bị nạp chồng (overload) bởi các tham số của kiểu dữ liệu khác nhưinteger, double và float

Phương thức được ghi đè (overriden) là phương thức có mặt ở lớp cha (superclass) cũng như ở các lớp kế thừa. Phương thức này cho phép một lớp tổng quát chỉ định các phương thức sẽ là phương thức chung trong các lớp con.Ví dụ lớp xác định phương thức tổng quát „area()‟. Phương thức này có thểđược hiện thực trong một lớp con để tìm diện tích một hình cụ thểnhư hình chữ nhật, hình vuông …

Phương thức nạp chồng là một hình thức đa hình (polymorphism) trong quá trình biên dịch (compiler). Còn phương thức ghi đè là một hình thức đa hình trong quá trình thực thi (runtime).

Đoạn chương trình sau mô tảnạp chồng phương thức được thực hiện như thế nào //defined once

protected void perfomTask(double salary){ ……….

System.out.prinln(“Salary is : ” + salary); ….

}

//overloaded –defined the second time with different parameters protected void performTask(double salary, int bonus){

……

System.out.println(“Total Salary is: ” + salary+bonus); ….

}

61

Phương thức ghi đè (Overriden) được định nghĩa lại ở các lớp con. Đoạn mã sau đây mô tảphương thức ghi đè.

Ở đây ta dùng từ khoá “this” biểu thị đối tượng hiện hành, trong khi đó „super‟ được sử dụng để chỉ đối tượng lớp cha.

Phương thức ghi đè không phải là phương thức tĩnh (static). Nó là loại non-static. Các đoạn mã sau đây mô tả việc thực thi ghi đè phương thức trong Java.

class SupperClass // Tạo lớp cơ bản {

int a;

SupperClass() // constuctor {

}

SupperClass(int b) //overloaded constructor {

a=b; }

public void message() {

System.out.println("In the super class"); }

}

class SubClass Extends SupperClass {// derriving a class int a;

SubClass(int a){//subclass constructor this.a;

}

public void message(){ // overiding the base class message() System.out.prinln(“In the sub class”);

} }

Bây giờ tạo ra một đối tượng lớp cha và gán một lớp nhỏ tham chiếu đến nó như sau:

SuperClasss spObj=new SubClass(22);

Câu lệnh „spObj.message()‟ thuộc phương thức lớp của SubClass.Ởđây kiểu đối tượng được gán cho „spObj‟ sẽ chỉ được xác định khi chương trình thực thi. Điều này được biết dưới khái niệm „liên kết động‟ (dynamic binding).

62

Một phần của tài liệu Bài giảng lập trình java phần 1 đh sư phạm kỹ thuật nam định (Trang 61 - 73)

Tải bản đầy đủ (PDF)

(146 trang)