一、抽象类(abstract)
随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一·般,更通用。类的设计应该保证父类和子类能够共享特征。有时将一个父类设计得非常抽象,以至于它没有具体的实例,这样的类叫做抽象类。
说明:子类的对象都已经很具体了,什么功能都能实现了,完全不用再创建父类的对象了,这样的父类,就成了抽象类。
1.1 abstract关键字
abstract关键字只能用来修饰类和方法。(不能修饰属性,构造器、final等)
(1)abstract 修饰类 即抽象类
abstract修饰类以后,这个类就成了抽象类,即不能实例化对象的类了。所有的事情交给他的子类去做,所以抽象类一定有子类,实例化子类的对象去完成相关开发操作
语法:
【权限修饰符】 abstract class 类名 {}
说明:虽然抽象类没法实例化了,但是还是需要提供构造器(区分接口,接口没有构造器,就是因为没子类,又没法实例化),因为抽象类的子类会通过super继承这个抽象类的属性和方法。
(2)abstract 修饰方法 抽象方法
abstract修饰方法以后,这个方法就成了抽象方法,即只有方法声明,没有方法体。抽象方法的方法体是留给后代去实现的,因此,后代必须重新该抽象方法,除非后代继续是抽象类。直到后代重写了父辈们的所有抽象类方法后,后代才可以实例化对象。换句话说,如果子类没有写完父辈的所有抽象方法,那么该子类也是抽象类(必须用abstract修饰)。
语法:【权限修饰符】 abstract 返回值类型 方法名(形参列表); //注意 没有{ },即没有方法体
说明:既然没有方法体,意味着对象或类没法调用该抽象方法,自然意味着抽象方法一定要在抽象类里面,即有抽象方法的类一定是抽象类。但是抽象类中可以没有抽象方法,抽象类只是不让这个类造对象而已。
既然必须在子类重写抽象方法,显然,抽象类不允许是私有private,要不其他类根本就看不到。
同理,抽象方法不允许是static的,因为static方法根本不能重写,类方法各是各的,不会覆盖。(因为static是类方法,每个类都可以有多个子类,子类继承父类方法的时候,先从静态开始,没法覆盖父类方法的,所以不能重写)。
语法:public abstract 返回值类型 方法名(); //注意,抽象方法没有方法体,所以没有大括号{}
(3)抽象类使用场景
比如求几何图形面积。父类就是几何图形,定义长宽高,体积,面积。但是由于不知道几何图形是啥,所以没法写他的面积公式。就可以把父类几何图形写成抽象类,让子类(具体的矩形,圆,三角形),来重写面积,周长公式。
或者比如乘坐某交通工具去美国,交通工具的燃油消耗率,行驶时间,都是根据具体交通工具而异,因此抽象交通工具,燃油消耗率,行驶时间等方法,让子类(具体的飞机,轮船),来重写这些方法。
抽象类具有多态性:即可以 抽象类 类名 = new 子类(); 然后 类名.子类方法();
扩展:匿名子类 (综合匿名对象)
所谓匿名,就是只能调用一次,就是为了省事。
匿名子类,就是一个没有名字的子类。抽象类 + 重写抽象类中的方法,就成了一个匿名子类。
语法: 抽象父类 类名 = new 抽象父类空参构造器(){ //子类什么名字不知道,这里的类名是父类类型,多态性体现
抽象父类中的抽象方法(形参列表){方法体;} //匿名子类,需要重写完抽象方法后,才可实例化出类名
}
说明:这里的父类类名用了多态,其实实例化的是子类对象,不过子类没有名字。匿名子类可以综合匿名对象一起使用,形成一个大匿名,更省事。
exp:某方法(new 抽象类(){ //main中的某方法,直接调用一个匿名子类的匿名对象
抽象方法1() //匿名子类的匿名对象需要完成抽象类的抽象方法
抽象方法2(){
})
二、接口(Interface)
一方面,有时必须从几个类中派生出一个子类,继承它们所有的属性和方法。但是, Java不支持多重继承。有了接口,就可以得到多重继承的效果。另一方面,有时必须从几个类中抽取出一些共同的行为特征,而它们之间又没有is-a(篮球运动员is a 运动员)的关系,仅仅是具有相同的行为特征而已。例如:鼠标、键盘、打印机、扫描仪、摄像头、充电器、MP3机、手机、数码相机、移动硬盘等都支持USB连接,但他们并不是is-a关系,而是has-a 关系,比如跨栏运动员和大学生都具备学习的技能,但显然学习技能不是他们的父类。飞机、风筝、热气球都可以飞等等。这种has-a关系,就可以用接口。
· 接口就是规范,定义的是一组规则,体现了现实世界中“如果你是. 则必须能.”的思想。继承是一个"是不是"的关系,而接口实现则是"能不能"的关系。接口的本质是契约,标准,规范,就像我们的法律一样。制定好后大家都要遵守。
2.1 接口的使用 interface关键字
在java中,接口和类是并列关系,(可以想象成接口是一种特别的类)
接口中,只能定义全局常量和抽象方法(JDK7以前 稳定版),静态方法、默认方法(JDK8以后)。
一个类可以实现多个接口。
接口可以继承接口,并且可以多重继承。
接口也能体现多态性。即 接口 类名 = new 实现类();
全局常量:public static final 声明的常量
抽象方法:public abstract 声明的方法
语法: interface 接口名 【extends 接口1,接口2...】{ //接口可以继承,并且是多重继承
【public static final】 数据类型 变量名 【=默认值】;//由于接口中只能是全局常量,因此public static final 可以省略
【public abstract】返回值类型 方法名();//抽象方法没有方法体,所以没有大括号
}
说明:接口中不能定义构造器,因为接口是has-a关系,没有子类,同时意味着接口不可以实例化(又没子类,又不能实例化,那自然不用构造器了)。为了实现接口的价值,java让类(非子类)去实现接口的价值(implements),这个类就是实现类。如果实现类覆盖了接口中的所有抽象方法,则此实现类就可以实例化。如果实现类没有覆盖完接口中的所有方法,则此实现类仍为抽象类。
语法:class 类名 【extends 父类 】implements 接口1【,接口2...】{ }
exp: interface Flyable{
int MAX_SPEED = 7900; //省略了【public static final】
void abstract void fly(); //抽象方法fly(),没有大括号,等实现类来重写。省略了【public abstract】
}
class Plane implements Flyable{ //实现类Plane
public void fly(){ //重写接口中的fly()方法,此时可以构造对象
System.out.println("蝴蝶飞飞");}
Java类可以实现多个接口。