从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方法时,编译器就会直接在类加载时把其符号引用解析为直接引用,不存在说子类找不到方法之后再去父类找这种行为,所以也叫解析调用。
这就是上面的例子中看起来像是重写的方法却没有产生重写的效果的原因。
全文完。
从Java继承类的重名static函数浅谈解析调用与分派的更多相关文章
- C++ 类的继承四(类继承中的重名成员)
//类继承中的重名成员 #include<iostream> using namespace std; /* 自己猜想: 对于子类中的与父类重名的成员,c++编译器会单独为子类的这个成员变 ...
- java 继承类与接口问题
java 先extends 继承类,再implements 继承接口 public class DataBase extends ClassBase implements Ijiekou { }// ...
- 深入理解java虚拟机(十一) 方法调用-解析调用与分派调用
方法调用过程是指确定被调用方法的版本(即调用哪一个方法),并不包括方法执行过程.我们知道,Class 文件的编译过程中并不包括传统编译中的连接步骤,一切方法调用在 Class 文件调用里面存储的都只是 ...
- [Java][Android][Process] Process 创建+控制+分析 经验浅谈
不管是Android亦或者Java中或多或少须要调用底层的一些命令.运行一些參数: 此时我们须要用到Java的Process来创建一个子进程.之所以是子进程是由于此进程依赖于发起创建请求的进程,假设发 ...
- Processing中PImage类和loadImage()、createImage()函数的相关解析
聊一聊Processing中PImage类和loadImage().createImage()函数.因为要借P5做多媒体创意展示,图片是一个很重要的媒体.有必要就图片的获取和展放作总结. 首先 有一点 ...
- java实体类的属性名首字母不能大写,不然el表达式无法取值
摘要:Java命名规范中,实体类属性名以小写字母开头,但并没有说不能以大写字母开头,然而事实告诉我,大写真不行 https://www.cnblogs.com/jnhs/p/10025757.html
- java获取类的全类名----类名.class.getName()的作用是获取这个类的全类名
类名.class.getName()的作用是获取这个类的全类名
- java 继承类之后,访问不到超类的属性的原因及解决方法
是因为超类里的属性没有加上public关键字 解决方法: 超类和超类里的属性或者方法如果想被其他包下的方法调用,就必须全部加上public权限,即设置为公开访问 例: @Controller publ ...
- java File类的使用以及一些函数
package file; import java.io.File; import java.io.IOException; import org.junit.jupiter.api.Test; /* ...
随机推荐
- 阿里REDIS优化
- Day19 Django
老师代码博客: http://www.cnblogs.com/yuanchenqi/articles/7552333.html 上节内容回顾: class Book(models.Model): ti ...
- windows10不能修改hosts解决方案(亲测)
hosts文本解释: 有时候我们要破解一些软件与服务器通讯,所以通常都需要更改Hosts文件来达到目的,XP系统可以直接修改保存,但是Win10系统却提示没有权限去修改,那么我们要怎样办呢,我们修改的 ...
- laravel 5.5 安装
PHP要求 PHP> = 7.0.0 OpenSSL PHP扩展 PDO PHP扩展 Mbstring PHP扩展 Tokenizer PHP扩展 XML PHP扩展 通过Composer创建项 ...
- NSURLSession 所有的都在这里(一)
这篇文章会有什么? 在这篇文章中把NSURLSession.h文件集体梳理一遍,把里面的每个属性.代理和方法都拿出来说说,通过这篇文章我相信对于NSURLSession这一块的东西会梳理的比较全面一点 ...
- kmeans算法思想及其python实现
第十章 利用k-均值聚类算法对未标注的数据进行分组 一.导语 聚类算法可以看做是一种无监督的分类方法,之所以这么说的原因是它和分类方法的结果相同,区别它的类别没有预先的定义.簇识别是聚类算法中经常使用 ...
- kaggle入门项目:Titanic存亡预测 (一)比赛简介
自从入了数据挖掘的坑,就在不停的看视频刷书,但是总觉得实在太过抽象,在结束了coursera上Andrew Ng 教授的机器学习课程还有刷完一整本集体智慧编程后更加迷茫了,所以需要一个实践项目来扎实之 ...
- 第二章 ArrayList源码解析
一.对于ArrayList需要掌握的七点内容 ArrayList的创建:即构造器 往ArrayList中添加对象:即add(E)方法 获取ArrayList中的单个对象:即get(int index) ...
- VS2010+OpenMP的简单使用
OpenMP是把程序中的循环操作分给电脑的各个CPU处理器并行进行.比如说我要循环运行100次,我的电脑有两个处理器,那OpenMP就会平均分给两个处理器并行运行,每个处理器运行50次.使用方法 1. ...
- 【转】微信小游戏接入Fundebug监控
在SegmentFault上看到Fundebug上线小游戏监控,刚好最近开始玩微信小游戏,于是尝试接入试了一下. 接入方法 创建项目的时候选择左下角的微信小游戏图标. 点击继续进入接入插件页面. 第三 ...