I. Các khái niệm cơ bản

1. Đối tượng và Lớp đối tượng

Đối tượng là một thực thể cụ thể, tồn tại và hoạt động trong hệ thống. Lớp là một tập hợp các đối tượng có mặt trong hệ thống. Đối tượng là một thể hiện cụ thể của lớp, lớp được dùng để biểu diễn đối tượng do đó lớp cũng có các thuộc tính và phương thức, thuộc tính của lớp tương ứng với thuộc tính của đối tượng và phương thức của lớp tương ứng với hành động của đối tượng.

Ví dụ: Lớp Xe Ô tô Thuộc tính: Nhãn hiệu xe, Màu xe, Giá xe. Phương thức: Khởi động xe, Chạy xe, Dừng xe, Tắt máy. Từ ví dụ trên có thể cài đặt Lớp Oto trong Java như sau:

public class Oto {
    private String nhanHieuXe;
    private String mauXe;
    private float giaXe;

    public void khoiDongXe(){
        //TODO something 
    }
    public void chayXe(){
        //TODO something 
    }
    public void dungXe(){
        //TODO something 
    }
    public void tatMay(){
        //TODO something 
    }

    public Oto(String nhanHieuXe, String mauXe, float giaXe){
        this.nhanHieuXe = nhanHieuXe;
        this.mauXe = mauXe;
        this.giaXe = giaXe;
    }

    public static void main(String []args){
        Oto honDa = new Oto("Honda", "Red", 780000000); // honDa là một đối tượng cụ thể, là một thể hiện của lớp Oto.
        honDa.khoiDongXe();
        honDa.chayXe();
        honDa.dungXe();
        honDa.tatMay();
    }

}

Trong hàm main khai báo một đối tượng honDa là một thể hiện của lớp Oto, với các thuộc tính cụ thể về nhãn hiệu xe "Honda", màu "Red" và giá 780 triệu, honDa lúc này chính là đối tượng của lớp Oto do đó honDa có thể thực hiện các hành động của Oto gồm khởi động xe, chạy xe, dừng xe và tắt máy, do đó đối tượng honDa có thể gọi tới các phương thức của lớp như trong đoạn code trên.

Trong chương trình, ta chú đến hàm khởi tạo của lớp, hàm này có ba biến cục bộ là nhanHieuXe, mauXe, giaXe, trùng với các biến của lớp. Do đó, trong phạm vi hàm này, biến this.nhanHieuXe, this.mauXe và this.giaXe sẽ chỉ các biến của lớp, còn các biến nhanHieuXe, mauXe, giaXe sẽ chỉ các biến cục bộ của hàm. Biến this là một biến ẩn đặc biệt luôn tồn tại trong các lớp java, một lớp có duy nhất một biến ẩn this, biến này được sử dụng trong khi chạy và nó trỏ đến bản thân lớp chứa nó. Biến this thường được sử dụng trong các hàm khởi tạo lớp, do đó các lệnh vẫn được thực thi như trong đoạn chuơng trình trên.

public static void main(String args[ ])

Đây là phương thức chính, từ đây chương trình bắt đầu việc thực thi. Tất cả các ứng dụng java đều sử dụng một phương thức main này. • Từ khoá public là một chỉ định truy xuất. Nó cho biết thành viên của lớp có thể được truy xuất từ bất cứ đâu trong chương trình. • Từ khoá static cho phép main được gọi tới mà không cần tạo ra một thể hiện (instance) của lớp. Nó không phụ thuộc vào các thể hiện của lớp được tạo ra. • Từ khoá void thông báo cho máy tính biết rằng phương thức sẽ không trả lại bất cứ giá trị nào khi thực thi chương trình. • String args[] là tham số dùng trong phương thức main. Khi không có một thông tin nào được chuyển vào main, phương thức được thực hiện với các dữ liệu rỗng – không có gì trong dấu ngoặc đơn.

