修饰位置
①类——>抽象类
②方法——>抽象方法
①抽象类
理解 & 用途
abstract
is a class that is incomplete, or to be considered incomplete。
与final完全相反的一个类
最大程度的抽象——将子类共性最大限度的抽取出来放在抽象父类中。提高程序的简洁性
格式
abstract class Identifier Statement
(主类显式写public,不写的话应该是默认default访问权限)
概念
抽象父类,抽象子类,抽象完全实现类,抽象方法
强调:incomplete,不完整的,或 be considered incomplete
注:抽象类中,可有抽象方法及非抽象方法(静态、初始化设定式等)以及内部类
实例
Human(顶级)抽象父类,YellowHuman抽象子类,Chinese抽象完全实现类
抽象子类YellowHuman虽然实现了一个抽象父类Human的eat抽象方法,但不完整;
YellowHuman==》be considered incomplete
抽象完全实现类Chinese只实现了say、sleep、zhongdi,但Chinese继承了抽象子类YellowHuman的eat方法的实现。所以Chinese是可以视为是"complete"
特性
1.被abstract修饰类只能被继承,不能生成实例;虽然不能new实例,但可在代码中声明为编译时类型( 类似接口 IService service = new ServiceImp1(); )
2.abstract只能被继承的特性——导致了不可能与final修饰符同时出现。要么是抽象类,要么是最终实现类
3.如果继承abstract父类,只有两种选择——成为抽象子类(仍是抽象类),或者成为抽象完全实现类
4.抽象完全实现类是可以被实例化new的,并且需要注意抽象类及其子类以及完全实现类都是有构造函数的。并且都可以定义内部类的,都可以 implements 接口。
5.抽象子类B,可实现抽象父类A的抽象方法,也可不实现。抽象子类B也可定义自己的抽象方法。但抽象完全实现类,必须实现继承线上所有抽象父类们的抽象方法,当然也可全部复写(包括被抽象B实现的抽象A的抽象方法)非抽象方法可以被称为concrete method,具体方法。
6.抽象完全实现类还可以被它自己的抽象子类继承,但不需要强制实现任何方法,因为都已被父类实现完全。虽然不知道意义何在……
7.关于抽象类的构造函数运行问题【虽然不能实例化,但也有构造器,可用于继承】
注:只有匿名内部类没有构造器
结论:默认执行父类的无参构造器
只有在子类的构造函数中显示指定super(args)父类有参构造器,才执行父类的有参构造。
//顶级抽象父类 rank 1
abstract class Human {
//1无参构造
public Human(){
System.out.println("Human");
}
//1有参构造
public Human(String name){
System.out.println(name + " is Human");
}
}
//次级抽象子类 rank 2
abstract class YellowHuman extends Human{
//2无参构造
public YellowHuman(){
//this("Tom")
System.out.println("YellowHuman");
}
//2有参构造
public YellowHuman(String name){
//super(name);
System.out.println(name + " is YellowHuman");
}
}
//抽象完全实现子类 rank 3
public class Chinese extends YellowHuman{
//3无参构造
public Chinese(){
//this("Tom")
System.out.println("Chinese");
}
//3有参构造
public Chinese(String name){
//super(name);
System.out.println(name + " is Chinese");
}
}
//main.java
public static void main(String[] args) {
Chinese chinese = new Chinese();
Chinese chinese2 = new Chinese("LiuXiang");
}
//console
Human
YellowHuman
Chinese
Human
YellowHuman
LiuXiang is Chinese
8.关于抽象类中的this调用
对于抽象类中的非statci(静态)和非abstract(抽象)方法中(静态方法中不能有关键字this之前已经讨论过可以参考 关于静态static那些事)的this代表的是它的继承类,而非抽象类本身,这个好理解,因为抽象类本身不能被实例化。如果有多个继承类,谁调用,this就代表谁。—— Amaranth007
②抽象方法
格式
abstract 返回值类型 函数签名 throws子句;
(对外部方法显式写public,不写的话应该是默认default访问权限)
特性 & 实例
1.抽象类A的每个非抽象子类都必须为A的抽象函数m提供实现(继承提供也可以)
2.抽象子类可以通过自己提供抽象方法声明来覆盖父类的抽象方法声明(设计者的原意是,可以通过abstract类的抽象函数来override接口的抽象函数,详见4.1),接口函数也是可被abstract修饰,但不能与函数修饰符default及static同时使用。
3.抽象方法只能在抽象类中出现,以及唯一例外出现在 an enum declaration 枚举声明中
enum Coin{
MALE{
public void hello(){
System.out.println("MALE");
}
},
FEMALE{
public void hello(){
System.out.println("FEMALE");
}
};
abstract void hello();
}
//Enum与abstract博文:https://www.cnblogs.com/xiangguoguo/p/9061678.html
4.Overriding规则
4.1.Abstract/Abstract Overriding
抽象函数可以Override implements 接口的方法
class BufferEmpty extends Exception {
BufferEmpty() { super(); }
BufferEmpty(String s) { super(s); }
}
class BufferError extends Exception {
BufferError() { super(); }
BufferError(String s) { super(s); }
}
interface Buffer {
char get() throws BufferEmpty, BufferError;
}
abstract class InfiniteBuffer implements Buffer {
//Buffer(interface).get() is implemented in InfiniteBuffer
public abstract char get() throws BufferError;
}
4.2.Abstract/Non-Abstract Overriding
abstract class Point {
int x, y;
public abstract String toString();
protected String objString() { return super.toString(); }
}
class ColoredPoint extends Point {
int color;
public String toString() {
return objString() + ": color " + color; // correct
}
}
5.抽象函数访问权限修改
1.父类访问权限 缺省 packagelocal(default)
package com.inbreeze.inner;
//顶级抽象父类 rank 1
abstract class Human {
abstract void hs1();
void humandefault(){}
}
//次级抽象子类 rank 2
abstract class YellowHuman extends Human{
abstract void yhs();
}
public class Chinese extends YellowHuman{
@Override
void hs1() {
//super.yhs();
//错误,不能直接访问 cannot be accessd directly
}
@Override
void yhs() {
}
}
/**********************Test***********************/
package com.inbreeze.outter;
import com.inbreeze.inner.Chinese;
public class Test {
public static void main(String[] args) {
Chinese chinese = new Chinese();
//chinese.hs1();
//错误,无此方法。
}
}
结论1:父类抽象函数缺省访问权限为packagelocal。但若子类可显式指定protected/public
2.父类访问权限显式写明
abstract class Human {
abstract public void sleep();
protected abstract void eat();
}
结论2:父类抽象函数只能显式写public、protected,与abstract顺序无所谓
3.子类override父类方法,并修改访问权限
public class Chinese extends YellowHuman{
/**3.1 父类显式public改写为子类protected
@Override
protected void sleep() {
}
*/
结论3.1:失败,因为Human显式定义为public,不能减小访问权限
/**3.2 父类显式protected改写为子类public**/
@Override
public void eat() {
super.eat();
}
结论3.2:成功,子类可以扩大访问权限
/**3.2 父类缺省改写为子类public/protected**/
@Override
public /* protected */ void eat() {
super.eat();
}
结论3.3:成功,子类可以扩大访问权限
}