任何抽象性都应该由需要驱动,有必要时才应该使用接口进行重构。 恰当的原则是有限

抽象类和方法

  • 创建抽象类是为了通过接口操纵一系列类
  • 若一个类包含一个或多个抽象方法,类本身也要为抽象类
  • 抽象类不能实例化
  • 继承抽象类的子类若要创建对象,则必须为基类所有抽象方法定义
  • 阻止别人创建对象可在前+abstract

接口创建

  • interface 关键字产生一个完全抽象的类,任何使用某特定接口的代码只能且仅需知道可以调用哪些该接口中的方法,而无法决定方法体
  • implements 使一个类遵循某个特定接口,提供接口实现。且来自接口中的方法必须被设置为public。 ```java interface Concept{ void idea1(); }

class Implementation implements Concept{ @Override public void idea1(){ System.out.println(“idea1”); } }

  1. - **default:** 当实现接口却没有定义方法时,可以使用** default** 创建的方法体。
  2. ```java
  3. interface Concept{
  4. void idea1();
  5. default void idea2(){
  6. System.out.println("default idea2");
  7. }
  8. }
  • 多继承:一个implementation可以实现多个接口,只要接口中所定义的函数方法签名(方法名+参数类型)[返回类型不行] 不同

    1. class MI implements One, Two, Three {}
  • 多继承产生冲突时,需要通过Overrride 来解决冲突。

    • super 关键字选择其中一个基类实现
    • 直接覆写
  • 静态方法:将工具功能置于接口,从而操作接口,成为通用工具。

    1. public interface Operations {
    2. void execute();
    3. static void runOps(Operations... ops) {
    4. for (Operations op: ops) {
    5. op.execute();
    6. }
    7. }
    8. //这个东西还蛮好玩
    9. //runOps()使用可变参数列表,按照传入顺序运行不同实现的execute()

抽象类与接口比较

特性 接口 抽象类
组合 新类可以组合多个接口 只能继承单一抽象类
状态 不能包含属性(除了静态属性,不支持对象状态) 可以包含属性,非抽象方法可能引用这些属性
默认方法 和 抽象方法 不需要在子类中实现默认方法。默认方法可以引用其他接口的方法 必须在子类中实现抽象方法
构造器 没有构造器 可以有构造器
可见性 隐式 public 可以是 protected 或友元

Java中的协变和逆变

  1. LSP原则:所有引用基类的地方必须能透明地使用其子类的对象。

    这里主要介绍后面两层定义:

    • 当子类覆盖或实现父类的方法时,方法的形参要比父类的方法更加宽松。
    • 当子类覆盖或实现父类的方法时,方法的返回值比父类更严格。
  2. Java常见类型转换的协变、逆变或不变性
    • 泛型——不变
    • 数组——协变
    • 方法
      • 普通情况:方法的形参是协变的、返回值是逆变的。
      • 从Java1.5开始,子类覆盖父类方法的时候允许协变返回更为具体的类型。 ```java class Super { Number method(Number n) { … } }

class Sub extends Super { @Override Integer method(Number n) { … } }

  1. 3. 泛型中的通配符
  2. - `<? extends>` 实现泛型协变
  3. `List<? extends Number> list = new ArrayList();`
  4. - `<? super>` 实现泛型逆变
  5. `List<? super Number> list = new ArrayList`
  6. 4. 理解extends & super
  7. ```java
  8. Number num = new Integer(1);
  9. ArrayList<Number> list = new ArrayList<Integer>(); //type mismatch
  10. List<? extends Number> list = new ArrayList<Number>();
  11. list.add(new Integer(1)); //error
  12. list.add(new Float(1.2f)); //error

由于 <? entends Number> 实行协变,表示list的类型为 Number与Number派生子类中的某一个,可以为Integer但不一定。故编译器在编译时无法确定这个list究竟为什么类型,所以会报错。
而改为 <? super Number> 后,表示list的类型为 Number与Number基类中的某一类型。
**extends** 确定泛型上界, **super** 确定泛型下界。

  1. PECS (produce extends,consume super) ```java // Wildcard type for parameter that serves as an E producer public void pushAll(Iterable<? extends E> src) { for (E e : src)
    1. push(e);
    } //假设src为Iterable对象 //produce过程

// Wildcard type for parameter that serves as an E consumer public void popAll(Collection<? super E> dst) { while (!isEmpty()) dst.add(pop()); } //假设泛型为Collection对象 //consume过程

  1. - 取数据,extends
  2. - 写数据,super
  3. - 又取又写,不用通配符
  4. <a name="tgo11"></a>
  5. ## 多接口结合
  6. 在多接口结合时,**派生类并不要求继承抽象或者完全具体的类。**<br />**若继承了一个非接口类,只能继承一个类。其余基元素必须是接口。**
  7. ```java
  8. interface CanFight {
  9. void fight();
  10. }
  11. interface CanSwim {
  12. void swim();
  13. }
  14. class ActionCharacter {
  15. public void fight(){System.out.println("fight");}
  16. }
  17. class Hero extends ActionCharacter implements CanFight,CanSwim{
  18. public void swim() {}
  19. }

若在 ActionCharacter 中没有 fight() 的实现,编译不会通过。

使用继承扩展接口

  1. interface Monster {
  2. void menace();
  3. }
  4. interface DangerousMonster extends Monster {
  5. void destroy();
  6. }
  7. class DragonZilla implements DangerousMonster {
  8. @Override
  9. public void menace() {}
  10. @Override
  11. public void destroy() {}
  12. }

嗯….

接口适配(Java设计模式)

接口最吸引人的原因之一就是允许同一个接口具有多个不同的实现

即每个实现接口的类都可以给这个接口所有方法不同实现,而不用修改主题框架代码。
TODO: read these blogs

对于书上内容不是很理解,建议阅读以上内容。

接口字段

接口字段自动为 staticfinal 的。
接口中字段不能是“空 final ”,但是可以用非常量表达式初始化,并且在类第一次被加载时初始化。

  1. public interface RandVals {
  2. Random RAND = new Random(47);
  3. int RANDOM_INT = RAND.nextInt(10);
  4. }