由于我将继承与多态的讲解分成了三篇博客,所以在这篇博客给出三篇博客总的链接,阅读顺序由第一篇至第三篇就可以。 第一篇:主要讲解分派:JVM–详解虚拟机字节码执行引擎之静态链接、动态链接与分派 第二篇:主要讲解invokevirtual指令:JVM–从JVM层面深入解析对象实例化、多态性实现机制 第三篇:主要讲解继承与方法表: JVM–再谈继承与多态 相信这三篇博客会给你带来惊喜~~~作者:championhengyi发表于2018/1/12 14:53:43 原文链接 阅读:57评论:0查看评论 继续阅读 >>


董恒毅 18/01/12 14:53:43
此文试图从JVM层面深刻剖析Java中的继承与多态,知识面覆盖class字节码文件,对象的内存布局,JVM的内存区域、分派,方法表等相关知识,内容整合于大量博客,知乎,书籍,并加上博主自己的理解,相信看完会对你大有裨益! 即使博主在JVM专栏已经有两篇博客对多态的实现机制进行了分析,但是今天在分析了一波继承的原理之后,发觉之前对于多态的讲述还不完整,在查阅的相关资料之后,决定在这一篇博客真正的将继承与多态讲透彻! 注:本篇博客有部分内容摘抄自:从JVM角度看Java多态。表示感谢~ 先来看一份代码: class Parent { protected int age; public Parent() { age = 40; } void eat() { System.out.println("父亲在吃饭"); } } class Child extends Parent { protected int age; public Child() { age = 18 继续阅读 >>


董恒毅 18/01/10 16:14:59
之前一直觉得对于字节码的执行过程,对象的实例化过程,多态的实现机制没有进行深刻的探讨,只是进行了简单的总结,一直也苦于没有找到恰当的例子,所幸今天看到一前辈的博客,对其进行钻研之后,终于解决了这个历史遗留问题。 首先贴出前辈的原文链接,并且这篇博客会引用其中的一些内容:Java重写方法与初始化的隐患 问题的还原 先来看一份代码: public class SuperClass { private int mSuperX; public SuperClass() { setX(99); } public void setX(int x) { mSuperX = x; } } public class SubClass extends SuperClass { private int mSubX = 1; public SubClass() {} @Override public void setX(int x) { super.se 继续阅读 >>


董恒毅 18/01/08 18:24:57
JVM开发团队一直在努力,缩小Java与C/C++语言在运行效率上的差距。 本篇博客,我们来谈一谈JVM(HotSpot)为了提高Java程序的运行效率,都实现了哪些激动人心的技术~ JIT编译器的引入 首先我们这篇文章中所说的编译器都是指JVM的组成部分之一—即时编译器(JIT),与生成Java字节码的javac编译器要区分开来。 你也许想说,为什么要引进JIT编译器?很好的问题。 我们知道,javac将程序源代码编译,转换成Java字节码,解释器对字节码进行解释执行。而虚拟机传统的解释器,就是要将字节码中的操作指令和真正的平台体系结构之间的指令做映射。比如把Java的load指令换成native code的load指令。 JIT的出现,是为了补强虚拟机边运行边解释的低性能。它会智能地对热点代码进行优化且重复利用,最终将这些代码编译为与本地平台相关的机器码。 解释器与编译器 并存架构 刚才说明了引入JIT编译器的好处,那么HotSpot JVM为什么不完全采用编译器模式而是采用解释器与编译器并存的架构呢? 解释器与编译器各有优势:当程序需要迅速 继续阅读 >>


董恒毅 17/12/28 10:09:34
谈起GC,应该是让Java程序员最激动的一项技术,我相信每个Java程序员都有探究GC本质的冲动! 本篇博客围绕三个问题展开: 1.哪些内存需要回收? 2.什么时候回收? 3.如何回收? 哪些内存需要回收 首先回答第一个问题:不再使用的对象需要进行回收,不使用的类也有可能回收。 那么我们如何判断一个对象不再使用呢?主要有以下两种方法。 引用计数算法 定义:给对象添加一个引用计数器,每当有一个地方引用它时,计数器就加1;当引用失效时,计数器就减一;任何时刻计数器为0的对象就是不会被使用的对象。 我们可以看出,引用技术方法实现简单。并且有一些GC中确实使用的是引用计数算法,但是在Java虚拟机中并没有使用这个方法进行内存管理,原因就是一个问题很难被解决—对象之间循环引用。 来看一个例子: class Node { Node next ; } Node a = new Node (); Node b = new Node (); a.next = b ; b.next = a ; 继续阅读 >>


董恒毅 17/12/20 20:26:28
前面学习了Class文件结构、类的加载机制、字节码执行引擎、对象的创建与销毁,所以我准备从一个Java代码进行切入,详细剖析它的生命历程,将所学的知识真正的用起来,也算是对前面所学的知识进行一个系统的总结。 我们以这份Java代码为例,来剖析一个Java程序的生命历程: interface ClassName { String getClassName(); } class Company implements ClassName { String className; public Company(String className) { this.className = className; } @Override public String getClassName() { return className; } } public class Main { public static void main(String[] args) { 继续阅读 >>


董恒毅 17/12/17 12:52:20
在前几篇博客中,我们探究了.class文件的本质,类的加载机制,JVM运行时的栈帧结构以及字节码执行时对应操作数栈以及局部变量表的变化。 如果你已经掌握了这些东西,你现在应该会有一种感觉,给你一个Java代码,你可以从JVM的层面上将这个类从javac编译成.class文件开始,到使用java命令运行这个Class文件,然后这个类的运行过程是怎么样的,你可以解释清楚。 但是等等,好像少了点什么?我们好像没有谈及JVM中对象的创建?也就是说,在Java代码中,你new一个对象,这时候都发生哪些事情,这就是今天我所要说的。 对象创建的时机 我们先不说对象创建的具体过程是啥,我们先来谈一谈什么时候JVM会创建对象。 以下5种方式,会使JVM帮助你创建一个对象: 使用new关键字创建对象 Student student = new Student(); 使用Class类的newInstance方法(反射机制) newInstance方法只能调用无参的构造器创建对象。 Student student2 = (Student)Class 继续阅读 >>


董恒毅 17/12/12 11:40:51
兑现我之前的承诺,这篇博客我们来讲讲这个看起来十分难啃的骨头—静态链接与动态链接。 前言 从接触Java语言的第一天起,往后,我相信你一定听过什么动态链接啊,动态扩展啊,静态链接啊,它和C++相比有哪些优缺点啊… …如果你只是听说而没有探究过他们,也许你现在仍没办法说出Java语言到底有什么优缺点。 我们知道class文件是源代码经过编译后得到的字节码,如果学过编译原理会知道,这个仅仅完成了一半的工作(词法分析、语法分析、语义分析、中间代码生成),接下来就是实际的运行了。而Java选择的是动态链接的方式,即用到某个类再加载进内存,而不是像C++那样使用静态链接:将所有类加载,不论是否使用到。当然了,孰优孰劣不好判断。静态链接优点在速度,动态链接优点在灵活。 静态链接 那么,首先,咱们先来聊聊静态链接。 如上面的概念所述,在C/C++中静态链接就是在编译期将所有类加载并找到他们的直接引用,不论是否使用到。而在Java中我们知道,编译Java程序之后,会得到程序中每一个类或者接口的独立的class文件。虽然独立看上去毫无关联,但是他们之间通过接 继续阅读 >>


董恒毅 17/12/09 22:46:52
本篇博客信息量依旧庞大! 前言 在讨论本文的主题之前,我们先来思考一下:什么是虚拟机字节码执行引擎?它有什么作用? 在说明这个问题之前,我们先来想想之前我们已经学习过的class文件与类加载机制。 当一个Java程序写好之后,我们使用javac命令对其进行编译,产生的虚拟机字节码存储在class文件中,我在JVM–解析Class类文件结构一文中详细分析了class文件中字节码的存储格式及其组成。然后我们紧接着说明了JVM–详解类加载机制,你应该了解到—类加载机制就是将class文件中的字节码加载进JVM的方法区并生成这个类的Class对象的过程(再次强调不是生成这个类的实例化对象的过程)。 虚拟机字节码执行引擎 那么,现在我们言归正传,解决上面的两个问题: 假设我们现在有这样一个类: public class Demo { public static void main(String[] args) { System.out.println("hello world"); } } 在这个Java 继续阅读 >>


董恒毅 17/12/08 23:55:35
由于系统重起了,当然本地的仓储和SSH生成的密钥就都没有了,这时如何在本地pull自己在GitHub上的仓储呢? 由于系统重装,~/.ssh文件肯定就没有了,这时候就需要重新生成公钥和密钥。 ssh-keygen -t rsa -C “your_email@example.com” Enter file in which to save the key (/home/XXX/.ssh/id_rsa): Created directory ‘/home/XXX/.ssh’. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/XXX/.ssh/id_rsa. Your public key has been saved in /home/XXX/.ssh/id_rsa.pub. The key fingerprint is: 79:3c:8c:e7:3e:5 继续阅读 >>


董恒毅 17/12/07 00:01:23