学习笔记参考来源
java学习路线...推荐链接:java-接口与继承-抽象类 学习笔记难免出错 望多指正!!!
什么叫做抽象类呢?
如果一个类中声明了一个方法,但这个方法没有实现体,也就说这是一个空方法,而这样的方法就叫做抽象方法,它必须使用“abstract”修饰符! 当一个类含有抽象方法的时候,这个类必须被“abstract”修饰符声明为抽象类!
抽象类是比普通类更具有通用性的,什么意思呢? 在java所有类中,Object是通用性最广泛的一个类,人们将它作为派生其他类的基类,而不是作为特定的实例类。
例子: 为英雄类Hero增加一个抽象方法attack,并且把Hero声明为abstract。 有:法术英雄类APHero,物理英雄类ADHero,可物可法英雄类ADAPHero三个类; 都是Hero的子类,继承了Hero的属性和方法。不过这三个类的attack方法肯定是不一样的,实现如下:
Hero.java
/*
Hero类是三个类的父类
*/
//包省略
public abstract class Hero{//因为Hero类含有抽象方法,所以必须加上abstract为抽象类
String name;
float hp;
float armor;
int moveSpeed;
public static void main(String[] args) {
}
// 抽象方法attack
// Hero的子类会被要求实现attack方法
public abstract void attack();
//空方法体
}
ADHero.java
/*
物理英雄类
*/
public class ADHero extends Hero{
public void physicAttack() {
System.out.println("进行物理");
}
@Override
public void attack() {
physicAttack();
}
}
APHero.java
/*
法术英雄类
*/
public class APHero extends Hero{
@Override
public void magicAttack() {
System.out.println("进行魔法");
}
@Override
public void attack() {
magicAttack();
}
}
ADAPHero.java
/*
可物可法英雄类
*/
public class ADAPHero extends Hero{
@Override
public void attack() {
System.out.println("既可以进行物理,也可以进行魔法");
}
public void magicAttack() {
System.out.println("进行魔法");
}
public void physicAttack() {
System.out.println("进行物理");
}
}
在这里,不要将重写和实现抽象方法相混淆,实现父类的抽象方法的步骤:
- 继承父类
- 重写(override)父类的抽象方法
子类重写父类抽象方法是实现父类抽象方法的最后一步,即在这里重写的目的是实现父类的抽象方法。
那么问题来了,继承了抽象类的子类需要把抽象类中的方法(包括抽象方法和普通方法)重写一遍吗? 我查了查资料,可以了解一下: 答案是(不一定)
- 普通类继承,并非一定要重写父类方法。
- 抽象类继承,如果子类也是一个抽象类,并不要求一定重写父类方法。如果子类不是抽象类,则要求子类一定要实现父类中的抽象方法。
- 接口类继承。如果是一个子接口,可以扩展父接口的方法;如果是一个子抽象类,可以部分或全部实现父接口的方法;如果子类不是抽象类,则要求子类一定要实现父接口中定义的所有方法。
抽象类与抽象方法
前面已经提到了,抽象类有抽象方法,也有普通方法。
那么类可不可以只有抽象方法或者只有普通方法呢?答案是可以的。 仅有抽象方法的类肯定是抽象类。 而仅有普通方法的类也可以声明为抽象类!(注意是也可以!意思是你可以把这个类声明为抽象类,也可以不声明为抽象类) 也就是说一个类可以在不提供抽象方法的前提下,声明为抽象类。
那么问题来了,既然一个类中没有抽象方法,那么为什么还要把这个类声明为抽象类呢?
因为一旦一个类被声明为抽象类,那么这个类就不能够被直接实例化!
/*
没有抽象方法的一个抽象类
*/
public abstract class Hero {
String name;
float hp;
float armor;
int moveSpeed;
public static void main(String[] args) {
//虽然没有抽象方法,但是一旦被声明为了抽象类,就不能够直接被实例化
Hero h= new Hero();//报错(具体如下图所示)
}
}
比如我有一个类,它没有抽象方法,但是呢,我不想它可以直接实例化,这个时候就可以将这个类声明为抽象类。 ![普通类实例化不会报错](https://img-blog.csdnimg.cn/20200614175839646.png#pic_left =300x100) ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200614180219684.png#pic_left =300x100)
抽象类与接口的区别
区别1: 子类只能继承一个抽象类,不能继承多个 子类可以实现多个接口 区别2: 抽象类可以定义 public,protected,package,private 静态和非静态属性 final和非final属性 但是接口中声明的属性,只能是 public 静态 final的 即便在这个接口中没有显式的声明
public interface AP {
public static final int resistPhysic = 100;//物抗
//resistMagic即便没有显式的声明为 public static final
//但依然默认为public static final
int resistMagic = 0;//法抗
public void magicAttack();//法术
}
注:默认方法
抽象类的实体方法就是普通方法。而接口中的实体方法,叫做默认方法
默认方法是JDK8新特性,指的是接口也可以提供具体方法了,而不像以前,只能提供抽象方法 Mortal 这个接口,增加了一个默认方法 revive,这个方法有实现体,并且被声明为了default
public interface Mortal {
public void die();//英雄死亡
default public void revive() {
System.out.println("本英雄复活了");
}
}
为什么会有默认方法?
假设没有默认方法这种机制,那么如果要为Mortal增加一个新的方法revive,那么所有实现了Mortal接口的类,都需要做改动。 但是引入了默认方法后,原来的类,不需要做任何改动,并且还能得到这个默认方法 通过这种手段,就能够很好的扩展新的类,并且做到不影响原来的类