欢迎您光临本小站。希望您在这里可以找到自己想要的信息。。。

Java接口深入分析

java water 742℃ 0评论

抽象类中包含普通方法和抽象方法,如果把抽象类进行更彻底的抽象,即所有的方法都是抽象方法,那就是另外一个机制 —— 接口。
接口和类很相似,但接口不是类,它不像抽象类属于一种特殊的类。在常量、变量与运算符(一) 这篇文章里对引用数据类型分类过,接口属于引用数据类型的一种,它和类是同等级的概念而不是包含关系。


接口听起来很像是电脑主板上的USB接口或者PCI接口,或者插座上的插孔。很多教材也会这么比喻,其实这是错误的理解。如果要以主板上的接口比喻,例如USB接口,那么接口应该USB接口应该遵守的规范而不是接口本身。所以接口这个名字很容易让新人误解。

接口是干什么的

要说接口是干什么的,我认为有两个关键字,一是规范,二是能力。接口通常用来规定实现这个接口的类必须遵守的规范,或者类必需具备的能力。

语法

接口既然不是类,那么定义接口是自然不再是用class这个关键字了,而是用interface关键字。
接口和抽象类一样不能实例化,也不能被类继承,它的使用方法是让类实现它。关键字是implements
接口可以继承其它接口,而且可以多继承。

定义接口的语法是:

[访问修饰符] interface 接口名 extends 父接口1, 父接口2, 父接口3... {
        [public static final]属性;
        [public]static方法;
        [public]default方法;
        [public abstract]方法;
        [public static]内部类;
        [public static]内部接口;
        [public static]内部枚举;
}

使用接口的语法是:

class ClassName implements 接口1, 接口2, 接口3... {

}

