深入拆解java虚拟机

本文章为学习极客时间-郑雨迪《深入拆解java虚拟机》的学习笔记。

1.boolean类型的变量编译后实际是int类型.

在java中,boolean 类型编译后字节码中实际存的是int类型。0表示flase,1表示true

有如下代码:

    boolean flag = true;

    If(flag) System.out.print(“hello java”);

反编译编译后的class文件可以看到:

    Int I = 1;

    If(I != 0){

        System.out.print(“hello java”);

    }

那么如果我这样写:

    boolean flag = true;

    If(flag == true) System.out.print(“hello java”);

反编译后的class代码是什么呢?

    Int I = 1;

    If(I == 1){

        System.out.print(“hello java”);

    }

2.类的初始化仅会被执行一次,因此这个特性被用来实现单例的延迟初始化。

    例:public class Singleton {

      private Singleton() {}

          private static class LazyHolder {

                static final Singleton INSTANCE = new Singleton();

          }

      public static Singleton getInstance() {

            return LazyHolder.INSTANCE;

      }

    }

那么类何时会被初始化呢?JVM规范枚举了下述多种触发情况:

1.当虚拟机启动时,初始化用户指定的主类

2.当遇到用以新建目标类实例的new指令时,初始化new指令的目标类

3.当遇到调用静态方法的指令时,初始化该静态方法所在的类

4.当遇到调用静态字段的指令时,初始化该静态字段所在的类

5.了类的初始货会触发父类的初始化

6.如果一个接口定义了default方法,那么直接实现或间接实现该接口的类的初始化,会触发该接口的初始化

7.使用反射API对某个类进行反射调用时,初始化这个类

8.当初次调用MethodHandle实例时,初始化该MethodHandle指向的方法所在的类。

看下边代码:

$ echo '

public class Singleton {

  private Singleton() {}

  private static class LazyHolder {

    static final Singleton INSTANCE = new Singleton();

    static {

      System.out.println("LazyHolder.<clinit>");

    }

  }

  public static Object getInstance(boolean flag) {

    if (flag) return new LazyHolder[2];

    return LazyHolder.INSTANCE;

  }

  public static void main(String[] args) {

    getInstance(true);

    System.out.println("----");

    getInstance(false);

  }

}' > Singleton.java

$ javac Singleton.java

$ java -verbose:class Singleton

问题 1:新建数组(第 11 行)会导致 LazyHolder 的加载吗?会导致它的初始化吗?

答:会加载但不会初始化

3.java 字节码中与调用相关的指令共有五种

    1.invokestatic:用于调用静态方法

    2.invokespecial:用于调用私有方法、构造器,以及使用super关键字调用父类的实例方法或构造器,和所实现接口的默认方法。

    3.invokevirtual:用于调用非私有实例方法

    4.invokeinterface:用于调用接口方法

    5.invokedynamic:用于调用动态方法

 

重载的方法在编译过程中即可完成识别。具体到每一个方法调用,Java 编译器会根据所传入参数的声明类型(注意与实际类型区分)来选取重载方法。选取的过程共分为三个阶段:

在不考虑对基本类型自动装拆箱(auto-boxing,auto-unboxing),以及可变长参数的情况下选取重载方法;

如果在第 1 个阶段中没有找到适配的方法,那么在允许自动装拆箱,但不允许可变长参数的情况下选取重载方法;

如果在第 2 个阶段中没有找到适配的方法,那么在允许自动装拆箱以及可变长参数的情况下选取重载方法。

如果 Java 编译器在同一个阶段中找到了多个适配的方法,那么它会在其中选择一个最为贴切的,而决定贴切程度的一个关键就是形式参数类型的继承关系。

 

如果子类定义了与父类中非私有方法同名的方法,且参数相同:

如果这两个方法都是静态的,那么子类中的方法隐藏了父类中的方法

如果这两个方法都不是静态的,那么子类的方法重写了父类的方法。

 

java虚拟机识别方法的关键在于类名、方法名以及方法描述符

Java虚拟机和java语言不同,java语言不允许相同名字和参数的方法同时出现,但java虚拟机允许。对于调用这些方法的字节码来说,由于字节码所附带的方法描述符包含了返回类型,因此java虚拟机能够准备的识别目标方法。

 

4.java虚拟机是如何处理异常的

在编译生成的字节码中,每个方法都附带一个异常表,由from、to、target、type构成。from和to表示try代码块的开始和结束位置,target表示异常处理开始位置,type则指的是异常的类型。

 

后续本文会持续更新~

参考文献:

1.极客时间 郑雨迪 深入拆解java虚拟机。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值