zl程序教程

您现在的位置是:首页 >  后端

当前栏目

java学习笔记7--抽象类与抽象方法

2023-09-14 08:58:00 时间
1、终结类与终结方法

被final修饰符修饰的类和方法,终结类不能被继承,终结方法不能被当前类的子类重写

终结类的特点:不能有派生类

终结类存在的理由:

安全: 黑客用来搅乱系统的一个手法是建立一个类的派生类,然后用他们的类代替原来的类

设计: 你认为你的类是最好的或从概念上你的类不应该有任何派生类

终结方法的特点:不能被派生类覆盖

终结方法存在的理由:

对于一些比较重要且不希望子类进行更改的方法,可以声明为终结方法。可防止子类对父类关键方法的错误重写,增加了代码的安全性和正确性

提高运行效率。通常,当java运行环境(如java解释器)运行方法时,它将首先在当前类中查找该方法,接下来在其超类中查找,并一直沿类层次向上查找,直到找到该方法为止

final 方法举例:

class Parent

 public Parent() { } //构造方法

 final int getPI() { return Math.PI; } //终结方法

}

举个例子:

将所有图形的公共属性及方法抽象到抽象类Shape。再将2D及3D对象的特性分别抽取出来,形成两个抽象类TwoDimensionalShape及ThreeDimensionalShape

–2D图形包括Circles、Triangles、Rectangles和Squares

–3D图形包括Cube、Sphere、或Tetrahedron

–在UML中,抽象类的类名为斜体,以与具体类相区别:

 

抽象类声明的语法形式为


仅有方法头,而没有方法体和操作实现,具体实现由当前类的不同子类在它们各自的类声明中完成,抽象类可以包含抽象方法

需注意的问题:


一个抽象类的子类如果不是抽象类,则它必须为父类中的所有抽象方法书写方法体,即重写父类中的所有抽象方法


只有抽象类才能具有抽象方法,即如果一个类中含有抽象方法,则必须将这个类声明为抽象类


隐藏具体的细节信息,所有的子类使用的都是相同的方法头,其中包含了调用该方法时需要了解的全部信息


举一个绘图的例子:

各种图形都需要实现绘图方法,可在它们的抽象父类中声明一个draw抽象方法


