第6章 抽象类和接口

抽象类和接口

抽象类

1)什么是抽象类

抽象类的引入是因为面向对象多态带来的不便利性才引入的,

// 多态
BaseClass sc = new SubClass();

如上将子类对象赋值给父类变量的调用过程。左边new SubClass是运行时的类型,右边BaseClass sc是编译时的类型,当我们调用sc的方法时,默认情况下总是变现子类方法的行为特征。

但如果有的方法只有子类有但是父类不存在时,sc就无法调用!如果一定要调用则必须强制类型转换。SubClass(sc).submethod();这就给编程带来了很大的不变。于是抽象类就诞生了!

抽象类是如何解决的呢?

将子类中的方法抽象到父类中,但却不写具体的方法实现,因为也用不着。那么这个类就升级成了抽象类!

2)抽象类的规则

1-抽象类必须使用abstract修饰符来修饰,抽象方法必须有abstract修饰符,抽象方法不能有方法体,抽象类中也可以没有抽象方法。

2-抽象类不能被实例化,因为抽象类是一种不完整的类。

3-抽象类可以包含成员变量、方法、构造器、初始化块、内部类、枚举。但是抽象类的构造器不是用来创造实例的而是用于被子类调用的。

4-含有抽象方法的类只能被定义成抽象类。

5-继承抽象类的子类必须实现该抽象类中的所有抽象方法。

为了解决8种基本数据类型的变量不能当成Object类型变量使用的问题。

3)举个抽象类的例子

// 创建一个抽象类
public abstract class Shape{
  {
    System.out.println("执行Shape的初始化块...");
  }
  private String color;
  
  // 定义一个计算周长的抽象方法
  public abstract double calPerimeter();
  // 定义一个返回形状的抽象方法
  public abstract String getType();
  
  public Shpae(){}
  public Shape(String color){
    System.out.println("执行Shape的构造器...");
    this.color = color;
  }
}
// 创建Triangle子类,并继承Shape抽象类
public class Triangle extends Shape{ 
  private double a;
  private double b;
  private double c;
  public Triangle(String color, double a, double b, double c){
    super(color);// 抽象类中的成员变量,普通方法,可以直接使用
    this.setSides(a,b,c);
  }
  public void setSides(double a, double b, double c){
    if(a>=b+c || b>=a+c || c>=a+b){
      System.out.println("三角形两边之和必须大于第三边");
      return;
    }
    this.a = a;
    this.b = b;
    this.c = c;
  }
  // 重写Shape类的计算周长的抽象方法
  public double calPerimeter(){
    return a+b+c;
  }
  // 重写Shape类的计算周长的抽象方法
  public double getType(){
    return "三角形";
  }
}
// 创建Circle子类,继承Shape类
public class Circle extends Shape{
  private double radius;
  public Circle(String color, double radius){
    super(color);// 抽象类中的成员变量,普通方法,可以直接使用
    this.setRadius(radius);
  }
  public void setRadius(double radius){
    this.radius = radius;
  }
  // 重写Shape类的计算周长的抽象方法
  public double calPerimeter(){
    return 2*Math.PI*radius;
  }
  // 重写Shape类的返回形状的抽象方法
  public String getType(){
    return "圆形";
  }
  
  public static void main(String[] args){
    Shape s1 = new Triangel("黑色",3,4,5);
    Shape s2 = new Circle("黄色",3);
    // 直接调用各自子类中的具体方法实现
    System.out.println(s1.getType());
    System.out.println(s1.calPerimeter());
    System.out.println(s2.getType());
    System.out.println(s2.calPerimeter());
  }
}
  • 利用抽象类和抽象方法的优势,可以更好的发挥多态的优势,使得程序更加灵活。

  • 抽象类体现的就是一种模板设计模式:

    a.抽象父类可以只定义需要使用的某些方法,把不能实现的部分抽象成抽象方法,留给其子类去实现;

    b.父类中可能包含需要调用其他系列方法的方法,这些被调用的方法既可以由父类实现,也可以由其子类实现。父类里提供的方法只是定义类一个通用算法,其实现也许并不完全有自身实现,而是由子类辅助实现。

接口

1)什么是接口

接口的引入主要有两点原因:

首先,接口是从多个相似类中抽象出来的规范。什么是规范,就是任何一个子类使用这个接口他都必须实现获得数据并可以输出数据。那么就说这个子类实现了这个接口,子类实现了接口的规范。它的多用就是,可以实现团队合作加速开发效率。

其次,java类之间不支持多继承,而接口就是模拟多继承的实现。一个类可以使用多个接口,只要它符合各接口的规范,该类就可以调用每个接口中的默认方法和成员变量。

