Mục lục bài họcĐang ở d03-b2
← AP Computer Science A
0/16 bài đã học xong
Chương 3 · Unit 3 — Class Creation · Bài 2/4 của chương · bài 10/16 của AP Computer Science A

Accessors, Mutators, and the static Keyword

Phương thức truy xuất, phương thức thay đổi, và từ khoá static
← Mục lục bài học
Lý thuyết · English

The only doors into a private object

An accessor (getter) returns a copy of some state and changes nothing: public int getCopies() { return copies; }. A mutator (setter) changes state and normally returns void. The reason a mutator beats a public field is that a mutator can refuse: it validates before it writes, so the object can never enter an impossible state.

A local variable declared inside a method exists only until the method returns, and it is not given a default value — using it before assignment is a compile-time error. An instance variable, by contrast, is initialised to the zero value of its type and lives as long as the object does.

static: one copy for the whole class

A static variable belongs to the class, not to any object: every object shares the same single copy, so a counter incremented in a constructor records how many objects have ever been made. A static method is called on the class — Widget.getMade() — and therefore has no this. That single fact explains the whole rule: a static method cannot read an instance variable or call an instance method directly, because there is no particular object to read from.

The reverse direction is always legal: an instance method may freely use static variables and static methods, since the one shared copy exists no matter which object is asking.

Giải thích tiếng Việt

Cửa duy nhất đi vào một đối tượng riêng tư

Phương thức truy xuất (accessor, getter) trả về giá trị của một trường và không đổi gì: public int getCopies() { return copies; }. Phương thức thay đổi (mutator, setter) ghi vào trường và thường trả về void. Lý do mutator hơn hẳn một trường public là mutator có quyền từ chối: nó kiểm tra trước khi ghi, nên đối tượng không bao giờ rơi vào trạng thái vô nghĩa.

Biến cục bộ khai trong thân phương thức chỉ sống tới lúc phương thức kết thúc, và không được gán giá trị mặc định — dùng khi chưa gán là lỗi biên dịch. Ngược lại, biến thực thể được khởi tạo về giá trị không của kiểu và sống cùng đối tượng.

static: một bản dùng chung cho cả lớp

Biến static thuộc về lớp chứ không thuộc đối tượng nào: mọi đối tượng dùng chung đúng một bản, nên một biến đếm tăng trong hàm khởi tạo sẽ ghi lại tổng số đối tượng đã từng được tạo. Phương thức static gọi qua tên lớp — Widget.getMade() — và vì thế không có this. Chỉ một sự thật đó giải thích trọn luật: phương thức static không đọc được biến thực thể và không gọi thẳng được phương thức thực thể, vì không có đối tượng cụ thể nào để đọc.

Chiều ngược lại thì luôn hợp lệ: phương thức thực thể dùng thoải mái biến static và phương thức static, vì bản dùng chung đó tồn tại bất kể đối tượng nào đang hỏi.

w1 id = 1 w2 id = 2 biến thực thể biến thực thể lớp Widget static made = 2 chỉ MỘT bản cả hai đối tượng cùng tăng một biến đếm w1.id và w2.id khác nhau · Widget.made thì không sau hai lần new Widget()
Đọc hình theo một câu. Vẽ hai hộp đối tượng và một hộp lớp. Mỗi biến thực thể được vẽ lại trong từng hộp đối tượng; mỗi biến static chỉ được vẽ đúng một lần, ở hộp lớp. Mọi câu hỏi kiểu giá trị in ra là bao nhiêu trong chương này đều giải xong khi bạn vẽ đúng cái hình này — biến nào nhân bản, biến nào dùng chung.
Ví dụ — mutator biết từ chối, và biến đếm static

Bổ sung cho lớp Book: một biến static đếm số đối tượng đã tạo, một accessor static đọc nó, và một mutator setCopies chỉ chấp nhận số không âm. Cho biết sau ba lần new và một lần setCopies(-5) thì trạng thái ra sao.

Giải.
public class Book {
    private String title;
    private int copies;
    private static int made = 0;

    public Book(String title, int copies) {
        this.title = title;
        this.copies = copies;
        made++;
    }

    public static int getMade() {
        return made;
    }

    public void setCopies(int n) {
        if (n >= 0) {
            copies = n;
        }
    }

    public int getCopies() {
        return copies;
    }
}

Sau ba lần new Book(...), biến made bằng 3 — không phải mỗi đối tượng một số 1, vì chỉ có một bản dùng chung được ba hàm khởi tạo lần lượt tăng.

Lời gọi b.setCopies(-5) không ném ngoại lệ và cũng không ghi gì: điều kiện n >= 0 sai nên thân if bị bỏ qua, copies giữ nguyên giá trị cũ. Đó chính là quyền từ chối mà một trường public không bao giờ có.

Chú ý getMade()static nên trong thân nó không được đụng tới title hay copies; nó chỉ đọc được made.

Bẫy hay mất điểm — Bẫy số một: đặt biến đếm là biến thực thể thay vì static, rồi ngạc nhiên vì đối tượng nào cũng báo đếm bằng 1. Bẫy số hai, ngược lại: để một dữ liệu riêng của từng đối tượng thành static, khiến đối tượng tạo sau ghi đè giá trị của đối tượng tạo trước. Cách chặn: trước khi gõ static, hỏi đúng một câu — nếu tôi tạo đối tượng thứ hai, giá trị này có phải nhân đôi không? Có thì bỏ static, không thì giữ.
Phải nhớ — Accessor đọc, mutator ghi có kiểm tra. static thuộc lớp và chỉ có một bản; phương thức static không có this nên không chạm được biến thực thể, còn phương thức thực thể thì chạm được biến static bất cứ lúc nào.

Đọc xong rồi — làm thử ngay

Bài tập của chương Unit 3 — Class Creation gồm 14 câu trắc nghiệm và 8 đề tự luận. Đáp án hiện ngay khi chọn, miễn phí.

Làm bài tập chương →