Định nghĩa lớp

Một phần của tài liệu Bai giang lap trinh HDT voi java ICTU (Trang 26)

Định nghĩa lớp là đặc tả một kiểu dữ liệu mới và mô tả cách cài đặt kiểu dữ liệu đó - Lớp là khuôn mẫu dùng để tạo ra đối tượng. Lớp định nghĩa dữ liệu trong một đối tượng cùng những phương thức truy cập dữ liệu đó.

- Lớp có tính chất kế thừa: Một lớp có thể kế thừa các thuộc tính dữ liệu và các phương thức của lớp khác

- Lớp có tính chất đa dạng: Cho phép cài đặt các lớp dẫn xuất (lớp con) rất khác nhau từ cùng một lớp nguồn (lớp cha).

* Khai báo lớp

Cú pháp

[<phạm vi>] class <Tên lớp> [extends <Tên lớp cha>] [implements <Tên giao diện>]

{

// Định nghĩa các vùng thuộc tính chứa dữ liệu thành phần của lớp // Định nghĩa các hàm thành phần của lớp (toán tử tạo lập)

} Trong đó:

class, extends, implements là các từ khoá. Những phần trong cặp [] là tùy chọn. Những phần này sẽ được đề cập chi tiết ở các phần sau.

class Diem { int x,y

27 }

3.2. Định nghĩa các hàm thành phần

Hành vi của các đối tượng của một lớp được xác định bởi các hàm thành phần của lớp đó.

[<phạm vi>] <kiểu trả lại giá trị> <tên hàm >(<danh sách tham biến hình thức>)[<mệnh đề throws>]

{<Nội dung của hàm> }

Trong đó:

<kiểu trả lại gt> có thể là kiểu nguyên thủy hoặc kiểu tham chiếu hoặc không có kiểu trả lại( thay bằng void)

<danh sách tham biến hình thức> bao gồm 1 dãy các tham biến(kiểu và tên) phân cách với nhau bởi dấu,

VD:

public class Diem { float x,y;

Diem(){}

public void nhapTTDiem()

{ Scanner input=new Scanner(System.in); System.out.print("Nhap vao toa X: "); x=input.nextFloat();

28 y=input.nextFloat();

}

public void inTTDiem()

{System.out.println("X: "+x+" Y: "+y); }

public double tinhKhoangCach(Diem d1)

{ double d=Math.sqrt((x-d1.x)*(x-d1.x)+(y-d1.y)*(y-d1.y)); return d;

} (adsbygoogle = window.adsbygoogle || []).push({});

public class ThucHanhSo1 {

public static void main(String[] args) { // TODO code application logic here Diem d1=new Diem();

Diem d2=new Diem();

System.out.println("Nhap thong tin cho diem 1"); d1.nhapTTDiem();

System.out.println("Nhap thong tin cho diem 2"); d2.nhapTTDiem();

System.out.println("Hai diem vua tao la "); d1.inTTDiem();

29 System.out.println("Khoang cach d1 va d2 la: "+d1.tinhKhoangCach(d2)); System.out.println("Khoang cach d2 va d1 la: "+d2.tinhKhoangCach(d1)); }

}

3.3. Nạp chồng các hàm thành phần (overloading)

Trong lập trình HĐT cho phép sử dụng cùng 1 tên hàm nhưng định nghĩa nhiều nội dung thực hiện khác nhau. Những hàm như thế được gọi là hàm nạp chồng (tải bội)

-Cơ chế nạp chồng cho phép nhiều hàm có cùng 1 tên gọi nhưng danh sách tham biến khác nhau, nội dung thực hiện khác nhau và kiểu giá trị trả lại khác nhau.

VD:

public class ToanHoc {

public static int tinhTong(int a,int b) {return a+b;

}

public static int tinhTong(int a,int b,int c) {return a+b+c;

}

public static int tinhTong(int m[]) { int tong=0;

for(int i=0;i<m.length;i++) tong+=m[i];

30 }

}

// chương trình public class CT {

public static void main(String args[]) {

System.out.println("tong cua 6 va 3 la :"+ToanHoc.tinhTong(5,6));

System.out.println("tong cua 4 va 3 va 9 la :"+ToanHoc.tinhTong(4,3,9)); int m[]={3,5,7,8};

System.out.println("Tong cua mang m la "+ToanHoc.tinhTong(m));

} }

