首页 > 技术文章 > 20145230《Java程序设计》第4周学习总结

kobe20145230 2016-03-27 23:04 原文

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 了解了继承、接口与多态的问题

参考资料

推荐阅读