20145219 《Java程序设计》第04周学习总结

20145219 《Java程序设计》第04周学习总结

教材学习内容总结

继承

  • 继承就是避免多个类间重复定义共同行为。

  • 面向对象中,子类继承父类,就是把程序中相同的代码部分提升为父类。

    Role.java

      package ch6;
      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;
          }
      
      }
    

    SwordaMan.java

      package ch6;
      public class SwordsMan extends Role
      {
          public void fight()
          {
              System.out.println("剑士攻击");
          }
      }
    
  • extends关键字,表示前者会扩充后者的行为,即继承后者的行为。fight()为SwordsMan扩充的Role没有的行为。

    Magician.java

      package ch6;
      public class Magician extends Role
      {
          public void fight()
          {
              System.out.println("魔法攻击");
          }
          public void cure()
          {
              System.out.println("魔法治疗");
          }
      }
    

    RPG.java

      package ch6;
      public class RPG
      {
          public static void main (String[] args)
          {
              demoSwordsMan();
              demoMagician();
          }
          static void demoSwordsMan()
          {
              SwordsMan swordsMan = new SwordsMan();
              swordsMan.setName("Justin");
              swordsMan.setLevel(1);
              swordsMan.setBlood(200);
              System.out.printf("剑士:(%s,%d,%d)%n",swordsMan.getName(),
                      swordsMan.getLevel(),swordsMan.getBlood());
          }
          static void demoMagician()
          {
              Magician magician = new Magician();
              magician.setName("Moinca");
              magician.setLevel(1);
              magician.setBlood(100);
              System.out.printf("魔法师:(%s,%d,%d)%n",magician.getName(),
                      magician.getLevel(),magician.getBlood());
      
          }
      }
    

  • private成员也会被继承,不过子类无法直接存取,必须通过父类提供的方法存取。

is-a(是一种)关系

  • 子类只能继承一个父类,这种子类父类之间的关系就是is-a关系
  • 检查语法逻辑是否正确,方式是从=右边往左读:判断右边是不是一种左边。例:Role role1=new SwordsMan();即判断SwordsMan是不是一种Role?若是则语法正确,反之则编译失败。
  • 强制让后者是一种前者:Role role1=new SwordsMan();SwordsMan swordsman=(SwordsMan) role1;

多态

  • 使用单一接口操作多种类型的对象,具有更高的可维护性。

  • Java以继承及界面来实现多态,是次态多态的一种实现。

      public class RPG2
      {
          public static void main (String[] args)
          {
              SwordsMan swordsMan = new SwordsMan();
              swordsMan.setName("Justin");
              swordsMan.setLevel(1);
              swordsMan.setBlood(200);
      
              Magician magician = new Magician();
              magician.setName("Moinca");
              magician.setLevel(1);
              magician.setBlood(100);
      
              showBlood(swordsMan);   //SwordsMan是一种Role
              showBlood(magician);
          }
          static void showBlood(Role role)   //声明为Role类型
          {
              System.out.printf("%s 血量 %d%n",role.getName(), role.getBlood());
          }
      }
    

重新定义行为

  • SwordsMan与Magician的fight()方法签署的都是public void fight(),操作接口相同,只是方法操作内容不同,因此,可以将fight()方法提升至Role类中定义。

    Role.java

      public class Role{
      	...
      	public void fight()
          {
              //子类要重新定义fight()行为
          }
      }
    

    SwordsMan.javaMagician.java都与上例相同。

    RPG.java

      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();
              magician.setName("Moinca");
              magician.setLevel(1);
              magician.setBlood(100);
      
              drawFight(swordsMan);
              drawFight(magician);
          }
          static void drawFight(Role role)
          {
              System.out.print(role.getName());
              role.fight();
          }
      }
    

  • 如果传入drawFight()的是SwordsMan,role参数参考的就是SwordsMan实例,操作的就是SwordsMan上的fight()方法定义。

  • 重新定义父类中某个方法时,子类必须撰写与父类方法中相同的签署。可以在子类中某个方法前使用@Override要求编译程序检查该方法是不是真的重新定义了父类中某个方法,如果不是会引发编译错误。

  • 对于父类中的方法权限,只能扩大不能缩小。

    Role2.java

      public abstract class Role2{
      
          ......
          public String toString(){
              return String.format("(%s, %d, %d)", this.name, this.level, this.blood);
          }
      }
    

    SwordsMan2.java

      public class SwordsMan2 extends Role2
      {
          ......
          @Override
          public String toString(){
              return "剑士"+super.toString();
          }
      }
    

    Magician2.java

      public class Magician2 extends Role2
      {
          ......
          @Override
          public String toString(){
              return "魔法师"+super.toString();
          }
      }
    
  • 如果想执行父类中的某构造函数,可以用super()指定。

抽象方法 抽象类

  • 抽象方法:某方法区块中没有任何程序代码操作,用abstract表示该方法为抽象方法,不用撰写{}区块,直接";"结束即可。
  • 抽象类:内含抽象方法的类,一定要在class前标示abstract,表示类定义不完整,不能用来生成实例。

