[Tự học lập trình Java] Các đối tượng.

 

Các đối tượng (Objects)

Khái niệm về đối tượng.

Một cách điển hình trong chương trình Java tạo nhiều đối tượng, như bạn biết, tương tác bằng gọi các phương thức. Mặc dù tương tác với đối tượng, trong chương trình cần quan tâm đến đầu ra của nó, như triển khai một GUI, chạy một kịch bản, gửi và nhận thông tin của mạng. Một đối tượng có thể hoàn thành công việc mà nó được tạo ra, tài nguyên nó được tái sử dụng với các đối tượng khác.

Chương trình CreateObjectDemo, tạo ba đối tượng: một đối tượng Point và hai đối tượng Rectangle. Bạn sẽ cần ba tệp để biên dịch chương trình này.

Tệp CreateObjectDemo có nội dung:

public class CreateObjectDemo {
 
    public static void main(String[] args) {
                 
        // Declare and create a point object and two rectangle objects.
        Point originOne = new Point(23, 94);
        Rectangle rectOne = new Rectangle(originOne, 100, 200);
        Rectangle rectTwo = new Rectangle(50, 100);
                 
        // display rectOne's width, height, and area
        System.out.println("Width of rectOne: " + rectOne.width);
        System.out.println("Height of rectOne: " + rectOne.height);
        System.out.println("Area of rectOne: " + rectOne.getArea());
                 
        // set rectTwo's position
        rectTwo.origin = originOne;
                 
        // display rectTwo's position
        System.out.println("X Position of rectTwo: " + rectTwo.origin.x);
        System.out.println("Y Position of rectTwo: " + rectTwo.origin.y);
                 
        // move rectTwo and display its new position
        rectTwo.move(40, 72);
        System.out.println("X Position of rectTwo: " + rectTwo.origin.x);
        System.out.println("Y Position of rectTwo: " + rectTwo.origin.y);
    }
}

Lớp Point có nội dung:

public class Point {

    public int x = 0;

    public int y = 0;

    // a constructor!

    public Point(int a, int b) {

    x = a;

    y = b;

    }

}

Lớp Rectangle có nội dung:

public class Rectangle {

    public int width = 0;

    public int height = 0;

    public Point origin;

 

    // four constructors

    public Rectangle() {

    origin = new Point(0, 0);

    }

    public Rectangle(Point p) {

    origin = p;

    }

    public Rectangle(int w, int h) {

    origin = new Point(0, 0);

    width = w;

    height = h;

    }

    public Rectangle(Point p, int w, int h) {

    origin = p;

    width = w;

    height = h;

    }

 

    // a method for moving the rectangle

    public void move(int x, int y) {

    origin.x = x;

    origin.y = y;

    }

 

    // a method for computing the area of the rectangle

    public int getArea() {

    return width * height;

    }

}

Chương trình tạo, thao tác, và hiển thị thông tin của các đối tượng khác nhau. Đầu ra của chương trình là:

Width of rectOne: 100
Height of rectOne: 200
Area of rectOne: 20000
X Position of rectTwo: 23
Y Position of rectTwo: 94
X Position of rectTwo: 40
Y Position of rectTwo: 72

Ba phần sau sử dụng ví dụ ở phía trên mô tả vòng đời của một đối tượng trong một chương trình. Từ chúng, bạn sẽ học được cách viết mã nguồn như tạo và sử dụng các đối tượng trong chương trình của bạn. Bạn cũng sẽ học được làm thế nào làm sạch hệ thống trước một đối tượng khi vòng đời của nó kết thúc.

Tạo đối tượng.

Tạo đối tượng như thế nào:

Như bạn đã biết, một lớp cung cấp bản thiết kế (blueprint) cho các đối tượng; bạn tạo một đối tượng từ một lớp. Mỗi một câu lệnh sau đây, được lấy từ chương trình CreateObjectDemo ở trên tạo một đối tượng và gán nó cho một biến:

Point originOne = new Point(23, 94);
Rectangle rectOne = new Rectangle(originOne, 100, 200);
Rectangle rectTwo = new Rectangle(50, 100);

Mỗi câu lệnh có ba thành phần (bàn chi tiết bên dưới):Dòng đầu tiên tạo một đối tượng của lớp Point, và dòng thứ hai và thứ ba tạo một đối tượng của lớp Rectangle.

·        Khai báo (Declaration): Vế trái là tất cả các biến được khai báo có liên kết với một tên biến và một kiểu đối tượng.

·        Cụ thể hóa (Instantiation): Từ khóa new là toán tử dùng để tạo đối tượng.

·        Khởi tạo (Initialization): Toán tử new cho phép gọi một hàm khởi tạo, gán cho đối tượng mới được tạo ra.

Khai báo một biến tham chiếu đến một đối tượng.

