以下为个人学习笔记和习题整理
课程:面向对象程序设计 ——Java 语言
- 浙江大学 - 翁恺 @ 中国大学 MOOC
https://www.icourse163.org/course/ZJU-1001542001
# 课堂笔记
# Swing
# 布局管理器
部件 button
容器 frame
部件可以被放在容器里,容器本身也是一种部件。
布局管理器 BorderLayout
来管理部件的大小、位置等。BorderLayout
类把容器分为五个部分,分别是 NORTH
、 SOUTH
、 EAST
、 WEST
、 CENTER
(默认),同一个位置,同一个时间,只能有一个部件。并根据内容来计算布局长宽。
# 事件机制 addActionListener
Swing 使用一个非常灵活的模型来处理 GUI 的输入:采用事件监听器的事件处理 (event handling) 模型。
Swing 框架本身以及大部分部件在发生一些情况时会触发相关的事件,而其他的对象也许会对这些事件感兴趣。
不同类型的动作会导致不同类型的事件。
当点击一个按钮或选中一个菜单项,部件就会触发动作事件;而当点击或移动鼠标时,会触发鼠标事件;当框架被关闭或最小化时,会触发窗口事件。另外还有许多种其他事件。
所有的对象都可以成为任何这些事件的监听器,而一旦成为监听器,就可以得到这些事件触发的通知。
实现了众多监听器接口之一的对象就成为一个事件监听器。
如果对象实现了恰当的接口,就可以注册到它想监听的组件上。
# 匿名类
在 new
对象的时候给出的类的定义形成了匿名类。
匿名类可以继承某类,也可以实现某接口。
Swing 的消息机制广泛使用匿名类。
# 内部类
内部类就是指一个类定义在另一个类的内部,从而成为外部类的一个成员。
因此一个类中可以有成员变量、方法,还可以有内部类。
实际上 Java 的内部类可以被称为成员类,内部类实际上是它所在类的成员。
所以内部类也就具有和成员变量、成员方法相同的性质。
比如,成员方法可以访问私有变量,那么成员类也可以访问私有变量了。
也就是说,成员类中的成员方法都可以访问成员类所在类的私有变量。
内部类最重要的特点就是:能够访问外部类的所有成员,包括任何私有的成员。
也可以定义在函数内部。
外部是函数时,只能访问那个函数里 final
的变量
# MVC 模式
数据、表现和控制三者分离,各负其责。Model
模型
保存和维护数据,提供接口让外部修改数据
通知表现,需要刷新
View
表现
从模型获得数据,根据数据画出表现
Control
控制
从用户得到输入,根据输入调整数据
用户在界面上的操作,不直接显示
# 课内项目
# 注入反转
由按钮公布一个守听者接口和一对注册 / 注销函数。
你的代码实现那个接口,将守听者对象注册在按钮上。
一旦按钮被按下,就会反过来调用你的守听者对象的某个函数。
例子:狐狸与兔子添加步进按钮
package FoxAndRabbit; | |
import field.Field; | |
import field.View; | |
import field.Location; | |
import java.awt.BorderLayout; | |
import java.awt.event.ActionEvent; | |
import java.awt.event.ActionListener; | |
import java.util.ArrayList; | |
import javax.swing.JFrame; | |
import javax.swing.JButton; | |
import animal.Fox; | |
import animal.Rabbit; | |
import animal.Animal; | |
import cell.Cell; | |
public class FoxAndRabbit{ | |
private Field thefield; | |
private View theview; | |
private JFrame frame; | |
/** | |
* 内部类 StepListener | |
*/ | |
private class StepListener implements ActionListener { | |
@Override | |
public void actionPerformed(ActionEvent e) { | |
step(); | |
frame.repaint(); | |
} | |
} | |
public FoxAndRabbit( int size ){ | |
thefield = new Field(size, size); | |
for( int row = 0; row <thefield.getHeight(); row++ ){ | |
for( int col = 0; col < thefield.getWidth(); col++ ){ | |
double probability = Math.random(); | |
if( probability <0.05 ){ | |
thefield.place( row, col, new Fox()); | |
}else if( probability < 0.15 ){ | |
thefield.place( row, col, new Rabbit()); | |
} | |
} | |
} | |
theview = new View(thefield); | |
frame = new JFrame(); | |
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); | |
frame.setResizable(false); | |
frame.setTitle("FoxAndRabbit"); | |
frame.add(theview, BorderLayout.CENTER); | |
// 添加一个按钮 | |
JButton btnStep = new JButton("单步"); | |
frame.add(btnStep, BorderLayout.NORTH); | |
// 按钮绑定事件,方法 1:匿名类 | |
// btnStep.addActionListener(new ActionListener() { | |
// @Override | |
// public void actionPerformed(ActionEvent e) { | |
// System.out.println ("按下啦!"); | |
// step(); | |
// frame.repaint(); | |
// } | |
// }); | |
// 按钮绑定事件,方法 2:内部类 | |
btnStep.addActionListener(new StepListener()); | |
frame.pack(); | |
frame.setVisible(true); | |
} | |
public void step(){ | |
for( int row = 0; row < thefield.getHeight(); row++ ){ | |
for( int col = 0; col < thefield.getWidth(); col++ ){ | |
Cell cell = thefield.get(row, col); | |
if( cell != null ){ | |
Animal animal = (Animal)cell; | |
animal.grow(); | |
if( animal.isAlive()){ | |
//move | |
Location loc = animal.move(thefield.getFreeNeighbour(row, col)); | |
if( loc != null ){ | |
thefield.move(row, col, loc); | |
} | |
//eat animal.eat(thefield); | |
if( animal instanceof Fox){ | |
Cell[] neighbour = thefield.getNeighbour(row, col); | |
ArrayList<Animal> listRabbit = new ArrayList<Animal>(); | |
for( Cell an : neighbour ){ | |
if( an instanceof Rabbit ){ | |
listRabbit.add( (Rabbit)an ); | |
} | |
} | |
if( !listRabbit.isEmpty() ){ | |
Animal fed = animal.feed(listRabbit); | |
if( fed != null ){ | |
thefield.remove((Cell)fed); | |
} | |
} | |
} | |
//breed | |
Animal baby = animal.breed(); | |
if( baby != null ){ | |
thefield.placeRandomAdj(row, col, (Cell)baby); | |
} | |
}else{ | |
thefield.remove(row, col); | |
} | |
} | |
} | |
} | |
} | |
public void start( int steps ){ | |
for( int i = 0; i < steps; i++){ | |
step(); | |
theview.repaint(); | |
try{ | |
Thread.sleep(200); | |
}catch (InterruptedException e){ | |
e.printStackTrace(); | |
} | |
} | |
} | |
public static void main(String[] args) { | |
FoxAndRabbit fnr = new FoxAndRabbit(30); | |
//fnr.start(10); | |
} | |
} |
# 课程表
用 JTable
类可以以表格的形式显示和编辑数据。JTable
类的对象并不存储数据,它只是数据的表现。
package kcb; | |
import javax.swing.JFrame; | |
import javax.swing.JScrollPane; | |
import javax.swing.JTable; | |
public class KCB { | |
public static void main(String[] args) { | |
JFrame frame = new JFrame(); | |
JTable table = new JTable(new KCBData()); | |
JScrollPane pane = new JScrollPane(table); | |
frame.add(pane); | |
frame.pack(); | |
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); | |
frame.setVisible(true); | |
} | |
} |
package kcb; | |
import javax.swing.event.TableModelListener; | |
import javax.swing.table.TableModel; | |
public class KCBData implements TableModel { | |
private String[] title = { "周一", "周二", "周三", "周四", "周五", "周六", "周日" }; | |
private String[][] data = new String[8][7]; | |
public KCBData() { | |
for (int i = 0; i < data.length; i++) { | |
for (int j = 0; j < data[i].length; j++) { | |
data[i][j] = ""; | |
} | |
} | |
} | |
@Override | |
public void addTableModelListener(TableModelListener arg0) { | |
// TODO Auto-generated method stub | |
} | |
@Override | |
public Class<?> getColumnClass(int arg0) { | |
return String.class; | |
} | |
@Override | |
public int getColumnCount() { | |
return 7; | |
} | |
@Override | |
public String getColumnName(int arg0) { | |
return title[arg0]; | |
} | |
@Override | |
public int getRowCount() { | |
return 8; | |
} | |
@Override | |
public Object getValueAt(int arg0, int arg1) { | |
// TODO Auto-generated method stub | |
return data[arg0][arg1]; | |
} | |
@Override | |
public boolean isCellEditable(int arg0, int arg1) { | |
// TODO Auto-generated method stub | |
return true; // 可以被编辑 | |
} | |
@Override | |
public void removeTableModelListener(TableModelListener arg0) { | |
// TODO Auto-generated method stub | |
} | |
@Override | |
public void setValueAt(Object arg0, int arg1, int arg2) { | |
// TODO Auto-generated method stub | |
data[arg1][arg2] = (String) arg0; | |
} | |
} |
# 课堂讨论
- 在第 5 周的城堡程序那里,我们做的
Handler
是需要在构造的时候注入Game
的。那么,在学习了内部类之后,能否用Game
的内部类来实现这些Handler
呢?应该怎么做?
package castle; | |
import java.util.HashMap; | |
import java.util.Scanner; | |
public class Game { | |
public abstract class Handler { | |
public abstract void doCmd(String word); | |
public boolean isBye(){ | |
return false; | |
} | |
} | |
public Game() | |
{ | |
// handlers.put("go",new HandlerGo(this)); | |
// handlers.put("bye",new HandlerBye(this)); | |
// handlers.put("help",new HandlerHelp(this)); | |
// createRooms(); | |
handlers.put("go", new Handler() { | |
@Override | |
public void doCmd(String word) { | |
goRoom(word); | |
} | |
}); | |
handlers.put("help", new Handler() { | |
@Override | |
public void doCmd(String word) { | |
System.out.println("迷路了吗?你可以做的命令有go bye help"); | |
System.out.println("如:\tgo east"); | |
} | |
}); | |
handlers.put("bye", new Handler() { | |
@Override | |
public void doCmd(String word) { | |
System.out.println("bye"); | |
} | |
@Override | |
public boolean isBye() { | |
return true; | |
} | |
}); | |
createRooms(); | |
} | |
} |