今天开始随NOVA兴趣组学习CS61B,计划每天记录学习笔记。
2026年3月15日。

checklist:

  • reading 1.1, 1.2
  • lab 0, lab 1
  • hw 0

关于环境搭建(lab0和lab1)

安装java和IntelliJ过程比较顺利,按照lab一步步操作就好了。
一开始下载java 17,会遇到“权限不足无法修改注册表”的问题,解决办法是以管理员身份运行安装程序,或者在安装过程中选择“为所有用户安装”选项。
在IntelliJ中运行java文件时,遇到“无法找到或加载主类”的错误,解决办法是检查运行配置中的工作目录是否正确设置为项目的根目录。这在lab中似乎没有记载,在佳铭的教程里给出了,但我之前没有注意到。这里我还没有完全理解IntelliJ这个工具的使用逻辑。
加入gradescope的时候我想当然地以为学校填南大就行,结果始终没有办法通过。想当然地原因是认为学校名和用户身份绑定,但实际上是和课程码绑定的,(按照我的推测)南京大学名下没有这个课程码对应的课程,所以无法加入课程。所以正确的做法是输入课程码MB7ZPY并在学校一栏填入UC Berkeley。名字,邮箱什么的都不重要。

Reading 1.1

介绍了java的编译和运行过程,java源代码文件以.java结尾,javac编译后生成.class文件,Java解释器运行.class文件。运行时需要指定类名而不是文件名。java的main函数必须是public static void main(String[] args),并且必须包含在一个类中。

java是一种静态类型语言。Java 变量只能包含该类型的值,且仅能包含该类型的值。此外,变量的类型永远不会改变。System.out.print可以在参数中输出数字+字符串,java会自动将数字转换为字符串并连接起来输出。但是,又不能像python那样直接使用*输出一个字符串的多次重复。

java的所有代码都属于某个类。属于类的函数称为方法。因此java中没有全局函数,所有函数都必须包含在一个类中。方法前面有冗长的修饰符,如public static void等,这些修饰符指定了方法的访问权限、是否为静态方法以及返回类型等信息。

java中,尽可能对所有方法和类使用javadoc注释,这些注释以/**开头,以*/结尾,位于方法或类的前面。javadoc注释可以包含标签,如@param和@return,用于描述方法的参数和返回值。

Objects

java是一种面向对象的编程语言,所有数据都是对象。对象是类的实例,类是对象的蓝图。类定义了对象的属性和方法。对象通过调用方法来执行操作。调用一个方法的另一个类可以被称为“client”。类可以被实例化,每个实例有自己的数据成员和方法。类可以有静态成员和方法,这些成员和方法属于类本身,而不是任何实例。一个实例无法自行添加新的属性或方法。
实例化一个类时,必须使用new关键字来创建一个对象,并调用类的构造函数来初始化对象的属性。构造函数是一种特殊的方法,用于创建和初始化对象。构造函数的名称与类名相同,并且没有返回类型。

类方法与实例方法

类方法(静态方法)是属于类本身的方法,可以通过类名直接调用,而不需要创建实例。实例方法(非静态方法)是属于实例的方法,必须通过实例来调用。类方法通常用于执行与类相关的操作,而实例方法用于执行与特定对象相关的操作。我们可以使用this关键字在实例方法中引用当前对象(类似于python中的self)。

1
2
3
4
5
6
public static Dog maxDog(Dog d1, Dog d2) {
if (weightInPounds > d2.weightInPounds) {
return this;
}
return d2;
}

这段代码中,maxDog方法是一个静态方法,没有实例上下文,不能使用this关键字来引用当前对象。

静态变量

静态变量(类变量)是属于类本身的变量,所有实例共享同一个静态变量,因此它不是实例的。实例变量(非静态变量)是属于实例的变量,每个实例都有自己的实例变量。静态变量通常用于存储与类相关的数据,而实例变量用于存储与特定对象相关的数据。我们应该使用类名来访问静态变量,而不是通过实例来访问,虽然java允许通过实例来访问静态变量,但这可能会导致混淆和错误。

public stativ void main(String[] args)

这是java程序的入口点,必须包含在一个类中。public表示该方法可以被任何其他类访问,static表示该方法属于类本身而不是任何实例,void表示该方法没有返回值,main是方法的名称,String[] args是一个字符串数组参数,用于接收命令行参数。

exercise 1.2.3

编写一个程序,计算命令行参数的总和(假设所有参数都是整数)。

1
2
3
4
5
6
7
8
9
public class Sum {
public static void main(String[] args) {
int sum = 0;
for (String arg : args) {
sum += Integer.parseInt(arg);
}
System.out.println(sum);
}
}

使用库

在这个课程中,我们将使用java内建的库,以及一些第三方库,如StdDraw和StdAudio。但是尽量不要额外使用其他库。我们可以查看java的官方文档来了解一些内建库的使用方法。

HW0

学习了JAVA的基础语法。非常奇怪的是所有函数似乎都必须包含在一个类中,所有函数和类的前面都有非常冗长的修饰。
数据类型:INT, DOUBLE, STRING, ARRAY
语法:if-else, for loop, while loop, switch-case, define function, System.out.println, System.out.print

exercise 1a

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static class DrawTriangle {
public static void main(String[] args) {
int n = 5;
while (n > 0) {
int i = 0;
while (i < 6 - n) {
System.out.print("*");
i++;
}
System.out.println();
n--;
}
}
}

exercise 1b

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class DrawTriangle {
public static void DrawTriangle(int n) {
int m = n;
while (n > 0) {
int i = 0;
while (i < m - n + 1) {
System.out.print("*");
i++;
}
System.out.println();
n--;
}
}

public static void main(String[] args) {
DrawTriangle(10);
}
}

exercise 2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class ClassNameHere {
/** Returns the maximum value from m. */
public static int max(int[] m) {
int max = 0;
int i = 0;
while (i < m.length) {
if (m[i] > max) {
max = m[i];
}
i++;
}
return max;
}
public static void main(String[] args) {
int[] numbers = new int[]{9, 2, 15, 2, 22, 10, 6};
System.out.println(max(numbers));
}
}

exercise 3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class ClassNameHere {
/** Returns the maximum value from m using a for loop. */
public static int forMax(int[] m) {
int max = 0;
for (int i : m) {
if (i > max) {
max = i;
}
}
return max;
}
public static void main(String[] args) {
int[] numbers = new int[]{9, 2, 15, 2, 22, 10, 6};
System.out.println(forMax(numbers));
}
}

exercise 4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class BreakContinue {
public static void windowPosSum(int[] a, int n) {
/** your code here */
for(int i = 0; i < a.length - 1; i++) {
int ad = 0;
if (a[i] < 0) continue;
for(int j = 1; j <= n; j++) {
if (i + j < a.length) {
ad += a[i + j];
} else {
break;
}
}
a[i] += ad;
}
}

public static void main(String[] args) {
int[] a = {1, 2, -3, 4, 5, 4};
int n = 3;
windowPosSum(a, n);

// Should print 4, 8, -3, 13, 9, 4
System.out.println(java.util.Arrays.toString(a));
}
}

虽然和C/C++语法几乎没有什么区别,但是这里传入的数组是引用传递的,所以在函数内修改数组会直接修改原数组;这和C/C++不同,但是和python却很像。