Ở phần trước, bạn đã học khai báo một biến theo cú pháp:

type name;

Khai báo cho trình biên dịch bạn sẽ sử dụng tên để tham chiếu đến dữ liệu type. Với một biến nguyên thủy, khai báo này cũng dành số lượng bộ nhớ thích hợp cho biến.

Bạn có thể khai báo biến tham chiếu như thế. Ví dụ:

Point originOne;

Nếu bạn khai báo biến originOne như cách này, giá trị của nó sẽ không xác định cho đến khi một đối tượng thực sự được tạo ra và gán cho nó. Khai báo đơn giản một biến tham chiếu không tạo đối tượng. Điều đó, bạn cần sử dụng toán tử new, sẽ được mô tả trong phần tiếp theo. Bạn phải gán một đối tượng cho originOne trước khi sử dụng nó trong mã nguồn của bạn. Nếu không trình biên dịch sẽ bị lỗi.

Một biến trong trạng thái này, biến hiện tại không tham chiếu đến một đối tượng nào, có thể minh họa điều đó (tên biến, là originOne, cộng với một tham chiếu không xác định).

Khai báo biến tham chiếu mà không gán đối tượng

Khai báo biến tham chiếu mà không gán đối tượng

Khởi tạo một lớp.

Toán tử new khởi tạo một lớp bằng cách cấp vùng nhớ cho đối tượng mới được tạo ra và trả về một tham chiếu đến vùng nhớ đó. Toán tử new cũng gọi hàm tạo đối tượng.

Ghi nhớ: Câu “khởi tạo một lớp” có nghĩa như là “tạo một đối tượng”. Khi bạn tạo một đối tượng, bạn đang tạo ra một “cái cụ thể” của một lớp, do đó cũng “khởi tạo một lớp”.

Toán tử new là một từ đơn, đặt trước đối số: một lời gọi hàm khởi tạo. Tên của hàm khởi tạo cung cấp tên của lớp khởi tạo.

Toán tử new trả về một tham chiếu đến đối tượng được tạo ra. Tham chiếu này thường được gán cho biến có kiểu phù hợp như:

Point originOne = new Point(23, 94);

Khởi tạo một đối tượng.

Mã nguồn sau là lớp Point:

public class Point {
    public int x = 0;
    public int y = 0;
    //constructor
    public Point(int a, int b) {
        x = a;
        y = b;
    }
}

Lớp này bao gồm một hàm khởi tạo đơn. Bạn có thể nhận ra một hàm khởi tạo bởi vì nó được khai báo có tên giống với tên lớp và không có kiểu trả về. Hàm khởi tạo trong lớp Point có hai đối số nguyên, được khai báo trong đoạn code (int a, int b). Câu lệnh cung cấp số 23 và số 94 cho đối số:

Point originOne = new Point(23, 94);

Kết quả của thực thi là câu lệnh có thể minh họa trong dưới.

Minh họa thực thi câu lệnh khởi tạo đối tượng cho biến tham chiếu

Minh họa thực thi câu lệnh khởi tạo đối tượng.

Mã nguồn của lớp Rectangle, bao gồm bốn hàm khởi dựng:

public class Rectangle {
    public int width = 0;
    public int height = 0;
    public Point origin;
 
    // four constructors
    public Rectangle() {
        origin = new Point(0, 0);
    }
    public Rectangle(Point p) {
        origin = p;
    }
    public Rectangle(int w, int h) {
        origin = new Point(0, 0);
        width = w;
        height = h;
    }
    public Rectangle(Point p, int w, int h) {
        origin = p;
        width = w;
        height = h;
    }
 
    // a method for moving the rectangle
    public void move(int x, int y) {
        origin.x = x;
        origin.y = y;
    }
 
    // a method for computing the area of the rectangle
    public int getArea() {
        return width * height;
    }
}
Mỗi hàm khởi tạo, bạn hãy cung cấp các giá trị ban đầu cho hình chữ nhật, chiều rộng, chiều cao, sử dụng cả kiểu dữ liệu nguyên thủy và các kiểu dữ liệu tham chiếu. Nếu một lớp có nhiều hàm khởi dựng, bạn phải phân biệt bằng chữ ký. Trình biên dịch của Java phân tiệt các hàm khởi tạo dựa trên số lượng và kiểu dữ liệu của các đối số. Khi trình biên dịch biên dịch mã nguồn, nó biết gọi hàm khởi dựng nào trong lớp Rectangle với yêu cầu một đối số là đối tượng của lớp Point theo sau đó là hai số nguyên:

Rectangle rectOne = new Rectangle(originOne, 100, 200);

