自学内容网 自学内容网

Java接口一口气讲完!~~~///(^v^)\\\~~~

Java 接口

Java面向对象设计 - Java接口

什么是接口?

Java中的接口定义了一个引用类型来创建抽象概念。接口由类实现以提供概念的实现。

在Java 8之前,一个接口只能包含抽象方法。 Java 8允许接口具有实现的静态和默认方法。

接口通过抽象概念定义不相关类之间的关系。

例如,我们可以创建一个Person类来表示一个人,我们可以创建一个Dog类来表示一只狗。

人和狗都可以走路。这里的步行是一个抽象的概念。狗可以走,人也是这样。这里我们可以创建一个名为Walkable的接口来表示walk的概念。然后我们可以有Person类和Dog类来实现Walkable概念并提供自己的实现。 Person类实现了Walkable接口,并使人以人的方式走路。Dog类可以实现Walkable界面,使狗以狗的方式走路。

例子

在下面我们将使用一个例子来说明为什么我们需要接口。

假设 Person 类有一个walk()方法。

public interface Walkable {
  void walk();
}

class Person implements Walkable {
  public Person() {
  }

  public void walk() {
    System.out.println("a person is walking.");
  }
}
class Dog implements Walkable {
  public Dog() {
  }
  public void walk() {
    System.out.println("a dog is walking.");
  }
}

类可以在其声明中使用关键字implements实现一个或多个接口。

通过实现一个接口,类保证它将为接口中声明的所有方法提供一个实现,或者类将自己声明为抽象。

如果一个类实现了Walkable接口,它必须提供walk()方法的实现。

像类一样,接口定义了一个新的引用类型。

当定义一个新的接口(例如,Walkable)时,我们定义一个新的参考接口类型。

以下声明有效:

Walkable  w;  // w  is a  reference variable of  type   Walkable

您不能创建接口类型的对象,因为接口是定义抽象概念。以下代码无效:

new Walkable(); // A  compile-time error

我们可以为一个类类型创建一个对象,但是我们可以使用一个接口类型变量来引用其类实现该接口的任何对象。

因为Person和Dog类实现了Walkable接口,所以Walkable类型的引用变量可以引用这些类的对象。

Walkable  w1  = new Person(); // OK 
Walkable  w2  = new Dog();     // OK

我们可以使用它的引用类型变量访问接口的任何成员。由于Walkable接口只有一个成员,这是walk()方法,我们可以编写如下代码:

// Let  the   person  walk 
w1.walk();
// Let  the   dog walk 
w2.walk();

当调用w1上的walk()方法时,它调用Person对象的walk()方法,因为w1指的是Person对象。

当调用w2上的walk()方法时,它调用Dog对象的walk()方法,因为w2指的是Dog对象。

当使用接口类型的引用变量调用方法时,它调用它所引用的对象上的方法。

例2

下面的代码创建了一个方法来使用interface我们的参数类型。

public class Main{
  public static void main(String[] args) {
    Walkable[] w = new Walkable[2];
    w[0] = new Person();
    w[1] = new Dog();

    Walkables.letThemWalk(w);
  }
}

class Walkables {
  public static void letThemWalk(Walkable[] list) {
    for (Walkable w : list) {
      w.walk();
    }
  }
}

声明接口

声明接口的一般语法是

<modifiers> interface <interface-name>  { 
    Constant-Declaration
    Method-Declaration
    Nested-Type-Declaration
}

接口声明以修饰符列表开头,可能为空。

像类一样,一个接口可以有一个公共或包级别的作用域。

关键字public用于指示接口具有公共范围。

缺少范围修饰符指示接口具有包级别作用域。具有包级别作用域的接口只能在其包的成员内引用。

关键字interface用于声明接口,后面是接口的名称。

接口的名称必须是有效的Java标识符。

接口体跟在其名称后面并放在大括号内。

接口的主体可以为空。以下是最简单的接口声明:

package com.w3cschool;

interface Updatable  {
    // The interface body  is empty
}