Role.java

	public abstract class Role{
		...
		public abstract void fight();
	}
  • 子类继承抽象类方法:1.继续标示该方法为abstract;2.操作抽象方法。
  • 用设计模式设计猜数字程序

GuessGame.java

	public abstract class GuessGame {
	    public void go() {
	        int number=(int)(Math.random()*10);
	        int guess;
	        do {
	            print("输入数字:");
	            guess=nextInt();
	        }while(guess!=number);
	        println("猜中了");
	    }
	
	    public void println(String text) {
	        print(text+"\n");
	    }
	
	    public abstract void print(String text);
	    public abstract int nextInt();
	}

ConsoleGame.java

	import java.util.Scanner;
	
	public class ConsoleGame extends GuessGame {
	    private Scanner scanner=new Scanner(System.in);
	
	    @Override
	    public void print(String text) {
	        System.out.print(text);
	    }
	
	    @Override
	    public void println(String text) {
	        System.out.println(text);
	    }
	
	    @Override
	    public int nextInt() {
	        return scanner.nextInt();
	    }
	}

Guess.java

	public class Guess {
	    public static void main(String[] args){
	        GuessGame game=new ConsoleGame();
	        game.go();
	    }
	}

protected

  • 被声明为protected的成员,相同包中的类可以直接存取,不同包中的类可以在继承后的子类直接存取。

    Role.java

      public abstract class Role{
      
          protected String name;
          protected int level;
          protected int blood;
      ......
      }
    

    SwordsMan.java

      public class SwordsMan extends Role
      {
          ......
          public String toString(){
              return String.format("剑士(&s, %d, %d)", this.name, this.level, this.blood);
          }
      }
    

    Magician.java

      public class Magician extends Role
      {
          ......
          public String toString(){
              return String.format("魔法师(&s, %d, %d)", this.name, this.level, this.blood);
          }
      }
    
  • private、无关键字、protected、public权限依次递增。

构造函数

  • 类有继承关系时,会先进行父类定义的初始流程,再进行子类定义的初始流程。
  • 父类中可以重载多个构造函数,如果子类构造函数中没有制定执行父类中哪个构造函数,默认会调用父类中无参数构造函数。
  • this()super()只能择一调用,并且要写在构造函数第一行执行。

final关键字

  • class或方法被声明为final,表示这是最后一个,不会再有子类或子类不可以重新定义方法。

java.lang.Object

  • java.lang.Object是最上层父类,Java中所有对象一定是一种Object。

ArrayList.java不限长度收集对象

	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;
	    }
	}

Guest.java收集访客名称并转为大写显示

	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有垃圾收集(GC)机制,执行流程中无法通过变量参考的对象就是垃圾对象。GC在进行回收前会调用对象的finalize()方法

接口

  • 类要操作接口必须用implements关键字。
  • 操作接口时,对接口中定义的方法有两种处理方式:1.操作接口中定义的方法2.再度将该方法标示为abstract。
  • Java的接口支持多重继承,操作接口表示“拥有行为”,但不是“是一种”的关系。

Swimmer.java

	public interface Swimmer {
	        public abstract void swim();
	}

Fish.java

	public abstract class Fish implements Swimmer{
	    protected String name;
	    public Fish(String name){
	        this.name=name;
	    }
	    public String getName()
	    {
	        return name;
	    }
	    @Override
	    public abstract void swim();
	}

Human.java

	public class Human implements Swimmer{
	    private String name;
	    public Human(String name){
	        this.name=name;
	    }
	    public String getName()
	    {
	        return name;
	    }
	    @Override
	    public void swim(){
	        System.out.printf("人类 %s 游泳 %n",name);
	    }
	}

Submarine.java

	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);
	    }
	}

Ocean.java

	public class Ocean{
	    public static void main(String[] args)
	    {
	        doSwim(new Human("贾斯汀"));
	        doSwim(new Submarine("黄色一号"));
	    }
	
	    static void doSwim(Swimmer swimmer){
	        swimmer.swim();
	    }
	}

解决需求变化

  • 增加新的需求,原有的程序无需修改,只需针对新需求撰写程序,就是有弹性、具可维护性的程序。
  • Java中类可以操作两种以上的类。

Flyer.java

	public interface Flyer {
	    public abstract void fly();
	}

Airplane.java

	public class Airplane implements Swimmer,Flyer{
	    private String name;
	    public Airplane(String name){
	        this.name=name;
	    }
	    public String getName()
	    {
	        return name;
	    }
	
	    @Override
	    public void fly(){
	        System.out.printf("海上飞机 %s 在飞%n",name);
	    }
	
	    @Override
	    public void swim(){
	        System.out.printf("海上飞机 %s 航行海面%n",name);
	    }
	}

FlyingFish.java

	public class FlyingFish extends Fish implements Flyer{
	    public FlyingFish(String name){
	        super(name);
	    }
	
	    @Override
	    public void swim(){
	        System.out.println("飞鱼游泳");
	    }
	
	    @Override
	    public void fly(){
	        System.out.println("飞鱼会飞");
	    }
	}

