Java SE 019 多态详解
前言:此笔记为圣思园张龙老师讲述的java视频课程笔记,自己看视频学习时记录的,用于积累与复习,在此分享给学习软件编程的兄弟姐妹们,以供参考。
一.父类型的引用可以指向子类型的对象。
Parent p = new Child();
解说:
(1)p可以指向生成出来的Child的那个对象。换句话说,就是父类的引用指向了生成了子类的那个实例。
(2)p指向谁,就会去调用谁的方法,当前指向的是Child()的一个对象,所以它调用的就是Child类对象的方法。而不是Parent的方法。
(3)多态无处不在,没有多态,很多东西实现起来是很繁索的。非常麻烦的,而且会造成很多重复的工作。
(4)p虽然是指向子类型的一个引用,但是这个p是个什么类型的,是Parent类型的,Parent这个类型有这个sing()方法吗?它没有这个sing()方法。对于现在写的这种形式来说,要求这个p去指向一个子类的对象,并且去调用子类的某个方法,那么这个方法在父类里面也必须要存在,因为这个引用p它本身是父类型的。它是什么类型的,它才能去使用什么类型的方法,虽然它实际指向的是一个子类的对象,但是p本身还是一个父类型的一个的引用,也就是说它是一个父类型的变量,你不可能说我父类型的变量没有,而子类型里面有,我就能去调用,它是调用不了的。代码如下:
public class PolyTest{
public static void main(String [] args){
Parent p = new Child();//多态
p.sing();
/*执行此条语句的时候,它首先会检查父类里面是否有sing()这个方法,如果有这个方法的话,它再去子类里面去调用不管是继承过来的,还是重写之后的那个版本的sing()方法。*/
}
}
class Parent{
//父类没有sing()方法
}
class Child{
public void sing(){
System.out.println(“parent”);
}
}
注意:
必须要在父类方法中也要存在这样一个sing()方法,因为这是由p的类型Parent来决定的。所以在使用父类型的引用去指向子类型的对象,去调用子类的某个方法的时候,这个方法一定要确保在父类里面要出现过,或者说父类里面一定要定义过这个方法才可以,否则编译的时候会出错。因为它在父类型的时候,它找不到这个sing()方法。
二.小结
Parent p = new Child();
当使用多态方式调用方法时,首先检查父类中是否有sing()方法,如果没有则编译错误,如果有,再去调用子类的sing()方法。
三.向下的类型转换
(1)父类到子类,父类在上面,子类在下面,因此称作向下类型转换。
(2)向下类型转换的一个原则是看,Parent p = new Child();引用p实际指向的是什么,就可以将它转换成什么类型的引用。因为p实际指向的是Child类对象,所以就可以转换为Child对象的引用,即:
Child c = (Child) p;
四.指向谁就调用谁的方法
例1:
public class polytest2{
public static void main(string [] args){
animal animal = new cat();
animal animal2 = new animal();
/*
将anmal2指向animal所指向的cat对象
指向谁就调用谁的方法
*/
animal2 = animal;
animal2.sing();
}
}
class animal{
public void sing(){
system.out.println("animal is sing!");
}
}
class dog extends animal{
public void sing(){
system.out.println("dog is sing!");
}
}
class cat extends animal{
public void sing(){
system.out.println("cat is sing!");
}
}
例2:
public class polytest2{
public static void main(string [] args){
animal animal = new cat();
animal animal2 = new Animal();
/*指向谁就调用谁的方法,此处将animal指向
animail2指向的Animal的对象
*/
animal = animal2;
animal.sing();
}
}
class animal{
public void sing(){
system.out.println("animal is sing!");
}
}
class dog extends animal{
public void sing(){
system.out.println("dog is sing!");
}
}
class cat extends animal{
public void sing(){
system.out.println("cat is sing!");
}
}
例3:
public class polytest2{
public static void main(string [] args){
Cat cat = new Cat();
/*
cat 现在指向的是子类的对象,将它赋给Animal对象,
变成了Animal类型的引用指向了子类的对象,因此就
调用子类Cat类的sing()方法
*/
Animal animal = cat;
animal.sing();
}
}
class animal{
public void sing(){
system.out.println("animal is sing!");
}
}
class dog extends animal{
public void sing(){
system.out.println("dog is sing!");
}
}
class cat extends animal{
public void sing(){
system.out.println("cat is sing!");
}
}
例4:
public class polytest2{
public static void main(string [] args){
/*
Animal对象的引用指向了父类的引用
接下来进行强制类型转换,强制将animal
转换为一个cat,因为Cat是Animal的一个子
类,在编译的时候,java只知道这个信息,
但是这个Animal到底指向的是谁,只有到
执行的时候,才能确定下来。一个Animal的
对象在执行的时候,强制的转换成Cat对象。
就好比人强制转换成男人,从常理上来说是
错误的。指向谁才能转换成谁,我指向的是Cat
才能转换成Cat,现在我指向的是Animal,是不
能随便转换成Cat的。
*/
Animal animal = new Animal();
Cat cat = (Cat) animal;
}
}
class animal{
public void sing(){
system.out.println("animal is sing!");
}
}
class dog extends animal{
public void sing(){
system.out.println("dog is sing!");
}
}
class cat extends animal{
public void sing(){
system.out.println("cat is sing!");
}
}
五.一共有两种类型的强制类型转换
1.向上类型转换(upcast)
比如说将Cat类型转换为Animal类型,即将子类型转换为父类型。对于向上类型转换,不需要显示指定(如例3)。即不需要在前面加上“()”,当然写上也可以。
### 2.向下类型转换(downcast)
比如将Animal类型转换为Cat类型。即将父类型转换为子类型。对于向下类型转换,必须显示指定(必须要使用强制类型转换)。
Animal a = new Cat();
Cat c = (Cat)a;
c.sing();
调用a.sing()方法与调用c.sing()方法,结果是一样的.
六.那么我们为什么有些时候还要进行向下类型转换呢?
如果父类有3个方法,子类继承过来了或者重写了,此时使用强制类型转换,其实意义不大。因为使用的话,也是调用的子类的3个方法而已。不使用也是调用的这3个方法,但是父类有的,子类可以添加,在子类再添加到5个方法,如果使用a来调用方法的时候,就只能调用子类当中存在于父类里面的那3个方法,也就是父类里面声明过的那3个方法。另外的子类新增加的2个方法,就根本调用不了。因为它的类型是Animal类型的。要想调用子类新添加的2个方法,这时候就必须要使用向下类型转换,将它转换成子类型的,转换成子类型之后,才能使用子类又新添加的方法。