抽象类
当父类的某些方法,需要声明,但是又不确定如何实现时,可以将其声明为抽象方法,那么,这个类就是抽象类
抽象类的价值更多是在于设计,是设计者设计好之后,让子类继承并实现抽象类
class Animal{
private String name;
private int age;
public Animal(String name, int age){
super();
this.name = name;
this.age = age;
}
//动物都有eat的行为,这里的eat实现了也没啥意义,因为不确定是什么动物
//这就体现了父类方法的不确定
public void eat(){
System.out.println("这是一个动物,但是目前不知道吃什么");
}
}
像图示代码中的eat()方法往往是Animal类的子类去重写,但是为了让子类去重写,父类也不得不写这样一个方法,这就很矛盾了,也就是父类方法的不确定性问题
简言之,当我们有一个类,其是父类,它有一些方法我们不能确定怎么去实现,我们又不想去实现怎么办?我们就可以把这个方法做成抽象方法,把这个类做成一个抽象类,这其实就是抽象类的一个来源
抽象方法?
抽象方法其实就是没有实现的方法,那什么又叫方法没有实现呢?其实就是指没有方法体;
public abstract void eat();//这其实就是一个抽象方法
//注意! 方法一旦声明成抽象方法之后,类也必须跟着声明成抽象类,
//也可以换种表述: 当一个类中存在抽象方法时,需要将该类声明为abstract类
小结:
- 当父类的一些方法不能确定时,可以用abstract关键字来修饰该方法,这个方法就是抽象方法,用abstract来修饰该类就是抽象类;
- 一般来说,抽象类会被继承,有其子类来实现抽象方法
抽象类的使用细节
抽象类不能被实例化
抽象类不一定要包含abstract方法,也就是说,抽象类可以没有abstract方法
public class Journey {
public static void main(String[] args) {
//报错: 'A' is abstract; cannot be instantiated
// new A();
}
}
//同时注意,此时的A就是抽象类,但是没有abstract方法,也没有报出异常
//甚至A中还可以有实现的方法
abstract class A{
public void hi(){
System.out.println("hi");
}
}
一旦一个类包含了abstract方法,则这个类必须声明为abstract
abstract只能修饰类和方法,不能修饰属性和其它的;
抽象类可以有任意成员【因为抽象类本质上还是类】,比如:非抽象方法(实现了的方法),构造器,静态属性等
public class Journey {
public static void main(String[] args) {
System.out.println("享受每一种体验!");
}
}
abstract class A{
public int youth = 679;
public static String essence = "不赶路,慢慢感受路";
//非抽象方法(实现了的方法)
public void hi(){
System.out.println("哦嗨哟");
}
//抽象方法
public abstract void hello();
//静态方法
public static void Fun(){
System.out.println("Enjoy my life!");
}
}
///以上代码可以正常跑出结果“享受每一种体验”
抽象方法不能有主体,即不能实现
如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,除非它自己也声明为abstract类
abstract class Life{
public abstract void Fun();
}
//报错:Class 'Youth' must either be declared abstract or implement abstract method 'Fun()' in 'Life'
//给了你两个选择,要么自己也玩抽象,要么实现Life类中的Fun方法hhhh,二选一
class Youth extends Life{ }
//solution 1: 自己也玩抽象
abstract class Youth extends Life{ }
//solution 2: 实现父类中所有的抽象方法
class Youth extends Life{
@Override
public void Fun() {
}
}
抽象方法不能使用private、final和static来修饰,因为这些关键字都是和重写相违背的
//这个抽象方法如果用private来修饰,那么子类继承了父类,也没有机会去实现;
//同样,如果加了final,final本意就是不希望子类来重写这个方法,同样也会导致子类没有机会去重写
//以及,static其本身就是和重写无关的一个关键字,写了也是肯定不行
public abstract void Fun();
练习
先写主要的抽象类
//抽象类---Employee
abstract class Employee{
private String name;
private int id;
private double salary;
//抽象方法work()
public abstract void work();
public Employee(String name, int id, double salary) {
this.name = name;
this.id = id;
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
接下来写继承抽象类的Manager类和CommonEmployee类
class Manager extends Employee{
private double bonus;
public Manager(String name, int id, double salary, double bonus) {
super(name, id, salary);
this.bonus = bonus;
}
@Override
public void work() {
System.out.println("经理"+getName()+"正在工作");
}
}
class CommonEmployee extends Employee{
public CommonEmployee(String name, int id, double salary) {
super(name, id, salary);
}
@Override
public void work() {
System.out.println("普通工人"+getName()+"正在工作中");
}
}
最后在main方法中测试下整体效果
public class Journey {
public static void main(String[] args) {
Manager manager1 = new Manager("kerwin", 111, 10000, 5000);
manager1.work();
CommonEmployee commonEmployee1 = new CommonEmployee("jason", 112, 8000);
commonEmployee1.work();
}
}
//最后的输出结果
经理kerwin正在工作
普通工人jason正在工作中
抽象类的最佳实践–模板设计模式
需求1:通过方法计算1+2+…800000;(要求,最大化地考虑代码复用性)
需求2:通过方法计算1 x 2 x 3 x … x 800000;(要求,最大化地考虑代码复用性)
本来可以写两个类,然后分别实现的,但仔细考虑会发现,二者除了核心的计算方法不同外,其余的步骤都相同,可以抽象出来,所以我们考虑模板设计模式在这之中的应用
//将两个计算需求的核心给分别实现
//计算任务1+.....+800000
public class AA extends Template{
@Override
public void job() {//实现了Template的抽象方法job
long num = 0;
for (int i = 1; i <= 800000; i++) {
num+= i;
}
}
}
//计算任务1*2*3....*800000
public class BB extends Template{
@Override
public void job() {//这里也重写了Template的job方法
long num = 0;
for (int i = 1; i <= 800000; i++) {
num*= i;
}
}
}
抽象出的模板类–这就是除了计算部分外的其他二者的可复用部分
//抽象类--模板设计模式
abstract public class Template {
//抽象方法
public abstract void job();
//实现了的方法,调用了job()方法
public void calculateTime(){
//得到开始的时间
long start = System.currentTimeMillis();
job();//这里涉及到动态绑定机制,动态绑定机制中调用方法,要看运行类型是哪个类其中的对象调用的job()
//得到结束的时间
long end = System.currentTimeMillis();
System.out.println("任务执行时间 "+(end - start));
}
}
最后来写个测试类,测试下
public class TestTemplate {
public static void main(String[] args) {
AA aa = new AA();
aa.calculateTime();
BB bb = new BB();
bb.calculateTime();
}
}
//通过跑这个测试类代码,我们就可以动态地查看两个计算需求任务所耗费的时间(输出结果用时因为各自电脑配置不同而可能导致不同)