AP Computer Science A · 鼎睿学苑

Unit 3: Class Creation

单元 3:类的定义

Design your own classes with instance variables, constructors, methods, encapsulation, static members, scope, and the this keyword.

自行设计类,掌握实例变量、构造方法、方法、封装、静态成员、作用域以及 this 关键字。

10–18% of AP Exam 占 AP 考试 10–18% ~20–22 Class Periods 约 20–22 课时 9 Topics 9 个小节

Abstraction and Program Design

抽象与程序设计

Abstraction reduces complexity by focusing on the main idea while hiding irrelevant details.

抽象(abstraction通过聚焦主要思想、隐藏无关细节来降低复杂度。

Data Abstraction, separates what data represents from how it's stored. An instance variable like balance names the concept without exposing implementation.

数据抽象,将数据"代表什么"与"如何存储"分离开来。像 balance 这样的实例变量(instance variable)只为概念命名,而不暴露具体实现。

Procedural Abstraction, gives a name to a process (method). You use a method knowing what it does, not how. This enables code reuse and method decomposition.

过程抽象,为某个过程(方法)赋予名称。你只需知道方法做了什么,而不必关心如何做。这便于代码复用与方法分解。

Design First 先设计 Before coding, plan each class: identify its attributes (data/nouns) and behaviors (methods/verbs). This can be done with natural language, UML diagrams, or pseudocode. 编码前先为每个类(class)做规划:识别其属性(数据/名词)与行为(方法/动词)。可用自然语言、UML 图或伪代码来完成。
Key Vocabulary 关键词汇 An attribute is a variable defined in a class outside any method. An instance variable is unique to each object. A class variable is shared by all objects. 属性是在类中、任何方法之外定义的变量。实例变量每个对象(object)独有一份。类变量由所有对象共享。
Worked Example: Designing a Library class
例题:设计一个 Library

Problem. Sketch a class to model a public library that tracks books and members.

题目。勾画一个类,用于建模一个跟踪藏书与会员的公共图书馆。

Step 1. Identify nouns (attributes). A library "has" a name and a collection of books. A book has a title and an ISBN.

第 1 步:识别名词(属性)。一个图书馆"有"一个名称和一批藏书。一本书有标题和 ISBN。

Step 2. Identify verbs (behaviors). A library can add a book, check out a book to a member, return a book, list available books.

第 2 步:识别动词(行为)。图书馆可以添加一本书把书借给会员还书列出可借阅的书

Step 3. Decide what to expose. Public methods form the API (addBook, checkOut). Private helpers do internal work. Instance variables are always private.

第 3 步:决定对外暴露什么。公有方法构成 API(addBookcheckOut)。私有辅助方法负责内部工作。实例变量永远是 private

Step 4. Sketch the skeleton.

第 4 步:勾画骨架。

public class Library {
    private String name;
    private ArrayList<Book> books;

    public Library(String name) { /* ... *//* ... */ }
    public void addBook(Book b) { /* ... *//* ... */ }
    public boolean checkOut(String isbn) { /* ... *//* ... */ }
}
AP Trap: Attribute vs Method AP 陷阱:属性 vs 方法 On AP MCQs, "has-a" relationships indicate attributes (data); "can-do" or "does" indicate methods (behavior). A library has books (attribute); a library checks out books (method). Don't model behaviors as fields. 在 AP 选择题中,"有一个"(has-a)关系表示属性(数据);"能做"或"会做"则表示方法(行为)。图书馆书(属性);图书馆外借书(方法)。不要把行为建模为字段。

Impact of Program Design

程序设计的影响

Programs impact society, the economy, and culture, both positively and negatively. The AP exam tests this with 1–2 conceptual MCQs per year. Easy points if you've seen the framework once.

程序会对社会、经济和文化产生正面或负面的影响。AP 考试每年都会出 1–2 道概念性选择题。只要熟悉这个框架,就是稳拿分。

System Reliability, a program should perform as expected under all stated conditions, not just the happy path. Test with edge cases, invalid input, and boundary values to maximize reliability. A reliability gap is a failure for a stated condition.

系统可靠性,程序应当在所有规定条件下都按预期运行,而不仅仅是顺利路径。要用边界情况、非法输入和临界值来测试以最大化可靠性。可靠性缺口指的是在某个规定条件下出现失败。

Unintended Consequences, a program built for one purpose can cause harm outside its intended scope. A recommendation algorithm optimised for engagement can amplify misinformation; a routing app's optimum may cause traffic chaos on residential streets. The harm was not intended by the designer but emerged from the design.

意料之外的后果,为某种目的设计的程序可能在其预期范围之外造成危害。以"参与度"为目标优化的推荐算法可能放大错误信息;以最优路径为目标的导航 App 可能让住宅街道交通陷入混乱。这种危害并非设计者所期望,而是从设计中浮现出来。

Intellectual Property, code published as open source under a permissive license (MIT, Apache) can be reused with attribution. Code under a copyleft license (GPL) requires that derivatives also be open-sourced. Code with no license, or a proprietary license, requires explicit permission (and often payment) before reuse.

知识产权,以宽松许可证(MIT、Apache)开源发布的代码,只要署名即可复用。以 copyleft 许可证(GPL)发布的代码,要求衍生作品也必须开源。没有许可证的代码或专有许可证下的代码,则必须在获得明确许可(通常还要付费)后才能复用。

Plagiarism, copying another student's submitted code (even partially, even modified) without attribution is plagiarism, a serious academic-integrity violation. Cite the source of any code you didn't write yourself, including snippets adapted from documentation or online forums.

抄袭,未署名地复制其他同学提交的代码(哪怕只是部分、哪怕做过修改)就是抄袭,属于严重的学术诚信违规。任何并非你本人编写的代码都应标注出处,包括根据文档或在线论坛改编的代码片段。

Telling Unintended Consequence from Reliability 如何区分"意料之外的后果"与"可靠性" A subtle but exam-tested distinction. Reliability = the program fails to do what it was designed to do under some valid input. Unintended consequence = the program does exactly what it was designed to do, but that behavior causes harm in a way the designer did not anticipate. 这是一个细微但考点常考的区别。可靠性 = 程序在某些合法输入下没能完成设计要做的事。意料之外的后果 = 程序恰恰完成了设计要做的事,但这种行为以设计者未预见的方式造成了危害。
A weather-prediction app shows accurate forecasts 99% of the time but on rare extreme-weather days predicts mild conditions. Which best describes the issue?
一款天气预报 App 在 99% 的情况下都能准确预报,但在罕见的极端天气日却预报为温和天气。下列哪一项最贴切地描述了问题?
Intellectual property violation侵犯知识产权
Plagiarism抄袭
Lack of system reliability under edge-case inputs在边界输入下缺乏系统可靠性
Unintended consequence意料之外的后果
Correct! The app fails on a specific class of inputs (extreme weather). It's not behaving as designed under all stated conditions, that's a reliability gap. (Unintended consequence would be: the app works perfectly, but its accurate predictions cause panic-buying that harms grocery supply chains.)
正确!这个 App 在某一类特定输入(极端天气)下失败。它没有在所有规定条件下都按设计运行,这就是可靠性缺口。("意料之外的后果"会是:App 工作完全正常,但其准确预报引发抢购,破坏了食品供应链。)
"Reliability" = performs as expected under all conditions. A 99% success rate with a known failure mode on edge cases is a reliability issue. "Unintended consequence" means the program works as intended but causes side-effect harm.
"可靠性" = 在所有条件下都按预期运行。99% 的成功率、且在边界情形下存在已知失败模式,这属于可靠性问题。"意料之外的后果"指的是程序按设计运行,但引发副作用造成危害。

Anatomy of a Class

类的结构剖析

Encapsulation

封装

Data encapsulation hides implementation details from external classes using access modifiers.

数据封装(encapsulation利用访问修饰符(access modifier)把实现细节对外部类隐藏起来。

Keyword关键字Who Can Access谁可以访问Used For用途
publicAny class任何类Classes, constructors, methods that form the API类、构造方法(constructor)、构成 API 的方法
privateOnly the declaring class只有声明它的类Instance variables (best practice), helper methods实例变量(最佳实践)、辅助方法
AP CSA Rules AP CSA 规则 Classes → always public. Constructors → always public. Instance variables → always private (for encapsulation). 类 → 总是 public。构造方法 → 总是 public。实例变量(instance variable) → 总是 private(用于封装)。
public class Dog {
    // Instance variables, private!// 实例变量,私有!
    private String name;
    private int age;

    // Constructor, public// 构造方法,公有
    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // Public methods// 公有方法
    public String getName() { return name; }
    public int getAge() { return age; }
}
Worked Example: Translate an FRQ prompt to a class skeleton
例题:把 FRQ 题干翻译成类骨架

Problem. "Write a class Student with a name (String), grade (int 9–12), and methods to access each."

题目。"编写一个类 Student,包含 name(String)、grade(int 9–12),以及访问每个字段的方法。"

Step 1. Class declaration. Always public class.

第 1 步:类声明。总是写 public class

Step 2. Instance variables. Always private. Types come from the prompt: String name, int grade.

第 2 步:实例变量。总是 private。类型来自题干:String nameint grade

Step 3. Constructor. Public. Parameters match the data the prompt says the class needs. Use this. when the parameter shadows the field.

第 3 步:构造方法。public。形参与题干所述类所需的数据一致。当形参与字段同名时,使用 this.

Step 4. Accessors. One per private field. Return type matches the field type. Body is a single return.

第 4 步:访问器。每个私有字段一个。返回类型与字段类型一致。方法体只有一行 return

public class Student {
    private String name;
    private int grade;

    public Student(String name, int grade) {
        this.name = name;
        this.grade = grade;
    }

    public String getName() { return name; }
    public int getGrade() { return grade; }
}
AP Trap: Don't Forget public AP 陷阱:别忘了 public Omitting public on a method or constructor doesn't cause a Java compile error (it makes them package-private), but the AP rubric requires public on every constructor and every method intended to be called from outside the class. Always write public. Losing it is one of the most common Class Design FRQ mistakes. 在方法或构造方法上漏写 public 不会引起 Java 编译错误(它们会变成包私有),但 AP 评分标准要求每个构造方法以及每个打算从外部调用的方法都必须带 public永远写上 public。忘写 public 是 Class Design FRQ 最常见的失分点之一。

Constructors

构造方法

A constructor sets the initial state of an object by assigning values to all instance variables.

构造方法(constructor)通过给所有实例变量(instance variable)赋值来设定对象的初始状态

State = the object's attributes and their current values (has-a relationship).

状态 = 对象的属性及其当前值(has-a 关系)。

When a constructor is called with new, memory is allocated and an object reference is returned.

当用 new 调用构造方法时,内存被分配,并返回一个对象引用。

Mutable Object Parameters 可变对象形参 If a constructor receives a mutable object, store a copy, not the original reference. This prevents outside code from changing the object's internal state. 如果构造方法收到一个可变对象,应保存一份副本,而不是原始引用。这样可以防止外部代码改动对象的内部状态。

Default Constructor

默认构造方法

If you write no constructors, Java provides a default (no-argument) constructor that sets fields to default values:

如果你一个构造方法都没写,Java 会提供一个默认(无参)构造方法(default constructor,把各字段设为类型默认值:

Default Values, Must Know
默认值(必须掌握)
Type类型Default Value默认值
int0
double0.0
booleanfalse
Reference types引用类型null
If a class has no constructors and contains private boolean active;, what is active after new MyClass()?
如果一个类没有任何构造方法,并且包含 private boolean active;,那么 new MyClass() 之后 active 的值是?
true
null
false
Compile error编译错误
Correct! The default value of a boolean is false.
正确!boolean 的默认值是 false
The default value for boolean instance variables is false (not null, that's for reference types).
boolean 实例变量的默认值是 false(不是 nullnull 是引用类型的默认值)。

Overloaded Constructors

重载构造方法(overloaded constructor

A class can have multiple constructors with different parameter lists. The compiler picks the right one at the call site based on the arguments, this is method overloading.

一个类可以有多个构造方法,每个的形参列表不同。编译器会在调用处根据实参选择合适的那一个,这就是方法重载(overloading

public class Dog {
    private String name;
    private int age;

    // Full constructor// 完整构造方法
    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // Convenience constructor, defaults age to 0// 便利构造方法,age 默认为 0
    public Dog(String name) {
        this.name = name;
        this.age = 0;
    }
}

Dog a = new Dog("Rex", 5);  // uses 2-arg constructor// 使用 2 参构造方法
Dog b = new Dog("Buddy");     // uses 1-arg constructor// 使用 1 参构造方法
AP Trap: A "constructor" with a return type isn't a constructor AP 陷阱:带返回类型的"构造方法"不是构造方法 If you accidentally write public void Dog(String name) { ... } (with void), it's a method named "Dog", not a constructor. Java won't invoke it via new Dog("Rex"). Worse, since no real constructor was declared, the compiler auto-generates a default no-arg constructor, so new Dog() compiles but does nothing useful. Constructors have no return type. 如果你不小心写成 public void Dog(String name) { ... }(带 void),它就是一个名叫 "Dog" 的方法,而不是构造方法。Java 不会通过 new Dog("Rex") 来调用它。更糟的是,由于没有声明真正的构造方法,编译器会自动生成一个默认无参构造方法,于是 new Dog() 能通过编译,但什么有用的事都没做。构造方法没有返回类型。

Methods: How to Write Them

方法:如何编写

void vs Non-void Methods

void 方法 vs 非 void 方法

Type类型Returns返回Keyword关键字Example示例
voidvoidNothing不返回任何值voidpublic void bark()
Non-void非 voidA single value单个值Return type返回类型public int getAge()

Accessor vs Mutator

访问器 vs 修改器

Accessor (getter), returns a copy of an instance variable's value. Always non-void.

访问器(accessor / getter),返回某个实例变量(instance variable)值的副本。永远是非 void。

Mutator (setter), changes an instance variable's value. Usually void.

修改器(mutator / setter),修改某个实例变量的值。通常是 void。

// Accessor// 访问器
public String getName() {
    return name;
}

// Mutator// 修改器
public void setName(String newName) {
    name = newName;
}
return Exits Immediately return 立即退出 The return keyword sends control back to the caller. Any code after return in the same block is unreachable and will cause a compile error. A return inside a loop or if-statement exits the entire method. return 关键字会把控制权交回调用者。同一代码块中 return 之后的任何代码都不可达,会导致编译错误。位于循环或 if 语句中的 return 会退出整个方法。
Pass by Value (Primitives) 按值传递(pass by value,基本类型) When a primitive is passed as an argument, the parameter gets a copy of the value. Changing the parameter inside the method does not affect the original variable. 当基本类型作为实参传入时,形参拿到的是值的副本。在方法内部修改形参不会影响原变量。

Mutator with Input Validation

带输入校验的修改器

A robust mutator validates input before changing state. Reject obviously-bad values; preserve the object's invariants.

健壮的修改器会在改变状态之前先校验输入。拒绝明显非法的值,以维护对象的不变式。

public class BankAccount {
    private double balance;

    public void deposit(double amount) {
        if (amount > 0) {           // validate// 校验
            balance += amount;
        }
        // silently ignore non-positive deposits// 静默忽略非正存款
    }

    public boolean withdraw(double amount) {
        if (amount <= 0 || amount > balance) {
            return false;            // reject invalid// 拒绝非法输入
        }
        balance -= amount;
        return true;
    }
}

Accessor Returning a Mutable Object, Defensive Copy

访问器返回可变对象,防御性拷贝(defensive copy

If an accessor returns a reference to a mutable object (array, ArrayList, or any class you wrote), the caller has the same reference as your field, and can mutate it, breaking encapsulation.

如果访问器返回一个可变对象的引用(数组、ArrayList 或你自己写的任何类),调用方就持有了与字段相同的引用,可以对其进行修改,从而破坏封装。

// BAD: caller can mutate our internal list// 错误示范:调用方可以修改我们的内部列表
public ArrayList<String> getNames() {
    return names;
}

// GOOD: return a fresh copy// 正确示范:返回一份新副本
public ArrayList<String> getNames() {
    return new ArrayList<>(names);
}
AP Trap: Accessor That Leaks Internal State AP 陷阱:泄露内部状态的访问器 Returning the array reference (return arr;) or list reference (return list;) means external code holds your internal data and can change it. The FRQ rubric awards a point for defensive copy when the accessor returns a mutable type. Worth remembering: String is immutable so it's fine to return directly; arrays and ArrayList are mutable so return a copy. 返回数组引用(return arr;)或列表引用(return list;),意味着外部代码持有了你的内部数据并可以修改它。当访问器返回可变类型时,FRQ 评分标准会为防御性拷贝给一分。值得记住:String 是不可变的,可以直接返回;数组和 ArrayList 是可变的,要返回副本。

Methods: Passing and Returning References

方法:传递与返回引用

When an object reference is passed to a method, the parameter receives a copy of the reference, but both the caller's variable and the parameter refer to the same object on the heap. Mutations made through the parameter are visible to the caller. This comes up a lot on AP MCQ questions about methods.

当一个对象引用传给方法时,形参收到的是引用的副本,但调用方的变量和形参指向堆上的同一个对象。通过形参所做的修改对调用方是可见的。这是关于方法的 AP 选择题里反复出现的考点。

Primitives vs Objects in Method Calls 方法调用中:基本类型 vs 对象 A method that takes a primitive (int, double, etc.) can never change the caller's variable, the parameter is a fresh copy of the value. A method that takes an object can change the caller's object through mutation, but cannot make the caller's variable refer to a different object. It's a common AP MCQ trap. 接收基本类型intdouble 等)的方法永远无法改变调用方的变量,形参只是值的全新副本。接收对象的方法可以通过变异来改变调用方的对象,但不能让调用方的变量指向另一个对象。这是 AP 选择题常见的陷阱。
Worked Example 1: Method mutates a passed object
例题 1:方法修改传入的对象
public class Dog {
    private String name;
    public Dog(String n) { name = n; }
    public String getName() { return name; }
    public void setName(String n) { name = n; }
}

public static void rename(Dog d) {
    d.setName("Max");  // mutates the original Dog// 修改原始 Dog 对象
}

Dog rex = new Dog("Rex");
rename(rex);
System.out.println(rex.getName());  // prints: Max// 打印:Max

Why? The parameter d is a copy of the reference to the same Dog object as rex. d.setName(...) mutates that object. rex "sees" the change because both names still refer to the same heap object.

原因。形参 drex 所指 Dog 对象的引用副本。d.setName(...) 修改了该对象。rex 能"看到"这个变化,因为这两个名字仍然指向堆上同一个对象。

Worked Example 2: Reassigning the parameter doesn't change the caller
例题 2:重新给形参赋值并不会改变调用方
public static void replace(Dog d) {
    d = new Dog("Replaced");  // reassigns the LOCAL copy// 重新赋值的是本地副本
}

Dog rex = new Dog("Rex");
replace(rex);
System.out.println(rex.getName());  // prints: Rex (unchanged!)// 打印:Rex(未变!)

Why? d = new Dog(...) only changes what the local parameter d points to. The caller's rex reference is unchanged. You can't reassign your way to "replacing" the caller's object. This is the AP trap that catches the most students.

原因。d = new Dog(...) 只改变本地形参 d 所指的对象。调用方的 rex 引用并未改变。你无法靠重新赋值来"替换"调用方的对象。这是抓走最多学生的 AP 陷阱。

Worked Example 3: Aliasing in assignment
例题 3:赋值中的别名
Dog rex = new Dog("Rex");
Dog buddy = rex;       // alias: buddy and rex refer to the SAME object// 别名:buddy 和 rex 指向同一个对象
buddy.setName("Buddy");
System.out.println(rex.getName());  // prints: Buddy// 打印:Buddy

Why? buddy = rex copies the reference, not the object. Both names refer to the same Dog object. A mutation through one is visible through the other. This is "aliasing" and is the same mechanism as passing an object to a method.

原因。buddy = rex 复制的是引用,不是对象。两个名字指向同一个 Dog 对象。通过其中一个所做的修改,通过另一个也能看到。这就是"别名(aliasing)"现象,与把对象传给方法是同一种机制。

Aliasing: Friend or Bug 别名:是助手还是 bug Aliasing is fine when intentional (e.g., shorter local name for clarity). It's a bug when accidental, e.g., a constructor stores a passed-in array reference and the caller later mutates the array, corrupting the object's invariants. The fix: defensive copy at the boundary (in the constructor or accessor). 如果是有意为之(例如取一个更短的本地名以提升可读性),别名没问题。但如果是无意造成的,就是 bug,例如构造方法存下传入的数组引用,之后调用方修改了该数组,破坏了对象的不变式。修复方法:在边界处(构造方法或访问器中)做防御性拷贝
Private Access Rule 私有访问规则 A method cannot access the private fields of a parameter object, unless the parameter is the same type as the enclosing class. e.g., a Dog instance method can read another Dog parameter's private fields directly, because they're in the same class. 方法不能访问形参对象的 private 字段,除非形参与所在类是同一类型。例如,Dog 的实例方法可以直接读取另一个 Dog 形参的私有字段,因为它们在同一个类中。
Consider public static void inc(int x) { x++; } and the call int n = 5; inc(n); System.out.println(n);. What is printed?
考虑 public static void inc(int x) { x++; },以及调用 int n = 5; inc(n); System.out.println(n);。会打印什么?
4
5
6
Compile error编译错误
Correct! x is a local copy of the value 5. x++ increments that copy, not the caller's n. n remains 5. Primitives are always passed by value in Java.
正确!x 是值 5 的本地副本。x++ 自增的是这份副本,而不是调用方的 nn 仍然是 5。在 Java 中,基本类型始终按值传递。
Primitives are passed by value. The method's x is a copy. Mutating the copy doesn't affect the caller. n = 5.
基本类型按值传递。方法里的 x 只是一个副本,修改副本不会影响调用方。n = 5。
Consider a class Box with a void clear() method that sets a private field to null. Given Box b = new Box(); Box c = b; c.clear();, what happens to b?
某个类 Box 含有一个 void clear() 方法,会把某个私有字段设为 null。给定 Box b = new Box(); Box c = b; c.clear();b 会发生什么?
b is unchanged because c is a copyb 不变,因为 c 是副本
b becomes nullb 变成 null
b's internal field is now nullb 的内部字段现在是 null
Compile error, can't share Box across variables编译错误,Box 不能在多个变量间共享
Correct! c = b creates an alias. c and b refer to the same Box. c.clear() mutates that shared Box, so the Box's internal field is null. The variable b itself is unchanged (still points to the same object), it's the object's state that changed.
正确!c = b 创建了一个别名。cb 指向同一个 Box。c.clear() 修改了这个共享的 Box,因此 Box 的内部字段是 null。变量 b 本身没变(仍指向同一个对象),变的是该对象的状态
Aliasing: c = b shares the reference. c.clear() mutates the object. b (the variable) still refers to the same object, but that object's internal state has changed.
别名现象:c = b 共享了引用。c.clear() 修改了该对象。变量 b 仍然指向同一个对象,但该对象的内部状态已经改变。

Class Variables and Methods

类变量与类方法

static Variables

static 变量

A static variable belongs to the class, not to any individual object. All instances share one copy.

static 变量属于,而不属于任何单个对象。所有实例共享同一份。

public class Dog {
    private static int dogCount = 0;  // shared// 共享
    private String name;               // per object// 每个对象一份

    public Dog(String name) {
        this.name = name;
        dogCount++;
    }

    public static int getDogCount() {
        return dogCount;
    }
}
Feature特性Instance实例Class (static)类(static)
Belongs to归属Each object每个对象The class itself类本身
Accessed via访问方式obj.method()ClassName.method()
Can use instance vars?能使用实例变量吗?Yes可以No (unless passed an instance)不能(除非传入一个实例)
final Keyword final 关键字 A variable declared final cannot be reassigned after initialization. Often combined with static for constants: public static final double PI = 3.14159; 声明为 final 的变量在初始化之后不能再被赋值。常与 static 组合来定义常量:public static final double PI = 3.14159;
Can a static method directly access an instance variable?
static 方法可以直接访问实例变量吗?
Yes, always可以,总是可以
No, it needs an instance passed as a parameter不可以,需要把一个实例作为形参传入
Only if the variable is public只有当变量是 public 时才行
Correct! Static methods have no implicit object (this), so they can only access instance data through an explicit object reference.
正确!static 方法没有隐式对象(没有 this),所以只能通过显式的对象引用来访问实例数据。
Static methods don't belong to any object, so they can't directly access instance variables. They need an object reference passed in.
static 方法不属于任何对象,因此不能直接访问实例变量,需要外部传入对象引用。

Scope and Access

作用域与可见性

Local variables are declared inside a method, constructor, or block. They exist only within that block.

局部变量(local variable声明在方法、构造方法或代码块(block)内部,只在该代码块中存在。

Scope rules:

作用域(scope)规则:

Instance variables → accessible throughout the entire class.

实例变量 → 在整个类中都可访问。

Local variables → accessible only in the block where declared.

局部变量 → 只在其声明所在的代码块内可访问。

Parameters → local to their method/constructor.

形参 → 仅在其所属的方法/构造方法中有效。

Name Shadowing 名称遮蔽(name shadowing If a local variable or parameter has the same name as an instance variable, the local variable takes precedence inside that method. Use this.variableName to access the instance variable. 如果某个局部变量或形参与实例变量同名,那么在该方法内部,局部变量优先生效。要访问实例变量,请使用 this.variableName
public Dog(String name) {
    // "name" here refers to the parameter// 这里的 "name" 指形参
    // "this.name" refers to the instance variable// "this.name" 指实例变量
    this.name = name;
}
Worked Example: Shadowing pitfall in action
例题:名称遮蔽陷阱实例
public class Counter {
    private int count = 100;  // instance variable// 实例变量

    public void increment(int count) {  // parameter shadows field// 形参遮蔽字段
        count++;            // increments the PARAMETER, not the field// 自增的是形参,不是字段
        this.count++;       // increments the FIELD// 自增的是字段
    }

    public int getCount() { return count; }  // field// 字段
}

Counter c = new Counter();
c.increment(5);
                  // parameter starts at 5, becomes 6 (ignored)// 形参从 5 自增到 6(被忽略)
                  // field starts at 100, becomes 101// 字段从 100 自增到 101
System.out.println(c.getCount());  // prints: 101// 打印:101

Takeaway. Without this., a bare count inside increment refers to the parameter. The field is reachable only via this.count. This is the most common cause of "constructor doesn't seem to work" bugs.

要点。increment 内部,如果不加 this.,光写 count 指的是形参。字段只能通过 this.count 才能访问。这是"构造方法好像没生效"这类 bug 最常见的原因。

AP Trap: Silent Shadowing AP 陷阱:无声的名称遮蔽 Shadowing compiles cleanly, the compiler never warns you. The bug manifests at runtime as "the field never changed". On the AP MCQ, watch for parameter names that match field names; if the method body doesn't use this., the field is untouched. 名称遮蔽能正常编译通过,编译器永远不会发出警告。bug 表现在运行时是"字段始终没变"。在 AP 选择题中,要盯住与字段同名的形参;如果方法体没用 this.,那么字段就没被改动过。

this Keyword

this 关键字

Inside an instance method or constructor, this is a reference to the current object, the object whose method is being called.

在实例方法或构造方法内部,this 是指向当前对象的引用,即被调用方法所属的那个对象。

Common uses of this:

this 的常见用法:

1. Disambiguate instance variables from parameters with the same name.

1. 区分实例变量与同名的形参。

2. Pass the current object as an argument to another method.

2. 把当前对象作为实参传给另一个方法。

public void addToList(DogList list) {
    list.add(this);  // pass the current Dog object// 传入当前 Dog 对象
}
No this in static Methods static 方法中没有 this Since static methods aren't called on any object, they have no this reference. Attempting to use this in a static method causes a compile error. 由于 static 方法不针对任何对象调用,它们没有 this 引用。在 static 方法中使用 this 会导致编译错误。

Complete Class, BankAccount

完整类示例:BankAccount

public class BankAccount {
    // Class variable: tracks how many accounts exist// 类变量:记录存在多少个账户
    private static int accountCount = 0;

    // Instance variables (private for encapsulation)// 实例变量(为封装而私有)
    private String owner;
    private double balance;
    private int id;

    // Constructor// 构造方法
    public BankAccount(String owner, double initialBalance) {
        this.owner = owner;
        this.balance = initialBalance;
        accountCount++;
        this.id = accountCount;
    }

    // Accessor methods// 访问器方法
    public String getOwner() { return owner; }
    public double getBalance() { return balance; }
    public int getId() { return id; }

    // Mutator methods// 修改器方法
    public void deposit(double amount) {
        if (amount > 0) balance += amount;
    }

    public void withdraw(double amount) {
        if (amount > 0 && amount <= balance) {
            balance -= amount;
        }
    }

    // Class method// 类方法
    public static int getAccountCount() {
        return accountCount;
    }
}
What to Notice 要点 Private instance variables, public constructor and methods, this for disambiguation, a static variable for counting, and a static method to access it. This is the pattern the AP exam expects you to write for FRQ #2 (Class Design). 私有实例变量(instance variable)、公有构造方法(constructor)与方法、用 this 消除歧义、用 static 变量计数、再用一个 static 方法读取它。这正是 AP 考试 FRQ #2(类设计题)希望你写出的模式。

How Class Creation Shows Up on the AP Exam

类的定义在 AP 考试中如何考

The AP CSA exam has 4 Free-Response Questions. Class Creation directly underpins FRQ #2: Class Design, which appears every year. Knowing the rubric is half the battle, the College Board awards points for specific syntactic features, not just "correct" code.

AP CSA 考试有 4 道自由回答题(FRQ)。类的定义正是 FRQ #2:类设计的核心,该题每年都考。熟悉评分标准已经赢了一半——College Board 给分看的是具体的语法要素,而不仅仅是"代码对了"。

Typical FRQ #2 prompt structure:

典型的 FRQ #2 题干结构:

"Write a class X that has <list of attributes>. Include a constructor that <assigns the attributes from parameters>. Include accessor methods <getName, getAge, ...>, mutator methods <setAge with validation>, and a behavior method <summary, isAvailable, ...> that uses the fields."

"编写一个类(classX,它包含 <属性清单>。包含一个 <从形参为属性赋值> 的构造方法(constructor)。包含访问器方法(accessor)<getName、getAge…>、修改器方法(mutator)<带校验的 setAge>,以及一个 <summary、isAvailable…> 这样的行为方法,使用各字段。"

You'll write this from scratch in ~25 minutes. The class is usually 25–50 lines of code. Partial credit is rubric-driven.

你要在约 25 分钟内从零写完。整个类一般有 25–50 行代码。部分给分严格按评分标准来。

FRQ #2 Rubric, Common Point Allocations (≈9 pts total) FRQ #2 评分标准:常见给分点(共约 9 分)
  • +1–2: Class declared public class X with private fields
  • +1: Constructor signature matches the prompt's parameters
  • +1: All instance variables assigned in the constructor
  • +1: this. used to disambiguate where parameter and field share a name
  • +2–3: Each method correctly written, return type, parameter list, and body behavior match the description
  • +1: Mutator includes any required validation (the prompt usually says "if the value is positive…")
  • +1: Defensive copy where applicable (returning an array or ArrayList)
  • +1–2:public class X 声明类,并使用私有字段
  • +1:构造方法的方法签名(method signature)与题干给出的形参一致
  • +1:构造方法中给所有实例变量都赋了值
  • +1:当形参与字段同名时使用 this. 消除歧义
  • +2–3:每个方法正确实现,返回类型(return type)、形参列表与方法体行为均与题目描述相符
  • +1:修改器包含题目要求的校验(题干通常会说"如果值为正…")
  • +1:必要时进行防御性拷贝(defensive copy,当返回数组或 ArrayList 时)
Common FRQ #2 Mistakes, Each Costs ~1 Point FRQ #2 常见错误(每个大约扣 1 分)
  • Public instance variables (must be private)
  • Missing public on the constructor or on any method
  • Constructor with a return type (e.g., public void Dog(...), silently becomes a method)
  • Accessor with the wrong return type (e.g., void on a getter)
  • Forgetting to assign some of the instance variables in the constructor
  • Parameter name shadowing the field, without this. qualification
  • Returning the raw array/ArrayList reference instead of a copy
  • Forgetting input validation on a mutator when the prompt requires it
  • 实例变量写成 public(必须是 private
  • 构造方法或某个方法漏写 public
  • 构造方法带返回类型(例如 public void Dog(...),悄无声息地变成普通方法)
  • 访问器返回类型写错(例如给 getter 写 void
  • 构造方法中漏给某些实例变量赋值
  • 形参与字段同名,但没有用 this. 限定
  • 直接返回数组/ArrayList 的原始引用而非副本
  • 题干要求校验,却忘了在修改器中做输入校验
Time-Saver, Read the Stem Twice 省时技巧:把题干读两遍 Before writing code, underline each noun the prompt mentions (those are your private fields, with the types named in the prompt) and each verb (those are your methods, with return types and parameters derived from the prompt). Then code from your underlines, don't ad-lib fields or methods that aren't asked for, since extra unrequested code doesn't earn points and can break the rubric. 在写代码前,把题干里的每个名词都划线(这些就是你的私有字段,类型用题干给出的)和每个动词(这些就是你的方法,返回类型和形参也都源自题干)。然后按划线的内容写代码,不要"自由发挥"出题目未要求的字段或方法——多写未要求的代码不仅不会加分,反而可能违反评分标准。

Flashcards, Click to Flip

闪卡:点击翻面

What is encapsulation?什么是封装(encapsulation)?
Hiding implementation details from external classes using private access.private 访问权限把实现细节对外部类隐藏起来。
Accessor vs Mutator?访问器(accessor)vs 修改器(mutator)?
Accessor → returns data (getter, non-void)
Mutator → changes data (setter, usually void)
访问器 → 返回数据(getter,非 void)
修改器 → 修改数据(setter,通常是 void)
Default value of an int field?int 字段的默认值?
0
Default value of a reference type field?引用类型字段的默认值?
null
What does this refer to?this 指代什么?
The current object, the one whose method or constructor is executing.当前对象,即正在执行其方法或构造方法的那个对象。
static variable belongs to…?static 变量属于……?
The class (shared by all instances), not any individual object.类(由所有实例共享),而不是任何单个对象。
Can a static method use this?static 方法可以使用 this 吗?
No, static methods don't run on an object, so there's no this.不行,static 方法不针对对象运行,所以没有 this
What is name shadowing?什么是名称遮蔽(name shadowing)?
Local var hides the instance field of the same name.
Fix: use this.var to reach the field.
局部变量遮蔽了同名的实例字段。
修复:用 this.var 来访问字段。
Pass-by-value for objects means…?对象的按值传递(pass by value)是指……?
A copy of the reference is passed.
The method can still mutate the original object.
传入的是引用的副本。
方法仍然可以修改原始对象。
What does final do?final 有什么作用?
Prevents a variable from being reassigned after initialization.禁止变量在初始化之后被重新赋值。
Can constructors be overloaded?构造方法(constructor)可以重载(overloading)吗?
Yes, multiple constructors with different parameter lists. Java picks one based on the arguments at the call site.可以,多个构造方法、形参列表各不相同。Java 会根据调用处的实参选择其中一个。
Should a constructor declare a return type?构造方法应该声明返回类型吗?
No. Writing void or any type turns it into a regular method, not a constructor, and Java will auto-generate the default no-arg constructor.不应。写 void 或任何类型,都会把它变成普通方法而非构造方法,Java 会自动生成默认无参构造方法。
Why "defensive copy" in a getter?getter 为什么要"防御性拷贝(defensive copy)"?
If the field is mutable (array, ArrayList, etc.), returning the reference lets the caller mutate it. Return a copy to protect encapsulation.如果字段是可变的(数组、ArrayList 等),返回引用就让调用方可以修改它。返回副本以保护封装。
Can a method reassign the caller's reference?方法能重新指定调用方的引用吗?
No. Reassigning the parameter (d = new Dog(...)) only changes the local copy. The caller's reference still points to the original object.不能。给形参重新赋值(d = new Dog(...))只改变本地副本。调用方的引用仍指向原对象。
How are static methods called?static 方法如何调用?
ClassName.method(), using the class name, not an object reference. e.g., Math.abs(-5), User.getTotalUsers().ClassName.method(),用类名调用,而不是对象引用。例如 Math.abs(-5)User.getTotalUsers()

Unit 3, Practice Quiz

单元 3 练习小测

1. Which access modifier should instance variables have for proper encapsulation?
1. 为了正确实现封装(encapsulation),实例变量(instance variable)应当使用哪个访问修饰符(access modifier)?
private
public
static
final
Correct! Encapsulation requires keeping instance variables private so only the class's own methods can access them.
正确!封装要求把实例变量保持为 private,这样只有类自己的方法才能访问它们。
Instance variables should be private for encapsulation.
实例变量应当是 private 以实现封装。
2. What happens if you write no constructors in a class?
2. 如果你在类(class)中一个构造方法(constructor)都不写,会发生什么?
The class cannot create objects该类无法创建对象
All fields are set to null所有字段都被设为 null
Java provides a default no-arg constructor with default valuesJava 提供一个无参的默认构造方法,字段使用默认值
Compile error编译错误
Correct! Java auto-generates a no-parameter constructor. Fields get type-based defaults: 0, 0.0, false, or null.
正确!Java 会自动生成一个无参构造方法。字段获得基于类型的默认值:0、0.0、false 或 null。
Java provides a default constructor when none is written. Fields get defaults based on type.
当一个构造方法都没写时,Java 会提供默认构造方法。字段按类型获得默认值。
3. What type of method is public double getBalance()?
3. public double getBalance() 属于哪一类方法?
Mutator (void)修改器(mutator,void)
Accessor (non-void)访问器(accessor,非 void)
Constructor构造方法
Static methodstatic 方法
Correct! It returns a value (non-void) and reads data without changing it, that's an accessor/getter.
正确!它返回一个值(非 void),并且只读数据不修改数据,这就是访问器/getter。
A method with a return type that reads (not modifies) data is an accessor.
带返回类型、只读取(不修改)数据的方法就是访问器。
4. Given private static int count = 0;, how is count shared?
4. 给定 private static int count = 0;count 是如何共享的?
Each object gets its own copy每个对象拥有自己的副本
Only the first object can access it只有第一个对象可以访问
It cannot be changed它不能被修改
All objects of the class share one copy该类的所有对象共享同一份
Correct! static means the variable belongs to the class, all objects share a single copy.
正确!static 意味着该变量属于类,所有对象共享同一份。
static variables are shared: one copy for the whole class, not per-object.
static 变量是共享的:整个类只有一份,而不是每个对象一份。
5. Inside a constructor, this.name = name; does what?
5. 在构造方法内部,this.name = name; 的作用是什么?
Assigns the parameter name to the instance variable name把形参 name 赋给实例变量 name
Creates a new variable called this.name创建一个名为 this.name 的新变量
Causes a compile error引发编译错误
Assigns the instance variable to the parameter把实例变量赋给形参
Correct! this.name refers to the instance variable, while name refers to the parameter. The parameter's value is stored in the field.
正确!this.name 指向实例变量,而 name 指向形参。形参的值被存入字段。
this.name = instance variable, name = parameter. The line stores the parameter value into the field.
this.name = 实例变量,name = 形参。这一行把形参的值存到字段里。
6. Consider:
public class Box {
    private int[] contents;
    public Box(int[] items) {
        contents = items;
    }
}
int[] arr = {1, 2, 3};
Box b = new Box(arr);
arr[0] = 99;
What is in b's contents after this code runs?
6. 考虑:
public class Box {
    private int[] contents;
    public Box(int[] items) {
        contents = items;
    }
}
int[] arr = {1, 2, 3};
Box b = new Box(arr);
arr[0] = 99;
这段代码执行后,bcontents 是什么?
{1, 2, 3}, the Box made a copy{1, 2, 3},Box 做了一份副本
Compile error编译错误
{99, 2, 3}, the Box's field aliases arr{99, 2, 3},Box 的字段是 arr 的别名
null
Correct! contents = items stored the caller's reference, which is the same array on the heap as arr. Mutating arr after construction is visible inside the Box. Fix: contents = items.clone(); in the constructor.
正确!contents = items 存下了调用方的引用,它指向堆上与 arr 相同的数组。构造之后再修改 arr,在 Box 内部能看到。修复:构造方法里改为 contents = items.clone();
Both contents and arr reference the same array. Mutating through one is visible through the other. The Box constructor needs a defensive copy (items.clone()) to prevent this.
contentsarr 指向同一个数组。通过其中一个所做的修改,通过另一个也能看到。Box 的构造方法需要做防御性拷贝(items.clone())来避免这种情况。
7. Given the class
public class Counter {
    private static int total = 0;
    private int value;
    public Counter(int v) { value = v; total++; }
    public int getValue() { return value; }
    public static int getTotal() { return total; }
}
which of the following lines does not compile?
7. 给定如下类:
public class Counter {
    private static int total = 0;
    private int value;
    public Counter(int v) { value = v; total++; }
    public int getValue() { return value; }
    public static int getTotal() { return total; }
}
下列哪一行不能通过编译?
Counter c = new Counter(5);
Counter.getValue();
Counter.getTotal();
new Counter(0).getValue();
Correct! getValue() is an instance method, it needs an object reference. Counter.getValue() tries to call it as a static method, which doesn't compile.
正确!getValue()实例方法,需要对象引用。Counter.getValue() 把它当作 static 方法调用,不能通过编译。
Static methods are called on the class. Instance methods need an object. getValue() is instance, so Counter.getValue() fails to compile.
static 方法用类名调用,实例方法需要对象。getValue() 是实例方法,所以 Counter.getValue() 编译失败。
8. Consider:
public class P {
    private int n;
    public P(int n) { n = n; }
    public int getN() { return n; }
}
System.out.println(new P(42).getN());
What is printed?
8. 考虑:
public class P {
    private int n;
    public P(int n) { n = n; }
    public int getN() { return n; }
}
System.out.println(new P(42).getN());
会打印什么?
42
0
Compile error编译错误
null
Correct! Classic shadowing bug. Inside the constructor, n = n assigns the parameter n to itself, it never touches the field. The field stays at its default value 0. Fix: this.n = n;
正确!经典的名称遮蔽(name shadowing)bug。在构造方法内部,n = n 把形参 n 赋给它自己,根本没碰字段。字段保留默认值 0。修复:this.n = n;
The constructor body is n = n, which assigns the parameter to itself. The field is shadowed and never written, so it keeps its default value 0. Always use this.n = n when names collide.
构造方法体是 n = n,把形参赋给它自己。字段被遮蔽且从未被写入,因此保留默认值 0。名称冲突时永远写 this.n = n
9. A class has a private String[] arr and an accessor public String[] getArr() { return arr; }. What's the issue?
9. 某个类有一个 private 字段 String[] arr,以及访问器 public String[] getArr() { return arr; }。这里有什么问题?
The caller can mutate the array, breaking encapsulation调用方可以修改数组,从而破坏封装
The method signature is invalid for arrays对数组而言该方法签名不合法
The method needs to be static该方法需要写成 static
There is no issue, accessors should return the field directly没有问题,访问器就该直接返回字段
Correct! Returning the array reference exposes the field. Any mutation by the caller (e.g. obj.getArr()[0] = 99) changes the class's internal state, encapsulation is broken. Defensive fix: return arr.clone(); for a shallow copy of the array spine. (For an array of mutable objects, you'd need a deep copy.)
正确!返回数组引用就把字段暴露出去了。调用方任何修改(例如 obj.getArr()[0] = 99)都会改动类的内部状态,封装被破坏。防御性修复:return arr.clone();,对数组主体做一次浅拷贝。(如果是可变对象数组,还需要深拷贝。)
Mutable accessors must return a copy. The AP rubric awards a defensive-copy point on FRQ #2 when the field is a mutable type like an array or ArrayList.
返回可变对象的访问器必须返回副本。当字段是数组或 ArrayList 这类可变类型时,FRQ #2 评分标准会为防御性拷贝(defensive copy)给一分。

AP-Style Practice Problems

AP 风格练习题

15 exam-level multiple-choice questions (3 medium · 12 hard), code-trace heavy with realistic distractors and fully worked solutions. Built for top-score prep — go here after you've worked through the notes and the in-page quiz above.

15 道考试难度选择题(3 道中等 · 12 道困难),偏重代码追踪,干扰项贴近真题,每题都有完整解析。为冲击满分而设——把上面的讲义和小测过完之后再来。

Practice Problems →练习题 →

鼎睿学苑 · Dingrui Scholars

AP Computer Science A, Unit 3: Class Creation · 2026 Edition

AP 计算机科学 A,单元 3:类的定义 · 2026 版