1、抽象类的定义与使用
抽象类只是在普通类的基础上扩充了一些方法而已,所谓的抽象方法就是只声明而未实现的方法。所有抽象方法要求使用
abstract
关键字来定义,并且抽象方法所在的类也要使用abstract
关键字来定义,表示抽象类。
注意:抽象类不能直接产生实例化对象。
1.1 抽象类的使用原则
- 所有抽象类必须有子类
- 抽象类的子类必须覆写抽象类的所有抽象方法(子类不是抽象类)
- 抽象类的对象可以通过对象多态性利用子类为其实例化
- private和abstract不能同时使用
abstract class Person {
private String name;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public abstract void getPersonInfo();
}
class Student extends Person {
public void getPersonInfo() {
System.out.println("I am a student!");
}
}
public class Test {
public static void main(String[] args) {
Person per = new Student();
per.getPersonInfo();
}
}
1.2 抽象类的相关规定
- 抽象类只是比普通类多了一些抽象方法,在抽象类中也允许提供构造方法,并且在实例化子类时一定先调用父类构造方法。
abstract class Person {
private String name;
public Person() {
System.out.println("******************");
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public abstract void getPersonInfo();
}
class Student extends Person {
public Student() {
System.out.println("############");
}
public void getPersonInfo() {
//空实现
}
}
public class Test {
public static void main(String[] args) {
new Student();
}
}
- 如果父类没有无参构造,那么子类构造必须使用super明确指出使用父类的哪个构造方法。
来看一段特殊的代码:
abstract class A {
public A() {
this.print();
}
public abstract void print();
}
class B extends A {
private int num = 100;
public B(int num) {
super();
this.num = num;
}
public void print() {
System.out.println(this.num);
}
}
public class Test {
public static void main(String[] args) {
new B(30);
}
}
上面这段代码输出是啥,不妨猜一下,30 ???来我们我看一下运行结果:
为什么是0呢,我们来分析一下运行的过程:
首先第一步肯定是实例化子类对象new B(30);
接着调用子类实例化对象:
调用子类实例化对象的方法时,有super()方法,首先调用父类构造:
父类的构造方法中,调用了本类的抽象方法print(),接着去调用被子类覆写的方法print();
注意,此时子类对象的属性还没有被初始化
,所以打印出来的还是对应数据类型的默认值,也就是0,最后才执行子类中this.num = num;
这个语句,为类中属性初始化。
- 抽象类中允许不定义任何的抽象方法,但是此时抽象类依然无法直接创建实例化对象。
- 抽象类一定不能使用final声明,因为使用final声明的类不允许存在子类,而抽象类必须有子类,同理,抽象方法也不能使用private定义,因为抽象方法必须要能被覆写。
- 抽象类也分为内部抽象类和外部抽象类,内部抽象类中也可以使用static定义来描述外部抽象类。
2、接口的定义与使用
抽象类存在单继承局限,所以就有了接口。
概念:
接口就是抽象方法和全局常量的集合,在Java中接口使用interface
关键字定义。
子类如果想使用接口,就必须使用implements
关键字来实现接口,同时,一个类可以实现多个接口。
注意:
对于接口的子类必须覆写接口中的全部抽象方法,随后可以利用子类的向上转型通过实例化子类来得到接口的实例化对象。
2.1 接口的使用限制
- 接口中只允许public权限(不管是属性还是方法,其权限都是public)
- 当一个子类既需要实现接口又需要继承抽象类时,先使用
extends
继承一个抽象类,再使用implements
实现多个接口。 - 一个抽象类可以使用
implements
实现多个接口,但是接口不能继承抽象类。
interface IMessage {
public void print();
}
abstract class News implements IMessage {
//News是抽象类,可以不实现Imessage中的抽象方法
public abstract void getNews();
}
class MessageImpl extends News {
public void print() {
System.out.println("I am a girl");
}
public void getNews() {
System.out.println("I am news");
}
}
public class Test {
public static void main(String[] args) {
IMessage m = new MessageImpl();
m.print();
News news = (News) m;
news.getNews();
}
}
- 一个接口可以使用
extends
继承多个父接口 - 接口可以定义一系列的内部结构,包括内部普通类、内部接口。其中使用static定义的内部接口就相当于一个外部接口。
interface A {
public void printA();
static interface B {
public void printB(); //使用static定义,描述一个外部接口
}
}
class Impl implements A.B {
public void printB() {
}
}
public class Test {
public static void main(String[] args) {
}
}
3、抽象类与接口的区别
- 结构组成
抽象类是普通类+抽象方法,接口是抽象方法+全局常量。 - 权限
抽象类支持各种权限,接口只支持public - 子类使用
子类通过extends
关键字继承抽象类,使用implements
关键字实现接口 - 关系
一个抽象类可以实现多个接口,接口不能继承抽象类,但是接口可以使用extends
关键字继承多个父接口 - 子类限制
一个子类只能继承一个抽象类,一个子类可以实现多个接口