从Java继承类的重名static函数浅谈解析调用与分派

今天被实习生问了这么个问题: 在java中,static成员函数是否可以被重写呢?

结论是,你可以在子类中重写一个static函数,但是这个函数并不能像正常的非static函数那样运行。

也就是说,虽然你可以定义一个重写函数,但是该函数没有多态特性。让我们测试一下:

 1 class  testClass1{
 2     static void SMethod(){
 3         System.out.println("static in testClass1");
 4     }
 5 }
 6 class testClass2 extends testClass1{
 7     static void SMethod(){
 8         System.out.println("static in testClass2");
 9     }
10 }
11 public class MainClass{
12     public static void main(String... args){
13         testClass1 tc1=new testClass2();
14         testClass2 tc2 =new testClass2();
15         tc1.SMethod(); //输出结果为 static in testClass1
16         tc2.SMethod(); //输出结果为 static in testClass2
17     }
18 }

从结果中可以看到,当我们用父类的实例引用(实际上该实例是一个子类)调用static函数时,调用的是父类的static函数。

原因在于方法被加载的顺序。

当一个方法被调用时,JVM首先检查其是不是类方法。如果是,则直接从调用该方法引用变量所属类中找到该方法并执行,而不再确定它是否被重写(覆盖)。如果不是,才会去进行其它操作(例如动态方法查询)

可能有的人一拍大腿,这不就是java的静态/动态分派么!

有点像,但还真不是,静态分派与动态分派是用来确定重载和重写逻辑的。在重载过程中,编译器根据方法参数的静态类型(比如tc1的静态类型是class1,tc2的是class2,但本文这里不是重载!)来确定使用方法的版本,这叫做静态分派。动态分派是用于方法重写的,比如我调用一个类A的方法f,如果该类有子类a,那么我以a来调用f的时候,调用的实际是a.f而非A.f。

看起来还真的像动态分派是不是?但是结果不符合啊!

这里的原因在于,动态分派时,我们实际是在讨论Java的invokevirtual指令的行为:这个指令首先会去寻找调用者的运行时类型,然后在其方法表里面寻找匹配的方法,如果找不到,再从其父类里找。这个过程就是Java中方法重写的本质,也就是动态分派。

而static方法是通过invokestatic指令来调用的。由于static方法是一种编译期可知,运行期不可变的方法,所以尽管子类和父类都有同样的方法名,而事实上它们是不同的方法,也是完全可以区分的方法。在调用static方法时,编译器就会直接在类加载时把其符号引用解析为直接引用,不存在说子类找不到方法之后再去父类找这种行为,所以也叫解析调用。

这就是上面的例子中看起来像是重写的方法却没有产生重写的效果的原因。

全文完。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏锦小年的博客

python学习笔记2.4-数据结构之列表和元组

python语言中包含的数据结构比较简单,除了简单的变量以外,还有列表(元组)、字典、集合。对于数据结构的操作一般包含四种:增、删、查、改。本文主要介绍列表(l...

20690
来自专栏黑泽君的专栏

java基础学习_常用类03_StringBuffer类、数组高级和Arrays类、Integer类和Character类_day13总结

============================================================================= ==...

9730
来自专栏java达人

两个关于字符串的经典例子

示例1: ==运算符 public static void test(){ String x = "hello"; String y = "world"; S...

22180
来自专栏androidBlog

表达式(四则运算)计算的算法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gdutxiaoxu/article/details/...

46410
来自专栏积累沉淀

Python快速学习第六天

第六天: 面向对象 1. 面向对象的特点——多态,封装,继承  对象:包括特性和方法,特性只是作为对象的一部分变量,而方法则是存储在对象内的函数。 (1)多态—...

19970
来自专栏猿人谷

在字符串中删除特定的字符

题目:输入两个字符串,从第一字符串中删除第二个字符串中所有的字符。例如,输入”They are students.”和”aeiou”,则删除之后的第一个字符串变...

23090
来自专栏赵俊的Java专栏

合并排序数组

33410
来自专栏前端开发

【JavaScript】Array数组对象下的方法

16850
来自专栏赵俊的Java专栏

判断字符串是否没有重复元素

14820
来自专栏Python

re模块和正则表达式

re模块 讲正题之前我们先来看一个例子:https://reg.jd.com/reg/person?ReturnUrl=https%3A//www.jd.com...

28550

扫码关注云+社区

领取腾讯云代金券