赞
踩
接口(Interface),在Java编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface关键字来声明。Java接口是用于描述类所具有的方法集合,但并不提供实现这些方法的代码。它们被用来定义一个协议或者契约(Contract),使得各种不同的实现可以遵循相同的接口规则进行开发。
接口可以包括常量、方法签名和默认方法。常量在接口中被隐式的声明为public static final,而方法签名则是public abstract。默认方法是指在Java 8之后添加的一种方法,允许在接口中提供默认的实现方法,而不需要让实现类必须去覆盖该方法。
实现类必须通过implements关键字来实现接口,并且必须实现接口中声明的所有方法。由于Java不支持多继承,因此接口提供了一种机制来实现类似于多继承的特性。同时,接口还可以用于实现回调函数,以及在类与类之间传递消息等场景。
【在计算机编程中,契约(Contract)是一种规范或者协议,用于定义程序中组件之间的交互方式。可以将契约看作是一个约定,各个组件必须遵守该约定以便能够与其他组件进行交互。】
Java接口和类是两种不同的概念,它们有一些相同点,也有一些重要的区别。
相同点:
都是Java中的语法结构;
都可以定义方法和常量;
都可以被继承。
不同点:
类可以提供方法的具体实现,而接口只能定义方法的签名,不能提供具体实现;
一个类可以实现多个接口,但只能继承一个父类;
接口中的变量隐式的是public static final类型,并且必须进行初始化赋值,而类中的变量则不需要;
接口中的方法默认是public abstract类型,不能有具体实现;而在类中,可以定义public、protected、private类型的方法,并且可以有具体实现;
接口中还可以定义default方法和static方法,在Java 8之后添加,用于提供默认实现和静态方法等功能。
【在Java中,方法的签名(Signature)包括方法名和参数列表。方法名用于标识方法的名称,参数列表则描述了方法需要接收的参数类型和数量,用于唯一标识一个方法。方法签名不包含方法返回值类型和修饰符。
例如,以下两个方法的签名是不同的:
java
public void print(String message) {}
public void print(int message) {}
虽然它们都有相同的方法名print,但是它们的参数列表不同,一个接收一个字符串参数,一个接收一个整数参数,因此它们有不同的方法签名。】
Java使用接口程序的组成通常包括以下几个部分:
接口定义:使用interface关键字来定义接口,其中包含了方法签名和常量等元素;
实现类定义:实现类通过implements关键字来实现接口,并提供具体的实现代码;
调用者代码:调用者可以直接使用接口类型来引用任意一个实现类对象,并调用接口中定义的方法。
以下是一个示例,本例将接口、实现类和调用测试类定义在同一个Java文件中:
- //接口Animal
- interface Animal {
- void eat();
- }
-
- //实现类Cat
- class Cat implements Animal {
- public void eat() {
- System.out.println("Cat is eating.");
- }
- }
-
- //调用者(测试类)代码
- public class Main {
- public static void main(String[] args) {
- Animal animal = new Cat();
- animal.eat(); // 打印输出:Cat is eating.
- }
- }
【在同一个Java文件中,只能有一个public类(或接口),这个类的名称必须与文件名相同。】
上面的例子将接口、实现类和调用测试类定义在同一个Java文件中,但通常不建议这样做,因为这会导致代码可读性下降,增加代码维护难度。我们还是应该将接口、实现类和调用者测试代码类分别放置在独立的Java文件中。
这种保存方式符合Java的模块化设计思想,有利于代码的组织和管理。同时,这也是Java编译器所要求的规定,如果没有按照这种方式保存文件,就会导致编译错误。
需要注意的是,当实现类较少时,也可以将其与接口定义保存在同一个.java文件中。这种做法虽然不太规范,但在某些情况下可以提高代码的可读性和方便性。然而,调用者代码仍然应该单独放在一个.java文件中,以确保程序的可维护性和扩展性。
下面是一个简单的示例,演示了Java使用接口程序的基本结构:
本示例由三个文件构成
Shape.java文件:
- // 定义接口
- public interface Shape{
- public double getArea();
- }
Circle.java文件:
- // 实现Circle类
- public class Circle implements Shape{
- private double radius;
-
- public Circle(double r){
- radius = r;
- }
-
- // 实现接口的方法
- public double getArea(){
- return Math.PI * radius * radius;
- }
- }
- // 调用者代码
- public class Test{
- public static void main(String[] args){
- Shape s = new Circle(2.0);
- double area = s.getArea();
- System.out.println("圆面积:" + area); //圆面积:12.566370614359172
- }
- }
在上面的示例中,我们首先定义了一个Shape接口,它包含一个getArea()方法,用于计算形状的面积。然后我们定义了Circle类,它实现了Shape接口,并提供了自己的getArea()实现。最后,我们在Test类中创建了一个Circle实例,并将其赋给一个Shape类型的变量s,然后调用s的getArea()方法来计算圆形的面积。
这个示例展示了Java使用接口程序的基本结构,其中包括了接口定义、实现类定义和调用者代码三个部分。通过使用接口,我们可以方便地对不同的实现类进行管理和扩展,并且保障程序的稳定性和可维护性。
下面是对上面例子的改进,添加Rectangle部分,修改Test。
本示例是对前一个示例的改进,添加了Rectangle文件,修改了Test文件,由四个文件构成:
定义接口的Shape.java文件和实现Circle类的文件和前面相同。
Rectangle.java类文件:
- // 实现 Rectangle类
- public class Rectangle implements Shape{
- private double width;
- private double height;
-
- public Rectangle(double w, double h){
- width = w;
- height = h;
- }
-
- // 实现接口的方法
- public double getArea(){
- return width * height;
- }
- }
Test.java文件修改为:
- // 调用者代码
- public class Test{
- public static void main(String[] args){
- Shape s1 = new Circle(2.0);
- Shape s2 = new Rectangle(3.0, 4.0);
-
- System.out.println("圆面积:" + s1.getArea()); //圆面积:12.566370614359172
- System.out.println("矩形面积:" + s2.getArea()); //矩形面积:12.0 }
- }
在Java中,接口可以像类一样继承其他接口,这种机制称为接口的继承。接口继承基本语法如下:
public interface SubInterface extends SuperInterface {
// 子接口定义的方法
}
其中SubInterface是子接口,SuperInterface是父接口。子接口可以继承一个或多个父接口,多个父接口之间使用逗号,分隔。
子接口从父接口中继承了所有抽象方法,并且可以在自身中添加新的抽象方法。子接口也可以重写父接口中的默认方法和静态方法,并且可以使用super关键字来调用父接口中的默认方法。
例如,以下是一个接口继承的例子:
Animal.java文件:
- // Animal接口
- public interface Animal {
- void eat();
- }
Cat.java文件:
- //Cat接口继承了Animal接口
- public interface Cat extends Animal {
- void meow();
- }
PersianCat.java文件:
- public class PersianCat implements Cat {
- public void eat() {
- System.out.println("The cat is eating...");
- }
-
- public void meow() {
- System.out.println("Meow~");
- }
- }
TestA.java文件:
- // 调用者(测试)代码
- public class TestA{
- public static void main(String[] args){
- PersianCat cat = new PersianCat();
- cat.eat(); // The cat is eating...
- cat.meow(); // Meow~
- }
- }
在上述例子中,Animal接口定义了eat()方法,Cat接口继承了Animal接口并新增了meow()方法,PersianCat类实现了Cat接口,并且必须实现父接口Animal中的抽象方法eat()和新增的抽象方法meow()。
【关于抽象类(abstract class)可参见https://mp.csdn.net/mp_blog/creation/editor/130618011】
接口(interface)和抽象类(abstract class)都是Java中用于实现多态性的机制。它们都可以被继承,并且都可以包含抽象方法,但它们之间也存在着很多不同之处。下面我们来看一下它们之间的异同。
1.抽象类可以包含非抽象方法和成员变量,而接口只能包含常量和抽象方法。换句话说,抽象类既可以包含具体的实现,也可以包含抽象的行为,而接口只能定义抽象的行为。
2.子类只能继承一个抽象类,但是可以实现多个接口。这是因为Java语言本身不支持多重继承,但是子类可以通过实现多个接口来获得多个行为的实现。如果一个类既要继承其他类,又要实现多个接口,那么就必须使用抽象类来作为基类。
3.抽象类可以包含构造方法,而接口不能包含构造方法。这是因为接口没有实例化的概念,所以它也没有构造方法的需求。
4.抽象类的访问权限可以是public、protected或默认的,而接口的访问权限必须是public。这是因为接口是一种公共的契约,任何类都可以实现它,所以它必须是公开的。
5.抽象类可以用来定义模板方法,而接口则不能。模板方法是一种设计模式,在抽象类中定义了一个算法的框架,然后由子类去实现具体的步骤。
总的来说,我们可以这么理解接口和抽象类的区别:抽象类是对事物的抽象,既包含行为又包含状态;接口是对行为的抽象,只定义了行为规范,没有状态的表示。
在使用时,我们应该根据具体的需要选择使用接口还是抽象类。如果我们需要定义一些基本的行为和属性,并且希望子类能够共享这些基础功能,那么就可以使用抽象类;如果我们需要定义一些行为规范,但不关心实现细节,那么就可以使用接口。
附录、进一步学习了解
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。