[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.

[Tự học lập trình Java] Lớp trong lập trình.

 Với những gì bạn đã biết về cú pháp lập trình cơ bản của ngôn ngữ lập trình Java, bạn có thể học viết các lớp của bạn. Trong phần này, bạn sẽ tìm thấy các thông tin về định nghĩa các lớp của bạn, bao bồm khai báo các thành viên: các biến, các phương thức và các phương thức khởi dựng.

Bạn sẽ học sử dụng các lớp để tạo ra các đối tượng và làm thế nào để sử dụng các đối tượng bạn tạo ra.

Cũng trong chương này bạn cũng được biết các lớp nằm trong lớp khác, và kiểu dữ liệu liệt kê.

Ngôn ngữ lập trình Java - tinhoccoban.net


Lớp (Class)

Khái niệm

Trong phần này trình bày với bạn cấu trúc của một lớp, và làm thế nào để định nghĩa các trường (fields), các phương thức (methods) và các hàm khởi dựng (contructors).

Trong phần giới thiệu về khái niệm lập trình hướng đối tượng ở chương trước có sử dụng lớp bicycle làm ví dụ, với chiếc xe đua, xe đạp leo núi, xe đạp song song với tư cách là lớp con. Ở đây là ví dụ mã nguồn về khả năng thực thi một lớp Bicycle, để cho bạn một cái nhìn tổng quan về khai báo lớp. Tiếp theo phần này sẽ quay về giải thích khai báo lớp từng bước một. Hiện tại, bạn đừng quan tâm đến chi tiết của chúng.

public class Bicycle {
        
    // the Bicycle class has
    // three fields
    public int cadence;
    public int gear;
    public int speed;
        
    // the Bicycle class has
    // one constructor
    public Bicycle(int startCadence, int startSpeed, int startGear) {
        gear = startGear;
        cadence = startCadence;
        speed = startSpeed;
    }
        
    // the Bicycle class has
    // four methods
    public void setCadence(int newValue) {
        cadence = newValue;
    }
        
    public void setGear(int newValue) {
        gear = newValue;
    }
        
    public void applyBrake(int decrement) {
        speed -= decrement;
    }
        
    public void speedUp(int increment) {
        speed += increment;
    }
        
}

Một khai báo lớp cho lớp MountainBike là lớp con của lớp Bicycle, có thể thấy như sau:

public class MountainBike extends Bicycle {
        
    // the MountainBike subclass has
    // one field
    public int seatHeight;
 
    // the MountainBike subclass has
    // one constructor
    public MountainBike(int startHeight, int startCadence,
                        int startSpeed, int startGear) {
        super(startCadence, startSpeed, startGear);
        seatHeight = startHeight;
    }   
        
    // the MountainBike subclass has
    // one method
    public void setHeight(int newValue) {
        seatHeight = newValue;
    }   
}

MountainBike kế thừa tất cả các thuộc tính và các phương thức của Bicycle và thêm trường seatHeight và một phương thức thiết lập nó (xe đạp leo núi có chỗ ngooif có thể di chuyển lên và xuống phụ thuộc vào địa hình).

Khai báo lớp (Declaring Classes)

Cú pháp khai báo lớp:

class MyClass {
    // field, constructor, and 
    // method declarations
}

Trong cú pháp khai báo, thân lớp (vùng nằm giữa 2 dấu ngoặc nhọn) bao gồm tất cả mã nguồn cung cấp cho vòng đời (life cycle) của các đối tượng được tạo ra từ lớp này: các phương thức khởi dựng (constructor) để khời gán cho các đối tượng mới, khai báo các trường (field) cung cấp trạng thái cho lớp và các đối tượng (objects) và các phương thức thực thi hành vi của lớp và các đối tượng.

Cách khai báo trước là cách khai báo lớp một cách tối thiểu. Nó chỉ bao gồm thành phần của một lớp được khai báo được yêu cầu. Bạn có thể cung cấp nhiều thông tin hơn về lớp, như tên của lớp cha (superclass), hay khai là lớp thực thi bất kỳ một interface nào đó ở vị trí bắt đầu khai báo lớp, ví dụ như sau:

class MyClass extends MySuperClass implements YourInterface {
    // field, constructor, and
    // method declarations
}

Nghĩa là  lớp MyClass là lớp con của lớp MysuperClass và thực thi interface YourInterface.

Bạn costheer thêm phạm vi tác động như public hoặc private ở đầu, do vậy bạn có thể thấy khi mở dòng đầu tiên của khai báo lớp đã trở lên khá phức tạp. Các phạm vi như public và private quyết định các lớp khác có thể truy cập vào MyClass hay không, được bàn ở sau trong mục này. Bài học về interface và kế thừa sẽ giải thích làm thế nào và tại sao bạn sử dụng từ khóa extendsimplements trong khai báo một lớp. Bây giờ bạn không cần quan tâm lo lắng về các yếu tố này.

Nói chung, khai báo lớp có thể bao gồm các thành phần thứ tự như sau:

·        Các từ bổ nghĩa như public, private và một số phần khác mà bạn sẽ gặp phải sau này (Tuy nhiên, ghi nhớ rằng từ private có thể áp dụng trong lớp lồng.)

·        Tên lớp với ký tự bắt đầu tuân theo quy ước định danh.

·        Tên lớp cha (superclass) bất kỳ nào đều phải được theo trước đó là từ khóa extend cho một cha.

·        Danh sách các interface được thực thi bởi lớp phải cách nhau bởi dấu phẩy và phí trước có từ khóa implements. Một lớp có thể thực thi một hoặc nhiều interface.

·        Thân lớp được bao bọc bởi dấu đóng mở ngoặc nhọn {}.

Khai báo các thành viên thuộc tính (Declaring Member Variables)

Cú pháp khai báo:

Có một vài loại biến sau:

·        Các biến thành viên của một lớp được gọi là các trường (thuộc tính).

·        Các biến của một phương thức hoặc một khối mã nguồn được gọi là các biến cục bộ.

·        Các biến trong khai báo phương thức được gọi là các tham số.

Trong lớp Bicycle sử dụng các dòng code định nghĩa các trường:

public int cadence;
public int gear;
public int speed;

 Khai báo trường (thuộc tính) bao gồm ba thành phần, thứ tự như sau:

1.      Không hoặc có bổ ngữ phạm vi như public hoặc private.

2.      Kiểu của thuộc tính.

3.      Tên thuộc tính.

Các trường trong lớp Bicycle được đặt tên cadencegearspeed  tất cả đều có kiểu dữ liệu số (int). Từ khóa public xác định các thuộc tính là các thành viên công khai, được truy cập từ bất kỳ đối tượng nào có thể truy cập vào lớp.

Phạm vi truy cập (Access Modifiers)

Đầu tiên (ngoài cùng bên trái) cho phép bạn kiểm soát được việc truy cập vào một thành viên của lớp. Trong ví dụ này, chỉ có publicprivate.  Các bổ ngữ quy định truy cập chúng ta sẽ bàn sau.

·        Bổ ngữ public - thuộc tính được truy cập ở tất cả các lớp.

·        Bổ ngữ private – thuộc tính chỉ được truy cập bên trong lớp sở hữu thuộc tính đó.

Dựa trên tinh thần đóng gói thì phổ biến tạo ra các thuộc tính private. Điều này nghĩa là  chúng chỉ có thể được truy cập trực tiếp từ lớp Bicycle. Tuy nhiên, chúng ta vẫn cần truy cập các giá trị đó. Ở đây có thể truy cập gián tiếp bằng cách thêm vào phương thức công khai vẫn lấy được các giá trị thuộc tính cho chúng ta.

public class Bicycle {
        
    private int cadence;
    private int gear;
    private int speed;
        
    public Bicycle(int startCadence, int startSpeed, int startGear) {
        gear = startGear;
        cadence = startCadence;
        speed = startSpeed;
    }
        
    public int getCadence() {
        return cadence;
    }
        
    public void setCadence(int newValue) {
        cadence = newValue;
    }
        
    public int getGear() {
        return gear;
    }
        
    public void setGear(int newValue) {
        gear = newValue;
    }
        
    public int getSpeed() {
        return speed;
    }
        
    public void applyBrake(int decrement) {
        speed -= decrement;
    }
        
    public void speedUp(int increment) {
        speed += increment;
    }
}

Kiểu dữ liệu

Tất cả các biến phải có một kiểu dữ liệu nào đó. Bạn cần sử dụng các kiểu dữ liệu nguyên thủy như int, float, boolean, vân vân. Hoặc bạn có thể sử dụng các kiểu dữ liệu tham chiếu, như kiểu chuỗi (strings), kiểu mảng (array) hoặc các đối tượng.

Các tên thuộc tính.

Tất cả các biến, chúng được gọi là các thuộc tính, biến cục bộ, hoặc các tham số, đều theo quy tắc định danh trong phần cú pháp lập trình cơ bản đã giới thiệu.

Trong phần này, tương tự với quy tắc trên cho sử dụng cho tên phương thức và tên lớp, ngoại trừ:

·        ký tự đầu của lớp nên viết hoa và

·        từ đầu tiên (hoặc duy nhất) của phương thức nên là một động từ.

Định nghia các phương thức (Defining Methods)

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

Ở đây có một ví dụ khai báo phương thức điển hình:

public double calculateAnswer(double wingSpan, int numberOfEngines,
                              double length, double grossTons) {
    //do the calculation here
}

Chỉ yêu cầu các thành phần khai báo của phương thức là: Kiểu trả về, tên phương thức, cặp ngoặc đơn, và thân phương thức nằm giữa cặp dấu đóng mở ngoặc nhọn {}.

Khái quát hơn, khai báo phương thức có sáu thành phần theo thứ tự sau:

1.      Bổ ngữ - như public, private và các bổ ngữ khác, bạn sẽ học sau.

2.      Kiểu dữ liệu trả về - kiểu dữ liệu của giá trị trả về bởi phương thức hoặc void nếu là phương thức không trả về giá trị.

3.      Tên phương thức – áp dụng theo quy tắc đặt tên nhưng có một chút khác.

4.      Danh sách tham số trong dấu ngoặc tròn, các tham số đầu vào cách nhau bởi dấu phẩy, trước mỗi tham số là kiểu dữ liệu của phương thức, kết thúc danh sách này là dấu đóng ngoặc tròn. Nếu không có tham số thì phải có dấu đóng mở ngoặc tròn và bên trong bỏ trống.

5.      Một danh sách ngoại lệ - sẽ được bàn sau.

6.      Thân phương thức được bao quanh bởi một cặp mở / đóng ngoặc nhọn, ở đó bao gồm khai báo biến cục bộ, và toàn bộ mã nguồn của phương thức.

Các bổ ngữ, các kiểu dữ liệu trả về và các tham số sẽ được bàn sau. Ngoại lệ cũng sẽ được bàn sau.

Chú ý: Hai thành phần khai báo của một phương thức được gọi là chữ ký phương thức – bao gồm tên phương thức và các kiểu tham số. Ví dụ chữ ký phương thức được khai báo như dưới đây:

calculateAnswer(double, int, double, double)

Tên của phương thức.

Mặc dù tên phương thức có thể là bất kỳ định danh hợp pháp nào, quy tắc mã nguồn hạn chế tên phương thức. Bởi quy ước, tên phương thức nên là một động từ viết thường hoặc gồm tổ hợp từ mà từ đầu tiên của tên phải là động từ được viết thường toàn bộ chữ cái. Theo sau từ đó là một tính từ, danh từ vân vân. Trong các tên tổ hợp từ, chữ cái đầu tiên của các từ thứ 2 trở đi viết hoa. Ví dụ:

run
runFast
getBackground
getFinalData
compareTo
setX
isEmpty

Một cách điển hình, một phương thức có duy nhất một tên trong một lớp (class). Tuy nhiên, một phương thức có thể có tên giống với tên của phương thức khác như các phương thức nạp chồng (method overloading).

Các phương thức nạp chồng.

Ngôn ngữ lập trình Java hỗ trợ các phương thức nạp chồng (method overloading), và Java có thể phân biệt được giữa các phương thức khác nhau thông qua chữ ký phương thức (method signatures). Điều này nghĩa là các phương thức trong một lớp có thể có cùng tên nếu các danh sách tham số khác nhau (là một vài “chứng nhận” sẽ được bàn trong “Giao diện lập trình và kế thừa”).

Có thể hình dung như sau, bạn có một lớp có thể sử dụng nhiều thư pháp để vẽ nhiều kiểu dữ liệu (chuỗi, số, và nhiều kiểu khác) và bao gồm một phương thức cho mỗi kiều dữ liệu. Nó sẽ rất cồng kềnh cho việc sử dụng các tên mới cho mỗi phương thức ví dụ drawStringdrawIntegerdrawFloat và nhiều phương thức khác. Trong ngôn ngữ lập trình Java, bạn có thể sử dụng tên giống nhau cho tất cả các phương thức vẽ nhưng khác nhau ở tham số truyền vào cho mỗi phương thức. Như vậy, lớp vẽ dữ liệu có thể khai báo bốn phương thức draw, mỗi phương thức phân biệt bằng danh sách tham số.

public class DataArtist {
    ...
    public void draw(String s) {
        ...
    }
    public void draw(int i) {
        ...
    }
    public void draw(double f) {
        ...
    }
    public void draw(int i, double f) {
        ...
    }
}

Các phương thức nạp chồng khác nhau bởi số tham số, kiểu tham số truyền vào trong phương thức. Trong ví dụ này draw(String s)draw(int i) là các phương thức riêng biệt và duy nhất bởi vì chúng yêu cầu kiểu dữ liệu tham số khác nhau.

Bạn không thể khai báo nhiều hơn một phương thức cùng tên và cùng số tham số, cùng kiểu tham số bởi trình biên dịch không thể phân biệt được chúng riêng biệt.

Trình biên dịch không coi kiểu dữ liệu trả về khi xét các phương thức khác nhau, do vậy bạn không thể khai báo hai phương thức cùng tên, cùng chữ ký và chúng chỉ khác nhau kiểu trả về.

Ghi nhớ: Các phương thức nạp chồng có thể làm cho bạn tiết kiệm việc viết mã nguồn hơn.

Cung cấp các phương thức khởi dựng (Contructors) cho lớp.

Một lớp bao gồm các phương thức khởi dựng (contructor) được gọi để tạo ra các đối tượng từ các lớp sử dụng chúng (blueprint). Khai báo các phương thức khởi dựng (Contructor) giống như khai báo các phương thức khác ngoại trừ tên phương thức chính là tên lớp và không có kiểu dữ liệu trả về. Ví dụ trong lớp Bicycle có phương thức khởi dựng:

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

Tạo ra một đối tượng thuộc lớp Bicycle có tên là myBike, gọi một phương thức khởi dựng bởi toán tử new:

Bicycle myBike = new Bicycle(30, 0, 8);

new Bicycle(30, 0, 8) tạo một không gian bộ nhớ cho đối tượng và khởi gán các giá trị ban đầu cho các thuộc tính.

public Bicycle() {
    gear = 1;
    cadence = 10;
    speed = 0;
}
Bicycle yourBike = new Bicycle();

Gọi phương thức khởi dựng không tham số tạo ra một đối tượng Bicycle có tên là yourBike.

Tất cả các phương thức khởi dựng đều được khai báo trong lớp Bicycle bởi vì chúng khác nhau về các danh sách tham số. Giống như phương thức, các phương thức khởi dựng trong nền tảng Java phân biệt nhau bởi các yếu tố cơ bản như số lượng tham số trong danh sách tham số  và kiểu của chúng. Bạn không thể viết hai phương thức khởi dựng (contructors) có số và kiểu tham số giống nhau, bởi vì nền tảng này không thể hiểu các thành phần này. Và sẽ bị lỗi biên dịch.

Bạn không phải cung cấp bất kỳ phương thức khởi dựng nào cho lớp của bạn, nhưng phải cẩn thận khi dùng lớp này. Trình biên dịch tự động cung cấp phương thức khởi dựng mặc định không tham số cho bất kỳ lớp nào không khai báo phương thức khởi dựng. Phương thức khởi dựng mặc định này sẽ được gọi là phương thức khởi dựng không tham số cho lớp cha (superclass) của nó. Trong tình huống mà trình biên dịch không tìm thấy phương thức khởi dựng không tham số của lớp cha thì bạn phải xác nhận. Nếu lớp của bạn không có lớp cha rõ ràng nào thì một nó sử lớp cha của lớp Object có hàm khởi dựng không tham số.

Bạn có thể sử dụng một phương thức khởi dựng mặc định của lớp cha cho lớp của bạn. Lớp MountainBike bắt đầu học trong phần này đã sử dụng nó. Sẽ bàn sâu hơn ở phần giao diện lập trình và kế thừa sau này.

Bạn có thể sử dụng bổ ngữ truy cập trong khai báo phương thức khởi dựng để kiểm soát các lớp khác có thể gọi phương thức khởi dựng.

Ghi nhớ: Nếu lớp khác không gọi được một phương thức khởi dựng trong lớp MyClass, nó không thể tạo trực tiếp các đối tượng MyClass.

Truyền giá trị tham số cho phương thức hoặc hàm khởi dựng.

Khái niệm về truyền giá trị.

Khai báo một phương thức hoặc hàm khởi tạo/ khởi dựng (contructor) khai báo số lượng và kiểu dữ liệu của các đối số cho phương thức hoặc hàm khởi dựng. Ví dụ, khai báo một phương thức tính toán tiền phải trả hàng tháng khi vay tiền mua nhà, dựa trên số tiền vay và lãi suất, thời hạn vay (một giai đoạn nào đó), và giá trị vay trong tương lai.

public double computePayment(
                  double loanAmt,
                  double rate,
                  double futureValue,
                  int numPeriods) {
    double interest = rate / 100.0;
    double partial1 = Math.pow((1 + interest),
                      - numPeriods);
    double denominator = (1 - partial1) / interest;
    double answer = (-loanAmt / denominator)
                    - ((futureValue * partial1) / denominator);
    return answer;
}

Ghi nhớ: Các tham số (Parameters) tham chiếu là một danh sách biến trong khai báo phương thức. Các đối số (Arguments) là các giá trị thật được truyền vào khi gọi phương thức. Khi bạn gọi một phương thức, các đối số phải được khớp với các tham số khai báo cả về kiểu và thứ tự.Phương thức này có bốn tham số: số tiền vay (loanAmt), lãi suất (rate), giá trị tương lai (futureValue) và giai đoạn vay (numPeriods). Ba tham số đầu tiên có kiểu double, tham số thứ bốn có kiểu số int. Các tham số được sử dụng trong thân phương thức và sẽ chạy với các giá trị truyền vào cho các tham số.

Các kiểu tham số.

Bạn có thể sử dụng bất kỳ kiểu dữ liệu nào cho một tham số của một phương thức hay hàm khởi tạo (phương thức khởi dựng). Bao gồm các kiểu dữ liệu nguyên thủy, như double, float, int giống như bạn nhìn thấy trong phương thức computePayment trong ví dụ trên, và các kiểu dữ liệu tham chiếu giống như các đối tượng và các mảng.

Ở đây có một ví dụ về một phương thức chấp nhận một mảng như một đối số. Trong ví dụ này, phương thức tạo đối tượng mới Polygon khởi gán một mảng đối tượng Point (Point là một lớp có hai tọa độ đại diện là x, y).

public Polygon polygonFrom(Point[] corners) {
    // method body goes here
}

Số lượng đối số tùy ý - .Ghi nhớ: Nếu bạn muốn truyền một phương thức vào một phương thức thì sử dụng biểu thức lambda hoặc tham chiếu phương thức sẽ được bàn ở phần lớp lồng trong chương này.

Bạn có thể xây dựng phương thức theo một cách được gọi là kỳ đà (varargs) để truyền vào bất kỳ số nào cho giá trị của một phương thức. Bạn sử dụng kỳ đà khi không biết bao nhiêu kiểu của đối dố sẽ truyền vào cho phương thức. Một đường tắt được tạo ra cho mảng thực (phương thức trước đó có thể sử dụng kỳ đà hơn là dùng mảng).

Để sử dụng kỳ đà, bạn sử dụng các kiểu của tham số cuối bằng dấu chấm lửng (ba chấm, …), sau đó là dấu cách, và tên tham số. Phương thức có thể được gọi với bất kỳ số lượng tham số nào bao gồm cả không cần tham số.

public Polygon polygonFrom(Point... corners) {
    int numberOfSides = corners.length;
    double squareOfSide1, lengthOfSide1;
    squareOfSide1 = (corners[1].x - corners[0].x)
                     * (corners[1].x - corners[0].x) 
                     + (corners[1].y - corners[0].y)
                     * (corners[1].y - corners[0].y);
    lengthOfSide1 = Math.sqrt(squareOfSide1);
 
    // more method body code follows that creates and returns a 
    // polygon connecting the Points
}

Bạn thường sẽ sử dụng phương pháp kỳ đà với các phương thức in, ví dụ phương thức printf sau:Bạn có thể thấy rằng, bên trong phương thức, corners được coi như là một mảng. Phương thức này có thể được gọi với một mảng hoặc một thứ tự các đối số. Mã nguồn trong thân phương thức sẽ coi tham số như là một mảng trong trường hợp này.

public PrintStream printf(String format, Object... args)

Cho phép bạn in bao nhiêu đối tượng cũng được. Nó có thể được gọi như:

System.out.printf("%s: %d, %s%n", name, idnum, address);

Hoặc được gọi như:

System.out.printf("%s: %d, %s, %s, %s%n", name, idnum, address, phone, email);

Hoặc gọi phương thức với không đối số.

Các tên tham số.

Khi bạn khai báo tham số cho phương thức hoặc hàm tạo, bạn cung cấp một cái tên cho tham số. Tên này được sử dụng trong thân phương thức và tham chiếu để truyền đối số.

Tên của tham số phải là duy nhất trong một phạm vi. Nó không thể giống với tên của một tham số khác ở cùng một phương thức hoặc hàm tạo, và không thể cùng tên với một biến cục bộ trong phương thức hoặc hàm tạo.

Một tham số có thể giống một thuộc tính của lớp. Nếu trong trường hợp, tham số được gọi là ánh xạ (shadows) của thuộc tính. Các ánh xạ của trường có thể được tạo trong mã nguồn của bạn sẽ khó đọc và được quy ước sử dụng chỉ với các hàm khởi tạo và các phương thức thiết lập cho thuộc tính. Ví dụ, trong lớp Circle có phương thức thiết lập setOrigin.

public class Circle {
    private int x, y, radius;
    public void setOrigin(int x, int y) {
        ...
    }
}

Truyền các đối số có kiểu dữ liệu nguyên thủy.Lớp Circle có ba thuộc tính: x, y và radius. Phương thức setOrigin có hai tham số, mỗi tham số có tên giống với một trong các thuộc tính. Mỗi tham số là ánh xạ (shadows) của thuộc tính tương ứng cùng tên. Cũng sử dụng tên x hoặc y trong thân phương thức tham số tham chiếu, không phải thuộc tính. Truy cập vào các thuộc tính, bạn phải sử dụng một tên chuẩn. Sẽ bàn sau trong phần này.

Các đối số nguyên thủy, như một số kiểu int hoặc double, được truyền qua giá trị của phương thức. Điều này có nghĩa là bất kỳ thay đổi nào với các giá trị cho các tham số chỉ  tồn tại trong phạm vi phương thức. Khi trả phương thức trả về, các tham số sẽ biến mất và bất kỳ thay đổi nào của chúng cũng biến mất. Ví dụ:

public class PassPrimitiveByValue {
 
    public static void main(String[] args) {
           
        int x = 3;
           
        // invoke passMethod() with 
        // x as argument
        passMethod(x);
           
        // print x to see if its 
        // value has changed
        System.out.println("After invoking passMethod, x = " + x);
           
    }
        
    // change parameter in passMethod()
    public static void passMethod(int p) {
        p = 10;
    }
}

Khi chạy chương trình này, kết quả trả về:

After invoking passMethod, x = 3

Các tham số kiểu dữ liệu tham chiếu, giống như các đối tượng, là cũng truyền vào các phương thức bằng giá trị. Điều  này có nghĩa là khi trả về các giá trị, các các tham chiếu truyền vào vẫn tham chiếu đến các đối tượng trước đó. Tuy nhiên, các giá trị của các thuộc tính đối tượng có thể được thay đổi trong phương thức, nếu chúng truy cập ở mức độ phù hợp.Truyền các đối số kiểu dữ liệu tham chiếu (Passing Reference Data Type Arguments).

Trong ví dụ, xem xét phương thức bất kỳ trong lớp Circle chuyển đổi các đối tượng Circle:

public void moveCircle(Circle circle, int deltaX, int deltaY) {
    // code to move origin of circle to x+deltaX, y+deltaY
    circle.setX(circle.getX() + deltaX);
    circle.setY(circle.getY() + deltaY);
        
    // code to assign a new reference to circle
    circle = new Circle(0, 0);
}

Hãy gọi phương thức với các đối số như sau:

moveCircle(myCircle, 23, 56)

Bên trong phương thức, cicrle ban đầu tham chiếu đến myCircle. Phương thức thay đổi tọa độ x và tọa độ y của circle mà nó tham chiếu đến (đó là myCircle) với 23 và 56 tương ứng. Sự thay đổi sẽ vẫn tồn tại khi hàm trả về giá trị. Sau đó circle được gán một tham chiếu đối tượng Circle mới với x=y=0. Sự gán lại này không lâu dài, bởi vì tham chiếu đã truyền vào bằng giá trị không thể thay đổi. Bên trong phương thức, thuộc tính điểm của đối tượng circle đã thay đổi, tuy nhiên, khi phương thức trả về giá trị myCircle vẫn tham chiếu đến đối tượng Circle đó như trước khi phương thức được gọi.


[Tự học lập trình Java] hướng dẫn cài đặt Netbean IDE

 



  • Java Standard Edition (Java SE) – Là nền tảng cơ bản cho phép phát triển giao diện điều khiển, các ứng dụng mạng và các ứng dụng dạng Win Form.
  • Java Enterprise Edition (Java EE) – Được xây dựng trên nền tảng Java SE, giúp phát triển các ứng dụng web, các ứng dụng ở cấp doanh nghiệp, …
  • Java Mobile Edition (Java ME) – Là nền tảng cho phép phát triển các ứng dụng nhúng vào các thiết bị điện tử như mobile,…

Phiên bản Java SE gồm có 2 thành phần:

  • JRE (Java Runtime Environment): cung cấp JVM (Java Virtual Machine) và thư viện được sử dụng để chạy chương trình Java.
  • JDK (Java Development Kit): được biết đến như bộ cung cụ phát triển Java, bao gồm: trình biên dịch và trình gỡ rối được sử dụng để phát triển các ứng dụng Java.

NetBeans IDE là gì?

  • NetBeans IDE là một công cụ hỗ trợ lập trình viết mã code miễn phí được cho là tốt nhất hiện nay, được sử dụng chủ yếu cho các lập trình viên phát triển Java, tuy nhiên. phần mềm này có dung lượng khá “nặng” dành cho các máy cấu hình có RAM, CPU tương đối cao để vận hành.
  • NetBeans IDE là môi trường phát triển tích hợp và cực kỳ cần thiết cho các lập trình viên, công cụ này có thể hoạt động tốt với rất nhiều nền tảng hệ điều hành khác nhau như Linux, Windows, MacOS,…Đồng thời là một mã nguồn mở cung cấp các tính năng cần thiết nhất để tạo ra các ứng dụng web, thiết bị di động, desktop.
  • NetBeans IDE cũng hỗ trợ rất nhiều những ngôn ngữ lập trình như Python, Ruby, JavaScript, Groovy, C/C++ và PHP.
  • Để có thể cài đặt được NetBeans IDE các bạn phải cài đặt và cấu hình sẵn JDK trong máy thì mới có thể tiến hành cài đặt. Đáng chú ý, NetBeans IDE được chia thành nhiều gói khác nhau để người dùng có thể tải về từng phần, tiết kiệm dung lượng, tùy theo nhu cầu của mình.

Hướng dẫn cài đặt NetBeans

  1. Tải về Java SE Development Kit (JDK)

Bước 1: Chọn phiên bản JDK cần sử dụng tại đây.

 

Bước 2: Lựa chọn phiên bản phù hợp với hệ điều hành (trong hướng dẫn này sẽ download phiên bản dành cho Window X64).

2. Tải về bộ cài đặt NetBeans IDE

Link download: NetBeans 12.3

Bước 1:

Bước 2:

Bước 3:

Bước 4:

Sau khi tải về 2 bộ cài đặt JDK và NetBeans IDE, chúng ta sẽ tiến hành cài đặt JDK trước và cài đặt NetBeans IDE sau đó.

Tiến hành cài đặt

  1. Cài đặt Java SE Development Kit (JDK)

Bước 1: Chạy file JDK đã tải phía trên – Chọn Yes

Bước 2: Chọn Next

Bước 3: Chọn Next

Bước 4: Chọn Close

2. Cài đặt NetBeans

Bước 1: Chạy file NetBeans IDE đã tải phía trên – Chọn Yes

Bước 2: Chọn Next

Bước 3: Tích Accept, sau đó chọn Next

Bước 4: Chọn Browse để chỉnh lại đường dẫn cài đặt nếu cần thiết, sau đó chọn Next

Bước 5: Chọn Install

Bước 6: Chọn Finish để kết thúc cài đặt

Sau khi cài đặt thành công, trên màn hình sẽ xuất hiện Shortcut của Apach NetBeans IDE.

Thiết lập biến môi trường

Bước 1: Trên màn hình Desktop, click chuột phải vào Computer (This PC) sau đó chọn Properties.

Bước 2: Chọn Advanced system settings

Bước 3: Chọn Environment Variables

Bước 4: Trong System Variables, chọn “New…”

Bước 5: Trong hộp thoại New System Variable, điền thông tin như sau:


Variable name: JAVA_HOME
Variable value: C:\Program Files\Java\jdk-11.0.11 (điền đường dẫn thư mục đặt JDK)
Sau đó, click “OK” để hoàn tất việc đặt tên biến môi trường

Bước 6: Sửa đổi biến môi trường Path: Trong phần System Variable, ta sửa biến môi trường Path: Click đúp chuột vào dòng “Path”

Bước 7: Click “New” và điền %JAVA_HOME%\bin

Hướng dẫn sử dụng NetBeans IDE

Bước 1: Trên màn hình Desktop, click đúp vào Shortcut Apach NetBeans 12.3

Bước 2: Tạo dự án mới, chọn File/New Project (Ctrl + Shift + N)

Bước 3: Chọn Java with Ant/ Java Application/ Next

Bước 4: Sửa lại tên dự án (Project Name) và chọn vị trí lưu dự án (Browse phần Project Location), sau đó chọn “Finish”.

Bước 5: Kết quả

Đến đây, chúng ta đã hoàn thành cài đặt NetBeans IDE – Công cụ hỗ trợ viết mã code miễn phí được xem là tốt nhất hiện nay, được sử dụng chủ yếu đối với các lập trình viên Java.

Bài đăng phổ biến

Bài viết mới nhất

Tin học cơ bản - Nền tảng của mọi kỹ năng

Mọi thông tin trên blog đều được giữ bản quyền bởi Tin học cơ bản. Các bạn nếu muốn lấy thông tin từ blog vui lòng ghi rõ nguồn Tinhoccoban.net

TIN HỌC CƠ BẢN