Java 从入门到进阶之路(十三)
丰寸 人气:0在之前的文章我们介绍了一下 Java 类的 private,static,final,本章我们来看一下 Java 中的抽象类和抽象方法。
我们先来看下面一段代码:
1 // 根据周长求面积 2 class Square { // 方形类 3 double c; 4 5 double area() { // 方形面积 6 return 0.0625 * c * c; 7 } 8 } 9 10 class Circle { // 圆形类 11 double c; 12 13 double area() { // 圆形面积 14 return 0.0796 * c * c; 15 } 16 }
在上面的代码中我们分别定义了一个方形类和圆形类,然后根据周长计算出各自的面积。咋上面的代码中可以看出这两段代码都有相同的地方,我们第一感觉就是将相同的部分单独封装成一个父类,然后通过集成的方式完成,如下:
1 class Shape { // 图形 2 double c; 3 4 double area() { // 如果不 return 的话会编译错误 5 return 系数 * c * c; // 不同形状系数不同 6 } 7 8 void area() { // 不会出现编译错误,但是这样写这个方法没有任何意义 9 10 } 11 } 12 13 // 根据周长求面积 14 class Square extends Shape { // 方形类 15 16 } 17 18 class Circle extends Shape { // 圆形类 19 20 }
在上面的代码中我们单独封装了一个 Shape 类,但是有一个问题,周长 c 是公共的没问题,但是面积 area() 方法却由于不同图形的面积系数不同,没法解决,此时就需要利用抽象方法来解决了,即在方法体前面加 abstract 关键字,如下:
1 class Shape { // 图形 2 double c; 3 4 abstract double area(); // 抽象方法 --不完整 5 6 }
抽象方法的定义:
1、由 abstract 修饰;
2、只有方法的定义,没有方法的实现(大括号都没有);
但是抽象方法是不完整的,所以我们需要将类也变成抽象类,如下:
1 abstract class Shape { // 图形 --不完整 2 double c; 3 4 abstract double area(); // 抽象方法 --不完整 5 6 }
抽象类的定义:
1、由 abstract 修饰;
2、包含抽象方法的类必须是抽象类;
3、抽象类不能被实例化;
4、抽象类是需要被继承的,所以子类需要:
1)重写所有抽象方法 --- 常用
2)也声明未抽象类 ---不常用
在第 4 点钟抽象类是需要被继承的,如下代码:
1 abstract class Shape { // 图形 --不完整 2 double c; 3 4 abstract double area(); // 抽象方法 --不完整 5 6 } 7 8 9 class Square extends Shape { // 编译错误,因为继承了 Shape 类,Shape 类中包含 抽象方法 10 11 } 12 13 // 改进 14 abstract class Square extends Shape { // 不报错误,但是 Square 类也变成了抽象类 15 16 } 17 18 // 改进 19 class Square extends Shape { // 不报错误,将 Square 类中的抽象类重写为非抽象类 20 double area() { 21 return 0.0625 * c * c; 22 } 23 }
在上面的代码中我们实现了抽象类和抽象方法,但是貌似看上去多此一举,如下:
1 class Shape { // 图形 只提取公共变量 c 2 double c; 3 } 4 5 abstract class Shape { // 图形 --不完整 6 double c; 7 8 abstract double area(); // 抽象方法 --不完整 9 }
在上面的代码中,我们完全可以只提取公共变量 周长c 就可以了,因为 area() 方法反正是要重写的,何必多此一举呢。
接下来我们看下面的需求,就是分别以 周长 c = 1,2,3 来创建三个 Square 和 Circle 类,然后找出这 6 个图形中面积最大的一个。我们首先想到的方法应该是这样:
1 public class HelloWorld { 2 public static void main(String[] args) { 3 Square[] squares = new Square[3]; 4 squares[0] = new Square(1); 5 squares[1] = new Square(2); 6 squares[2] = new Square(3); 7 8 Circle[] circles = new Circle[3]; 9 circles[0] = new Circle(1); 10 circles[1] = new Circle(2); 11 circles[2] = new Circle(3); 12 13 /** 14 * 1、找到 squares 中最大面积 sMax 15 * 2、找到 circles 中最大面积 cMax 16 * 3、比较 sMax 与 cMax 的最大值 17 */ 18 19 } 20 } 21 22 class Shape { 23 double c; 24 } 25 26 class Square extends Shape { 27 Square(double c) { 28 this.c = c; 29 } 30 31 double area() { 32 return 0.0625 * c * c; 33 } 34 } 35 36 37 class Circle extends Shape { 38 Circle(double c) { 39 this.c = c; 40 } 41 42 double area() { 43 return 0.0796 * c * c; 44 } 45 }
在上面的代码中,我们先定义一个数组,里面存数三个周长 c = 1,2,3 的 Square,再定义一个数组,里面存放三个周长 c = 1,2,3 的 Circle,然后我们分别计算出两个数组中面积的最大值再比较出面积最大的一个,这个可以解决我们的问题,但是如果再价格六边形,就需要再定义一个数组,那么我们上面写的代码就出现了 代码重复,扩展性差,维护性差 的问题。
接下来我们用抽象类的方法来写一下:
1 public class HelloWorld { 2 public static void main(String[] args) { 3 Shape[] shapes = new Shape[6]; // 向上造型 4 shapes[0] = new Square(1); 5 shapes[1] = new Square(2); 6 shapes[2] = new Square(3); 7 shapes[3] = new Circle(1); 8 shapes[4] = new Circle(2); 9 shapes[5] = new Circle(3); 10 11 double max = shapes[0].area(); // 先假设第一个为最大值 12 for(int i=1;i<shapes.length;i++){ 13 double area = shapes[i].area(); 14 if(area > max){ 15 max = area; 16 } 17 } 18 System.out.println(max); 19 } 20 } 21 22 abstract class Shape { 23 double c; 24 abstract double area(); 25 } 26 27 class Square extends Shape { 28 Square(double c) { 29 this.c = c; 30 } 31 32 double area() { 33 return 0.0625 * c * c; 34 } 35 } 36 37 38 class Circle extends Shape { 39 Circle(double c) { 40 this.c = c; 41 } 42 43 double area() { 44 return 0.0796 * c * c; 45 } 46 }
在上面的代码中我们先定义了一个 Shape[] 数组,然后通过向上造型的方式向数组中分别添加 Square 和 Circle,这样就只在一个数组中比较最大值就可以了,当再添加五边形,六边形时只需要扩充 Shape[] 数组就可以了。
抽象类的意义:
1、为其子类提供一个公共的类型 -- 向上造型;
2、封装子类中的重复内容(成员变量和方法);
3、定义有抽象方法,子类虽然有不同的实现,但该方法的定义是一致的。
加载全部内容