java接口概述

【0】README

0.1) 本文描述+源代码均 转自 core java volume 1, 旨在理解 java 接口概念 ;
0.2)接口技术: 这种技术主要用来描述类具有什么功能, 并不给出每个功能的具体实现; 一个类可以实现多个接口, 但只允许单继承;
0.3) 最后简单阐述了 接口和抽象类 的 区别;

【1】 接口

1.1)接口中的所有方法自动属于public: 故,在接口中声明方法时,不必提供关键字public;
1.2)接口可以包含多个方法: 在接口中还可以定义常量;然而,更重要的是 要知道接口不能提供哪些功能;接口不能提供实例域, 也不能在接口中实现方法, 提供实例域和方法实现的任务应该由实现接口的那个类来完成;因此,可以将接口看做是没有实例域的抽象类,但接口和抽象类还是有区别的, 稍后给出解释
1.3)为了让类实现一个接口, 需要以下两个steps:

  • step1)将类声明为实现给定的接口;
  • step2)对接口中的所有方法进行定义;
  • Warning)因为 接口中的所有方法自动属于public, 故,在接口中声明方法时,不必提供关键字public;但是 ,类在实现接口时,必须把方法声明为 public, 否则,编译器将认为这个方法的 访问属性是包可见性, 即类的默认访问属性;

1.4)排序访问必须让它实现 compareTo 方法:我们已经看到, 要让一个类使用排序访问必须让它实现 compareTo 方法,这是理所当然的,因为要向 sort方法提供对象的比较方式;
1.5)但是 , 为什么不能在 Employee类直接提供一个 compareTo 方法, 而必须实现 Comparable 接口呢? 主要原因在于 java 是一种强类型的语言;在调用方法的时候, 编译器将会检查这个方法是否存在, 如,

if(a[ i ].compareTo(a[ j ]) > 0)
{
............
}

编译器必须确认 a[i] 一定有 compareTo 方法,如果a 是一个 Comparable 对象 的数组, 就可以确保拥有 compareTo 方法,因为每个实现 Comparable 接口的类都必须提供这个方法的定义;
1.6)看个荔枝:

[API] java.lang.Comparable<T> 1.0
int compareTo(T other) :用这个对象域 与 other 进行比较;
[API] java.util.Arrays 1.2
static void sort(Object[] a) : 使用mergesort 对数组a中的元素进行排序; 要求数组中的元素必须实现了 Comparable 接口的类, 并且元素间必须是可
比较的;
[API] java.lang.Integer 7
static int compare(int x, int y) : 如果x<y 返回一个负数, 相等返回0, 否则返回一个正数;

Annotation)

  • A1)语言标准规定: 对于任意的x 和 y, 实现必须能够保证 sgn(x.compareTo(y)) = -sgn(y.compareTo(x)); 这也就是说, 如果y.compareTo(x) 抛出 一个异常,那么 x.compareTo(y) 也应该抛出一个异常;
  • A2)这里的sgn 是一个数值的符号: 如果n为负值, sgn(n) 等于 -1, 如果n是0, sgn(n) 等于0;如果n是正数, sgn(n) 等于1;
  • A3)简单讲, 如果调换compareTo 的参数,结果的符号也应该调换(而不是实际值);

出现的问题)因为 Manager 扩展了 Employee, 而 Employee实现的是Comparable , 而不是 Comparable, 如果 Manager覆盖了 compareTo, 就必须要有经理 与 雇员进行比较的心理准备, 决不能仅仅将 雇员转换为 经理;

class Manager extends Employee
{
    public int compareTo(Employee other)
    {
        Manager otherManger = (Manager)other; //NO
        ......
    }
}
  • P1)这不符合 “反对称”的规定:如果x是一个 Employee对象, y 是一个 Manager对象, 调用 x.compareTo(y) 不会抛出异常, 它只是将 x 和 y 都作为雇员进行比较。 但是反过来, y.compareTo(x) 将会抛出一个 ClassCastExcaption;

解决办法(Solutions):

  • S1)如果子类之间的比较含义不一样, 那就属于不同类对象 的非法比较, 每个 compareTo 方法都应该在开始时 进行下列检测:
    if(getClass != other.getClass()) throw new ClassCastException();
  • S2)如果存在这样一种通用算法, 它能够对两个不同的子类对象进行比较,则应该在超类中提供一个 compareTo方法, 并将这个方法法声明为final;
  • S3)假如 不管薪水的多少,都想让 manager 大于 雇员, 即如果要按照职务排列 的话, 那就应该在 Employee类中 提供一个 rank方法, 每个子类覆盖rank, 并实现一个 比较 rank值的 compareTo 方法;

【2】 接口的特性

2.1)可以声明接口变量, 且接口变量必须引用实现了接口的类对象:

Comparable x ; 这是OK 的;
x = new Employee();

2.2)可以使用 instanceof 检查一个对象是否实现了某个特定的接口:

if(anObject instanceof Comparable) {}

2.3)接口也可以继承, 这里允许存在多条从具有较高通用性接口到较高专用性接口的链:看个荔枝

public interface Moveable {
    void move(double x, double y);
}
//然后用 Movable 扩展一个 Powered 的接口:
public interface Powered extends Moveable {
    double milesPerGallon();
}
//虽然在接口中不能包含实例域或静态方法, 但可以包含常量:
public interface Powered extends Moveable {
    double milesPerGallon();
    double SPEED_LIMIT = 95; // a public static final constant
}
  • Attention)与接口中的方法都自动被设置为 public, 接口中的 域都被自动设为 public static final
  • Annotation)有些接口只是定义了常量,而没有定义方法, 这样应用接口似乎有点偏离了接口概念的初衷,所以, 最好不要这样用它;

2.4)类是单继承,但是可以实现多个接口;看个荔枝:
java 中有一个 非常重要的 内置接口, Cloneable, 如果某个类实现了这个Cloneable 接口,Object类中的 clone 方法就可以创建类对象的一个copy, 如果希望自己设计的类拥有 克隆和比较的能力, 只要实现这两个接口就可以了(一个类可实现多个接口)

class Employee implements Cloneable, Comparable

【3】接口与抽象类

3.1)疑问?为什么java还要不辞辛苦引入接口概念? 为什么不将 Comparable直接设计成抽象类:

abstract class Comparable
{
    public abstract int compareTo(Object obj);
}
//然后, Employee再扩展这个抽象类, 并提供 compareTo方法的实现:
class Employee extends Comprable
{
    public int compareTo(Object other){ ... }
}

3.2)使用抽象类表示通用属性存在这样一个问题:每个类只能扩展一个类, 假设 Employee 类已经扩展了一个类, 比如Person, 它就不能再像下面这样扩展第二个类了; 但是每个类可以实现多个接口:

class Employee extends Person implements Comparble //OK

你可能感兴趣的:(java,接口,接口与抽象类)