大家好,我是小刀,今天和大家讨论一下接口实现的两个问题,众所周知,接口是设计模式的基石,所以了解接口的一些实现对理解设计模式,源码都大有裨益!
接口圈真乱
之所以会提出如标题中的问题, 是因为在看 ArrayList 时,发现接口实现好像有点混乱
如上图所示,其实是有两个问题 1. AbstractList
实现了 List 接口, 然后 ArrayList
又实现了 List
接口. 2. Collection
接口中有个 size()
方法, List
接口中也有一个 size()
方法. 如果有某个类同时实现 Collection
和 List
接口, 会不会报错?
实践出真知
首先,我们能正常使用 ArrayList
说明上面两个问题应该是不成问题的.对于问题 1. 大家纠结的点应该是在于, 对于接口 A, 如果抽象类 B 实现了接口,那么子类 C 在实现接口时,还要不要重写方法
接口 Greet
/**
* @author lixiang
* @date 2020/6/16
**/
public interface Greet {
/**
* 加油的接口定义
*/
void cheer();
}
抽象实现类 AbstractGreet
/**
* @author lixiang
* @date 2020/6/18
**/
public abstract class AbstractGreet implements Greet {
}
这里我们看到抽象类实现接口,要不要去重写方法都不会报错但是通用来说, 抽象类的作用就是,要有一个通用的实现,所以一般来说,还是实现方法比较好, 然后再抛一个抽象的具体实现, 如下所示:
/**
* @author lixiang
* @date 2020/6/18
**/
public abstract class AbstractGreet implements Greet {
/**
* 加油的接口定义
*/
@Override
public void cheer() {
System.out.println("这里通常会做一些通用的处理,比如资源初始化,赋初值之类的");
doCheer();
}
/**
* 留给子类去实现
*/
public abstract void doCheer();
}
真正的子类 TrueGreet
/**
* @author lixiang
* @date 2020/6/17
**/
public class TrueGreet extends AbstractGreet implements Greet {
/**
* 留给子类去实现
*/
@Override
public void doCheer() {
System.out.println("加油加油");
}
}
在这里可以看到,虽然我们也实现了 Greet 接口,但是因为 AbstractGreet
已经实现过了接口,所以这里就不用再实现接口的 cheer
方法, 只需要实现抽象类的 doCheer()
方法就可以了,当然也可以实现
@Override
public void cheer() {
super.cheer();
System.out.println("子类自己的实现");
}
这样加上自己的实现也是没有问题的,所以说, 像开头 AbstractList
实现了 List 接口后, ArrayList
是不用再实现 List
的接口的, 实现了不重写其中的方法,编译也不会报错, 只能说是让结构更清晰一些. 这里还有一个比较有趣的现象,就是在 idea 中, 要重写方法时, 提示的是覆写抽象类的,而不是接口的,如下图所示:
报错的场景
上面都是正确的,其实有一种报错的场景要注意, 就是当两个不同的接口定义的方法签名不一致的时候(方法名,入参一样,返回值不一样)的时候,对于实现类,就找不到该重写哪个了,就会报错,如下所示
GreetCopy 接口
/**
* @author lixiang
* @date 2020/6/17
**/
public interface GreetCopy {
/**
* 加油的接口定义
*/
String cheer();
}
和最开始我们定义的 Greet
接口不一样的是, 返回值从 voi
改成了 String
,
如上图所示, 这样编译都是通不过的, 但是如果签名换成一样的,就不成问题了.
总结
其实在写本文之前,小刀也是对这些实现关系不是很清楚, 这样边实践边写下来就清晰多了.希望大家也能多实践,也如我一直说的,学编程其实就是多实践,多思考. 大家一起加油!
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于