抽象类

本文深入探讨了抽象类的概念,包括其基本定义、使用限制及实际应用。通过实例展示了抽象类如何通过抽象方法强制子类实现特定行为,以及如何在模板设计模式中发挥关键作用。

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

抽象类的基本概念

如果说现在在一个类之中需要定义一个没有方法体的方法,可以用abstract关键字来进行抽象方法定义,而包含有抽象方法的类就可以使用abstract来定义成为抽象类。
类的核心组成:属性、方法,但是在学习完继承操作之后,会发现子类存在有一种覆写父类方法的机制,而且这一机制直接与对象的多态性有关。于是这样就会出现这样一个问题:假设现在使用的是普通类,并且在这个类里面有一个print()方法。
在这里插入图片描述
但是这个时候子类完全可以选择是否需要覆写方法。但是由于只是一个普通方法,所以对于子类是否覆写没有任何的要求,于是这样就会出现一个漏洞,父类无法强制有求子类覆写方法。
如果只依靠普通类的继承,那么根本就不能够对子类产生限制,所以就可以利用抽象类和抽象方法来解决而此类问题。
范例:定义抽象类
在这里插入图片描述
在这里插入图片描述
抽象方法的特点:一是使用了abstract关键字定义,另一个是方法的后面没有“{}”,表示没有方法体。
在这里插入图片描述
本处直接采用了关键字new实例化了抽象类对象,但是编译的时候就会出现如下的错误提示信息。
在这里插入图片描述
抽象类是不能够直接进行对象实例化操作的。因为一旦类的对象实例化了,就意味着可以调用类中的所有方法了,但是抽象方法只是一个声明,并没有具体的方法体,所以在实际的开发之中对于抽象类的使用规则如下:

  • 抽象类必须有子类,子类利用extends关键字来继承抽象类,一个子类只能够继承一个父类;
  • 抽象类的子类(如果不是抽象类),那么必须要覆写抽象类中的全部抽象方法;
  • 抽象类可以利用对象的向上转型机制,通过子类对象进行实例化操作。
    在这里插入图片描述
    在这里插入图片描述
    抽象类与普通类相比最大的好处是强制定义了子类的实现要求。
    本质上讲抽象类就是比普通类多了一些抽象方法的定义而已。
    在实际的设计之中,父类的设计是最重要的,明显抽象类的约束更加的严格,所以在实际的开发之中,几乎不会出现普通类定义子类的情况,大多数都是继承抽象类。

抽象类的相关说明

抽象类的使用限制:

  • 不能使用final关键字定义;
  • 抽象类就是比普通类多了抽象方法而已,普通类的所有结构抽象类都可以定义,而且子类也符合对象实例化流程,默认先调用父类中的无参构造,而后再调用子类自己的构造。
    范例:观察
abstract class A{
	public static final String INFO="Hello";
	public A(){
		this.fun();
	}
	public void fun(){
		System.out.println("*********************");
	}
	public abstract void print(); //没有方法体,使用abstact声明
}
class B extends A{
	public void print(){
		System.out.println("这个方法是强制子类要覆写的方法。");
	}
}
public class Hello{
	public static void main(String args[]){
		A a = new B();//向上转型
		a.print();//被子类所覆写过的方法
	}
}

在这里插入图片描述
范例:思考题

abstract class A{
	public A(){
		this.print();
	}
	public abstract void print(); //没有方法体,使用abstact声明
}
class B extends A{
	private int num = 50;
	public B(int num){
		this.num=num;
	}
	public void print(){
		System.out.println("num="+this.num);
	}
}
public class Hello{
	public static void main(String args[]){
		new B(100);
	}
}

在这里插入图片描述
本程序的关键解决思路,子类对象实例化前一定要先实例化父类对象,也就是此时子类对象的属性都没有内容。

