【11】java之抽象类
一、抽象类基本概念
1.1 抽象类
抽象类:是指在普通类的结构里增加抽象方法的组成部分,抽象类要使用 abstract 声明。
抽象方法:没有方法体且必须使用 abstract 关键字进行定义。
拥有抽象方法的类一定是抽象类。
抽象类的使用原则如下:
- 抽象类必须有子类,即每一个抽象类一定要被子类所继承;
- 抽象类的子类(子类不是抽象类)必须要覆写抽象类里的抽象方法;
- 抽象类的对象实例化需要依靠子类完成,采用向上转型的方式处理。
范例:正确使用抽象类
abstract class A{
public void print(){
System.out.println("A、print()");
}
public abstract void fun();
}
class B extends A{
public void fun(){
System.out.println("B、fun()");
}
}
public class TestDemo{
public static void main(String args[]){
A a = new B();
a.fun();
}
}
1.2 总结
1、抽象类继承子类里会有明确的方法覆写要求,而普通类没有;
2、抽象类只比普通类多了一些抽象方法的定义,其他的组成部分和普通类完全一样;
3、普通类对象可以直接实例化,但是抽象类必须经过向上转型后才能实例化。
虽然一个子类可以去继承任何一个普通类,但是从开发的实际要求来讲,普通类不要去继承另外一个普通类,只能继承抽象类 或 接口。
二、抽象类的相关限制
1、抽象类中有构造方法吗?
有。抽象类会存在一些属性,那么在抽象类之中一定会存在构造方法,目的:为属性初始化,并且子类对象实例化的时候依然满足于先执行父类构造,再调用子类构造的情况。
2、抽象类能使用 final 定义吗?
不能。因为 final 定义的类不能被继承,而抽象类必须有子类,所以不能。
3、抽象类能用 static 定义吗?
外部抽象类不允许使用 static 声明,而内部的抽象类可以使用 static 声明。
使用 static 声明的内部类就相当于是一个外部抽象类,继承的时候使用“外部类.内部类”的形式表示类名称。
4、抽象类能否有 static 修饰的方法,此类是否需要被继承?
任何情况下,如果要执行类中的 static 方法的时候,都可以在没有对象的时候直接调用,对于抽象类也是一样。
此时可以没有子类。
5、有些时候,由于抽象类只需要一个特定的系统子类操作,所以可以忽略掉外部子类。
abstract class A{
public abstract void print();
private class B extends A{
public void print(){
System.out.println("Hello World!");
}
}
public static A getInstance(){
return new B();
}
}
public class TestDemo{
public static void main(String args[]){
A a = A.getInstance();
a.print();
}
}
这样的设计在系统类库之中会比较常见,目的是为用户隐藏不需要知道的子类。
对于之前有一个遗留的问题,那么下面看一段代码,分析代码的执行结果:
abstract class A{
public A(){
this.print();
}
public abstract void print();
}
class B extends A{
private int num = 100;
public B(int num){
this.num = num;
}
public void print(){
System.out.println("num = " + this.num);
}
}
public class TestDemo{
public static void main(String[] args){
new B(30);
new B(30).print();
}
}
执行结果:num = 0 和 num = 0 、 num = 30。
分析:在任何一个类的构造执行完之前所有属性的内容都是其对应数据类型的默认值,而子类构造执行之前一定先执行父类构造,那么此时子类构造没有执行完,所以 num 为 0。
三、抽象类应用——模板设计
例如,现在有三类事物:
- 机器人:充电、工作;
- 人:吃饭、工作、睡觉;
- 猪:吃饭、睡觉。
要求可以实现以上的操作控制,即可以任意的控制人、机器人、猪的操作行为(吃、工作、睡觉)。
【分析】
**这三类事物有一个共通的表现:行为。**具备相同的行为。
行为是抽象的概念,可以通过 abstract 描述。
abstract class Action{
public static final int EAT = 1;
public static final int WORK = 5;
public static final int SLEEP = 7;
abstract void eat();
abstract void work();
abstract void sleep();
public void command(int flag){
switch(flag){
case EAT:
this.eat();
break;
case WORK:
this.work();
break;
case SLEEP:
this.sleep();
break;
case EAT + WORK:
this.eat();
this.work();
break;
}
}
}
class Robot extends Action{
public void eat(){
System.out.println("机器人在充电。");
}
public void work(){
System.out.println("机器人在工作。");
}
public void sleep(){}
}
class Human extends Action{
public void eat(){
System.out.println("人在吃饭。");
}
public void work(){
System.out.println("人在工作。");
}
public void sleep(){
System.out.println("人在睡觉。");
}
}
class Pig extends Action{
public void eat(){
System.out.println("猪在吃饭。");
}
public void work(){
}
public void sleep(){
System.out.println("猪在睡觉。");
}
}
public class TestDemo{
public static void main(String args[]){
fun(new Robot());
fun(new Human());
fun(new Pig());
}
public static void fun(Action action){
action.command(Action.EAT);
action.command(Action.WORK);
action.command(Action.SLEEP);
}
}
这些不同的类型最终都在行为上成功的进行了抽象,即如果要想使用行为操作,那么就必须按照Action类的标准来实现子类。
模板设计思路:基类提供多个抽象方法和1个公共的普通方法,这个公共的普通方法会根据用户发出的请求不同,调用不同的抽象方法功能(并且每个子类有不同的实现)。
四、总结
1、如果要使用类继承,那么就使用抽象类(20%的情况下可能这样使用);
2、抽象类强制规定了子类必须要做的事情,而且可以与抽象类的普通方法相配合;
3、不管抽象类如何努力都有一个天生最大的问题:单继承局限。