Java编程思想 -- 接口

抽象类和抽象方法

Java提供一种抽象方法的机制,这种方法是不完整的,仅有声明而没有方法体。包含有抽象方法的类叫做抽象类,该类必须被限定为抽象的

也可以创建一个没有任何抽象方法的抽象类:如果有一个类我们想要阻止产生这个类的任何对象,那么这样做就很有用

抽象类是很有用的重构工具,因为它们可以很容易地将公共方法沿着继承层次结构向上移动

接口

接口产生一个完全抽象的类,它根本没有提供任何具体实现。

接口可以包含域,但这些域隐式地是static和final的,这里的域是指变量这些

接口中方法隐式为public

完全解耦

接口+策略设计模式+设配器模式

这里简单描述一下,比如有一个方法App.exe(OneInterface o);,在使用的时候只需要继承该接口的类就可调用,这是策略模式的一种表现;但是现在已经有一个类,不管其中继承关系多复杂,如果先要调用App.exe(OneInterface o);方法,就只需继承并实现OneInterface接口就可以。

Java中的多重继承

interface CanFight{ void fight(); }

interface CanSwim{ void swim(); }

interface CanFly{ void fly(); }
class Action {
    public void fight(){ }
}

class Hero extends Action implements CanFight, CanSwim, CanFly{
    public void swim() { }
    public void fly() { }
}

这里需要注意的是,CanFight接口与Action类中fight()方法的特征签名是一样的,而且Hero没有提供fight()的定义

再由于上述的App.exe(OneInterface o)的方便,所以我们应该使用接口还是抽象类??
- 如果要创建不带任何方法定义和成员的基类,那么就应该选择接口而不是抽象类。(方法定义:大概的意思就是方法没有具体实现过程,只是声明)

通过接口继承来扩展接口

interface Monster{
    void menace();
}

interface DangerousMonster extends Monster{
    void destroy();
}

interface Lethal{
    void kill();
}

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

从上面的例子可以看出接口继承扩展接口的实例,这种情况有比较了解一下,一些Android开源框架就涉及到这个。以及接口中嵌套接口的情况,下面分析

一般情况下,只可以将extends用于单一类,但是可以引用多个基类接口。但是像上面所看到的,只需用逗号将接口名一一分隔开即可。

组合接口时的名字冲突

比如前面的CanFIght和Action都有一个相同的void fight(),这种情况没有什么问题。

例子:

interface I1 { void f(); }
interface I2 { int f(int i); }
interface I3 { int f(); }

class C { public int f() { return 1; } }

class C2 implements I1, I2{
    public void f(){ }
    public int f(int i) { return 1; }  // I2
}

class C3 extends C implements I2{
    public int f(int i) { return 1; }  // I2
}

class C4 extends C implements I3{
    public int f() { return 1; }  // C && I3
}

// 下面两种情况有问题
class C5 extends C implements I1{ }  // C: int f()  I1:void f()
interface I4 extends I1, I3{ }  // I1:void f()  I3: int f()

可以看出重载方法仅通过返回类型是区分不开的
所以应尽量避免这种情况发生

接口的适配

这里类似前面的完全解耦的策略设计模式,所以不做多讲

接口中的域

如前面所述,接口中的任何域都是自动static和final和public,所以就成为了Java SE5之前一种很便捷的用来创建常量组的工具。因此,在标识常量的时候,要注意使用大写字母及下划线风格标识。

初始化接口中的域

域是static的,它们就可以在类第一次被加载时初始化,这发生在任何域首次被访问时,而且不能是“空final”,但是可以被非常量表达式初始化。

这些域不是接口的一部分,它们的值被存储在该接口的静态存储区域内

嵌套接口

下面例子分别是在接口内嵌套接口和在类中嵌套接口的情况:

interface E{
    // 接口内的接口
    interface G{
        void f();
    }

    public interface H{
        void f();
    }

    void g();

    // 接口E内的域默认为public
    // private interface I { }
}

class A{
    // 类A内部接口B
    interface B{
        void f();
    }
    public class BImp implements B{
        public void f() { }
    }
    private class BImp2 implements B{
        public void f() { }
    }

    // 类A内部public接口C
    public interface C{
        void f();   
    }
    class CImp implements C{
        public void f() { }
    }
    private class CImp2 implements C{
        public void f() { }
    }

    // 类A内部private接口D
    private interface D{
        void f();
    }
    private class DImp implements D{
        public void f() { }
    }
    public class DImp2 implements D{
        public void f() { }
    }

    public D getD() { return new DImp2(); }
    private D dRef;
    public void receiveD(D d){
        dRef = d;
        dRef.f();
    }
}
public class TestInterface{
    // B为类A内接口
    public class BImp implements A.B{
        public void f();
    }

    // C为类A内public接口
    class CImp implements A.C{
        public void f();
    }

    // D为类A内private接口
    // class DImp implements A.D{ }

    class EImp implements E{
        public void g();
    }

    // E接口内的G接口
    class EGImp implements E.G{
        public void f();
    }

    class EImp2 implements E{
        public void g();
        class EG implements E.G{
            public void f();
        }
    }


    public static void main(String[] args){
        A a = new A();

        // A.D:不能获取A内部private接口D    
        // A.D ad = a.getD();

        // 
        // A.DImp2 di2 = a.getD();

        // 
        // a.getD().f();

        A a2 = new A();
        a2.reciveD(a.getD());
    }
}

从中可以看出,嵌套接口跟非嵌套接口差不多。

但是private的嵌套接口的情况有点不一样,A.DImp2内部类被实现为public类。但是A.DImp2只能被其自身所使用。你无法说它实现了一个private接口D,因此实现一个private接口只是一种方式,它可以强制该接口中的方法定义不要添加任何类型信息(也就是说,允许向上转型)

getD()方法使我们陷入困境,这个问题与private接口相关:它是一个返回private接口的引用的public方法。对这个方法返回值能做些什么呢?在main()中,可以看到数次尝试使用返回值的行为都失败了。只有一个方式成功,就是将返回值交给有权使用它的对象。就是另一个A通过receiveD()方法来实现的

需要特别注意的是,但实现某个接口时,并不需要实现嵌套在其内部的任何接口

接口与工厂

工厂模式

直接上代码:

//具体编程技能模块
interface ICode {
    void coding();
}

class CodeImplAndroid implements ICode {
    @Override
    public void coding() {
        System.out.println("Coding Android!");
    }
}

class CodeImplPHP implements ICode {
    @Override
    public void coding() {
        System.out.println("Coding PHP!");
    }
}
//创建技能工厂模块
interface IFactory {
    ICode getCodingSkill();
}

class FactoryImplAndroid implements IFactory {
    @Override
    public ICode getCodingSkill() {
        return new CodeImplAndroid();
    }
}

class FactoryImplPHP implements IFactory {
    @Override
    public ICode getCodingSkill() {
        return new CodeImplPHP();
    }
}

public class Main {
    public static void coding(IFactory ifactory){
        ICode code = factory.getCodingSkill();
        code.coding();
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值