像类一样,一个接口有一个简单的名称和一个完全限定名。关键字interface后面的标识符是其简单名称。

接口的完全限定名称通过使用其包名称和用点分隔的简单名称形成。

在上面的示例中,Updatable是简单的名称,com.java2s.Updatable是完全限定名称。

使用接口的简单和完全限定名的规则与类的规则相同。

下面的代码声明一个名为ReadOnly的接口。它有一个公共范围。

package  com.w3cschool;

public interface  ReadOnly {
    // The interface body  is empty
}

接口声明总是抽象的,无论是否明确声明它是抽象的。

标记接口

标记接口是没有成员的接口。

标记接口标记具有特殊含义的类。

interface  Shape {
}
class Circle implements Shape{
}

Shape c = new Circle();

if (c instanceof Shape)  {
   System.out.println("Using a  Shape object");
}

Java API有许多标记接口。 java.lang.Cloneable,java.io.Serializable和java.rmi.Remote都是标记接口。

功能接口

仅具有一个抽象方法的接口被称为功能接口。

多态性 - 一个对象,多个视图

多态性是指对象具有多种形式的能力。

多态性是对象提供其不同视图的能力。

接口让我们创建一个多态对象。

Java 接口字段

Java面向对象设计 - Java接口字段

一个接口可以有三种类型的成员:

  • 常量字段
  • 抽象,静态和默认方法
  • 静态类型作为嵌套接口和类

一个接口不能有可变的实例和类变量。与类不同,接口不能被实例化。接口的所有成员都是隐式公开的。

常量字段声明

我们可以在接口中声明常量字段,如下所示。它声明一个名为Choices的接口,它有两个字段的声明:YES和NO。两者都是int数据类型。

public interface  Choices   {
    public static final int YES  = 1;
    public static final int NO  = 2;
}

接口中的所有字段都是隐式的public,static和final。

Choices接口可以声明如下,而不改变其含义:

public interface  Choices   {
    int YES  = 1;
    int NO  = 2;
}

您可以使用点形式的形式访问界面中的字段

<interface-name>.<field-name>

您可以使用Choices.YES和Choices.NO访问Choices界面中的YES和NO字段的值。

下面的代码演示了如何使用点符号来访问接口的字段。

public class ChoicesTest {
  public static void main(String[] args) {
    System.out.println("Choices.YES = " + Choices.YES);
    System.out.println("Choices.NO = " + Choices.NO);
  }
}

接口中的字段总是最终的,无论关键字final是否在其声明中使用。我们必须在声明时初始化一个字段。

我们可以使用编译时或运行时常量表达式来初始化字段。由于final字段只赋值一次,因此除了声明之外,我们不能设置接口字段的值。

以下代码显示了接口的一些有效和无效字段声明:

public interface ValidFields {
  int X = 10;
  int Y = X;
  double N = X + 10.5;

  boolean YES = true;
  boolean NO = false;

  Test TEST = new Test();
}

使用接口中字段名称中的所有大写字母表示它们是常量是一种约定。

接口的字段总是公共的。

Java 接口方法

Java面向对象设计 - Java接口方法

方法声明

您可以在接口中声明三种类型的方法:

  • 抽象方法
  • 静态方法
  • 默认方法

在Java 8之前,您只能在接口中声明抽象方法。修饰符static和default用于分别声明静态和默认方法。

缺少静态和默认修饰符使得方法抽象。

以下是具有所有三种类型方法的接口的示例:

interface AnInterface {
  // An abstract method
  int m1();

  // A static method 
  static int m2()  {
    // The method  implementation goes  here
  }

  // A default method
  default int m3() {
    // The method implementation goes here
  }
}

抽象方法声明

接口中的所有方法声明都是隐式抽象和公开的,除非它们声明为static或default。

接口中的抽象方法没有实现。

抽象方法的主体总是由分号表示,而不是一对大括号。

下面的代码声明一个名为Player的接口:

public interface Player {
  public abstract void play();

  public abstract void stop();

  public abstract void forward();

  public abstract void rewind();
}

播放器界面是音频/视频播放器的规范。

真实的播放器,例如DVD播放器,将通过实现播放器接口的所有四种方法来提供该规范的具体实现。

在接口中的方法声明中使用抽象和公共关键字是多余的。

上面的Player接口的声明可以改写如下,而不改变其含义:

public interface  Player {
    void  play(); 
    void  stop(); 
    void  forward(); 
    void  rewind();
}

接口中的抽象方法声明可以包括参数,返回类型和throws子句。

public interface NewPlayer {
  boolean play(int account) throws AccountNotFoundException;

  boolean stop(double amount);

  boolean forward(double amount) throws InsufficientBalanceException;

  double rewind();
}

来自接口的抽象方法由实现接口的类实现,类重写它们以提供实现。

接口中的抽象方法不能声明为final。

类可以声明接口final的重写方法,表示子类不能重写该方法。

静态方法声明

从Java 8,我们可以在接口中有静态方法。

静态方法包含静态修饰符,并且是隐式公开的。

我们可以重新定义Walkable接口以包括letThemWalk()方法。

interface Walkable {
  // An abstract method 
  void walk();

  // A static convenience method
  public static void letThemWalk(Walkable[] list) {
    for (int i = 0; i < list.length; i++) {
      list[i].walk();
    }
  }
}

您可以使用点表示法使用接口的静态方法。

<interface-name>.<static-method>

与类中的静态方法不同,接口中的静态方法不会通过实现类或子接口来继承。

从另一个接口继承的接口称为子接口。只有一种方法来调用接口的静态方法:使用接口名称。

必须使用MyInterface.myStaticMethod()调用接口MyInterface的静态方法myStaticMethod()。

我们可以使用方法的非限定名称myStaticMethod()来调用它仅在接口的主体中,或者当我们使用静态import语句导入方法时。

默认方法声明

接口中的默认方法使用modifier default来声明。默认方法是在Java 8中添加新功能。

默认方法为实现接口的类提供了一个默认实现,但不重写默认方法。

假设,我们有以下接口。

interface Shape{
  void setX(double x);
  void setY(double y);
  double getX();
  double getY();
}

下面的代码显示了实现Shape接口的Circle。

class Circle implements Movable {
  private double x;
  private double y;

  public Circle() {
  }

  public Circle(double x, double y) {
    this.x = x;
    this.y = y;
  }

  public void setX(double x) {
    this.x = x;
  }

  public void setY(double y) {
    this.y = y;
  }

  public double getX() {
    return x;
  }

  public double getY() {
    return y;
  }

  public String toString() {
    return "Circle(" + x + ", " + y + ")";
  }
}

如果我们向Shape添加一个新方法如下。

interface Shape {
  void setX(double x);

  void setY(double y);

  double getX();

  double getY();

  void move(double deltaX, double deltaY);
}

在Java 8之前,新方法move()是一个抽象方法。所有实现Shape接口的类都必须提供新方法的实现。

实现Shape接口的Pen类将不再编译,除非将新方法添加到这些类中。

在Java 8之前,在将接口分发给公共接口之后,不能在不中断现有代码的情况下向接口添加方法是不可能的。

Java接口默认方法是接受的接口解决方案。可以将默认方法添加到现有接口,并为该方法提供默认实现。

所有实现该接口的类都将继承默认实现,因此不会破坏它们。类可以选择重写默认实现。

默认方法使用关键字 default 声明。默认方法不能声明为abstract或static。它必须提供一个实现。否则,将发生编译时错误。

以下代码使用默认方法更改Shape接口。

interface Movable {
  void setX(double x);

  void setY(double y);

  double getX();

  double getY();

  // A default method
  default void move(double deltaX, double deltaY) {
    double newX = getX() + deltaX;
    double newY = getY() + deltaY;
    setX(newX);
    setY(newY);
  }
}

以下项目列出了类中的具体方法和接口中的默认方法之间的相似点和差异。

两者都以相同的方式访问关键字 this 。 关键字 this 是调用该方法的对象的引用。

类中的一个具体方法可以访问类的实例变量。

默认方法不能访问实现接口的类的变量的实例。

默认方法可以访问接口的其他成员。

两种类型的方法都可以使用它们的参数。

两个方法都可以有一个throws子句。

接口中的嵌套类型声明定义了一个新的引用类型。

我们可以将一个类,接口,枚举和注释声明为嵌套类型。

在接口内声明的接口/类称为嵌套接口/类。

接口和类定义新的引用类型,因此做嵌套接口和嵌套类。

嵌套接口始终通过其封装接口访问。

我们还可以在接口中声明一个嵌套类。

具有嵌套类和常量字段的作业接口。

interface Task {
  class EmptyTask implements Task {
    private EmptyTask() {
    }
    public void runJob() {
      System.out.println("Empty...");
    }
  }
  // A constant field
  Task EMPTY_JOB = new EmptyTask();
  void runJob();
}

public class Main {
  public static void main(String[] args) {
    submitJob(Task.EMPTY_JOB);
  }
  public static void submitJob(Task job) {
    job.runJob();
  }
}

Java 接口类型

Java面向对象设计 - Java接口类型

接口定义了一个新的引用类型。

我们可以使用接口类型来声明变量,在方法中声明参数类型,作为方法的返回类型等。

interface  Shape {
    void  draw();
}
public class Main {
  // interface type as instance variable
  private Shape myShape;

  // interface type as parameter type for a constructor
  public Main(Shape s) {
    this.myShape = s;
  }

  // interface type as return type of a method
  public Shape getShape() {
    return this.myShape;
  }

  // interface type as parameter type for a method
  public void setShape(Shape s) {
    this.myShape = s;
  }

  public void letItSwim() {
    // interface type as a local variable
    Shape locaShape = null;

    locaShape = this.myShape;

    // interface variable can invoke methods
    // declared in the interface and the Object class
    locaShape.draw();
  }
}

注意

接口类型的变量是指其类实现该接口的内存中的对象。

我们可以使用接口类型的变量或直接使用接口名称来访问接口中声明的任何常量字段。

最好使用接口名访问接口的常量。常量。

我们可以使用接口类型的变量来调用接口中声明的任何方法。

接口类型的变量可以调用java.lang.Object类的任何方法。

默认情况下,接口类型的实例或静态变量将初始化为null。

Java 接口实现

Java面向对象设计 - Java接口实现

实现接口

接口指定对象必须提供的协议。

类可以提供接口的抽象方法的部分实现,并且在这种情况下,类必须将自身声明为抽象。

实现接口的类使用“implements”子句来指定接口的名称。

“实现”子句由关键字implements,后跟逗号分隔的接口类型列表组成。

一个类可以实现多个接口。

实现接口的类声明的一般语法如下:

<modifiers> class  <class-Name>  implements <comma-separated-list-of-interfaces>  {
    // Class body  goes  here
}

假设有一个Circle类。

public class Circle implements Shape {
   void  draw(){
      System.out.println("draw circle");
   }
}

实现接口的类必须重写以实现接口中声明的所有抽象方法。否则,类必须声明为abstract。

接口的默认方法也由实现类继承。

植入类可以选择不需要重写默认方法。

接口中的静态方法不会被实现类继承。

下面的代码定义了两种引用类型,一种来自Circle类,另一种来自接口类型。

Circle c = new Circle(); 
Shape shape = new Circle();

变量c是Circle类型。它指的是Circle对象。

第二个赋值也是有效的,因为Circle类实现了Shape接口,而Circle类的每个对象也都是Shape类型。

实现接口方法

当一个类完全实现了一个接口时,它为所实现的接口的所有抽象方法提供一个实现。

接口中的方法声明包括方法的约束。例如,方法声明中的throws子句是​​方法的约束。

import java.io.IOException;
interface Shape {
  void draw(double amount) throws IOException;
}
class Main implements Shape{

