Java中的 向上转型 | 向下转型

简介: Java中的 向上转型 | 向下转型

一.向上转型

向上转型其实就是创建一个子类对象,并将其当作父类对象来使用,一般语法格式如下:


父类类型对象名 = new 子类类型()



一般有以下三种使用场景:


直接赋值

我们这里以父类为Animal类举例,并且有一个Cat类来继承他

class Animal {
    String name;
    int age;
    //构造方法
    public Animal(String name,int age) {
        this.name = name;
        this.age = age;
    }
    public void eat() {
        System.out.println(this.name + "正在吃食物~~~");
    }
}
class Cat extends Animal {
    //构造方法
    public Cat(String name,int age) {
        super(name,age);
    }
}


       在这种情况下,我们用父类对象直接引用子类对,不但程序不会报错,反而还可以正常调用父类中的成员方法


 

    public static void main(String[] args) {
        Cat cat = new Cat("布偶",3);
        Animal animal1 = cat;
        animal1.eat();
        Animal animal2 = new Cat("橘猫",2);
        animal2.eat();
    }

输出结果:



那能不能调用子类的成员方法呢?我们在子类中新添加一个sleep方法


class Animal {
    String name;
    int age;
    //构造方法
    public Animal(String name,int age) {
        this.name = name;
        this.age = age;
    }
    public void eat() {
        System.out.println(this.name + "正在吃食物~~~");
    }
}
class Cat extends Animal {
    //构造方法
    public Cat(String name,int age) {
        super(name,age);
    }
    //新添加的子类方法
    public void sleep() {
        System.out.println(this.name + "正在睡觉......");
    }
}



我们尝试用上述过程来调用以下子类的中的方法:

    public static void main(String[] args) {       
        Animal animal = new Cat("橘猫",2);
        animal.eat();
        animal.sleep();   
    }

 

但是等我们写好了后,就会发现编译器报错了



也就是说:


使用向上转型后,我们可以正常调用父类中的成员方法,但是不能调用子类中自己的方法

但是要解决上述问题还是很简单的,当我们在子类中重写父类方法后,我们就可以调用子类方法了,这也就是我们多态的实现

class Animal {
    String name;
    int age;
    //构造方法
    public Animal(String name,int age) {
        this.name = name;
        this.age = age;
    }
    public void eat() {
        System.out.println(this.name + "正在吃食物~~~");
    }
    public void sleep() {
    }
}
class Cat extends Animal {
    //构造方法
    public Cat(String name,int age) {
        super(name,age);
    }
    public void sleep() {
        System.out.println(this.name + "正在睡觉......");
    }
}
    public static void main(String[] args) {
        Animal animal = new Cat("橘猫",2);
        animal.eat();
        animal.sleep();
    }

现在我们就可以正常调用输出了:



总结:

当我们通过向上转型新建了一个对象后,我们可以通过这个对象来访问父类中的方法,但是不能访问子类中自己的方法,除非我们在子类中重写父类方法,也就是说当一个方法只有在父类和子类中都出现的情况下,我们才能访问子类中的这个方法


通过向上转型新建的对象可以访问的方法范围是:


  • 父类有 子类没有
  • 父类有 子类也有

不能访问的范围是


  • 父类没有 子类也没有
  • 父类没有 但子类有

通过传参

class Animal {
    String name;
    int age;
    //构造方法
    public Animal(String name,int age) {
        this.name = name;
        this.age = age;
    }
    public void eat() {
        System.out.println(this.name + "正在吃食物~~~");
    }
}
class Dog extends Animal {
    //构造方法
    public Dog(String name,int age) {
        super(name,age);
    }
    public void eat(){
        System.out.println(this.name + "正在吃狗粮~~~");
    }
}
class Cat extends Animal {
    //构造方法
    public Cat(String name,int age) {
        super(name,age);
    }
    public void eat(){
        System.out.println(this.name + "正在吃猫粮~~~");
    }
}
    public static void fun(Animal animal) {
        animal.eat();
    }
fun(new Dog("哈士奇",2));
fun(new Cat("橘猫",2));


我们通过一个方法来接受一个父类对象,然后通过这个父类对象来调用eat方法,当我们传入的参数是一个子类对象的时候,就相当于我们用父类对象做参数来接到了子类对象,也就是发生了向上转型


输出结果:



通过返回值

class Animal {
    String name;
    int age;
    //构造方法
    public Animal(String name,int age) {
        this.name = name;
        this.age = age;
    }
    public void eat() {
        System.out.println(this.name + "正在吃食物~~~");
    }
}
class Dog extends Animal {
    //构造方法
    public Dog(String name,int age) {
        super(name,age);
    }
    public void eat(){
        System.out.println(this.name + "正在吃狗粮~~~");
    }
}
class Cat extends Animal {
    //构造方法
    public Cat(String name,int age) {
        super(name,age);
    }
    public void eat(){
        System.out.println(this.name + "正在吃猫粮~~~");
    }
}
    public static Animal fun1(Animal animal) {
        return new Cat("布偶",3);
    }
    public static Animal fun2(Animal animal) {
        return new Dog("哈士奇",2);
    }


