Java 9改进的接口(6.6)

参考《Java疯狂讲义》
抽象类是从多个类中抽象出来的模板,如果将这种抽象进行的更彻底,则可以提炼出一种更加特殊的“抽象类”——接口(interface)

1. 接口概念
接口定义了某一批类所需要遵守的规范,接口不关心这些类的内部状态数据,也不关心这些类方法的实现细节,它只提供这批类里必须要提供的方法(公有方法),提供这些方法的类就可以满足实际需要。接口体现的是规范和实现分离的设计哲学

2. Java 9中接口定义

[修饰符] interface 接口名 extends 父接口1,父接口2,....
{
	零个到多个常量定义...
	零个到多个抽象方法定义...
	零个到多个内部类,接口,枚举定义...
	零个到多个私有方法,默认方法,类方法定义...
}

修饰符:public或省略(包权限访问控制符),因为接口是多各类共同的公共行为规范,所以接口里所有的成员(除了私有方法)都是public访问权限。省略访问控制权限则默认为包访问控制权限
继承:一个接口可以有多个直接父类,但接口只能继承接口,不能继承类
1 成员变量:只能是静态常量(static final)它们是接口相关的,因此当在接口中定义成员变量时不管你是否使用public static final系统会默认加上,也就是接口里的成员变量总是用这三个修饰符来修饰。
2 方法
抽象实例方法:只能是抽象实例方法,类方法,默认方法(default)和私有方法,因此如果定义的不是类方法,默认方法或私有方法,则系统为普通方法默认加abstract修饰符,接口里的普通方法总是用public abstract修饰的。
私有方法:私有方法主要是用来作工具方法的,为接口中的默认方法或类方法提供支持,私有方法只能用private修饰,私有方法可以是类方法,也可以是实例方法。
默认方法:默认方法必须使用default修饰,不能使用static修饰(因此不能直接使用接口调用该方法),其实接口中的默认方法就是实例方法。无论程序是否指定,默认方法总是使用public修饰
类方法:类方法不能使用default修饰,无论程序是否指定,系统都会加public修饰。
3 内部类:接口里定义的内部类,内部接口,内部枚举默认都采用public static修饰,不管定义时是否指定,系统都会自动使用这两个修饰符对他们进行修饰。
4 没有构造器和初始化块

注意:从某个角度看,接口可被当成一个特殊的类,因此一个java源文件只能有一个public接口,如果Java源文件指定了一个public接口,则该源文件的主文件名必须与该接口名相同

3. 接口的继承
接口继承完全支持多继承,即可以有多个直接父接口。和类继承类似,子接口扩展某个父接口,将会获得父接口里定义的所有抽象方法,默认方法,常量。

4. 使用接口
接口不能用于创建实例,但接口可以用于声明引用类型变量。当使用接口来声明引用类型时,这个引用类型必须引用到实现类的对象。

接口主要用途
定义变量,也可用于进行强制类型转换
调用接口中定义的常量
被其它类实现

一个类可以实现一个或多个接口,继承用extends,实现则用implements关键字,因为一个类可以实现多个接口,这也是Java为单继承灵活性不足所做的补充,实现接口语法如下:

[修饰符] class 类名 extends 父类 implements 接口1,接口2...
{
	类体部分;
}

一个类可以继承一个父类,并同时实现多个接口,implements部分必须放在extends之后。实现类必须完全实现这些接口里所定义的全部抽象方法(重写);否则,该类保留从父接口那里继承得到的抽象方法,该类也必须被定义成抽象类。

interface Product
{
   int getProduceTime();
}
//让Printer类实现Output和Product接口
public class Printer implements Output , Product
{
   private String[] printData
      = new String[MAX_CACHE_LINE];
   // 用以记录当前所需要的打印数
   private int dataNum = 0;
   public void out()
   {
      //只要还有作业,就继续打印
      while(dataNum > 0)
      {
         System.out.println("打印机打印" + printData[0]);
         // 把作业队列整体前移1位,并将剩下的作业数减1
         System.arraycopy(printData , 1
            , printData, 0, --dataNum);
      }
   }
   public void getData(String msg)
   {
      if (dataNum >= 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 Printer();
      System.out.println(p.getProduceTime());
      // 所有接口类型的引用变量都可直接赋给Object类型变量
      Object obj = p;
   }
}

注意:实现接口的方法时,必须使用public访问控制符,因为接口里的方法都是public的,而子类(相当于实现类)重写父类方法时访问控制权限只能更大或则相等,所以实现类实现接口里的方法只能使用public访问控制权限。

5. 接口和抽象类
接口和抽象类的共同点

  1. 结构和抽象类都不能被实例化,他们都位于继承树的顶端,用于被其它类实现和继承。
  2. 接口和抽象类都可以包含抽象方法,实现接口或继承抽象类的普通子类都必须完全实现这些抽象方法。
    接口与抽象类的差别又非常大,主要体现在设计目的上。接口体现的是一种规范,是整个系统的总纲。而抽象类体现的是一种模板式设计。
  3. 接口里只能包含抽象方法,静态方法,默认方法和私有方法,不能为普通方法提供方法实现,抽象类则完全可以包含抽象方法。
  4. 接口里只能定义静态常量,不能定义普通成员变量:抽象类里则既可以定义普通成员变量,也可以定义静态常量。
  5. 接口里不包含构造器和初始化块,抽象类则可以,但抽象类的构造器并不能用于创建实例,只是用于供子类调用的。
  6. 一个类最多只能有一个直接父类,包括抽象类;但一个类可以直接实现多个接口,通过实现多个接口可以弥补Java单继承的不足。
    6. 面向接口编程
    1简单工厂模式
    2命令模式
    对于这样一个需求,必须把“处理行为”作为参数传入该方法,这个“处理行为”用编程语言来实现就是一段代码。那么如何用代码来实现呢,可以有两种方法,1是用接口,2是用Lambda表达式传入代码块作为参数。
    两种设计模式具体理解过程参考《java疯狂讲义》P198

猜你喜欢

转载自blog.csdn.net/qq_43215734/article/details/85334894