2. Tính Kế thừa trong Java

Xét bài toàn quản lý nhân sự và sinh viên của một trường đại học. Ta có 2 lớp đối tượng quản lý chính là lớp Nhân Viên và lớp Sinh Viên, giả sử 2 lớp có các thuộc tính và phương thức như sau:

Lớp Nhân Viên Lớp Sinh Viên
Thuộc tính: Tên, Ngày sinh, Giới tính, Lương. Thuộc tính: Tên, Ngày sinh, Giới tính, Lớp.
Phương thức: Nhập/xem tên, Nhập/xem ngày sinh, Nhập/xem giới tính, Nhập/xem lương. Phương thức: Nhập/xem tên, Nhập/xem ngày sinh, Nhập/xem giới tính, Nhập/xem lớp.

Ta thấy 2 lớp có một số thuộc tính và phương thức chung: tên, ngày sinh, giới tính. Tuy nhiên, không thể loại bỏ các thuộc tính riêng biệt để gộp chúng thành 1 lớp duy nhất, vì các thuộc tính lương nhân viên và lớp của sinh viên là cần thiết cho việc quản lí. Vấn đề này nảy sinh một số vấn đề như phải viết mã trùng nhau đến 2 lần cho các phương thức như nhập/xem tên, nhập/xem ngày sinh, nếu có sự thay đổi về kiểu dữ liệu, chẳng hạn ngày sinh được quản lý trong hệ thống, ta phải sửa lại chương trình 2 lần. Để tránh rắc rối do các vấn đề phát sinh như vậy, kỹ thuật kế thừa trong java nhóm các phần giống nhau của các lớp thành một lớp mới, sau đó các lớp ban đầu kế thừa lại lớp được tạo ra. Như vậy, mỗi lớp kết thừa (lớp dẫn xuất, lớp con) đều có các thuộc tính và phương thức của lớp bị kế thừa (lớp cơ sở, lớp cha).

Từ phân tích trên, ta tạo một lớp mới gọi là lớp Người, lớp Người sẽ chứa các thuộc tính và phương thức chung của 2 lớp Nhân Viên và Sinh Viên hay còn gọi là lớp cha của lớp Nhân Viên và lớp Sinh Viên. Khi đó, các lớp sẽ chứa các thuộc tính và phương thức như sau:

Lớp Người
Thuộc tính: Tên, Ngày sinh, Giới tính
Phương thức: Nhập/xem tên, Nhập/xem ngày sinh, Nhập/xem giới tính

Cài đặt các lớp trong Java như sau: Lớp Người:

public class Nguoi {
    public String ten;
    public String ngaySinh;
    public String gioiTinh;

    public Nguoi(String ten, String ngaySinh, String gioiTinh){
        this.ten = ten;
        this.ngaySinh = ngaySinh;
        this.gioiTinh = gioiTinh;
    }
    public void show(){
        System.out.println(ten+ " sinh ngay "+ngaySinh+ " gioi tinh "+gioiTinh);
    }
}

Lớp Sinh Viên

class SinhVien extends Nguoi {
    private String lop;
    public SinhVien(String ten, String ngaySinh, String gioiTinh, String lop) {
        super(ten, ngaySinh, gioiTinh);
        this.lop = lop;
    }
}

Lớp Nhân Viên

class NhanVien extends Nguoi{
    private float luong;
    public NhanVien(String ten, String ngaySinh, String gioiTinh, float luong){
        super(ten, ngaySinh, gioiTinh);
        this.luong = luong;
    }
    public static void main(String []args){
        NhanVien nhanVien = new NhanVien("Tuan", "20/02/1993", "Nam", 1000);
        nhanVien.show();
    }
}

