16、Java基础---抽象类

本文详细介绍了Java中的抽象类和抽象方法,包括抽象类的特性、抽象方法的定义、如何创建和使用抽象类的实例,以及抽象类在多态中的作用。通过示例展示了抽象类如何作为图形类Shape的基类,派生出点和长方形类,强调了抽象类在代码组织和设计中的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

抽象类

一、抽象类

首先考虑“点” 和“长方形”这两个图形,这两个类中都有用于绘图的方法draw;下面来设计这两个类。

点类Point
这是表示点的类,不持有字段。方法draw的实现如下,只显示一个符号字符'+' 

void draw() {
	System.out.println ('+');
}

长方形类Rectangle
这是表示长方形的类,持有表示长和宽的int型字段width和height,方法draw的实现和显示如下:

void draw() [
    for (int i = 1; i <= height; i++){
        for (int j = 1; j <= width; j++)
            System.out.print('*');
        System.out.println ();
   }
}

即使在单独定义的类中创建了方法draw, 它们也是毫无关系的,从“图形” 类派生出“点” 和“长方形” 

图形类Shape
这是表示图形的类,点、长方形和直线等类都直接或间接派生自该类。

思考1:方法draw应该执行什么操作呢?
应该显示什么呢?找不出合适的内容
思考2:该怎样来创建实例呢?
虽然还未设计各个类的构造函数,但应该如下面这样执行调用来创建实例
类Point···new Point() ---无参数
类Rectangle···new Rectangle(4, 3)---传入长和宽

类Shape的实例无法按照这样的形式进行创建。看不出应该传递什么样的参数

类Shape与其说是图形的设计图, 倒不如说是表示图形这一概念的抽象设计图。
像Shape这样表示具有下述性质的类的就是抽象类:
1)无法创建或者不应该创建实例;
2)无法定义方法的主体,其内容应该在子类中具体实现

如果将类Shape定义为抽象类. 则如下所示:

abstract class Shape{
    abstract void draw();
}

类Shape和方法draw的声明中都加上了abstract关键字,从该类派生的类Point和类Rectangle都不是抽象类,而是普通(非抽象)的类。

这三个类的类层次图如图,抽象类的名称用斜体表示:

将类Shape设计为抽象类,并从中派生类Point和类Rectangle,程序如下:

// 图形类群
//===== 图形 =====//
abstract class Shape {
	abstract void draw();			// 绘图(抽象方法)
}
//===== 点 =====//
class Point extends Shape {
	Point() { }						// 构造函数
	void draw() {					// 绘图
		System.out.println('+'); 
	}
}
//===== 长方形 =====//
class Rectangle extends Shape {
	private int width;		// 长
	private int height;		// 宽
	Rectangle(int width, int height) {	// 构造函数
		this.width = width;
		this.height = height;
	}
	void draw() {						// 绘图
		for (int i = 1; i <= height; i++) {
			for (int j = 1; j <= width; j++)
				System.out.print('*'); 
			System.out.println(); 
		}
	}
}

二、抽象方法

类Shape中的方法draw的开头加上了abstract。像这样声明的方法就是抽象方法,方法的前面加上的abstract蕴含了如下含义:

在这里(我的类中)不可以定义方法的主体,请在我派生的类中定义!

由于抽象方法中不存在主体、因此在其声明中,将{}替换为 ";"即使方法的主体为空,也不可以写为程序块{}

abstract void draw() { }	//错误【无法定义】

类Point和类Rectangle中重写了方法draw, 并定义了主体,像这样在从抽象类派生的类中,重写抽象方法、定义主体的操作称为实现方法【重写超类中的抽象方法,声明方法主体的定义的操作称为实现方法】(类Point和类Rectangle中就实现了抽象类Shape中的方法draw)

像类Shape这样,只要包含1个抽象方法,该类就必须声明为抽象类,为了将类声明为抽象类,需要在class的前面加上absract,不过,不包含抽象方法的类也可以声明为抽象类【对于抽象类,不可以指定final、Static、private】

// 图形类群的使用示例
class ShapeTester {
	public static void main(String[] args) {
// 	下述声明错误:抽象类无法实例化
//		Shape s = new Shape();
		Shape[] a = new Shape[2];
		a[0] = new Point();			// 点
		a[1] = new Rectangle(4, 3);	// 长方形
		for (Shape s : a) {
			s.draw();		// 绘图
			System.out.println();
		}
	}
}

输出:

无法创建抽象类的实例

上述代码中s的声明发生错误(注释掉了),由于抽象类中的方法未具体定义,因此无法使用new Shape()来创建实例

抽象类和多态
a是Shape类型的数组。其元素a[0]和a[1]为Shape类型的类类型变量,引用了派生自Shape的类的实例;

如图,a[0]引用的是类Point类型的实例,a[l]引用的是类Rectangle类型的实例,通过扩展for语句对数组a中的元素调用方法draw,对第1个元索调用类Point的方法draw,对第2个元素调用类Rectangle的方法draw,这从运行结果中也可以得到确认

抽象类Shape并不是具体的图形,而是表示图形概念的类,抽象类虽然是无法创建主体的不完整的类,但可以让包含自身在内的派生类具有“血缘关系”【如果用于对下位类进行分组,充分利用多态的类中没有具体的主体,则可以将其定义为抽象类】

如果从抽象类派生的子类中未实现抽象方法,则抽象方法会被直接继承,如图:

抽象类A中的两个方法 a 和 b 都是抽象方法,从类A派生的、未实现方法b的类B也是抽象类。
如果类B的声明中省略abstract,就会发生编译错误;从类B派生的类C中囚为实现了方法b, 所以它就不再是抽象类

三、总结

1、声明中加上abstract的方法是抽象方法,抽象方法没有方法主体;
2、只要包含一个抽象方法,类就必须定义为抽象类,抽象类的声明中需要加上abstract;
3、无法创建抽象类的实例;
4、抽象类的类类型变量可以引用该类的下位类实例,因此可以灵活应用多态;
5、抽象类可以对它派生的下位类群进行分组,让它们具有“血缘关系”;
6、重写超类中的抽象方法,定义方法主体的操作称为实现方法;
7、方法中可以调用同一个类中的、没有主体的抽象方法。要调用的方法会在程序运行时通过动态联编来确定(调用与实例的类型相对应的方法)
8、超类中的非抽象方法可以在子类中被重写为抽象方法;
9、通过将Object类的非抽象方法public String toString ()重写为抽象方法,可以强制该类的下位类实现toString方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值