Gọi một hàm khởi tạo Rectangle tạo origin thành originOne. Theo đó, hàm khởi tạo sẽ thiết lập width là 100 và height là 200. Bây giờ, có hai đối tượng Point tham chiếu đến cùng  một đối tượng, một đối tượng có thể có nhiều tham chiếu đến nó, biểu hiện trong dưới.

Đối tượng Point có hai tham chiếu đến - tinhoccoban.net

Đối tượng Point có hai tham chiếu đến.

Theo dòng mã nguồn khởi tạo Rectangle yêu cầu hai đối đố, cung giastrij cho width và height. Nếu bạn để ý dòng lệnh trong hàm khởi tạo, bạn sẽ nhìn thấy tạo đối tượng Point có giá trị x và giá trị y được khởi gán bằng 0.

Rectangle rectTwo = new Rectangle(50, 100);

Hàm khởi dựng Rectangle sử dụng dòng lệnh không có bất kỳ đối số nào, nó được gọi là hàm khởi dựng không đối số:

Rectangle rect = new Rectangle();

Tất các các lớp có ít nhất một hàm khởi tạo. Nếu lớp đó không có hàm này rõ ràng, trình biên dịch Java sẽ tự động cung cấp một hàm khởi tạo không đối số, được gọi là hàm khởi tạo mặc định (default contructor). Hàm khởi tạo mặc định này sẽ gọi hàm khởi tạo không tham số của lớp cha, hoặc đối tượng khởi tạo Object nếu nó không có lớp cha. Nếu lớp cha không có hàm khởi tạo (Lớp Object thì có một hàm), trình biên dịch sẽ từ chối chương trình.

Sử dụng đối tượng.

Khi bạn tạo ra một đối tượng, bạn có thể muốn sử dụng nó vào một vài việc. Bạn có thể cần sử dụng giá trị của các thuộc tính, thay đổi các thuộc tính, hoặc gọi các phương thức để thực thi một hành động nào đó.

Thuộc tính đối tượng tham chiếu.

Các thuộc tính đối tượng được truy cập bởi tên của chúng. Bạn phải sử dụng tên rõ ràng.

Bạn có thể sử dụng một tên đơn giản cho một thuộc tính bên trong một lớp. Ví dụ, chúng ta có thể thêm một lệnh vào trong lớp Rectangle để in ra width và height:

System.out.println("Width and height are: " + width + ", " + height);

Trong trường hợp này, widthheigh là những tên đơn.

Mã nguồn bên ngoài lớp của đối tượng đó phải sử dụng một đối tượng tham chiếu hoặc một biểu thức theo sau đó là toán tử dấu chấm (.), theo sau đó nữa là tên thuộc tính đơn như ví dụ:

objectReference.fieldName

Ví dụ, mã nguồn của CreateObjectDemo là bên ngoài lớp Rectangle. Do vậy tham chiếu đến các thuộc tinh origin, width, và height của đối tượng rectOne của lớp Rectangle, lớp CreateObjectDemo phải sử dụng các tên: rectOne.origin, rectOne.width, rectOne.height tương ứng. Chương trình sử dụng hai trong số các tên này để hiển thị width và height của đối tượng rectOne:

System.out.println("Width of rectOne: "  + rectOne.width);
System.out.println("Height of rectOne: " + rectOne.height);

Cố gắng sử dụng tên widthheight trong mã nguồn của lớp CreateObjectDemo không có nghĩa, các trường này chỉ tồn tại trong một đối tượng, và sẽ trả về một kết quả biên dịch lỗi.

Sau này, chương trình sử dụng tương tự mã nguồn hiển thị thông tin về recTwo. Các đối tượng cùng loại có bản sao của riêng chúng cuẩ các thuộc tính giống nhau. Như vậy, mỗi đối tượng Rectangle có các thuộc tính origin, width, và height. Khi bạn truy cập vào một thuộc tính cụ thể của đối tượng tham chiếu, bạn tham chiếu đến thuộc tính của đối tượng. Hai đối tượng rectOnerectTwo trong chương trình CreateObjectDemo có các thuộc tính origin, width, và height khác nhau.

Để truy cập vào một thuộc tính, bạn có thể sử dụng tên được tham chiếu cho một đối tượng, giống như trong ví dụ trước, hoặc bạn sử dụng một biểu thức bất kỳ trả về một đối tượng tham chiếu. Gọi lại toán tử new trả về tham chiếu của một đối tượng. Do vậy bạn có thể sử dụng giá trị trả về từ  truy vâp vào các thuộc tính đối tượng mới:

int height = new Rectangle().height;

