121、Java虚拟机结束生命周期的几种情形?

  • 程序正常执行结束
  • 程序执行了System.exit()方法
  • 程序在执行过程中遇到了异常或者错误而异常终止
  • 由于操作系统出现错误从而导致Java虚拟机进程终止

122、详细介绍一下Java类的加载、连接和初始化的过程。

  • 加载:查找并加载类的二进制数据,实际上就是把类的class文件中的二进制数据从磁盘读到内存里面,并且将其放置在运行时数据区内,然后在内存中创建一个java.lang.Class对象(JVM规范并没有说明Class对象存放在哪里,HotSpot虚拟机将其存放在了方法区中,想必大多数人都会以为存放在了堆里面了吧,我也很迷惑)用来封装类在方法区内的数据结构。文件如果不存在,就直接抛出异常。
  • 连接:连接是一个比较复杂的过程,又可细分为三个阶段,验证、准备和解析。验证是为了确保被加载类的正确性,确保被加载的字节码文件没有被恶意的篡改,而且是符合JVM对字节码文件的要求;准备阶段是为类的静态变量分配内存,并将其初始化为默认值,这个时候类的实例还不存在,解析阶段是把类的符号引用转换为直接引用,所谓符号引用可以理解为一种间接的引用,直接引用就是通过指针的方式直接指向被引用的对象的内存的位置。
  • 初始化:为类的静态变量赋予正确的初始值。

虚拟化面试题 虚拟化试题及答案复习题1 虚拟化工程师面试_虚拟化面试题 虚拟化试题及答案复习题1

123、Java程序对类的使用方式分为哪几种?

  1. 主动使用(7种):
  • 创建类的实例
  • 访问某个类或者接口的静态变量,或者对该静态变量赋值
  • 调用类的静态方法
  • 反射(比如Class.forName("com.test.Test"))
  • 初始化一个类的子类,也算是对该类的主动使用
  • Java虚拟机启动时被标注为启动类的类(比如包含main方法的类)
  • JDK1.7开始提供了动态语言的支持:java.lang.invoke.MethodHandle实例的解析结果REF_getStatic,REF_putStatic,REF_invokeStatic句柄对应的类没有初始化,则初始化(了解一下就行了)
  1. 被动使用:除了以上七种情况,其他使用Java类的方式都被看作是对类的被动使用,都不会导致类的初始化!不会初始化,并不意味着不会加载和连接类,这一点要区分。

所有的Java虚拟机实现必须在每个类或者接口被Java程序“首次主动使用”时才初始化他们。

124、加载.class文件的方式有哪些?

  1. 从本地文件系统中直接加载(使用的最多)
  2. 通过网络下载.class文件
  3. 从zip,jar等归档文件中加载.class文件
  4. 从专有数据库中提取.class文件
  5. 将Java源文件动态编译为.class文件(动态代理)
  6. JSP文件先转化为servlet,然后再编译为class文件(JavaWeb开发的时候)

125、说出下面的程序的执行结果。

/**
 * @author YuZhansheng
 * @desc  考察静态代码块及引用的使用
 * @create 2019-03-14 14:28
 */
public class MyTest1 {
    public static void main(String[] args) {
        System.out.println(MyChild1.str);
    }
}

class MyParent1{
    public static String str = "hello world";
    static {
        System.out.println("MyParent1 static block");
    }
}

class MyChild1 extends MyParent1{
    public static String str2 = "welcome";
    static {
        System.out.println("MyChild1 static block");
    }
}

结果:

MyParent1 static block
hello world

解析:对于静态字段来说,本题中就是str,只有直接定义了该字段的类才会被初始化,本题中就是MyParent1这个类,本题中,是通过子类MyChild1来访问父类MyParent1里的str静态字段的,这种情况我们称之为对MyParent1的主动使用,并没有主动使用MyChild1,虽然里面出现了MyChild1.str,但是str这个字段却是在MyParent1中定义的。没有主动使用MyChild1,则不会对MyChild1进行初始化,静态代码块就不会执行,所以System.out.println("MyChild1 static block");这一句也不会执行。因此执行结果就是上面的了,再看下面一道。

126、说出下面的程序的执行结果。

/**
 * @author YuZhansheng
 * @desc  考察静态代码块及引用的使用
 * @create 2019-03-14 14:28
 */
public class MyTest1 {
    public static void main(String[] args) {
        System.out.println(MyChild1.str2);
    }
}

class MyParent1{
    public static String str = "hello world";
    static {
        System.out.println("MyParent1 static block");
    }
}

class MyChild1 extends MyParent1{
    public static String str2 = "welcome";
    static {
        System.out.println("MyChild1 static block");
    }
}

结果:

MyParent1 static block
MyChild1 static block
welcome

解析:由于字段str2是在子类里面定义的,因此一旦调用这个字段,就是对子类的主动引用,肯定会初始化子类,但是!!初始化一个类的子类的时候,会先初始化这个类,因此MyParent1也会被初始化,这就解释了为什么是上面的输出结果了。125、126两题算是对123题“Java程序对类的使用方式分为哪几种?”的一个验证吧。重点:当一个类在初始化时,要求其全部父类(直到Object类)都已初始化完毕了。

127、了解JVM参数吗?说出你知道的一个及其功能?

-XX:+TraceClassLoading 该虚拟机参数的用于追踪类的加载信息并打印出来。

我们以上面的125题为例进行讲解。在125题中,只对父类进行了初始化,子类并未进行初始,但是没有对子类进行初始化,是不是就代表了对子类也没有加载呢?对于这个问题,我们就可以使用 -XX:+TraceClassLoading来查看到底虚拟机加载了没有子类。首先在IDEA中配置一下:

虚拟化面试题 虚拟化试题及答案复习题1 虚拟化工程师面试_虚拟化面试题 虚拟化试题及答案复习题1_02

运行程序后查看打印的信息,打印出的信息很多,就是说所有加载的类都被打印出来了,不过大部分都是JDK内部的类,我这里只截取一小部分,如下所示:

虚拟化面试题 虚拟化试题及答案复习题1 虚拟化工程师面试_初始化_03

看到了没,三个类,Mytest1、MyParent1、MyChild1都被加载进了虚拟机。

128、讲解一下JVM参数写法的含义

这就考的有点偏了,了解一下吧。

JVM参数就只有三种形式,如下所示:

1、-XX:+<option> :表示开启option选项,JVM中有些是默认关闭的,你要使用的时候就要开启,比如127题中的参数“-XX:+TraceClassLoading ”,默认是不显示加载信息的,你要查看加载信息就要使用“+”,开启。
2、-XX:-<option>:同理,JVM中有些参数默认是开启的,有些情况下不需要开启,就使用“-”来关闭。
3、-XX:<option>=<value>:有些参数是以key-value形式给出的,比如设置堆内存的大小,这时候就需要使用这种形式的配置了。

129、Java的类加载器的种类都有哪些?

  1. 根类加载器(Bootstrap)--C++写的,我们看不到源码。负责加载JVM基础核心的类库(rt.jar)
  2. 扩展类加载器(Extension)--加载位置:jre/lib/ext,从java.ext.dirs系统属性所指定的的目录中加载类库,它的父加载器是Bootstrap。
  3. 系统(应用)类加载器(System/App):其父类是Extension,他是应用最广泛的类加载器,他从环境变量classpath或者系统属性java.class.path所指定的目录中加载类,是用户自定义加载器的默认父加载器。
  4. 自定义加载器(必须继承ClassLoader)

130、Java中为什么会有GC机制呢?

  • 安全性考虑;
  • 减少内存泄漏;
  • 减少程序员工作量。