接口与抽象类

Abstract约定

在Java的世界里,如果一个类提供了某个功能的骨架实现,则会将这个类命名为AbstractXXX。 比方说AbstractList, AbstractMap…

强制让子类覆盖弗雷里面的方法

  1. 抛出异常 AbstractCollection里面的add()方法,throw UnSupportedOperationException(); 为什么要抛出这个异常而不是编译时候的错误呢?因为AbstractCollection的子类有可能是 不可变的类,也有可能是可变的类。可变的类会重写这个方法(@Override),不会报错。但是如果 没有重写这个方法的话,说明是不可变得类,调用add()方法应该报错。

  2. 抽象类/抽象化

    • 抽象类不能被实例化。因为抽象类的抽象方法是空的,调用的时候不知道该干什么。
    • 可以实例化的子类一定要补全所有方法体
    • 可以包含抽象方法
    • 可以包含成员变量
  3. 接口

    • 接口不是类,只代表某种功能
    • 内部类可以声明在任何东西里面: 类,抽象类,接口,枚举..
    • 接口中的成员只能包含 public static final,默认就是这样,写不写都一样
    • 接口中可以定义默认的实现,通过default来补充之前设计没有想到方法,比如List里面的sort方法, 而且不会破坏向后兼容性。但是这样的会产生一个问题,两个接口定义同名的default函数,一个类实现了 这两个接口,那么这个类到底选择了哪一个default函数呢?事实上编译器会报错的。
  4. (IDEA快捷键 -> 一个接口的实现类)

  5. 为什么Java要这样设计

    • 为了实现最大程度的灵活性和最大程度的复用(本身两者是矛盾的)
    • 灵活性是指每个人都可以写自己的代码
    • 复用是指大家一起共用相同的代码
  6. Comparable接口

    • 约定:
      1. 当a<b,返回负数
      2. 当a=b,返回0
      3. 当a>b,返回正数
    • List.sort(aList)要求aList实现Comparable接口,否则无法进行排序
    • 一个非常大的坑:TreeSet里面,如果两个不相等的元素因为实现Comparable接口时 的错误代码而被判断为相等,那么因为Set本身是不会容纳相同的元素的,所以相同 的元素会被随机选中而丢掉,造成难以发现的bug(两个不等的元素,compareTo绝对不能返回0)
  7. 内部类和静态内部类的区别

    1. 每一个内部类都和外部的类的实例相绑定,这使得内部类可以直接调用外部类的实例方法! (编译器偷偷地注入了一个外围类的实例,比如 private Home this$0, 进入target/classes/…,javap -private ‘Home$CatNameCollector’)
    2. 静态内部类不和外部类的实例相绑定,所以不能调用外部类的实例方法
    3. 永远使用静态内部类,除非编译器报错
    4. 匿名内部类只是在代码里面没有名字,编译后的文件名是其所在的外围类的名字+$1/2/3… 4.把外围类变成匿名内部类的好处是内部类可以直接调用其外围类的参数,不用传来传去,而且代码也更加紧密。