多态性是一种允许使用一个界面来访问一类动作的特性,特定的动作可以由不同的具体情况而定(传入不同的参数)。多态性是发送消息给某个对象,让该对象自行决定响应何种行为
通过将子类对象引用赋值给超类对象引用变量来实现动态方法调用
public class Test1{
public static void main(String[] atgs){
Fa cc=new fa();
//调用的是一个名称为pp的方法,但是参数不同执行的处理不同
cc.pp();//Fa...pp
cc.pp(12);//Fa.pp(int)
}
}
class Fa{
public void pp(){
System.out.println("Fa...pp");
}
public void pp(int k){
System.out.println("Fa.pp(int)");
}
}
多态性通过允许同一界面指定一类动作减少了程序的复杂度,编译器工作就是选择适用于各个情况的特定动作,而程序员则无须手动进行选择,使用者仅仅是记得以及利用这个统一的界面
多态形成的三个必要条件:
- 有继承,父类定义方法,子类重写方法
- 父类的引用指向子类的对象
- 可以使用参数传递时多态,也可以直接创建对象时多态
多态可以用
三个定义和两个方法
来总结。三个定义分别是父类定义子类构建、接口定义实现类构建和抽
象类定义实体类构建,而两个方法分别是方法重载和方法重写。
多态分为两种:
- 编译时多态:方法的重载
- 运行时多态:JAVA运行时系统根据调用该方法的实例的类型来决定选择调用哪个方法则被称为运行时多态
对象的多态性
继承表示的是is a的语义
public class 汽车 extends 车库{} //错误的
public class 学生 extends 人{} 正确的,因为任何一个学生都是人
强调的一个人点:编程是对现实世界的模拟体现
class 动物{}
class 猫 extends 动物{}
猫 x=new 猫();
动物 x=new 猫();//正确的,因为所有的猫都是动物,因为定义class猫extends 动物{}
猫 x=new 动物();//错误的,不是所有的动物都是猫 ,因为动物是猫的父类
一个对象
x
有两种形态,猫这类事物即具有猫的形态,又具有着动物的形态,这就是对象的多态性。简单
说就是一个对象对应着不同类型
Object x=new Student();
Person x=new Student();
Student x=new Student();
多态在代码中的体现
父类或者接口的引用指向其子类的对象。例如:动物 x=new 猫()
public class Test1{
public static void main(String[] args){
动物 x1=new 动物();
动物 x2=new 猫();//猫extends动物,表示具有动物的所有特性,同时猫具备都有的特征
//x2.plsy();语法报错的原因是:编译器了类型和运行时类型的问题
}
}
class 动物{}
class 猫 extends动物{
public void play(){
System.out.println("使劲的抓老鼠....");
}
}
public class Test1{
public static void main(String[] args){
动物 x2=new 猫();//猫extends动物,表示猫具有动物的所有特征,同时猫具备一些自己的特征
x2.play();//使劲的抓老鼠...
//这里的语法不报错的原因是动物类中定义了play方法,但是真正运行系统则会发现实际上是猫所以需要调用的不是动物类中的方法,而是猫中定义方法
}
}
class 动物{
public void play(){
System.out.println("使劲的睡觉....");
}
}
class 猫 extends 动物{
public void play(){
System.out.println("使劲的抓老鼠....")
}
}
动物 dw=new 猫();
dw.play();//如果猫类中没有定义play方法,则执行的是从动物类中继承play方法;如果猫类中也定义play方法,则最终执行的是猫类中定义的方法
//dw.抓王八()语法错误,因为在编译时系统识别dw为动物类型,所有没有这个方法的定义
if(dw instanceof 猫){
((猫)dw).抓王八();
//强制类型转换后则可以调用猫类中所定义的特使方法,否则只能调用动物类中定义的方法
}
对象多态性可以使程序有良好的扩展,并可以对所有类的对象进行通用处理
public class Test1{
public static void main(String[] args){
//需要使用动物的类
tt.new 需要使用动物的类();
tt.pp(new 动物());
tt.pp(new 猫());
}
}
class 需要使用动物的类{
public void pp(动物 dongwu){
//假设定义方法时参数使用pp(猫 dongwu)当前程序就和猫类耦合了,如果需要切换到狗则必须修改源代码,但是参数类型为动物,则不管是猫还是狗都能接收
dongwu.play();
}
}
多态引用时,构造子类对象时的构造方法的调用顺序
- 先调用超类的构造方法,多重超类首先调用最远超类的方法
- 然后再执行当前子类的构造方法
this和super的用法
this
用于指代当前对象,
super
用于指代父类的内存空间的标识
this关键字
this
代表其所在函数所属对象的引用。换言之,
this
代本类的对象的引用
- 当成员变量和局部变量重名,可以用关键字this来区分,this就是所在函数所属对象的引用
- 对象调用了this所在的函数,this就代表哪个对象。一般方法调用默认加this
- 通过this在构造函数中调用其他构造函数的时候,只能定义在构造函数的第一行,因为初始化动作要先执行,否则就会报错
super关键字
- 当本类的成员和局部变量同名用this区分,当子父类中的成员变量同名用super区分父类
- 当子父类中出现成员函数一模一样的情况,会运行子类的函数。这种现象,称为覆盖操作,这是函数在子父类中的特性。在子类覆盖方法中,继续使用被覆盖的方法可以通过super.函数名获取
- this()表示调用当前类中的另外一个构造器,()中可以带有参数;super()表示调用父类中的某个构造器,()中可以带有参数
this()和super()
this()
表示调用当前类中的另外一个构造器
,()
中可以带有参数
super()
表示调用父类中的某个构造器,
()
中可以带有参数
new 子类()的执行过程
首先上溯子类的所有祖先类,然后再从上向下逐步执行各个层次父类的构造器
Object—
爷爷的构造
器
—
父亲的构造器
;
最后才执行子类自己的构造器
因为每个类的构造方法中默认第一句话为
super()
表示调用父类的无参构造器,除非编程
super
。
特殊情况:
问题:父类已经定义了带参构造器后是否还有无参构造器?
没有,因为只有当不定义构造器时,系统才提供一个无参构造器。当自定义构造器时,系统不再提供无
参构造器
因为子类的构造器中没有显式调用父类构造器,所以子类构造器方法中第一句是
super()
表示调用父类中
的无参构造器,但是父类中没有无参构造器,所以报错
this
和
super
的三种用法:
从语义的角度上说, this 用于指代当前对象; super 用于指代父类对象1 、 this() 表示调用另外一个构造器 ,super() 表示调用父类中的某个构造器, () 中的参数决定调用的是哪个构造器2 、 this. 成员属性用于表示当前对象的某个成员,一般用于局部变量和属性名称一致的场景下。 super. 成员属性用于表示父类中定义的某个属性,一般用于子类中覆盖定义了某个父类属性的场景下。3 、 this. 成员方法 () 用于表示当前对象的某个成员方法; super. 成员方法 () 用于表示当前类的父类中定义的某个成员方法,一般用于覆盖定义时【就近原则】。4 、在 static 方法中不允许使用 this/super 之类关键字