当父类的某一些方法并不知道具体实现内容,但需要继承给子类让其在子类中实现时,就可以将这些方法声明为抽象方法,而有抽象方法的类就叫做抽象类。使用abstract来声明。
package com.atguigu.abstract_; public class AbstractTest01 { public static void main(String[] args) { Cat cat = new Cat("小花猫"); cat.eat(); } } abstract class Animal { //抽象类 private String name; public Animal(String name) { super(); this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } //eat , 抽象方法 public abstract void eat(); } //解读 //1. 当一个类继承了抽象类,就要把抽象类的所有抽象方法实现 //2. 所谓方法实现,指的是 把方法体写出, 方法体是空,也可以. class Cat extends Animal { public Cat(String name) { super(name); // TODO Auto-generated constructor stub } public void eat() { System.out.println(getName() + " 爱吃 <・)))><<"); } }
语法说明
抽象类:
访问修饰符 abstract class 类名{}
抽象方法:(抽象方法没有方法体!)
访问修饰符 abstract 返回类型 方法名(参数列表);
抽象类使用细节
-
抽象类不可以被实例化
-
抽象类不一定必须包含abstract方法,即抽象类不一定有抽象方法
-
一旦包含了抽象方法,则这个类必须声明为abstract抽象类
-
abstract只能修饰类与方法,不可以修饰其他内容
-
抽象类可以有任意成员(因为抽象类还是类),比如:非抽象方法、构造器、静态属性等等
-
抽象方法不能有主体,即不能实现
-
如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,除非它自己也声明为abstract类。
-
抽象方法不能使用private、final 和 static来修饰,因为这些关键字都是和重写相违背的。
package class_abstract; public class Abstract_Test { public static void main(String[] args) { //细节1:对于抽象类而言,不可以声明实例 // A a = new A(); //报错:Cannot instantiate the type A //细节5.但当抽象类的子类,创建了实例之后,仍然可以使用A类中满足访问权限的所有东西。(继承的特点) B b = new B(); b.setName("小范"); b.getName(); } } abstract class A{ //细节3:由于A类中的hi()方法是被abstract修饰的(即抽象方法),所以A类也必须声明为抽象的 private String name; //细节5:抽象类中也可以有非抽象的东西,抽象类本质也是一个类 public String getName() { return name; } public void setName(String name) { this.name = name; } public abstract void hi(); //细节6:对于抽象类而言,不可以有{},即方法体 public abstract void hello(); } class B extends A{ //细节7:只要继承抽象类,则必须实现抽象类中所有的抽象方法。否则编译器报错: //The type B must implement the inherited abstract method A.hi().... @Override public void hi() { System.out.println("B----hi"); } @Override public void hello() { System.out.println("B-----hello"); } } abstract class C extends A{ /* 细节7: * 若继承了抽象类,但子类本身也是一个抽象类,那么可以不用实现抽象类中的抽象方法 * 因为对于抽象子类C而言,是允许抽象方法存在的。 * 一旦有非抽象子类D,继承了子类C,那么D同样需要实现抽象子类C中的所有抽象方法 */ // private abstract int age; //abstract 只能修饰方法与类,不可以修饰属性和其他的 /* 细节8: * 对于抽象方法而言,不可以使用 private 或 final 修饰 * 因为,抽象的本质就规范化父类的东西,让子类去实现父类已经写好的抽象方法 * 而用private与final修饰的方法都不可以被子类继承,这就与抽象的作用冲突了 */ // private abstract void m1(); /* 细节8: * 对于抽象方法而言,也不可以使用 static 修饰 * 因为,static修饰之后,方法不再是成员方法了,而是类方法。 * 而子类是无法继承类方法的,所以static与abstract的作用也是产生冲突了。 */ // public static abstract void m2(); } class D extends C{ @Override public void hi() { System.out.println("D-----hi"); } @Override public void hello() { System.out.println("D-----hello"); } }
多态在抽象类中的实现
简单案例
package class_abstract; public class AbstractPolyArray { public static void main(String[] args) { //抽象类不可以实例化,但可以使用多态数组 Animal[] animal = new Animal[2]; animal[0] = new Dog("小黑狗"); animal[1] = new Cat("小花猫"); //多态数组的使用 for (int i = 0; i < animal.length; i++) { show(animal[i]); } } //这里不用担心会传入一个Animal类型的实例,因为Animal不能实例化 //编译器不会通过,所以只会传入Animal的子类实例 public static void show(Animal a) { a.eat(); //多态的使用 if(a instanceof Dog) { ((Dog)a).watch(); }else if(a instanceof Cat) { ((Cat)a).catchMouse(); } } } abstract class Animal{ private String name; public Animal(String name) { super(); this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } //动物都有eat的动作,但我们并不知道每一个动物具体怎么样eat //所以这里通过抽象提供了eat方法,需要子类来实现 public abstract void eat(); } class Dog extends Animal{ public Dog(String name) { super(name); } @Override public void eat() { System.out.println(getName() + "啃骨头......"); } public void watch() { System.out.println(getName() + "守家....."); } } class Cat extends Animal{ public Cat(String name) { super(name); } @Override public void eat() { System.out.println(getName() + "吃鱼......"); } public void catchMouse(){ System.out.println(getName() + "抓老鼠....."); } }
程序输出
小黑狗啃骨头......
小黑狗守家.....
小花猫吃鱼......
小花猫抓老鼠.....
抽象类简单应用案例
编写一个Employee类,声明为抽象类,包含如下三个属性:name,id,salary。
-
提供必要的构造器和抽象方法:work()。
-
请使用继承的思想,设计CommonEmployee类和Manager类,
-
对于Manager类来说,他既是员工,还具有奖金(bonus)的属性。
-
要求类中提供必要的方法进行属性访问,实现work(),提示 "经理/普通员工 名字 工作中...."
package class_abstract; public class Abstract_ClassWork { public static void main(String[] args) { Employee[] em = new Employee[2]; em[0] = new Manager("小黄", 1001, 5000, 1120); em[1] = new CommonEmployee("小范", 1002, 3000); System.out.println(em[0].toString()); em[0].work(); System.out.println(em[1].toString()); em[1].work(); } } abstract class Employee{ private String name; private int id; private double salary; 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; } public abstract void work(); @Override public String toString() { return "name=" + name + ", id=" + id + ", salary=" + salary; } } //对于Manager类来说,他既是员工,还具有奖金(bonus)的属性。 class Manager extends Employee{ private double bonus; public Manager(String name, int id, double salary, double bonus) { super(name, id, salary); this.bonus = bonus; } public double getBonus() { return bonus; } public void setBonus(double bonus) { this.bonus = bonus; } //"经理/普通员工 名字 工作中...." @Override public void work() { System.out.println("经理" + getName() + "工作中......"); } @Override public String toString() { return super.toString() + ",bonus =" + bonus; } } class CommonEmployee extends Employee{ public CommonEmployee(String name, int id, double salary) { super(name, id, salary); // TODO Auto-generated constructor stub } //"经理/普通员工 名字 工作中...." @Override public void work() { System.out.println("普通员工" + getName() + "工作中......"); } }
程序输出
name=小黄, id=1001, salary=5000.0,bonus =1120.0
经理小黄工作中......
name=小范, id=1002, salary=3000.0
普通员工小范工作中......
抽象类最佳实践-模板设计模式
抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为方式。
1) 当功能内部一部分实现是确定,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。
2) 编写一个抽象父类,父类提供了多个子类的通用方法,并把一个或多个方法留给其子类实现,就是一种模板模式
简单案例
1) 设计一个抽象类(Template),能完成如下功能:
2) 编写方法caleTime() ,可以计算某段代码的耗时时间
3) 编写抽象方法code()
4) 编写一个子类Sub,继承抽象类Template,并实现code方法。
package class_abstract; public class Abstract_Template { public static void main(String[] args) { Template sub = new Sub(); sub.caleTimes(); //实际是调用了Template中的caleTimes方法 Template subStringB = new SubStringB(); subStringB.caleTimes(); //这里可以看到 StringBuffer在拼接字符串时,远远优于String拼接的效率 } } abstract class Template{ //抽象类 public abstract void code(); //抽象方法 public void caleTimes(){ // 统计耗时多久是确定 //统计当前时间距离 1970-1-1 0:0:0 的时间差,单位ms long start = System.currentTimeMillis(); code(); //这里的code在调用时,就是指向子类中已经重写实现了的code long end = System.currentTimeMillis(); System.out.println("耗时:"+(end-start)); } } class Sub extends Template{ @Override public void code() { String x = ""; for(int i = 0;i < 10000 ; i++) { //拼接1W个hello 看处理时间 x += "hello" + i; } } } class SubStringB extends Template{ @Override public void code() { StringBuffer stringBuffer = new StringBuffer(); for(int i = 0;i < 10000 ; i++) { //拼接1W个hello 看处理时间 stringBuffer.append("hello" + i); } } }
程序输出
耗时:606
耗时:2