jdk16全面学习之jls的第五章Conversions and Contexts


  这一章其实是对第四章类型变量值的进一步补充,包括了类型转换过程中的精度丢失等.主要分为两部分,一是在转换过程中的精度问题,二是jvm本质的类型转换规则.

1 转换中的精度丢失

  这里的转换主要针对数值而言,比如float转为int时发生的精度丢失.运行如下代码Float2Int.java


public class Float2Int {
}
class Test5_1 {
    public static void main(String[] args) {
        int i = (int)12.5f;
        System.out.println("(int)12.5f==" + i);
        float f = i;
        System.out.println("after float widening: " + f);
    }
}

  运行结果为
在这里插入图片描述
  可见,从int转为float时精度丢失了,但是接下来的一个语句就深入的多了,一时半会可能看不明白.
  float f = i;
  这个语句“应该”是有毛病的,因为不能把int直接赋值给float类型.下面会详细说明这么做的原因.

2 jvm类型转换规则详述

  先把上面的float f = i;搁置一下,来看在第四章分析时举过的例子,运行代码TransferDeep.java


public class TransferDeep {
}

interface Colorable {
    void setColor(byte r, byte g, byte b);
}

class Point {
    int x, y;
}

class ColoredPoint extends com.company.c5.Point implements com.company.c5.Colorable {
    byte r, g, b;

    public void setColor(byte rv, byte gv, byte bv) {
        r = rv;
        g = gv;
        b = bv;
    }
}

class TestThis5_2 {
    public static void main(String[] args) {
        com.company.c5.Point p = new com.company.c5.Point();
        com.company.c5.ColoredPoint cp = new com.company.c5.ColoredPoint();
        p = cp;
        if (p instanceof ColoredPoint) {
            System.out.println("p is ColoredPoint object");
        } else {
            System.out.println("p not");
        }
        //cp = p;
        //ColoredPoint p1 = (ColoredPoint) p;
        //cp = p1;
    }
}

  运行结果如下
在这里插入图片描述
  这说明p是ColoredPoint类型的对象,现在把//cp = p;的注释放开,得到
在这里插入图片描述

2.1 规则一: 类型和指针分离

  可见,此时在右值p依然被视为Point类型,而不是ColoredPoint类型,这说明jvm是变量类型和指针是分离的,也就是说变量的值的类型不一定是变量自身的类型,这句话有些绕.
  一句话,cpp使用模版分离变量的类型和变量值的类型.jvm沿用此规则不足为奇,真正重要的是下面的规则.

2.2 规则二: 左值屏蔽右值

  接着把//ColoredPoint p1 = (ColoredPoint) p;和//cp = p1;的注释放开,把cp = p注释掉,再运行就没问题了.
  可见,在java语言层面,所谓的上溯和下溯,本来就是指子类转为父类和父类转为子类,但是这里面有一个关键点,被转化的一定在右边,转为的结果一定在左边.
  这又回到了cpp的左值和右值的问题,左值一定是变量,有类型和值,右值不是变量,但是有值.jvm正是利用了这一点完成了前面在第四章所说的屏蔽,也就是利用左值来屏蔽右值,把左值当做掩码来处理右值,因为右值只有值,没有类型(不准确,但是可以先这么认为),所以只能拿左值来进行操作.
  直观上看,ColoredPoint p1 = (ColoredPoint) p是把p转为了子类,因为之前就已经赋值了子类的地址,cp = p1就可以进行了,因为同为一样的子类了.再深入分析一下直接进行cp = p为什么不行,首先是cp为子类,无法屏蔽右值p的父类,也就是这挡板本身就比要遮挡的对象都大.其次由于类型和指针分离,在类型上也会产生逻辑上的矛盾,所以在设计上这种直接操作就不允许出现.

2.3 规则总结

  至此,可以总结jvm层面的类型转换规则:
  1 类型和指针分离
  2 左值屏蔽右值
  3 方法表权限修改
  回到float f=i,i本身就是float转换而来,所以再复制给一个float类型,自然不会有什么问题.

3 总结

  Java语言层面的类型转换无非就是子转父或父转子,表面上看,子转父可以直接转,而父转子的前提是父类对象为子类的指针,简单说就是父类本来就是从子类而来.这一现象的背后则是jvm层面的转换规则在起作用,这一套规则灵活使用了cpp的模版语法,更注重的则是设计的内在逻辑.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值