1、终结类与终结方法

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

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

终结类存在的理由:

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

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

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

终结方法存在的理由:

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

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

final 方法举例:

class Parent
{
public Parent() { } //构造方法
final int getPI() { return Math.PI; } //终结方法
}

说明: getPI()是用final修饰符声明的终结方法,不能在子类中对该方法进行重载

2、抽象类

抽象类:代表一个抽象概念的类

  • 没有具体实例对象的类,不能使用new方法进行实例化

  • 类前需加修饰符abstract

  • 可包含常规类能够包含的任何东西,例如构造方法,非抽象方法

  • 也可包含抽象方法,这种方法只有方法的声明,而没有方法的实现

存在意义:
  • 抽象类是类层次中较高层次的概括,抽象类的作用是让其他类来继承它的抽象化的特征

  • 抽象类中可以包括被它的所有子类共享的公共行为

  • 抽象类可以包括被它的所有子类共享的公共属性

  • 在程序中不能用抽象类作为模板来创建对象;

  • 在用户生成实例时强迫用户生成更具体的实例,保证代码的安全性

举个例子:

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

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

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

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

抽象类声明的语法形式为

abstract class Number {
. . .
}

3、抽象方法

声明的语法形式为:

public abstract <returnType> <methodName>(...);

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

需注意的问题:

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

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

  • 除了抽象方法,抽象类中还可以包括非抽象方法

抽象方法的优点:

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

  • 强迫子类完成指定的行为,规定其子类需要用到的“标准”行为

举一个绘图的例子:

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

abstract class GraphicObject {
int x, y;
void moveTo(int newX, int newY) { . . . }
abstract void draw();
}

然后在每一个子类中重写draw方法,例如:

class Circle extends GraphicObject {
void draw() { . . . }
}
class Rectangle extends GraphicObject {
void draw() { . . . }
}

举一个例子:

首先定义一个抽象类:

abstract class Person {
private String name; //具体数据
public Person(String n) { //构造函数
name = n;
}
public String getName() { //具体方法
return name;
}
public abstract String getDescription(); //抽象方法
}

下面通过抽象类Person扩展一个具体子类Student:

class Student extends Person {
private String major;
public Student(String n, String m) {
super(n);
major = m;
}
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 class Point   //点类
{
private int x, y; //coordinate
public Point(int x, int y) { this.x = x; this.y = y;}
public int GetX() { return x; }
public int GetY() { return y; }
}
class Line //线段类
{
private Point p1,p2; // 两端点
Line(Point a, Point b) {
p1 = new Point(a.GetX(),a.GetY());
p2 = new Point(b.GetX(),b.GetY());
}
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 < 4; 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

参考资料:

《java程序设计》--清华大学

java学习笔记7--抽象类与抽象方法的更多相关文章

  1. Java学习笔记之抽象类与接口

    抽象类(abstract) 抽象类概述:一个类被abstract修饰表示这个类是抽象类, 自己定义方法但是不实现方法,后代去实现 抽象方法:   一个方法被abstract修饰表示这个方法是抽象方法 ...

  2. 0026 Java学习笔记-面向对象-抽象类、接口

    抽象方法与抽象类 抽象方法用abstract修饰,没有方法体部分,连花括号都不能有: 抽象方法和抽象类都用abstract修饰 包含抽象方法的类一定是抽象类:但不包含抽象方法的类也可以是抽象类 不能创 ...

  3. Java学习笔记之---比较接口与抽象类

    Java学习笔记之---比较接口与抽象类 抽象类是描述事物的本质,接口是描述事物的功能 接口与抽象类的异同 1.一个类只能继承一个父类,但是可以有多个接口 2.抽象类中的抽象方法没有方法体,但是可以有 ...

  4. 0028 Java学习笔记-面向对象-Lambda表达式

