在Java面向对象编程中,总会用到接口和抽象类,他们都是对事物的一种抽象,有一些共同点但是也有很多区别。
接口Interface
在Java中接口需要用interface关键字定义,他是对一种行为的抽象,是一种约定的协议,只定义行为不会实现具体的行为(Java 1.8中有default 方法)。
Java中定义一个接口:
public interface InterfaceName{
public void doSomething();
}
在接口中的行为必须都是公共的,如果定义成员变量也必须是静态不可变的(static final)。接口中定义的行为都是abstract的,也可以理解为特殊的抽象。
抽象类abstract class
在面向对象的编程中,对象都是通过class来描述的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。
抽象类需要用abstract关键字来定义,表示一个类为抽象类,抽象类是对一类事物共性的一种抽象,实现公共的行为,并且构造出一个固定的一组行为的抽象描述,但是这组行为却能够有任意个可能的具体实现方式。
抽象类中用abstract表示就是个抽象类,一般都有抽象方法,如果定义没有抽象方法的抽象类,在语法层面是可行的,但是实际并很少这么用。
Java中抽象类的定义:
几点区别:
从语法定义层面看abstract class和interface
在abstract class方式中,可以有自己的数据成员,也可以有非abstarct的成员方法,而在interface方式的实现中,只能够有静态的不能被修改的数据成员,所有的成员方法都是abstract的并且为公有的。
具体区别如下:
- 抽象类可以提供成员方法的实现细节,而接口中只能存在public abstract 方法(Java 1.8中有default 方法);
- 抽象类中的成员变量可以是private、protected和public,而接口中的成员变量只能是public static final类型的;
- 接口中不能含有静态方法和代码块,而抽象类可以有静态代码块和静态方法;
- 一个类只能继承一个抽象类,而一个类却可以实现多个接口。如果一个类实现部分接口的方法这个类也需要定义为抽象类。
从设计区分abstract class和interface
abstarct class在Java语言中体现了一种继承关系,要想使得继承关系合理,父类和派生类之间必须存在"is a"关系,即父类和派生类在概念本质上应该是相同的。对于interface 来说则不然,并不要求interface的实现者和interface定义在概念本质上是一致的,仅仅是实现了interface定义的契约而已。
可以理解为抽象类是对一类事物的抽象,而接口是对行为的抽象。
下面引用一个很经典的例子,大神们分析好了,我们看一看。
假设在我们的问题领域中有一个关于Door的抽象概念,该Door具有执行两个动作open和close,此时我们可以通过abstract class或者interface来定义一个表示该抽象概念的类型,定义方式分别如下所示:
其他具体的Door类型可以extends使用abstract class方式定义的Door或者implements使用interface方式定义的Door。看起来好像使用abstract class和interface没有大的区别。
如果现在要求Door还要具有报警的功能。我们该如何设计类结构呢?
大家很容易想到是在Door中增加一个抽象方法alarm()。这种方法首先违反了面向对象设计中的一个单一原则,在Door的定义中把Door概念本身固有的行为方法和另外一个概念"报警器"的行为方法混在了一起。如果一个门根本没有报警器功能,也得跟着修改。
另一种就是增加单独报警接口,由于Java语言不支持多重继承,所以应该把报警设计成接口。Abstract class在Java语言中表示一种继承关系,而继承关系在本质上是"is a"关系,把Door设计成抽象类比较合适,报警只是一种行为从设计上说也应该设计成接口。
所以对于Door这个概念,我们应该使用abstarct class方式来定义。另外,AlarmDoor又具有报警功能,说明它又能够完成报警概念中定义的行为,所以报警概念可以通过interface方式定义。如下所示:
总结:
接口和静态类都是用于实现多态性的机制,但在语法、实现方式、成员变量、构造函数、方法实现、使用场景等方面存在一些区别。
1. 定义关键字不同:接口使用关键字 interface 来定义,而静态类使用关键字 static class 来定义。
2. 继承或实现的关键字不同:接口使用 implements 关键字定义其具体实现,而静态类不能被继承。
3. 子类扩展的数量不同:接口的实现类可以有多个,而静态类不能被继承。
4. 成员变量的不同:接口中的成员变量默认都是 public static final 的常量,而静态类中的成员变量可以是任何类型。
5. 构造函数的不同:接口中不能写构造方法,因为接口不能被实例化。但是,静态类可以有构造方法。
6. 方法实现的不同:接口中的方法默认都是公共的抽象方法,不包含具体的实现代码;而静态类中可以包含抽象方法和非抽象方法,其中抽象方法没有具体的实现,而非抽象方法有具体的实现代码。
7. 使用场景的不同:接口通常用于定义应用程序与外部设备或系统交互时所遵循的协议,而静态类通常用于定义那些不需要继承关系、不需要多态性、不需要动态创建对象的场景。
接口引申讲解:
接口声明时,如果关键字interface前面加上public->public接口,可以被任何一个类使用
如果一个接口不加public修饰-> 接口类,可以被同一个包中的类使用
java7接口中可以包含
1、常量
2、抽象方法
java8接口中额外包含:
3、默认方法
4、静态方法
java9接口额外包含:
5、私有方法
接口抽象方法:
注意:
1、接口当中的抽象方法,修饰符必须是两个固定的关键字,public abstract
2、这两个关键字修饰符,可以选择性地省略
使用:
1、接口不能直接使用。必须有一个实现类来实现接口
格式:
public class 类名称 implements 接口名称{
//..
}
2、接口的实现类必须覆盖重写接口中所以的抽象方法
重写接口中的方法,访问权限一定时public
3、创建实现类的对象,进行调用
public interface MyInterface {
void method();
public default void method1(){
System.out.println("新添加的方法");
}
}
public class Interface implements MyInterface {
@Override
public void method() {
}
}
public class B {
public static void main(String[] args) {
Interface aa=new Interface();
aa.method();
aa.method1();
}
}
接口的默认方法会被子类继承,可以由子类调用
这样就可以不用全部都重新覆盖,但子类仍然可以调用新添加的方法
注意:接口的默认方法也可以被子类覆盖重写
接口的静态方法:
public static 返回值 方法名称(参数名称){
方法体
}
public可以省略
不能通过接口实现类的对象来调用接口当中的静态方法
通过接口名称,直接调用其中的静态方法:
接口名称.静态方法名(参数)
public interface MyInterface {
public static void method1(){
System.out.println("调用静态方法");
}
}
public class B {
public static void main(String[] args) {
MyInterface.method1();
}
}
接口的私有方法:
如果需要抽取一个共有方法,用来解决两个默认方法之间重复代码的问题。
但是这个共有方法不应该让实现类使用,应该是私有化的。
所以,应该把这个共有方法实设为私有的
1、普通私有方法,解决多个默认方法之间重复代码问题:
private 返回值类型 方法名称(参数列表){
方法体}
public interface MyInterface {
public default void method1(){
method();
}
public default void method2(){
method();
}
private void method(){
System.out.println("111");
}
}
public class A implements MyInterface {
}
public class B {
public static void main(String[] args) {
A aa = new A();
aa.method1();
aa.method2();
}
}
2、静态私有方法,解决多个静态方法之间重复代码问题:
格式:
private static 返回值 方法名称(参数列表){
方法体}
public interface MyInterface {
public static void method1(){
method();
}
public static void method2(){
method();
}
private static void method(){
System.out.println("111");
}
}
public class A implements MyInterface {
}
public class B{
public static void main(String[] args) {
MyInterface.method1();
MyInterface.method2();
}
}
https://blog.csdn.net/m0_52043808/article/details/123032080