Java 抽象类 详解
文章目录
- 一、概述
- 1.1、什么是抽象类
- 1.2、定义抽象类
- 1.3、什么是抽象方法
- 1.4、定义抽象方法
- 二、特点
- 2.1、抽象类的特点
- 2.1.1、抽象类不可以实例化对象
- 2.1.2、抽象类必须要被继承
- 2.1.3、抽象类的子类
- 2.1.4、抽象类的成员
- 2.2、抽象方法的特点
- 2.2.1、只能有方法声明,不能有方法体
- 2.2.2、抽象方法只存在于抽象类当中
- 2.2.3、抽象方法必须要能够被继承
- 2.2.4、其子类必须要重写抽象方法
- 三、应用
- 四、总结
一、概述
1.1、什么是抽象类
在Java中使用最多的就是类,类用于抽象一类事物,是将现实世界的事物通过抽象的方式给描述成为一个类,该类具有这一类事物的属性和行为,通过new关键字可以实例化类,在程序世界中按照类的描述创建一个对象。而当一个类提供的信息不足以实例化一个具体的对象时,或者说当前类的行为不符合具体对象的行为时,我们是不会将当前类实例化对象的,这种类一般被定义为抽象类。举个例子:定义一个宠物类,其中定义成员属性:姓名、年龄、毛色,定义成员行为:吃饭,睡觉等,这个时候我们看宠物类,宠物宠物,是哪一种动物?有点指代不清,并且不同的宠物吃的东西不一样,宠物狗吃狗粮,宠物猫吃猫粮,也就是说宠物类提供的信息不足以描述一个具体的对象,因此我们不会实例化宠物类这个对象,而是将其设置为抽象类。
简而言之,言而简之,当一个类内部定义的成员变量成员方法不足以描述一个具体的对象时,便将该类定义为抽象类
1.2、定义抽象类
在Java中,如果被abstract关键字修饰一个类,那么当前类被称之为抽象类
访问修饰符 abstract class 类名{ }
1.3、什么是抽象方法
宠物类不是一个具体的动物,那么其内部的eat()方法就无法具体实现,具体的eat()方法只有子类具体的动物对象才可以实现。像这种无法定义具体实现内容的方法我们可以将其设置为抽象方法。
1.4、定义抽象方法
被abstract关键字修饰方法,那么当前方法被称之为抽象方法,抽象方法不需要写方法体,只有方法声明,没有具体的方法实现,没有{ }。
访问修饰符 abstract 返回类型 方法名(参数列表);
public abstract class Animal {//当前Animal类为抽象类public abstract void eat();//eat()方法为抽象方法public abstract void fly();//fly()方法为抽象方法
}
二、特点
2.1、抽象类的特点
2.1.1、抽象类不可以实例化对象
本身就是因为当前类提供的信息不足以描述一个具体的类才将当前类设置为抽象类的,而又将抽象类进行实例化对象,那么得到的结果将得不偿失,抽象类不支持实例化对象,也就是不可以通过new关键字实例化对象。
实例化Animal抽象类,编译直接爆红。
2.1.2、抽象类必须要被继承
抽象类存在的意义本身就是为了被继承,抽象类没有被继承本身抽象类又不可以实例化对象,那么定义当前抽象类来干什么?
2.1.3、抽象类的子类
抽象类的子类必须要重写抽象类当中的全部抽象方法,否则一直爆红,即抽象类当中只要是被abstract关键字修饰的方法都被强制重写。
有一种方法可以让子类不用重写父类抽象类当中的抽象方法,就是将子类也定义为抽象类,这样当前情况就是抽象类继承抽象类无需重写抽象方法,但是最终还是逃不过重写抽象方法的,该来的还是会来跑不掉的,即便子类是抽象类,那么只要是抽象类结果都是被继承,那么子类抽象类的子类还是要重写抽象方法,而且还是重写父类和父类的父类两个类的抽象方法
这也就意味着抽象类的子类可以有两种选择:
1、子类也定义为抽象类
2、子类不是抽象类
不过最终的结果还是继承普通类,即便子类是抽象类也2逃不过被继承的命运最终还是要重写全部都抽象方法
2.1.4、抽象类的成员
抽象类和普通类基本一致,普通类有的抽象类都有,抽象类当中可以定义成员变量,构造器(同样支持重载),普通成员方法,抽象方法。
唯一和普通类不同的就是:普通类不可以定义抽象方法,抽象类可以定义抽象方法。
public abstract class Animal {//当前Animal类为抽象类protected String name;protected int age;protected String color;public Animal() {}public Animal(String name, int age, String color) {this.name = name;this.age = age;this.color = color;}public void love() {System.out.println(name + "爱主人");}public abstract void eat();//eat()方法为抽象方法public abstract void fly();//fly()方法为抽象方法
}
2.2、抽象方法的特点
2.2.1、只能有方法声明,不能有方法体
当方法被abstract关键字修饰时,当前方法就是抽象方法,那么当前方法就不能够有具体的实现细节,将方法头编写完整后直接加上“;”,不可以加{ },否则系统会爆红。
当方法被关键字abstract修饰时,该方法注定了要被子类重写,因此当前方法没必要再编写具体的实现细节了,语法也不支持编写方法体。
2.2.2、抽象方法只存在于抽象类当中
抽象类当中可以不包含抽象方法,但是抽象方法必须存在于抽象类当中,这也就意味着:抽象方法不能存在普通类中。
Dog类是普通类,在Dog类当中编写抽象类,语法不支持,结果就是系统爆红
2.2.3、抽象方法必须要能够被继承
抽象类存在的意义就是被继承,抽象方法的存在就是被重写,那么抽象方法必须要满足重写的条件,这也就意味着抽象方法不能够被:static关键字,final关键字,private关键字修饰,被这三个关键字修饰的方法都不支持重写
也就是说:abstract关键字和static关键字,final关键字,private关键字不能共存,就像是this()和super()不能同时出现一样。
2.2.4、其子类必须要重写抽象方法
抽象方法存在的意义就是被重写,当子类继承抽象类,如果子类不重写抽象方法,那定义抽象方法有何意义,因此语法要求:其子类(非抽象类)必须重写父类抽象类的抽象方法,否则编译不通过。
三、应用
public abstract class Animal {//当前Animal类为抽象类protected String name;public Animal(String name) {this.name = name;}public void love() {System.out.println(name + "爱主人");}public abstract void eat();
}class Dog extends Animal {public Dog(String name) {super(name);}@Overridepublic void eat() {System.out.println(name + "吃狗粮....");}
}class Cat extends Animal {public Cat(String name) {super(name);}@Overridepublic void eat() {System.out.println(name + "吃猫粮....");}
}
四、总结
可能会有人说:普通的类也可以定义普通方法,然后其继承的子类也可以重写这些普通方法啊,那这样子抽象类有什么意义?定义成为抽象类然后子类一定要重写抽象方法和子类重写普通父类的普通方法有什么区别吗?这不是脱裤子放屁多此一举吗?
事实上使用抽象类相当于多了一层编译器的校验,在很多时候,实际的工作不应该由父类来完成,而应该由子类来完成,父类本身的作用就是实现共性的抽取,实现代码的复用,而且大多数情况下父类所提供的信息都是不足以描述一个具体的对象的。那么此时我们一不小心误用了父类,使用普通方法是不会报错的,但是使用抽象类,当父类实例化的时候会提示错误,让我们尽早的发现并解决问题。这也就意味着抽象类本质上是一种预防出错的机制。
很多语法存在的意义都是为了“预防出错” ,例如我们曾经使用fianl关键字,当我们定义变量后,不再对该变量进行更改时,该变量不就相当于是常量吗?但我们使用final关键字时就多了一层预防机制,当我们不小心对该变量进行了修改,编译器就会及时的提醒我们,让我们及时修改错误,避免出现不必要的麻烦。