abstract class A{
	public A(){//2.默认调用父类构造
		this.print();//3.调用print()方法
	}
	public abstract void print(); //没有方法体,使用abstact声明
}
class B extends A{
	private int num = 50;
	public B(int num){//1.传递内容过来,在子类对象实例化前先实例化父类对象
		this.num=num;
	}
	public void print(){//4.调用此方法执行,但是此时子类对象还未实例化,内容没有赋值
		System.out.println("num="+this.num);//5.只能够输出对应数据类型的默认值
	}
}
public class Hello{
	public static void main(String args[]){
		new B(100);
	}
}
  • 抽象类中可以没有抽象方法,但是依然不可能使用关键字new进行对象的实例化操作;
abstract class A{	
}
public class Hello{
	public static void main(String args[]){
		A a = new A();
	}
}

在这里插入图片描述
因为类A上有abstract关键字,所以此处无法进行对象的直接实例化。

  • 外部抽象类上不允许使用static抽象类声明,但是内部抽象类中可以使用static声明,这样表明的是一个外部抽象类。
    范例:定义普通的内部抽象类
abstract class A{	
	public abstract void printA();
	abstract class B{
		public abstract void printB();
	}
}
class X extends A{
	public void printA(){}
	class Y extends B{
		public void printB(){}
	}
}

范例:在内部抽象类中使用static关键字

abstract class A{	
	public abstract void printA();
	static abstract class B{
		public abstract void printB();
	}
}
class X extends A.B{
	public void printB(){}
}
  • 抽象类中可以定义static方法,而且static方法不受实例化对象的控制。
    范例:直接通过抽象类产生实例化对象
abstract class A{	//此类设计之初没有子类,但考虑到之后会需要子类的定义
	public abstract void printA();
	private static class B extends A{//在A类中直接定义实现的子类
		public void printA(){
			System.out.println("Hello World!");//Hello World!

		}
	}
	public static A getInstance(){
		return new B();
	}
}
class C extends A{
	public void printA(){
		System.out.println("************************");
	}
}
public class Hello{
	public static void main(String args[]){
		A a = A.getInstance();
		a.printA();
		A a1 = new C();//留给用户做的
		a1.printA();
	}
}

日后如果发现,在系统类库中有某个抽象类可以直接利用一个static方法取得取得实例化对象的时候不要觉得陌生。
以上出现的几种形式有一些是在后面讲解系统类库终会出现的问题,现阶段看看就好。

抽象类的实际应用——模板设计模式

抽象类与普通类到底有哪些区别?
在这里插入图片描述
在这里插入图片描述
范例:实现程序操作

abstract class Action{//定义的是行为,行为一定不是具体的
	public static final int Eat=1;
	public static final int Sleep=2;
	public static final int Work=5;
	public void command(int flag){//执行命令
		switch(flag){//数值用switch判断最好
			case Eat :{
				this.eat();
				break;
			}
			case Sleep :{
				this.sleep();
				break;
			}
			case Work :{
				this.work();
				break;
			}
		}
		
	}
	public abstract void eat();//因为这些具体的行为如何执行不知道
	public abstract void sleep();//交由子类根据自己的实际情况完成
	public abstract void work();	
}

范例:定义子类

class Robot extends Action{
	public void eat(){
		System.out.println("机器人补充能量");
	}
	public void sleep(){}
	public void work(){
		System.out.println("机器人正在工作");
	}
}
class Person extends Action{
	public void eat(){
		System.out.println("人在吃饭");
	}
	public void sleep(){
		System.out.println("人在睡觉");
	}
	public void work(){
		System.out.println("人在工作");
	}
}
class Pig extends Action{
	public void eat(){
		System.out.println("猪在啃食槽");
	}
	public void sleep(){
		System.out.println("猪在养肉肉");
	}
	public void work(){}
}

不同的子类有着自己不同的操作支持。
范例:程序测试

public class Hello{
	public static void main(String args[]){
		fun(new Pig());
		System.out.println("****************************************");
		fun(new Robot());
		System.out.println("****************************************");
		fun(new Person());
		System.out.println("****************************************");
	}
	public static void fun(Action act){//接收的是行为
		act.eat();
		act.sleep();
		act.work();
	}
}

在这里插入图片描述
现在在整个程序之中,如果某一事物需要实现特定的功能,那么就必须按照Action定义的方法进行覆写。这个时候子类必须按照父类提供的模板编写代码。

总结

抽象类的设计

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值