Java中为什么静态方法不能被重写?为什么静态方法不能隐藏实例方法?

Java中为什么静态方法不能被重写?为什么静态方法不能隐藏实例方法?问题描述 Java 中为什么静态方法不能被重写 为什么静态方法不能隐藏实例方法 诸如此类 前期准备首先理解重写的意思 重写就是子类中对父类的实例方法进行重新定义功能 且返回类型 方法名以及参数列表保持一致 且对重写方法的调用主要看实际类型 实际类型如果实现了该方法则直接调用该方法 如果没有实现 则在继承关系中从低到高搜索有无实现 那么问题又来了 为什么只能对实例方法才能重写 我头好晕 这两个问题在这互相

问题描述

  Java中为什么静态方法不能被重写?为什么静态方法不能隐藏实例方法?诸如此类。

前期准备

Person student= new Student(); student.work();

例子

package com.learn.pra06; class Demo01{ public void method1(){ System.out.println("This is father non-static"); } public static void method2(){ System.out.println("This is father static"); } } public class Demo02 extends Demo01{ 
    public void method1(){ System.out.println("This is son non-static"); } public static void method2(){ System.out.println("This is son static"); } public static void main(String[] args){ Demo01 d1= new Demo01(); Demo02 d2= new Demo02(); Demo01 d3= new Demo02(); //父类引用指向子类对象 d1.method1(); d1.method2(); d2.method1(); d2.method2(); d3.method1(); d3.method2(); } }

分析

首先看看上面main 方法的字节码:

 // access flags 0x9 public static main([Ljava/lang/String;)V L0 LINENUMBER 19 L0 NEW com/learn/pra06/Demo01 DUP INVOKESPECIAL com/learn/pra06/Demo01. 
  
    ()V ASTORE 
   1 L1 LINENUMBER 
   20 L1 NEW com/learn/pra06/Demo02 DUP INVOKESPECIAL com/learn/pra06/Demo02. 
   
     ()V ASTORE 
    2 L2 LINENUMBER 
    21 L2 NEW com/learn/pra06/Demo02 DUP INVOKESPECIAL com/learn/pra06/Demo02. 
    
      ()V ASTORE 
     3 L3 LINENUMBER 
     22 L3 ALOAD 
     1 INVOKEVIRTUAL com/learn/pra06/Demo01.method1 ()V L4 LINENUMBER 
     23 L4 INVOKESTATIC com/learn/pra06/Demo01.method2 ()V L5 LINENUMBER 
     24 L5 ALOAD 
     2 INVOKEVIRTUAL com/learn/pra06/Demo02.method1 ()V L6 LINENUMBER 
     25 L6 INVOKESTATIC com/learn/pra06/Demo02.method2 ()V L7 LINENUMBER 
     26 L7 ALOAD 
     3 INVOKEVIRTUAL com/learn/pra06/Demo01.method1 ()V L8 LINENUMBER 
     27 L8 INVOKESTATIC com/learn/pra06/Demo01.method2 ()V L9 LINENUMBER 
     28 L9 RETURN L10 
     
    
  

编译时把对象的静态类型(声明类型)作为该方法的接受者。运行时则根据指令集再进行更改。

INVOKEVIRTUAL指令流程

package com.learn.pra06; public class ClassReference { 
    static class Person { @Override public String toString(){ return "I'm a person."; } public void eat(){ System.out.println("Person eat"); } public void speak(){ System.out.println("Person speak"); } } static class Boy extends Person{ @Override public String toString(){ return "I'm a boy"; } @Override public void speak(){ System.out.println("Boy speak"); } public void fight(){ System.out.println("Boy fight"); } } static class Girl extends Person{ @Override public String toString(){ return "I'm a girl"; } @Override public void speak(){ System.out.println("Girl speak"); } public void sing(){ System.out.println("Girl sing"); } } public static void main(String[] args) { Person boy = new Boy(); Person girl = new Girl(); System.out.println(boy); boy.eat(); boy.speak(); System.out.println(girl); girl.eat(); girl.speak(); } }
 public static main([Ljava/lang/String;)V L0 LINENUMBER 47 L0 NEW com/learn/pra06/ClassReference$Boy DUP INVOKESPECIAL com/learn/pra06/ClassReference$Boy. 
  
    ()V ASTORE 
   1 L1 LINENUMBER 
   48 L1 NEW com/learn/pra06/ClassReference$Girl DUP INVOKESPECIAL com/learn/pra06/ClassReference$Girl. 
   
     ()V ASTORE 
    2 L2 LINENUMBER 
    49 L2 GETSTATIC java/lang/System.out : Ljava/io/PrintStream; ALOAD 
    1 INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V L3 LINENUMBER 
    50 L3 ALOAD 
    1 INVOKEVIRTUAL com/learn/pra06/ClassReference$Person.eat ()V L4 LINENUMBER 
    51 L4 ALOAD 
    1 INVOKEVIRTUAL com/learn/pra06/ClassReference$Person.speak ()V L5 LINENUMBER 
    53 L5 GETSTATIC java/lang/System.out : Ljava/io/PrintStream; ALOAD 
    2 INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V L6 LINENUMBER 
    54 L6 ALOAD 
    2 INVOKEVIRTUAL com/learn/pra06/ClassReference$Person.eat ()V L7 LINENUMBER 
    55 L7 ALOAD 
    2 INVOKEVIRTUAL com/learn/pra06/ClassReference$Person.speak ()V L8 LINENUMBER 
    57 L8 RETURN L9 
    
  

为什么静态方法不能隐藏实例方法?

静态方法的调用的是通过在编译器静态绑定的,而实例方法的调用是在运行时动态绑定的,2者的调用的方式不同,所以二者只能存在其一,否则会存在歧义!

为什么静态方法能隐藏静态方法?

因为调用方式一致,不会像上面造成歧义,虽然父类和子类都定义了同样的函数,但是编译器会根据对象的静态类型激活对应的静态方法的引用,造成了重写的假象,实则不是重写!

总结

总体流程就是:编译器将类编译成class文件,其中方法会根据静态类型从而将对应的方法引用写入class中,运行时,JVM会根据INVOKEVIRTUAL 所指向的方法引用在常量池找到该方法的偏移量,再根据this找到引用类型真实指向的对象,访问这个对象类型的方法表,根据偏移量找出存放目标方法引用的位置,取出这个引用,调用这个引用实际指向的方法,完成多态!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/210722.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 上午7:02
下一篇 2026年3月19日 上午7:02


相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号