多态
多态
概念
同一操作作用于不同的对象,产生不同的执行结果
就像一个人对待朋友、家人、爱人的状态是不一样的
在java中,就是把类中又相似功能的不能方法使用同一个方法名实现,从而可以使用相同的方式来调用这些具有不同的佛南功能的同名方法。
方法名字没有改变,给p从Parent new成 Child了然后方法就随之改变了
package test1;
//祖父登场!
class Grandparent{
public void say(){
System.out.println("Grandparent");
}
}
//父亲继承祖父
class Parent extends Grandparent{
public void say(){
System.out.println("Parent");
}
}
//儿子继承父亲
class Child extends Parent{
public void say(){
System.out.println("Child");
}
}
public class Class1 {
public static void main(String[] args){
//定义Grandparent p
Grandparent p = null;
//引用成Parent对象
p = new Parent(); //父亲上身,实际上已经是Parent了
p.say();
//引用成Child对象
p= new Child(); //小子上身,实际上已经是Child了
p.say();
//使用Parent类型变量引用CHild对象
Grandparent p2 = new Child(); //实际上是Child
p2.say();
}}
Parent
Child
Child
这个过程中,只使用say( ),却产生了多种结果。
引用变量的两种类型
声明类型、实际类型
声明类型:变量声明时的类型
实际类型:被引用出来的类型,是new出来的
动态绑定
方法可以在沿着继承链的多个类别中实现,当调用实例方法的时候,由虚拟机动态决定所需要调用的方法——动态绑定
动态绑定机制的原理:
当绑定实例方法的时候,虚拟机从这个变量的实际类型开始,沿着继承。沿着继承链向上查找到该方法的实现,知道找到为止,并且调用第一次找到的实现。
如下
package test1;
//祖父登场!
class Grandparent{
public void say(){
System.out.println("Grandparent");
}
}
//父亲继承祖父
class Parent extends Grandparent{
public void say(){
System.out.println("Parent");
}
}
//儿子继承父亲
class Child extends Parent{
public void say(){
//这里不作定义
}
}
public class Class1 {
public static void main(String[] args){
//定义Grandparent类型的引用变量
Grandparent p = new Child();//实际上已经是Child了
p.say();
}}
按书上来说应该是
Parent
但是我的是:
如你所见:空
貌似这里的Child里面没有定义say,就是空了
对象的类型转换
对象的类型转换是指 可以将一个对象的类型转换成继承结构中的另一种的类型
有两种
向上转型——子到父——隐式转换
向下转型——父到子——显示转换
package test1;
//祖父登场!
class Grandparent{
public void say(){
System.out.println("Grandparent");
}
}
//父亲继承祖父
class Parent extends Grandparent{
public void say(){
System.out.println("Parent");
}
}
//儿子继承父亲
class Child extends Parent{
public void say(){
System.out.println("Child");
}
}
public class Class1 {
public static void main(String[] args){
Grandparent p = new Child(); //p表面为Grandparent,实际是Child。是隐式的转换,向上转型
Parent o = (Parent)p; //p表面从Grandparent变成Parent,是向下转型。
//p实际上从Child到Parent了。必须强制转换
o.say();
}}
Child
同级之间无法强制转换
从结果看来,对象向下转型后,调用的方法还是由实际的对象来决定的
特别: 向下转型时候 被转换变量的实际类型——必须是转换类或者他的子类1
package test1;
//祖父登场!
class Grandparent{
public void say(){
System.out.println("Grandparent");
}
}
//父亲继承祖父
class Parent extends Grandparent{
public void say(){
System.out.println("Parent");
}
}
//叔叔继承祖父
class Uncle extends Grandparent{
public void say(){
System.out.println("Uncle");
}
}
public class Class1 {
public static void main(String[] args){
Grandparent p = new Uncle(); //向上
Parent o = (Parent)p; //向下
o.say();
}}
//父亲继承祖父
//儿子继承祖父
Grandparent p = new Child(); //向上
Parent o = (Parent)p; //向下
o.say();
p表面为Grandparent,实际为Child
要从Grandparent到Parent当然可以。
报错:
变量p实际:Uncle;声明:Grandparent。
编译的时候,编译器检测的是声明类型,所以从Grandparent到parent是🆗的
在运行的时候,转换的是实际类型,p实际上是Uncle类型,要同级转换到Parent就不行,这里无法强制转换。
故失败。
为防止此情况,我们有instanceof
insatanceof
用于判断一个对象的实际类型,表达式返回boolean的值
语法格式:
变量名 instanceof 类名
package test1;
//祖父登场!
class Grandparent{
public void say(){
System.out.println("Grandparent");
}
}
//父亲继承祖父
class Parent extends Grandparent{
public void say(){
System.out.println("Parent");
}
}
//儿子继承父亲
class Child extends Grandparent{
public void say(){
System.out.println("Child");
}
}
public class Class1 {
public static void main(String[] args){
//孙上祖身
Grandparent p = new Child();
//p instanceof Child 判断实际类型是Parent还是Child,然后声明并强制转换为对应类型。
if(p instanceof Parent){
Parent o =(Parent) p;
o.say();
}else if (p instanceof Child){
Child o = (Child) p;
o.say();
}
}}
Child
---------------------------
“朝着一个既定的方向去努力,就算没有天赋,在时间的积累下应该也能稍稍有点成就吧。”