天天看點

JAVA學習筆記--接口篇

接口指定了類必須執行的操作,但并不指定具體的方法,可以把接口當作類的大綱或者藍圖(如果一個類實作了一個接口,但并沒有為該接口中的所有方法提供方法主體,那麼該類必須是抽象類)。

類實作接口的步驟

  1. 将類聲明為實作給定的接口
  2. 對接口中的所有方法進行定義

舉例如下

class Employee implements Comparable //implements關鍵字表示類實作某個接口
{
  ...
  public int compareTo(Object otherObject) //對接口中的所有方法進行定義
  {
    Employee other = (Employee) otherObject;
    return Double.compare(salary,other.salary)
  }
}
           

繼承中可能存在的問題

請看例子

class Manager extends Employee
{
  public int compareTo(Employee other)
  {
    Manager otherManager = (Manager) other;
  }
  ...
}
           

在繼承的過程中,Manager覆寫了compareTo方法,在進行比較時,假設x是一個Employee對象,y是一個Manager對象,調用x.compareTo(y)時不會出現異常,但是當調用y.compareTo(x)時,會抛出ClassCastException。

解決辦法

如果子類之間的比較含義不一樣,不同子類之間無法比較,那以上例子就屬于非法比較,應該在比較的方法前進行以下檢測

如果子類之間有通用的比較方法,則應該在超類中提供一個比較方法,并将該方法聲明為final。

接口的特性

  • 無法構造接口的對象,但能聲明接口的變量
x = new Compareble(...); //ERROR
Comparable x; //OK
           
  • 可以使用instance檢查一個對象是否實作了某個特定的接口
  • 如同建立類的繼承關系一樣,接口可以被擴充
public interface Moveable
{
  void move(double x, double y);
}
public interface Powered extends Moveable      //擴充接口
{
  double milesPerCallon();
}
           
  • 之是以引入接口的概念,是因為Java中不存在多重繼承,引入接口可以提供多重繼承的大多數好處,同時還能避免多重繼承的複雜性和低效性。

預設方法

可以為接口方法提供一個預設實作,但必須用default修飾符标記這樣一個方法。如下

public interface Comparable<T>
{
  default int comparableTo(T other){return 0;}
}
           

預設方法的一個重要用法是“接口演化”。舉例,以Collection接口為例,假設初始時提供了這樣一個類

後來,在Java SE 8中又為該接口增加了一個stream方法,如果stream方法不是預設方法,由于Bag類中沒有實作這個新方法,是以Bag類将編譯失敗。

Java中解決預設方法沖突

  1. 超類優先。如果超類提供了一個具體方法,同名且有相同參數類型的預設方法會被忽略
  2. 接口沖突。如果一個超接口提供了一個預設方法,另一個接口提供了

    一個同名而且參數類型相同的方法,那麼必須覆寫這個方法來解決沖突。舉例如下

interface Named
{
  default String getName() {return getClass().getName()+"-"+hashCode();}
}

interface Person
{
  default String getName() {return getClass().getName();}
}

//假設有一個類同時實作了這兩個接口
class Student implements Person,Named
{
  public String getName() {return Person.super.getName();}  //覆寫兩個接口中的getName方法
}
           

繼續閱讀