JavaRush /Java 博客 /Random-ZH /喝咖啡休息#140。Java中的抽象类和接口

喝咖啡休息#140。Java中的抽象类和接口

已在 Random-ZH 群组中发布
来源:InfoWorld 今天您将了解开发人员在哪些情况下应使用抽象类,在哪些情况下应使用接口。我们还将识别 Java 语言的这些元素之间的差异以及如何在程序中使用它们。 喝咖啡休息#140。 Java 中的抽象类和接口 - 1抽象类和接口在 Java 代码甚至 Java 开发工具包 (JDK) 本身中非常常见。每个元素都有不同的用途:
  • 接口是 Java 语言中的一种构造,有助于实现抽象方法和静态常量。
  • 抽象类与常规类类似,只不过它们可以包含抽象方法,即没有主体的方法。无法创建抽象类。
许多开发人员认为接口和抽象类很相似,但实际上并不完全正确。让我们看看它们之间的主要区别。

什么是接口

从本质上讲,接口是一个契约,因此它取决于实现来定义其创建的目的。接口不能使用可变实例变量,只能使用final变量。

何时使用接口

接口对于分离代码和实现多态性非常有用。我们可以在 JDK 中通过List接口看到这一点:
public interface List<E> extends Collection<E> {

    int size();
    boolean isEmpty();
    boolean add(E e);
    E remove(int index);
    void clear();
}
您可能已经注意到,这段代码虽然简短,但具有很强的描述性。我们可以很容易地看到方法签名,它将用于使用具体类实现接口中的方法。List接口包含可由ArrayListVectorLinkedList和其他类实现的协定。要使用多态性,我们可以简单地使用List声明变量的类型,然后选择任何可用的实例。这是另一个例子:
List list = new ArrayList();
System.out.println(list.getClass());

 List list = new LinkedList();
 System.out.println(list.getClass());
输出是:
类 java.util.ArrayList 类 java.util.LinkedList
在这种情况下, ArrayListLinkedListVector 的实现方法是不同的,这是使用该接口的绝佳场景。如果您注意到许多类属于具有相同方法操作但行为不同的父类。在这种情况下,建议使用该接口。接下来,让我们看看使用接口的几个选项。

接口方法重写

我们已经知道,接口是一种必须由具体类实现的契约。接口方法是隐式抽象的,需要类的具体实现。这是一个例子:
public class OverridingDemo {
  public static void main(String[] args) {
    Challenger challenger = new JavaChallenger();
    challenger.doChallenge();
  }
}

interface Challenger {
  void doChallenge();
}

class JavaChallenger implements Challenger {
  @Override
  public void doChallenge() {
    System.out.println("Challenge done!");
  }
}
结论:
挑战完成!
请注意,接口方法是隐式抽象的。这意味着我们不需要显式声明它们是抽象的。

常量变量

另一个要记住的规则是接口只能包含常量变量。这是一个例子:
public class Challenger {

  int number = 7;
  String name = "Java Challenger";

}
这里两个变量都是隐式的finalstatic。这意味着它们是恒定的,独立于实例,并且不能更改。现在我们将尝试更改Challenger界面中的变量,如下所示:
Challenger.number = 8;
Challenger.name = "Another Challenger";
这会导致编译错误:
无法为最终变量“number”赋值 无法为最终变量“name”赋值

默认方法

当 Java 8 中引入默认方法时,一些开发人员认为它们与抽象类相同。然而,事实并非如此,因为接口不能拥有状态。默认方法可能有实现,但抽象方法没有。默认方法是 lambda 表达式和流创新的结果,但我们必须谨慎使用它们。JDK中使用默认方法的方法是forEach() ,它是Iterable接口的一部分。我们可以简单地重用forEach方法,而不是将代码复制到每个Iterable实现中:
default void forEach(Consumer<? super T> action) {
  // Code implementation here...
任何Iterable实现都可以使用forEach()方法,而不需要新的方法实现。然后我们可以使用默认方法重用代码。让我们创建自己的默认方法:
public class DefaultMethodExample {

  public static void main(String[] args) {
    Challenger challenger = new JavaChallenger();
    challenger.doChallenge();
  }

}

class JavaChallenger implements Challenger { }

interface Challenger {

  default void doChallenge() {
    System.out.println("Challenger doing a challenge!");
  }
}
结果:
挑战者正在挑战!
对于默认方法,需要注意的是每个这样的方法都需要实现。默认方法不能是静态的。现在让我们继续讨论抽象类。

抽象类的本质

抽象类可以具有带有实例变量的状态。这意味着实例变量可以被使用和修改。这是一个例子:
public abstract class AbstractClassMutation {

  private String name = "challenger";

  public static void main(String[] args) {
    AbstractClassMutation abstractClassMutation = new AbstractClassImpl();
    abstractClassMutation.name = "mutated challenger";
    System.out.println(abstractClassMutation.name);
  }

}

class AbstractClassImpl extends AbstractClassMutation { }
结论:
变异挑战者

抽象类中的抽象方法

与接口一样,抽象类可以具有抽象方法。抽象方法是没有主体的方法。与接口不同,抽象类中的抽象方法必须显式声明为抽象。这是一个例子:
public abstract class AbstractMethods {

  abstract void doSomething();

}
这里尝试声明一个没有实现和抽象 关键字的方法:
public abstract class AbstractMethods {
   void doSomethingElse();
}
不幸的是,它会导致编译错误:
缺少方法体,或者声明为抽象

何时使用抽象类

当您需要实现可变状态时,建议使用抽象类。例如,Java Collections Framework 包括一个使用变量状态的AbstractList类。在不需要维护类状态的情况下,通常最好使用接口。

抽象类和接口之间的区别

从面向对象编程的角度来看,接口和抽象类之间的主要区别在于接口不能具有状态,而抽象类可以具有带有实例变量的状态。另一个关键区别是类可以实现多个接口,但它们只能扩展一个抽象类。这一解决方案基于以下事实:多重继承(扩展多个类)可能导致代码死锁。Java 语言的开发人员决定避免这种情况。另一个区别是,接口可以由类实现,也可以由接口扩展,但类只能被扩展。需要注意的是,lambda 表达式只能与函数式接口(即只有一种方法的接口)一起使用,而只有一种抽象方法的抽象类不能使用 lambda 表达式。以下是抽象类和接口之间的更多区别。 界面:
  • 只能有最终静态变量。接口永远不能改变它自己的状态。
  • 一个类可以实现多个接口。
  • 可以使用implements关键字来实现。一个接口可以扩展另一个接口。
  • 方法只能使用静态最终字段、参数或局部变量。
  • Java 中只有函数式接口才能使用 lambda 函数。
  • 不能有构造函数。
  • 可能有抽象方法。
  • 可以有默认方法和静态方法(Java 8 中引入)。
  • 可以拥有带有实现的私有方法(在 Java 9 中引入)。
抽象类:
  • 可以有任何实例或静态变量,可变或不可变。
  • 一个类只能扩展一个抽象类。
  • 可能有可变字段、参数或局部变量的实例。
  • 只有一个抽象方法的抽象类不能使用 lambda 表达式。
  • 可能有一个构造函数。
  • 可以有任何方法。
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION