JAVA字段存在多态性吗

简介: JAVA字段存在多态性吗

概述


最近看到了一道关于多态的题目,总之我做错了,归根到底还是基础知识不够扎实,现在也拿来考考大家。

public class FieldHasNoPolymorphic {
    static class Animal {
        public String name = "animal";
        public Animal() {
            name = "new animal";
            callMyName();
        }
        public void callMyName() {
            System.out.println("my name is " + name);
        }
    }
    static class Cat extends Animal {
        public String name = "cat";
        public Cat() {
            name = "new Cat";
            this.callMyName();
        }
        @Override
        public void callMyName() {
            System.out.println("cat say my name is " + name);
        }
    }
    public static void main(String[] args) {
        Animal cat = new Cat();
        cat.callMyName();
        System.out.println(cat.name);
        System.out.println(((Cat)cat).name);
    }
}

运行结果:

1671176167268.jpg

是不是和大家心理想的一样呢? cat.name最终输出的竟然是new animal, 而不是 new Cat。虽然在真实情况下,我们不会这样写代码,但是可以拿来帮我们理解Java的多态,字段没有多态。


字节码分析


我们利用idea的jclasslib插件查看相应的字节码,

  1. 查看主函数的字节码

1671176176167.jpg

  1. 查看Cat类构造方法的字节码

1671176183141.jpg

  1. 查看Animal类构造方法的字节码

1671176189225.jpg

运行结果分析:

  1. main方法调用Cat的构造函数,Cat的构造函数会默认调用父类Animal的构造函数,父类构造函数会用invokevirtual指令调用callMyName方法,invokevirtual指令具有多态性,会调用实际类型的callMyName方法,也就是Cat类的方法, 此时Cat类的的name还没有初始化,他需要在子类构造函数中初始化, 所以第一行是 cat say my name is null
  2. 后面是子类构造函数中的this.callMyName,最终输出cat say my name is new Cat
  3. 第三行cat say my name is new Cat是由 cat.callMyName();输出得到的。
  4. System.out.println(cat.name); 最终输出的是new animal,是不是出乎大家的意料,我看字节码可以知道它是用的Animal中的name。

1671176196763.jpg

  1. 强转后,它就用的Cat类的name,所以输出的是new Cat。

1671176205826.jpg


总结


从这个例子我们知道了以下几点:

  1. 类中的字段没有多态性,如果子类和父类定义了同样的字段,最终会用引用类型的字段。
  2. 类的方法存在多态性,最终会调用运行时确定的实际类型的方法,如果方法中没有就调用父类的,依次类推,这个过程是依赖invokevirtual指令实现的。
目录
相关文章
|
7月前
|
Java
在Java中,多态性是通过继承和接口实现的
【4月更文挑战第7天】在Java中,多态性是通过继承和接口实现的
72 1
|
2月前
|
设计模式 算法 Java
Java中的多态性:深入理解与应用
【10月更文挑战第16天】 在Java编程的广阔天地中,多态性作为一种强大的面向对象特性,扮演着至关重要的角色。它允许我们以统一的方式处理不同类型的对象,极大地提高了程序的灵活性和可扩展性。本文将深入浅出地探讨Java中多态性的概念、实现机制以及在实际开发中的应用,帮助读者更好地理解和运用这一特性。
|
7月前
|
安全 Java 开发者
Java中的读写锁ReentrantReadWriteLock详解,存在一个小缺陷
【5月更文挑战第8天】Java中的读写锁ReentrantReadWriteLock详解,存在一个小缺陷
54 2
|
3月前
|
安全 Java 编译器
java访问字段
java访问字段
27 6
|
3月前
|
安全 Java 编译器
java访问类字段
java访问类字段
|
7月前
|
Java Maven
【Java报错】显示错误“Error:java: 程序包org.springframework.boot不存在“
【Java报错】显示错误“Error:java: 程序包org.springframework.boot不存在“
334 3
|
4月前
|
SQL Java Apache
实时计算 Flink版操作报错合集之使用parquet时,怎么解决报错:无法访问到java.uti.Arrays$ArrayList类的私有字段
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
java.lang.NullPointerExceptionMybatisPlus出现,测试,java.lang.NullPointe,空指针异常,public方法少写了一个字段,没加注解
java.lang.NullPointerExceptionMybatisPlus出现,测试,java.lang.NullPointe,空指针异常,public方法少写了一个字段,没加注解
|
6月前
|
Java
在 Java 中,类是一种定义对象的模板,它包含数据成员(字段)和方法。
在 Java 中,类是一种定义对象的模板,它包含数据成员(字段)和方法。
|
6月前
|
Java 编译器
在 Java 中,重写(Override)和重载(Overload)是两种不同的概念,用于实现多态性。它们有着不同的作用和使用场景。
在 Java 中,重写(Override)和重载(Overload)是两种不同的概念,用于实现多态性。它们有着不同的作用和使用场景。