生有尽,业无穷:一条JVM指令引发的思考

Mhere 发布于:2019/06/20 15:30 ⋅ 886 阅读

#博客迁移#

“生有尽,业无穷”,第一次听说这句话时受到了强烈的震撼,那是在学校时管理学老师说的。

一、一个JVM指令

我不喜欢模糊的立场,却又怀疑过分肯定的答案——许知远

以前有个同事问我一个问题,他写了下面的代码

Parent parent=son;
parentMapper.insert(parent);

这段代码在执行的时候报错,提示不能把Son类型的插入到Parent表里,他很纳闷,都把son向上转型成Parent类型了,为什么还提示是Son类型呢?
我以前也遇到过这种坑,所以就直接告诉他说向上转型并不能改变对象的真实类型。为什么是这样的呢?当时事情都做完了,就想从字节码的层面找找原因。当时写了代码,然后执行javac、javap(查看代码及字节码),发现向上/向下转型那行代码的JVM指令都是invokespecial,这个指令表示调用初始化方法,但是向上转型调的是子类的初始化方法,就是向上转型后新的对象还是子类类型。向下转型调的是原始对象的类型的初始化方法。就是说不管是向上还是向下转型,新对象的类型和原始对象的类型还是一致的。
接着问题来了,invokespecial是怎么实现?Java的原理和Java代码的实现可以说是JVM的执行引擎来完成的,但是JVM执行引擎的原理和实现是用什么来做的呢?
这时想起了老师说的“生有尽,业无穷”。

二、死胡同与另一扇门

走进死胡同是令人沮丧的;打开新的一扇门是令人欣喜的。——我

很多技术都是以另一个或多个技术作为基础的。在一个领域里面穷根究底后总会遇到类似1+1=2的基础。遇到1+1就走进了死胡同,只有换个角度进入另一个领域才能打开新的一扇门。就比如Java基础是JVM,JVM基础是另一个领域一样。
但是进入一个领域到走进死胡同,再到进入另一个领域:

while(hasNextDoor()){
    openTheDoor();
}

这样会被累死的,整个IT里有无数个小领域,生有尽,业无穷。奈何?

三、知识结构的广度与深度

这时就是知识结构的问题了,知识结构的广度和深度。深度和广度是互相作用的,没有广度很难往深度上发展,有了深度以后,自然就会有广度。
由于各种原因,本人的知识广度是相当广的,并且自信比多我3年工作经验的人的广度还要广,和多我5年工作经验的人差不多。可以说是很NB的全栈工程师了。要在这些方面都深入发展是不可能的。

四、兼顾广度与深度:自我定位

磨刀不误砍柴工,但是如果拿刀砍白菜,谁磨刀谁是傻子。——知乎用户

怎么兼顾知识结构的广度与深度呢?
我觉得这要看个人的自我定位了。给自己的定位不同涉及到的知识广度和深度就自然不同。难就难在自我定位上。

附录

Java代码:

    public void upConvert() {
        Son son=new Son();
        Parent upConvert=son;
    }
    public void downConvert1() {
        Parent parent=new Parent();
        Son downConvert=(Son) parent;
    }
    public void downConvert2() {
        Parent sonInParent=new Son();
        Son downConvert=(Son) sonInParent;
    }

字节码:

  public void upConvert();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=3, args_size=1
         0: new           #4                  // class com/yuanye/Son
         3: dup
         4: invokespecial #5                  // Method com/yuanye/Son."<init>":()V
         7: astore_1
         8: aload_1
         9: astore_2
        10: return
      LineNumberTable:
        line 22: 0
        line 23: 8
        line 24: 10

  public void downConvert1();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=3, args_size=1
         0: new           #2                  // class com/yuanye/Parent
         3: dup
         4: invokespecial #3                  // Method com/yuanye/Parent."<init>":()V
         7: astore_1
         8: aload_1
         9: checkcast     #4                  // class com/yuanye/Son
        12: astore_2
        13: return
      LineNumberTable:
        line 26: 0
        line 27: 8
        line 28: 13

  public void downConvert2();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=3, args_size=1
         0: new           #4                  // class com/yuanye/Son
         3: dup
         4: invokespecial #5                  // Method com/yuanye/Son."<init>":()V
         7: astore_1
         8: aload_1
         9: checkcast     #4                  // class com/yuanye/Son
        12: astore_2
        13: return
      LineNumberTable:
        line 30: 0
        line 31: 8
        line 32: 13
}

已有 0 条评论

    我有话说: