首页 > 编程笔记 > Java笔记 阅读:11

Java接口(interface)用法详解(附带实例)

接口是 Java 实现抽象机制的另一种方式,一般地,我们只能在接口中声明抽象方法和静态变量。

接口与抽象类的本质其实是一样的,所以接口的作用与抽象类的相同,都是对同类事物进行规范约束,保证所有实现了接口的类和它的子类都具有相同的接口,从而实现多态机制。

接口的定义与类相似,不同的地方在于类通过 class 关键字来定义,而接口则通过 interface 关键字来定义。具体的语法如下:
访问修饰符 interface 接口名 {
    访问修饰符 非访问修饰符 变量类型 变量名 = 变量值;
    访问修饰符 返回类型 方法名(参数列表);
}
对于其中的所有元素我们都在前面的类定义中介绍过了,注意接口中定义的变量都必须是静态变量。

Java定义完整的接口

在 Java 程序中,只有完整的接口才能运行起来,所谓完整的接口是指包含了抽象方法和具体实现,即接口的定义和接口的实现。

下面我们看实例中如何实现一个完整的接口:
public interface Shape {
    public float calcArea(float height, float width);
}
第一步是定义一个接口,该接口的名称为 Shape,接口里面定义了一个 calcArea() 抽象方法。

第二步是实现接口,这一步需要用到 implements 关键字,实例程序如下:
class Triangle implements Shape {
    public float calcArea(float height, float width) {
        return height * width / 2;
    }
}

class Rectangle implements Shape {
    public float calcArea(float height, float width) {
        return height * width;
    }
}
可以看到程序中 Triangle 和 Rectangle 两个类都实现了 Shape 接口,然后各自实现各自的 calcArea() 方法。

最后我们通过一个实例来看中接口的使用:
public class InterfaceTest {
    public static void main(String[] args) {
        Shape s1 = new Triangle();
        System.out.println(s1.calcArea(10, 10));
        s1 = new Rectangle();
        System.out.println(s1.calcArea(10, 10));
    }
}
其实它与抽象类的用法一样,通过 Shape 接口类型变量来实现多态,也就是说 Triangle 对象和 Rectangle 对象都可以转换成 Shape 类型变量。

Java接口的继承

接口是可以继承的,与类一样也是通过 extends 关键字来实现继承。

子接口继承了父接口就相当于继承了父接口的变量和方法,同时也可以对父接口的变量和方法进行重写。实例代码如下:
public interface Shape {
    public float calcArea(float height, float width);
}

public interface RectangleShape extends Shape{
    public int getSideNum();
}
程序中 Shape 作为父接口,而 RectangleShape 接口则继承了 Shape 接口。

继承后的效果如下,当某个类实现了 RectangleShape 接口时,它就必须同时实现 calcArea() 和 getSideNum() 两个方法,代码如下:
public class InterfaceTest2 implements RectangleShape {
    public float calcArea(float height, float width) {
        return height * width;
    }

    public int getSideNum() {
        return 4;
    }
}

Java实现多个接口

Java 规定一个类不能同时继承两个父类,自然也就不能同时继承两个抽象类。然而接口却可以弥补这方面的不足,一个类虽然不能同时继承多个抽象类,但可以同时实现多个接口,从而增强多态机制的灵活性。

下面的实例程序中,定义了 Shape 和 Color 两个接口,它们分别包含了一个方法。
public interface Shape {
    public float calcArea(float height, float width);
}

public interface Color {
    public String getColor();
}

在下面的实例程序中,BlackRectangle 类通过 implements 同时实现了 Shape 接口和 Color 接口,多个接口之间通过逗号进行分隔。一旦一个类实现了多个接口就必须重写所有接口包含的方法,这里必须编写 getColor() 和 calcArea() 两个方法。
public class BlackRectangle implements Shape, Color {
    public String getColor() {
        return "black";
    }

    public float calcArea(float height, float width) {
        return height * width;
    }
}

编译器的隐性作用

前面提到过接口中只能定义静态变量和抽象方法,但是我们经常看到接口中定义的变量并不是静态的,而且定义的方法也没有使用 abstract 关键字进行修饰。这是为什么呢?

实际上编译器会隐性地帮我们将变量定义为静态,且将方法定义为抽象。


图 1 接口中的变量

如上图中的例子,我们编写的代码中定义了一个 Vehicle 接口,其中声明的变量为非静态的,而且方法也是非抽象的。那么通过编译器的编译后,会自动添加 final 和 static 来修饰变量,也会自动添加 abstract 来修饰方法。所以我们在接口中看到的变量都属于静态变量,方法都属于抽象方法。

Java default关键字

default 意为默认,就是说接口可以定义一个默认的方法实现,如果实现类中没有重写该方法,则直接使用该默认的方法实现。

我们对 Shape 接口做些改动,添加一个 default 的 print() 方法,代码如下:
public interface Shape {
    public float calcArea(float h, float w);

    public default void print() {
        System.out.println("this is a default method");
    }
}
然后 Triangle 类重写 print() 方法,而 Rectangle 类不重写 print() 方法。分别创建 Triangle 类对象和 Rectangle 类对象,再分别调用它们的 print() 方法,代码如下:
public class InterfaceTest3 {
    public static void main(String[] args) {
        Shape s1 = new Triangle();
        s1.print();
        s1 = new Rectangle();
        s1.print();
    }
}

class Triangle implements Shape {
    ...

    public void print() {
        System.out.println("triangle method");
    }
}

class Rectangle implements Shape {
    ...
}
输出结果如下:

triangle method
this is a default method

说明 Triangle 类对象调用了自己实现的 print() 方法,而 Rectangle 类对象则调用了 Shape 接口提供的默认 print() 方法。

相关文章