一、概念
接口:就像类与类之间的一种协议,只需要知道某个类实现的某个接口, 那么,他就可以通过调用接口里面的方法来指向这个类的实现。
二、特性
(1)使用interface标注
(2)完全抽象
(3)属性域必须是public final static(这个是编译器自动转换的)
(4)方法必须是public
(5)向上转型,为父类指向子类对象提供途径,同时也使得java拥有多态这个特性
(6)不可以实例化
(7)接口可以多重实现
package com.ray.ch07;
public class Test {
public void tune(Instrument instrument) {
instrument.Play();
}
public void tune(Instrument[] instruments) {
for (int i = 0; i < instruments.length; i++) {
tune(instruments[i]);
}
}
public static void main(String[] args) {
Test test = new Test();
// Instrument instrument = new Instrument();//error
Instrument wind = new Wind();
Instrument bass = new Bass();
Instrument[] instruments = { wind, bass };
test.tune(instruments);
System.out.println(Instrument.id);// id是static
}
}
interface Instrument {
// private int id=0;//error
// private void Play();//error
int id = 0;
void Play();
}
class Wind implements Instrument {
@Override
public void Play() {
// id=2;//The final field Instrument.id cannot be assigned
System.out.println(id);
System.out.println("wind play");
}
}
class Bass implements Instrument {
@Override
public void Play() {
System.out.println("bass play");
}
}
输出:
0
wind play
bass play
0
从上面的代码可以看见:
1.接口是不可以new 的
2.子类必须实现接口的方法
3.通过向上转型,以Instrument为类型定义的wind和bass,也可以调用play方法,而且运行时自动识别应该绑定那个play方法
4.由于wind和bass必须重写play,因此play一定是public,因为wind和bass不是继承Instrument
5.我们通过打印Instrument里面的id,知道id一定是static,因为可以直接使用Instrument调用,而不需要new
6.通过在实现类wind里面修改id,就可以看到他的提示,提示id是final的。
三、接口解耦
我们建立一个通用接口,然后两个基类分别实现接口,然后通过向上转型,实现多态,使得TestObjectInterface这个父类指向各个不同的子类的,从而调用不同子类的方法。
在这里我们再扩展一下,其实是运用了策略设计模式。TestObjectInterface一直是执行算法里面固定的部分,然后通过不同类型的传入,分别执行不同的实现。
package com.ray.ch07;
public class Test {
public static void test(TestObjectInterface testObjectInterface) {
testObjectInterface.test();
}
public static void main(String[] args) {
test(new Wind());
test(new Bass());
test(new BMW());
test(new Audi());
}
}
interface TestObjectInterface {
void test();
}
class Instrument implements TestObjectInterface {
@Override
public void test() {
System.out.println("Instrument test");
}
}
class Wind extends Instrument {
@Override
public void test() {
System.out.println("Wind test");
}
}
class Bass extends Instrument {
@Override
public void test() {
System.out.println("Bass test");
}
}
class Vehicle implements TestObjectInterface {
@Override
public void test() {
System.out.println("Vehicle test");
}
}
class BMW extends Vehicle {
@Override
public void test() {
System.out.println("BMW test");
}
}
class Audi extends Vehicle {
@Override
public void test() {
System.out.println("Audi test");
}
}
四、多重接口
使用继承,我们只是继承某一类,只能够一种向上转型,但是在接口的使用方面,可以实现多个接口,然后实现多种的向上转型。
package com.ray.ch07;
public class Test {
public static void testSwim(CanSwim canSwim) {
canSwim.swim();
}
public static void testEat(CanEat canEat) {
canEat.eat();
}
public static void testRun(CanRun canRun) {
canRun.run();
}
public static void main(String[] args) {
Person person = new Person();
testSwim(person);//向上转型为CanSwim
testEat(person);//向上转型为CanEat
testRun(person);//向上转型为CanRun
Fish fish = new Fish();
testSwim(fish);//
// testEat(fish);//error,因为没有实现接口,不能向上转型
// testRun(fish);//error,因为没有实现接口,不能向上转型
}
}
interface CanRun {
void run();
}
interface CanSwim {
void swim();
}
interface CanEat {
void eat();
}
class Person implements CanEat, CanRun, CanSwim {
@Override
public void swim() {
System.out.println("i can swim");
}
@Override
public void run() {
System.out.println("i can run");
}
@Override
public void eat() {
System.out.println("i can eat");
}
}
class Fish implements CanSwim {
@Override
public void swim() {
System.out.println("i can swim");
}
}
解释一下上面的代码:
1.建立了三个接口:会游泳,会跑,会吃
2.建立一个Person类,实现上面三个接口
3.建立一个Fish类,只是实现游泳的接口
4.然后在测试代码里面使用策略设计模式,测试一下三种技能
在代码里,Person 分别向上转型为CanRun、CanSwim、CanEat这三种类型,这样大大增强代码的灵活性,要不然我们就必须在测试代码方面增加代码,才能够完整测试。而且也不利于代码的复用,假如CanSwim这个不是接口,他变成了基类,但是他的实现可能对于Person或者Fish来说都是不合适的,而且代码可能歧义,但是现在是接口,只是一种协议,说明子类只是具备某种功能,而这个功能怎么实现,具体需要根据子类的实现来说,这样代码更能够广泛的复用。
五、接口与工厂设计模式
接口是实现多重继承的途径,生成遵循某个接口协议的对象的典型方式是工厂设计模式。
这种设计模式使得接口与实现完全分开。
package com.ray.ch07;
interface Service {
void doSomeThing();
}
interface ServiceFactory {
Service getService();
}
class ServiceImpl implements Service {
@Override
public void doSomeThing() {
}
}
class ServiceFactoryImpl implements ServiceFactory {
@Override
public Service getService() {
// TODO Auto-generated method stub
return null;
}
}
public class Test {
public static void test(ServiceFactory factory) {
Service service = factory.getService();
service.doSomeThing();
}
public static void main(String[] args) {
test(new ServiceFactoryImpl());
}
}
从上面的代码看出,我们只是在最后一步new的时候,才把实现类放进去,其他的代码基本以接口来实现,从而把接口与实现完全分离,这样有利于Test这个代码的重复使用。
那么,怎么使用呢?
我们下面给出例子:(就是有多个Service的时候,Test就可以重复使用了)
package com.ray.ch07;
interface Service {
void doSomeThing();
}
interface ServiceFactory {
Service getService();
}
class ServiceImpl implements Service {
@Override
public void doSomeThing() {
}
}
class ServiceFactoryImpl implements ServiceFactory {
@Override
public Service getService() {
// TODO Auto-generated method stub
return null;
}
}
class ServiceImpl2 implements Service {
@Override
public void doSomeThing() {
}
}
class ServiceFactoryImpl2 implements ServiceFactory {
@Override
public Service getService() {
// TODO Auto-generated method stub
return null;
}
}
public class Test {
public static void test(ServiceFactory factory) {
Service service = factory.getService();
service.doSomeThing();
}
public static void main(String[] args) {
test(new ServiceFactoryImpl());
test(new ServiceFactoryImpl2());
}
}