Abstract 抽象类介绍

  • 抽象类:
    • 不可被实例化
    • 可以实例化的东西一定要补全所有的方法体
    • 可以包含抽象方法 - 非private/public
    • 可以包含成员变量
    • 声明:public abstract class Name {}
  • JDK中有非常多这样的例子,比如:
    • ArrayList -> AbstractList -> Collection -> Iterator
    • AbstractMap
  • 具体的类去提供行为,覆盖抽象类的方法
  • 抽象方法:abstract void method() {}

接口

  • 接口部分地实现了多继承,一个类能够实现多个接口
  • 接口不是类
  • 接口的扩展
  • 接口只代表一种功能实现的合约

接口能够包含什么

  • 方法(默认public)
  • 常量(默认public static final)
  • extends接口
  • 默认方法(有方法体的):
    • Since Java 8
    • 是一种妥协产物
    • 可以用来实现mixin
    • 菱形继承
  • Java 8之前接口方法不能有方法体,只声明方法的签名

接口的限制

  • 一个接口一旦发布,就不能修改了,否则会导致所有实现该接口的类失效,打破了向后兼容性
    • Java 8 之后破解了这个限制,可以设置默认方法 default fn() {}
    • 默认方法可以有方法体
  • 接口的设计本意是避免二义性,default接口方法的产生又引入的二义性

使用场景

  • 当你想要复用一些代码,用抽象类
  • 当你想要描述一个功能,用接口,接口抽象程度更高

抽象类和接口对比

1. 共同点:

  • 抽象,不可实例化
  • 可包含抽象方法,没有方法体

    2. 不同点:

  • 抽象类是类,可以包含类的一切东西,但是接口只能包含受限的成员和方法

  • 抽象类只能单一继承,但是接口可以implements多个或者多次

抽象类和接口设计的意义

  • 最大程度的灵活性
  • 最大程度的代码复用

多态实战:FileFilter

  • FIles.walkFileTree
  • 实现FileVisitor接口
  • FileVisitor的默认实现:SimpleFileVisitor

接口和抽象类实现策略模式

内部类详解

使用内部类有助于写代码时注意力的集中,同时提供足够程度的封装。

1. 匿名内部类

  1. // ...
  2. static class UserFilter implements XxFilter {
  3. public boolean isValid () {}
  4. }
  5. public void main() {
  6. return filter(users, new UserFilter() {
  7. @Override
  8. public boolean isValid(User user) {
  9. return user.id % 2 == 0;
  10. }
  11. });
  12. // lambda实现
  13. // return filter(users, user -> user.id % 2 == 0});
  14. }
  15. // JDK内部有Predicate接口,其中test方法用于给定一个元素,返回判断布尔值
  16. public static List<User> filter(List<User> users, Predicate<User> predicate) {
  17. List<User> ret = new ArrayList<>();
  18. for(User u : users) {
  19. if(predicate.test(u)) ret.add(u);
  20. }
  21. return ret;
  22. }

2.隐藏细节

  • private内部类可以不受限地互相访问对方
  • 而外部无法访问private的内部类

3.静态内部类

  • 内部类: private class A {}:

    • 和它的外围类的实例相绑定(是实例的内部类)
    • 在里面调用的是外围类的实例的方法
    • tips:编译器帮你在内部类中注入了一个外围类的实例 this$0
  • 静态内部类:private static class A {}:

    • 是外围类的内部类,不与实例相绑定
    • 在里面调用的是外围类的类方法,不能调用实例方法
    • 想调用外围类的实例方法,可使用A类的构造器将实例传入

4. 内部类不止可以用在类中,可以用在接口,枚举,抽象类等各种地方