在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。
抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。
由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。也是因为这个原因,通常在设计阶段决定要不要设计抽象类。
父类包含了子类集合的常见的方法,但是由于父类本身是抽象的,所以不能使用这些方法。
在Java中抽象类表示的是一种继承关系,一个类只能继承一个抽象类,而一个类却可以实现多个接口。
抽象类和抽象方法的声明格式
1 | abstract class <类名> { |
例如:
1 | abstract public class Animal { |
从例子中可以看出,抽象类是用关键字 abstract 修饰的。抽象类中有一种特殊方法,即用 abstract 关键字来修饰的方法,称为”抽象方法“。
抽象类和抽象方法的特点
抽象方法不允许直接实例化,换句话说抽象类不能创建对象,他只能作为其他类的父类。但可以通过向上转型,指向实例化。
抽象方法只有声明,不能实现,也就是说仅有方法头,而没有方法体和操作实现。
如:
abstract void sleep();
抽象类的意义
为其子类提供一个公共的类型(父类引用指向子类)
1
Animal a = new Cat();
封装子类中重复内容(成员变量和方法)
将父类设计成抽象类后,既可借由父子继承关系限制子类的设计随意性,在一定程度上避免了无意义父类的实例化
重点注意
含有抽象方法的类,只能被定义成抽象类
1
2
3
4
5
6
7
8
9public class Animal {//这里报错了
public String name;
public void eat(){
System.out.println("animal eating...");
}
abstract public void sleep();
}抽象类不一定包含抽象方法
1
2
3
4
5public class Animal {
public void eat(){
System.out.println("animal eating...");//一般方法
}
}在抽象类中的成员方法可以包括一般方法和抽象方法
1
2
3
4
5
6
7
8abstract public class Animal {
public String name;
public void eat(){
System.out.println("animal eating...");
}
abstract public void sleep();
}抽象类不能实例化,及时抽象类里不包含抽象方法 ,这个抽象类 也不能创建实例,抽象类的构造方法主要是用于被其子类调用
例子:
Animal 抽象类中不包含抽象方法
1
2
3
4
5
6
7abstract public class Animal {
public String name;
public void eat(){
System.out.println("animal eating...");
}
}测试类中实例化 Animal ,编译器会报错
1
2
3
4
5public class Main {
public static void main(String[] args) {
Animal a = new Animal();//这里报错了
}
}一个类继承抽象类后,必须实现其所有抽象方法,否则也是抽象类,不同的子类对父类的抽象方法可以有不同的实现
如父类:
1
2
3
4
5
6
7
8
9abstract public class Animal {
public String name;
public void eat(){
System.out.println("animal eating...");
}
abstract public void sleep();
}则其子类 Cat 有两种做法
方案一:重写抽象方法 sleep(),使方法得以实现
1
2
3
4
5
6
7
8
9public class Cat extends Animal{
public void sleep(){
System.out.println("猫要睡大觉!");
}
public void run(){
System.out.println("我不想跑");
}
}方案二:子类 Cat 类也定义为抽象类
1
2
3
4
5
6abstract public class Cat extends Animal{//没有实现父类中的抽象方法,所以是抽象类
public void run(){
System.out.println("我不想跑");
}
}即使父类是具体的,但其子类也可以是抽象的,如 Object 是具体的,但可以创建抽象子类
abstract 方法不能用 static 和 private 修饰;对于类,不能同时用 final 和 abstract 修饰,因为 final 关键字使得类不可继承,而 abstract 修饰的类如果不可以继承将没有任何意义。两者放一起回起冲突
一个完整的抽象类的例子
父类:
1 | abstract public class Shape { |
子类:
1 | public class Circle extends Shape { |
测试类:
1 | public class Main { |
运行结果:
圆的面积为:38.465
小结
- 抽象类不能被实例化,如果被实例化,就会报错,编译无法通过。只有抽象类的非抽象子类可以创建对象
- 抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类
- 抽象类中的抽象方法只是声明,不包含方法体,就是不给出方法的具体实现
- 构造方法,类方法(用 static 修饰的方法)不能声明为抽象方法
- 抽象类的子类必须给出抽象类中的抽象方法的具体实现,除非该子类也是抽象类