Java再学习-JVM类加载和执行机制

  JVM简介


JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。Java虚拟机包括一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆和一个存储方法域。 JVM屏蔽了与具体操作系统平台相关的信息,使Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。JVM在执行字节码时,实际上最终还是把字节码解释成具体平台上的机器指令执行。

JVM类的加载   

        Java虚拟机的加载,连接,初始化。

        Java程序对类的使用方式,分成两种,一是主动使用,二是被动使用,所有的Java虚拟机实现必须在每个类或者接口被Java程序程序“首次主动使用”时才初始化类。

主动使用包括六种:

-创建类的实例

        -访问某个类或接口的静态变量,或者对该静态变量赋值

        -调用类的静态方法

        -反射(如 Class.forName(“com.tgb.java”))

        -初始化一个类的子类

        -Java虚拟机启动时被表明为启动类的类

        类的加载,也许很熟悉了,在开始学习谭浩强的C语言的时候,就知道将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。

       类的加载方式:

-从本地系统中直接加载

        -通过网络下载.class文件

        -从zip,jar等归档文件中加载.class文件

        -从专有数据库中提取.class文件

        -将Java源文件动态编译为.class文件

        关于类的主动使用

       

类的解析阶段:

在解析阶段java虚拟机会把类的二进制中的符号引用替换成直接引用。

 

类的初始化阶段

当java虚拟机初始化一个类时,要求它的所有的父类都已经被初始化了,但是这条规则不适用接口

初始化一个类 并不会初始化它所实现的接口

初始化一个接口时,并不会先初始化它的父接口

 

对子类主动使用会导致父类初始化

对父类主动使用不会导致子类初始化

只有当程序访问的静态变量或者静态方法确实在当前类或者当前接口定义时,才可以认为是对类或者接口的主动使用。

调用ClassLoader类的loadClass方法加载一个类,并不是对类的主动使用,不会导致类的初始化

上面的几点,只有在程序中才能真正的体现出来。

<pre name="code" class="java">package com.tgb.classLoader;
public class TestSix {

    static {
        System.out.println("Test static block");
    }

    public static void main(String[] args) {
        System.out.println(child3.a);
        child3.doSomethind();
    }
}

class Parent3 {
    static int a = 3;
    static {
        System.out.println("Parent3 static block");
    }

    static void doSomethind() {
        System.out.println("do something");
    }
}

class child3 extends Parent3 {

    static {
        System.out.println("Child3 static block");
    }
}

Test static block

Parent3 static block

3

do something

        上面是输出顺序,可能最大的疑惑就是在child3.a这段代码了,当调用a这个静态变量时,大家可能以为对child3的主动使用了,其实错了,只有当静态类或者变量存在child3时,才可以是对其的主动使用,但是静态变量a存在父类parent中,所以是对parent的主动使用了。输出parent3 static
block就不足为奇了。

        基础的一些概念在学习的时候可能不太注意但是如果真的在使用过程中,出现一些我们无法解释的现象时,回头看看基础的概念,问题就在其中

时间: 2024-08-26 23:38:46

Java再学习-JVM类加载和执行机制的相关文章

深入java虚拟机学习 -- 类的加载机制(续)

