一. 接口的定义

专业来说,多个抽象类的的抽象就是接口。

通俗地讲,在Java中最小的程序单元就是类,接口其实是一个特殊的类。

Java中的接口表示规,用于定义一组抽象方法,表示某一类事物必须具备的功能,要求实现类必须来实现该接口并提供方法实现。


二. 语法

定义类语法:

[public] class 类名{}

定义接口语法:

[public] interface 接口名{}; //(在这里还没有考虑接口的父接口等等).

接口起名问题:

表示具有某些能力的,有人习惯以able/handler结尾。Walkable,表示可以行走的。
有的公司或个人,习惯以 I 打头,表示接口,如:IWalkable.java.

成功编译之后,和类一样,具有一份字节码。


三. 接口存在的成员:

(1) 接口中没有构造器,推论:接口不能创建对象(不能 new ),接口中不能定义普通方法。

(2) 接口中定义的成员变量,实质是全局静态常量,默认使用 public static final来修饰.

interface IWorkable
{
	String name = "name";
}

反编译:

java面向接口编程 订单下单 java面向接口编程详解_java

(3) 接口中定义的方法都是公共的抽象方法,默认的使用 public abstract 来修饰方法.

interface IWorkable
{
	void doWork();
}

反编译:

java面向接口编程 订单下单 java面向接口编程详解_抽象类_02


一般的,我们在接口中定义方法,不喜欢使用修饰符.

(4) 接口中定义的内部类都是公共的静态内部类,默认使用public static来修饰内部类。

interface IWorkable
{
	class test{}
}

反编译:

java面向接口编程 订单下单 java面向接口编程详解_抽象类_03


标志接口:

接口中没有任何成员,就仅仅是一个接口的定义,就是一个标志,其他的类实现该接口,就属于该家族,我们可以通过第三方代码赋予该接口实现类特殊的功能(不推荐)。

常量接口:

有人喜欢使用接口来封装多个常量信息,
我们称之为常量接口,其目的和常量类相同(不推荐)。
咱们使用的接口,主要都包含了抽象方法。

四. 接口的特点

(1)没有构造方法,不能被实例化

(2)接口只能继承接口,不能继承类,且接口支持多继承(类是单继承)

【修饰符】interface 接口名 extends 接口1,接口2

(3)接口里的方法全是抽象的,默认修饰符是 public abstract

(4)接口里的字符全是全局静态常量,默认修饰符是 public static final

(5)接口里的内部类全是静态的,默认修饰符是 public static

五. 接口的实现关系

接口的实现者:实现类

接口仅仅只是定义了某一类事物应该具有某些功能,但是没有提供任何实现。

此时,我们得提供类,再让该类去实现接口,并覆盖接口中的方法,从而实现类接口中定义的功能.


接口和实现类之间的关系,严格上称之为 “实现关系”,使用implements来表示。但是在开发,有时候为了方便也把这个实现关系称之为特殊继承关系。

所以可以这样理解:接口是实现类的父类,实现类就是接口的子类。

注意:
接口中的方法是公共的抽象的,所以实现类必须覆盖接口中的方法,并且方法必须使用public修饰.

请看以下代码:

interface IWorkable
{
	void swim();
} 
class Cat  implements IWorkable
{
	void swim(){} // 编译报错
}
class InterfaceDemo
{
	public static void main(String[] args) {}
}
---------- 编译java ----------
InterfaceDemo.java:8: 错误: Cat中的swim()无法实现IWorkable中的swim()
	void swim();
	     ^
  正在尝试分配更低的访问权限; 以前为public
1 个错误

输出完成 (耗时 0 秒) - 正常终止

上面的代码中的Cat类明明已经实现了IWorkable类中的swim方法,还是还是编译错误,在之前的一篇博客(继承关系与方法覆盖)中,我们提到,方法覆盖是,子类方法访问权限不能比父类中被重写的方法的访问权限更低。这是因为IWorkable类(父类)中定义的方法默认是public修饰的,所以子类中方法也必须要用public修饰。

六. 接口和类之间的关系

类和类之间存在是 继承关系:使用 extends 来表示。

接口和接口之间只能是 继承关系:使用 extends 来表示。

接口和实现类之间只能是 实现关系(有的也称继承),使用 implements来表示。

七. 类和类以及类和接口之间的关系

class Animal{}

//定义一个爬行类接口
interface IWalkable
{
	void walk();
}

//再定义一个水生类接口
interface ISwimable
{
	void swim();
}

//两栖动物接口
interface Amphibians extends IWalkable , ISwimable
{
}

//猫
class Cat implements IWalkable
{
	public void walk()
	{
		System.out.println("好奇害死猫");
	}
}