Ocean2.java

	public class Ocean2{
	    public static void main(String[] args)
	    {
	        doSwim(new Human("贾斯汀"));
	        doSwim(new Submarine("黄色一号"));
	        doSwim(new Airplane("空军零号"));
	        doSwim(new FlyingFish("甚平"));
	    }
	
	    static void doSwim(Swimmer swimmer){
	        swimmer.swim();
	    }
	}

接口的默认

  • Java中可以使用interface来定义抽象的行为和外观。
  • 接口中的方法没有操作时一定得是公开且抽象的。
  • 接口可以继承别的接口,也可以同时继承两个以上的接口,同样也是用extends关键字,这代表了继承父接口的行为。

枚举常数

  • 使用接口

Action.java

	public interface Action{
	    public static final int STOP=0;
	    public static final int RIGHT=1;
	    public static final int LEFT=2;
	    public static final int UP=3;
	    public static final int DOWN=4;
	}

Game.java

	import static java.lang.System.out;
	public class Game{
	    public static void main(String[] args){
	        play(Action.RIGHT);
	        play(Action.UP);
	    }
	    public static void play(int action){
	        switch(action){
	            case Action.STOP:
	                out.println("播放停止动画");
	                break;
	            case Action.RIGHT:
	                out.println("播放向右动画");
	                break;
	            case Action.LEFT:
	                out.println("播放向左动画");
	                break;
	            case Action.UP:
	                out.println("播放向上动画");
	                break;
	            case Action.DOWN:
	                out.println("播放向下动画");
	                break;
	            default:
	                out.println("不支持此动作");
	        }
	    }
	}

  • 使用enum:enum定义了特殊的类,继承自java.lang.Enum,由编译程序处理。

Action2.java

	public enum Action2
	{
	    STOP,RIGHT,LEFT,UP,DOWN
	}

Game2.java

	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;
	        }
	    }
	}

匿名内部类

  • 临时继承某个类或操作某个接口并建立实例,由于这类子类或接口操作类只使用一次,不需要为这些类定义名称,可以使用匿名内部类。

Client.java

	public class Client{
	    public final String ip;
	    public final String name;
	    public Client(String ip,String name){
	        this.ip=ip;
	        this.name=name;
	    }
	}

ClientEvent.java

	public class ClientEvent{
	    private Client client;
	    public ClientEvent(Client client){
	        this.client=client;
	    }
	    public String getName(){
	        return client.name;
	    }
	    public String getIp(){
	        return client.ip;
	    }
	}

ClientListener.java

	public interface ClientListener{
	    void clientAdded(ClientEvent event);
	    void clientRemoved(ClientEvent event);
	}

ClientQueue.java

	import java.util.ArrayList;
	public class ClientQueue{
	    private ArrayList clients=new ArrayList();
	    private ArrayList listeners=new ArrayList();
	    public void addClientListener(ClientListener listener){
	        listeners.add(listener);
	    }
	    public void add(Client client){
	        clients.add(client);
	        ClientEvent event=new ClientEvent(client);
	        for(int i=0;i<listeners.size();i++){
	            ClientListener listener=(ClientListener) listeners.get(i);
	            listener.clientAdded(event);
	        }
	    }
	    public void remove(Client client){
	        clients.remove(client);
	        ClientEvent event=new ClientEvent(client);
	        for(int i=0;i<listeners.size();i++){
	            ClientListener listener=(ClientListener) listeners.get(i);
	            listener.clientRemoved(event);
	        }
	    }
	}

MultiChat.java

	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);
	    }
	}

学会使用wc统计代码行数

  • 在power cmd中输入`wc -l *.java

代码调试中的问题和解决过程

问题:本来像书上p167中的fight()方法运行都没有问题,但是按照书上p169抽象方法与抽象类中,将前面的Role.java中的fight()方法改成如下的格式public abstract void fight();之后,RPG.java就运行不了了。

解决方法:待解决。

本周代码托管截图

其他(感悟、思考等,可选)

第6、7章的内容有许多的代码,从这两章中知道了,并不是一个项目中只能建一个class,更多时候要把很多class放在一个包里来一起运行才能达到预期效果。由于前几周最后完成博客时都比较赶,这一周我早早的就开始看书、运行代码、看视频,没有再把任务都拖到最后让自己手忙脚乱,学习还是应该尽量往前赶,不要拖延。

学习进度条

代码行数(新增/累积) 博客量(新增/累积) 学习时间(新增/累积) 重要成长
目标 5000行 30篇 400小时
第一周 150/150 1/2 15/15 学会搭建Java环境,学会写Hello World小程序
第二周 350/500 1/3 20/35 掌握IDE的使用方法,学会Java的基本语法规则
第三周 400/900 1/4 35/70 学会代码托管,学习了类类型、面向对象、函数等知识
第四周 990/1890 1/5 40/110 学会使用wc统计代码行数,学会将多个class文件放在一个包内

参考资料

posted @ 2016-03-26 15:51  20145219宋歌  阅读(190)  评论(2编辑  收藏  举报