1 抽象类
1.1 什么是抽象类
使用抽象关键字abstract声明的类是抽象类,抽象类不能直接实例化创建对象。
这个定义看上去非常茫然,究其原因是因为在面向对象设计时候,会利用“泛化”将子类的共同属性和方法抽取出来设计出父类,此时的父类往往是半成品类,只包含部分属性和方法,甚至属性值都没有合理初始化,如下图所示:
如果直接创建对象并且使用有可能造成各种不理想结果,甚至是异常故障。
可以用抽象父类来解决这个问题。
1.2 抽象类示例
为便于理解抽象类的作用,我们先开发一个不使用抽象类的案例,查看此时可能存在的问题。
/**
* Person类的作用是为子类提供代码复用
*/
public class Person {
String name;
int age;
public void whoru() {
System.out.println("我是"+name);
}
}
package day07.abstract01;
public class Student extends Person{
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public void study() {
System.out.println("学习");
}
}
package day07.abstract01;
public class Teacher extends Person{
public Teacher(String name, int age) {
this.name = name;
this.age = age;
}
public void teach() {
System.out.println("讲课");
}
}
package day07.abstract01;
public class Worker extends Person{
public Worker(String name, int age) {
this.name = name;
this.age = age;
}
public void work() {
System.out.println("工作");
}
}
package day07.abstract01;
public class AbstractDemo1 {
public static void main(String[] args) {
Student s = new Student("Tom", 12);
Teacher t = new Teacher("Andy", 28);
Worker w = new Worker("Jerry", 28);
s.whoru();
s.study();
t.whoru();
t.teach();
w.whoru();
w.work();
//问题:如果能够直接创建Person对象,其方法运算结果不理想
Person p = new Person();
p.whoru();
}
}
上面案例的运行结果如下所示:
上述运行结果中创建Person类型对象,调用其whoru()方法,得到结果是null。
这个结果并不理想,就像生活中问一个人是谁,回答“佚名”一样。造成这个结果的原因是:泛化出来的父类Person 是个半成品类,创建其对象后,其name属性没有合理初始化,导致输出了name的默认值 null。
如何解决上述问题呢?需要明确表示 Person是一个半成品类,不能直接实例化。
因此,就可以使用abstract修饰一下Person类型,使其成为抽象类,这样Java的编译器就会限制Person类型,不允许其直接实例化创建对象。不能被实例化,就不可能造成后续结果了。所以合理使用abstract类,可以避免创建不应该创建的对象,减少程序的错误。
将上述案例中的Person类声明为抽象类,可避免出现创建半成品实例的情况。案例代码示意如下:
/**
* Person类的作用是为子类提供代码复用
*/
public abstract class Person {
String name;
int age;
public void whoru() {
System.out.println("我是"+name);
}
}
package day07.abstract02;
public class AbstractDemo2 {
public static void main(String[] args) {
Student s = new Student("Tom", 12);
Teacher t = new Teacher("Andy", 28);
Worker w = new Worker("Jerry", 28);
s.whoru();
s.study();
t.whoru();
t.teach();
w.whoru();
w.work();
//问题:如果能够直接创建Person对象,其方法运算结果不理想
//Java编译器检查,不允许创建抽象类型的对象!
//Person p = new Person();
//p.whoru();
}
}
1.3 抽象类不可以实例化
面向对象设计时候根据子类泛化得到的半成品父类,应该定义为抽象类,这样可以限制创建半成品类的对象,减少意外的错误发生。
正因为抽象类不可以被实例化,因此 abstract 和 final 不可以同时修饰一个类:final 关键字使得类不可被继承,而抽象类既不能能被继承,又不能被实例化,则没有任何意义。
使用抽象类时:
1、在类名前面添加abstract关键字以后就是抽象类了
2、抽象类可以作为父类被子类继承,可以定义变量
3、抽象类不能直接创建对象
2 抽象方法
2.1 什么是抽象方法
使用abstract关键字声明,不包含方法体的方法称为抽象方法。
这个定义同样晦涩,究其原因是因为在利用泛化设计父类时候,有这种情况全体子类都有相同的方法,但是每个具体方法实现都并不相同,这样只能将方法名抽取到父类,方法体留在每个子类中,这种只有方法名称的方法,就是抽象方法。
2.2 抽象方法的语法
抽象方法的语法:
1、使用abstract声明方法,不能有方法体
2、包含抽象方法的类必须声明为抽象类,因为包含抽象方法的类一定是不完整的半成品类
3、子类继承抽象类时候必须重写(实现)抽象方法,否则出现编译错误
- 可以将抽象方法看作父类对子类的行为约定,必须被子类重写实现
实际使用时,如何选择抽象方法?建议规则:每个子类都有,但是每个子类实现都不同的方法泛化为抽象方法!
定义抽象类,并包含抽象方法;定义子类继承自抽象类,并重写抽象方法。编写代码测试其特点。
案例示意代码如下:
/**
* Person类的作用是为子类提供代码复用
* 设计为抽象类,只能被继承,不能创建对象
*/
public abstract class Person {
String name;
int age;
public void whoru() {
System.out.println("我是"+name);
}
/**
* 日程计划
*/
public abstract void schedule();
}
package day07.abstract03;
public class Student extends Person {
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public void study() {
System.out.println("学习");
}
public void schedule() {
System.out.println("吃饭、听课");
}
}
package day07.abstract03;
public class Student extends Person {
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public void study() {
System.out.println("学习");
}
public void schedule() {
System.out.println("吃饭、听课");
}
}
package day07.abstract03;
public class Worker extends Person {
public Worker(String name, int age) {
this.name = name;
this.age = age;
}
public void work() {
System.out.println("工作");
}
public void schedule() {
System.out.println("吃饭、开车");
}
}
package day07.abstract03;
public class AbstractDemo3 {
public static void main(String[] args) {
Student s = new Student("Tom", 12);
Teacher t = new Teacher("Andy", 28);
Worker w = new Worker("Jerry", 28);
s.schedule();
t.schedule();
w.schedule();
}
}
综合抽象类和抽象方法的讲解,可以简单理解抽象类的意义如下:
- 为其子类提供一个公共的类型
- 封装子类中的重复内容(成员变量和方法)
- 定义有抽象方法,子类虽然有不同的实现,但该方法的定义是一致的