Java 多态运行顺序&&多态上转型对象

先写一个简单的水果之间继承的各个类及关系,方便测试

class GoldenDelicious extends Apple{
	public GoldenDelicious(){}
        public void makeAppleCider(){System.out.println("GoldenDelicious");}

 }

class Macintosh extends Apple{
      public Macintosh(){}
}

class Apple extends Fruit{
      public Apple(){}
}

class Orange extends Fruit{
      public Orange(){}
}

class Fruit{
      public Fruit(){}
}


在main中

<span style="font-family:SimSun;">Fruit fruit = new GoldenDelicious();
fruit.makeAppleCider();
</span>
刚写完就报错了,提示我们在Fruit中找不到makeAppleCider()方法。这是因为我们用的Fruit fruit = new,相当于这三句
<span style="font-family:SimSun;">Fruit fruit ;
GoldenDelicious g = new GoldenDelicious();
fruit = g;               //g向上转型,fruit称为g的上转型对象</span>

Java对上转对象有规定,其特点为:

(1)上转对象不能操作子类新增的成员变量;不能使用子类新增的方法。

(2)上转对象可以操作子类继承或隐藏成员变量,也可以使用子类继承的或重写的方法。

(3)如果子类重写了父类的某个方法后,对象的上转型对象调用这个方法时,一定是调用了这个重写的方法。

(4)可以将对象的上转型对象再强制转化为一个子类对象,这时,该子类对象又具备子类的所有属性和功能。


对于第一个我们已经证实,子类GoldenDelicious虽然有方法makeAppleCider()方法,但是Fruit类中无该方法,所以访问不到。接下来我们在Fruit类加入方法

class GoldenDelicious extends Apple{
	public GoldenDelicious(){}
	public void makeAppleCider(){System.out.println("GoldenDelicious");}

}
class Macintosh extends Apple{
	
	public Macintosh(){}
}
class Apple extends Fruit{
	public Apple(){}
	
}
class Orange extends Fruit{
	public Orange(){}
}
class Fruit{
	public Fruit(){}
	public void makeAppleCider(){System.out.println("fruit");
}
	
}
main.java:
Fruit fruit = new GoldenDelicious();
fruit.makeAppleCider();
结果:

GoldenDelicious

这里可以证实上面的结论②,调用的是GoldenDelicious的方法makeAppleCider();


其中多态运行顺序为:

  1、当该方法无参数时,那么只看实例化该对象的类是什么,从实例类的开始从下到上找起,一直找到Object类,那一层先有那个无参方法就调用哪一个方法。

  2、当方法有参数时,也是从实例类的开始从下到上找起,不过找的时候会比较参数,看参数的引用是谁,去匹配类方法中参数的类型定位到哪一层的的方法。


这里对应第一种情况就是先从GoldenDelicious类找起,里面有makeAppleCider(),就用GoldenDelicious的方法makeAppleCider(),不再往上找。

假如我们去掉GoldenDelicious类方法makeAppleCider(),而在Apple类中加入方法makeAppleCider(),那么按这个顺序,结果应该是apple才对。

class GoldenDelicious extends Apple{
	public GoldenDelicious(){}
	//public void makeAppleCider(){System.out.println("GoldenDelicious");}
}
class Macintosh extends Apple{
	
	public Macintosh(){}
}
class Apple extends Fruit{
	public Apple(){}
	public void makeAppleCider(){System.out.println("apple");}
}
class Orange extends Fruit{
	public Orange(){}
}
class Fruit{
	public Fruit(){}
	public void makeAppleCider(){System.out.println("fruit");}
	
}

结果:apple


第二种情况解释:

首先我们在继承类中加入一些带参数的方法,分别在三个类中加入带参方法makeAppleCider(),例如:

<span style="font-family:SimSun;">class GoldenDelicious extends Apple{
	public GoldenDelicious(){}
	public void makeAppleCider(){System.out.println("GoldenDelicious");}
	public void makeAppleCider(GoldenDelicious obj){System.out.println("GoldenDeliciousTwo");}    //加
}
class Macintosh extends Apple{
	
	public Macintosh(){}
}
class Apple extends Fruit{
	public Apple(){}
	public void makeAppleCider(){System.out.println("apple");}
	public void makeAppleCider(Apple obj){System.out.println("appleTwo");}                        // 加
}
class Orange extends Fruit{
	public Orange(){}
}
class Fruit{
	public Fruit(){}
	public void makeAppleCider(){System.out.println("fruit");}
	public void makeAppleCider(Fruit obj){System.out.println("fruitTwo");}                         //加
	
}</span>

现在我们在main()中这样若这样调用:
Fruit fruit = new GoldenDelicious();
Fruit fruit1 = new GoldenDelicious();
fruit.makeAppleCider(fruit1);
结果:

fruitTwo

分析:

这里调用函数时的参数fruit1的引用类型是Fruit,这里先从GoldenDelicious类由下往上找的时候会看里面有没有带有形参类型为Fruit的方法makeAppleCider()

GoldenDelicious类的makeAppleCider()方法的形参类型为GoldenDelicious,不匹配;所以再向上找到Apple类,里面makeAppleCider()方法的形参类型为Apple,不匹配;

所以再向上找到Fruit类,里面makeAppleCider()方法的形参类型为Fruit,匹配,所以输出fruitTwo.


再例如我们将Apple类中的形参类型变一下,变成Fruit,即:

class GoldenDelicious extends Apple{
	public GoldenDelicious(){}
	public void makeAppleCider(){System.out.println("GoldenDelicious");}
	public void makeAppleCider(GoldenDelicious obj){System.out.println("GoldenDeliciousTwo");}
}
class Macintosh extends Apple{
	
	public Macintosh(){}
}
class Apple extends Fruit{
	public Apple(){}
	public void makeAppleCider(){System.out.println("apple");}
	public void makeAppleCider(Fruit obj){System.out.println("appleTwo");}               //变参数类型
}
class Orange extends Fruit{
	public Orange(){}
}
class Fruit{
	public Fruit(){}
	public void makeAppleCider(){System.out.println("fruit");}
	public void makeAppleCider(Fruit obj){System.out.println("fruitTwo");}
	
}
按上面的分析,那么结果应该是 appleTwo

结果:

appleTwo


3.上转型对象的前三个特点我们都已经证实,最后一个可以将对象的上转型对象再强制转化为一个子类对象,这时,该子类对象又具备子类的所有属性和功能

这样再转化为子类的话,goldendeliciouus又完全具备GoldenDelicious类的所有属性和功能。

Fruit fruit = new GoldenDelicious();
GoldenDelicious goldendelicious = (GoldenDelicious)fruit;

class GoldenDelicious extends Apple{
	public GoldenDelicious(){}
	public void makeAppleCider(){System.out.println("GoldenDelicious");}
}
class Macintosh extends Apple{
	
	public Macintosh(){}
}
class Apple extends Fruit{
	public Apple(){}
	
}
class Orange extends Fruit{
	public Orange(){}
	
}
class Fruit{
	public Fruit(){}
	
}
</span>
结果为:

GoldenDelicious

说明:这时的goldendeliciouus对象完全不依赖父类,可以实现GoldenDelicious类的所有属性和功能,包括新增的。


最后,总结多态的实验过程:

(1)子类重写父类的方法。

(2)编译方法时,调用父类定义的方法。

(3)运行时,根据实际创建的对象类型动态决定使用哪个方法。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值