目录
1.5 抽象的具体应用:模板方法设计模式(TemplateMethod)
01 抽象类(abstract)
随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一般,更通用。类的设计应该保证父类和子类能够共享特征。有时将一个父类设计得非常抽象,以至于它没有具体的实例,这样的类叫做抽象类
修饰类(抽象类)
/*
abstract 修饰类:抽象类
* 》 此类不能实例化
* 》 抽象类中一定有构造器,便于子类实例化时调用(涉及:子类对象实例化全过程)
* 》 开发中,都会提供抽象类的子类,让子类对象实例化,实现相关的操作
*/
public class AbstractTest {
public static void main(String[] args){
Person1 person = new Person1(); // 报错 不可实例化
Student student = new Student();
}
}
abstract class Person1{ //形容 类
String name;
int age;
public Person1() {
}
public Person1(String name, int age) {
this.name = name;
this.age = age;
}
}
// 子类可以实例化
class Student extends Person1{
public Student(String name, int age){
super(name, age);
}
}
修饰方法(抽象方法)
4.abstract 修饰方法:抽象方法
* > 抽象方法,只有方法的声明,没有方法体。
* > 包含抽象方法的类,一定是一个抽象类。反之,抽象类中可以没有抽象方法
抽象方法不可被调用,就要保证类不能被实例化
* > 若子类重写了父类中所有的抽象方法,此子类才能实例化,否则此子类也是抽象类
abstract class Creature{
public abstract void breath(); // 只能声明,没有方法体
}
abstract class Person extends Creature{
String name;
int age;
public Person(){
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
//不是抽象方法
// public void eat(){
// System.out.println("人吃饭");
// }
//抽象方法
public abstract void eat(); // 此时Person类有两个抽象方法
public void walk(){
System.out.println("人走路");
}
}
class Student extends Person{
public Student(String name,int age){
super(name,age);
}
public void eat(){ // 重写父类的抽象方法
System.out.println("学生应该多吃有营养的。");
}
@Override
public void breath() { // 也要重写根类的抽象方法
System.out.println("学生应该呼吸新鲜的无雾霾空气");
}
}
1.1 抽象应用场景举例
抽象类是用来模型化那些父类无法确定全部实现,而是由其子类提供具体实现的对象的类。
/* Java 允许类设计者指定:超类声明一个方法但不提供实现,该方法的实现由子类提 供。这样的方法称为抽象方法。有一个或更多抽象方法的类称为抽象类。
* Vehicle 是一个抽象类,有两个抽象方法。
* 注意:抽象类不能实例化 new Vihicle()是非法的
*/
public abstract class Vehicle{
public abstract double calcFuelEfficiency();//计算燃料效率的抽象方法
public abstract double calcTripDistance();//计算行驶距离的抽象方法
}
public class Truck extends Vehicle{
public double calcFuelEfficiency(){
//写出计算卡车的燃料效率的具体方法
}
public double calcTripDistance(){
//写出计算卡车行驶距离的具体方法
}
}
public class RiverBarge extends Vehicle{
public double calcFuelEfficiency() {
//写出计算驳船的燃料效率的具体方法
}
public double calcTripDistance( ) {
//写出计算驳船行驶距离的具体方法
}
}
1.2 abstract注意点
- abstract不能修饰: 属性,构造器等结构(构造器本身不能重写,只能重载)
- abstract不能修饰
- private方法(private方法无法在子类中重写,但abstract总会在子类中重写)
- static方法 子父类方法均为static 不叫重写
- final方法和类: final不能重写;也不能被继承
1.3 抽象类的练习
Employee(抽象类)
/*
* 编写一个 Employee 类,声明为抽象类,
* 包含如下三个属性:name,id,salary。
* 提供必要的构造器和抽象方法:work()。
* 对于 Manager 类来说,他既是员工,还具有奖金(bonus)的属性。
* 请使用继承的思想,设计 CommonEmployee 类和 Manager 类,
* 要求类中提供必要的方法进行属性访问。
*
*/
public abstract class Employee {
private String name;
private int id;
private double salary;
public Employee(){
super();
}
public Employee(String name, int id, double salary) {
super();
this.name = name;
this.id = id;
this.salary = salary;
}
public abstract void work();
}
Manager类
/*
* 对于 Manager 类来说,他既是员工,还具有奖金(bonus)的属性。
*
*/
public class Manager extends Employee{
private double bonus; //奖金
public Manager(double bonus) {
super();
this.bonus = 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("管理员工,提高公司运行效率。");
}
}
1.4 抽象类的匿名子类
public class Num {
}
abstract class Creature{
public abstract void breath();
}
abstract class Person extends Creature{
String name;
int age;
public Person(){
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
//不是抽象方法
// public void eat(){
// System.out.println("人吃饭");
// }
//抽象方法
public abstract void eat();
public void walk(){
System.out.println("人走路");
}
}
class Student extends Person{
public Student(String name,int age){
super(name,age);
}
public Student(){
}
public void eat(){
System.out.println("学生应该多吃有营养的。");
}
@Override
public void breath() {
System.out.println("学生应该呼吸新鲜的无雾霾空气");
}
}
PersonTest 类
/*
* 抽象类的匿名子类
*
*/
public class PersonTest {
public static void main(String[] args) {
method(new Student()); //匿名对象,匿名对象只用一次
Worker worker = new Worker();
method1(worker); //非匿名的类非匿名的对象
method1(new Worker()); //非匿名的类匿名的对象
System.out.println("*********************");
//创建了一个匿名子类的对象:p 这里为匿名子类
Person p = new Person(){
@Override
public void eat() {
System.out.println("吃东西");
}
@Override
public void breath() {
System.out.println("呼吸空气");
}
};
method1(p);
System.out.println("**********************");
//创建匿名子类的匿名对象
method1(new Person(){
@Override
public void eat() {
System.out.println("吃零食");
}
@Override
public void breath() {
System.out.println("云南的空气");
}
});
}
public static void method1(Person p){
p.eat();
p.walk();
}
public static void method(Student s){
}
}
class Worker extends Person{
@Override
public void eat() {
}
@Override
public void breath() {
}
}
1.5 抽象的具体应用:模板方法设计模式(TemplateMethod)
抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为方式。
解决的问题:
当功能内部一部分实现是确定的,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。
在软件开发中实现一个算法时,整体步骤很固定、通用,这些步骤已经在父类中写好了。但是某些部分易变,易变部分可以抽象出来,供不同子类实现。这就是一种模板模式。
ublic class TemplateTest {
public static void main(String[] args){
Template template = new subTemplate();
template.spendTime();
}
}
abstract class Template{
// 计算某段代码执行花费时间
public void spendTime(){
long start = System.currentTimeMillis();
code(); // 不确定的部分
long end = System.currentTimeMillis();
System.out.println(end - start);
}
public abstract void code(); // 抽象方法
}
// 在子类中重写抽象方法
class subTemplate extends Template{
@Override
public void code() {
for(int i = 2 ; i <= 1000; i++){
boolean isFlag = true;
for(int j = 2; j <= Math.sqrt(i) ; j++){
if(i % j == 0){
isFlag = false;
break;
}
}
if(isFlag == true){
System.out.println(i);
}
}
}
}
1.6 抽象类的练习
类的编写
abstract class Employee {
private String name;
private int id;
private MyDate birthday;
public Employee(String name, int id, MyDate birthday) {
this.name = name;
this.id = id;
this.birthday = birthday;
}
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 MyDate getBirthday() {
return birthday;
}
public void setBirthday(MyDate birthday) {
this.birthday = birthday;
}
public abstract double earings();
public String toString(){
return "Employee:" + name + " " + id + " " + birthday.toDateString();
}
}
class MyDate{
private int year;
private int month;
private int day;
public MyDate(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
public String toDateString(){
return year + "年" + month + "月" + day + "日";
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public int getDay() {
return day;
}
public void setDay(int day) {
this.day = day;
}
}
class SalariedEmployee extends Employee{
private double monthlySalary;
public SalariedEmployee(String name, int id, MyDate birthday, double monthlySalary) {
super(name, id, birthday);
this.monthlySalary = monthlySalary;
}
@Override
public double earings() {
return monthlySalary;
}
@Override
public String toString() {
return "SalariedEmployee{" + this.getName() + " " + this.getId() + " " + this.getBirthday().toDateString() +
" monthlySalary=" + monthlySalary +
'}';
}
}
class HourlyEmployee extends Employee{
private int wage;
private int hour;
public HourlyEmployee(String name, int id, MyDate birthday, int wage, int hour) {
super(name, id, birthday);
this.wage = wage;
this.hour = hour;
}
public int getWage() {
return wage;
}
public int getHour() {
return hour;
}
public void setWage(int wage) {
this.wage = wage;
}
public void setHour(int hour) {
this.hour = hour;
}
@Override
public double earings() {
return wage * hour;
}
@Override
public String toString() {
return "HourlyEmployee{" + this.getName() + " " + this.getId() + " " + this.getBirthday().toDateString() + "}";
}
}
主程序测试
import java.util.Scanner;
public class PayrollSystem {
public static void main(String[] args){
Employee[] employees = new Employee[4];
employees[0] = new SalariedEmployee("Masen", 1001, new MyDate(1997,12,30),5000);
// 数组的初始化,每一个索引相当于新new一个对象
employees[1] = new SalariedEmployee("WangSan", 1002, new MyDate(1996,10,20),11000);
employees[2] = new HourlyEmployee("LiSi", 1009, new MyDate(1996,10,20),10, 70);
employees[3] = new HourlyEmployee("ZhangWu", 5000, new MyDate(1998,7,20),10, 70);
Scanner scanner = new Scanner(System.in);
int month = scanner.nextInt();
for(int i = 0; i < employees.length; i++){
System.out.print(employees[i].toString());
if(month == employees[i].getBirthday().getMonth()){
System.out.println("本月奖金100元");
}
System.out.println();
}
}
}