Nivelle 开拓视野冲破艰险看见世界 身临其境贴近彼此感受生活

java基础(七)之接口

2017-06-10
nivelle

抽象类和抽象方法

包含抽象方法的类叫做抽象类。如果一个类包含一个或多个抽象方法,该类必须被限定为抽象的。(否则,编译器就会报错)

如果从一个抽象类继承,并想创建该新类的对象,那么就必须为基类中的所有抽象方法提供方法定义。如果不这样做(可以选择不做),那么导出类便也是抽象类,且编译器将会将会强制我们用abstract关键字来限定这个类。

我们也可以创建一个没有任何抽象方法的抽象类。考虑这种情况:如果有一个类,让其包含任何abstract方法都显得没有实际意义,而且我们也想阻止产生这个类的任何对象,那么这时这样做就很有用了。

接口

interface关键字使抽象的概念向前迈进了一步,它根本就没有提供任何具体实现,这些实现是由此类的继承者创建的。一个接口表示:所有实现了该特定接口的类看起来都像这样。因此,任何使用某特定接口的代码都知道可以调用该接口的那些方法,而且仅需知道这些。因此,接口被用来建立类与类之间的协议。

interface不仅仅是一个极度抽象的类,因为它允许人们创建一个能够被向上转型为多种基类的类型,来实现某种类似多重继变种的特性。

接口前面也可以加public关键字,如果不添加,则它只有包访问权限,这样它就只能在同一个包内可用。接口也可以包含域,但是这些域隐式地是static和final的。

可以选择在接口中显示地将方法声明为public的,但即使你不这么做,它们也是public的。因此,当要实现一个接口时,在接口中被定义为是public的,否则,它们只能得到默认的包访问权限,这样在方法被继承的过程中,其可访问权限就被降低了,这是java编译器不允许的。

java中的多重继承

接口不仅仅是一种更纯粹的抽象类,它没有任何具体实现,也就是说没有任何与接口相关的存储,因此也就无法阻止多个接口的组合.

导出类中,不强制要求必须有一个抽象的或”具体”(没有任何抽象方法)的基类.如果从一个非接口的类继承,那么只能从一个类去继承,其余的基元素都必须是接口.需要将所有的接口都置于implements关键字之后,用逗号一一分开.可以继承任意多个接口,并向上转型为每个接口,因为每一个接口都是一个独立类型.

package learn;

interface CanFight{
  void fight();
}
interface CanSwim{
  void swim();
}

interface CanFly{
  void fly();
}
class ActionCharacter{
  public void fight(){System.out.println("i am fighting in actionCharacter");};
}

class Hero extends ActionCharacter implements CanFight,CanFly,CanSwim{

  @Override
  public void swim() {
    System.out.println("i am swimming");
    
  }

  @Override
  public void fly() {
    System.out.println("i am flying");
    
  }
  
}
public class Adventure {
    public static void t(CanFight x){x.fight();}
    public static void u(CanSwim x){x.swim();}
    public static void v(CanFly x){x.fly();}    
    public static void w(ActionCharacter x){x.fight();}
    public static void main(String args[]){
      Hero h = new Hero();
      t(h);
      u(h);
      v(h);
      w(h);
    }
}



使用接口的核心原因:

  • 能向上转型为多个基类型

  • 防止客户端程序员创建该类的的对象,确保这仅仅是建立一个接口.

原则:如果知道某个事物应该成为一个基类,那么第一个选择应该是使他成为一个接口.

通过继承来拓展接口

通过继承,可以很容易地在接口中添加新的方法声明,还可以通过继承在新接口中组合数个接口.这两种方式都可以获得新的接口:

package learn;

interface Monster {
  void menace();
}

interface DangerousMonster extends Monster {
  void destory();
}

interface Lethal {
  void kill();
}

class DragoonZilla implements DangerousMonster {

  @Override
  public void menace() {
    System.out.println("DragoonZilla process menace");

  }

  @Override
  public void destory() {
    System.out.println("DragoonZilla process destory");

  }

}

interface Vampire extends DangerousMonster, Lethal {
  void drinkBlood();
}

class VeryBadVampire implements Vampire {

  @Override
  public void destory() {
    System.out.println("VeryBadVampire process destory");

  }

  @Override
  public void menace() {
    System.out.println("VeryBadVampire process menace");

  }

  @Override
  public void kill() {
    System.out.println("VeryBadVampire process kill");

  }

  @Override
  public void drinkBlood() {
    System.out.println("VeryBadVampire process drinkBlood");

  }

}

public class HoeeorShow {
  static void u(Monster b) {
    b.menace();
  }

  static void v(DangerousMonster d) {
    d.menace();
    d.destory();
  }

  static void w(Lethal l) {
    l.kill();
  }

  public static void main(String args[]) {
    DangerousMonster barney = new DragoonZilla();
    u(barney);
    v(barney);
    Vampire vlad = new VeryBadVampire();
    u(vlad);
    v(vlad);
    w(vlad);
  }
}




DangerousMonster是Monster的直接拓展,它产生了一个新接口.DragonZilla中实现了这个接口.

在Vampire中使用的语法仅适用于接口继承.一般情况下,只可以将extends用于单一类,但是可以引用多个基类接口.就像如上列子,只需要用逗号将接口名一一分隔开即可.

适配接口

接口最吸引人的原因之一是允许同一个接口具有多个不同的实现.在简单的情况中,它的体现形式通常是一个接受接口类型的方法,而该接口的实现和向该方法传递的对象则取决于方法的使用者.

接口中的域

放入接口中的任何域都自动是static和final的,所以接口就成为了一种便捷的用来创建常量组的工具.接口中的域自动是public的,所以可以不用显示指明. SE5之后可以使用enum了,所以接口中的域就没什么意义了.

接口中的域在第一次被加载时初始化,这发生在任何域首次被访问时.这些域不是接口的一部分,它们的值被存储在该接口的静态存储区域内.

接口与工厂

接口是实现多重继承的途径,而生产遵循某个接口的对象的典型方式就是工厂方法设计模式.这与直接调用构造器不同,我们在工厂对象上调用的是创建方法,而该工厂对象将生成接口的某个实现的对象.

package learn;

interface Service {
  void method1();

  void method2();
}

interface ServiceFactory {
  Service getService();
}

class Implementation1 implements Service {
  public Implementation1() {

  }

  @Override
  public void method1() {
    System.out.println("implementation1 method1");

  }

  @Override
  public void method2() {
    System.out.println("implementation1 method2");

  }
}

class Implementation1Factory implements ServiceFactory {

  @Override
  public Service getService() {
    // TODO Auto-generated method stub
    return new Implementation1();
  }

}

class Implementation2 implements Service {
  public Implementation2() {
    // TODO Auto-generated constructor stub
  }

  @Override
  public void method1() {
    // TODO Auto-generated method stub

  }

  @Override
  public void method2() {
    // TODO Auto-generated method stub

  }

}

class Implementation2Factory implements ServiceFactory {

  @Override
  public Service getService() {
    // TODO Auto-generated method stub
    return new Implementation2();
  }

}

public class Factories {
  public static void serviceConsumer(ServiceFactory fact) {
    Service s = fact.getService();

    s.method1();
    s.method2();
  }
  public static void main(String[] args) {
    serviceConsumer(new Implementation1Factory());
    serviceConsumer(new Implementation2Factory());
  }
}


如果不是工厂方法,就必须在某处指定将要创建的Service的确切类型,以便调用合适的构造器.


评论