JAVA学习语法多态

发布时间:2024年01月21日

JAVA学习语法多态

大纲

  1. 重载和重写的多态
  2. (重点)对象的多态
  3. 向上转型
  4. 向下转型
  5. instanceof
  6. 总结

具体案例

1.重载是根据形参列表的差异来确定,而重写是按照从子类到父类的查找方式来确定使用哪个属性或方法 (具体看本专栏的重写与覆盖)
2.(重点)对象的多态

  1. 确定运行类型和编译类型
  2. 父类是可以创建子类的对象的

在这里插入图片描述
下面代码是对编译类型和运行类型的理解

package Test;

public class Animal {
    public void say(){
        System.out.println("我是animal");
    }
}//这是父类,定义了say方法

//==================================================

package Test;

public class Dog extends Animal{
    public void say(){
        System.out.println("我是小狗,小狗汪汪叫");
    }
}//这是animal子类dog,也定义了say方法
//===================================================
package Test;

public class Cat extends Animal{
    public void say (){
        System.out.println("我是cat,小猫喵喵叫" );
    }
}//这是animal的另一个子类cat,也定义了say方法
//===================================================
package Test;

public class Test {
    public static void main(String[] args) {
        Animal animal = new Dog();//这里编译类型是Animal,运行类型是Dog;父类创建子类的对象
        animal.say();//这里这样调用方法是会从运行类型开始调用,
        // 即使父类和子类都有方法的重写,但是会从运行类型开始
        animal = new Cat();
        animal.say();//是可以更改运行对象的,但是编译对象不更改
    }
}

最后会输出“我是小狗,小狗汪汪叫”
“我是cat,小猫喵喵叫”
因为dog是运行类型,所以调用的say方法是从dog开始的(前提是都有say方法),后面把运行类型改成cat了,就调用的是cat里面的say方法

3.向上转型

在这里插入图片描述
理解:

  1. 首先只能是拥有继承关系才能转型

  2. 只能调用编译类型里的所有成员方法和属性(还是要遵守修饰符的访问条件),不能调用运行类型里的编译类型不存在的属性和方法(就是运行类型特有的),在运行时,是从子类往上开始查找,遵循继承里面的查找方法,比如如果编译类型和运行类型两个都同时有相同的方法的,就调用运行类型。而如果运行里面没有,就一层一层往上找
    =======================================
    可以理解为对于方法都是从运行类型开始寻找,但是前提是只能是编译类型中有的才有资格寻找

  3. 创建的对象是可以更改的
    比如上述代码这一段

public class Test {
   public static void main(String[] args) {
       Animal animal = new Dog();//这里编译类型是Animal,运行类型是Dog;父类创建子类的对象
       animal.say();//这里这样调用方法是会从运行类型开始调用,
       
       animal = new Cat();
       animal.say();//是可以更改运行对象的,但是编译对象不更改
   }
}

4.向下转型

  1. 首先也是必须要有继承关系才能转型(必须是直系的就是说在一条继承关系上,而不能是父类的另外一条继承关系上)

  2. 对于属性
    在这里插入图片描述
    属性就取决于编译类型的属性,只是在继承时进行初始化时,是就近寻找的

  3. 对于方法
    有两种方式

package Test;

public class Test {
    public static void main(String[] args) {
        Animal animal = new Dog();//这里编译类型是Animal,运行类型是Dog;
        animal.say();//这里这样调用方法是会从运行类型开始调用,
        // 即使父类和子类都有方法的重写,但是会从运行类型开始
        animal = new smallCat();//是可以更改运行对象的,但是编译对象不能更改
        animal.play();//在smallCat里面没有play就,往上找到cat里面的play
        //向下转型
        Cat cat = (Cat) animal;//第一种
        cat.test();//相当于引出来了个新的叫法。新的引用类型,且该类型是cat类的,所以可以调用cat的方法,属性
        ((Cat)animal).test();//第二种,没有引入新名字,类似于直接强制转换
    }
}

对于第一种,引出来了个新的叫法,可以通过它调用它cat类型的方法,就是cat相当于一个新名字在调用方法上面。但是如果调用属性,调用的是其编译类型的属性
(与直接创建新的cat的区别就是没有新对象,易于管理)

对于第二种,相当于直接强转换,没有新的引用出现,当然也不能 ((Cat)animal).属性的方式去调用属性

5.instanceof
在这里插入图片描述
使用
xx instanceof xx
返回布尔类型(前面的那个是不是后面的那个的类型或者子类型)(注意:这里判断的是运行类型

6.总结

  1. 属性:在子类构造器初始化时是就近原则,其余是调用出编译类型的属性
  2. 方法:全是从子类(运行类型)开始往上调用,注意在向上转型时,调用的只能是编译类型里面有的方法,在向下转型时,可以创建新的引用类型(必须有继承关系)来调用新的引用类型的编译类型(在引用类型的理解上可以理解就是换了个名字),或者强制转换来调用新的引用类型的编译类型
  3. 注意:这里的编译类型的方法包括其父类里面的,但是不包括子类里面的,因为子类要先加载父类的初始化
    (属性找编译类型,方法找运行类型,子类没有找父类,方法中的属性就近原则)
文章来源:https://blog.csdn.net/2403_82385265/article/details/135712919
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。