在Java中,一个没有方法体的方法应该定义为抽象方法,而如果一个类中含有抽象方法,则该类必须定义为一个抽象类。接口是功能的集合,同样可看做是一种特殊的数据类型,是比抽象类更为抽象的类,接口只描述所应该具备的方法,并没有具体实现,具体的实现由接口的实现类(相当于接口的子类)来完成。这样将功能的定义与实现分离,优化了程序设计 ~ 本篇主要记录内容包括:抽象类、接口、抽象类和接口的差异、接口的新特性——默认方法和静态方法、 标记接口等相关内容
- 上一篇内容:Java基础:Java面向对象
- 下一篇内容:Java基础:Java异常机制
- 更多知识学习:全网最全的 Java 技术栈内容梳理(持续更新中)
文章目录
代码语言:txt复制- [一、抽象类](https://cloud.tencent.com/developer)
- [1、抽象类概述](https://cloud.tencent.com/developer)
- [2、抽象类特点](https://cloud.tencent.com/developer)
- [二、接口](https://cloud.tencent.com/developer)
- [1、接口概述](https://cloud.tencent.com/developer)
- [2、接口特点](https://cloud.tencent.com/developer)
- [三、抽象类和接口的差异](https://cloud.tencent.com/developer)
- [1、相同点](https://cloud.tencent.com/developer)
- [2、不同点](https://cloud.tencent.com/developer)
- [四、接口的新特性——默认方法和静态方法(jdk8之后)](https://cloud.tencent.com/developer)
- [1、默认方法](https://cloud.tencent.com/developer)
- [2、静态方法](https://cloud.tencent.com/developer)
- [3、注意事项](https://cloud.tencent.com/developer)
- [五、标记接口(标签接口)](https://cloud.tencent.com/developer)
一、抽象类
1、抽象类概述
在Java中,一个没有方法体的方法应该定义为抽象方法,而如果一个类中含有抽象方法,则该类必须定义为一个抽象类
抽象类通常作为一个框架,把子类将实现的抽象方法组织起来,简化或限制子类的设计
抽象方法定义的格式:public abstract 返回值类型 方法名(参数);
抽象类定义的格式:abstract class 类名 {}
2、抽象类特点
- 抽象类和抽象方法都需要被
abstract
修饰。抽象方法一定要定义在抽象类中; static、final、private
不能与abstract
同时出现;- 抽象类不一定有抽象方法,但是含有抽象方法的类必须是抽象类;
- 构造方法,类方法(用
static
修饰的方法),不能声明为抽象方法; - 抽象类本身不能实例化(但是多态机制可以用子类实例化),不可以直接创建对象,原因:调用抽象方法没有意义;
- 只有覆盖了抽象类中所有的抽象方法后,其子类才可以创建对象。否则该子类还是一个抽象类;
- 抽象类只定义了类的部分行为(包含具体行为), 这些行为是 子类共有的,其它行为由子类实现的抽象方法提供
- 抽象类的成员变量:既可以变量,又可以是常量;
- 抽象类的构造方法:用于父类数据的初始化
- 子类继承抽象类时,构造方法不会被覆盖。 而且,在实例化子类对象时首先调用的是抽象类中的构造方法再调用子类中的
二、接口
1、接口概述
接口是功能的集合,同样可看做是一种特殊的数据类型,是比抽象类更为抽象的类,接口只描述所应该具备的方法,并没有具体实现,具体的实现由接口的实现类(相当于接口的子类)来完成。这样将功能的定义与实现分离,优化了程序设计
接口的声明:使用interface
代替了原来的class
其他步骤与定义类相同
接口的实现类:使用implements
关键字实现接口,当类实现接口的时候,类要实现接口中所有的方法。否则,类必须声明为抽象类
2、接口特点
接口中方法的修饰符:public abstract(默认不写)
- 接口是隐式抽象的,当声明一个接口的时候,不必使用 abstract 关键字;
- 接口中定义的变量,固定的修饰符为
public static final
(默认不写,也可以选择性写)所以接口中的变量也称之为常量,其值不能改变; - 接口中定义的方法,固定的修饰符为
public abstract
(默认不写,也可以选择性写),不能指定其它的访问控制修饰符; - 接口中的成员变量必须显式初始化;
- 接口中成员方法定义的固定格式:
public abstract 返回值类型 方法名字(参数列表)
; - 子类必须覆盖接口中所有的抽象方法后,子类才可以实例化,否则子类是一个抽象类;
- 接口的重载条件和普通类没有任何区别,只是重载的方法没有方法体;
- 接口中的方法也可以覆盖(
Override
),但没有实际的意义,因为接口中不提供方法的实现; - 一个接口能继承另一个接口,和类之间的继承方式比较相似。接口的继承使用extends关键字,子接口继承父接口的方法。在Java中,类的多继承是不合法,但接口允许多继承。
三、抽象类和接口的差异
1、相同点
- 抽象类和接口都位于继承的顶端,用于被其他类实现或继承.
- 都不能直接实例化对象.
- 都包含抽象方法,其子类都必须覆盖这些抽象方法.
2、不同点
- 抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行
- 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是
public static final
类型的 - 接口中不能含有静态代码块以及静态方法(用
static
修饰的方法),而抽象类是可以有静态代码块和静态方法; - 一个类只能继承一个抽象类,而一个类却可以实现多个接口;
总的来说,优先选用接口,尽量少用抽象类,需要定义子类的行为,又要为子类提供共性功能时才选用抽象类
四、接口的新特性——默认方法和静态方法(jdk8之后)
1、默认方法
- 可以在不影响已有类的情况下,修改接口;
- 可以有方法实现;
- 父类中的默认方法可以被子接口继承;
- 子接口可以覆盖父接口中的默认方法,甚至还可以把父接口中的默认方法覆盖为抽象方法;
- 实现接口后,因为默认方法不是抽象方法,所以可以不重写,但是如果开发需要,也可以重写;
- 默认方法使用
default
关键字,只能通过接口实现类的对象来调用; - 注意:默认方法的访问权限也是默认
public
2、静态方法
- 可以有方法实现;
- 可以直接通过接口名来访问;
- 静态方法没有方法覆盖,因为静态方法没有运行时多态
interface Test{
//这个是默认方法
default String get(String aa){
System.out.println("我是jdk1.8默认实现方法...");
return "";
}
//这个是静态方法
static void staticmethod(){
System.out.println("我是静态方法");
}
}
3、注意事项
- 接口默认方法、静态方法可以有多个;
- 默认方法通过实例调用,静态方法通过接口名调用;
default
默认方法关键字只能用在接口中;- 默认方法可以被继承,如果继承了多个接口,多个接口都定义了多个同样的默认方法,实现类需要重写默认方法不然会报错;
- 静态方法不能被继承及覆盖,所以只被具体所在的接口调用
五、标记接口(标签接口)
Java中的标记接口(Marker Interface),又称标签接口(Tag Interface),是没有任何方法和属性的接口,它不对实现它的类有任何语义上的要求,它仅仅表明实现它的类属于一个特定的类型
在Java中很容易找到标记接口的例子,比如JDK中
的Serialzable
接口就是一个标记接口
标记接口并不是Java语言独有的,而是计算机科学中的一种通用的设计理念。
The tag/marker interface pattern is a design pattern in computer science, used with languages that provide run-time type information about objects. It provides a means to associate metadata with a class where the language does not have explicit support for such metadata.
具体说的就是,标记接口是计算机科学中的一种设计思路,用于给那些面向对象的编程语言描述对象。因为编程语言本身并不支持为类维护元数据,而标记接口可以用作描述类的元数据,弥补了这个功能上的缺失。对于实现了标记接口的类,我们就可以在运行时通过反射机制去获取元数据。
以Serializable
接口为例,如果一个类实现了这个接口,则表示这个类可以被序列化。因此,我们实际上是通过了Serializable
这个接口给该类标记了【可被序列化】的元数据,打上了【可被序列化】的标签。这也是标记/标签接口名字的由来。
具体在Java中,标记接口主要有以下两种目的:
- 建立一个公共的父接口:
例如,
EventListener
接口,一个由几十个其它接口扩展的Java API,当一个接口继承了EventListener
接口,Java虚拟机(JVM)就知道该接口将要被用于一个事件的代理方案。同样的,你可以使用一个标记接口来建立一组接口的父接口。 - 向一个类添加数据类型: 这是标记接口最初的目的,实现标记接口的类不需要定义任何接口方法(因为标记接口根本就没有方法),但是该类通过Java的多态性可以变成一个接口类型。
java.awt.event
包中的MouseListener
接口继承的java.util.EventListener
接口定义如下: package java.util; public interface EventListener {}
Java源码中几个标记接口的优秀例子:
java.io.Serializable
:未实现此接口的类将无法使其任何状态序列化或反序列化。为保证serialVersionUID
值跨不同Java编译器实现的一致性,序列化类必须声明一个明确的serialVersionUID
值。java.lang.Cloneable
:表明Object.clone()
方法可以合法地对该类实例进行按字段复制。实现此接口的类应该使用公共方法重写Object.clone
(它是受保护的)。如果在没有实现 Cloneable接口的实例上调用Object的clone()方法,则会导致抛出CloneNotSupportedException
异常。java.util.RandomAccess
:用来表明其支持快速(通常是固定时间)随机访问。此接口的主要目的是允许一般的算法更改其行为,从而在将其应用到随机或连续访问列表时能提供良好的性能。java.rmi.Remote:Remote
接口用于标识其方法可以从非本地虚拟机上调用的接口。任何远程对象都必须直接或间接实现此接口。只有在远程接口(扩展java.rmi.Remote
的接口)中指定的这些方法才可远程使用。