昨晚写 深入java虚拟机学习 -- 类的加载机制 都到1点半了,由于第二天还要工作,没有将上篇文章中的demo讲解写出来,今天抽时间补上昨晚的例子讲解. 这里我先把昨天的两份代码贴过来,重新看下: class Singleton { private static Singleton singleton = new Singleton(); //第一份代码的位置 public static int counter1; public static int counter2=0; private s

JVM类加载以及执行的实战

前几篇文章主要是去理解JVM类加载的原理和应用,这一回讲一个可以自己动手的例子,希望能从头到尾的理解类加载以及执行的整个过程. 这个例子是从周志明的著作<深入理解Java虚拟机>第9章里抄来的.原作者因为有丰富的经验,可以站在一个很高的高度去描述整个过程.而我只能以现有的水平,简单的理解这个例子. 如果读者感觉不错,那都是原作者的智慧:如果觉得不过尔尔,那就是我水平有限. 先说说日志.原先,我特别不喜欢在自己的程序里输出日志.写的时候那叫一个爽,可是一旦运行出错,那就麻烦了.因为不知道具体执行

Java再学习——随机面试题

1.final, finally, finalize的区别 final—是修饰符,可以修饰变量.方法和类. final类不能再派生出新的子类即不可当父类: final变量必须在声明时给定初值或在构造方法中赋值,在以后的引用中只能读取,不可修改. final方法不能重载. finally—在异常处理时提供 finally 块来执行收尾操作.如果抛出一个异常,那么相匹配的 catch 子句就会执行,而finally则是只要try代码块有执行(无论return与否),最后都会进入到 finally 块

Java再学习-反射机制

首先说到反射,大家肯定不会陌生,如果不知道反射,相信那些市面上常用的主流框架就不会出现了.废话不说,上主题! Java反射机制 运行时 判断任意一个对象所属的类 构造任意一个类的对象 判断任意一个类所具有的成员变量和方法 调用一个对象的方法 注意点:运行时,而不是编译时 首先概念性的东西,小编就不细说了,想了解的直接问度娘吧,直接上干货吧. 通过反射来进行方法调用的具体步骤: 1.首先要获取Class对象(手段比较多,例如通过forname手段和InvokeTester.class手段) 2.如

java虚拟机学习-JVM内存管理:深入Java内存区域与OOM(3)

概述 Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来. 对于从事C.C++程序开发的开发人员来说,在内存管理领域,他们即是拥有最高权力的皇帝又是执行最基础工作的劳动人民——拥有每一个对象的“所有权”,又担负着每一个对象生命开始到终结的维护责任. 对于Java程序员来说,不需要在为每一个new操作去写配对的delete/free,不容易出现内容泄漏和内存溢出错误,看起来由JVM管理内存一切都很美好.不过,也正是因为Java程序员把内存控制的

java虚拟机学习-JVM调优总结-调优方法(12)

JVM调优工具 Jconsole,jProfile,VisualVM Jconsole : jdk自带,功能简单,但是可以在系统有一定负荷的情况下使用.对垃圾回收算法有很详细的跟踪.详细说明参考这里 JProfiler:商业软件,需要付费.功能强大.详细说明参考这里 VisualVM:JDK自带,功能强大,与JProfiler类似.推荐. 如何调优 观察内存释放情况.集合类检查.对象树 上面这些调优工具都提供了强大的功能,但是总的来说一般分为以下几类功能 堆信息查看 可查看堆空间大小分配(年轻代

Java再学习——栈(stack)和堆(heap)

一.内存分配的策略 按照编译原理的观点,程序运行时的内存分配有三种策略,分别是静态的,栈式的,和堆式的. 静态存储分配是指在编译时就能确定每个数据目标在运行时刻的存储空间需求,因而在编译时就可以给他们分配固定的内存空间.这种分配策略要求程序代码中不允许有可变数据结构(比如可变数组)的存在,也不允许有嵌套或者递归的结构出现,因为它们都会导致编译程序无法计算准确的存储空间需求. 栈式存储分配也可称为动态存储分配,是由一个类似于堆栈的运行栈来实现的.和静态存储分配相反,在栈式存储方案中,程序对数据区的

Java再学习——深究static关键字

一.static关键字的用途 可以在没有创建对象的情况下来进行(方法/变量)调用.也就是,被static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问. 1,static修饰方法 static方法一般称作静态方法,由于静态方法不依赖于任何对象就可以进行访问,因此对于静态方法来说,是没有this的,因为它不依附于任何对象,既然都没有对象,就谈不上this了.并且由于这个特性,在静态方法中不能访问类的非静态成员变量和非静态成员方法,因为非静态成员方法/变

java虚拟机学习-JVM调优总结-新一代的垃圾回收算法(11)

垃圾回收的瓶颈 传统分代垃圾回收方式,已经在一定程度上把垃圾回收给应用带来的负担降到了最小,把应用的吞吐量推到了一个极限.但是他无法解决的一个问题,就是Full GC所带来的应用暂停.在一些对实时性要求很高的应用场景下,GC暂停所带来的请求堆积和请求失败是无法接受的.这类应用可能要求请求的返回时间在几百甚至几十毫秒以内,如果分代垃圾回收方式要达到这个指标,只能把最大堆的设置限制在一个相对较小范围内,但是这样有限制了应用本身的处理能力,同样也是不可接收的. 分代垃圾回收方式确实也考虑了实时性要求而