Java接口与抽象类--知道何时使用什么

61 阅读4分钟

Java中的interfaceabstract class 引用类型是用来创建抽象的

interfaceabstract class 都不能直接实例化。它们需要由其他类来实现或扩展。

但是这两种引用类型有很多不同之处,它们改变了你的抽象的工作方式。

一个明显的区别是,一个abstract class 是一个类。一个Javaclass 只能扩展一个类,但它可以实现许多接口。

下面是Javainterfaceabstract class 引用类型之间的一些明显的区别。

成员的访问修改器

一个abstract class 可以有带访问修饰符的成员(如private,protected, 和public ),而interface 成员都是public :

abstract class Individual {
protected String tribe = "Hominini";
private String species = "Homo Sapiens";
public String name = "Nathan";
}
interface Human {
protected String tribe = "Hominini";
// ERROR: protected modifier not allowed
 private String species = "Homo Sapiens";
// ERROR: private modifier not allowed
 public String name = "Nathan";
// WARNING: public modifier is redundant
}

protectedprivate 的访问修饰符不允许出现在interface 中。

public 修饰符是多余的,因为interface 的所有变量成员默认都是公共的。

成员的非访问修饰符

默认情况下,一个interface 的成员都是staticfinal

另一方面,一个abstract class 的成员可以是finalstatic ,或者都不是。

考虑一下下面的interface 代码例子:

interface Human {
String name = "Nathan";
}
public class Main {
public static void main(String[] args) {
System.out.println(Human.name); // Nathan
 Human.name = "Jack" // ERROR
 }
}

一个interface 成员可以被直接调用,因为它们默认是static

在一个abstract class ,你需要将成员声明为static ,以便直接访问它们:

abstract class Individual {
String first_name = "Nathan";
static String last_name = "Sebhastian";
}
public class Main {
public static void main(String[] args) {
System.out.println(Individual.first_name); // ERROR
 System.out.println(Individual.last_name); // OK

Individual.first_name = "Smith"; // ERROR
 Individual.last_name = "Smith"; // OK
 }
}

你也可以添加final 修改器来使成员的值不可改变:

abstract class Individual {
// this is the default in interface:
 final static String last_name = "Sebhastian";
}

因为abstract class 变量默认不是最终的,你可以声明变量而不初始化它们,如下所示:

abstract class Individual {
String first_name;
String last_name;
}

而这就是interfaceabstract class 在非访问修饰符方面的不同之处。

引用类型中的方法修饰符

默认情况下,一个interface 只能有抽象的方法。声明一个带实现的方法将导致一个编译时错误:

interface Human {
void greetings() {
System.out.println("Hello!");
}
// ERROR: abstract methods cannot have a body

void call(); // Correct abstract method
}

从Java 8开始,interface 类型得到了改进,所以它也可以有defaultstatic 方法。

当你想为interface 方法提供一个默认的实现时,请添加default 修饰符,如下所示:

interface Human {
default void greetings() {
System.out.println("Hello!");
}
// You can also declare a static method:
 static void call() {
System.out.println("Hi!");
}
}

在一个abstract class ,你可以同时声明常规和抽象方法,如下图所示:

abstract class Individual {
void greetings() {
System.out.println("Hello!");
}
abstract void call();
}

注意,在一个abstract class 中声明抽象方法时,需要添加abstract 修饰符。

继承规则

interfaceabstract class 没有特殊的继承规则。

当你需要的时候,你可以扩展一个单一的类并实现多个接口到一个abstract class

class A {}
class B {}
interface ZX {}
interface ZY {}
abstract class C extends A, B {}
// ERROR: only one class allowed

abstract class C extends A implements ZX, ZY {}
// OK

另一方面,一个interface 只能扩展另一个接口:

class A {}
interface ZX {}
interface ZY {}
interface Test implements ZX {}
// ERROR: implements not allowed

interface Test extends A {}
// ERROR: interface expected, class A received

interface Test extends ZX, ZY {}
// OK

而这些就是Java中的interfaceabstract class 的明显区别。

什么时候使用接口或抽象类?

要记住的关键点是,一个interface 是用来实现完全抽象的,而一个abstract class 是用来实现部分抽象的。

一个interface 是用来提供实现class 将提供的能力

例如,Animal 接口承诺实现对象可以行走:

interface Animal {
void walk();
}

但是walk 方法的实现是留给实现它的对象的。

一个Dog 类将用四条腿行走,而一个Kangaroo 类用两条腿行走:

class Dog implements Animal {
@Override
public void walk() {
System.out.println("4 legs");
}
}
class Kangaroo implements Animal {
@Override
public void walk() {
System.out.println("2 legs");
}
}

尽管现在你可以有defaultstatic 方法,但规则仍然是一样的:一个interface 定义了一个对象能做什么

另一方面,一个abstract class一个对象是什么更感兴趣。

当使用一个abstract class ,你是在赋予实现对象之间的共同特征:

abstract class Person {
String first_name;
String last_name;
int lungs = 2;
void breathe() {
System.out.println("Breathe in.. breathe out");
}
}

一个人的first_namelast_name 通常是在这个人出生时给出的,所以它们被声明,但没有被初始化。

你不能用一个interface 做同样的事情,因为在一个interface 中声明的任何变量都是final

总而言之,一个interface 是用来提供一个对象可以做什么和拥有什么的承诺的。

同时,abstract class 提供一个对象可以做和拥有的共享事物。

我希望这个教程能帮助你理解interfaceabstract class 之间的区别。👍