java面向对象---多态(基础进阶篇)

一、引言(概念)

Java 中的多态是面向对象编程的一个重要特性,它允许我们使用一个接口来表示不同的类实例。多态可以通过方法重写(override)和接口实现来实现。下面是关于 Java 中多态的一些关键概念和示例。
1、方法重写:
方法重写是指在子类中重新定义父类的方法。
重写的方法必须具有相同的签名(方法名、参数列表和返回类型)。
重写的方法可以改变行为,但不能降低访问级别。
2、向上转型:
可以将子类的对象赋值给父类类型的引用变量,这种转换称为向上转型(upcasting)。
向上转型是自动进行的,不需要显式转换。
3、向下转型:
可以将父类类型的引用变量转换为子类类型的引用变量,这称为向下转型(downcasting)。
向下转型需要显式转换,并且只有当对象实际上是子类实例时才安全。

二、多态的用处

情景1:假设现在有个需求完成学生的管理系统,有老师和学生和管理员这三个模块,在以前

我们需要写三个部分

也就是这样,很显然这样是不好的,重复性太高了。所以这个时候我们就可以使用多态来实现这个模块----在写register时在参数部分写上(Person p==new teacher() 把teacher这个对象赋值给p)同理对于student和administor

 三、多态的用法

首先,看到多态的表现形式

package 继承练习2;

public class person {
    String name;
     int age;
    public person(){
        
    }
    public person(String name, int age){
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
  public void show(){
System.out.println(name+" ,"+age+" ");
}
}

这边,我新建了一个Person父类,如图

然后接着定义student类继承父类

package 继承练习2;

public class student extends person{
@Override
    public void show() {
    System.out.println("学生的信息为:"+getName()+","+getAge());
}
}

teacher类

package 继承练习2;

public class teacher  extends person{
    @Override
    public void show() {
        System.out.println("老师的信息为:"+getName()+","+getAge());
    }

}

admin类

package 继承练习2;

public class admin  extends  person{
    @Override
    public void show() {
        System.out.println("管理员的信息为:"+getName()+","+getAge());
    }
}

最后一个test类

package 继承练习2;

public class test2 {
    public static void main(String[] args) {
        //创建三个对象,调用register方法
        student s = new student();
        s.setName("张三");
        s.setAge(12);

        teacher t =new teacher();
        t.setName("李四");
        t.setAge(13);

        admin ad=new admin();
        ad.setName("王五");
        ad.setAge(14);

        register(s);
        register(t);
        register(ad);

    }
    public static void register(person p) {
    p.show();

    }
}

在这些代码中,就有多态的使用,在test中register(s);register(t); register(ad);这三句,就是多态的场景用法。

四、 多态中调用成员方法的特点

1、这里调用回分两种情况:一种是变量调用,一种事方法调用

1.调用变量

package 继承练习2;


public class Test3 {
    public static void main(String[] args) {
        Animal ad=new dog();
        System.out.println(ad.name);//动物
//调用变量,编译看左边,运行也看左边

    }
}
class Animal{
    String name="动物";
    public void show(){
        System.out.println("animal---动物");
    }

}
class dog extends Animal {
    String name="小狗";
    @Override
    public  void show(){
        System.out.println("dog----show");

    }
}

可以看到,在程序运行的结果是----“动物”---,这是因为在程序运行到Animal ad=new dog();时,因为调用的是一个成员变量,所以在编译时会先看左边,左边是父类,而且父类是存在name这个变量的,如果左边编译成功,那运行的结果也就是左边的答案。

2.调用方法

package 继承练习2;


public class Test3 {
    public static void main(String[] args) {
        Animal ad=new dog();
        //System.out.println(ad.name);//动物
//调用变量,编译看左边,运行也看左边
ad.show();//编译看左边,但是运行会看右边

    }
}
class Animal{
    String name="动物";
    public void show(){
        System.out.println("animal---动物");
    }

}
class dog extends Animal {
    String name="小狗";
    @Override
    public  void show(){
        System.out.println("dog----show");

    }
}

可以看到,在程序运行的结果是----“dog----show”,当在调用方法时,编译看左边,但是运行会看右边,左边编译是正确的,但是在程序运行的时候,结果是打印右边子类的结果。

