编译环境
- windows 10
- JDK 1.8
- eclipse
前言
上一篇文章中,粗略的了解了多态,也了解到了一小些关于抽象类和接口,所以决定写一篇详细一点的关于抽象类和接口的文章。
抽象类(Abstract class)
一、基本概念
抽象类不可以用于创建对象。抽象类可以包含抽象方法,这些方法将在具体的子类中实现。抽象类和抽象方法使用abstract关键字来创建。抽象类不能实例化对象,所以抽象类必须被继承才能够被使用。
在抽象方法中,抽象方法只包含一个方法名,方法名后边直接跟一个分号,而不是花括号;抽象方法没有具体实现方法的方法体,具体的实现要靠子类的重写来实现。但是任何子类必须重写父类的抽象方法,或者声明自身为抽象类。不可以只定义一个抽象方法,继承父类的子类不重写该抽象方法。如果一个类包含抽象方法,那么该类必须是抽象类。
二、抽象类的几点说明
1、抽象方法不能包含在非抽象类中,在实现抽象类的子类中,必须实现所有的抽象方法,而且要注意的是抽象方法是非静态的。
2、抽象类是不能使用new操作来初始化的,但是仍然可以有构造方法,这个构造方法在它的子类的构造方法中调用。
3、包含抽象方法的类必须是抽象的,但是可以定义一个不含抽象方法的抽象类。
4、子类可以覆盖父类的方法并将它定义为abstract。
5、即使子类的父类是具体的,这个子类也可以是抽象的。
三、代码实例
1、定义合法的抽象类
/** 文件名 A.class */
public abstract class A {
}
/** 文件名 A.class */
public abstract class A {
public abstract void unfinished();
}
/** 文件名 xxx.class */
abstract class A {
}
/** 文件名 xxx.class */
abstract class A {
abstract void unfinished();
}
/** 文件名 xxx.class */
abstract class A {
public void unfinished(){
}
}
/** 文件名 xxx.class */
abstract class A {
protected void unfinished(){
}
}
解释说明:
如果使用到public来定义一个抽象类的话,那么文件名要和该类的名字是相同的。
2、继承抽象类
/** 文件名 Debug.class */
public class Debug {
/** Main method */
public static void main(String[] args) {
Children child = new Children();
child.print(); // 调用子类重写方法
child.test(); // 调用父类的方法
}
}
/** 抽象类 */
abstract class Parent {
/* 抽象方法 */
abstract void print();
/* 非抽象方法 */
public void test() {
System.out.println("Parent\'s method");
}
}
/** 实现抽象类的子类 */
class Children extends Parent {
/* 重写父类的抽象方法 */
@Override
public void print() {
System.out.println("Hello World!");
}
}
输出:
Hello World!
Parent's method
解释说明:
父类定义为抽象类,然后通过子类的非抽象类来继承父类,实现了父类的抽象方法,但是父类的非抽象方法,在子类也是可以直接使用的。
接口(Interface)
一、基本概念
接口不是类,接口被看作是一种特殊的类。一个类通过继承接口的方式,从而来继承接口的抽象方法。接口跟抽象类很相似,**不能只定义一个方法,而实现接口的类不去重写接口的方法,除非实现接口的类是抽象类,否则该类要重写定义接口中的所有方法。**一个类可以实现多个接口,但是只能继承一个父类。接口使用关键字interface来声明。
二、抽象类和接口
1、抽象类中的方法可以有方法体,但是接口中的方法没有方法体。
2、抽象类的成员变量可以是各种类型的,而接口中的变量只能是public static final类型的。
3、接口中不能含有静态代码块以及静态方法,而抽象类是可以有静态代码块和静态方法的。(JDK 1.8 之后,接口里可以有静态方法和方法体了)
4、一个类只能继承一个抽象类,而一个类却可以实现多个接口。
变量 | 构造方法 | 方法 | |
---|---|---|---|
抽象类 | 无限制 | 子类通过构造方法调用构造方法,抽象类不能用new操作符实例化 | 无限制 |
接口 | 所有的变量必须是public static final | 没有构造方法,接口不可以用new操作符实例化 | 所有方法必须是公共的抽象实例方法 |
三、接口特性
1、接口中每一个方法也是隐式抽象的,接口中的方法也会被隐式的指定为public abstract。
2、接口中可以含有变量,但是接口中的变量会被隐式的指定为public static final 变量。
3、接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口中的方法。
4、当类实现接口的时候,类要实现接口中所有的方法,否则类必须声明为抽象类。
四、代码实例
1、由于接口中所有的数据域都是public static final,而且所有方法都是public abstract,所以Java允许忽略这些修饰符。因此。下面的接口定义是等价的:
/** 文件名 A.class */
public interface A {
/* 变量 */
public static final int a = 0;
/* 方法 */
public abstract void method();
}
/** 上下两个接口的定义是等价的 */
public interface A {
/* 变量 */
int a = 0;
/* 方法 */
void method();
}
2、接口的实现
/** 文件名 Debug.class */
public class Debug {
/** Main method */
public static void main(String[] args) {
Pen pen = new Pen(); // 调用实现接口的类
pen.yellow(); // 调用改类方法
}
}
/** 接口 */
interface Color {
/* 抽象方法 */
void yellow();
}
/** 实现接口 */
class Pen implements Color {
/* 实现抽象方法 */
@Override
public void yellow() {
System.out.println("My pen color is yellow");
}
}
输出:
My pen color is yellow
解释说明:
接口通过关键字implements来实现。
3、接口的多继承和实现多个接口
/** 文件名 Debug.class */
/** 接口1 */
interface Pen {
/* 抽象方法 */
void pen();
}
/** 接口2 */
interface Apple {
/* 抽象方法 */
void apple();
}
/** 接口3 */
interface All extends Pen, Apple {
/* 抽象方法 */
void pineapple();
}
/** 实现接口 */
class Song implements All {
@Override
public void pen() {
System.out.println("I have a pen");
}
@Override
public void apple() {
System.out.println("I have an apple");
}
@Override
public void pineapple() {
System.out.println("I have a pineapple");
}
public void play() {
this.pen();
this.apple();
this.pineapple();
System.out.println();
}
}
public class Debug {
/** Main method */
public static void main(String[] args) {
Song song = new Song();
song.play();
}
}
/** 实现多个接口的方式
class Song implements Pen, Apple {
}
*/
输出:
I have a pen
I have an apple
I have a pineapple
解释说明:
继承了多个接口之后,实现接口的类,要把接口中所有的抽象方法都重写。
总结
Java中的接口是非常有用的,接口的灵活性要比抽象类要高。讲完抽象类和接口后,你是不是会有这样子一个疑问:既然抽象类和接口的实现都要在子类进行重写,那么为什么不直接把这些接口中的方法直接写在子类中呢?可以参考一下这个文章https://blog.csdn.net/weixin_41804194/article/details/79506045
参考
1、https://lingcoder.gitee.io/onjava8/#/sidebar
2、https://www.runoob.com/java/java-tutorial.html
3、https://blog.csdn.net/weixin_41804194/article/details/79506045