  @Override
  public void draw(double amount) {
    // TODO Auto-generated method stub
  }  
}

Main的代码是有效的,即使它丢弃了throws子句。当类覆盖接口方法时,允许删除约束异常。

如果我们使用Shape类型,我们必须处理IOException。

import java.io.IOException;

interface Shape {
  void draw(double amount) throws IOException;
}
class Main implements Shape{

  @Override
  public void draw(double amount) {
    // TODO Auto-generated method stub
    
  }
  public void anotherMethod(){
    Shape s = new Main();
    try {
      s.draw(0);
    } catch (IOException e) {
      e.printStackTrace();
    }
    draw(0); 
  }
}

实现多个接口

一个类可以实现多个接口。类实现的所有接口都在类声明中的关键字implements之后列出。

通过实现多个接口,类同意为所有接口中的所有抽象方法提供实现。

interface Adder {
  int add(int n1, int n2);
}
interface Subtractor {
  int subtract(int n1, int n2);
}
class Main implements Adder, Subtractor {
  public int add(int n1, int n2) {
    return n1 + n2;
  }
  public int subtract(int n1, int n2) {
    return n1 - n2;
  }
}

部分实现接口

类不必为所有方法提供实现。

如果一个类不提供接口的完全实现,它必须声明为abstract。

interface Calculator {
  int add(int n1, int n2);

  int subtract(int n1, int n2);
}
abstract class Main implements Calculator{
  public int add(int n1, int n2) {
    return n1 + n2;
  }
}

Java 接口继承

Java面向对象的设计 - Java接口继承

接口可以从另一个接口继承。与类不同,接口可以从多个接口继承。

interface Singer {
  void sing();
  void setRate(double rate);
  double getRate();
}
interface Writer {
  void write();
  void setRate(double rate);
  double getRate();
}
interface Player {
  void play();
  void setRate(double rate);
  default double getRate() {
    return 300.0;
  }
}

一个接口使用关键字extends来继承自其他接口。关键字extends之后是以逗号分隔的继承接口名称列表。

继承的接口称为超级接口,继承接口的接口称为子接口。

接口继承其超级接口的以下成员:

  • 抽象和默认方法
  • 常量字段
  • 嵌套类型

接口不从其超级接口继承静态方法。

接口可以重写它从其超级接口继承的继承的抽象和默认方法。

如果超级接口和子接口具有相同名称的字段和嵌套类型,则子接口获胜。

interface A {
  String s = "A";
}
interface B extends A {
  String s = "B";
}
public class Main {
  public static void main(String[] argv){
    System.out.println(B.s);
  }
}

以下代码显示如何重写默认方法。

interface A {
  default String getValue(){
    return "A";
  }
}
interface B extends A {
  default String getValue(){
    return "B";
  }
}

class MyClass implements B{
}

public class Main {
  public static void main(String[] argv){
    System.out.println(new MyClass().getValue());
  }
}

上面的代码生成以下结果。

继承冲突实现

引入默认方法使得类可以从其超类和超级接口继承冲突的实现。

Java使用三个简单的规则为了解决冲突。

  1. 超类总是获胜
  2. 最具体的超级接口获胜
  3. 类必须重写冲突的方法

instanceof运算符

我们可以使用instanceof运算符来评估引用类型变量是指特定类的对象还是其类实现特定接口。

instanceof运算符的一般语法是

referenceVariable instanceof  ReferenceType
interface A {
  default String getValue(){
    return "A";
  }
}
interface B {
  default String getValue(){
    return "B";
  }
}

class MyClass implements B,A{
  public String getValue(){
    return "B";
  }
}

public class Main {
  public static void main(String[] argv){
    MyClass myClass = new MyClass();
    System.out.println(myClass instanceof MyClass);
    System.out.println(myClass instanceof A);
    System.out.println(myClass instanceof B);
  }
}

上面的代码生成以下结果。


原文地址:https://blog.csdn.net/m0_69824302/article/details/142705506

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!