Unit 3: Class Creation
单元 3:类的定义
Design your own classes with instance variables, constructors, methods, encapsulation, static members, scope, and the this keyword.
自行设计类,掌握实例变量、构造方法、方法、封装、静态成员、作用域以及 this 关键字。
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.
过程抽象,为某个过程(方法)赋予名称。你只需知道方法做了什么,而不必关心如何做。这便于代码复用与方法分解。
class)做规划:识别其属性(数据/名词)与行为(方法/动词)。可用自然语言、UML 图或伪代码来完成。
object)独有一份。类变量由所有对象共享。
Library classLibrary 类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(addBook、checkOut)。私有辅助方法负责内部工作。实例变量永远是 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) { /* ... *//* ... */ } }
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.
抄袭,未署名地复制其他同学提交的代码(哪怕只是部分、哪怕做过修改)就是抄袭,属于严重的学术诚信违规。任何并非你本人编写的代码都应标注出处,包括根据文档或在线论坛改编的代码片段。
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用途 |
|---|---|---|
public | Any class任何类 | Classes, constructors, methods that form the API类、构造方法(constructor)、构成 API 的方法 |
private | Only the declaring class只有声明它的类 | Instance variables (best practice), helper methods实例变量(最佳实践)、辅助方法 |
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; } }
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 name、int 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; } }
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 调用构造方法时,内存被分配,并返回一个对象引用。
Default Constructor
默认构造方法
If you write no constructors, Java provides a default (no-argument) constructor that sets fields to default values:
如果你一个构造方法都没写,Java 会提供一个默认(无参)构造方法(default constructor),把各字段设为类型默认值:
| Type类型 | Default Value默认值 |
|---|---|
int | 0 |
double | 0.0 |
boolean | false |
| Reference types引用类型 | null |
private boolean active;, what is active after new MyClass()?private boolean active;,那么 new MyClass() 之后 active 的值是?boolean is false.boolean 的默认值是 false。boolean instance variables is false (not null, that's for reference types).boolean 实例变量的默认值是 false(不是 null,null 是引用类型的默认值)。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 参构造方法
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示例 |
|---|---|---|---|
| voidvoid | Nothing不返回任何值 | void | public void bark() |
| Non-void非 void | A 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 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,基本类型)
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); }
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 选择题里反复出现的考点。
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.
接收基本类型(int、double 等)的方法永远无法改变调用方的变量,形参只是值的全新副本。接收对象的方法可以通过变异来改变调用方的对象,但不能让调用方的变量指向另一个对象。这是 AP 选择题常见的陷阱。
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.
原因。形参 d 是 rex 所指 Dog 对象的引用副本。d.setName(...) 修改了该对象。rex 能"看到"这个变化,因为这两个名字仍然指向堆上同一个对象。
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 陷阱。
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)"现象,与把对象传给方法是同一种机制。
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 形参的私有字段,因为它们在同一个类中。
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);。会打印什么?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++ 自增的是这份副本,而不是调用方的 n。n 仍然是 5。在 Java 中,基本类型始终按值传递。x is a copy. Mutating the copy doesn't affect the caller. n = 5.x 只是一个副本,修改副本不会影响调用方。n = 5。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 会发生什么?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 创建了一个别名。c 和 b 指向同一个 Box。c.clear() 修改了这个共享的 Box,因此 Box 的内部字段是 null。变量 b 本身没变(仍指向同一个对象),变的是该对象的状态。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 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;
static method directly access an instance variable?static 方法可以直接访问实例变量吗?this), so they can only access instance data through an explicit object reference.this),所以只能通过显式的对象引用来访问实例数据。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)
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; }
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 最常见的原因。
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 对象 }
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; } }
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."
"编写一个类(class)X,它包含 <属性清单>。包含一个 <从形参为属性赋值> 的构造方法(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 行代码。部分给分严格按评分标准来。
- +1–2: Class declared
public class Xwith 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时)
- Public instance variables (must be
private) - Missing
publicon 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.,
voidon 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/
ArrayListreference 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的原始引用而非副本 - 题干要求校验,却忘了在修改器中做输入校验
Flashcards, Click to Flip
闪卡:点击翻面
encapsulation)?private access.用 private 访问权限把实现细节对外部类隐藏起来。accessor)vs 修改器(mutator)?Mutator → changes data (setter, usually void)访问器 → 返回数据(getter,非 void)
修改器 → 修改数据(setter,通常是 void)
int field?int 字段的默认值?0nullthis refer to?this 指代什么?static variable belongs to…?static 变量属于……?this?static 方法可以使用 this 吗?this.不行,static 方法不针对对象运行,所以没有 this。name shadowing)?Fix: use
this.var to reach the field.局部变量遮蔽了同名的实例字段。修复:用
this.var 来访问字段。pass by value)是指……?The method can still mutate the original object.传入的是引用的副本。
方法仍然可以修改原始对象。
final do?final 有什么作用?constructor)可以重载(overloading)吗?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 会自动生成默认无参构造方法。defensive copy)"?ArrayList, etc.), returning the reference lets the caller mutate it. Return a copy to protect encapsulation.如果字段是可变的(数组、ArrayList 等),返回引用就让调用方可以修改它。返回副本以保护封装。d = new Dog(...)) only changes the local copy. The caller's reference still points to the original object.不能。给形参重新赋值(d = new Dog(...))只改变本地副本。调用方的引用仍指向原对象。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 练习小测
encapsulation),实例变量(instance variable)应当使用哪个访问修饰符(access modifier)?private so only the class's own methods can access them.private,这样只有类自己的方法才能访问它们。private for encapsulation.private 以实现封装。class)中一个构造方法(constructor)都不写,会发生什么?public double getBalance()?public double getBalance() 属于哪一类方法?private static int count = 0;, how is count shared?private static int count = 0;,count 是如何共享的?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 变量是共享的:整个类只有一份,而不是每个对象一份。this.name = name; does what?this.name = name; 的作用是什么?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 = 形参。这一行把形参的值存到字段里。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?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;这段代码执行后,b 的 contents 是什么?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();。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.contents 和 arr 指向同一个数组。通过其中一个所做的修改,通过另一个也能看到。Box 的构造方法需要做防御性拷贝(items.clone())来避免这种情况。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?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; }
}下列哪一行不能通过编译?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 方法调用,不能通过编译。getValue() is instance, so Counter.getValue() fails to compile.getValue() 是实例方法,所以 Counter.getValue() 编译失败。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?public class P {
private int n;
public P(int n) { n = n; }
public int getN() { return n; }
}
System.out.println(new P(42).getN());会打印什么?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;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。String[] arr and an accessor public String[] getArr() { return arr; }. What's the issue?String[] arr,以及访问器 public String[] getArr() { return arr; }。这里有什么问题?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();,对数组主体做一次浅拷贝。(如果是可变对象数组,还需要深拷贝。)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 道困难),偏重代码追踪,干扰项贴近真题,每题都有完整解析。为冲击满分而设——把上面的讲义和小测过完之后再来。
鼎睿学苑 · Dingrui Scholars
AP Computer Science A, Unit 3: Class Creation · 2026 Edition
AP 计算机科学 A,单元 3:类的定义 · 2026 版