我们用父类对象做返回值类型,但是我们返回的是子类对象,这也就相当于发生了向上转型


向上转型的优点:让代码实现更简单灵活。

向上转型的缺陷:不能调用到子类特有的方法


二.向下转型

将一个子类对象经过向上转型之后当成父类方法使用,再无法调用子类的方法,但有时候可能需要调用子类特有的方法,此时:将父类引用再还原为子类对象即可,即向下转换


class Animal {
    String name;
    int age;
    //构造方法
    public Animal(String name,int age) {
        this.name = name;
        this.age = age;
    }
    public void eat() {
        System.out.println(this.name + "正在吃食物~~~");
    }
    public void sleep() {
    }
}
class Cat extends Animal {
    //构造方法
    public Cat(String name,int age) {
        super(name,age);
    }
    public void sleep() {
        System.out.println(this.name + "正在睡觉......");
    }
}
public class Test_4 {
    public static void main(String[] args) {
        Animal animal = new Cat("橘猫",2);
        Cat cat = new Cat("布偶",2);
        animal.eat();
        animal.sleep();
        cat = (Cat)animal;
        cat.eat();
        cat.sleep();
    }
}


输出结果:



instanceof

向下转型用的比较少,而且不安全,万一转换失败,运行时就会抛异常。Java中为了提高向下转型的安全性,引入了 instanceof  ,如果该表达式为true,则可以安全转换

public static void main(String[] args) {
    Cat cat = new Cat("元宝",2);
    Dog dog = new Dog("小七", 1);
    // 向上转型
    Animal animal = cat;
    animal.eat();
    animal = dog;
    animal.eat();
    if(animal instanceof Cat) {
        cat = (Cat)animal;
    }
    if(animal instanceof Dog) {
        dog = (Dog)animal;
    }
}


对于instanceof的详细信息可以查看官方资料:


Chapter 15. Expressions (oracle.com)


目录
相关文章
|
2月前
|
安全 Java
【Java】向上转型和向下转型
【Java】向上转型和向下转型
32 0
|
安全 Java
【零基础学Java】—对象的向上和向下转型(二十七)
【零基础学Java】—对象的向上和向下转型(二十七)
|
6月前
|
Java
Java:什么是向上转型与向下转型
Java:什么是向上转型与向下转型
|
安全 Java 编译器
Java | 浅谈多态中的向上转型与向下转型
Java | 浅谈多态中的向上转型与向下转型
199 0
java_类向上转型以及动态绑定机制(多态)
语法:父类类型 变量名=new 子类类型();特点:编译类型看左边,运行类型看右边
59 0
【Java挠头】继承、抽象、接口、多态、向上转型、向下转型等精妙干货
【Java挠头】继承、抽象、接口、多态、向上转型、向下转型等精妙干货
142 0
【Java挠头】继承、抽象、接口、多态、向上转型、向下转型等精妙干货
|
XML Java Android开发
Java中多态向下转型的意义
在了解多态时,我们一般使用它默认的向上转型,也不需要强制转换。
136 0
java面向对象之多态(向上转型和向下转型)
java面向对象之多态(向上转型和向下转型)
|
2天前
|
Java
Java—多线程实现生产消费者
本文介绍了多线程实现生产消费者模式的三个版本。Version1包含四个类:`Producer`(生产者)、`Consumer`(消费者)、`Resource`(公共资源)和`TestMain`(测试类)。通过`synchronized`和`wait/notify`机制控制线程同步,但存在多个生产者或消费者时可能出现多次生产和消费的问题。 Version2将`if`改为`while`,解决了多次生产和消费的问题,但仍可能因`notify()`随机唤醒线程而导致死锁。因此,引入了`notifyAll()`来唤醒所有等待线程,但这会带来性能问题。
Java—多线程实现生产消费者
|
4天前
|
安全 Java Kotlin
Java多线程——synchronized、volatile 保障可见性
Java多线程中,`synchronized` 和 `volatile` 关键字用于保障可见性。`synchronized` 保证原子性、可见性和有序性,通过锁机制确保线程安全;`volatile` 仅保证可见性和有序性,不保证原子性。代码示例展示了如何使用 `synchronized` 和 `volatile` 解决主线程无法感知子线程修改共享变量的问题。总结:`volatile` 确保不同线程对共享变量操作的可见性,使一个线程修改后,其他线程能立即看到最新值。