2)接口的规则

1-接口里不能包含构造器和初始化块,但是可以包含成员变量、方法(抽象实例方法、类方法、默认方法(就是实例方法)或私有方法)、内部类;

2-接口里定义的成员变量只能在定义时指定默认值,默认使用public static final修饰;

3-接口里定义的普通方法,系统会默认增加abstract修饰;

4-类方法可以使用接口来调用;

5-接口完全支持多继承,即一个接口可以有多个直接父接口。子接口扩展某个父接口,将会获得父接口里定义的所欲抽象方法、常量。

6-一个类实现了一个或多个接口之后,这个类必须完全实现这些接口里所定义的全部抽象方法;

3)举个接口的例子

// 创建一个Output接口
package lee;
public interface Output{
  // 接口里定义的成员变量只能是常量
  int MAX_CACHE_LINE = 50;
  // 接口里定义的普通方法只能是public的抽象方法
  void out();
  void getData(String msg);
  // 接口里定义默认方法,需要使用default,等于实例方法
  default void print(String... msgs){
    for(String msg:msgs){
      System.out.println(msg);
    }
  }
  // 默认方法 
  default void test(){
    System.out.println("默认的test()方法");
  }
  // 在接口里定义类方法,需要使用static修饰
  static String staticTest(){
    return "接口里的类方法";
  }
  // 定义私有方法
  private void foo(){
    System.out.println("foo私有方法");
  }
  // 定义私有静态方法
  private static void bar(){
    System.out.println("bar私有静态方法");
  }
}
// 创建一个Product接口
interface Product{
  int getProduceTime();
}

// 创建一个Printer类来实现Output和Product接口
public class Printer implements Output, Product{
  private String[] printData = new String[Output.MAX_CACHE_LINE];
  // 用以记录当前需打印的作业数
  private int dataNum = 0;
  public void out(){
    // 只要还有作业,就继续打印
    while(dataNum > 0){
      System.out.println("打印机打印:"+printData[0]);
      // 把作业队列整体前移一位,并将剩下的作业数减1
      System.arraycopy(printData, 1, printData, 0, --dataNum);
    }
  }
  public void getData(String msg){
    if(dataNum >= Output.MAX_CACHE_LINE){
      System.out.println("输出队列已满,添加失败");
    }
    else{
      // 把打印数据添加到队列里,已保存数据的数量加1
      printData[dataNum++] = msg;
    }
  }
  public int getProduceTime(){
    return 45;
  }
  
  public static void main(String[] args){
    // 创建一个Printer对象,当成Output使用
    Output o = new Printer();
    o.getData("轻量级java ee企业应用实战");
    o.getData("疯狂Java讲义");
    o.out();
    o.getData("疯狂Android讲义");
    o.getData("疯狂Ajax讲义");
    o.out();
    // 调用Output接口中定义的默认方法
    o.print("孙悟空","猪八戒","白骨精");
    o.test();
    
    //创建一个Printer对象,当成Product使用
    Product p = new Product();
    System.out.println(p.getProductTime());
    
    // 所有接口类型的引用变量都可直接赋给Object类型的变量
    Object obj = p;
  }
}
  • 接口的主要用途有:

    a.定义变量,也可用于进行强制类型装换;

    b.调用接口中定义的常量;

    c.被其他类实现;

抽象类和接口的区别

相同点:

接口和抽象类都不能被实例化,它们主要用于被其他类实现和继承;

接口和抽象类都可以包含抽象方法,实现接口或继承抽象类的普通子类都必须实现这些抽闲方法;

不同点:

1-使用上

接口体现的是一种规范。对于接口的实现者,接口规定了实现者必须向外提供哪些服务;对于接口的调用者,接口规定了调用者可以调用哪些服务,以及如何调用这些服务。

抽象类体现的是一种模板式设计,可以被当成系统实现过程中的中间产品。

2-语法规则上

  • 接口里只能包含抽象方法、静态方法、默认方法和私有方法,不能为普通方法提供方法实现;抽象类则完全可以包含普通方法;
  • 接口里只能定义静态常量,不能定义普通成员变量;抽象类里则既可以定义普通成员变量,也可以定义静态常量;
  • 接口里不包含构造器;抽象类里可以包含构造器,但不是自己用,而是让子类调用的;
  • 接口里不能包含初始化块;但抽象类则完全可以包含初始化块;
  • 一个类最多只能有一个直接父类,包括抽象类;但一个类可以实现多个接口,这弥补了java单继承的不足;

参考书籍:《疯狂Java讲义 》李刚;

发布了9 篇原创文章 · 获赞 0 · 访问量 102
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览