一、多态
1、使用多态:可以定义一个"父类类型的引用",指向它的"子类的对象",这种形式就叫:多态
父类 fl = new 子类();
Animala1 = new Cat();
2、多态的前提和体现;
1.一定要存在"继承关系";
2.方法重写;
3、成员变量的访问特点:
1.成员变量:编译看左边(父类中一定要有,否则编译错误);运行看左边(如果子类覆盖父类的成员变量,
打印的是父类的)
2.成员方法:编译看左边(父类中一定要有,否则编译错误);运行时看右边(如果子类重写父类的成员方
法,调用的是子类的)
3.静态方法:编译看左边(父类中一定要有,否则编译错误);运行时看左边(如果子类重写父类中的静态方
法,调用的是父类的)
总而言之:当多态时,访问的成员(成员变量、成员方法)父类中必须要有,否则编译错误。
运行时,只有"被覆盖的普通成员方法"访问的是"子类的",其它都是"父类"的。
4、利用"多态"的特性。一个方法的形参可以声明为某个"父类"类型。就表示:可以接收任何的它的子类对象的引用。
5、多态的弊端:
1.当多态时,不能访问子类特有成员;
classA{
intn = 10;
}
classB extends A{
intm = 20;
}
main(){
Aa = new B();
System.out.println(a.m);//编译错误。
}
2.可以通过转型,去访问子类特有成员;
6、多态中的类型转换:
1.向上转型(隐式的,自动的):"父类"类型的变量,存储"子类对象"的引用;
Animal a = new Cat();//向上转型;
2.向下转型(显示的,强制转换):如果我们确定一个"父类"类型的变量,存储了某个具体的"子类对象"的引用。
我们可以将这个"父类类型"强制转换为它所存储的"子类类型";
Animal a = new Cat();//向上转换
Cat c = (Cat)a;//向下转换
Dog d = (Dog)a;//错误。
3.向下转型由于要使用"强制转换",这就有了隐藏的危险。如果类型不匹配,将在运行时异常:ClassCastException。
Java为我们提供了一种方式,在强制转换前,可以先进行判断,如果为true,再进行转换。
使用关键字:instanceof
它是双目运算符:左操作数 instanceof 右操作数
左操作数:一般是一个"变量名";
右操作数:是某个"类名"
整体的意思:"左操作数"是否是"右操作数"的类型:是:返回true,否则:返回:false
Animala = new Cat();
if(ainstanceof Cat){
Cat c = (Cat)a;//转换是安全的;
}
if(ainstanceof Dog){
Dogd = (Dog)a;
}
7、孔子装爹案例:
class 孔爹{
intage = 75;
voidteach(){
System.out.println("孔爹讲Java");
}
}
class 孔子extends 孔爹{
intage = 30;
voidteach(){
System.out.println("孔子讲IOS");
}
voidplayGame(){
System.out.println("打英雄联盟");
}
}
主程序:
main(){
//当前孔爹已经被人请走讲课去了。只有孔子在家。这时又来人请孔爹去讲Java,孔爹没在家,孔子一看
//来人给的价钱也很高,于是乎:孔子打算替他爹出山。于是,进入带上胡子,穿上孔爹的袍子,跟人走了。
孔爹 kd = new 孔子();
System.out.println("我今年:" + kd.age);//我今年:75
kd.teach();//IOS
kd.playGame();//编译错误
//孔子回家,卸妆
孔子 kz = (孔子)kd;
//打游戏
kz.playGame();//OK的
}
代码实现:
class 孔爹{
intage = 75;
voidteach(){
System.out.println("孔爹讲Java");
}
}
class 孔子extends 孔爹{
intage = 30;
voidteach(){
System.out.println("孔子讲IOS");
}
voidplayGame(){
System.out.println("打英雄联盟");
}
}
classDemo
{
publicstatic void main(String[] args)
{
//当前孔爹已经被人请走讲课去了。只有孔子在家。这时又来人请孔爹去讲Java,孔爹没在家,孔子一看
//来人给的价钱也很高,于是乎:孔子打算替他爹出山。于是,进入带上胡子,穿上孔爹的袍子,跟人走了。
孔爹 kd = new 孔子();
System.out.println("我今年:" + kd.age);//我今年:75
kd.teach();//IOS
// kd.playGame();//编译错误
//孔子回家,卸妆
孔子 kz = (孔子)kd;
//打游戏
kz.playGame();//OK的
}
}
二、抽象类
1.一般不会实例化"父类"的对象;因为"父类"没有对应现实世界中的实体。我们经常使用子类。
2.父类会定义某些方法,而这个方法会被每个子类重写。
classPerson{
voidshow(){
System.out.println("我是传智播客的一员");
}
}
classStudent extends Person
{
//重写
voidshow(){
System.out.println("我是传智播客的一名学生,我骄傲!!");
}
classTeacher extends Person{
//重写
voidshow(){
System.out.println(我是传智播客的一名教师,我骄傲!!");
}
3.基于上述,以及一些其它原因:
1.某些父类既然不会去实例化,那么就干脆将这个类定义为:不可实例化的;这种类就叫:抽象类
2.父类中的某些方法,都会被子类重写,那么干脆:父类只提供"方法签名",不提供"具体实现"。
这种方法就叫:抽象方法;
4.定义抽象类,使用关键字:abstract
5.可以修饰:
1.类:abstract class类名{}
说明:此类将不能被实例化;就是用来做父类的,让子类去继承的;
2.成员方法:abstarctvoid show();
说明:此方法是个"抽象方法",用来被子类"重写的"
6.说明:
1.一个"抽象类"中可以没有抽象方法;
2.如果一个类中包含了"抽象方法",那么这个类必须是"抽象类";
3.如果一个"子类"继承"抽象类",仍然使用关键字:extends。而且仍然是"单继承";
4.如果一个"子类"继承了"抽象类",那么必须重写全部的"抽象方法"。如果不重写,或不完全重写,
那么这个"子类"也必须是个"抽象类"。
从另一个角度:一个抽象类,可以继承自另一个抽象类;
7、抽象类:
1.抽象类中可以没有抽象方法;也可以什么都没有;
2.如果抽象类中包含了抽象方法,那么这个类必须要声明为抽象的;
3.抽象类中可以有什么:
1).成员变量;
2).构造方法,并且可以重载;为成员变量赋值;
3).普通,实现的成员方法:
4).抽象方法;
4.抽象类跟普通的父类的区别:
1).抽象类不能被实例化;
2).抽象类中可以包含抽象方法;
8、面试题
一.一个类如果没有抽象方法,可不可以定义为抽象类?如果可以,有什么意义?
1.可以(一个抽象类内部,可以什么都不定义);
2.只是父类使用。而且这个父类不可以实例化;
二.abstract不能和哪些关键字共存:
1.private:因为一个抽象方法就是被子类重写的。要重写就必须不能为private的。
2.final:因为一个抽象方法就是被子类重写的。而final表示:最终方法,不能被重写。所以这两个关键字冲突;
作用在"类"上也是一样:一个抽象类就是用来被继承的。而final类:表示最终类,不能被继承。所以也是冲突;
3.static:因为一个抽象方法没有方法体。所以不能定义为static的。因为无法被分配空间;
三、接口
1、如果一个抽象类中,没有成员变量,没有实现的方法,只包含了一些"抽象方法",这时,我们可以将
这个类定义为"接口":
1.定义接口,使用关键字:interface
2.接口:不能被实例化,用来被子类"实现"的;
3.子类实现接口,使用关键字:implements
4.接口中可以包含(JDK8以前):
1).成员变量:必须被声明为:publicstatic final。如果不写这几个修饰符,系统会自动添加.
2).抽象方法:必须被声明为:publicabstract。如果不写这几个修饰符,系统会自动添加。
5.接口的作用:
1).Java是"单继承"的,不能同时继承多个类。
Java的一个类实现接口时,可以同时实现多个接口;
所以,在Java中,通过"实现接口"达到"功能扩展的目的";
6、重写接口中的抽象方法时,必须要使用:public访问修饰符;
2、接口的使用:
1、接口的作用就是用来扩展功能
2、一个子类,可以同时实现一个或者多个接口
3、一个子类可同时继承一个类,并实现一个或者多个接口,但是一定要先继承,后
实现接口
4、一个子类,如果实现一个接口,那么必须从写接口中的抽象方法,否则这个子类
也得是一个抽象的
5、一个接口可以继承自另一个或者多个接口,也就意味着使用关键字extends,并且
可以多继承
例:interface A{
}
inteface B{
}
interface C extendsA,B{
}
3、类和类,类和接口,接口和接口之间的关系:
1.类和类:继承:使用关键字:extends;单继承;
2.类和接口:实现;使用关键字:implements;可以同时实现多个接口
3.接口和接口:继承:使用关键字:extends;可以多继承;
上述中说的类都包含"抽象类"
四、抽象类和接口的区别
1、成员:
抽象类:成员变量、常量、构造方法、实现的方法、抽象方法
接口:常量、抽象方法
2、关系
抽象类:子类是继承,使用关键字extends
接口:子类是实现,使用关键字:implements
类和类:是继承 使用extends
类和接口:是实现,使用implements
接口和接口:是继承,使用extends
3、设计理念
抽象类:被设计为“is a”的关系
接口:接口:被设计为"like a"的关系。