一. 接口的定义
专业来说,多个抽象类的的抽象就是接口。
通俗地讲,在Java中最小的程序单元就是类,接口其实是一个特殊的类。
Java中的接口表示规,用于定义一组抽象方法,表示某一类事物必须具备的功能,要求实现类必须来实现该接口并提供方法实现。
二. 语法
定义类语法:
[public] class 类名{}
定义接口语法:
[public] interface 接口名{}; //(在这里还没有考虑接口的父接口等等).
接口起名问题:
表示具有某些能力的,有人习惯以able/handler结尾。Walkable,表示可以行走的。
有的公司或个人,习惯以 I 打头,表示接口,如:IWalkable.java.
成功编译之后,和类一样,具有一份字节码。
三. 接口存在的成员:
(1) 接口中没有构造器,推论:接口不能创建对象(不能 new ),接口中不能定义普通方法。
(2) 接口中定义的成员变量,实质是全局静态常量,默认使用 public static final来修饰.
interface IWorkable
{
String name = "name";
}
反编译:
(3) 接口中定义的方法都是公共的抽象方法,默认的使用 public abstract 来修饰方法.
interface IWorkable
{
void doWork();
}
反编译:
一般的,我们在接口中定义方法,不喜欢使用修饰符.
(4) 接口中定义的内部类都是公共的静态内部类,默认使用public static来修饰内部类。
interface IWorkable
{
class test{}
}
反编译:
标志接口:
接口中没有任何成员,就仅仅是一个接口的定义,就是一个标志,其他的类实现该接口,就属于该家族,我们可以通过第三方代码赋予该接口实现类特殊的功能(不推荐)。
常量接口:
有人喜欢使用接口来封装多个常量信息,
我们称之为常量接口,其目的和常量类相同(不推荐)。
咱们使用的接口,主要都包含了抽象方法。
四. 接口的特点
(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();
}
}
八. 接口与抽象类的区别
相同点:
(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 秒) - 正常终止