slug
type
status
category
date
summary
tags
password
icon
第二次月考23题:
Let’s carefully trace the execution step by step.
Given behavior of Checker.validate(Item i)
lastIDstarts at 0
- If
i.getIdNum() == lastID→ print invalid
- Otherwise → update
lastIDto the new id and print valid
Objects created
So:
ihas ID 23
jhas ID 55
c.lastID = 0
Assume
checkID(c) simply calls:Execution trace
1️⃣ i.checkID(c);
id = 23
lastID = 0
23 != 0→ valid
- Update
lastID = 23
Output:
2️⃣ j.checkID(c);
id = 55
lastID = 23
55 != 23→ valid
- Update
lastID = 55
Output:
3️⃣ j.checkID(c);
id = 55
lastID = 55
55 == 55→ invalid
lastIDunchanged
Output:
4️⃣ i.checkID(c);
id = 23
lastID = 55
23 != 55→ valid
- Update
lastID = 23
Output:
✅ Final printed output (in order)
Activity 4.9.9.
我直接按从上到下、几乎每一行给你讲一遍在干嘛,也顺便帮你串一下整体逻辑。
import语句:告诉 Java 编译器“我要用java.util这个包里的类”。
java.util里有很多集合类,比如ArrayList,HashMap等。
- 表示导入这个包中所有公共类。
在这段代码里,我们实际用到的是:
ArrayList。- 定义一个公共类
WordPairTest。
- 按照 Java 规范:一个 .java 文件里如果有 public 类,那么文件名必须和这个类名完全一致,所以这个文件应该叫
WordPairTest.java。
- 大括号
{表示这个类的开始。
public:主方法对外是公开的,JVM 可以调用它。
static:是类方法,不需要创建WordPairTest对象就可以直接用类名调用。JVM 启动程序时就是直接调用这个静态方法。
void:表示这个方法没有返回值。
main:Java 程序的入口方法,固定写法。
String[] args:命令行参数(字符串数组),这段代码里没用到。
{:主方法体的开始。
- 这一行是注释(
//开头),给人看的,不会被编译器执行。
- 中文意思:创建一个存放
WordPair对象的ArrayList,名字叫pairs。
ArrayList<WordPair>:这是一个泛型集合,表示“一个ArrayList,里面存的是WordPair类型的对象”。- 和
ArrayList<String>类似,只不过这里存的是你自定义的WordPair。
pairs:变量名,这个变量引用一个ArrayList对象。
=:赋值运算符,把右边new出来的对象赋给左边的变量。
new ArrayList<WordPair>():new:在堆内存中创建一个新的ArrayList对象。<WordPair>再写一遍,是旧一点的写法。也可以写成:
- 整句含义:创建一个空的、用来装
WordPair对象的动态数组,并用变量pairs引用它。
这一行做了两件事:
new WordPair("hi", "there")- 调用了下面定义的
WordPair构造方法,传入两个字符串"hi"和"there"。 - 会创建一个
WordPair对象,其中: word1="hi"word2="there"
pairs.add( … )add是ArrayList的方法,用来把一个元素放到列表的末尾。- 这里就是:把刚刚创建好的
WordPair("hi", "there")放进pairs这个列表里。
- 同理,再创建一个
WordPair对象: word1="hi"word2="bye"
- 再把这个对象添加到
pairs的后面。
- 此时
pairs里有两个元素(两个WordPair对象): (hi, there)(hi, bye)
System.out.println(...):向控制台打印内容。
- 当你打印一个
ArrayList时,ArrayList会调用: - 每个元素的
toString()方法来生成字符串, - 然后用逗号+空格分隔,外面再加一对方括号
[]。
- 我们的
WordPair类里重写了toString(),返回"(" + word1 + ", " + word2 + ")"。
- 所以打印结果会是:
- 这两个右大括号依次关闭:
- 最里层
}:结束main方法。 - 外层
}:结束WordPairTest类定义。
从这里开始是第二个类的定义:
- 定义一个类
WordPair,注意这里 没有写public,所以它是包可见(同一个包里可以访问,别的包看不到)。
- 这个类用来表示“一对单词”。
- 定义两个实例变量(成员变量):
word1:存第一 个单词。word2:存第二个单词。
private:封装性,这两个变量外部类不能直接访问,只能通过方法(getter)访问。
String:表示用字符串类型存单词。
这是
WordPair 的构造方法:- 方法名和类名相同
WordPair,说明这是构造器。
public:外部可以用new WordPair(...)来创建对象。
- 参数列表:
(String word1, String word2): - 调用构造方法时需要提供两个字符串。
- 方法体内部:
this.word1 = word1;- 左边
this.word1:当前对象的成员变量word1。 - 右边
word1:方法参数。 - 等式含义:把传进来的参数赋值给当前对象的成员变量。
this.word2 = word2;同理。
- 为何要用
this? - 因为参数名和成员变量名相同,用
this.word1区分“对象里的那个”。
- 这是一个 getter 方法。
public:外部可以调用。
- 返回类型是
String。
- 方法名
getFirst():语义上表示“获得第一个单词”。
- 方法体只有一句:
return word1; - 返回当前对象的
word1。
- 同样是 getter。
- 返回当前对象的
word2。
public String toString():- 这是从
Object类继承来的方法,这里进行了重写(override)。 - 当你打印对象(
System.out.println(obj))或者把对象拼接到字符串时,会自动调用toString()。
- 方法体:
- 用字符串拼接,把两个单词包装成一个形如
(hi, there)的字符串。 - 如果
word1 = "hi",word2 = "there",那么toString()返回:"(hi, there)"。
- 最后的
}:结束WordPair类。
总结一下整体运行流程
- 程序从
main方法开始执行。
- 创建一个
ArrayList<WordPair>叫pairs。
- 向
pairs里添加两个WordPair对象: "hi", "there""hi", "bye"
System.out.println(pairs):ArrayList调用每个WordPair的toString(),得到:(hi, there)和(hi, bye)。- 然后组合成:
[(hi, there), (hi, bye)]打印出来。
Project 4.9.10.
先给你一个整体图,然后重点讲你关心的「打印部分」是怎么一步一步工作的。
一、整体在干什么?
这段代码一共两个类:
WordPairsList:负责生成并保存一堆单词对,以及统计相同单词对的个数。
WordPair:代表一对单词,比如(Hi, there)。
main 方法里:做了三件事:
- 定义一个
String[]数组words。
- 用这个数组创建一个
WordPairsList对象list。
System.out.println(list);打印这个对象。
二、构造方法:生成所有有序单词对 (i < j)
allPairs是一个ArrayList<WordPair>:里面存的每一个元素都是一个WordPair对象。
- 外层循环:
i从 0 到words.length - 1
- 内层循环:
j从i + 1到words.length - 1
- 条件
j = i+1保证 永远 i < j,所以不会出现(words[1], words[0])这种“逆序”,也不会出现(words[0], words[0])这种自己跟自己配对。
对于
{"Hi", "there", "Tyler", "Sam"},索引和单词是:- 0 → "Hi"
- 1 → "there"
- 2 → "Tyler"
- 3 → "Sam"
两层循环生成的配对顺序是:
i = 0:j = 1→(words[0], words[1])=(Hi, there)j = 2→(Hi, Tyler)j = 3→(Hi, Sam)
i = 1:j = 2→(there, Tyler)j = 3→(there, Sam)
i = 2:j = 3→(Tyler, Sam)
一共 6 个
WordPair 对象,依次被加进 allPairs 里。三、WordPair 类做了什么?
一个
WordPair 就是“两件事”:- 保存两个字符串:
word1/word2
- 知道自己如何打印:
toString()返回"(" + word1 + ", " + word2 + ")"的格式
比如:
会调用
p.toString(),输出:四、最关键:System.out.println(list); 到底发生了什么?
来拆开:
这行代码的逻辑是:
println要把list变成字符串 → 会自动调用list.toString()。
- 所以这行代码等价于:
看
WordPairsList 的 toString():也就是说:
list.toString()其实就是调用allPairs.toString()。
再往下一层:
allPairs 是一个 ArrayList<WordPair>。ArrayList 自己有一个内置的 toString() 实现,大致是这样的效果:核心点:
ArrayList 在转成字符串时,会调用每个元素自己的 toString() 方法。
而我们的元素类型是
WordPair,所以会依次调用每个 WordPair 的 toString():于是整个调用链是:
System.out.println(list);
- → 调用
list.toString()
- → 返回
allPairs.toString()
- →
ArrayList的toString()把每个WordPair转成字符串
- → 每个
WordPair用自己的toString()格式化成(word1, word2)
- 最终结果变成一个大字符串:
所以你在控制台看到的大约就是这一行(顺序如上)。
五、numMatches() 方法在干什么?
虽然你重点问打印,我顺带把这个也讲清楚,你以后写第二部分题目会用到。
含义:
- 遍历
allPairs里的每一个WordPair: wp.getFirst()取word1wp.getSecond()取word2
- 如果两个字符串
.equals(),说明这对是(x, x),也就是两个单词一样,就把count加 1。
- 最后返回这样的配对个数。
在当前的
words = {"Hi", "there", "Tyler", "Sam"} 情况下:- 生成的 6 个 pair 里,没有任何一个是
(同一个单词, 同一个单词),
- 所以
numMatches()会返回0。
如果你改一改
words,比如:生成的 pair 是:
- (Hi, Hi)
- (Hi, Sam)
- (Hi, Sam)
此时:
(Hi, Hi)计数一次
(Hi, Sam)不计
(Hi, Sam)不计
那么
numMatches() 返回就是 1。六、你可以自己验证一下打印结果
如果在
main 里把 numMatches() 的测试也打开:输出大概是:
七、总结一下打印逻辑的“调用链”
用一条线帮你记忆:
如果你愿意,我也可以帮你把这一整段改成“手动打印”的版本,比如用
for 循环一个个打印 WordPair,这样你会对 toString() 和 println 的关系更有感觉。第二次月考23题
- 作者:现代数学启蒙
- 链接:https://www.math1234567.com/article/codeexplained49
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
相关文章





