Java基础教程(17)--接口

??就像类一样,接口也是引用类型。它可以包含常量,方法签名,默认方法,静态方法和嵌套类型。在接口中,只有默认方法和静态方法有方法体。但不同于类,接口无法实例化,它只能被类实现或被其他接口继承。

一.定义接口

??接口的定义由修饰符、关键字interface、接口名、extends关键字和若干继承的父接口(如果有的话)以及接口体组成,语法如下(方括号表示可选内容):

public interface DoIt [extends Interface1, Interface2] {
    void doSomething (int i, double x);
    int doSomethingElse(String s);
}

??public修饰符代表这个接口可以在任何地方使用。如果没有指定接口是public的,那么这个接口只能在定义这个接口的包中使用。

??一个接口可以继承其他接口,就像一个类可以继承另外一个类一样。不同的是,一个类只能继承一个父类,而一个接口可以继承多个接口。

??接口体包含了若干个抽象方法,从Java8之后,接口中还可以包含默认方法和静态方法。抽象方法后直接跟分号,没有大括号,因为抽象方法不包含实现。默认方法使用default关键字定义,静态方法使用static关键字定义。接口中的所有方法都默认且必须是public的,因此可以省略方法前的public。

??此外,接口可以包含常量声明。在接口中定义的所有常量都默认是public,static和final的,因此可以省略这些修饰符。

二.实现接口

??要实现接口,需要在定义类时在类名后面使用implements关键字,然后跟着以逗号分隔的要实现的接口列表。按照惯例,如果类既继承了父类,又实现了接口,implements语句应该放在extends语句后面。

??下面定义了一个USB接口:

public interface USB {
    void read();
    void write();
}

??如果一个类实现了某个接口,则它必须实现这个接口中所有的抽象方法。假设现在我们要定义一个U盘类,它需要实现USB接口,那么它必须实现USB接口中定义的read和write方法:

public class UDisk implements USB {
    @Override
    public void read() {
        System.out.println("Reading UDisk...");
    }

    public void write() {
        System.out.println("Writing UDisk...");
    }
}

??当定义了一个新的接口时,实际上就是定义了一个新的引用数据类型。如果定义了一个接口类型的变量,则这个变量只能引用实现了这个接口的类的实例。例如:

USB usb = new UDisk();

三.接口中的静态方法

??和类一样,接口也可以有静态方法。不同的是,在类中,既可以通过定义静态方法的类及其子类调用静态方法,也可以通过该类和子类的实例调用静态方法(可以但不推荐);在接口中,则只能通过定义静态方法的接口去调用静态方法,而不能通过实现它的类及其实例调用静态方法。接口的静态方法仅对于接口本身可见。例如下面的接口:

public interface Bar {
    static void foo() {
        System.out.println("I‘m a static method.");
    }
}

??可以通过Bar.foo()的形式调用这个静态方法。假设有个BarImpl实现了这个接口,那么无论是BarImpl.foo()或new BarImpl().foo()都会产生编译错误,因为这个静态方法对它们来说是不可见的。

四.默认方法

??从Java8之后,可以为接口中的方法提供一个默认实现。使用关键字default来表示这是一个默认方法。例如:

public interface Comparable<T> {
    default int compareTo(T other) {
        return 0;
    }
}

??当然,这里的默认方法并没有太大用处,因为Comparable的每一个实现类都要覆盖这个方法。不过有些情况下,默认方法可能很有用。如果希望在发生鼠标点击事件时得到通知,就要实现一个包含5个方法的接口:

public interface MouseListener {
    void mouseClicked(MouseEvent event);
    void mousePressed(MouseEvent event);
    void mouseReleaseed(MouseEvent event);
    void mouseEntered(MouseEvent event);
    void mouseExited(MouseEvent event);
}

??大多数情况下,我们只关心其中的一两个事件。可以将所有方法声明为默认方法,这些默认方法什么也不做:

public interface MouseListener {
    default void mouseClicked(MouseEvent event) {}
    default void mousePressed(MouseEvent event) {}
    default void mouseReleaseed(MouseEvent event) {}
    default void mouseEntered(MouseEvent event) {}
    default void mouseExited(MouseEvent event) {}
}

??这样一来,实现这个接口时,只需要覆盖真正关心的事件方法就可以了。

??默认方法可以调用其他的默认方法、静态方法和抽象方法。例如,Collection接口可以定义一个便利方法:

public interface Collection {
    int size();
    default boolean isEmpty() {
        return size() == 0;
    }
}

??这样在实现Collection接口时就不用操心isEmpty方法了。

??默认方法的一个重要用法是“接口演化”。以Collection接口为例,这个接口作为Java的一部分已经很多年了。后来,在Java8中,又为这个接口增加了一个stream方法。假设stream不是一个默认方法,那么其他已经实现了Collection接口的类将不能编译,因为要实现接口就必须实现接口所有的抽象方法。这样一来,就要修改其他所有已经实现了Collection接口的类的代码,这显然不是我们愿意看到的。

??不过,如果我们为stream方法提供默认实现,那么问题就迎刃而解了。其他已经实现了Collection接口的类不用做任何修改,就可以通过编译,而且还可以在这些类的实例上调用stream方法。如果真的有部分类需要重新定义stream方法而不是使用默认的stream方法,那么工作量也会小很多。

??下面来讨论默认方法的继承问题。当一个接口继承一个包含默认方法的接口时,可以执行以下操作:

  1. 不做任何修改,完全继承父接口的默认方法;
  2. 重新声明这个默认方法,使它变成抽象方法;
  3. 重写这个默认方法。

??执行第1种和第3种操作时,接口的实现类既可以选择使用默认的实现,也可以覆盖这个默认的方法。但执行第2种操作时,则必须实现这个抽象方法。

