本人在这篇博文中要讲解的知识点,和本人之前的一篇博文有所关联。因为,“抽象类” 是按照 “自下而上” 的顺序来编写所需的类,而在本人之前的博文《详解 继承(上)—— 工具的抽象与分层》中讲到的 继承 则与之相反,按照 “自上而下” 的顺序来编写所需类,那么,话不多说,现在本人就开始讲解这篇博文的主题
抽象类的基本概念:
首先,本人来介绍下什么是抽象类:
定义:
在Java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类
那么,抽象类具有如下特点:
特点:
- 抽象类 和 抽象方法 必须用abstract关键字修饰:
抽象类格式: abstract class 类名 {}
抽象方法格式: public abstract void eat();- 抽象类 不一定有抽象方法,有抽象方法的类 一定是抽象类
- 抽象类中可以有构造方法,抽象类不能进行实例化:
问:那么要构造方法有什么作用呢?
答曰:用于子类访问父类数据时的初始化- 抽象类不能直接实例化
问:那么,抽象类如何实例化呢?
答曰:按照多态的方式,由具体的子类实例化。其实这也是多态的一种,抽象类多态。- 抽象类的子类 :
要么是抽象类
要么重写抽象类中的所有抽象方法
本人来通过两个例子,来展示这个知识点的应用:
一、图形类:
假设现在要求编写几个类可以分别根据图形的属性求出图形的 周长 及 面积。
那么,若我们将几个图形的共性拿出来,做一个基类,之后我们再根据基类派生出各图形的方法。
首先,我们来编写 基本图形类(BaseShape类):
BaseShape.java:
package com.mec.about_abstruct; public abstract class BaseShape { //只要含抽象方法,就是抽象类,就要加上“abstract”修饰符 protected String name; protected String type; protected BaseShape() { } protected BaseShape(String name) { this.name = name; } //这两行代码,就是“抽象方法”,不在本类中实现,是专门用来给子类实现的 public abstract double area(); public abstract double rounder(); public String getName() { return name; } public void setName(String name) { this.name = name; } public String getType() { return type; } public void setType(String type) { this.type = type; } @Override public String toString() { return name + "的" + type; } }
现在本人来通过这个类编写一个 确定图形类 ——“Circle类”:
Circle.java:
package com.mec.about_abstruct; public class Circle extends BaseShape { private double radius; public Circle() { } public Circle(String name) { super(name); this.type = "圆"; } public Circle(String name, double radius) { this(name); this.radius = radius; } @Override public double area() { return Math.PI * radius * radius; } @Override public double rounder() { return 2 * Math.PI * radius; } }
现在同学们可能就对抽象类有了进一步了解:
抽象类:将类似的东西的共同部分(toString() 及 name 和 type)实现,将不同的、但必须要完成的(area()、rounder() 及 各图形特有尺度)表现出来,但不实现。
现在本人来对 Test类 进行一些改动:
Test类:
package com.mec.about_abstruct.test; import com.mec.about_abstruct.BaseShape; import com.mec.about_abstruct.Circle; public class Test { public static void main(String[] args) { circleOne = new Circle("地球", 6371000.0); System.out.println(circleOne.toString() + "周长= " + circleOne.rounder()); System.out.println(circleOne.toString() + "面积= " + circleOne.area()); } }
我们现在来看看运行结果:
现在,本人来总结下抽象类的注意点:
注意点:
- 只要含抽象方法,就是抽象类,就要加上“abstract”修饰符;
- 抽象类不能存在对象,因为它存在未实现的方法;
- 抽象类中不能存在private类成员及方法,所有抽象方法不能用static修饰;
- 抽象类派生的所有非抽象类,那么,
派生出来的非抽象类必须实现这个抽象类中的所有抽象方法;
若未实现,则子类也为抽象类,必须加上“abstract”修饰符;
我们能够发现,无论是 “继承” 还是 “抽象类” ,都是为了 “代码复用”。而本人在本专栏第一篇博文中就讲过,Java最主要的特点就是“面向对象”,也就是“面向工具”,我们现在来实现下一个有趣的问题——计算房价:
我们只需改动一下上面的代码:
BaseShape.java:
package com.mec.about_abstruct.shape; public abstract class BaseShape { //只要含抽象方法,就是抽象类,就要加上“abstract”修饰符 protected String name; protected String type; //据了解:深圳近3年房价一平最低100 protected double price = 100; protected BaseShape() { } protected BaseShape(String name) { this.name = name; } public double getPrice() { //所有的抽象方法,都可以在本类中被非静态方法调用 return price * area(); } //这两行代码,就是“抽象方法”,不在本类中实现,是专门用来给子类实现的 public abstract double area(); public abstract double rounder(); public String getName() { return name; } public void setName(String name) { this.name = name; } public String getType() { return type; } public void setType(String type) { this.type = type; } @Override public String toString() { return name; } }
因为一般租的房子是投影式长方形的,所以本人现在来编写一个 长方形类:
Rectangle.java:
package com.mec.about_abstruct.shape; public class Rectangle extends BaseShape { private double width; private double height; public Rectangle() { } public Rectangle(String name) { super(name); this.type = "长方形"; } public Rectangle(String name,double width, double height) { this(name); this.height = height; this.width = width; } public double getWidth() { return width; } public void setWidth(double width) { this.width = width; } public double getHeight() { return height; } public void setHeight(double height) { this.height = height; } @Override public double area() { return width * height; } @Override public double rounder() { return 2 * (width + height); } }
Test.java:
package com.mec.about_abstruct.test; import com.mec.about_abstruct.shape.BaseShape; import com.mec.about_abstruct.shape.Rectangle; public class Test { public static void main(String[] args) { BaseShape rectangleOne = new Rectangle("深圳一间小房间", 6, 6); System.out.println(rectangleOne.toString() + "周长= " + rectangleOne.rounder()); System.out.println(rectangleOne.toString() + "面积= " + rectangleOne.area()); System.out.println(rectangleOne.toString() + "房价/月 约= " + rectangleOne.getPrice( )); } }
二、货币类:
因为本人在上文中已经将“抽象类”的基本知识点都已讲解完毕,那么,在这个例子中,本人就不会再做过多解释,以展示使用方法为目的,为同学们加深这个知识点的印象。
Currency类(抽象类):
package com.mec.about_abstruct.currency; public abstract class Currency { protected String goodsName; protected double weight; //以下是人民币分别对应其他货币的汇率 public static double RMB = 1.0; public static double DOLLAR = 0.1459; public static double EURO = 0.1250; public static double POUND = 0.1110; public static double YEN = 16.3797; public static double WON = 163.8141; public Currency(String goodsName, double weight) { this.goodsName = goodsName; this.weight = weight; } public double getWeight() { return weight; } public abstract double price(); public void setWeight(double weight) { this.weight = weight; } public double value(double currencyType) { return price() * currencyType; } //这个方法调用了抽象方法,并将其返回值作为货币转换的基础数据 public String getValueString(double currencyType) { return weight + "克" + goodsName + "价格为:" + value(currencyType) + currencyName(currencyType); } public String currencyName(double currencyType) { if(Math.abs(currencyType - DOLLAR) < 1e-6) { return "美元"; } if(Math.abs(currencyType - EURO) < 1e-6) { return "欧元"; } if(Math.abs(currencyType - YEN) < 1e-6) { return "日元"; } if(Math.abs(currencyType - WON) < 1e-6) { return "韩元"; } if(Math.abs(currencyType - POUND) < 1e-6) { return "英镑"; } return "人民币"; } }
Silver 类:
package com.mec.about_abstruct.currency; public class Silver extends Currency{ public Silver(double weight) { super("白银", weight); } @Override public double price() { return 3.12 * weight; } }
Gold 类:
package com.mec.about_abstruct.currency; public class Gold extends Currency { public Gold(double weight) { super("黄金", weight); } @Override public double price() { return 264.5 * weight; } }
测试类(Demo 类):
package com.mec.about_abstruct.currency; public class Demo { public static void main(String[] args) { Gold gold = new Gold(1.47); System.out.println(gold.getValueString(Currency.RMB)); System.out.println(gold.getValueString(Currency.DOLLAR)); System.out.println(gold.getValueString(Currency.POUND)); System.out.println("下面演示白银兑换率:"); Silver silver = new Silver(132.0); System.out.println(silver.getValueString(Currency.EURO)); System.out.println(silver.getValueString(Currency.WON)); System.out.println(silver.getValueString(Currency.YEN)); } }
下面本人来展示下运行结果:
由以上代码运行结果的展示,我们大致能够看出:
抽象类的成员具有如下特点:
抽象类的成员特点:
- 成员变量:
既可以是变量,也可以是常量。- 构造方法:
必须有,因为 要用于子类访问父类数据的初始化。- 成员方法:
既可以是抽象的,也可以是非抽象的。
抽象类的成员方法具有如下特性:
抽象类的成员方法特性:
- 抽象方法
强制要求子类做的事情- 非抽象方法
子类继承的事情,提高代码复用性
抽象类和继承的逻辑顺序是相反的。
并且,抽象类 与 本人下一篇博文—— 《内部类 与 匿名内部类》 还有很深的关系,能够看出,这个知识点还是蛮重要的,所以,希望同学们能够加以重视。
来源:https://www.cnblogs.com/codderYouzg/p/12418343.html