3.4. Viết đè các hàm thành phần( kế thừa)

Trong nhiều trường hợp một lớp có thể viết đè hay thay đổi nội dung thực hiện của những hàm được kế thừa từ lớp cha, khi những hàm này được gọi để thực hiện đối với những đối tượng ở lớp con thì nội dung được định nghĩa mới ở lớp con sẽ được thực thi.

VD: (adsbygoogle = window.adsbygoogle || []).push({});

import java.util.Scanner; public class Nguoi { String hoTen,diaChi;

31 int namSinh;

public void inTT()

{System.out.println("Ho ten: "+hoTen+"\nDia chi: "+diaChi+"\nnamSinh: "+namSinh);

}

public void nhapTT()

{Scanner input=new Scanner(System.in); System.out.print("nhap Ho ten: "); hoTen=input.nextLine();

System.out.print("nhap Dia chi: "); diaChi=input.nextLine();

System.out.print("nhap Nam Sinh: "); namSinh=input.nextInt();

} }

class SinhVien extends Nguoi { String maSV;

float d1,d2;

public void inTT()

{ System.out.println("Ma SV: "+maSV); super.inTT();

32 // hoac // System.out.println("Ho ten: "+hoTen+"\nDia chi: "+diaChi+"\nnamSinh"+namSinh);

}

public void nhapTT()

{Scanner input=new Scanner(System.in);

System.out.print("nhap ma SV: ");maSV=input.nextLine(); super.nhapTT();

} }

//lớp CT

Nguoi ng1=new Nguoi();

SinhVien sv1=new SinhVien();

System.out.println("Nhap thong tin cho ng1"); ng1.nhapTT();

System.out.println("nhap thon tin cho SV1"); sv1.nhapTT();

System.out.println("Sinh vien vua nhap la"); sv1.inTT();

System.out.println("Thong tin cua nguoi vua nhap la: "); ng1.inTT();

Chú ý:

33 +Định nghĩa của những hàm viết đè không được khai báo final ở lớp cha

3.5. Toán tử tạo lập đối tượng.(Constructor) (adsbygoogle = window.adsbygoogle || []).push({});

Mục đích của toán tử tạo lập là đặt các giá trị khởi tạo cho đối tượng khi một đối tượng được tạo ra bằng toán tử new

Ta có thể định nghĩa toán tử tạo lập mặc định tường minh theo cú pháp sau: Giống như hàm

[<phạm vi>] <kiểu trả lại gt> <tên lớp >(<danh sách tham biến hình thức>)[<mệnh đề throws>]

{<Nội dung của hàm> }

VD: điểm. Class Diem { int x,y; Diem(){}

Diem(int x1,int y1) {x=x1;y=y1;} }

//Lơp chuong trinh

Diem d1=new Diem(3,6);//sử dụng toán tử tạo lập

Diem d2=new Diem();// sử dụng toán tử tạo lập mặc định D2.nhapTTDiem();

34 D2.inTTDiem();

*Toán tử tạo lập mặc định

Toán tử tạo lập mặc định là toán tử tạo lập không có tham biến có dạng <Tên lớp>(){ }

Khi một lớp không định nghĩa toán tử tạo nào cả thì hệ thống sẽ tự động cung cấp một toán tử tạo lập không tường minh có dạng

<Tên lớp>(){ }// không làm gì cả

Tuy nhiên khi sử dụng toán tử new để tạo ra đối tượng thì các biến nguyên thủy sẽ được khởi tạo các giá trị mặc định tương ứng;

VD: Diem d3=new Diem();

3.6. Truyền tham số trong lời gọi hàm.

a) Truyền các giá trị kiểu nguyên thủy

Bởi vì các biến hình thức là cục bộ trong định nghĩa của một hàm nên mọi thay đổi của biến hình thức không ảnh hưởng đến các tham biến hiện thời.

Các tham biến có thể là các biểu thức và chúng phải được tính trước khi truyền vào lời gọi hàm.

Với các tham bién hình thức có kiểu nguyên thủy, java truyền theo cơ chế tham trị (giá trị của các tham biến hiện thời truyền vào trong lời gọi hàm không đổi khi thoát khỏi hàm mặc dù trong thân hàm có các câu lệnh tác động là thay đổi giá trị của chúng. ) Ví dụ 3.5 Truyền các giá trị nguyên thủy