Lớp NhanhVien và lớp SinhVien được kế thừa từ lớp Nguoi, lớp kế thừa được hiện bởi từ khóa extends. Ở lớp NhanVien, vì được kế thừa từ lớp Nguoi, do đó đối tượng nhaVien có thể gọi đến phương thức show() của lớp Nguoi, khi chạy đoạn chương trình của lớp NhanVien sẽ in ra dòng thông báo: "Tuan sinh ngay 20/02/1993 gioi tinh Nam". Như vậy, sự kế thừa:

  • Cho phép lớp dẫn xuất có thể sử dụng các thuộc tính và phương thức của lớp cơ sở tương tự như sử dụng các thuộc tính và phương thức của mình.
  • Cho phép chỉ cần cài đặt phương thức ở 1 lớp cơ sở, mà có thể sử dụng được ở tất cả các lớp dẫn xuất.
  • Tránh sự cài đặt trùng lặp mã nguồn của chương trình.
  • Chỉ cần thay đổi một lần khi cần phải thay đổi dữ liệu của các lớp.

3. Tính Đa hình

Trở lại với ví dụ về quản lí trường đại học, với hai lớp Nhân viên và lớp Sinh viên, đều kế thừa từ lớp Người. Khi đó, ta thêm vào mỗi lớp một phương thức show():

  • Phương thức show của lớp Người sẽ giới thiệu tên, ngày sinh và giới tính của người đó.
  • Phương thức show của lớp Nhân viên sẽ giới thiệu nhân viên đó có tiền lương là bao nhiêu
  • Phương thức show của lớp Sinh viên sẽ giới thiệu là sinh viên đó đang học ở lớp nào.

Khi đó, nếu trong hệ thống có các đối tượng cụ thể tương ứng với ba lớp, thì:

  • Khi ta gọi hàm show từ đối tượng của lớp Người, sẽ nhận được tên, ngày sinh và giới tính của người đó.
  • Khi ta gọi phương thức show từ đối tượng của lớp Nhân viên, sẽ nhận được số tiền lương của nhân viên đó.
  • Khi ta gọi phương thức show từ đối tượng của lớp Sinh viên, ta sẽ biết được lớp học của sinh viên đó. Việc chỉ cần gọi cùng một phương thức, nhưng từ các đối tượng khác nhau, sẽ cho kết quả khác nhau được gọi là tính đa hình.

