7、接口
# 接口
接口是一个更抽象的思想,一个类通过继承接口的方式,从而来继承接口的抽象方法。
注 :接口并不是类,所以也不能实例化
可以说接口是再抽象类的基础上更抽象的规范。
使用interface
可以声明一个接口、implements
实现一个或多个接口,语法:
//定义接口
interface TrafficControlOffice {
public static final String name = "HaC";
public abstract void drive();
}
interface TrafficControlOffice2 {
void drive2();
}
//实现接口
public class Car implements TrafficControlOffice {
@Override
public void drive() {
}
}
接口中的方法会被隐式的指定为
public abstract
,所以这两个修饰符不需要写出来(写不写效果都一样)。接口中可以含有变量,但是接口中的变量会被隐式的指定为
public static final
变量(并且只能是 public,用 private 修饰会报编译错误)。
# 接口继承
一个interface
可以继承自另一个interface
,相当于扩展了接口的方法。
# 接口的意义
在JavaSE中,接口的使用比较少,在初学者面试,很难体现接口的意义。
下面来举个栗子来看看接口的意义。
虽然哈C我买了好几辆车,但是车要上路,就要遵循车管所的要求,必须上牌、登记好信息才行。
车管所规定:我提供了drive()
方法,只要汽车厂商按照我的方法行驶,就能上路。
我只要实现车管所的方法,就能愉快的开车了:
interface TrafficControlOffice {
void drive(); //车管所规定的drive()
}
public class Car implements TrafficControlOffice {
@Override
public void drive() {
System.out.println("平平无奇地开车");
}
}
class WuLingHongGuang extends Car {
@Override
public void drive() {
System.out.println("开五菱宏光");
}
}
class BaoMa extends Car {
@Override
public void drive() {
System.out.println("开宝马");
}
}
假如哈C我又要买车了,这次买了一辆 大货车 Truck
,大货车并不属于Car
,如果我要开上路,那怎么办?
简单,我也只需要实现车管所TrafficControlOffice
的方法就行了。
class Trunk implements TrafficControlOffice{
@Override
public void drive() {
System.out.println("开大货车");
}
}
开车:
class HaC {
public static void main(String[] args) {
new WuLingHongGuang().drive();//开五菱宏光
new Trunk().drive(); //开大货车
}
}
之前说到我要请司机来帮我开车,那我现在只需要告诉司机,安装车管所的接口规定来开车即可:
class Driver {
public void driveCar(TrafficControlOffice trafficControlOffice) { //司机表示只要是TrafficControlOffice 交管所规定的车都可以开
trafficControlOffice.drive();
}
}
然后我就不需要担心车管所什么的了,我把我的车交给司机开就行了,只要他遵循车管所的规定即可。
让司机开车:
class HaC {
public static void main(String[] args) {
Driver driver = new Driver(); //请一个司机
driver.driveCar(new WuLingHongGuang()); //告诉司机开五菱宏光
driver.driveCar(new Trunk()); //告诉司机开大货车
}
}
输出:
开五菱宏光
开大货车
这样看,我可以不需要改变WuLingHongGuang
、BaoMa
这几个类,就可以实现我想要的功能了。
如果还不明显,我再举个小栗子,某一天我买比特币暴富了,我想买个飞机来开一下,但是我和我的司机不会开飞机怎么办?
我和司机学一起开飞机,但是也必须遵循航空局的规定驾驶技能才能驾驶飞机。
interface AerospaceOffice { //航空局规定的开飞机接口
void fly();
}
interface TrafficControlOffice {
void drive(); //车管所规定的drive()
}
class Driver implements AerospaceOffice {
public void driveCar(TrafficControlOffice trafficControlOffice) {
trafficControlOffice.drive();
}
@Override
public void fly() {
System.out.println("司机可以开飞机去玩了");
}
}
class HaC implements AerospaceOffice {
@Override
public void fly() {
System.out.println("哈C也可以开飞机去玩了");
}
}
public class Travel {
void flyToPlay(AerospaceOffice aerospaceOffice){ //面向接口编程
aerospaceOffice.fly();
}
public static void main(String[] args) {
Travel travel = new Travel(); //去旅行
Driver driver = new Driver(); //请司机
travel.flyToPlay(driver);//让司机开飞机
HaC haC = new HaC(); //亲自来
travel.flyToPlay(haC);//亲自来开飞机
}
}
输出:
司机可以开飞机去玩了
哈C也可以开飞机去玩了
# 总结
例子可能难理解,但是在代码的增加层面来说,我们不需要修改已有的代码,只需要增加就可以了,你尽管规定好方法名,我调用你的接口,我只考虑结果。
但是随着代码量增加、多人协作情况下,使用接口会减少很多问题,在接口定义对外的方法,写好注释,下次查看的时候就可以一眼明白方法的功能。
比如我要调用Driver
类的方法,让它帮我修车,那么Driver
这个类只需要返回修好的结果给我,至于你需要花费多少钱、需要什么工具,我完全不需要知道,你可以把用钱的方法、使用工具的方法 设成private
。
看到知乎有一个很形象的说法:
比如说你今年放假出去杭州旅游,玩了一上午,你也有点饿了,突然看到前面有个店子,上面挂着KFC,然后你就知道今天中饭有着落了。
KFC就是接口,我们看到了这个接口,就知道这个店会卖炸鸡腿(实现接口)。
那么为神马我们要去定义一个接口涅,这个店可以直接卖炸鸡腿啊(直接写实现方法),是的,这个店可以直接卖炸鸡腿,但没有挂KFC的招牌,我们就不能直接简单粗暴的冲进去叫服务员给两个炸鸡腿了。
要么,我们就要进去问,你这里卖不卖炸鸡腿啊,卖不卖汉堡啊,卖不卖圣代啊(这就是反射)。很显然,这样一家家的问实在是非常麻烦(反射性能很差)。 要么,我们就要记住,中山路108号卖炸鸡,黄山路45号卖炸鸡(硬编码),很显然这样我们要记住的很多很多东西(代码量剧增),而且,如果有新的店卖炸鸡腿,我们也不可能知道(不利于扩展)。
作者:Ivony 链接:https://www.zhihu.com/question/20111251/answer/16585393 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
# 接口的特点
接口中方法默认是
public abstract
(只能是这两个关键字,或其中一个或都省略)。因为要被继承,所以是public
的。接口中的变量默认是
public static final
(只能是这三个关键字,或其中两个/一个或都省略)。接口中有成员变量意义不大,实现类可以通过接口名称.变量名称
来调用。java中一个类只能继承一个类,但一个接口可以继承多个接口。类也可以实现多个接口
接口不能实现接口。
接口中不能有构造方法。
1.8中及以后,接口中可以有
default
默认方法(普通方法),可以有静态方法和方法体了。
eg1:
public interface People {
public static String a ="1";
public static final String b ="2";
public static void test(){
System.out.println("我是接口的静态方法");
}
//普通方法
default void testA2() {
System.out.println("A");
}
public void test1();
}
eg2:
//定义接口
interface TrafficControlOffice1 {
void drive1();
}
interface TrafficControlOffice2 {
void drive2();
}
//接口的多重继承
interface TrafficControlOffice3 extends TrafficControlOffice1, TrafficControlOffice2 {
void drive3();
}
//实现多个接口
class Car1 implements TrafficControlOffice1, TrafficControlOffice2 {
@Override
public void drive1() {
}
@Override
public void drive2() {
}
}