Câu lệnh này tạo một đối tượng Rectangle mới và lập tức lấy chiều cao height. Bản chất câu lệnh tính toán giá trị mặc định chiều cao height của một Rectangle. Lưu ý rằng, sau khi câu lệnh này được thực thi xong, chương trình không còn tham chiếu đến đối tượng Rectangle đã tạo, bởi vì chương trình không bao giờ lưu trữ tham chiếu ở bất kỳ đâu. Đối tượng không được tham chiếu, tài nguyên đó được giải phóng và được tái sử dụng bởi máy ảo Java (Java Vitual Machine).

Gọi các phương thức của một đối tượng.

Bạn cũng có thể sử dụng một đối tượng tham chiếu để gọi các phương thức của đối tượng. Bạn nối tên đơn cho phương thức để tham chiếu đối tượng, với sử dụng một toán tử chấm (.). Do vậy, bạn cung cấp, bên trong dấu ngoặc đơn, bất kỳ một đối số nào cho phương thức. Nếu phương thức không yêu cầu một đối số nào, sử dụng dấu mở đóng ngoặc, bên trong để trống.

objectReference.methodName(argumentList);

Hoặc:

objectReference.methodName();

Lớp Rectangle có hai phương thức: getArea() để tính toán diện tích và move() để thay đổi hình chữ nhật ban đầu. Ở đây, trong mã nguồn CreateObjectDemo đã gọi cả hai phương thức:

System.out.println("Area of rectOne: " + rectOne.getArea());
...
rectTwo.move(40, 72);

Cũng giống như các thuộc tính cụ thể, objectReference phải được tham chiếu đến một đối tượng. Bạn có thể sử dụng bên biến, nhưng bạn cũng có thể sử dụng bất kỳ biểu thức nào có trả về một đối tượng tham chiếu. Toán tử new trả về một đối tượng tham chiếu, do vậy bạn có thể sử dụng giá trị trả về từ việc gọi phương thức cho đối tượng mới:Câu lệnh đầu gọi phương thức getArea() ở đối tượng rectOne và hiển thị kết quả. Câu lệnh thứ hai, di chuyển đối tượng rectTwo bởi vì phương thức move() gán giá trị mới cho đối tượng là origin.xorigin.y.

new Rectangle(100, 50).getArea()

Biểu thức new Rectangle(100, 50) trả về một đối tượng tham chiếu tham chiếu đến một đối tượng Rectangle. Như minh họa, bạn có thể sử dụng dấu chấm để gọi phương thức getArea() cho đối tượng Rectangle mới để tính toán diện tích hình chữ nhật mới này.

Một vài phương thức, như getArea(), trả về một giá trị. Các phương thức trả về một giá trị, bạn có thể sử dụng để gọi trong một biểu thức. Bạn có thể gán giá trị trả về cho một biến, sử dụng nó để quyết định, hoặc điều khiển một vòng lặp. Mã nguồn này gán giá trị trả về  của getArea() cho một biến là areaOfRectangle:

int areaOfRectangle = new Rectangle(100, 50).getArea();

Nhớ rằng, gọi một phương thức trong một đối tượng cụ thể là sử dụng giống như gửi một thông điệp đến đối tượng đó. Trong trường hợp này, đối tượng sẽ gọi phương thức getArea() của đối tượng hình chữ nhật được tạo ra bởi hàm khởi tạo.

Dọn dẹp rác trong Java.

Một vài ngôn ngữ lập trình hướng đối tượng yêu cầu bạn phải bám sát tất cả các đối tượng được tạo ra và giải phóng chúng khi không cần sử dụng một thời gian dài. Quản lý bộ nhớ như vậy rất đơn điệu và dễ mắc lỗi. Nền tảng Java cho phép bạn tạo ra rất nhiều đối tượng mà bạn muốn (tất nhiên là có giới hạn, bởi vì hệ thống của bạn có thể kiểm soát chúng), bạn không thể cần lo lắng về việc giải phóng chúng. Môi trường lập trình Java xóa các đối tượng khi nó xác định chúng không dùng nữa. Tiến trình này được gọi là dọn dẹp rác trong Java (garbage collection).

Một đối tượng đạt tiêu chuẩn để được dọn rác khi không còn tham chiếu nào đến đối tượng đó. Các tham chiếu được hỗ trợ xóa đến một biến nếu biến đó không còn không còn nằm trong phạm vi tham chiếu. Hoặc, bạn có thể xóa một đối tượng tham chiếu bằng cách cài đặt biến đó có giá trị null. Nhớ rằng, một chương trình có thể có nhiều tham chiếu đến một đối tượng, tất cả các tham chiếu đến đối tượng đố phải được xóa trước khi đối tượng đó được dọn rác.

Môi trường lập trình Java có một cơ chế dọn rác, đó là định kỳ làm sạch bộ nhớ được sử dụng bởi các đối tượng không được tham chiếu. Cơ chế dọn rác làm việc tự động và quyết định thời gian phù hợp.

Mới hơn Cũ hơn

Biểu mẫu liên hệ