00:00
那接着啊,咱们往下讲,下边一个呢,叫做类型转换指令啊,这里边儿咱们提的这个类型转换呢,主要呢,针对的是Java当中的基本数据类型,基本数据类型呢,我们说有八种对吧,那么八种当中呢,涉及到的一些类型之间的相互转换,就是咱们这里边提到的类型转换指令,好,那首先呢,我们来看这里边儿的一个说明。说呢,类型转换指令呢,可以将两种不同的数值类型进行相互的转换,对吧,这里边儿重点提到是数值类型。那咱们基本数据类型里边呢,其实主要的就是数值类型的,对吧,除了这个布尔类型呢,是比较特别的之外,剩下的我们说都是数值类型,而且呢,我们在讲到这个基本数据类型变量运算的时候呢,其实我们一开始也都是把这个布尔类型单独给它剔出来的,它是你说一个处加上个一,什么意思呢?其实没有什么意思,对吧,所以一般呢,我们都剔除布尔类型,所以这块呢,主要指的就是除了布尔类型之外的七种基本数据类型。
01:01
啊,这呢不多说,下面一个说这些转换操作呢,一般用于实现用户代码中的叫显示类型转换操作。显示类型转换,就是我们明确的将一个比如说是一个int型的一个变量,我们给它转换成是一个float。当然这呢在咱们Java中呢,叫做向上这个自动类型转换,对吧?那当然你也可以是由一个比如说float呢,再转换成是一个int,就是它的一个逆运算,这呢我们称为呢叫强制类型转换,那这两个操作呢,在咱们这里边呢,又起了个名字叫做宽化类型转换和窄化类型转换,宽化呢就好比是容量小的int转换成float,而容量大的float呢,转化成int呢,就称为叫窄化类型转化。OK,这是一个,然后或者呢,是用来处理字节码指令集中数据类型相关的指令无法与数据类型一一对应的问题。这里边呢,提到一个,比如说我们说一个BAT类型的,你要转化成是个long类型,那我们就得观察一下有没有对应的BAT往这个long类型转换的这个指令呢,那事实上我们发现呢,其实是没有的,就是严格上的一个bit转换成是个long是没有的,那这块呢,咱们在下边一个讲解当中呢,也会提到类似这样的问题,好,那下边呢,咱们来看一下具体的类型转化呢,分成的宽化类型转化和窄化类型转化。
02:24
首先呢,咱们来看一下这个宽化类型转换。看一下这个转换规则,说这个框化类型转换呢,主要呢,就是从小范围的类型向大范围的类型进行了转换,这呢以前呢,也通常我都称为呢,叫做自动类型提升,就是你将一个小范围的往大方向展呢,自动的就有一个转换了,就是称为我们这里边叫宽化类型转换,那主要的这个指令的话呢,这个大家会看到有这样的一些不需要呢,我们这个显示的去写一个,比如说像强转弧这样操作了,对吧,这个大家注意一下,但是我们如果去看一下这个自己码指令的话呢,还会有相关的一些这样的指令的信息,那是这样子的,一会儿咱们一看这个具体操作就知道了。
03:06
好,我们这块来分析一下看都有哪些,嗯,这里边提到了int类型往long类型,Float型、double型的一个转换,对应的呢,就是I to l to f f to d,这个一看大家应该都明白对吧?然后呢,Long类型到float和double的就是l to fl to d,然后float呢到double的就f to d啊很清楚对吧?那把这几个呢,总结在一起的话呢,我这写了一个简化图,这个大家直接看这个图就行,那我们刚才说的这三组,相当于呢,对应的就是int转化成long int转换成float int转换成double,这是一组,然后呢,Long转换成float long转换成double,这是第二组,第三组呢,就是float转换成double,没问题,对吧?那现在的这个指令呢,大家应该一看呢就明白。行,那基于咱们刚才说的这个基本的转换规则呢,咱们首先呢,来看一个具体的操作。啊,这呢,就是关于这个宽化类型转化,咱们这个代码当中的第一个,那就是说这个基本的测试,这个针对于这个宽化。
04:07
类型转换的基本测试,行,那大家来看一下,我这呢定义了一个int型的变量叫I是十,然后把这个I呢付给long float double。然后呢,我们上边不是有个L嘛,把这个L类型,也就long类型呢,转换成float,转换成double,然后以及呢,把这个float类型呢,也转换成double,这不就我们刚才看到的这三组嘛,是这意思吧,那这块呢,我们首先做一个编译。好编译完之后呢,我们在那做一个查看刷新一下,首先呢,我们来看一下这个叫UPCA1,就是针对我们这个操作。那这里呢,我们前面已经讲过的,包括这个压站和存储的这个操作,这个咱们就不具体的就是说的这么细致了,主要呢,我们看一下这个核心的操作,那这里边呢,像咱们把这个I呢,复制给long,你看这里边对应的就是I to l没问题对吧?然后下边呢,I复制给Fi toi复制给wi to d。
05:04
没问题,然后把这个long类型呢复制给float long类型复制给float long to f,然后long类型复制给double。对吧,然后这个float型复制给double。没问题对吧?行这呢就是我们主要看的这几个结构,当然相应的会涉及到我们往操作站里边去压入数据,然后把这个数据呢,又保存在我们的这个局部变量表当中,相应的涉及到了比如说浪类型和double类型,人家呢该占两个这个槽位的,你就占两个槽位,比如说你看这块呢,我们浪类型你存储到这个这个所引为二的位置了,你下一个是flow的类型,那就是该四了,因为二跟三它都被这个浪类型占用了,对吧?所以这块这个细节呢,大家再关注一下就可以了,行这呢,就是咱们说这个基本的一个类型的一个测试。好,那接着呢,咱们再往下看,这呢,关于这个宽化类型转化呢,涉及到一个精度损失的问题。精度损失,按说呢,怎么把容量小的往容量大的这里边转,还会有精度损失的问题呢,来咱们看一下。
06:04
说这个宽化类型转换啊,不会,因为这个是不会因为超过目标类型最大值而丢失信息的,比如说我们从in的类型转换成long类型,或者呢,从in的类型转换到W类型,不会呢,丢失任何信息,那转化后的这个结果呢,是非常精确的。呃,这个大家能理解的,其实也正常就是这种情况对吧,这里边儿主要提到什么问题呢?就是不会因为这个目标过大而丢失信息,正常来讲呢,你这个转化到的这个类型,它不就是存储的范围比左边这个更大吗?对吧,正常来讲其实是这样子的,那还有哪些特殊情况呢?大家看一下。说呢,从这个int long类型转化成float,或者呢,从这个long呢转成double的时候,将可能发生精度损失,或者叫精度丢失。那可能会丢失掉,呃,几个最低有效位上的值,转化后呢,按照这样一个这个国际上的这样一个标准,四舍五入的方式上取得正确的这个数值数值,对吧?那这里边儿大家你想一个问题啊,咱们这个long类型呢,是不是在讲Java语言的时候,咱们说它是八个字节对吧?那咱们在底层存的话呢,也确实是两个槽位,那我们这个flow的类型呢,你知道它其实是四个字节,相当于是一个槽位,那这里边儿呢,其实就存在一个偏差,明明我们这个浪类型使用的内存就是占用的这个空间更大,那凭什么你转化成这个float型的时候呢,这个使用的空间小了,反而float体型的容量更大。
07:29
就是你范围既小还更精确,这个事儿不可能不可能兼顾的,对吧,所以我们从这个浪类型,你往float的类型,乃至于说你是in的型往float的类型转的时候呢,它既然容量大了,它的精度呢,就不会这么精准。那如果大家呢,之前了解过呢,就知道咱们float呢,它有一部分呢,是表示这个底数,另外一部分呢,是来表示指数,所以呢,它可以存储的范围更大,但是相应的问题就是它精度呢,就没有这么高了。那我们在Java当中如果涉及到精度非常高的问题呢,你用big decimal来替换就OK了,对吧?那这里边儿关于基本数类型精度的问题,在宽化类型转化上呢,也是存在的。
08:08
大家来看一下我下边写的这个例子,咱们呢是来这个刻画,或者来这个举例这个精读损失的问题,好,那我们看一下我这呢举了一个in的型的一个数值,1231231233组,这呢是在我们这个in的范围内,那如果说你这个数过大的时候呢,本身编译呢,是不是就不通过了,对吧?那我这呢,一共是有三组,然后呢,我把这个I呢复制给一个float类型,咱们打印一下这个float的一个值,我这呢用了一个单一测试方法,嗯,下边这个呢,咱们也可以暂时先给它都注释一下,行,把这个呢我们做一个执行。好出来结果了,那这时候呢,大家就会发现我们这个没有报异常,但是它的精度呢,确实出现了损失。那本身的话呢,应该是123 123 123,你看第三组的123,那个三呢,是不是就损失了呀,这里边儿呢,就是十的八次方,实际上对应的结果就是我们如果用一个整数来进行刻画的话呢,实际上这个结果就是变成了123 123120。
09:10
就成这个数据了,所以这呢就发生了一个精度的损失。好这呢,就我们说的这个问题,然后咱们接着呢,把下边这个打开。这个下边这个浪类型呢,我写了12344组,这个123这个数呢,其实也挺大的,这个数呢,我把它呢复制给一个double类型,看看此时呢,会不会出现这个精度的损失。一共是四组,那你看123123 12313没问题,这时候呢,没有发生这个精度的损失,那主要是因为我们这个值呢不够大,毕竟这个double类型呢,我们称为叫双精度,它比这个flow的类型呢,它这个精度会更高一些,那在刚才这个举例当中,它没有发生精度的损失,然后我这块呢,写了123456组,这个数据呢,没有超过浪的范围,但是呢,我们转化成double的时候。那这时候大家再看123啊,一组两组,这一组的话呢,你看这个三就丢失掉了,对吧,所以呢,这个时候呢,运算的结果相当于就是我们这个值拿过来以后呢,最后这个。
10:11
改成一个零了是吧,就成这样了,也发生了一个精度的损失问题。OK,这个大家呢,注意一下我们说的这个场景,就是说在宽化类型转换这块呢,仍然是会发生精度损失的啊,仍然会发生精度损失的问题,但是呢,我们虽然会发生精度损失,嗯,需要注意的就是不会抛出运行时异常。就是我们从容量小,网容量大这块呢,是不会出现异常的,这个呢也是一个基本常识,大家应该也明白啊,不多说,然后再往下这块呢,咱们就提到一个点,大家会发现呢,刚才讲这个过程当中啊,嗯,不是刚才说了属于这个数值类型的转换吗?那你数值类型那很自然而然的,不就还有这个BAT short,乃至于说这个char类型也是啊。但是我们在这个指令当中,大家会发现没有任何关于B图什么,C图什么或者S图什么的,对吧,那这块怎么理解呢?这个跟咱们前面讲的相关的一些指令是不是又是一脉相承的了。
11:10
也就是说呢,我们从BA叉或者是short以往int类型转换,乃至于说呢,往long float double类型转换,这个我们对应的指令呢,首先说是不存在的。首先说是不存在的,也就是说呢,我们BAT short,或者是差这个类型,在咱们指令当中,对应的资金码指令当中,乃至于是我们真正把它存储到内存当中的时候,咱们都看成是一个int类型来进行的处理。对吧,都看成是一个int类型来进行的处理,那也就意味着比如说我们把一个BAT类型的数据转化成long的话呢,大家会发现底层对应的就是IL这样的一个指令。来我这儿呢,也写了一个例子。在这写的是吧,这儿呢,就是针对于。哎,针对于我们说BAT这个short。
12:01
我这没写具体的差了啊,等这个转换为这个高级类型。或者叫容量大的类型啊,类型时我们说这个对应的指令,或者呢,就是将这个此类型。是不是看做这个int类型处理啊,那相应的这个指令的话呢,那就是I to什么了,那我这呢,声明了一个bad类型的一个B,把它转换成是一个I,把它转换成个long,把它转换成个double,那我们这时候看一下它的这个情况,Up cost3。在这儿呢,对吧,打开这个code行,那这个代码比较少,咱们就整体来分析一下吧,这呢是我们说叫局部变量表,这呢我们称它叫操作入站,首先的话呢,我们在局变量表这里边角标012,这我就先写这样的几个位置,首先呢,这个有个Z,这是第一个位置了,然后接下来呢,我们在这个角标一的位置呢,这不有个BY的类型的B,对吧?这个B呢,有个具体的值啊,这个值呢,你得看你具体是几了,调离方法的时候呢,给大家附上值,举个例子,比如说这个值是十。
13:04
我们调研方法的时候呢,负的值是十,好,然后呢,接下来我们看这个方法体里边一上来I漏的下划线一把这个十呢,是不是就加入到我们这个操作站了,十就过来了,嗯,接下来的话呢,把这个S到二,就是把我们这个十呢在出站,把它保存在角标为二的局部变量表当中,那这个呢,就是十,这个其实对应的就是我们这个I。那在我们把这个bit类型转化成int类型的时候,大家会发现这里边儿没有任何的指令。你看对吧,没有任何的指令,所以看似呢,这是一个数据类型的一个提升,或者我们叫一个括号类型转换,但实际上呢,没有对应的指令支持,相当于我们就把BY类型就看作是了int类型。就看作是in的类型,直接呢就转了行,下一个呢,就是我们,哎这个你你一保存了,这就没有了吧,然后接下来的话呢,I的一,咱把这个一的的位置,这个矢呢又拿进来。接下来的话有个I to l,那我们在代码层面看到这个B呢,是一个bad类型,转化成是一个long,好像似乎应该是b to l,但是我们说根本没有这样一个指令,那只有这个把这个BAT看成是int类型的这个I to l了,所以呢,我们把这个十呢拿过来就放到这儿,对吧,这呢就是一个十。
14:14
那这个是,然后这个呢,就也没有了。行对吧,然后再接下来的话呢,这个我们保存在角B为三的位置,这个是咱们的这个L了啊,然后再I的一,再把我们这个角标为一的这个十呢,给它拿过来。然后来了,接下来呢,这叫I to d,那还是那个意思,把它看成是一个in的类型,那转换成是一个W类型,就I to d,然后再接着呢,做一个保存,注意这个保存呢,你看这个值是五,因为我们这个long类型呢,是不是要占两个槽位啊,所以角标为五的这个时候呢,这呢咱们又放了个十,哎是个W类型,W呢是不是也占两个槽位,这还有个六呢,这呢是我们这个D的一个占用。在这呢,就是我画的这样一个图,应该是比较清楚的,那下边这个呢,是针对于这个short的类型,其实呢,原理是一样子的,那我们简单来说明,那我们这呢,是一个short类型,你转换成是一个I类型的时候呢,这没有任何的这个指令去支持,对吧?然后再把short类型转换成long类型的时候,还是I图L,把short类型转换成flow的类型,那还是I to f。
15:16
那跟我们这个bad类型呢,是一样子的。行,那关于这个char类型呢,我就不多去举例子了,这个大家呢,应该是类比着就能知道这个场景对吧?好,这呢就是咱们说的这个情况啊,那为什么这个没有by short char呢?这个咱们前边其实也都解释过了,无外乎就是这样两个情况,第一个的话呢,就是咱们在其实我常说的其实是这个指令对吧?哎,这个原因就是我们在这个具体的把它往内存中去放的时候呢,你败的也好,差也好,少的也好,咱们说呢都讲叫槽位,槽位一个槽位呢,是一个最基本的单位了,它是占四个字节的。那也就是说呢,咱们像bad short叉它们这三种类型,这个你们在内存中存的话呢,也是以四个字节为最小的单位了,那四个字节呢,其实就是我们int的这样一个范围,所以本身呢,就把你们看成是一个int类型这个范围去存储的就是,呃,名正言顺是吧,就是完全可以用。
16:09
那这最低的就是32倍了,所以这个我们把它都看成是in的是没问题的,那另外一个方面呢,就是这三种类型。这三种类型的话呢,如果我们也去分配相关的一些B图什么,C图什么,呃,这个s to什么等等这样的一些指令的话呢,实际上呢,会使得咱们整个的一个字节码指令这块就偏多了,这个我们随便点一个,咱们进入这个章节里边,这不是说过有这么这么多这个指令,那这个指令的话呢,咱们说是用一个字节来表示的,咱们一开始也讲过,那就意味着最大呢是256,你不能超过这个数了,那咱们现在已经有200多个了,你要是再把这些呢,再加上,很有可能就导致我们这就不够了,乃至说以后我们扩容的这个。可能性都没有了,因为以后我们可能还会补充一些,随着Java语言的变化,我们去补充一些这个指令的,对吧,像我们讲方法的时候呢,这里边提到一个叫dynamic。
17:04
这样一个指令,这呢就是我们这个期以后呢,咱们补充进来的,那以后呢,你要是不给留一些空余的话呢,呃,再添加没有空间了,那显然不可以对吧,所以尽量呢,我们也没有必要呢,去提供他们三个类型往这个高类型转换的这个指令行,这儿呢,就咱们说的这个宽化类型转换,咱平时呢经常用,那对应的这个代码层面呢,是怎么体现的,包括呢哪些呢,没有具体的指令啊,这个大家呢,一看应该是都清楚啊,这就可以了。
我来说两句