以下为个人学习笔记和习题整理
课程:面向对象程序设计 ——Java 语言
- 浙江大学 - 翁恺 @ 中国大学 MOOC
https://www.icourse163.org/course/ZJU-1001542001
# 课堂笔记
容器 collection
或 container
是现代程序设计非常基础而重要的手段。
所谓容器,就是 “放东西的东西”。
数组可以看作是一种容器,但是数组的元素个数一旦确定就无法改变,这在实际使用中是很大的不足。
一般意义上的容器,是指具有自动增长容量能力的存放数据的一种数据结构。
在面向对象语言中,这种数据结构本身表达为一个对象。
所以才有 “放东西的东西” 的说法。
# 顺序容器
即放进容器中的对象是按照指定的顺序(放的顺序)排列起来的,而且允许具有相同值的多个对象存在。
ArrayList<String> notes = new ArrayList<String>; |
容器类有两个类型:
- 容器的类型
ArrayList
- 元素的类型
String
根据下标索引操作 ArrayList
# 对象数组
当数组的元素的类型是类的时候,数组的每一个元素其实只是对象的管理者,而不是对象本身。
因此,仅仅创建数组并没有创建其中的每一个对象!
public class Main { | |
public static void main(String[] args) { | |
int[] ia = new int[10]; | |
String[] a = new String[10]; | |
System.out.println(ia[0]); // 0 | |
System.out.println(a[0]); // null | |
System.out.println(ia[0]+2); // 2 | |
System.out.println(a[0]+"a"); // nulla | |
System.out.println(a[0].length());// 报错 | |
String s = null; | |
System.out.println(s.length()); // 报错 | |
for (int i=0; i<a.length; i++) { | |
a[i] = ""+i; | |
} | |
System.out.println(a[0].length());// 1 | |
} | |
} |
for each
循环
import java.util.ArrayList; | |
class Value { | |
private int i; | |
public void set(int i) { | |
this.i = i; | |
} | |
public int get() { | |
return i; | |
} | |
} | |
public class Main { | |
public static void main(String[] args) { | |
Value[] a = new Value[10]; | |
for (int i=0;i<a.length;i++) { | |
a[i] = new Value(); | |
a[i].set(i); | |
} | |
for (Value v : a) { | |
System.out.println(v.get());// 0 1 2 3 4 5 6 7 8 9 | |
v.set(0); | |
} | |
for (Value v : a) { | |
System.out.println(v.get()); // 0 0 0 0 0 0 0 0 0 0 | |
} | |
ArrayList<String> b = new ArrayList<String>(); | |
b.add("first"); | |
b.add("second"); | |
for (String s : b) { | |
System.out.println(s); // first second | |
} | |
} | |
} |
# 集合容器 set
集合就是数学中的集合的概念:所有的元素都具有唯一的值,元素在其中没有顺序。
import java.util.ArrayList; | |
import java.util.HashSet; | |
class Value { | |
private int i; | |
public void set(int i) { | |
this.i = i; | |
} | |
public int get() { | |
return i; | |
} | |
public String toString() { | |
return ""+i; | |
} | |
} | |
public class Main { | |
public static void main(String[] args) { | |
ArrayList<String> b = new ArrayList<String>(); | |
b.add("first"); | |
b.add("second"); | |
b.add("first"); | |
/*for (String s : b) { | |
System.out.println(s); | |
}*/ | |
System.out.println(b); // [first, second, first] | |
System.out.println("------------"); | |
HashSet<String> s = new HashSet<String>(); | |
s.add("first"); | |
s.add("second"); | |
s.add("first"); // 集合没有重复元素 | |
/*for (String k : s) { | |
System.out.println(k); | |
}*/ | |
System.out.println(s); // [first, second] | |
} | |
} | |
/* | |
first | |
second | |
first | |
------------ | |
first | |
second | |
*/ |
# 散列表 Hash
传统意义上的 Hash
表,是能以 int
做值,将数据存放起来的数据结构。
Java 的 Hash
表可以以任何实现了 hash()
函数的类的对象做值来存放对象。
键是唯一的,如果同一个键被设定了多次值,只保留最后一个。
键和值都必须是对象。
import java.util.HashMap; | |
import java.util.Scanner; | |
public class Coin { | |
private HashMap<Integer, String> coinnames = new HashMap<Integer, String>(); | |
public Coin() { | |
coinnames.put(1,"penney"); | |
coinnames.put(10, "dime"); | |
coinnames.put(25, "quarter"); | |
coinnames.put(50, "half-dolar"); | |
coinnames.put(50, "五毛"); | |
System.out.println(coinnames.keySet().size()); // 4 | |
System.out.println(coinnames); | |
// 遍历,对 key 的集合进行 for each | |
for (Integer k : coinnames.keySet()) { | |
String s = coinnames.get(k); | |
System.out.println(s); | |
} | |
} | |
public String getName(int amount) { | |
if(coinnames.containsKey(amount)) | |
{ | |
return coinnames.get(amount); | |
} | |
else | |
{ | |
return 'NOT FOUND'; | |
} | |
} | |
public static void main(String[] args) { | |
Scanner in = new Scanner(System.in); | |
int amount = in.nextInt(); | |
Coin coin = new Coin(); | |
String name = coin.getName(amount); | |
System.out.println(name); | |
} | |
} |
# 课内项目
# 记事本
功能:
- 能存储记录
- 不限制能存储的记录的数量
- 能知道已经存储的记录的数量
- 能查看存进去的每一条记录
- 能删除一条记录
- 能列出所有的记录
接口设计:add(String note);
getSize();
getNote(int index);
removeNote(int index);
list();
人机交互部分需与业务逻辑分开
package notebook; | |
import java.util.ArrayList; | |
public class NoteBook { | |
// ArrayList of String | |
// 用来存放 String 的一个 ArrayList | |
// ArrayList 是泛型类 | |
private ArrayList<String> notes = new ArrayList<String>(); | |
//private int size = 0; | |
// 添加一条数据 | |
public void add (String s) { | |
notes.add(s); | |
//notes.add (0); // 报错 | |
//size++; | |
} | |
// 加入某个现有元素前面 | |
public void add(String s, int location) { | |
notes.add(location, s); | |
} | |
public int getSize() { | |
//return size; | |
return notes.size(); | |
} | |
// 根据编号获得数据内容 | |
public String getNote(int index) { | |
return notes.get(index); | |
} | |
// 根据编号删除数据内容 | |
public void removeNote(int index) { | |
//return notes.remove (index); // 报错 | |
notes.remove(index); | |
} | |
// 数据列表 | |
public String[] list() { | |
String[] a = new String[notes.size()]; | |
/* | |
* for (int =0; i < notes.size(); i++) { a[i] = notes.get(i) } | |
*/ | |
notes.toArray(a); | |
return a; | |
} | |
public static void main(String[] args) { | |
String[] a = new String[2]; | |
a[0] = "first"; | |
a[1] = "second"; | |
NoteBook nb = new NoteBook(); | |
nb.add("first"); | |
nb.add("second"); | |
nb.add("third", 1); | |
System.out.println(nb.getSize()); | |
System.out.println(nb.getNote(0)); | |
System.out.println(nb.getNote(1)); | |
nb.removeNote(1); | |
String[] b =nb.list(); | |
for(String s : a) { | |
System.out.println(s); | |
} | |
} | |
} |
# 课堂讨论
- 当我们用
add
函数把对象放进容器中去的时候,究竟是把什么放进了容器?放进去的是对象本身吗?放进去以后,那个对象还在外面吗?如果修改了放进去的那个对象,容器中的对象会变化吗?写点代码来验证自己的猜测吧。
- 放进容器的是对象的引用(类似于 C++ 的指针,对象的地址),而非对象本身。
- 对象本身存在堆上,如果已经有变量存储它(实际上存储的也是引用)的话,放进容器后还是可以通过变量访问该对象。
- 修改放进去的对象,
ArrayList
容器的对象也会变化,因为是同一个对象。
但需要注意的是,简单地赋新值给变量,只会让变量关联到一个新的对象上,并没有改变原来的对象;另外,不可变类是不能修改其对象的,比如String
import java.util.ArrayList; | |
import java.util.Arrays; | |
public class Main { | |
public static void main(String[] args) { | |
ArrayList<int[]> list = new ArrayList<int[]>(); | |
int[] array = { 1, 2, 3 }; | |
list.add(array); | |
System.out.println("before modification:"); | |
System.out.println("array: " + array); | |
System.out.println("list.get(0): " + list.get(0)); | |
System.out.println("array: " + Arrays.toString(array)); | |
System.out.println("list.get(0): " + Arrays.toString(list.get(0))); | |
array[0] = 42; | |
System.out.println("\nafter modification:"); | |
System.out.println("array: " + array); | |
System.out.println("list.get(0): " + list.get(0)); | |
System.out.println("array: " + Arrays.toString(array)); | |
System.out.println("list.get(0): " + Arrays.toString(list.get(0))); | |
} | |
} | |
/* | |
before modification: | |
array: [I@7852e922 | |
list.get(0): [I@7852e922 | |
array: [1, 2, 3] | |
list.get(0): [1, 2, 3] | |
after modification: | |
array: [I@7852e922 | |
list.get(0): [I@7852e922 | |
array: [42, 2, 3] | |
list.get(0): [42, 2, 3] | |
*/ |
- 如何设计能传递任意数量参数的函数?
在定义方法时,在最后一个形参后加上三点
...
,就表示该形参可以接受多个参数值,多个参数值被当成数组传入。
上述定义有几个要点需要注意:
- 可变参数只能作为函数的最后一个参数,但其前面可以有也可以没有任何其他参数;
- 由于可变参数必须是最后一个参数,所以一个函数最多只能有一个可变参数;
- Java 的可变参数,会被编译器转型为一个数组。
public static int max(int... value) { | |
int max = Integer.MIN_VALUE; | |
for ( int k : value) { | |
if ( k>max ) { | |
max = k; | |
} | |
} | |
return max; | |
} | |
public static void main(String[] args){ | |
System.out.print(max(1,2,3,4,5,6,7,8,9,6,5,4,12,3,3)); | |
} | |
// 输出:12 |
- 集合能用
get()
函数来获得某个位置上的元素吗?
不能。
首先在 Java 的HashSet
类中没有定义get()
方法,调用无效;
其次,作为数学意义上的具有无序性的集合,试图以线性的索引去获取其中的值是毫无意义的。
- 学生成绩的数据结构
如果要写程序表达一个班级的很多个学生的很多门课的成绩,应该如何表达这些数据?
如果我们希望通过学生的姓名,可以找到他的所有的成绩,而每一门课的成绩,是由课程名称和分数构成的。
而如果我们还希望这个程序能找出某一门课的全部学生的成绩应该怎样做呢?
注意,并非所有的学生都参加了所有的课程。
import java.util.HashMap; | |
import java.util.Scanner; | |
public class ScoreTable { | |
// student name - course name, score | |
private HashMap<String, HashMap<String, Integer>> students = new HashMap<>(); | |
public void add(String student, String course, Integer score) { | |
HashMap<String, Integer> record; | |
if(students.containsKey(student)) { | |
record = students.get(student); | |
} else { | |
record = new HashMap<String, Integer>(); | |
} | |
record.put(course, score); | |
students.put(student, record); | |
} | |
public String getByStudent(String student) { | |
String records = ""; | |
String comma = ""; | |
if(students.containsKey(student)) { | |
HashMap<String, Integer> record = students.get(student); | |
for (String course : record.keySet()) { | |
records += comma + "科目" + course + "的成绩:" + record.get(course); | |
comma = "\n"; | |
} | |
} | |
return recordFilter(records); | |
} | |
public String getByCourse(String course) { | |
String records = ""; | |
String comma = ""; | |
for (String student : students.keySet()) { | |
HashMap<String, Integer> record = students.get(student); | |
if(record.containsKey(course)) { | |
records += comma + "学生" + student + "的成绩:" + record.get(course); | |
comma = "\n"; | |
} | |
} | |
return recordFilter(records); | |
} | |
private String recordFilter(String s) { | |
return s.length() > 0? s:"没有记录"; | |
} | |
public static void main(String[] args) { | |
ScoreTable s = new ScoreTable(); | |
Scanner in = new Scanner(System.in); | |
String student; | |
String course; | |
int score; | |
GO: | |
while (true) { | |
System.out.println("输入数据请输入'1'"); | |
System.out.println("学生查询请输入'2'"); | |
System.out.println("课程查询请输入'3'"); | |
System.out.println("~~退出请输入'0'~~"); | |
int jd = in.nextInt(); | |
switch (jd) { | |
case 0: | |
break GO; | |
case 1: | |
System.out.println("请输入姓名,课程,成绩:"); | |
student = in.next(); | |
course = in.next(); | |
score = in.nextInt(); | |
s.add(student, course, score); | |
break; | |
case 2: | |
System.out.println("请输入姓名:"); | |
student = in.next(); | |
System.out.println(s.getByStudent(student)); | |
break; | |
case 3: | |
System.out.println("请输入课程:"); | |
course = in.next(); | |
System.out.println(s.getByCourse(course)); | |
break; | |
} | |
} | |
in.close(); | |
} | |
} |