Như vậy, tính đa hình trong java:

  • Cho phép các lớp được định nghĩa các phương thức trùng nhau: cùng tên, cùng số lượng và kiểu tham số, cùng kiểu trả về. Việc định nghĩa phương thức trùng nhau của các lớp kế thừa nhau còn được gọi là sự ghi đè (overriding).
  • Khi gọi các phương thức trùng tên, dựa vào đối tượng đang gọi mà chương trình sẽ thực hiện phương thức của lớp tương ứng, và do đó, sẽ cho các kết quả khác nhau. Ví dụ: Khi muốn thay đổi nội dung của các phương thức được kế thừa từ lớp cha, ta có thể dùng cách khai báo phương thức ghi đè. Khai báo phương thức ghi đè là cách khai báo lại một phương thức có cùng tên và kiểu với một phương thức đã có trong lớp cha. Ví dụ ta muốn hàm show() in ra lương của nhân viên thay vì in ra các thông tin cá nhân tên, ngày sinh, giới tính, bằng cách sử dụng khai báo ghi đè, ta khai báo một phương thức có cùng tên và kiểu với phương thức show() trong lớp cha.
    class NhanVien extends Nguoi{
    private float luong;
    public NhanVien(String ten, String ngaySinh, String gioiTinh, float luong){
        super(ten, ngaySinh, gioiTinh);
        this.luong = luong;
    }
    public void show(){
        System.out.println(ten+ " có mức lương là  "+luong+"$/thang);
    }
    public static void main(String []args){
        NhanVien nhanVien = new NhanVien("Tuan", "20/02/1993", "Nam", 1000);
        nhanVien.show();
    }
    }

    Đoạn chương trình trên sẽ in ra dòng thông báo "Tuan có mức lương là 1000.0$/thang" thay vì dòng lệnh "Tuan sinh ngay 20/02/1993 gioi tinh Nam" như ban đầu, lý do là lúc này, đối tượng nhanVien sẽ gọi tới phương thức show() của lớp NhanVien mà không gọi phương thức show() của lớp Nguoi nữa.

3. Tính Đóng gói

Xét bài toán quản lý nhân viên văn phòng với lớp Nhân Viên như sau:

Lớp Nhân Viên
Thuộc tính: Tên, Ngày sinh, Giới tính, Phòng ban, Hệ số lương.
Phương thức: Tính lương nhân viên.

Ta có cách tính lương cho nhân viên là khác nhau đối với mỗi người: <Tiền lương> = <Hệ số lương> * <Lương cơ bản> * <Tỉ lệ phần trăm> Trong đó, tỉ lệ phần trăm là khác nhau cho mỗi phòng ban, ví dụ: Phòng kế hoạch là 105%, Phòng hành chính là 100%, Phòng nhân sự là 110% Khi đó, tuỳ vào thuộc tính phòng ban khác nhau mà ta phải dùng công thức tỉ lệ khác nhau để tính lương cho mỗi nhân viên. Tuy nhiên, cách tính cụ thể này là công việc bên trong của phương thức tính tiền lương của lớp Nhân viên. Với mỗi ứng dụng, khi tạo một đối tượng cụ thể của lớp nhân viên, ta chỉ cần truyền các tham số thuộc tính cho đối tượng, sau đó gọi phương thức tính tiền lương cho đối tượng nhân viên đó, ta sẽ biết được tiền lương của nhân viên. Cách gọi phương thức tính tiền lương là hoàn toàn giống nhau cho tất cả các đối tượng nhân viên của văn phòng.

Sự giống nhau về cách sử dụng phương thức cho các đối tượng của cùng một lớp, mặc dù bên trong phương thức có các cách tính toán khác nhau với các đối tương khác nhau, được gọi là tính đóng gói dữ liệu. Như vậy, tính đóng gói dữ liệu: • Cho phép che dấu sự cài đặt chi tiết bên trong của phương thức. Khi sử dụng chỉ cần gọi các phương thức theo một cách thống nhất, mặc dù các phương thức có thể được cài đặt khác nhau cho các trường hợp khác nhau. • Cho phép che dấu dữ liệu bên trong của đối tượng. Khi sử dụng, ta không biết được thực sự bên trong đối tượng có những gì, ta chỉ thấy được những gì đối tượng cho phép truy nhập vào. • Cho phép hạn chế tối đa việc sửa lại mã chương trình. Khi phải thay đổi công thức tính toán của một phương thức, ta chỉ cần thay đổi mã bên trong của phương thức, mà không phải thay đổi các chương trình gọi đến phương thức bị thay đổi.

||. Các cấu trúc lệnh trên Java

Java cung cấp hai loại cấu trúc điều khiển: Điều khiển rẽ nhánh:

  • Mệnh đề if-else
  • Mệnh đề switch-case

Vòng lặp:

  • Vòng lặp while
  • Vòng lặp do-while
  • Vòng lặp for

1. Câu lệnh if-else

Câu lệnh if-else kiểm tra giá trị dạng boolean của điều kiện. Nếu giá trị điều kiện là True thì khối lệnh sau if được thưc hiện, nếu False thì khối lệnh sau else được thực hiện: if (condition){ action1; } else{ action 2; } condition: Biểu thức boolean action1: Khối lệnh được thực hiện khi giá trị điều kiện là True action2: Khối lệnh được thực hiện khi giá trij điều kiện là False

public class CheckNumber {
    public static void main(String []args){
        int num = 10;
        if(num%2 == 0)
            System.out.println(num + " là số chia hết cho 2");
        else
            System.out.println(num + " là số không chia hết cho 2");
    }
}

Ở chương trình trên khai báo 1 biến số num, num được gán giá trị nguyên là 10. Câu điều kiện kiểm tra num lấy phần dư cho 2 có đúng bằng 0 hay không. Kết quả khi run chương trình trên in ra thông báo "10 là số chia hết cho 2", tức là điều kiện trả về giá trị True, khối lệnh sau if được thực hiện. Lưu ý, vì chỉ có 1 câu lệnh nên đoạn lệnh sau "if" và "else" không cần thiết phải được đưa vào dấu ngoặc móc "{" và "}", hai lệnh trở lên sẽ có ngoặc móc để đưa các lệnh vào 1 khối.

2. Câu lệnh switch-case

Khối lệnh switch-case có thể được sử dụng thay thế câu lệnh if-else trong trường hợp một biểu thức cho ra nhiều kết quả. Cú pháp: swich (expression) { case ‘value1’: action 1 statement; break; case ‘value2’: action 2 statement; break; ..................... case ‘valueN’: actionN statement; break; default: default_action statement; } expression - Biến chứa một giá trị xác định value1,value 2,....valueN: Các giá trị hằng số phù hợp với giá trị trên biến expression . action1,action2...actionN: Khối lệnh được thực thi khi trường hợp tương ứng có giá trị True break: Từ khoá được sử dụng để bỏ qua tất cả các câu lệnh sau đó và giành quyền điều khiển cho cấu trúc bên ngoài switch default: Từ khóa tuỳ chọn được sử dụng để chỉ rõ các câu lệnh nào được thực hiện chỉ khi tất cả các trường hợp nhận giá trị False default - action: Khối lệnh được thực hiện chỉ khi tất cả các trường hợp nhận giá trị False Đoạn chương trình sau xác định giá trị trong một biến nguyên và hiển thị ngày trong tuần được thể hiện dưới dạng chuỗi. Để kiểm tra các giá trị nằm trong khoảng từ 0 đến 6, chương trình sẽ thông báo lỗi nếu nằm ngoài phạm vi trên.

public class SwitchDemo {
    public static void main(String agrs[]) {
        int day = 2;
        switch (day) {
        case 0:
            System.out.println("Sunday");
            break;
        case 1:
            System.out.println("Monday");
            break;
        case 2:
            System.out.println("Tuesday");
            break;
        case 3:
            System.out.println("Wednesday");
            break;
        case 4:
            System.out.println("Thursday");
            break;
        case 5:
            System.out.println("Friday");
            break;
        case 6:
            System.out.println("Satuday");
            break;
        default:
            System.out.println("Invalid day of week");
        }
    }
}

Kết quả khi run, chương trình sẽ hiển thị "Tuesday".

3. Vòng lặp while

while (condition) { action; } condition: có giá trị boolean, vòng lặp được thực hiện nếu điều kiện vẫn có giá trị True. action: khối lệnh được thực hiện nếu condition nhận giá trị True Vòng lặp dừng lại khi condition nhận giá trị False. Chương trình thực hiện tính tổng các số nguyên chẵn lớn hơn 0 và bé hơn 5:

public class WhileLoopDemo {
    public static void main(String[] args) {
        int num = 5, sum = 0;
        while (num >=1){
            if(num%2 == 0){
                sum+= num;
            }
            num --;
        }
        System.out.println("Tổng các số chẵn nguyên dương bé hơn 5 là: "+ sum);
    }
}

Vòng lặp được thực hiện với điều kiện biến num >=1, cuối mỗi vòng lặp giá trị của num giảm đi 1 kể cả điều kiện if trong khối lệnh while có được thực hiện hay không, khối lệnh if kiểm tra các số num có chia hết cho 2 hay không, nếu chia hết giá trị sẽ được cộng với giá trị của biến sum, sau 5 vòng lặp giá trị của num bằng 0, điều kiện trả về là False và vòng lặp kết thúc. Kết quả sẽ được hiển thị "Tổng các số chẵn nguyên dương bé hơn 5 là: 6"

4. Vòng lặp do-while

do{ action; }while(condition);

condition: Biểu thức boolean, vòng lặp được thực hiện nếu điều kiện condition có giá trị True. action: khối lệnh luôn được thực hiện lần thứ nhất, từ vòng thứ 2, được thực hiện khi condition trả về giá trị True. Vòng lặp kết thúc khi condition trả về giá trị False. Chương trình tính tổng 5 số tự nhiên đầu tiên:

public class DoWhileDemo {
    public static void main(String[] args) {
        int num = 1, sum = 0;
        do {
            sum += num;
            num++;

        } while (num <= 5);
        System.out.println("Tổng 5 số tự nhiên đầu tiên là: " + sum);
    }
}

Biến num được khởi tạo giá trị 1, sau mỗi lần lặp được tăng giá trị lên 1 và được cộng dồn vào giá trị của biến sum. Kết thúc vòng lặp, chương trình sẽ in ra "Tổng 5 số tự nhiên đầu tiên là: 15".

5. Vòng lặp for

Vòng lặp for là kết hợp tất cả các đặc điểm chung của tất cả các loại vong lặp: giá trị khởi tạo của biến chạy, điều kiện dừng của vòng lặp và lệnh thay đổi của biến chạy. for(initialization statements; condition; increment statements) { action statements; } initialization statements: khởi tạo giá trị ban đầu cho các biến chạy, các lệnh khởi tạo được phân cách nhau bởi dấu phẩy và chỉ thực hiện duy nhất một lần vào thời điểm bắt đầu của vòng lặp. condition: Biểu thức bool; vòng lặp sẽ tiếp tục cho đến khi nào điều kiện có giá trị False. increment statements: Các câu lệnh thay đổi giá trị của biến chạy. Các lệnh này luôn được thực hiện sau mỗi lần thực hiện khối lệnh trong vòng lặp. Các lệnh phận biệt nhau bởi dấu phẩy. Chương trình in tổng các số tự nhiên là số lẻ lớn hơn 0 và bé hơn 5:

public class ForLoopDemo {
    public static void main(String[] args) {
        int i, sum = 0;
        for (i = 1; i <= 5; i++) {
            if (i % 2 == 1)
                sum += i;
        }
        System.out.println("Tổng các số tự nhiên là số lẻ lớn hơn 0 và bé hơn 5 là: " + sum);
    }

}

Ở ví dụ trên i và sum được gán giá trị ban đầu tương ứng là 1 và 0. Trong vòng lặp for kiểm tra điều kiện giá trị của i có bé hơn 5 hay không nếu đúng khối lệnh sau for được hiện, khối lệnh này thực hiện kiểm tra giá trị của i chia cho 2 có đúng dư bằng 1 hay không, nếu đúng thực hiện cộng giá trị của i với giá trị của biến sum và giá trị tổng này được lưu lại trong biến sum, nếu sai tiếp tục thực hiện vòng lặp tiếp theo, sau mỗi lần thực hiện, giá trị biến i được tăng lên 1 và tiếp tục được kiểm tra với điều kiện. Sau 5 vòng, giá trị i tăng lên 6, kiểm tra với điều kiện lúc này i đã lớn hơn 5, điều kiện trả về giá trị False và vòng lặp kết thúc. Kết quả màn hình in ra thông báo: "Tổng các số tự nhiên là số lẻ lớn hơn 0 và bé hơn 5 là : 9".

Bài viết này dừng lại ở đây, ở bài tiếp theo, sẽ giới thiệu chi tiết về các đặc trưng của các từ khóa của lớp, của thuộc tính cũng như cách sử dụng trong java như public, protected, final, private, abstract...

Viết câu trả lời

Drop Images

0 Bình luận