Java OOP 抽象类和接口

文章目录

  • Java OOP 抽象类和接口
    • 一、学习目标
    • 二、抽象类
    • 三、抽象类 (abstract)
    • 四、抽象方法
    • 五、抽象类和抽象方法的应用
    • 六、final用法
    • 七、愤怒的小鸟(抽象类实现)
    • 八、为什么使用接口
    • 九、什么是接口
    • 十、接口的定义与实现
    • 十一、接口模拟PCI插槽
    • 十二、接口进阶
    • 十三、愤怒小鸟(优化版)
    • 十四、面向对象设计原则
    • 十五、本章总结

一、学习目标

  1. 掌握抽象类和抽象方法
  2. 掌握final修饰符的用法
  3. 掌握接口的用法
  4. 理解面向对象设计原则

二、抽象类

问题: 星沐生态农场”游戏中,以下代码是否存在问题?

Crop crop= new Crop();
crop.print();

分析: 实例化Crop对象无意义,因为农作物是一个抽象的概念,而不是具体的某个实例对象。

方案: 使用抽象类

三、抽象类 (abstract)

语法:

[访问修饰符]  abstract class <类名> {//省略代码……
}

示例:

public abstract class Crop {//省略代码……
}

测试:

结论:

  • 抽象类不能被实例化(Crop is abstract; cannot be instantiated)

四、抽象方法

问题: 下面代码图的执行结果,有什么问题?

分析:

  • 从图中不难发现 Crop中print()方法体中输出的作物特性信息是无实际意义的,简单来说就是无用代码。

方案:

  • 抽象类中使用抽象方法优化代码

什么是抽象方法?

  • 使用**abstract**关键字修饰的方法称之为抽象方法

    • 抽象方法没有方法体
    • 抽象方法必须在抽象类里
    • 抽象方法必须在子类中被实现,除非子类是抽象类

语法:

[访问修饰符]  abstract  class 类名 {[访问修饰符] abstract <返回类型> <方法名>([参数列表]);
}

示例:

//抽象类
public abstract class Crop { //抽象方法,只有方法的声明,没有方法体中具体的实现public abstract void print();//普通方法public void test(){}
}

结论

  1. 有抽象方法的类必然是抽象类。
  2. 但抽象类中的方法并不一定都是抽象方法。
  3. 抽象方法只有方法声明,无具体实现。

五、抽象类和抽象方法的应用

需求: 为农场增加除虫功能,具体要求如下

  • 在“星沐生态农场”补充为作物除虫的相关功能,每种作物输出不同的除虫信息

    • 苹果树:萌芽前和开花时打药3次,果实生长期打药2次,采摘期打药1次
    • 玉米:种子喷洒农药后再播种,防止地下害虫咬食,果实生长期打药1次

分析:

  • 每种作物有各自的除虫方案

    • 在父类Crop中,无法抽取出其所有子类共同的除虫信息
    • 在父类中定义抽象方法disinfestation()
    • 在每个子类中重写该方法,实现该类对象的除虫操作

示例:

Crop类

public abstract class Crop{//省略属性和方法...//定义除虫的抽象方法public abstract void disinfestation();
}

AppleTree类

public class AppleTree extends Crop {// 没有重写父类的抽象方法disinfestation()
}

如图所示,当子类继承父类,父类是一个抽象类的时候,会出现红色的警告线,告诉我们编译错误,这也恰好论证了我们前面提出的观点:

  • 抽象方法必须在子类中被实现,除非子类是抽象类

语法:

