• 丨落灬小莫
    2018-07-23
    当替换为2的时候无输出
    当替换为3的时候打印HelloJava及HelloJVM
    猜测是因为将boolean 保存在静态域中,指定了其类型为'Z',当修改为2时取低位最后一位为0,当修改为3时取低位最后一位为1
    则说明boolean的掩码处理是取低位的最后一位

    作者回复: 对的!

     4
     197
  • 追梦
    2018-10-21
    有个地方初看不易看懂,我来解释下:
        作者一开始放的“吃没吃饭”的例子中boolean变量是局部变量,存放在Java方法栈的栈帧中的局部变量区,占据一个数据单元,无需做掩码;最后的例子中boolean变量是成员变量,存储在堆中的对象实例里,占有一个字节,且需要对最后一位做掩码
     2
     40
  • 金蝉子
    2018-07-23
    老师可以讲下ASM、Unsafe和CAS的底层原理吗?这块儿一直是个拦路虎,谢谢!

    作者回复: ASM你指的是那个字节码工程包吗?是的话那就是一个提供了字节码抽象的工具,允许用Java代码来生成或者更改字节码。JDK里也会用到ASM,用来生成一些适配器什么的。我印象中代码覆盖工具JaCoCo也是用ASM来实现的。

    Unsafe就是一些不被虚拟机控制的内存操作的合集。具体想要了解哪个API?

    CAS可以理解为原子性的写操作,这个概念来自于底层CPU指令。Unsafe提供了一些cas的Java接口,在即时编译器中我们会将对这些接口的调用替换成具体的CPU指令。

     1
     36
  • 东方
    2018-07-23
    Unsafe.putBoolean和Unsafe.puByte是native实现

    putBoolean和putByte也是通过宏SET_FIELD模板出的函数

    #define SET_FIELD(obj, offset, type_name, x) \
      oop p = JNIHandles::resolve(obj); \
      *(type_name*)index_oop_from_field_offset_long(p, offset) = truncate_##type_name(x)

    unsafe.cpp中定义宏做truncate
    #define truncate_jboolean(x) ((x) & 1)
    #define truncate_jbyte(x) (x)
    #define truncate_jshort(x) (x)
    #define truncate_jchar(x) (x)
    #define truncate_jint(x) (x)
    #define truncate_jlong(x) (x)
    #define truncate_jfloat(x) (x)
    #define truncate_jdouble(x) (x)

    综上:unsafe.Put*不会对值做修改
    ------------------------------------------------------------------------------------
    getBoolean和getByte也是通过宏GET_FIELD模板出的函数

    #define GET_FIELD(obj, offset, type_name, v) \
      oop p = JNIHandles::resolve(obj); \
      type_name v = *(type_name*)index_oop_from_field_offset_long(p, offset)

    综上,unsafe.Get*不会对值做修改
    ------------------------------------------------------------------------------------
    验证:
    unsafe.putByte(foo, addr, (byte)2); // 设置为: 2
    System.out.println(unsafe.getByte(foo, addr)); // 打印getByte: 2
    System.out.println(unsafe.getBoolean(foo, addr)); // 打印getBoolean: true

    unsafe.putByte(foo, addr, (byte)1); // 设置为: 1
    System.out.println(unsafe.getByte(foo, addr)); // 打印getByte: 1
    System.out.println(unsafe.getBoolean(foo, addr)); // 打印getBoolean: true
    ------------------------------------------------------------------------------------
    疑问:
    if(foo.flag)判断,使用getfield    Field flag:"Z",执行逻辑等于:0 != flag
    if(foo.getFlag())判断,使用invokevirtual    Method getFlag:"()Z",执行逻辑等于: 0 != ((flag) & 1)

    求大神帮忙解答

    --------------------------
    附getFlag jasm码:
    public Method getFlag:"()Z"
        stack 1 locals 1
    {
            aload_0;
            getfield    Field flag:"Z";
            ireturn;
    }



    https://gist.github.com/qudongfang/49635d86882c03e49cff2b0f7d833805
    展开

    作者回复: 研究得非常深入!

    Unsafe.putBoolean会做掩码,另外方法返回也会对boolean byte char short进行掩码

     1
     29
  • Kyle
    2018-07-23
    老师,文中看你说到:
    “也就是说,boolean、byte、char、short 这四种类型,在栈上占用的空间和 int 是一样的,和引用类型也是一样的。因此,在 32 位的 HotSpot 中,这些类型在栈上将占用 4 个字节;而在 64 位的 HotSpot 中,他们将占 8 个字节。”

    但是我记得boolean在内存中占1字节,char占2字节,这里是什么个意思?

    作者回复: 你说的是在堆里的情况。在解释器栈上是不一样的。至于原因吗,主要是变长数组不好控制,所以就选择浪费一些空间,以便访问时直接通过下标来计算地址。

    
     19
  • 匿名小板凳
    2018-09-12
    这节看的很吃力,对什么掩码,子码,反码,补码都换给大学老师了。
    
     18
  • Geek_dde3ac
    2018-07-23
    你好,在内存中都是0,那么是如何区别是哪种类型数据的呢?

    作者回复: 内存中是不做区分的。Java程序想要把它解读成什么类型,它就是什么类型。

    
     17
  • life is short, e...
    2018-09-14
    老师你好,我刚来订阅,所以才开始看。
    有一个疑问,您的原文“因此,在 32 位的 HotSpot 中,这些类型在栈上将占用 4 个字节;而在 64 位的 HotSpot 中,他们将占 8 个字节。”。但是有一句话,java一次编译,到处运行。计算机位数不一样的话,导致一样类型的size不一样,还可以到处运行吗?这里指的到处运行,是不是需要同位啊?比如32位的编译只能在32位的机器上运行,64只能在64的上运行。能互相兼容运行嘛?
     3
     10
  • 落叶飞逝的恋
    2018-07-24
    其实那个boolean的true虚拟机里面为1,也就是if(true==吃了没)其实可以替换成if(1==2)这样理解吧

    作者回复: 对的!

    
     10
  • Invincible、
    2018-11-29
    为什么我不能让boolvalue=2或者3……

    作者回复: 因为javac不支持这种操作,它把boolean是用int实现的这种虚拟机的实现细节给隐藏起来了,从而使得在语言层面没有这种会引起歧义的值。

    
     8
  • andy
    2018-09-13
    我替换成2和3,都只能打印出一个Hello Java为什么呢?下面是AsmTools反编译代码
    super public class Foo
            version 52:0
    {

    static Field boolValue:Z;

    public Method "<init>":"()V"
            stack 1 locals 1
    {
                    aload_0;
                    invokespecial Method java/lang/Object."<init>":"()V";
                    return;
    }

    public static Method main:"([Ljava/lang/String;)V"
            stack 2 locals 1
    {
                    iconst_2;
                    putstatic Field boolValue:"Z";
                    getstatic Field boolValue:"Z";
                    ifeq L18;
                    getstatic Field java/lang/System.out:"Ljava/io/PrintStream;";
                    ldc String "Hello, Java!";
                    invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V";
            L18: stack_frame_type same;
                    getstatic Field boolValue:"Z";
                    iconst_1;
                    if_icmpne L33;
                    getstatic Field java/lang/System.out:"Ljava/io/PrintStream;";
                    ldc String "Hello, JVM!";
                    invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V";
            L33: stack_frame_type same;
                    return;
    }

    } // end Class Foo
    展开
     1
     8
  • dong
    2018-07-27
    感觉"吃饭了"例子,弄得有点饶了。也有些地方语句的起承转合不是很通顺,个人理解。

    作者回复: 谢谢建议

    
     8
  • 杨春鹏
    2018-07-26
    局部变量中基本数据类型存储在栈中,变量的变量名(引用符号)和变量值(字面量)都存储在栈中。
    局部变量中引用数据类型的引用地址存储在栈中,对象的实例数据存储在堆中,类型数据存储在方法区
    全局变量的基本数据类型和引用数据类型,都存储在堆中。
    不知理解的是否正确
     1
     7
  • 别处
    2018-07-24
    以下两个引至本文内容:
    1、在 Java 虚拟机规范中,boolean 类型则被映射成 int 类型。
    2、在 HotSpot 中,boolean 字段占用一字节,

    问题:一个是int类型,一个是一个字节(32位系统的话就是byte类型),是没讲透还是错误?

    作者回复: 多谢指出。严格来说,前者指的是计算的时候被映射成int类型,后者指的是存储到堆中是一个字节。

    
     6
  • 迷上尼古丁的味道
    2019-02-22
    下面这段中0x8000000是不是少写了一个0呢

    前者在 Java 里是 0,后者是符号位为 1、其他位均为 0 的浮点数,在内存中等同于十六进制整数 0x8000000(即 -0.0F 可通过 Float.intBitsToFloat(0x8000000) 求得)。
    
     4
  • 志远
    2018-07-23
    NaN 有一个有趣的特性:除了“!= 始终返回 true”之外,所有其他比较结果都会返回 false。这句话好拗口啊,双引号的标点符号有问题吧

    作者回复: 多谢指出!应该是 “!=“

    
     4
  • Arvin
    2018-10-18
    当改为2或者3时则出现编译错误是则么回事!!!!
    
     3
  • crystal
    2018-08-27
    老师,有个问题请教:第一个例子将过饭没改为2,会输出吃过了;第二个例子将boolValue改为2,却不输出信息。两个变量值都是2,为什么输出的结果会不同?
    
     3
  • 梧桐树
    2018-07-26
    如果64位处理器,long 和double和其它类型一样都是8个字节码在栈中
    
     3
  • 沉淀的梦想
    2018-07-25
    为什么我替换成2和3,但是现象和第一讲的时候一样呢?都只能打印出一个Hello Java,我反复检查也没发现什么问题,这有可能是什么原因呢?
    
     3
我们在线,来聊聊吧