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

时间: 01-01

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

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基础教程完整版》电子版书正式发布,欢迎大家免费下载

截止目前,Java系列教程已更新完毕.内容覆盖了:JavaSE基本知识点.UML建模.单元测试等.希望对想学习Java语言的朋友能够提供帮助.在编写的过程中,难免会出现一些错误,希望大家能多多提些意见. 由于本书都是从笔者CSDN博客中摘抄过来的,基本没有经过什么正规的校验,所以难免会出现一些不对的地方.欢迎各位大牛对本书提出批评. 作者博客:http://blog.csdn.net/lhy_ycu 作者邮箱:[email protected] 笔者声明:该电子书由ITeye提供电子书DIY功能

java基础教程

比较经典的入门讲解 java基础总结 http://www.cnblogs.com/xdp-gacl/tag/java%E5%9F%BA%E7%A1%80%E6%80%BB%E7%BB%93/ 比较经典的入门讲解 javaWeb http://www.cnblogs.com/xdp-gacl/tag/JavaWeb%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93/default.html

java基础教程-面向对象(一)

一.面向对象 1.1 java键盘输入 1.1.1这种方法我认为是最简单,最强大的,就是用Scanner类 import java.util.Scanner; public static void main(String [] args) { Scanner sc = new Scanner(System.in); System.out.println(“请输入你的姓名:”); String name = sc.nextLine();//字符串输入 System.out.println(“请输入

IO流04--毕向东JAVA基础教程视频学习笔记

Day20 01 File概述02 File对象功能-创建和删除03 File对象功能-判断04 File对象功能-获取05 File对象功能-文件列表106 File对象功能-文件列表207 列出目录下所有内容-递归08 列出目录下所有内容-带层次09 删除带内容的目录 01 File概述 File类用来将文件或者文件夹封装成对象方便对文件与文件夹进行操作File对象可以作为参数传递给流的构造函数了解File类中的常用方法. public static final String separat

多线程--毕向东java基础教程视频学习笔记

多线程运行的安全问题 例子:售票系统 1 class Ticket implements Runnable 2 { 3 //定义静态变量ticket 4 private static int ticket=100; 5 public void run() 6 { 7 while(true) 8 { 9 //判断票编号是否大于0 10 if(ticket>0) 11 { 12 try 13 { 14 Thread.sleep(10); 15 } 16 catch (InterruptedExcep

集合3--毕向东java基础教程视频学习笔记

Day 15 集合框架01 TreeSet02 TreeSet存储自定义对象03 二叉树04 实现Comparator方式排序05 TreeSet练习06 泛型概述07 泛型使用08 泛型类09 泛型方法10 静态方法泛型11 泛型接口12 泛型限定13 泛型限定2 01 TreeSet |--Set   |--HashSet   |--TreeSet 可以对集合中的元素进行排序 1 import java.util.*; 2 class TreeSetTest 3 { 4 public sta

IO流02--毕向东JAVA基础教程视频学习笔记

提要 08 自定义装饰类09 LineNumberReader10 MyLineNumberReader11 字节流File读写操作12 拷贝图片13 字节流的缓冲区14 自定义字节流的缓冲区-read和write的特点15 读取键盘录入 08 自定义装饰类 1 /*自定义装饰设计类*/ 2 import java.io.*; 3 class MyBufferedReader2 extends Reader 4 { 5 private Reader r; 6 public MyBufferedR

Java基础之Comparable接口, Collections类,Iterator接口,泛型(Generic)

一.Comparable接口, Collections类 List的常用算法: sort(List); 排序,如果需要对自定义的类进行排序, 那就必须要让其实现Comparable接口, 实现比较两个类大小的方法 shuffle(List); 随机排列 void reverse(List); 逆序排列(Linked效率较高) copy(); 复制集合, 前提是size()相同(长度, 和容量的区别) fill(List, Object);使用某个对象填充整个List binarySearch()