//鱼
class Fish extends Animal implements ISwimable
{
	public void swim()
	{
		System.out.println("水里的空气,是我小心眼和坏脾气");
	}
}

//蛙类
class Frog extends Animal implements IWalkable , ISwimable
{
	public void walk()
	{
		System.out.println("蛙跳跳");
	}

	public void swim()
	{
		System.out.println("蛙游游");
	}
}

public class InterfaceDemo
{
	public static void main(String[] args) 
	{
		//用对象创建猫
		//Cat C = new Cat(); 不推荐

		//用接口创建猫
		IWalkable w = new Cat();//面向接口编程,存在多态
		w.walk();//体现多态特征,执行Cat类中的walk
		
		//用接口创建鱼
		ISwimable f = new Fish();
		f.swim();

		//同时用到多个接口,用对象创建
		//多接口对象,若只用到某一接口,可用该接口创建
		Frog frog = new Frog();
		frog.walk();
		frog.swim();
	}
}

java面向接口编程 订单下单 java面向接口编程详解_抽象类_04

八. 接口与抽象类的区别

相同点:
(1):都是位于继承的顶端,用于被其他类来实现或者继承。
(2):都不能进行实例化,即不能创建对象。
(3):都可以定义抽象方法,其子类/实现类都必须覆写这些抽象方法。

不同点:
(1):接口是没有构造器的,抽象类有构造器的(因为抽象类的子类创建对象时会调用父类构造器)。
(2):一个类只能继承一个抽象父类,接口是多继承的并且支持一个类实现多个接口(弥补了java单继承问题)
(3):抽象类可以包含普通方法和抽象方法,而接口只包含抽象方法 (Java1.8之前的规定)
(4):成员变量:接口默认是 public static final, 而抽象类默认的是包访问权限。
(5):方法:接口默认的是 public abstract,而抽象类默认的是包访问权限。
(6):内部类:接口默认的是 public static, 而抽象类默认的是包访问权限。

接口和抽象类适用场景:

如果接口和实现类可以完成相同的功能,尽量使用接口,体现面向接口编程的思想。

设计模式:接口和抽象类集合使用的(适配器模式)。

九. 面向接口编程

语法:

接口 变量 = 创建实现类对象; //体现了多态思想接口和实现类的多态关系才是我们见的最多的

类实现接口的语法:

一个类可以实现多个接口,从而也弥补了类的单继承问题。

[修饰符] class 实现类名 extends 父类 implements 接口1,接口2{}
interface IWorkable{
	void swim();
} 

class Cat  implements IWorkable{
	public void swim(){
		System.out.println("swiming");
	}
}

class InterfaceDemo{
	public static void main(String[] args) {
		IWorkable w= new Cat(); // 面向接口编程
		w.swim();
	}
}
---------- 运行java ----------
swiming

输出完成 (耗时 0 秒) - 正常终止

十. 面向接口编程的思想

多态的好处:把实现类对象赋给接口类型变量,屏蔽了不同实现类之间的实现差异,从而可以做到通用编程

我们来看一个案例:使用USB设备来工作。

// 制定USB接口规范
interface IUSB
{
	void doWork();
}

// 鼠标
class Mouse implements IUSB
{
	public void doWork(){
		System.out.println("点击.....");
	}
}

// 打印机
class Print implements IUSB
{
	public void doWork(){
		System.out.println("打印数据.....");
	}
}

// 主板
class MotherBoard
{

	private static IUSB[] USB = new IUSB[6]; //假设主板只能接受6个设备
	private static int index = 0; // 表示插入主板设备的第几个位置(从0开始)

	// 在主板中插入外设
	public static void plugIn(IUSB usb){
		if (index == USB.length)
		{
			System.out.println("USB插口已经插满了!!");
			return ;
		}
		USB[index] = usb;
		index++;
	}

	// 开始工作
	public static void startDoWork(){
		for(IUSB usb:USB){
			if (usb != null)
			{
				usb.doWork();
			}
		}		
	}
}

class USBDemo 
{
	public static void main(String[] args) 
	{
		IUSB m = new Mouse();
		IUSB p = new Print();
		MotherBoard.plugIn(m);
		MotherBoard.plugIn(p);
		MotherBoard.plugIn(p);
		MotherBoard.plugIn(p);
		MotherBoard.plugIn(p);
		MotherBoard.plugIn(p);
		MotherBoard.plugIn(p);
		MotherBoard.startDoWork();
	}
}
---------- 运行java ----------
USB插口已经插满了!!
点击.....
打印数据.....
打印数据.....
打印数据.....
打印数据.....
打印数据.....

输出完成 (耗时 0 秒) - 正常终止