20145230《Java程序设计》第4周学习总结
20145230《Java程序设计》第4周学习总结
教材学习内容总结
继承共同行为
本周学习的首先是Java语言中的继承与多态。何为我们的继承呢?在我们面向对象中,子类继承父类,避免重复的行为定义,不过并非为了避免重复定义行为就使用继承,滥用继承可能导致程序维护上的问题,继承基本上就是避免多个类间重复定义共同行为。下面我们来看代码:
package cc.openhome;
public class Role {
private String name;
private int level;
private int blood;
public int getBlood()
return blood;
}
public void setBlood(int blood) {
this.blood = blood;
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
我们注意到private成员是可以继承的,只不过子类无法直接存取而已,必须通过父类提供的方法来存取。
多态与is-a###
is-a,顾名思义,就是"是一种"的意思,在前面看到的范例中,SwordsMan和Magician都继承了Role,它们都是Role的子类,即它们都是一种Role。下面是代码:
package cc.openhome;
public class RPG {
public static void main(String[] args) {
SwordsMan swordsMan = new SwordsMan();
swordsMan.setName("Justin");
swordsMan.setLevel(1);
swordsMan.setBlood(200);
Magician magician = new Magician();
nagician.setName("Monica");
magician.setLevel(1);
magician.setBlood(100);
showBlood(swordsMan);
showBlood(magician);
}
static void showBlood(Role role) {
System.out.printf("%S 血量 %d%n", role, getName(), role.getBlood())
}
}
重新定义行为###
在继承父类之后,定义与父类中相同的方法部署,但执行内容不同,这称为重新定义。因为
对父类中已定义的方法执行不满意,所以在子类中重新定义执行。SwordsMan和Magician继承了Role后,也重新定义了fight()行为。下面是部分代码:
package cc.openhome;
public class SwordsMan extends Role{
public void fight(){
System.out.println("挥剑攻击");
}
}
抽象方法和抽象类
如果某方法区块中真的没有任何程序代码操作,可以直接使用abstract标示该方法为抽象方法,该方法不用撰写{}区块,直接";"结束即可。子类如果继承抽象类,对于抽象方法有两种做法,一种做法是继续标示该方法为abstract,另一种做法就是操作抽象方法。特别注意的是:如果两种做法都没有实施,那么就会引发编译错误。
构造函数
如果类有继承关系,在创建子类实例后,会先进行父类定义的初始流程,再进行子类中定义的初始流程,再执行子类构造函数定义的流程。父类中可重载多个构造函数,如果子类构造函数中没有指定执行父类中哪个构造函数,默认会调用父类中无参数构造函数。
再看final关键字
前面我们知道,如果变量值确定以后,不再想改变变量值,我们可以加上final限定,如果在后续撰写程序时,不经意想修改final变量,就会出现编译错误。如果class前使用了final关键字定义,那么这个类将不会有子类,也不能被继承。如果尝试在继承父类后,重新定义final方法,则会发生编译错误。
java.lang.Object
在java中,子类只能继承一个父类,如果定义时没有使用extends关键字指定继承任何类,那一定继承java.lang.Objecta。如果要收集对象,可通过add()的方法,如果想取得收集的对象,可以使用get()指定索引取得。如果想知道已收集对象个数,则通过size()的方法获得。下面是收集访客名称的代码:
package cc.openhome;
import java.util.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());
}
}
}
接口定义行为
接口可以用于定义行为但不定义操作,对象若想拥有Swimmer定义的行为,就必须操作Swimmer接口。类操作接口,必须使用implementa关键字。操作某接口时,对接口中定义的方法有两种处理方式,医师操作接口中定义的方法,二是再度将该方法标示为abstract。操作接口表示"拥有行为",但不会有"是一种"的关系。下面是部分代码:
public class Submarine implements Swimmer {
private String name;
public Submarine(String name){
this.name=name;
}
public String getName(){
return name;
}
@Override
public void swim(){
System.out.printf("潜水艇 %s 潜行%n",name);
}
}
行为与多态
只要是操作Swimmer接口的对象,都可以使用doSwim()的方法,Anemonefish、Shark、Human、Submarine等,都操作了Swimmer接口。只要对象拥有Swimmer行为,都不用撰写新的方法,可维护性提高了很多。
匿名内部类
写Java程序时,经常会有临时继承某个类或操作某个接口并建立实例的需求。由于这类子类或接口操作类只使用一次,不需要为这些类定义名称,这时可以使用匿名内部类来解决这个需要。以下是代码举例:
package cc.openhome;
public class Client{
public final String ip;
public final String name;
public Client(String ip,String name){
this.ip=ip;
this.name=name;
}
}
使用enum枚举常数
enum定义了特殊的类,继承自"java.lang.Enum",不过这是由编译程序处理,直接撰写程序继承Enum类会被编译程序拒绝。要注意的是,enum实际上定义了类,而enum中列举的常数,实际上是public static final,且为枚举类型实例,无法撰写程序直接实例化枚举类型,因为构造函数权限设定为private,只有类中才可以实例化。下面是enum语法的举例:
package cc.openhome;
public enum Action{
STOP,RIGHT,LEFT,UP,DOWN
}
教材学习中的问题和解决过程
问题
我在学习第六章的多态与"is-a"时遇到了这样的问题。Role role1=new SwordsMan();Role role2=new Magician();
这样的代码可以通过编译,但是,SwordsMan swordMan=new Role(); Magician magician=new Role();
却无法通过编译。
解决方法
我仔细看了这一块介绍的知识,大概就是一种继承的问题。举个通俗一点的例子,就是这里的=号并不是相等的意思,而是"is-a"的意思。我们可以说鲨鱼是一种鱼,小丑鱼是一种鱼,但反过来说鱼是一种鲨鱼则显得不妥,这种逻辑问题编译就不能通过。SwordsMan是一种Role,但Role不一定是一种SwordsMan。
代码调试中的问题和解决过程
问题
我在敲代码的过程中遇到了类似这样的问题:
解决方法
我通过询问同学才知道,书中的package cc.openhome是编书作者的一个包,而在我的idea上并没有这个包,所以我就重新建了一个cc.openhome的文件夹,解决了这个问题。下面那个Guest的问题是因为我建的C-class的名字和class下的Guest不符合,所以出现了编译失败的问题,我又只能修改C-class的名字才能解决。
本周代码托管截图
其他(感悟、思考等,可选)
这个星期我学习了第6、7章的java,自己学到了很多东西。上两章是"对象"的序幕,那么这两章则是对"对象"这个概念的深入介绍。而且这两章书中所举的例子都十分生动,有设计简单游戏的,也有举海洋动物的例子的。这样在我看来就十分好,代码是活的东西,它就应该像游戏一样让人开怀大笑,像动物一样栩栩如生。往往我们会对成百上千行的代码感到枯燥无味,那是因为我们没有了解它背后的内涵。这两章内容是对继承和接口的介绍,让我知道了父类和子类是不能颠倒的,也让我知道了接口表示的只是一种"拥有行为"。但我觉得自己还是不够认真,总把事情拖到最后来完成,要是自己能更加主动一点去学习就好了,想必这也是老师要教给我们的吧。希望下周自己能更加积极一点学习,客服拖延症!
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 2000行 | 25篇 | 400小时 | |
第一周 | 100/100 | 2/2 | 20/20 | 编写了HELLO WORLD程序 |
第二周 | 100/200 | 2/4 | 20/40 | 了解了Java基本语法 |
第三周 | 50/250 | 1/5 | 20/60 | 了解了对象封装问题 |
第四周 | 564/814 | 2/7 | 30/90 | 了解了继承、接口与多态的问题 |