Java 8 – Lớp


Được đăng vào ngày 24/04/2017 | 0 bình luận

Chúng ta đã tìm hiểu qua về lớp trong các phần trước, trong phần này chúng ta sẽ tìm hiểu kĩ hơn.

Khai báo lớp

Chúng ta đã biết cú pháp khai báo lớp như sau:

class MyClass {
    // thuộc tính và phương thức
}

Cú pháp trên là cú pháp khai báo lớp. Phần thân lớp nằm giữa cặp dấu ngoặc nhọn sẽ chứa đoạn code mô tả vòng đời của các đối tượng được tạo ra từ lớp đó, chẳng hạn như phương thức khởi tạo để khởi tạo các đối tượng, khai báo các thuộc tính để lưu giữ trạng thái của lớp và các đối tượng, khai báo phương thức để mô tả các hành vi của lớp.

Cú pháp trên là cú pháp cơ bản, chúng ta có thể khai báo lớp này kế thừa từ một lớp khác hay code một giao diện nào đó với cú pháp đầy đủ như sau:

class MyClass extends MySuperClass implements YourInterface {
    // thuộc tính và phương thức
}

Cú pháp trên có ý nghĩa là lớp MyClass kế thừa từ lớp MySuperClass, và code giao diện YourInterface.

Ngoài ra chúng ta có thể thêm các từ khóa phạm vi hoạt động như public hay private và trước từ khóa class, chúng ta sẽ tìm hiểu sau về phạm vi hoạt động.

Khai báo biến

Biến có các loại sau đây:

  • Biến thành viên của một lớp – có tên khác là trường hoặc thuộc tính
  • Biến nằm trong một phương thức hoặc khối lệnh – có tên khác là biến cục bộ
  • Biến nằm trong phần khai báo tên phương thức – có tên khác là tham số

Chẳng hạn như:

class Bicycle {
    public int speed;
    public int gear;
}

Trong đoạn code trên thì speedgear là các trường (hoặc thuộc tính), cú pháp khai báo trường gồm có:

  • Có thể có từ khóa khai báo phạm vi như public hoặc private
  • Kiểu dữ liệu (bắt buộc)
  • Tên trường (bắt buộc)

Từ khóa phạm vi hoạt động cho biết lớp nào có quyền được đọc/ghi trực tiếp lên thuộc tính. Bây giờ thì chúng ta chỉ xem qua 2 từ khóa chính là publicprivate thôi:

  • public – lớp nào cũng có thể đọc/ghi trực tiếp vào thuộc tính
  • private – chỉ có thể đọc/ghi từ chính lớp đó

Thông thường thì tất cả các thuộc tính nên được để private, tức là chỉ có thể truy xuất từ chính lớp chủ của nó, việc truy xuất từ các lớp khác nên được làm thông qua phương thức. Ví dụ:

public class Bicycle {
    private int gear;
    private int speed;

    public int getGear() {
        return gear;
    }

    public void setGear(int newValue) {
        gear = newValue;
    }

    public int getSpeed() {
        return speed;
    }

    public void speedUp(int increment) {
        speed += increment;
    }    
}

Kiểu dữ liệu của thuộc tính có thể là bất cứ kiểu dữ liệu nào, từ các kiểu dữ liệu cơ bản như int, float, boolean… cho đến các kiểu lớp và phức tạp hơn như String, mảng, đối tượng…v.v

Định nghĩa phương thức

Ví dụ về cú pháp của một phương thức như sau:

public double calculate(double first, double second) {
    // tính toán
}

Một phương thức cần ít nhất là kiểu dữ liệu trả về, cặp dấu ngoặc tròn () và khối lệnh trong cặp dấu ngoặc nhọn {}.

Ngoài ra phương thức còn có thể có từ khóa phạm vi (public, private) tên phương thức, danh sách các tham số trong cặp dấu ngoặc nhọn, tên phương thức, danh sách các lỗi ngoại lệ (sẽ tìm hiểu sau), phần thân phương thức trong cặp dấu ngoặc nhọn {}.

Chúng ta có thể có nhiều phương thức cùng tên nhưng khác danh sách tham số hoặc kiểu dữ liệu trả về, và được gọi là ghi đè phương thức, ví dụ:

public class Data {
    public void calculate(String s) {
        ...
    }

    public void calculate(int i) {
        ...
    }

    public void calculate(double f) {
        ...
    }    
}

Chúng ta không thể khai báo 2 phương thức có cùng tên, cùng kiểu dữ liệu trả về và cùng danh sách các phương thức.

Phương thức khởi tạo

Phương thức khởi tạo là các phương thức được gọi khi đối tượng được tạo ra, dùng để khai báo giá trị cho các thuộc tính, ví dụ:

public Bicycle(int startGear, int startSpeed) {
    gear = startGear;
    speed = startSpeed;
}

Để khởi tạo một đối tượng thì chúng ta dùng toán tử new như thường:

Bicycle myBike = new Bicycle(0, 8);

Toán tử new sẽ gọi phương thức khởi tạo Bicycle() ở trên.

Phương thức khởi tạo cũng giống như phương thức bình thường, chỉ khác là tên phương thức chính là tên lớp, và không có kiểu dữ liệu trả về. Chúng ta có thể có nhiều phương thức khởi tạo, miễn là chúng khác nhau danh sách tham số.

Phương thức khởi tạo không bắt buộc phải có, khi biên dịch thì trình biên dịch sẽ tự tạo ra một phương thức khởi tạo rỗng nếu chúng ta không khai báo.

Truyền tham số

Các phương thức khi được khai báo có thể nhận vào các biến, chúng ta gọi chúng là các tham số.  Ví dụ:

public double calculate(double a, double b) {
    ...
}

Trong đoạn code trên thì phương thức là calculate, có 2 biến tham số là ab có kiểu dữ liệu là double.

Cũng giống như các biến bình thường, kiểu dữ liệu của tham số cũng có thể là bất kì kiểu nào. Từ các kiểu cơ bản cho đến các kiểu phức tạp hơn.

Thông thường chúng ta hay khai báo số lượng các biến tham số một cách rõ ràng, tức là phương thức nhận vào 3 tham số thì chính xác là 3 tham số. Tuy nhiên Java có một cú pháp cho phép chúng ta truyền vào số lượng tham số bất kì. Ví dụ:

public double sum(double... values) {
    double result = 0;
    int n = values.length;
    for(int i = 0 ; i < n ; i++) {
        result += values[i];
    }
    return result;
}

Cú pháp này thực ra cũng chỉ là một dạng khác của mảng thôi, để khai báo thì chúng ta thêm 3 dấu chấm vào sau kiểu dữ liệu, và tham số lúc này sẽ là một mảng, chúng ta có thể thao tác như mảng bình thường. Khi truyền tham số thì chúng ta truyền từng giá trị đơn lẻ:

System.out.println(sum(2.3, 4.6, 1.0, 3.2, 9.8));

Các biến tham số cũng có phạm vi tương tự như các biến cục bộ, tức là chỉ có hiệu lực trong phương thức đó, do đó tên biến tham số không được trùng với tên các biến cục bộ khác. Tuy nhiên biến tham số có thể trùng tên với tên của thuộc tính, để có thể sử dụng 2 biến này với nhau chúng ta phải dùng đến con trỏ this, tuy nhiên con trỏ this sẽ được bàn đến trong các bài sau, và tốt hơn hết là không nên đặt tên 2 biến đó giống nhau.

Được đăng vào ngày 24/04/2017