Více rozhraní a jejich rozšiřování (dědičnost)

Tomáš Pitner, Radek Ošlejšek, Marek Šabo

Implementace více rozhraní I

  • Jedna třída může implementovat více rozhraní.

  • Jednoduše v případě, kdy objekty dané třídy toho "mají hodně umět".

  • Příklad: Třída Person implementuje 2 rozhraní:

public interface Informing { String retrieveInfo(); }
public interface Screaming { String scream(); }

public class Person implements Informing, Screaming {
  public String retrieveInfo() { ... }
  public String scream() { ... }
}

Implementace více rozhraní II

  • Co kdyby obě rozhraní měla stejnou metodu?

public interface Informing { String retrieveInfo(); }
public interface Screaming { String retrieveInfo(); }
  • Mají-li úplně stejnou hlavičku, je to v pořádku:

public class Person implements Informing, Screaming {
  @Override
  public String retrieveInfo() { ... }
}

Implementace více rozhraní III

  • Mají-li stejný název i parametry, ale různý návratový typ, je to PROBLÉM.

public interface Informing { String retrieveInfo(); }
public interface Screaming { void retrieveInfo(); }
public class Person implements Informing, Screaming { ... }
  • To samozřejmě nelze — viz totéž u přetěžování metod:

Person p = new Person();
// do we call method returning void or
// string and we ignore the result?
p.retrieveInfo();
Nesnesou se tedy metody lišící se pouze návratovým typem.

Rozhraní — vtip

Metody i samotné rozhraní by mělo obsahovat kvalitní dokumentaci s detailním popisem.

Rozhraní je jako vtip. Když ho třeba vysvělovat, není tak dobré.

Zajímavost — rozhraní bez metod

  • Občas se kupodivu používají i prázdná rozhraní, nepředepisující žádnou metodu.

  • Úplně bezúčelné to není — deklarace, že třída implementuje určité rozhraní, poskytuje typovou informaci o dané třídě.

  • Např. java.lang.Cloneable, java.io.Serializable.

Rozšiřování (dědičnost) rozhraní

  • Rozhraní může převzít (můžeme říci též dědit) metody z existujících rozhraní.

  • Říkáme, že rozhraní mohou být rozšiřována (extended).

  • Rozšířené rozhraní by mělo nabízet něco navíc než to výchozí (rozšiřované).

  • Příklad: Každá třída implementující WellInforming musí pak implementovat i metody z rozhraní Informing:

interface Informing {
  String retrieveInfo();
}
interface WellInforming extends Informing {
  String detailedInfo();
}
public class Person implements WellInforming {
  public String retrieveInfo() { ...  }
  public String detailedInfo() { ... }
}

Kde použít implements a kde extends

  • Ztrácíte se v klíčových slovech?

  • implements = třída implementuje rozhraní

    • ve třídě musím napsat kód (obsah) metod předepsaných rozhraním

  • extends = když dědím ze třídy nebo rozšiřuji rozhraní

    • dědím metody automaticky

Vícenásobé rozšiřování rozhraní

  • Rozhraní může dědit z více rozhraní zároveň:

public interface Informing { String retrieveInfo(); }
public interface Screaming { String scream(); }

public interface WellInforming extends Informing, Screaming {
  String detailedInfo();
}
  • Každá třída implementující WellInforming musí implementovat všechny 3 metody.

Řetězení rozšiřování (dědičnosti)

  • Dědičnost můžeme řetězit:

public interface Grandparent { int method1();  }
public interface Parent extends Grandparent { int method2(); }
public interface Child extends Parent { int method3(); }
  • Grandparent pak obsahuje jednu metodu, Parent dvě, Child tři.

Kdy je vícenásobné rozšiřování možné

  • Úplně stejné metody ze dvou rozhraní jsou OK

public interface A {
  void someMethod();
}
public interface B {
  void someMethod();
}
public interface AB extends A, B {
  // it is OK, methods have same signature
}

Kdy je vícenásobné rozšiřování možné

  • Stejné metody s různými parametry ze dvou rozhraní jsou také OK

public interface A {
  void someMethod();
}
public interface B {
  void someMethod(int param);
}
public interface AB extends A, B {
  // it is OK, methods have different params
}

Kdy vícenásobné rozšiřování není možné

  • Dvě metody lišící se jen návratovým typem nejsou OK

  • Třída implementující rozhraní AB by musela mít dvě metody lišící se jen návratovým typem, a to nejde

public interface A {
  void someMethod();
}
public interface B {
  int someMethod();
}
public interface AB extends A, B {
  // cannot be compiled
}