class KhachHang1{ // Lớp khách hàng public static void main(String[] arg){

35 int giaBan = 20;

double tien = banh.tinh(10,giaBan);

System.out.println("Gia ban: " + giaBan);// giaBan không đổi System.out.println("Tien ban duoc : " + tien);

} }

// Lớp Hãng sản xuất class HangSX{

double tinh(int num, double gia){ gia = gia /2;

return num * gia;// Thay đổi gia nhưng không ảnh hưởng tới giaBan, // nhưng số tiền vẫn bị thay đổi theo

} } (adsbygoogle = window.adsbygoogle || []).push({});

b) Truyền các giá trị tham chiếu đối tượng

Khi biến hiện thời tham chiếu tới đối tượng, thì giá trị tham chiếu của đối tượng sẽ được truyền cho biến hình thức. java truyền theo cơ chế tham trị đối với bản thân đối tượng, tham biến đối với các thành phần (thuộc tính, hàm ) của đối tượng (nghĩa là các thành phần của đối tượng lưu lại sự thay đổi được tác động trong thân hàm khi thoát khỏi hàm).

Ví dụ 3.6 Truyền theo giá trị tham chiếu //KhachHang2.java

class KhachHang2{ // Lớp khách hàng public static void main(String[] arg){

36 System.out.println("Nhoi thit vao banh truoc khi nuong:" + banhMoi.thit);

nuong(banhMoi); // (2)

System.out.println("Thit cua banh sau khi nuong:"+banhMoi.thit);

}

public static void nuong(Banh banhNuong){ // (3)

banhNuong.thit = “Thit vit”; // Người nướng bánh đổi nhân thành thịt vit

banhNuong = null; // (4)

} }

class Banh{ // Lớp Banh (5)

String thit = “Thit ga”; // Qui định của hãng làm nhân bánh bằng thịt gà }

 Kết quả:

- banhNuong sau khi gán giá trị = null trong than hàm, sau khi thoát khỏi hàm vẫn tồn tại – truyền theo cơ chế tham trị đối với cả bản thân đối tượng

- Thuộc tính thit của banhNuong sau khi thoát khỏi hàm được đổi thành “thịt vịt” – truyền theo cơ chế tham biến đối với thuộc tính của đối tượng

c ) Truyền các tham chiếu theo mảng

Mảng (array) trong Java được xem như là đối tượng. Các phần tử của mảng có thể có kiểu nguyên thủy hoặc kiểu tham chiếu (kiểu lớp).

37 Ví dụ 3.7 Truyền các tham chiếu kiểu mảng

// Loc.java class Loc{

public static void main(String[] args){

int[] day = {8, 1, 4, 3, 2, 5};// Khởi tạo mảng day và gán trị đầu // Hiển thị các phần tử của dãy trước khi lọc

for (int i = 0; i < day.length; i++) System.out.print(“ “ + day[i]);

System.out.println(); // Xuống dòng mới int maxIndex = 0;

// Lọc ra phần tử cực đại và đưa về cuối

for (int index = 1; index < day.length; index++) {

if (day[maxIndex] > day[index])

doiCho(day, maxIndex, index); // (1) maxIndex = index;

} (adsbygoogle = window.adsbygoogle || []).push({});

// Hiển thị dãy sau khi lọc

for (int i = 0; i < day.length; i++) System.out.print(“ “ + day[i]); System.out.println();

}

public static void doiCho(int[] bang,int i, int k){ // (2) int tg = bang[i]; bang[i] = bang[k]; bang[k] = tg;

38 }

}

3.7. Quan hệ kế thừa giữa các lớp.

Một trong những cơ chế để sử dụng lại được các đoạn chương trình trong lập trình hướng đối tượng là cơ chế kế thừa. Từ một lớp được xây dựng tốt, ta có thể dẫn xuất ra nhiều lớp mới nhiều kiểu mới( được gọi là lớp con, lớp dẫn xuất, hay lớp kế thừa). Lớp cơ sở được gọi là lớp cha. Lớp con có thể được bổ xung thêm một số tính chất, hành vi của những đối tượng cụ thể hoặc thay đổi các hàm được kế thừa từ lớp cha.

