2021-07-01

2 篇文章 0 订阅
1 篇文章 0 订阅

面向对象之向上转型



一、向上转型

把一个子类的引用转换为父类的引用

public class Test {
    public static void main(String[] args) {
//        Cat cat = new Cat();
//        Animal animal = null;

        //向上转型--把一个子类的引用转成父类的引用
//        animal = cat;

        //上面的代码可以合并到一起
//        Animal animal = new Cat();
//        Animal animal2 = new Bird();


        //向上转型也可能发生在方法传参的过程中
        //方法传参本质上也就是在进行“赋值”操作
        func(new Cat());


        //向上转型,也可能发生在方法返回的时候
        Animal animal = func2();
    }


    public static void func(Animal animal){
    }

    //方法返回和方法传参,本质上都是“赋值”

    public static Animal func2(){

//        return new Cat();

        //拆解
        Cat cat = new Cat();  //new一个子类的实例
        Animal animal = cat;  //向上转型
        return  animal;  //返回一个animal类型的引用



    }
}

父类的引用,只能访问到父类中的属性和方法。
方法也是同理

二、动态绑定

1、如果父类中包含的方法在子类中有对应的同名同参数的方法,就会进行动态绑定。
2、此处的“静态”和“动态”分别指的是“编译期”和“运行期”,和static无关。
3、运行时决定调用那个方法
public class Animal {

    public String name = "小动物";

    public  void est(String food){

        System.out.println("Animal 正在吃 " + food);
    }
}
public class Test {
    public static void main(String[] args) {
        animal.est("鱼");
    }
}

如果eat方法只存在父类中,此时调用的eat就是父类的eat方法(此时不涉及动态绑定)
在这里插入图片描述

  • 如果eat方法只在子类中存在,此时调用的eat就会编译报错(此时也不涉及动态绑定)

  • 如果eat方法在父类和子类中都存在,并且参数都相同,此时就会涉及到“动态绑定”,即在程序运行时,看animal指向的目标是父类实例还是子类实例;若是指向父类实例就调用父类版本的eat,若是指向子类实例就调用子类版本的eat。

  • animal此引用指向的是父类还是子类实例,在运行时才可以确实。

  • 若eat方法在父类和子类中都存在,并且参数不相同,此时调用eat不涉及“动态绑定”,此时相当于一个“方法重载”。此规则和前面最开始的两条类似–根据调用方法时传入的参数和类型判断父类中是否有匹配的方法,如果不存在就编译出错(编译器确定)

  • 上述的动态绑定规则,是基于编译器和JVM实现,其另有术语,即:“方法重写—override”

  • 方法限定符会影响到动态绑定。比如:子类的中的某个方法时private,这个时候外部根本看不到子类的方法,此时不涉及动态绑定。

  • 重写涉及到的子类和父类方法和属性都相同。

  • 重载是在同一个作用域中,方法相同,属性不同。

public class Animal {

    public String name = "小动物";

    public  void eat(String food){

        System.out.println("Animal 正在吃 " + food);
    }
}
public class Cat extends Animal{

    public String gender = "公猫";

    private void eat(String food){

        System.out.println("Cat 正在吃 " + food);
    }
}
public class Test {
    public static void main(String[] args) {
        Animal animal = new Cat();
        animal.eat("鱼");
    }
}

报错提示
在这里插入图片描述
父类的方法eat是public
子类的方法eat是private(private的访问权限比public低)
一般情况下,在实际工作过程中,都是两个public的方法进行“动态绑定”/“方法重写”

1 方法重写与方法重载

方法重写:子类实现父类的重名方法,且参数、类型、个数完全相同。这种实现过程叫做重写/覆写/覆盖(override)实际调用过程中需要
方法重载:同一个作用域中,同名方法不同属性。实际调用过程中需要根据属性来调用方法。

2 多态

多态是一种程序设计的思想方法,具体的语法体现:向上转型、方法重写、动态绑定;通俗的讲,一个引用,对应到多种不同的形态(不同类型的实例)

public class Shape {
    public void  draw(){
        //把当前的形状打印
    }
}
public class Circle extends Shape{
    public void draw(){
        System.out.println("○");
    }
}
public class Rect extends Shape {
    public void draw(){
        System.out.println("□");
    }
}

public class Flower extends Shape {
    public void draw(){
        System.out.println("❀");
    }
}
public class Test {
    public static void main(String[] args) {

        //多态
        //创建若干子类实例
        Shape shap1 = new Rect();
        Shape shap2 = new Circle();
        Shape shap3 = new Flower();

        draw(shap1);
        draw(shap2);
        draw(shap3);
    }
    public static void draw(Shape shape){
        shape.draw();
    }
}

运行结果:
在这里插入图片描述

此时实现draw方法,不需要知道shape的类型。

  • 1、多态的这种设计思想,是“封装”的更进一步。封装的目的是让使用者知道类的实现细节就可以使用,但是使用者必须知道此类的类型;
  • 相反,使用多态的时候不需要知道此类的实现细节,更不需要知道此类的具体类型,只需要知道该类有一个draw方法即可。
  • 2、方便拓展–未来若是需要新增一个形状,创建一个新的子类即可,并且让子类也去重写draw方法,类的调用者不需要做出较大修改。
public class Circle extends Shape{
    public void draw(){
        System.out.println("○");
    }
}

public class Test {
    public static void main(String[] args) {

        //多态
        //创建若干子类实例
        Shape shap1 = new Rect();
        Shape shap2 = new Circle();
        Shape shap3 = new Flower();

        draw(shap1);
        draw(shap2);
        draw(shap3);
    }
    public static void draw(Shape shape){
        shape.draw();
    }
}

新增Triangle类时,draw方法不用做过多修改。
运行结果:
在这里插入图片描述

  • 3、减少分支语句(if / else switch / case)

若无多态,则上述代码需要用以下方法实现:

        Shape[] shapes = {
                new Rect(),
                new Circle(),
                new Flower(),
                new Triangle(),
        };
        for(Shape shape : shapes){
            if(shape.type == "圆形"){
                //打印圆形
            }
            else if(shape.type == "方形"){
                //打印方形
            }
            else if(shape.type == "小花"){
                //打印小花
            }
            else if(shape.type == "三角形"){
               //打印三角形
            }
            else {
                //...
            }
        }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值