public String getDescription() { //实现抽象类中的getDescription方法 return "a student majoring in " + major; }

通过抽象类Person扩展一个具体子类Employee:

class Employee extends Person {

 private double salary;

 private Date hireDay;

 public Employee(String n, double s, int year, int month, int day) {

 super(n);

 salary = s;

 GregorianCalendar calendar = new GregorianCalendar(year, month - 1, day);

 hireDay = calendar.getTime();

 public double getSalary() {

 return salary;

 public Date getDate() {

 return hireDay;

 public String getDescription() { //实现抽象类中的getDescription方法

 return String.format("an employee with a salary of $%.2f", salary);

 public void raiseSalary(double byPercent) {

 double raise = salary * byPercent / 100;

 salary += raise;

}

测试程序如下:

public class javatest {

 public static void main(String[] args) {

 Person[] people = new Person[2];

 people[0] = new Employee("Hary Hacker", 50000, 1989, 10, 1);

 people[1] = new Student("Maria Morris", "Computer science");

 for(Person p : people)

 System.out.println(p.getName() + ", " + p.getDescription());

}

运行结果如下:

Hary Hacker, an employee with a salary of $50000.00
Maria Morris, a student majoring in Computer science

再举一个例子:

先定义一个几何抽象类GeometricObject:

import java.util.*;

public abstract class GeometricObject {

 private String color = "write";

 private boolean filled;

 private Date dateCreated;

 //构造函数(protected类型)

 protected GeometricObject() {

 dateCreated = new Date();

 protected GeometricObject(String color, boolean filled) {

 dateCreated = new Date();

 this.filled = filled;

 this.color = color;

 public String getColor() {

 return color;

 public void setColor(String color) {

 this.color = color;

 public boolean isFilled() {

 return filled;

 public void setFilled(boolean filled) {

 this.filled = filled;

 public Date getDateCreated() {

 return dateCreated;

 public String toString() {

 return "created on" + dateCreated + "\ncolor: " + color + " and filled: " + filled;

 public abstract double getArea(); //抽象方法

 public abstract double getPerimeter(); //抽象方法

}

定义一个具体类Circle继承抽象类:

public class Circle extends GeometricObject{

 private double radius;

 public Circle() {

 public Circle(double radius) {

 this.radius = radius;

 public Circle(double radius, String color, boolean filled) {

 this.radius = radius;

 setColor(color); //继承基类

 setFilled(filled); //继承基类

 public double getRadius() {

 return radius;

 public void setRadius(double radius) {

 this.radius = radius;

 public double getArea() { //实现抽象类中的抽象方法getArea()

 return radius * radius * Math.PI;

 public double getPerimeter() { //实现抽象类中的抽象方法getPerimeter()

 return radius * 2 * Math.PI;

}

定义一个具体类Rectangle继承抽象类:

public class Rectangle extends GeometricObject {

 private double width;

 private double heigth;

 public Rectangle() {

 public Rectangle(double width, double heigth) {

 this.width = width;

 this.heigth = heigth;

 public Rectangle(double width, double heigth, String color, boolean filled) {

 this.width = width;

 this.heigth = heigth;

 setColor(color);

 setFilled(filled);

 public double getWidth() {

 return width;

 public void setWidth(double width) {

 this.width = width;

 public double getHeigth() {

 return heigth;

 public void setHeigth(double heigth) {

 this.heigth = heigth;

 public double getArea() {

 return width * heigth;

 public double getPerimeter() {

 return 2 * (width + heigth);

}
3、类的组合

面向对象编程的一个重要思想就是用软件对象来模仿现实世界的对象,现实世界中,大多数对象由更小的对象组成

与现实世界的对象一样,软件中的对象也常常是由更小的对象组成,Java的类中可以有其他类的对象作为成员,这便是类的组合

组合的语法很简单,只要把已存在类的对象放到新类中即可,可以使用“has a”语句来描述这种关系

例如,考虑Kitchen类提供烹饪和冷藏食品的功能,很自然的说“my kitchen has a cooker/refrigerator”。所以,可简单的把对象myCooker和myRefrigerator放在类Kitchen中。格式如下:

class Cooker{ // 类的语句 }

class Refrigerator{ // 类的语句}

class Kitchen{ 

 Cooker myCooker;

 Refrigerator myRefrigerator;

}

public double Length() { return Math.sqrt(Math.pow(p2.GetX()-p1.GetX(),2) + Math.pow(p2.GetY()-p1.GetY(),2)); }

组合与继承的比较:

“包含”关系用组合来表达

如果想利用新类内部一个现有类的特性,而不想使用它的接口,通常应选择组合,我们需在新类里嵌入现有类的private对象

如果想让类用户直接访问新类的组合成分,需要将成员对象的属性变为public

“属于”关系用继承来表达

取得一个现成的类,并制作它的一个特殊版本。通常,这意味着我们准备使用一个常规用途的类,并根据特定需求对其进行定制

举个例子:

car(汽车)对象是一个很好的例子,由于汽车的装配是故障分析时需要考虑的一项因素,所以有助于客户程序员理解如何使用类,而且类创建者的编程复杂程度也会大幅度降低

class Engine { //发动机类

 public void start() {}

 public void rev() {}

 public void stop() {}

class Wheel { //车轮类 

 public void inflate(int psi) {}

class Window { //车窗类

 public void rollup() {}

 public void rolldown() {}

class Door { //车门类

 public Window window = new Window();

 public void open() {}

 public void close() {}

public class Car {

 public Engine engine = new Engine();

 public Wheel[] wheel = new Wheel[4];

 public Door left = new Door(),right = new Door(); 

 public Car() {

 for(int i = 0; i i++)

 wheel[i] = new Wheel();

 public static void main(String[] args) {

 Car car = new Car();

 car.left.window.rollup();

 Car.wheel[0].inflate(72);

}

许多时候都要求将组合与继承两种技术结合起来使用,创建一个更复杂的类

举个例子(组合与继承举例):

class Plate { //声明盘子

 public Plate(int i) {

 System.out.println("Plate constructor");

class DinnerPlate extends Plate { //声明餐盘为盘子的子类

 public DinnerPlate(int i) {

 super(i);

 System.out.println("DinnerPlate constructor");

class Utensil { //声明器具

 Utensil(int i) {

 System.out.println("Utensil constructor");

class Spoon extends Utensil { //声明勺子为器具的子类

 public Spoon(int i) {

 super(i);

 System.out.println("Spoon constructor");

class Fork extends Utensil { //声明餐叉为器具的子类

 public Fork(int i) {

 super(i);

 System.out.println("Fork constructor");

class Knife extends Utensil { //声明餐刀为器具的子类

 public Knife(int i) {

 super(i);

 System.out.println("Knife constructor");

class Custom { // 声明做某事的习惯

 public Custom(int i) { System.out.println("Custom constructor");}

public class PlaceSetting extends Custom {//声明餐桌的布置 

 Spoon sp; Fork frk; Knife kn; 

 DinnerPlate pl;

 public PlaceSetting(int i) {

 super(i + 1);

 sp = new Spoon(i + 2);

 frk = new Fork(i + 3);

 kn = new Knife(i + 4);

 pl = new DinnerPlate(i + 5);

 System.out.println("PlaceSetting constructor");

 public static void main(String[] args) {

 PlaceSetting x = new PlaceSetting(9);

} 

运行结果:

Custom constructor

Utensil constructor

Spoon constructor

Utensil constructor

Fork constructor

Utensil constructor

Knife constructor

Plate constructor

DinnerPlate constructor

PlaceSetting constructor