Java笔记整理 —— 多态、向上转型、向下转型

多态

       对于解决某些问题,比如 假设需要创建一个方法给宠物喂食,那么用传统方法来说,给猫喂鱼,狗喂骨头等等,需要每一个都写一个方法这样导致代码的复用性不高,而且不利于代码的维护,因此需要多态

       多态指 方法或对象具有多种形态。是面向对象的第三大特征,多态是建立在封装和继承基础之上的。

方法的多态

重写和重载就体现了多态。

    // 方法重载体现了多态——在同类中方法有多种形态
    public int sum(int num1,int num2){
        return num1 + num2;
    }

    public int sum(int num1,int num2,int num3){
        return num1+num2+num3;
    }

    // 方法重写体现了多态——在不同类中方法也有多种形态

    public int sum(int num1,int num2)
    {
        return num1 + num2;
    } //父类方法

    public int sum(int num1,int num2)
    {
        return num1 + num2;
    } //子类方法
     

对象的多态

1. 一个对象的编译类型和运行类型可以不一致编译类型看定义时 =号 的左边,运行类型看 =号 的右边。

Animal animal = new Dog();  // animal 编译类型是Animal,运行类型为 Dog

2. 编译类型在定义对象时就确定了,不能改变。

3. 运行类型是可以变化的。

animal = new Cat(); // animal的运行类型变成了Cat,编译类型仍然是Animal

4. 对象多态的前提:两个对象(类)之间存在继承关系。 

因为对象的多态,很多操作就简洁许多了。以上面的喂食例子,我们正常写的话应该是这样:

public void feed(Cat cat, Fish fish){
    ...;  //输出喂食信息
}

public void feed(Dog dog, Fish fish){
    ...;  //输出喂食信息
}
...... //所有动物类与食物类都要写一遍,写在Master类中

而如果用对象的多态方法来写,则是下面这样:

public void feed(Animal animal, Food food){
    ...;
} // 只需在Master类中写一个即可

当调用时,仍然是传入Animal类和Food类的子类,这时就用到了多态机制。

5. 多态参数:方法定义的形参类型为父类类型,实参类型允许为子类类型。

向上转型

1. 本质:父类的引用指向了子类的对象。

2. 语法:父类类型  引用名  =  new  子类类型();

3. 特点:

1)编译类型看左边,运行类型看右边。

2)可以调用父类中的所有成员(当然前提是遵守访问权限)。

3)不能调用子类中特有成员(如果子类重写了父类的方法,那么由于动态绑定机制,调用父类的成员和方法会先从子类找,因此子类重写的方法是可以被调用的),因为在编译阶段,能调用哪些成员,是由编译类型来决定的

Animal animal = new Cat();
animal.catchMouse();  //错误,因为catchMouse是子类的特有方法,向上转型不能调用
public class Car {
    public int age;
    public void say(){
        System.out.println("这是一个car类");
    }
}

//相同属性看编译类型,相同方法看运行类型

class BMW extends Car{
    public int age = 10;
    public void say(){
        System.out.println("这是一个BMW类");
    }
    public static void main(String[] args) {
        Car car = new BMW();
        Car car1 = new Car();
        BMW bmw = new BMW();
        System.out.println(car.age); //0
        System.out.println(car1.age); //0
        System.out.println(bmw.age); //10
        car.say(); //BMW类
        car1.say(); //Car类
        bmw.say(); //BMW类
    }
}

4)最终运行效果看子类的具体实现,即调用方法时,从子类(运行类型)开始查找方法,规则与前面的方法调用规则一致。

向下转型

1. 语法:子类类型  引用名  =  (子类类型) 父类引用。

Cat cat = (Cat)animal; 

  这里注意一点,向下转型后,cat的编译类型和运行类型都是Cat,cat和animal都指向Cat的对象(注意animal没有消失)。

2. 只能强转父类的引用,不能强转父类的对象。父类的对象是创建在堆区中的,这个是不能改变的(因为已经创建了),但是可以改变指向该对象的指针,向下转型就是让它指向一个子类的对象

3. 要求父类的引用必须指向的是当前目标类型的对象。

Animal animal = new Cat();
Dog dog = (Dog)animal;  //报错
Cat cat = (Cat)animal;  //正确

    就比如这个例子,父类的引用本来就指向Cat类的对象,因此向下转型只能使用Cat按照错误语句的理解,让一只狗指向猫对象,那肯定是错误的

4. 当向下转型后,可以调用子类类型中所有的成员(当然要符合访问范围)。

5. 下面是错误的向下转型写法,不能让没有引用的对象进行向下转型。

Cat cat = (Cat)(new Animal());
Cat cat = (Cat)new Animal();
// 这两种写法都是错误的,不能让没有引用的对象进行向下转型
// 编译器报告 cannot be cast to 错误

 多态数组 

    数组的定义类型为父类类型,里面保存的实际元素类型为子类类型,静态初始化可以直接写,动态初始化则需要new父类,然后对里面的元素单个向上转型 

        Person[] a = new Student[3];  //不能这样写        

        // 第一种写法,静态初始化
        Preson p = new Person();
	    Person t = new Teacher();
	    Person s = new Student();
	    Person[] persons = {p,t,s};

        //第二种写法,动态初始化
        Person[] a = new Person[3]; //new父类
        a[0] = new Student();

  这里需要介绍一个问题:如何调用子类特有的方法(很明显,光有向上转型是不能调用的,向上转型只能让子类加入到父类的数组中,因此需要用到向下转型) 

public class Person {
    private int age;
    private String name;
}

public class Student extends Person{
    public void Study(){
        System.out.println("学生正在学习");
    }
}

public class Test {
    public static void main(String[] args) {
        Person[] a = new Person[3];
        a[0] = new Student(); //向上转型
        a[0].Study(); 
     //报错,因为Study是子类特有的方法,向上转型不能调用(调用方法由编译类型决定)
    }
}
public class Test {
    public static void main(String[] args) {
        Person[] a = new Student[3];
        a[0] = new Student();
        Student stu = (Student)a[0];  //向下转型
        stu.Study();// 语义相同:((Student) a[0]).Study();
    }
}

房屋出租小项目的思路

多态是指同一行为具有多个不同的表现形式。在Java多态可以通过向上转型向下转型来实现。向上转型是指将子类类型转换为父类类型,这个过程是默认的,可以通过父类类型的变量引用子类类型的对象。例如,Animal a = new Cat(); 这里Cat是Animal的子类,通过向上转型,将Cat类型的对象赋值给Animal类型的变量a。这样,a可以调用Animal类的方法和属性,但无法调用Cat类特有的方法和属性。这是因为变量a被限定为Animal类型,只能访问Animal类定义的方法和属性。这就是多态向上转型。 而向下转型是指将父类类型转换为子类类型的转换过程,这个过程是强制的。在向上转型后,如果需要使用子类特有的方法和属性,就需要进行向下转型向下转型的语法是将父类类型的变量强制转换为子类类型的变量。例如,Cat c = (Cat) a; 这里将Animal类型的变量a强制转换为Cat类型的变量c。这样,变量c就可以调用Cat类特有的方法和属性,但需要注意的是,只有在向上转型之后,才能进行向下转型,否则会出现编译错误或运行时错误。这就是多态向下转型。所以,多态通过向上转型向下转型实现了同一行为具有多个不同的表现形式的特性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [多态向上转型向下转型](https://blog.csdn.net/Iam_am_lbj/article/details/122458965)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值