??如果先在一个接口中将一个方法定义为默认方法,然后在父类或另外一个接口中定义了相同的方法,JVM会怎么选择呢?规则如下:

  1. 父类优先。如果父类提供了这个方法,则接口中同名的默认方法将会被忽略。
  2. 接口冲突。如果一个接口提供了默认方法,另一个接口也提供了相同的方法(方法名和参数都相同),那么实现类必须覆盖这个方法来解决冲突。

原文地址:https://www.cnblogs.com/maconn/p/10204895.html

时间: 2024-10-12 20:50:51

Java基础教程(17)--接口的相关文章

Java基础教程:面向对象编程[2]

Java基础教程:面向对象编程[2] 三大特性 封装 封装(英语:Encapsulation)是指一种将抽象性函式接口的实现细节部份包装.隐藏起来的方法.封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问. 使用封装我们可以对成员变量进行更精确的控制,同时隐藏信息,实现细节等. 方法: public class Person{ private String name; private int age; ? public int getAge(){ return age;

Java基础教程:JDBC编程

Java基础教程:JDBC编程 快速开始 什么是JDBC JDBC 指 Java 数据库连接,是一种标准Java应用编程接口( JAVA API),用来连接 Java 编程语言和广泛的数据库. JDBC API 库包含下面提到的每个任务,都是与数据库相关的常用用法. 制作到数据库的连接. 创建 SQL 或 MySQL 语句. 执行 SQL 或 MySQL 查询数据库. 查看和修改所产生的记录. 从根本上来说,JDBC 是一种规范,它提供了一套完整的接口,允许便携式访问到底层数据库,因此可以用 J

Java基础教程(25)--I/O流

??I/O流表示输入源或输出目标.流可以表示许多不同类型的源和目标,例如磁盘文件.设备.其他程序等. ??流支持许多不同类型的数据,包括字节.原始数据类型.字符和对象等.有些流只传递数据; 有些流则可以操纵和转换数据. ??无论各种流的内部是如何工作的,所有流都提供相同的简单模型:流是一系列数据.程序使用输入流从源头获取数据,一次一项: ??程序使用输出流将数据写入目的地,一次一项: ??在本文中,我们会看到流可以处理各种各样的数据,无论是基本数据还是复杂对象.先来几张IO流的全家福: ??In

Java基础教程:枚举类型

Java基础教程:枚举类型 枚举类型 枚举是将一具有类似特性的值归纳在一起的方法.比如,我们可以将周一到周日设计为一个枚举类型.彩虹的七种颜色设计为一个枚举类型. 常量实现枚举 我们通过定义常量的方式来实现,如下: Public static class RainbowColor { // 红橙黄绿青蓝紫七种颜色的常量定义 public static final int RED = 0; public static final int ORANGE = 1; public static fina

Java基础教程:内部类

Java基础教程:内部类 内部类 内部类,是指在一个类的内部定义的类.就像下面这样: public class EnclosingClass {   . . .   public class NestedClass {   . . .     } } 内部类拥有访问外部类所有元素(包括private.static)的访问权.当某个外部类的对象创建了一个内部类对象时,此内部类对象必定会秘密地捕获一个指向那个外围类对象的引用.然后,在你访问此外围类的成员时,就是用那个引用来选择外围类的成员. 内部类

2.35 Java基础总结①抽象②接口③设计抽象类和接口的原则④接口和抽象类的区别

java基础总结①抽象②接口③设计抽象类和接口的原则④接口和抽象类的区别 一.抽象 abstract作用:不能产生对象,充当父类,强制子类正确实现重写方法和类相比仅有的改变是不能产生对象,其他的都有,包括构造.属性等等任何一个类只要有一个抽象的方法就成了抽象类 抽象方法 public abstract A();①方法是抽象的,这个类也是抽象的:②子类必须重写抽象方法,除非子类也是抽象类 抽象类可以没有抽象方法,但一般不这么设计 二.接口 interface 接口也是Java的一种引用数据类型(J

Java基础教程 - 组合

1. 什么是组合? 如果一个类的对象和另一个类满足"has-a"关系的话,我们就可以在一个类中,把另一个类的对象作为其对象成员. 什么是"has-a"关系,举个例子:现在有一个类LapTop.class,还有一个是Moniter.class.好显然,Laptop "has-a" Moniter,也就是说,他们是满足"has-a"关系的.这时候,我们就可以把Moniter作为Laptop的一个数据成员. class Laptop

Java基础05 实施接口(转载)

经过封装,产品隐藏了内部细节,只提供给用户接口(interface). 接口是非常有用的概念,可以辅助我们的抽象思考.在现实生活中,当我们想起某个用具的时候,往往想到的是该用具的功能性接口.比如杯子,我们想到加水和喝水的可能性,高于想到杯子的材质和价格.也就是说,一定程度上,用具的接口等同于用具本身.内部细节则在思考过程中被摒弃. 在public和private的封装机制,我们实际上同时定义了类和接口,类和接口混合在一起.Java还提供了interface这一语法.这一语法将接口从类的具体定义中

java基础学习总结——接口

java基础学习总结——接口 一.接口的概念 JAVA是只支持单继承的,但现实之中存在多重继承这种现象,如“金丝猴是一种动物”,金丝猴从动物这个类继承,同时“金丝猴是一种值钱的东西”,金丝猴从“值钱的东西”这个类继承,同时“金丝猴是一种应该受到保护的东西”,金丝猴从“应该受到保护的东西”这个类继承.这样金丝猴可以同时从 “动物类”.“值钱的东西类”.“应该受到保护的东西” 这三个类继承,但由于JAVA只支持单继承,因此金丝猴只能从这三个类中的一个来继承,不能同时继承这三个类.因此为了封装现实生活