    匿名内部类与Lambda表达式示例 下面代码来源于:0027 Java学习笔记-面向对象-(非静态.静态.局部.匿名)内部类 package testpack; public class Test1{ ...

  5. 《Java学习笔记(第8版)》学习指导

    <Java学习笔记(第8版)>学习指导 目录 图书简况 学习指导 第一章 Java平台概论 第二章 从JDK到IDE 第三章 基础语法 第四章 认识对象 第五章 对象封装 第六章 继承与多 ...

  6. 【Java学习笔记之二十六】深入理解Java匿名内部类

    在[Java学习笔记之二十五]初步认知Java内部类中对匿名内部类做了一个简单的介绍,但是内部类还存在很多其他细节问题,所以就衍生出这篇博客.在这篇博客中你可以了解到匿名内部类的使用.匿名内部类要注意 ...

  7. java学习笔记16--I/O流和文件

    本文地址:http://www.cnblogs.com/archimedes/p/java-study-note16.html,转载请注明源地址. IO(Input  Output)流 IO流用来处理 ...

  8. java学习笔记9--内部类总结

    java学习笔记系列: java学习笔记8--接口总结 java学习笔记7--抽象类与抽象方法 java学习笔记6--类的继承.Object类 java学习笔记5--类的方法 java学习笔记4--对 ...

  9. java学习笔记8--接口总结

    接着前面的学习: java学习笔记7--抽象类与抽象方法 java学习笔记6--类的继承.Object类 java学习笔记5--类的方法 java学习笔记4--对象的初始化与回收 java学习笔记3- ...

随机推荐

  1. EOJ 3247 铁路修复计划

    二分,最小生成树. 二分一下$k$,然后每次算最小生成树验证即可,事实证明,$cmp$函数,参数用引用还是能提高效率的,不引用一直$TLE$,时限有点卡常. 然后错误的代码好像$AC$了啊,$L$和$ ...

  2. Java Web开发——JSP基本语法杂记

    在一个JSP页面中,可以包括指令标识.HTML代码.JavaScript代码.嵌入的Java代码.注释和JSP动作标识等内容.但是这些并不是JSP页面所必须的. 1 指令标识指令标识主要用于设定整个J ...

  3. python升级带来的yum异常:File "/usr/bin/yum", line 30

    问题: $ yum File "/usr/bin/yum", line 30 except KeyboardInterrupt, e: ^ SyntaxError: invalid ...

  4. RxSwift 系列(八)

    前言 本篇文章我们将学习RxSwift中的错误处理,包括: catchErrorJustReturn catchError retry retry(_:) catchErrorJustReturn 遇 ...

  5. Python实现简单的API接口

    get方法 代码实现   # coding:utf-8       import json   from urlparse import parse_qs   from wsgiref.simple_ ...

  6. Hibernate 单项多对一的关联映射

    在日常开发中会出现很对多对一的情况,本文介绍hibernate中多对一的关联映射. 1.设计表结构 2.创建student对象 3.创建Grade对象 4.写hbm.xml文件 5.生成数据库表 生成 ...

  7. 绘制bitmap 全屏 安卓获取 屏幕大小

    韩梦飞沙  韩亚飞  313134555@qq.com  yue31313  han_meng_fei_sha 绘制bitmap 全屏 Rectf rectF = new RectF(0, 0, w, ...

  8. [BZOJ4539][HNOI2016]树(主席树)

    4539: [Hnoi2016]树 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 746  Solved: 292[Submit][Status][D ...

  9. 【洛谷】P1156 垃圾陷阱【DP】

    P1156 垃圾陷阱 题目描述 卡门――农夫约翰极其珍视的一条Holsteins奶牛――已经落了到“垃圾井”中.“垃圾井”是农夫们扔垃圾的地方,它的深度为D(2≤D≤100)英尺. 卡门想把垃圾堆起来 ...

  10. noip200806火柴棒等式

    试题描述: 给你n根火柴棍,你可以拼出多少个形如“A+B=C”的等式?等式中的A.B.C是用火柴棍拼出的整数(若该数非零,则最高位不能是0).用火柴棍拼数字0-9的拼法如图所示: 注意: 1)加号与等 ...