Java chỉ hỗ trợ kế thừa đơn hay một lớp chỉ được kế thừa từ một lớp cha. VD:

Cú pháp kế thừa

<Tên lớp con> extends <Tên lớp cha> { // các thuộc tính dữ liệu bổ xung

//Các hàm thành phần bổ xung hay viết đè }

Mọi lớp của Java đều là lớp con cháu mặc định của Object.

Java.lang.Object

BongDen NhaKho

39 Hình H4-6 Quan hệ kế thừa giữa các lớp

Chú ý:

 Mọi đối tượng của lớp con cũng sẽ là đối tượng thuộc lớp cha. Do vậy việc gán một đối tượng của lớp con sang cho biến tham chiếu đối tượng của lớp cha là sự mở rộng kiểu và do đó không cần ép kiểu.

 Ngược lại gán một đối tượng của lớp cha cho biến tham chiếu đối tượng thuộc lớp con sẽ phải thực hiện ép kiểu. Lưu ý khi đó sẽ có thể bị tổn thất thông tin. Ví dụ,

class SuperClass { /* ... */ } class SubClass { /* ... */ } class UserClass {

//

public static main(String args[]){

SuperClass super1 = new SuperClass();// Tạo ra đối tượng lớp cha SubClass sub1 = super1; // Mở rộng kiểu

SuperClass super2 = (SubClass) sub1; // Thu hẹp kiểu nên phải ép kiểu }

3.8. Toán tử móc xích giữa các lớp kế thừa this() và super()

Các toán tử tạo lập không thể viết đè ở các lớp dẫn xuất (lớp con). Chúng có thể được nạp chồng nhưng phải trong cùng lớp.

Trong Java có 2 toán tử tạo lập đặc biệt có tên là this() và super() được sử dụng để móc xích giữa các lớp có quan hệ kế thừa với nhau.

40 - Mỗi lớp của java luôn tồn tại một biến ần đặc biệt this, thường được sử dụng trong các toán tử tạo lập để chỉ chính bản thân lớp đó. Toán tử tạo lập this()này được sử dụng để tạo ra đối tượng của lớp hiện thời.

b) Toán tử tạo lập super(), biến super

Biến super dùng để chỉ bản thân lớp cha (thường dùng trong lớp con để gọi đến các hàm của lớp cha đã bị nạp chồng trong lớp con, các biến trong lớp cho đã bị che bóng ở lớp con ), toán tử super() được sử dụng trong các toán tử tạo lập của lớp con (subclass) để gọi tới các toán tử tạo lập của lớp cha (superclass) trực tiếp. (adsbygoogle = window.adsbygoogle || []).push({});

1.9.Lớp trừu tượng và giao diện a>Lớp trừu tượng (abstract)

Lớp trừu tượng là 1 lớp đặc biệt trong đó các phương thức chỉ được khai bảo ở dạng khuôn mẫu(template) mà không được cài đặt chi tiết các phương thức chỉ được thực hiện ở các lớp con kế thừa từ lớp trừu tượng đó

Lớp trừu tượng được sử dụng khi muốn định nghĩa một lớp không thể biết và định nghĩa ngay được các thuộc tính và phương thức của nó.

Abstract class Animal { abstract String getNam(); Abstract int get feet();}

Public class Bird extends Animal {public String getName()

{return “Bird”;} }

41 Public class Cat extends Animal

{ }

b> Giao diện (interface) phác thảo

interface định nghĩa mẫu hợp đồng thông qua việc phác thảo các hàm mẫu (prototype)

và không cài đặt nội dung thực hiện.

interface <Tên interface > { <Nội dung của interface >

}

<Nội dung của interface> thường chứa danh sách các hàm mẫu và các hằng.

Giao diện interface là loại kiểu lớp đặc biệt, trong đó tất cả các hàm thành phần đều là trừu tượng, do vậy không thể khởi tạo được giá trị, nghĩa là không thể tạo ra đối tượng của interface. Những hàm trong interface sẽ được cài đặt ở những lớp xây dựng mới theo dạng:

class <Tên lớp> implements <Tên interface>[extends<tên các lớp, các giao diện

cha>] {

// Bổ sung các thành phần;

// Cài đặt các hàm mẫu đã cho trong <Tên interface>; }

Lưu ý:

 Các hàm mẫu của interface được mặc định là abstract và không được khai báo

static;

 Một lớp có thể chọn một số hàm mẫu để cài đặt, nghĩa là có thể chỉ cài đặt một phần của giao diện interface;

42

 Một giao diện có thể kế thừa từ nhiều hơn một giao diện;

 Một giao diện có thể kế thừa từ nhiều hơn một giao diện và lớp;

 Các phương thức của giao tiếp chỉđược khai báo dưới dạng mẫu mà không có cài đặt chi tiết (có dấu chấm phẩy ngay sau khai báo và không có phần cài đặt trong dấu “{}”

 Phần cài đặt chi tiết của các phương thức chỉđược thực hiện trong các lớp (class) sử dụng giao diện đó.

Các thuộc tính của giao tiếp luôn có tính chất là hằng (final), tĩnh (static) và public. Do đó cần gán giá trị khởi đầu ngay khi khai báo thuộc tính của giao diện. VD:

package vidu.chuong4; public interface Product { (adsbygoogle = window.adsbygoogle || []).push({});

public static final String MARK = “Adidas”; public float getCost();

}

///Sử dụng giao diện

public class Shoe implements Product {

// Cài đặt phương thức được khai báo trong giao tiếp public float getCost()

{

return 10f; }

// Phương thức truy nhập nhãn hiệu sản phẩm public String getMark()

43 { return MARK; } } // Phương thức main

public static void main(String args[]) {

Shoe myShoe = new Shoe();

System.out.println(“This shoe is ” + myShoe.getMark() + “ having a cost of $” + myShoe.getCost());

}

3.10. Phạm vi và các thuộc tính kiểm soát truy nhập các thành phần của lớp.

Cơ chế đóng gói trong LTH ĐT giúp cho các đối tượng che dấu đi một phần chi tiết cài đặt cũng như phần dữ liệu cục bộ của nó và chỉ công bố ra ngoài những gì cần công bố để trao đổi thông tin với các đối tượng khác để thực thi các yêu cầu của hệ thống

3.10.1. Phạm vi các thành phần của lớp

Phạm vi lớp xác định giới hạn truy nhập và khả năng kế thừa các thành phần của một lớp khác trong cùng gói hoặc khác gói chứa lớp đó. Nó được xác định bởi các bổ ngữ public, private, protected, mặc định(không có public, private, protected)

44

*Các thành phần public

-Các thành phần khai báo công khai public cho phép truy nhập và kế thừa mọi nơi trong hệ thống đối với những lớp khác trong cùng gói và khác gói chứa lớp đó.

*Các thành phần protected

Những thành phần protected cho phép truy nhập đối với tất cả các lớp trong gói chứa lớp đó và kế thừa tất cả các lớp con(có thể ở lớp khác). Hay những lớp khác không phải là lớp con ở những gói khác thì không được phép truy nhập tới các thành phần protected

Client 3 public classA classC classB classA1 ClassB1 Được phép truy nhập goi1 goi2 “import”

Hình H4-2 Khả năng truy nhập đối với lớp công khai public Quan hệ kế thừa

45

*Các thành phần private

Những thành phần sở hữu riêng private được bảo vệ chặt chữ nhất không cho phép kế thừa và chỉ cho phép truy nhập đối với những đối tượng trong cùng một lớp hay nói cách khác những lớp khác dùng ở trong cùng gói hay những lớp con cháu cũng không được phép truy nhập trực tiếp đến các thành phần riêng private.

public class MatKhau { private String matKhau;

public boolean dangNhap(String mk) {if(mk.equals(matKhau)) return true; Client 3 protected classA classC classB classA1 ClassB1 Được phép truy nhập

goi1 “import” goi2 (adsbygoogle = window.adsbygoogle || []).push({});

Hình H4-2 Khả năng truy nhập đối với lớp công khai protected Quan hệ kế thừa

Không được phép truy nhập

46 else return false;

}

public boolean setMatKhau(String matKhauCu,String matKhauMoi) { if(dangNhap(matKhauCu))

{matKhau=matKhauMoi; return true;

Một phần của tài liệu Bai giang lap trinh HDT voi java ICTU (Trang 26)