 五、从内存图中理解多态中调用成员变量

如图所示,这个是代码运行时的内存图

在java中永远都是,父类先进入方法区然后加载字节码文件,当然最先进入的一定是object类,这个毋庸置疑。这个先是Animal a 在栈内存加载一个空间,让等号的右边有一个new就意味着在堆内存中兴建一块空间,当程序运行时,会先编译,在父类中也发现了变量name不为null,且在运行时也会看左边的父类,所以第一个结果就是----“动物”---,

二、对于调用成员方法,这个会先去在父类中找有没有该方法,如果存在就继续运行,如果不存在就直接报错,但是程序运行的结果是看右边的子类。所以第二个结果就是打印出子类的“dog----show”

六、多态的优势和弊端 

(1)多态的优势

1、 在项目操作时,如果我不想使用学生这个对象时,那我只需要对new Student 操作就行了,剩下的代码不用操作。提高了编写程序的便利。

2、可以接受所有的子类对象

(2)多态的弊端:不能调用子类的特有方法

package 继承3;

public class test {
    public static void main(String[] args) {
        Animal a = new dog();
        a.eat();
        
    }
}
class Animal {
    String name="动物";

    public void eat() {
        System.out.println("动物在吃东西");
    }
}
class dog extends Animal {
    String name="小狗";
    @Override
    public void eat() {
        System.out.println("小狗在吃饭");
    }
    public void lookHome(){
        System.out.println("小狗在看家");
    }
}
class Cat extends Animal{
    String name="小猫";
    @Override
    public void eat(){
        System.out.println("小猫在吃饭");

    }
    public void catcher() {
        System.out.println("小猫在抓老鼠");
    }


}

 在test中,如果调用a.eat()方法是可以的,这个会打印出---小狗在吃饭---的结果,但是如果想打印出---小狗在看家----这个是做不到的,多态中无法调用子类中特有的方法

解释:因为在调用方法的时候,编译先看左边,那左边是父类,父类是没lookHome这个方法的,程序就会出错。

2.1弊端的解决办法:

把调用者a再变回子类类型即可

package 继承3;

public class test {
    public static void main(String[] args) {
        Animal a = new dog();
        a.eat();
        dog d=(dog) a;
        d.lookHome();

    }
}
class Animal {
    String name="动物";

    public void eat() {
        System.out.println("动物在吃东西");
    }
}
class dog extends Animal {
    String name="小狗";
    @Override
    public void eat() {
        System.out.println("小狗在吃饭");
    }
    public void lookHome(){
        System.out.println("小狗在看家");
    }
}
class Cat extends Animal{
    String name="小猫";
    @Override
    public void eat(){
        System.out.println("小猫在吃饭");

    }
    public void catcher() {
        System.out.println("小猫在抓老鼠");
    }


}

只需要在刚才的test类中,  dog d = (dog)a;这个就相当于把a转回成子类

当然我们也需要做个判断来确定类型是不是转错,

  if(a instanceof dog  d){
            

            d.lookHome();
        } else if ( a instanceof  Cat  c) {
           
            c.catcher();
          else{
System.outer.println("没有这个结果,错误")
}

1.首先,判断a是不是dog类型,如果是强转成dog类型,转完之后,变量名为d,如果不是,就不会强转,结果就是false

对于下面的cat也是同理。

 七、总结

一、什么是多态:

说白了,就是对象的多种形态

二、多态的前提:

1、有继承或实现关系

2、有子类继承父类

3、要有方法重写

三、多态的好出:

1、父类方法可以接受子类中所有的形参,体现代码的扩展性和便利性。

  • 20
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值