方案:

  • 在子类中重写父类定义的抽象方法disinfestation()
  • AppleTree类
 @Override public void disinfestation() {System.out.println(super.getName()+"萌芽前和开花时打药3次," + "果实生长期打药2次,采摘期打药1次。");
}
  • Corn类
 @Overridepublic void disinfestation() {System.out.println(super.getName()+"种子喷洒农药后再播种,"+"防止地下害虫咬食,果实生长期打药1次。");}
  • 测试类关键代码
 public static void main(String[] args) {    Crop crop = new AppleTree("富士");//苹果树crop.disinfestation();crop = new Corn(50);//玉米crop.disinfestation();}
  • 运行结果

抽象类的优势

  • 提高可重用性

    • 抽象类可以看作是类的一个模版,定义了子类的行为,可以为子类提供默认实现,无需子类中重复实现这些方法
  • 代码松耦合,更易于维护

    • 子类可以分别实现抽象父类中定义的抽象方法,将方法定义和方法实现的分离
  • 方便实现多态

    • 抽象类作为继承关系下的抽象层,不能被实例化,通常定义抽象类类型变量,其具体引用是实现抽象类的子类对象

抽象类的应用场合

  • 抽象类用来列举一个类所需要的共性行为
  • 抽象类不明确提供具体实现方法
  • 抽象类必须由其子类实现它的抽象方法(除非子类也具有抽象性)

抽象类与抽象方法使用总结

  • 抽象方法只有方法声明,没有方法实现

  • 有抽象方法的类必须声明为抽象类

  • 子类必须重写所有的抽象方法才能实例化;否则,子类也必须声明成抽象类

  • 抽象类中可以没有、有一个或多个抽象方法,甚至可以定义全部方法都是抽象方法

  • 抽象类可以有构造方法,其构造方法可以被本类的其他构造方法调用

    • 不是由private修饰构造方法,可以被其子类的构造方法调用
  • abstract可以用来修饰类和方法,不能用来修饰属性和构造方法

六、final用法

问题:

Dog类不希望再被其他类继承,应该怎么做?
使用final类

public final class Puppy extends Dog { //…
}

方法不希望被重写?
使用final方法

public class Student {public final void print() {System.out.println("我是一个学生!");}
}

属性值不希望被修改?
使用常量

public class Dog {final String  name ="帅帅";public void setName(String name) {this.name=name; //编译错误,不可再赋值}
}

常见错误:

1.使用final修饰引用型变量,变量的值是固定不变的,而变量所指向的对象的属性值是可变的

public class Student {String name;public Student(String name) {this.name = name;}public static void main(String[] args) {final Student stu = new Student("李明");stu.name = "李明航"; stu = new Student("王亮");//编译错误,使用final修饰的引用型变量不可以再指向其他对象}
}

2.使用final修饰的方法参数,这些参数的值是固定不变的

class Value {int v;
}public class Test {public void changeValue(final int i, final Value value) { i = 8; //编译错误:使用final修饰的方法参数,在整个方法中不能改变参数值value.v = 8; }
}

3.常见错误示例:

  1. 抽象方法只有声明无具体实现,static方法可通过类名直接访问,但无法修饰一个没有实现的方法

  2. 抽象方法需在子类中重写,但private方法不能被子类继承,自然无法进行重写

  3. 抽象方法需要在子类中重写,但final修饰的方法表示该方法不能被子类重写,前后是相互矛盾的

总结:

  • final可以用来修饰类、方法和属性,不能修饰构造方法

  • Java提供的很多类都是final类,不能重写

    • 如:String类、Math类
  • Object类有一些final方法,只能被子类继承而不能被重写

    • 如:getClass( )、notify( )、wait( )
  • Object类的hashCode( )、toString( )、equals(Object obj)方法不是final方法,可以被重写

经验:

  1. abstract和static不能结合使用
  2. abstract和private不能结合使用
  3. abstract和final不能结合使用

七、愤怒的小鸟(抽象类实现)

训练要点

  • 抽象类和抽象方法

需求说明

  • 玩家将弹弓拉到极限后发射,小鸟就飞出去进行攻击

  • 不同类型的小鸟具有不同的攻击方式

  • 模拟分裂鸟和火箭鸟飞行、叫和攻击的行为

  • 要求

    • 分裂鸟会分裂攻击
    • 火箭鸟会加速冲撞攻击
    • 分裂鸟和火箭鸟飞行过程中都伴有“嗷嗷叫”的声音

实现思路

  • 按照面向对象分析的方法,通过提取名词和动词的方法分别找出类的属性和方法

    • 鸟类具有统一的行为
    • “飞行”、“叫”、“攻击”
  • 因为每个鸟的攻击行为不同,父类中将攻击行为定义为抽象方法,在子类中给出具体实现

  • ①.定义抽象类Bird,实现Bird类的飞行方法fly()、叫方法twitter()、抽象的攻击方法attack()

  • ②.定义分裂鸟类,继承抽象类Bird,实现自己的攻击方法attack()

  • ③.定义火箭鸟类,继承抽象类Bird,实现自己的攻击方法attack()

  • ④.编写测试类,模拟游戏

//定义抽象类Bird
package com.aiden.angrybirds;/*** 抽象类:鸟类*/
public abstract class Bird {public void fly() {System.out.println("弹射飞");}public void twitter() {System.out.println("嗷嗷叫");}/*** 抽象方法*/public abstract void attack();
}
//定义分裂鸟类
package com.aiden.angrybirds;/*** 分裂鸟*/
public class SplitBird extends Bird {public void attack() {System.out.println("分裂攻击!");}
}
//定义火箭鸟类
package com.aiden.angrybirds;/*** 火箭鸟*/
public class RocketBird extends Bird {public void attack() {System.out.println("加速冲撞!");}
}
//编写测试类
package com.aiden.angrybirds;public class TestAngryBirds {/*** 愤怒的小鸟测试类*/public static void main(String[] args) {//火箭鸟Bird rocketBird = new RocketBird();rocketBird.fly();rocketBird.twitter();rocketBird.attack();//分裂鸟Bird splitBird = new SplitBird();splitBird.fly();splitBird.twitter();splitBird.attack();}
}

八、为什么使用接口

问题:

假设“愤怒的小鸟”游戏需求发生变更

  1. 当弹弓拉到极限时,鸟飞出进行攻击,并发出“嗷嗷叫”的声音
  2. 不同的鸟具有不同的能力,配备不同的装备,可采取不同的攻击方式,如表中所示
名称 装备 能力 攻击方式
炸弹鸟 炸弹 - 使用炸弹进行爆炸攻击
喷火分裂鸟 喷火器 分裂能力 分裂并喷射火焰进行攻击
旋转鸟 旋转引擎 - 旋转攻击
超级鸟 加速马达 分裂能力、放大能力 加速冲撞、分裂并膨胀攻击

分析:

  • 鸟类具有飞行、叫和攻击行为;

  • 装备有炸弹、喷火器、旋转引擎、加速马达;

  • 将鸟类和装备分别定义为抽象类 ???

    • 愤怒的小鸟可以继承鸟类的同时又继承装备吗?如何解决这个问题?
  • 此时发现单继承已经满足不了我们需求了 (ಥ﹏ಥ)

    • 所以我们的==接口==从此诞生:

      • 将鸟类定义为抽象类,装备定义为接口
      • 各类愤怒的小鸟继承自鸟类,实现装备的接口==

结论

  • 类只能单继承,接口才可以改变这种囧境。

九、什么是接口

  • 生活中的接口就是一套规范

    • 如:主板上的PCI插槽有统一的标准,规定了尺寸、排线
    • 满足规范标准的设备可以组装在一起
      >
  • Java 中,接口

    • 是一种规范和标准

      • 可以约束类的行为,使得实现接口的类(或结构)在形式上保持一致
    • 是一些方法特征的集合

      • 可看作是一种特殊的“抽象类”

      • 但采用与抽象类完全不同的语法

  • 抽象类利于代码复用,接口利于代码的扩展和维护

  • 是一个不能实例化的类型

  • 定义接口

    //如果是public,则在整个项目中可见,如果省略,则只在该包中可见
    [访问修饰符]  interface 接口名 {// 接口成员
    }
    
  • 接口中的变量都是全局静态常量

    • 自动使用public static final修饰
    • 必须在定义时指定初始值
  public interface Cirlcle {int P=5; public static final int P = 5;int P;}
public class 类名 implements 接口名 {//类成员
}
  • 实现类必须实现接口的所有方法

  • 实现类可以实现多个接口

注意:JDK1.8版本之前,接口中只能定义抽象方法,自JDK1.8版本开始,接口还允许定义静态方法和默认方法

  • 向后兼容
    允许开发者在已有接口里添加新的方法时不需改动已经实施该接口的所有实现类

接口表示一种能力

“做这项工作需要一个钳工(木匠/程序员)”

钳工是一种“能力”,不关心具体是谁

接口是一种能力

体现在接口的方法上

面向接口编程

十、接口的定义与实现

示例:定义MyInterface接口

package com.aiden.interfaces;/*** @author Aiden*/
public interface MyInterface {int P = 5;//抽象方法void function1();//接口中抽象方法系统自动添加public abstract修饰//默认方法,如果不能满足某个实现类的需求,可在实现类中重写default void function2() {System.out.println("这是一个默认方法");}//静态方法,不允许在接口的实现类中重写,只能通过接口名称调用static void function3() {System.out.println("这是一个静态方法");}
}

示例:定义MyClass类实现MyInterface接口

public class MyClass implements MyInterface {@Overridepublic void function1() {System.out.println("实现MyInterface接口的function1()!");}
}

测试调用

package com.aiden.interfaces;
/*** @author Aiden*/
public class TestMyClass {public static void main(String[] args) {MyClass myClass = new MyClass();myClass.function1();     //调用实现类中重写方法myClass.function2();     //调用接口中默认方法MyInterface.function3(); //调用接口中静态方法}
}

运行结果:

十一、接口模拟PCI插槽

示例:

模拟将声卡、显卡和网卡装配到计算机的PCI插槽进行工作

分析:

  • PCI插槽本身没有实现任何功能

  • PCI插槽规定了启动和停止各种卡的要求

  • PCI插槽以被多种设备实现

    • 使用Java接口实现

实现步骤:

  1. 定义PCI接口,具有开始、停止和输出信息的功能
  2. 定义声卡类,符合PCI插槽标准,可以发声
  3. 定义显卡类,符合PCI插槽标准,可以显示图像
  4. 定义网卡类,符合PCI插槽标准,可以传输网络数据
  5. 定义装配类,安装网卡、声卡和显卡并模拟工作

实现代码:

1.定义PCI接口,具有开始、停止和输出信息的功能

package com.aiden.interfaces.pci;/*** 定义PCI接口*/
public interface PCI {//开始public void start();//停止public void stop();//输出信息public default void print() {System.out.println("符合PCI插槽标准!");}
}

2.定义声卡类,符合PCI插槽标准,可以发声

package com.aiden.interfaces.pci;/*** 声卡*/
public class SoundCard implements PCI {@Overridepublic void start() {System.out.println("声卡发出声音!");}@Overridepublic void stop() {System.out.println("声卡停止发出声音!");}
}

3.定义显卡类,符合PCI插槽标准,可以显示图像

package com.aiden.interfaces.pci;/*** 显卡*/
public class GraphicCard implements PCI {@Overridepublic void start() {System.out.println("显卡显示图像!");}@Overridepublic void stop() {System.out.println("显卡停止显示图像!");}
}

4.定义网卡类,符合PCI插槽标准,可以传输网络数据

package com.aiden.interfaces.pci;/*** 网卡*/
public class NetworkCard implements PCI {@Overridepublic void start() {System.out.println("网卡开始传输数据!");}@Overridepublic void stop() {System.out.println("网卡停止传输数据!");}
}

5.定义装配类,安装网卡、声卡和显卡并模拟工作

package com.aiden.interfaces.pci;
/*** 装配类*/
public class Assembler {/*** 装配方法* @param pci PCI接口*/public static void assemble(PCI pci){pci.print();pci.start();pci.stop();}public static void main(String[] args) {//装配网卡System.out.println("***装配网卡***");PCI networkCard = new NetworkCard();Assembler.assemble(networkCard);//装配声卡System.out.println("***装配声卡***");PCI soundCard = new SoundCard();Assembler.assemble(soundCard);//装配显卡System.out.println("***装配显卡***");PCI graphicCard = new GraphicCard();Assembler.assemble(graphicCard);}
}

6.测试调用

package com.aiden.interfaces.pci;public class TestPCI {public static void main(String[] args) {System.out.println("***模拟网卡工作***");PCI networkCard = new NetworkCard();networkCard.print();networkCard.start();networkCard.stop();System.out.println("***模拟声卡工作***");PCI soundCard = new SoundCard();soundCard.print();soundCard.stop();soundCard.stop();System.out.println("***模拟显卡工作***");PCI graphicCard = new GraphicCard();graphicCard.print();graphicCard.stop();graphicCard.stop();}
}

7.运行效果

十二、接口进阶

定义复杂的接口

接口的多继承语法:

//通过extends实现接口的继承关系
[ 访问修饰符 ] interface 接口名 extends 父接口 1, 父接口 2,……{//常量定义//方法定义
}

注意事项1: 一个接口可以继承多个接口,但接口不能继承类

类实现多个接口:

//通过implements实现多个接口
[ 访问修饰符 ] class 类名 extends 父类名 implements 接口 1, 接口 2,……{//类的成员
}

注意事项2:

  • 一个普通类只能继承一个父类,但能同时实现多个接口
  • extends 关键字必须位于 implements关键字之前
  • 类必须实现所有接口(接口1、接口2…)的全部抽象方法,否则必须定义为抽象类

注意事项3:

如果一个类实现了多个接口,且这些接口具有相同的默认方法,应该如何处理?

在实现类中必须提供自己的默认方法,来覆盖接口中的默认方法。例如:接口A中定义了默认方法print(),接口B中也定义了不同实现的默认方法print()。如果类C实现了接口A和接口B,则类C中必须定义自己的print()方法;否则,在调用C对象的print()方法时无法确定是访问接口A的print()方法,还是访问接口B的print()方法

interface A {default void print () {System.out.println("这是A接口的一个默认方法");}
}
interface B {default void print () {System.out.println(“这是B接口的一个默认方法");}
}
class C implements A,B {//C类中必须定义自己的print()方法void print () {System.out.println(“这是C类的print方法");}
}
public static void main(String[] args) {C cObject = new C();//无法确定是访问接口A或接口B的print()方法cObject.print();//调用C类print()方法
}

十三、愤怒小鸟(优化版)

重新设计“愤怒的小鸟”游戏,要求效果如下:

请选择鸟的类型:1.炸弹鸟 2.喷火分裂鸟 3.旋转鸟 4.超级鸟 5.退出
1
弹射飞
嗷嗷叫
炸弹鸟攻击:炸弹爆炸攻击!
请选择鸟的类型:1.炸弹鸟 2.喷火分裂鸟 3.旋转鸟 4.超级鸟 5.退出
2
弹射飞
嗷嗷叫
喷火分裂鸟攻击:分裂攻击!使用喷火器喷射火焰!
请选择鸟的类型:1.炸弹鸟 2.喷火分裂鸟 3.旋转鸟 4.超级鸟 5.退出
3
弹射飞
嗷嗷叫
旋转鸟攻击:使用旋转引擎旋转攻击!
请选择鸟的类型:1.炸弹鸟 2.喷火分裂鸟 3.旋转鸟 4.超级鸟 5.退出
4
弹射飞
嗷嗷叫
超级分裂鸟攻击:分裂攻击!膨胀攻击!加速冲撞!
请选择鸟的类型:1.炸弹鸟 2.喷火分裂鸟 3.旋转鸟 4.超级鸟 5.退出
5
您已退出游戏!

分析

  • 各类鸟 (is a 的关系)

    • 炸弹鸟是一只鸟
    • 喷火分裂鸟是一只鸟
    • 旋转鸟是一只鸟
    • 超级鸟是一只鸟
  • 每类鸟具备相应的装备(has a 的关系)(协议和规范或能力)

    • 返回装备名称
    • 展示装备功能
  • 每个鸟类在继承父类Bird的同时,根据需求实现不同的能力接口

实现过程

  1. 定义装备接口IEquipment(具备返回装备名称、展示装备功能的能力)
  2. 定义4个装备的实现类(旋转引擎装备:SpinEngine、炸弹装备:Bomb、加速马达装备:AccelerationMotor、喷火器装备:FlameThrower)
  3. 定义分裂能力接口ISpill
  4. 定义放大能力接口ISwell
  5. 实现抽象类Bird类 (抽象类,实现IEquipment接口,具备特定的装备和鸣叫、飞行、攻击、显示鸟行为的能力)
  6. 实现具体的鸟类
    • 超级鸟(SuperBird): 继承自Bird类实现ISwell、ISplit接口
    • 喷火分裂鸟(FlameSplitBird): 继承自Bird类,实现ISplit接口
    • 炸弹鸟 (BombBird): 继承自Bird类
    • 旋转鸟 (SpinBird): 继承自Bird类
  7. 编写测试类

愤怒小鸟(优化版)代码实现

接口与类的设计图

  1. 定义装备接口IEquipment(具备返回装备名称、展示装备功能的能力)
package com.aiden.angrybirdplus;/*** 装备接口*/
public interface IEquipment {/*** 返回装备名称* @return 装备名称*/String getName();/*** 展示装备功能*/void show();
}
  1. 定义4个装备的实现类(旋转引擎装备:SpinEngine、炸弹装备:Bomb、加速马达装备:AccelerationMotor、喷火器装备:FlameThrower)
package com.aiden.angrybirdplus;/*** 实现旋转引擎装备*/
public class SpinEngine implements IEquipment {@Overridepublic String getName() {return "旋转引擎";}@Overridepublic void show() {System.out.println("使用"+this.getName()+"旋转攻击!");}
}
package com.aiden.angrybirdplus;/*** 实现炸弹装备*/
public class Bomb implements IEquipment {@Overridepublic String getName() {return "炸弹";}@Overridepublic void show() {System.out.println(this.getName()+"爆炸攻击!");}
}
package com.aiden.angrybirdplus;/*** 实现加速马达装备*/
public class AccelerationMotor implements IEquipment {@Overridepublic String getName() {return "加速马达";}@Overridepublic void show() {System.out.println("加速冲撞!");}
}
package com.aiden.angrybirdplus;/*** 实现喷火器装备*/
public class FlameThrower implements IEquipment {@Overridepublic String getName() {return "喷火器";}@Overridepublic void show() {System.out.println("使用"+this.getName()+"喷射火焰!");}
}
  1. 定义分裂能力接口ISpill
package com.aiden.angrybirdplus;/*** 分裂能力接口*/
public interface ISplit {public default void split(){System.out.print("分裂攻击!");}
}
  1. 定义放大能力接口ISwell
package com.aiden.angrybirdplus;/*** 放大能力接口*/
public interface ISwell {public default void swell(){System.out.print("膨胀攻击!");}
}
  1. 实现抽象类Bird类 (抽象类,实现IEquipment接口,具备特定的装备和鸣叫、飞行、攻击、显示鸟行为的能力)
package com.aiden.angrybirdplus;public abstract class Bird {private IEquipment equipment;//装备public Bird(){}public Bird(IEquipment equipment){this.equipment = equipment;}public void twitter(){System.out.println("嗷嗷叫");}public void fly(){System.out.println("弹射飞");}/*** 抽象方法:攻击*/public abstract void attack();/*** 显示鸟的行为*/public void show(){fly();twitter();attack();}public IEquipment getEquipment() {return equipment;}public void setEquipment(IEquipment equipment) {this.equipment = equipment;}
}
  1. 实现具体的鸟类

    • 超级鸟(SuperBird): 继承自Bird类实现ISwell、ISplit接口
    • **喷火分裂鸟(FlameSplitBird): **继承自Bird类,实现ISplit接口
    • **炸弹鸟 (BombBird): **继承自Bird类
    • 旋转鸟 (SpinBird): 继承自Bird类
package com.aiden.angrybirdplus;/*** 超级鸟*/
public class SuperBird extends Bird implements ISplit, ISwell {public SuperBird(){super(new AccelerationMotor()); //加速马达}@Overridepublic void attack() {System.out.print("超级分裂鸟攻击:");this.split();this.swell();this.getEquipment().show();}
}
package com.aiden.angrybirdplus;/*** 喷火分裂鸟*/
public class FlameSplitBird extends Bird implements ISplit {public FlameSplitBird(){super(new FlameThrower()); //装备喷火器}@Overridepublic void attack() {System.out.print("喷火分裂鸟攻击:");this.split();this.getEquipment().show();}
}
package com.aiden.angrybirdplus;/*** 炸弹鸟*/
public class BombBird extends Bird {public BombBird(){super(new Bomb()); //装备炸弹}@Overridepublic void attack() {System.out.print("炸弹鸟攻击:");this.getEquipment().show();}
}
package com.aiden.angrybirdplus;/*** 旋转鸟*/
public class SpinBird extends Bird {public SpinBird(){super(new SpinEngine());//装备旋转引擎}@Overridepublic void attack() {System.out.print("旋转鸟攻击:");this.getEquipment().show();}
}
  1. 编写测试类Game
package com.aiden.angrybirdplus;
import java.util.Scanner;
public class Game {public static Bird chooseBird(int type){Bird bird = null;switch (type) {case 1:bird = new BombBird();break;case 2:bird = new FlameSplitBird();break;case 3:bird = new SpinBird();break;case 4:bird = new SuperBird();break;}return bird;}public static void main(String[] args) {Scanner input = new Scanner(System.in);int type;while(true) {System.out.println("请选择鸟的类型:1.炸弹鸟 " +"2.喷火分裂鸟 3.旋转鸟 4.超级鸟 5.退出 ");type = input.nextInt();if(type>=1 && type<=4) {Bird bird = Game.chooseBird(type);bird.show();}else{System.out.println("您已退出游戏!");break;}}}
}

十四、面向对象设计原则

为了让代码更具灵活性,更能适应变化,需遵循的原则

  • 摘取代码中变化的部分,形成接口

  • 多用组合,少用继承

  • 面向接口编程,不依赖于具体实现

  • 针对扩展开放,针对改变关闭

    • ——开闭原则

经验 面向接口编程可以实现接口和实现的分离,能够在客户端未知的情况下修改实现代码

如何理解接口是一种能力?

接口有比抽象类更好的特性

  1. 可以被多继承
  2. 设计和实现完全分离
  3. 更自然的使用多态
  4. 更容易搭建程序框架
  5. 更容易更换实现
  6. ……

十五、本章总结

Java OOP 第四章 抽象类和接口相关推荐

  1. Effective Java(第三版) 学习笔记 - 第四章 类和接口 Rule20~Rule25

    Effective Java(第三版) 学习笔记 - 第四章 类和接口 Rule20~Rule25 目录 Rule20 接口优于抽象类 Rule21 为后代设计接口 Rule22 接口只用于定义类型 ...

  2. Java编程那些事儿70——抽象类和接口(三)

    Java编程那些事儿70--抽象类和接口(三) 陈跃峰 出自:http://blog.csdn.net/mailbomb 8.9.3 抽象类和接口的比较 抽象类和接口都是进行面向对象设计时专用的设计结 ...

  3. Java编程那些事儿69——抽象类和接口(二)

    Java编程那些事儿69--抽象类和接口(二) 陈跃峰 出自:http://blog.csdn.net/mailbomb 8.9.2 接口 接口(Interface)是一种复合数据类型. 至此,Jav ...

  4. 第二十八节:Java基础-进阶继承,抽象类,接口

    前言 Java基础 - 进阶继承,抽象类,接口 进阶继承 class Stu {int age = 1; } class Stuo extends Stu {int agee = 2; } class ...

  5. Java编程那些事儿68——抽象类和接口(一)

    Java编程那些事儿68--抽象类和接口(一) 陈跃峰 出自:http://blog.csdn.net/mailbomb 8.9  抽象类和接口 在实际的项目中,整个项目的代码一般可以分为结构代码和逻 ...

  6. 尚学堂java实战第四章课后习题

    尚学堂java实战第四章课后习题 文章中的题目答案仅供参考 选择题答案: 1.B 解析:一个java类必然存在构造器,即使没有定义构造器,也会存在一个默认的无参构造器. 2.D 3.AC 解析: A( ...

  7. 疯狂java讲义第四章习题答案

    1.使用循环输出九九乘法表. 疯狂java讲义第四章课后习题第1题答案 2.根据给定的层数,使用循环输出等腰三角形. 疯狂java讲义第四章课后习题第2题答案 3.给定半径输出圆形. 需要注意的是,计 ...

  8. Java OOP 第五章 指导学习

    Java OOP 5 特种部队 文章目录 Java OOP 5 特种部队 一.内容回顾 二.难点突破 三.知识梳理--类和对象 四.知识梳理--继承 五.知识梳理--多态 六.知识梳理--抽象类 七. ...

  9. Java OOP 第三章 多态

    Java OOP 多态 文章目录 Java OOP 多态 一.学习目标 二.多态 1.为什么使用多态 2.什么是多态? 3.如何实现多态? 三.向上转型 四.父类作为形参 扩展种植梨树 五.多态的使用 ...

最新文章

  1. 汉字转换成全拼的拼音
  2. 饭后为什么不宜喝冷饮?
  3. ASP.Net开发新手常见问题备忘录
  4. JUnit单元测试笔记
  5. oracle rac standby,oracle RAC数据库建立STANDBY(二)
  6. java 创建文件夹_VS Code用来开发JAVA项目真香
  7. JDOM与DOM的相互转换
  8. 程序员被纳入新生代农民工;“腾讯视频崩了”上热搜;英特尔发布全新独立显卡品牌 Arc|极客头条...
  9. 输入输出运算符的重载
  10. manjaro linux vmware,Manjaro Linux处理vmware的vmmon、vmnet8、Network configuration is missing一堆问题的记录...
  11. java下载文件下载不动_JAVA实现文件下载,浏览器端得到数据没反应
  12. A*算法之野人传教士问题 python解法
  13. 中国象棋人工智能实现
  14. android hook 第三方app_Android三大hook框架
  15. [设计模式]创建模式-建造者(C++描述)
  16. 宝岛探险(C语言 )(DFS+BFS)
  17. Apple pencil 无法连接到ipad的解决办法汇总
  18. UFS详细介绍---终章
  19. 电容震动音的滋滋声音的原因与消除
  20. mysql取前一个月时间戳_mysql中获取一天、一周、一月时间数据的各种sql语句写...

热门文章

  1. 关闭QQ2007迷你首页 还清净系统
  2. 《Activiti/Flowable  深入BPM工作流》-如何设置local流程变量?
  3. 社区团购系统案例:亲民诚品社区拼团怎么样?
  4. 大维德选媳妇之责任链模式
  5. 不用找,你想要的灯具su模型素材都在这里
  6. jQuery和CSS3定制HTML5视频播放器
  7. 双远心镜头原理及选型(一)
  8. OTB官方评估代码python版本--评估自己跟踪器,对比其他跟踪器
  9. Win7 下安装 VC6 和SP5
  10. python期中考试知识点_FRM和CFA的总共五次考试,我未有失手!