20145214 《Java程序设计》第4周学习总结
教材学习内容总结
继承
继承基本上就是避免多个类间重复定义共同行为。要避免在程序设计上出现重复,可以把相同的程序代码提升为父类。
关键字
extends
的用法:A extends B
表示A会扩充B的行为,A继承了B的行为,也可以在A的程序中继续扩充B原本没有的行为。-
关于继承的代码如下。
public class RPG1
{
public static void main (String[] args)
{
demoSwordsMan();
demoMagician();
}
static void demoSwordsMan()
{
SwordsMan1 swordsMan1 = new SwordsMan1();
swordsMan1.setName("Justin");
swordsMan1.setLevel(1);
swordsMan1.setBlood(200);
System.out.printf("剑士 : (%s, %d, %d)%n",swordsMan1.getName(),
swordsMan1.getLevel(),swordsMan1.getBlood());
}
static void demoMagician()
{
Magician1 magician = new Magician1();
magician.setName("Moinca");
magician.setLevel(1);
magician.setBlood(100);
System.out.printf("魔法师 :(%s ,%d ,%d)%n",magician.getName(),
magician.getLevel(),magician.getBlood()); }
} 运行结果如下。
-
子类和父类之间有 is-a 的关系,检查语法逻辑是否正确的方法是看等号的右边类是不是左边类的子类。通过使用 is-a 规则,可以避免使用重载的繁琐,使程序具有更高的可维护性。代码如下。
public class RPG2
{
public static void main(String[] args)
{
SwordsMan1 swordsMan = new SwordsMan1();
swordsMan.setName("Justin");
swordsMan.setLevel(1);
swordsMan.setBlood(200); Magician1 magician = new Magician1();
magician.setName("Monica");
magician.setLevel(1);
magician.setBlood(100); showBlood(swordsMan);
showBlood(magician); }
static void showBlood(Role1 role)
{
System.out.printf("%s 血量 %d%n",role.getName(),role.getBlood());
}
} 运行结果如下。
-
子类在继承父类之后,定义与父类中相同的方法部署,但执行内容不同,这称为重新定义。要注意重新定义父类中某个方法时,子类必须撰写与父类中相同的签署。代码如下。
public class RPG3
{
public static void main(String[] args)
{
SwordsMan3 swordsMan3 = new SwordsMan3();
swordsMan3.setName("Justin");
swordsMan3.setLevel(1);
swordsMan3.setBlood(200); Magician3 magician3 = new Magician3();
magician3.setName("Monica");
magician3.setLevel(1);
magician3.setBlood(100); drawFight(swordsMan3);
drawFight(magician3); }
static void drawFight(Role3 role)
{
System.out.print(role.getName());
role.fight3();
}
} 运行结果如下。
内建的标准标注为
@Override
,表示要求编译程序检查该方法是不是真的重新定义了父类中某个方法。若某方法区块中没有任何程序代码操作,则可用
abstract
标示该方法为抽象方法,直接";"
结束即可,表示这个类定义不完整。
继承语法
如果父类中数据成员被定义为
private
无法直接在子类中存取,又不想开放访问权限时,可以定义这些数据成员为protected
。被声明为
protected
的成员,相同包中的类可以直接存取,不同包中的类可以在继承后的子类直接存取。Java*有四个权限范围:
private
,无关键字
,protected
,public
,权限依次从小到大。如果想取得父类中的方法定义,可以在调用方法前,加上
super
关键字,使用super
关键字调用的父类方法,不能定义为private
。如果想执行父类中某构造函数,可以使用
super()
指定。子类构造函数中没有指定执行父类中哪个构造函数,默认会调用父类中无参数构造函数。如果
class
前使用了final
关键字,表示这个类是最后一个,不会再有子类,也就是不能被继承。-
使用数组收集各种对象,可声明为
Object[]
类型,不限长度地收集对象代码如下。import java.util.Arrays; public class ArrayList {
private Object[] list;
private int next; public ArrayList(int capacity)
{
list=new Object[capacity];
} public ArrayList() {
this(16);
} public void add(Object o) {
if(next==list.length) {
list=Arrays.copyOf(list, list.length*2);
}
list[next++]=o;
}
public Object get(int index) {
return list[index];
} public int size() {
return next;
}
} -
使用上述自定义的
Arraylist
类,收集访客名称,并将名单转为大写后显示的代码如下。import java.util.Scanner;
import static java.lang.System.out; public class Guest {
public static void main(String[] args) {
ArrayList names=new ArrayList();
collectNameTo(names);
out.println("访客名单:");
printUpperCase(names);
} static void collectNameTo(ArrayList names) {
Scanner console=new Scanner(System.in);
while(true) {
out.print("访客名称:");
String name=console.nextLine();
if(name.equals("quit")) {
break;
}
names.add(name);
}
} static void printUpperCase(ArrayList names) {
for(int i=0;i<names.size();i++) {
String name=(String) names.get(i);
out.println(name.toUpperCase());
}
}
} 运行结果如下。
执行流程中,无法通过变量参考的对象,就是JVM垃圾收集机制认定的垃圾对象。
在取得用户输入、显示结果的环境未定时,可以通过设计来解决。以猜数字游戏为例,可以将此程序分为
GuessGame.java
、ConsoleGame.java
和Guess.java
三个部分。最后程序执行结果如下。
接口
对于定义行为,可以使用
interface
关键字定义,接口中的方法不能操作,直接标示为abstract
,而且一定是public
。类要操作接口,必须使用
implements
关键字。-
操作同一个接口,提高可维护性的代码如下。
public class Ocean{
public static void main(String[] args)
{
doSwim(new Anemonefish("尼莫"));
doSwim(new Shark("兰尼"));
doSwim(new Human("贾斯汀"));
doSwim(new Submarine("黄色一号"));
} static void doSwim(Swimmer swimmer){
swimmer.swim();
}
} 运行结果如下。
类与接口之间是实现关系,而且类可以继承一个类的同时实现多个接口,接口与接口之间可以有继承关系。各个类与接口代码已托管至开源中国,程序运行结果如下。
接口语法
可使用
interface
来定义抽象的行为与外观,接口中的方法没有操作时,一定得是公开且抽象,此时可以省略public abstract
。-
使用匿名内部类,直接建立操作对象代码如下。
public class MultiChat{
public static void main(String[] args){
Client c1=new Client("127.0.0.1","Caterpillar");
Client c2=new Client("192.168.0.2","Justin"); ClientQueue queue=new ClientQueue();
queue.addClientListener(new ClientListener(){
@Override
public void clientAdded(ClientEvent event){
System.out.printf("%s 从 %s 联机%n",
event.getName(),event.getIp());
}
@Override
public void clientRemoved(ClientEvent event){
System.out.printf("%s 从 %s 脱机%n",
event.getName(),event.getIp());
}
});
queue.add(c1);
queue.add(c2);
queue.remove(c1);
queue.remove(c2);
}
} 运行结果如下。
-
enum
语法可用于定义枚举常数。enum
定义了特殊的类,直接撰写程序继承Enum
类会被编译程序拒绝。对enum
的使用代码如下。import static java.lang.System.out;
public class Game2{
public static void main(String[] args){
play(Action2.RIGHT);
play(Action2.UP);
}
public static void play(Action2 action){
switch(action){
case STOP:
out.println("播放停止动画");
break;
case RIGHT:
out.println("播放向右动画");
break;
case LEFT:
out.println("播放向左动画");
break;
case UP:
out.println("播放向上动画");
break;
case DOWN:
out.println("播放向下动画");
break;
}
}
} 运行结果如下。
代码调试中的问题和解决过程
- 问题:如果没有使用IDEA,还有什么方法可以让有继承和接口的程序正确执行?
- 解决:尚未解决。
开源中国代码托管截图如下
其他(感悟、思考等,可选)
进入java学习的第四周,完成每一周的学习任务已经成为一种习惯了,学会了怎样在周一发布学习任务后到周日提交博客前合理地分配学习时间,不会再像之前把任务都堆积到周末完成。这样的学习模式让我每一天过得更充实了。自己动手敲代码,让代码成功运行也成为了一种乐趣。本周还学会了统计代码行数,这让我对自己的学习情况有了量化指标的掌握,也更有了满足感。
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第一周 | 200/200 | 2/2 | 20/20 | |
第二周 | 300/500 | 1/3 | 20/40 | |
第三周 | 400/900 | 1/4 | 25/65 | |
第四周 | 1236/2136 | 1/5 | 30/95 |