从定义接口的语法可以看到接口内部成员可以是static 属性、static 方法、default 方法、抽象方法、内部类、内部接口、内部枚举。后面三个内部类、内部接口和枚举现在我没写到先不谈。说说前面四个。

  • static 属性
    关于接口的static 属性有以下四点要说明的地方:

  • 接口所有的属性都是用public static final修饰。所以你写不写修饰符默认都是public static final。也就是说在接口里写public static final String sString s是等效的。

  • 因为接口不能实例化,也不能有static代码块。而属性都是final的,所以必须指定初始值。

  • 可以用接口调用static属性,接口不能实例化就是没有接口的对象,但是可以用实现了这个接口的类的对象调用static属性,但是建议用接口来调不要用对象来调,这样比较规范,这样一看就知道是属于接口的方法。

  • 如果接口A、接口B都有属性s。类C实现了A和B接口,那么就不能用类C的对象来调用s属性,因为不知道到底调用A.s还是B.s。

  • static 方法
    关于接口的static 方法有以下两点要说明的地方:

    • 所有static 方法都是用public修饰,写不写public都一样。

    • static 属性可以用实现了这个接口的类的对象来调用,但是static 方法不能,只能用接口来调用。

  • default 方法
    关于接口的default 方法有以下三点要说明的地方:

    • 所有default方法都是用public修饰,写不写public都一样。

    • 跟普通方法一样,使用实现了这个接口的类的对象调用default 方法。

    • 如果接口A、接口B都有default 方法m()。类C实现了A和B接口,那么类C就必须重写m(),否则m()方法冲突不知道实现的是A.m()还是B.m()。如果希望实现的是A.m()可以在重写m()的时候使用A.super().m()来复用代码。

    我举个例子来使用以下接口的 static 属性、static 方法和default 方法。
    示例代码:
    创建接口A,在前面加大写字母I是规范,方便和类区分。
    接口A有static 属性,static 方法和default 方法。

    public interface IA {
    
        String s = "我是接口A的static 属性";    static void show() {
            System.out.println("我是接口A的static 方法");
        }    default void defaultMethod() {
            System.out.println("我是接口A的default 方法");
        }
    
    }

    创建接口B,接口B有一个和接口A里同名的default 方法。

    public interface IB {    default void defaultMethod() {
            System.out.println("我是接口B的default 方法");
        }
    
    }

    创建类C实现接口A和接口B,用逗号隔开。因为接口A和接口B中都有名为defaultMethod()的default 方法,所以类C里必须重写。

    public class C implements IA, IB {    @Override
        public void defaultMethod() {        //因为IA, IB都有defaultMethod(),所以冲突了,必须重写
            IB.super.defaultMethod(); // 通过接口名.super.xx() 来调用接口的default 方法
        }
    }

    测试代码:

    C c = new C();System.out.println(IA.s); //static 属性可以通过对象c来调但是不建议这么做,避免混淆IA.show(); //static 方法只能通过接口调c.defaultMethod(); // default 方法通过对象c来调

    运行结果:

    我是接口A的static 属性
    我是接口A的static 方法
    我是接口B的default 方法

    以上是关于接口的static 属性,static 方法和default 方法。但是这三个成员其实不是很常用,最常用的是抽象方法。这个作为重点来讲:

    • 抽象方法
      关于接口的abstract方法有以下三点要说明的地方:

    • 抽象类可以有普通方法和抽象方法,但是接口只能有抽象方法

    • 接口的抽象方法和抽象类里的抽象方法一样,只是默认都是用public abstract修饰

    • 类C实现接口A,那么类C必须实现接口A的所有抽象方法,除非类C是抽象类

    来看示例代码,来个复杂点的例子。继续抽象类与抽象方法 里的示例代码。
    创建一个ITransport接口,有一个传输文件抽象方法。前面说接口通常用来定义规范和能力,这个传输文件就可以视为一种能力。实现这个接口的类必须有传输文件的能力。

    public interface ITransport {    //在两个硬盘间传输文件
        void transport(Dish dish1, Dish dish2);
    
    }

    创建一个ISATA和IUSB接口都继承ITransport,各自添加一个connection方法。以ISATA为例,它继承了ITransport那么也就继承了transport这个方法。即是说实现ISATA必须实现transport和connection两个方法。

    public interface ISATA extends ITransport {    // 连接硬盘到主板
        void connection(HDD hdd);
    
    }
    public interface IUSB extends ITransport {    // 连接U盘到主板
        void connection(UDish uDish);
    
    }

    创建一个主板类实现ISATA和IUSB两个接口,按照接口规定的能力它必须实现void transport(Dish dish1, Dish dish2);、void connection(HDD hdd);、void connection(UDish uDish);三个方法。

    public class MotherBoard implements ISATA, IUSB {    @Override
        public void transport(Dish dish1, Dish dish2) {
            connection(dish1);
            connection(dish2);        if (dish1.getIsConnection() && dish2.getIsConnection()) {            int speed1 = dish1.getSpeed();            int speed2 = dish2.getSpeed();            int speed = (speed1 > speed2 ? speed2 : speed1); // 传输速度取决于速度慢的那个
                System.out.println("以" + speed + "MB/S的速度传输文件");
            }
        }    //连接硬盘,返回是否连接成功
        boolean connection(Dish dish) {        if (dish instanceof HDD) {
                connection((HDD)dish);            return true;
            } else if (dish instanceof UDish) {
                connection((UDish)dish);            return true;
            } else {
                System.out.println("连接失败,主板与" + dish.getName() + "不兼容");            return false;
            }
        }    @Override
        public void connection(HDD hdd) {
            hdd.setIsConnection(true);
        }    @Override
        public void connection(UDish uDish) {
            uDish.setIsConnection(true);
        }
    
    }

    定义一个硬盘根类,抽象类无法实例化。有name、iSConnection两个属性和对应的getter()和setter(),有一个获取传输速度的getSpeed();方法交给子类去实现。

    public abstract class Dish {    protected String name;    protected boolean iSConnection; // 是否连接到主板
    
        public String getName() {        return this.name;
        }    public boolean getIsConnection() {        return this.iSConnection;
        }    public void setIsConnection(boolean isConnection) {        this.iSConnection = isConnection;
        }    public abstract int getSpeed(); // 传输速度}

    创建HDD、USB和TypeC三个类都继承自Dish,只是名字和传输速度不同。

    public class HDD extends Dish {
    
        public HDD() {        this.name = "HDD";
        }    @Override
        public int getSpeed() {        return 500;
        }
    
    }
    public class UDish extends Dish {
    
        public UDish() {        this.name = "UDish";
        }    @Override
        public int getSpeed() {        return 150;
        }
    
    }
    public class TypeC extends Dish {
    
        public TypeC() {        this.name = "TypeC";
        }    @Override
        public int getSpeed() {        return 1000;
        }
    }

    测试代码:

        HDD hdd = new HDD();
        UDish uDish = new UDish();
        TypeC tc = new TypeC();
        MotherBoard mb = new MotherBoard();
    
        mb.transport(hdd, uDish);
        mb.transport(hdd, tc);

    运行结果:

    以150MB/S的速度传输文件
    连接失败,主板与TypeC不兼容

    转载请注明:学时网 » Java接口深入分析

    喜欢 (0)or分享 (0)

    您必须 登录 才能发表评论!