Java学习笔记(疯狂Java讲义第三版)——抽象类

什么是抽象类?

个人理解:
对于一个类来说,主要有两点作用。第一点,用来创建对象,第二点用来被子类继承。
那么有一种类,这种类只希望被子类继承而不希望创建对象,那么这种类就可以定义成抽象类。
抽象类的特点就是不能被用来创建对象,只能用来被子类继承。同时需要重弄写该抽象类中定义的所有抽象方法(关于抽象方法下面会介绍)。

举例说明:对于狗,猫,老虎,狮子,它们都一个共同的特征,即都是哺乳类动物。所以,在定义狗、猫、老虎、狮子这四种动物的类的时候就可以先定义一个抽象类——哺乳类,然后通过继承这个抽象类来创建所需的子类。

我们都是知道类是对象的抽象,因为一类具有共同特征的对象归为一类。同理,多个具有共同特征的类可以抽象成抽象类,抽象类就是类的抽象。

抽象类的作用是什么?

个人感觉,抽象类规定了其子类的一些共有的成员变量和行为方法,起到了一个模板的作用。

什么是抽象方法?

对于抽象类来说,可以规定好多子类都共有的行为方法。但是对于子类来说,这些共有的行为方法的具体实现是完全不同的。例如:人类和大多数哺乳类动物都有一个共同的行为特征,就是可以行走。但是人类是直立行走而大多数哺乳类动物都是四肢行走。所以真对子类都具有的行为特征但是实现却大不相同的方法就可以定义成抽象方法,抽象方法的意思就是规定子类具有这一方法,但是关于子类是如何实现的由子类重写来实现。针对这一特点,抽象方法是不需要有方法体的,因为他只是它声明子类应该有哪些方法,但该方法具体有什么作用需要有子类进行重写了。

抽象类和抽象方法的相互配合就可以很好地发挥多态这一特性,通过父类类型的引用变量调用子类中实现的抽象方法进而产生不同的行为效果。

最后,抽象类从作用上看更像是用来定义其它类的模板

抽象类的应用——模板设计模式
定义一个速度表的通用算法:
公式:2 * PI * R * 转速
对于不同的速度表来说如果半径不同,转速不同,那么显示的速度就会不同。
所以定义一个速度表的抽象类:
public abstract class SpeedMeter
{

private double turnRate;//定义成员变量转速,用turnRate表示
public void setTrunRate(double turn){
	this.turn = turn;
}//setter方法,用来指定turnRate的数值

public SpeedMeter(){
}//因为该构造器的作用主要是被子类调用,所以是无参的即可

public abstract double getRadius();//由于不同转速表所需半径的不同,
//所以定义抽象方法,具体的数值由子类来实现

public double getSpeed(){
	return java.lang.Math.PI * 2 * getRadius() * turnRate;
	//w2 * PI * R * 转速 = 速度
}

}
public class CarSpeedMeter extends SpeedMeter
{

public double getRadius(){
	return 0.28;
}
public static void main(String[] args){
	CarSpeedMeter c = new CarSpeedMeter();
	c.setTurnRate(15);
	System.out.println(c.getSpeed());
}

}
这里的抽象方法定义的是一个无参的,由于抽象类中的抽象方法主要是用来被子类调用,而对于本例中的子类中的构造器是系统自动添加的默认构造器,二者正好匹配。个人感觉抽象父类构造器的定义要根据子类的使用来进行设计,对于本例来说如果父类的构造器定义成
public SpeedMeter(double turnRate)
{
this.turnRate = turnRate;
}
但是子类中却是无参的构造器,也就没有参数传递给父类构造器的turnRate形参,所以就会出错。
所以:对于抽象类中构造器的定义要根据子类的构造器需求就行设计。

在语法上如何实现抽象了?当一个类被abstract修饰那么这个类就是抽象类。

引用疯狂Java讲义中的代码:
定义一个用来求不同转速、不同车轮半径的
abstract class 类名
{

}
对于抽象类来说,此时可以在其内部定义抽象方法(只有抽象类中才可以定义抽象方法),同时该抽象类中定义的构造器将不能被用来创建对象只能在子类创建对象的时候被系统自动的调用来辅助子类的创建。

对于一个构造器来说,主要有两点作用,第一就是被用来创建对象。第二点就是在子类创建对象的时候,会调用父类的构造器。对于一个继承树来说,在创建子类的时候,会先调用父类的构造器,然后逐级调用父类的父类构造器一直上述到Object类的构造器。所以对于抽象类来说,虽然不能用来创建对象,但是该构造器还是要有,以便在子类创建对象的时候被子类调用。

在语法上上如何实现抽象方法?当一个方法,没有方法体且用abstract来修饰那么这个方法就是抽象方法。

abstract [访问权限修饰符] 方法返回值类型 方法名(形参列表);(注意是没有方法体的,且用来abstract关键字修饰的)

访问权限修饰符不可以是private,稍后会详细讲解。

特别注意:只有抽象类中才可以定义抽象方法,抽象方法不能有方法体。同时最最重要的一点,一个类如果继承了抽象类,那么就要重写该抽象类当中的所有抽象方法(如果有)。抽象方法只能定义在抽象类中,但是抽象类不一定会定义抽象方法,这一点不要弄混。

总结一下,抽象类和普通类进行比较可以看出,抽象类比不同类多了一个抽象方法,但是同时,抽象类的父类不能被用来创建对象,只能被子类在创建对象时调用。

对于abstract关键字的详细讲解

对于abstract和final的作用,可以得出abstract和final是完全互斥的。
首先,abstract只能用来修饰类和普通成员方法(不可以修饰类方法,稍后介绍)。被abstract修饰的方法为抽象方法,被abstract修饰的类为抽象类。
总结下:
abstract修饰类——抽象类——被子类继承才有意义。
abstract修饰普通成员方法——抽象方法——被子类重写才有意义。

final关键字可以用来修饰类、成员变量、成员方法、局部变量(包括类方法和普通成员方法)。
由于abstract只能用来修饰类和普通成员方法,不能用来修饰成员变量、局部变量和类方法。所以,只有在修饰类和普通成员方法的时候二者才有机会同时出现,所以只对比两个关键字对于类和普通成员方法的修饰。
final修饰类——类不可以被继承
fianl修饰方法——方法不可以被重写。

所以对比abstract和final关键字的作用可以得出二者不可以同时出现,为完全的互斥。

abstract不可以用来修饰类方法。即在修饰方法上static和abstract关键字不可以同时出现。因为类方法可以通过类来调用,而由于abstract方法没有方法体。所以如果abstrac方法从某种意义上来说是没办法被调用的,所以static和abstract不能在修饰方法的时候不可以同时使用。(仅限于修饰方法上,在修饰内部类的时候是可以一起使用的)
简单来说类方法不能被定义成抽象方法,抽象方法同理不能被定义成类方法。

在修饰方法上,abstract关键字和private关键字不可以同时使用。即抽象方法的访问权限不能被定义成private
因为继承抽象类的子类必须重写抽象类中所有的抽象方法。private修饰的方法是对子类完全隐藏的,换句话说子类无法访问和重写父类的private方法,由于abstract修饰的方法必须被子类重写,所以不能用用private修饰abstract方法。

总结一下
1、abstract和final完全互斥
2、抽象方法不能被定义成类方法,即不能别static修饰。类方法也不能被abstract修饰。
3、抽象方法不能被private修饰符修饰

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值