一个简单而有趣的类型转换问题

时间:2021-07-28 17:25:21
默认的整数值类型是int,默认的小数值类型是double。
int a = 56; //数值56默认为int类型
double d = 3.14; //数值3.14默认为double类型



下面问题来了:
float f = 3.14; //编译通过不了。因为无法将一个double类型的值赋给一个float类型的变量。

short s = 56; // 编译可以通过。这是为什么呢?将一个int类型的值赋给一个short类型的变量不损失精度么?为什么可以通过编译呢?

22 个解决方案

#1


3.14默认是double类型,你把double类型数据复制给float当然不行,float f = 3.14f;这样就行了。
给short赋值,只要在-32768到32767之间就没问题

#2


整数就没什么精度了吧,
不过short s = 100000;好像不可以

#3


short s = 56;没有问题啊,56在short能表示的范围之内。

#4


引用 1 楼 xulong1 的回复:
3.14默认是double类型,你把double类型数据复制给float当然不行,float f = 3.14f;这样就行了。
给short赋值,只要在-32768到32767之间就没问题


谢谢你的回答,但没说到本质啊。
我也知道将double类型的数值赋给float类型的变量当然不行,但将int类型的数值赋给short类型的变量就可以?
大范围的类型值赋给小范围的类型变量时不是要强制类型转换么?

#5


引用 3 楼 zhiqiu 的回复:
short s = 56;没有问题啊,56在short能表示的范围之内。


那 3.14也在float表示的范围内啊~ 呵呵

#6


引用 5 楼 u010134240 的回复:
Quote: 引用 3 楼 zhiqiu 的回复:

short s = 56;没有问题啊,56在short能表示的范围之内。


那 3.14也在float表示的范围内啊~ 呵呵



3.1333333333333333   <   3.14

能用float表示么?小数一般说的也是精度。



#7


int a = 56; //数值56默认为int类型  
我怎么不知道??

#8


引用 7 楼 she383 的回复:
int a = 56; //数值56默认为int类型  
我怎么不知道??


Java语言的整型常量本来就默认是int型的,Java浮点型常量默认是double类型。

int a = 2147483647;//编译通过
int a = 2147483648;//编译不通过

这难道还说明不了问题么。

#9


一个简单而有趣的类型转换问题是我没把问题描述清楚么?

其实总结一下就是:
short s = 56; //为什么能通过编译?int类型的数值56 为什么能直接赋给 short类型的变量s 而不需要强制类型转换?

作为对比,float f = 3.14; 都通不过编译 , 必须写成  float f = (float)3.14; 才行。

#10


Java语言是一种强类型的语言。强类型的语言有以下几个要求:
变量或常量必须有类型
要求声明变量或常量时必须声明类型,而且只能在声明以后才能使用。
赋值时类型必须一致
值的类型必须和变量或常量的类型完全一致。
运算时类型必须一致
参与运算的数据类型必须一致才能运算。

在整数之间进行类型转换时,数值不发生改变, jvm会自己做个隐式转换的
Java常用的数据类型,都是有固定顺序的,低类型向高类型转,可以认为是隐式;高类型要转成低类型,必须要显示的转换。

你在

int a = 56; //数值56默认为int类型 ?? 你这是定义a是int类型
short s = 56; //你这是定义s是short类型 

56是个常量 

从汇编角度讲,常量是在指令上的量,就像指令中的立即数寻址,系统取到指令后不需要通过地址再去取数据,它不占空间,也就没有地址的概念,当然有人认为系统对常量和变量都有空间存储,只是对待不同。
而变量是在内存中有个空间对它进行存储,指令保存它的地址。

我们可以认为,常量在编译后所占用的内存大小已经确定,所以常量1在内存里就是二进制1,而变量需要在运行时进行分配,因此要根据变量的数据类型进行空间开辟,也就是先根据数据类型来n个0,然后把1塞进去

需要注意的一点就是int a = 56;这一句,a是a,56是56,虽然值一样。
只看a和56,它们两个都是存放在栈内存中。
我们知道存放在栈中的数据大小与生存期必须是确定的,所以a根据它的数据类型int占用4字节,看到的二进制就是00000000 00000000 00000000 00000000。
再看56,他是个地道的常量,他所占用的栈内存空间就是由它本身确定也就是111000。
然后将56赋值给a,就是将a指向到56,但不管a也好还是56也好,他们本身的内存空间大小都没有发生改变,所以我们看到a的二进制就是00000000 00000000 00000000 00111000,而56则是111000

综上,我们看到的a和56的内存空间是两块不同的内存空间。

你用short s = 56 也是一样的这个步骤,那么既然56 这个常量没有超出short的范围,那么这么定义编译通过有什么不可以?

你要是要是改成这样:
int a = 56;
short s = a;
你可以自己试试看能编译过不?

如果不行 你再改成
int a = 56
short s = (short) a;
这次看看可以了不?

#11


至于你说的3.14 那是因为
float和double是表示浮点型的数据类型,他们之间的区别在于他们的精确度不同

float 3.402823e+38 ~ 1.401298e-45(e+38表示是乘以10的38次方,同样,e-45表示乘以10的负45次方)占用4个字节

double 1.797693e+308~ 4.9000000e-324 占用8个字节

double型比float型存储范围更大,精度更高,所以通常的浮点型的数据在不声明的情况下都是double型的。

也就是说,在不声明的情况下,他默认浮点数是double类型,你想把一个double类型赋值给float类型,而且是从高类型转低类型,违反了从高转低需要显式转换的规则,当然编译不过。

#12


引用 11 楼 acefr 的回复:
至于你说的3.14 那是因为
float和double是表示浮点型的数据类型,他们之间的区别在于他们的精确度不同

float 3.402823e+38 ~ 1.401298e-45(e+38表示是乘以10的38次方,同样,e-45表示乘以10的负45次方)占用4个字节

double 1.797693e+308~ 4.9000000e-324 占用8个字节

double型比float型存储范围更大,精度更高,所以通常的浮点型的数据在不声明的情况下都是double型的。

也就是说,在不声明的情况下,他默认浮点数是double类型,你想把一个double类型赋值给float类型,而且是从高类型转低类型,违反了从高转低需要显式转换的规则,当然编译不过。


好,你说数值3.14默认是double类型对吧,那数值56是什么类型?

#13


牛啊,受教了~

#14


引用 10 楼 acefr 的回复:
Java语言是一种强类型的语言。强类型的语言有以下几个要求:
变量或常量必须有类型
要求声明变量或常量时必须声明类型,而且只能在声明以后才能使用。
赋值时类型必须一致
值的类型必须和变量或常量的类型完全一致。
运算时类型必须一致
参与运算的数据类型必须一致才能运算。

在整数之间进行类型转换时,数值不发生改变, jvm会自己做个隐式转换的
Java常用的数据类型,都是有固定顺序的,低类型向高类型转,可以认为是隐式;高类型要转成低类型,必须要显示的转换。

你在

int a = 56; //数值56默认为int类型 ?? 你这是定义a是int类型
short s = 56; //你这是定义s是short类型 

56是个常量 

从汇编角度讲,常量是在指令上的量,就像指令中的立即数寻址,系统取到指令后不需要通过地址再去取数据,它不占空间,也就没有地址的概念,当然有人认为系统对常量和变量都有空间存储,只是对待不同。
而变量是在内存中有个空间对它进行存储,指令保存它的地址。

我们可以认为,常量在编译后所占用的内存大小已经确定,所以常量1在内存里就是二进制1,而变量需要在运行时进行分配,因此要根据变量的数据类型进行空间开辟,也就是先根据数据类型来n个0,然后把1塞进去

需要注意的一点就是int a = 56;这一句,a是a,56是56,虽然值一样。
只看a和56,它们两个都是存放在栈内存中。
我们知道存放在栈中的数据大小与生存期必须是确定的,所以a根据它的数据类型int占用4字节,看到的二进制就是00000000 00000000 00000000 00000000。
再看56,他是个地道的常量,他所占用的栈内存空间就是由它本身确定也就是111000。
然后将56赋值给a,就是将a指向到56,但不管a也好还是56也好,他们本身的内存空间大小都没有发生改变,所以我们看到a的二进制就是00000000 00000000 00000000 00111000,而56则是111000

综上,我们看到的a和56的内存空间是两块不同的内存空间。

你用short s = 56 也是一样的这个步骤,那么既然56 这个常量没有超出short的范围,那么这么定义编译通过有什么不可以?

你要是要是改成这样:
int a = 56;
short s = a;
你可以自己试试看能编译过不?

如果不行 你再改成
int a = 56
short s = (short) a;
这次看看可以了不?


谢谢你打了这么多字 一个简单而有趣的类型转换问题

但我还是有些疑问,你说56是个地道的常量,没有超出short范围,所以可以直接赋给short类型的变量对吧。那我想知道3.14是个地道的常量么?它超出float的范围了么?那它为什么不能直接赋给float类型的变量呢?你要是想说3.14默认是double类型的,高精度向低精度赋值要强制类型转换,那我就会继续问56默认是什么类型的?它为什么可以直接赋值给short类型的变量呢? 
我怎么总感觉整型和浮点型的赋值规则不一样啊。呵呵

#15


大家不要嫌烦啊 一个简单而有趣的类型转换问题

没事的时候扣扣细节呗。也挺好玩的不是么~

#16


心中的这个结 始终解不开啊!
看来今天晚上要失眠了 一个简单而有趣的类型转换问题

#18


楼主  你这就不存在类型转换的问题吧?!   只是变量的赋值,你如果在3.14后面加了f就能编译过了吧

#19


float f = 3.14f;

#20


引用 14 楼 u010134240 的回复:
Quote: 引用 10 楼 acefr 的回复:

Java语言是一种强类型的语言。强类型的语言有以下几个要求:
变量或常量必须有类型
要求声明变量或常量时必须声明类型,而且只能在声明以后才能使用。
赋值时类型必须一致
值的类型必须和变量或常量的类型完全一致。
运算时类型必须一致
参与运算的数据类型必须一致才能运算。

在整数之间进行类型转换时,数值不发生改变, jvm会自己做个隐式转换的
Java常用的数据类型,都是有固定顺序的,低类型向高类型转,可以认为是隐式;高类型要转成低类型,必须要显示的转换。

你在

int a = 56; //数值56默认为int类型 ?? 你这是定义a是int类型
short s = 56; //你这是定义s是short类型 

56是个常量 

从汇编角度讲,常量是在指令上的量,就像指令中的立即数寻址,系统取到指令后不需要通过地址再去取数据,它不占空间,也就没有地址的概念,当然有人认为系统对常量和变量都有空间存储,只是对待不同。
而变量是在内存中有个空间对它进行存储,指令保存它的地址。

我们可以认为,常量在编译后所占用的内存大小已经确定,所以常量1在内存里就是二进制1,而变量需要在运行时进行分配,因此要根据变量的数据类型进行空间开辟,也就是先根据数据类型来n个0,然后把1塞进去

需要注意的一点就是int a = 56;这一句,a是a,56是56,虽然值一样。
只看a和56,它们两个都是存放在栈内存中。
我们知道存放在栈中的数据大小与生存期必须是确定的,所以a根据它的数据类型int占用4字节,看到的二进制就是00000000 00000000 00000000 00000000。
再看56,他是个地道的常量,他所占用的栈内存空间就是由它本身确定也就是111000。
然后将56赋值给a,就是将a指向到56,但不管a也好还是56也好,他们本身的内存空间大小都没有发生改变,所以我们看到a的二进制就是00000000 00000000 00000000 00111000,而56则是111000

综上,我们看到的a和56的内存空间是两块不同的内存空间。

你用short s = 56 也是一样的这个步骤,那么既然56 这个常量没有超出short的范围,那么这么定义编译通过有什么不可以?

你要是要是改成这样:
int a = 56;
short s = a;
你可以自己试试看能编译过不?

如果不行 你再改成
int a = 56
short s = (short) a;
这次看看可以了不?


谢谢你打了这么多字 一个简单而有趣的类型转换问题

但我还是有些疑问,你说56是个地道的常量,没有超出short范围,所以可以直接赋给short类型的变量对吧。那我想知道3.14是个地道的常量么?它超出float的范围了么?那它为什么不能直接赋给float类型的变量呢?你要是想说3.14默认是double类型的,高精度向低精度赋值要强制类型转换,那我就会继续问56默认是什么类型的?它为什么可以直接赋值给short类型的变量呢? 
我怎么总感觉整型和浮点型的赋值规则不一样啊。呵呵


晚上不上线的,刚上来, 不好意思哈, 你这个问题其实涉及到jvm。 jvm是基于栈的机器,几乎所有的指令都与操作数栈相关。栈操作包括把常量压入操作数栈、执行通用的栈操作、在操作数栈和局部变量之间往返传输值。常量值隐含包含在操作码内部。
比如我敲下如下代码编译一下:
int a  = 56;
short s = 57;//为了区别于a,这边用57
s = (short)(s+1);//你这里可以试试,不加short会怎样?
s+=1;//这里为什么可以,在反汇编生成的字节码里面就看出来了
double d = 3.14;
float f = 3.15f;//如果不加f 为什么会不过,在字节码里面也可以看到
编译一下, 然后用反汇编器看看java编译器为我们生成的字节码。这样就可以对照源代码和字节码,从而了解很多编译器内部的工作。 反汇编后如图
一个简单而有趣的类型转换问题

看见没有, 是bipush,实际上一开始认为常量56也好或者57也好, 都是当做byte 隐式转换上来的 没有超过short的范围,当然可以通过。
那么接下来, 我们如果加一句,看看结果又会变成什么样子?

一个简单而有趣的类型转换问题
这里9999为什么用sipush?

说明在赋值常量的时候是从低到高的。你甚至可以认为,在jvm里面,常量池的数据类型跟每个数据类型取值范围的定义是一样的,有兴趣的话, 你可以试试看int a =2147483647,看看生成的字节码是什么?

#21


大神真多啊 一个简单而有趣的类型转换问题

#22


引用 20 楼 acefr 的回复:
Quote: 引用 14 楼 u010134240 的回复:

Quote: 引用 10 楼 acefr 的回复:

Java语言是一种强类型的语言。强类型的语言有以下几个要求:
变量或常量必须有类型
要求声明变量或常量时必须声明类型,而且只能在声明以后才能使用。
赋值时类型必须一致
值的类型必须和变量或常量的类型完全一致。
运算时类型必须一致
参与运算的数据类型必须一致才能运算。

在整数之间进行类型转换时,数值不发生改变, jvm会自己做个隐式转换的
Java常用的数据类型,都是有固定顺序的,低类型向高类型转,可以认为是隐式;高类型要转成低类型,必须要显示的转换。

你在

int a = 56; //数值56默认为int类型 ?? 你这是定义a是int类型
short s = 56; //你这是定义s是short类型 

56是个常量 

从汇编角度讲,常量是在指令上的量,就像指令中的立即数寻址,系统取到指令后不需要通过地址再去取数据,它不占空间,也就没有地址的概念,当然有人认为系统对常量和变量都有空间存储,只是对待不同。
而变量是在内存中有个空间对它进行存储,指令保存它的地址。

我们可以认为,常量在编译后所占用的内存大小已经确定,所以常量1在内存里就是二进制1,而变量需要在运行时进行分配,因此要根据变量的数据类型进行空间开辟,也就是先根据数据类型来n个0,然后把1塞进去

需要注意的一点就是int a = 56;这一句,a是a,56是56,虽然值一样。
只看a和56,它们两个都是存放在栈内存中。
我们知道存放在栈中的数据大小与生存期必须是确定的,所以a根据它的数据类型int占用4字节,看到的二进制就是00000000 00000000 00000000 00000000。
再看56,他是个地道的常量,他所占用的栈内存空间就是由它本身确定也就是111000。
然后将56赋值给a,就是将a指向到56,但不管a也好还是56也好,他们本身的内存空间大小都没有发生改变,所以我们看到a的二进制就是00000000 00000000 00000000 00111000,而56则是111000

综上,我们看到的a和56的内存空间是两块不同的内存空间。

你用short s = 56 也是一样的这个步骤,那么既然56 这个常量没有超出short的范围,那么这么定义编译通过有什么不可以?

你要是要是改成这样:
int a = 56;
short s = a;
你可以自己试试看能编译过不?

如果不行 你再改成
int a = 56
short s = (short) a;
这次看看可以了不?


谢谢你打了这么多字 一个简单而有趣的类型转换问题

但我还是有些疑问,你说56是个地道的常量,没有超出short范围,所以可以直接赋给short类型的变量对吧。那我想知道3.14是个地道的常量么?它超出float的范围了么?那它为什么不能直接赋给float类型的变量呢?你要是想说3.14默认是double类型的,高精度向低精度赋值要强制类型转换,那我就会继续问56默认是什么类型的?它为什么可以直接赋值给short类型的变量呢? 
我怎么总感觉整型和浮点型的赋值规则不一样啊。呵呵


晚上不上线的,刚上来, 不好意思哈, 你这个问题其实涉及到jvm。 jvm是基于栈的机器,几乎所有的指令都与操作数栈相关。栈操作包括把常量压入操作数栈、执行通用的栈操作、在操作数栈和局部变量之间往返传输值。常量值隐含包含在操作码内部。
比如我敲下如下代码编译一下:
int a  = 56;
short s = 57;//为了区别于a,这边用57
s = (short)(s+1);//你这里可以试试,不加short会怎样?
s+=1;//这里为什么可以,在反汇编生成的字节码里面就看出来了
double d = 3.14;
float f = 3.15f;//如果不加f 为什么会不过,在字节码里面也可以看到
编译一下, 然后用反汇编器看看java编译器为我们生成的字节码。这样就可以对照源代码和字节码,从而了解很多编译器内部的工作。 反汇编后如图
一个简单而有趣的类型转换问题

看见没有, 是bipush,实际上一开始认为常量56也好或者57也好, 都是当做byte 隐式转换上来的 没有超过short的范围,当然可以通过。
那么接下来, 我们如果加一句,看看结果又会变成什么样子?

一个简单而有趣的类型转换问题
这里9999为什么用sipush?

说明在赋值常量的时候是从低到高的。你甚至可以认为,在jvm里面,常量池的数据类型跟每个数据类型取值范围的定义是一样的,有兴趣的话, 你可以试试看int a =2147483647,看看生成的字节码是什么?


short s = 57;//为了区别于a,这边用57
s = (short)(s+1);//你这里可以试试,不加short会怎样?

对啊,为什么+1,编译器又认为1是int类型了?等于是将short的57隐式的转换成了int型然后加int的1?这是为什么?

#1


3.14默认是double类型,你把double类型数据复制给float当然不行,float f = 3.14f;这样就行了。
给short赋值,只要在-32768到32767之间就没问题

#2


整数就没什么精度了吧,
不过short s = 100000;好像不可以

#3


short s = 56;没有问题啊,56在short能表示的范围之内。

#4


引用 1 楼 xulong1 的回复:
3.14默认是double类型,你把double类型数据复制给float当然不行,float f = 3.14f;这样就行了。
给short赋值,只要在-32768到32767之间就没问题


谢谢你的回答,但没说到本质啊。
我也知道将double类型的数值赋给float类型的变量当然不行,但将int类型的数值赋给short类型的变量就可以?
大范围的类型值赋给小范围的类型变量时不是要强制类型转换么?

#5


引用 3 楼 zhiqiu 的回复:
short s = 56;没有问题啊,56在short能表示的范围之内。


那 3.14也在float表示的范围内啊~ 呵呵

#6


引用 5 楼 u010134240 的回复:
Quote: 引用 3 楼 zhiqiu 的回复:

short s = 56;没有问题啊,56在short能表示的范围之内。


那 3.14也在float表示的范围内啊~ 呵呵



3.1333333333333333   <   3.14

能用float表示么?小数一般说的也是精度。



#7


int a = 56; //数值56默认为int类型  
我怎么不知道??

#8


引用 7 楼 she383 的回复:
int a = 56; //数值56默认为int类型  
我怎么不知道??


Java语言的整型常量本来就默认是int型的,Java浮点型常量默认是double类型。

int a = 2147483647;//编译通过
int a = 2147483648;//编译不通过

这难道还说明不了问题么。

#9


一个简单而有趣的类型转换问题是我没把问题描述清楚么?

其实总结一下就是:
short s = 56; //为什么能通过编译?int类型的数值56 为什么能直接赋给 short类型的变量s 而不需要强制类型转换?

作为对比,float f = 3.14; 都通不过编译 , 必须写成  float f = (float)3.14; 才行。

#10


Java语言是一种强类型的语言。强类型的语言有以下几个要求:
变量或常量必须有类型
要求声明变量或常量时必须声明类型,而且只能在声明以后才能使用。
赋值时类型必须一致
值的类型必须和变量或常量的类型完全一致。
运算时类型必须一致
参与运算的数据类型必须一致才能运算。

在整数之间进行类型转换时,数值不发生改变, jvm会自己做个隐式转换的
Java常用的数据类型,都是有固定顺序的,低类型向高类型转,可以认为是隐式;高类型要转成低类型,必须要显示的转换。

你在

int a = 56; //数值56默认为int类型 ?? 你这是定义a是int类型
short s = 56; //你这是定义s是short类型 

56是个常量 

从汇编角度讲,常量是在指令上的量,就像指令中的立即数寻址,系统取到指令后不需要通过地址再去取数据,它不占空间,也就没有地址的概念,当然有人认为系统对常量和变量都有空间存储,只是对待不同。
而变量是在内存中有个空间对它进行存储,指令保存它的地址。

我们可以认为,常量在编译后所占用的内存大小已经确定,所以常量1在内存里就是二进制1,而变量需要在运行时进行分配,因此要根据变量的数据类型进行空间开辟,也就是先根据数据类型来n个0,然后把1塞进去

需要注意的一点就是int a = 56;这一句,a是a,56是56,虽然值一样。
只看a和56,它们两个都是存放在栈内存中。
我们知道存放在栈中的数据大小与生存期必须是确定的,所以a根据它的数据类型int占用4字节,看到的二进制就是00000000 00000000 00000000 00000000。
再看56,他是个地道的常量,他所占用的栈内存空间就是由它本身确定也就是111000。
然后将56赋值给a,就是将a指向到56,但不管a也好还是56也好,他们本身的内存空间大小都没有发生改变,所以我们看到a的二进制就是00000000 00000000 00000000 00111000,而56则是111000

综上,我们看到的a和56的内存空间是两块不同的内存空间。

你用short s = 56 也是一样的这个步骤,那么既然56 这个常量没有超出short的范围,那么这么定义编译通过有什么不可以?

你要是要是改成这样:
int a = 56;
short s = a;
你可以自己试试看能编译过不?

如果不行 你再改成
int a = 56
short s = (short) a;
这次看看可以了不?

#11


至于你说的3.14 那是因为
float和double是表示浮点型的数据类型,他们之间的区别在于他们的精确度不同

float 3.402823e+38 ~ 1.401298e-45(e+38表示是乘以10的38次方,同样,e-45表示乘以10的负45次方)占用4个字节

double 1.797693e+308~ 4.9000000e-324 占用8个字节

double型比float型存储范围更大,精度更高,所以通常的浮点型的数据在不声明的情况下都是double型的。

也就是说,在不声明的情况下,他默认浮点数是double类型,你想把一个double类型赋值给float类型,而且是从高类型转低类型,违反了从高转低需要显式转换的规则,当然编译不过。

#12


引用 11 楼 acefr 的回复:
至于你说的3.14 那是因为
float和double是表示浮点型的数据类型,他们之间的区别在于他们的精确度不同

float 3.402823e+38 ~ 1.401298e-45(e+38表示是乘以10的38次方,同样,e-45表示乘以10的负45次方)占用4个字节

double 1.797693e+308~ 4.9000000e-324 占用8个字节

double型比float型存储范围更大,精度更高,所以通常的浮点型的数据在不声明的情况下都是double型的。

也就是说,在不声明的情况下,他默认浮点数是double类型,你想把一个double类型赋值给float类型,而且是从高类型转低类型,违反了从高转低需要显式转换的规则,当然编译不过。


好,你说数值3.14默认是double类型对吧,那数值56是什么类型?

#13


牛啊,受教了~

#14


引用 10 楼 acefr 的回复:
Java语言是一种强类型的语言。强类型的语言有以下几个要求:
变量或常量必须有类型
要求声明变量或常量时必须声明类型,而且只能在声明以后才能使用。
赋值时类型必须一致
值的类型必须和变量或常量的类型完全一致。
运算时类型必须一致
参与运算的数据类型必须一致才能运算。

在整数之间进行类型转换时,数值不发生改变, jvm会自己做个隐式转换的
Java常用的数据类型,都是有固定顺序的,低类型向高类型转,可以认为是隐式;高类型要转成低类型,必须要显示的转换。

你在

int a = 56; //数值56默认为int类型 ?? 你这是定义a是int类型
short s = 56; //你这是定义s是short类型 

56是个常量 

从汇编角度讲,常量是在指令上的量,就像指令中的立即数寻址,系统取到指令后不需要通过地址再去取数据,它不占空间,也就没有地址的概念,当然有人认为系统对常量和变量都有空间存储,只是对待不同。
而变量是在内存中有个空间对它进行存储,指令保存它的地址。

我们可以认为,常量在编译后所占用的内存大小已经确定,所以常量1在内存里就是二进制1,而变量需要在运行时进行分配,因此要根据变量的数据类型进行空间开辟,也就是先根据数据类型来n个0,然后把1塞进去

需要注意的一点就是int a = 56;这一句,a是a,56是56,虽然值一样。
只看a和56,它们两个都是存放在栈内存中。
我们知道存放在栈中的数据大小与生存期必须是确定的,所以a根据它的数据类型int占用4字节,看到的二进制就是00000000 00000000 00000000 00000000。
再看56,他是个地道的常量,他所占用的栈内存空间就是由它本身确定也就是111000。
然后将56赋值给a,就是将a指向到56,但不管a也好还是56也好,他们本身的内存空间大小都没有发生改变,所以我们看到a的二进制就是00000000 00000000 00000000 00111000,而56则是111000

综上,我们看到的a和56的内存空间是两块不同的内存空间。

你用short s = 56 也是一样的这个步骤,那么既然56 这个常量没有超出short的范围,那么这么定义编译通过有什么不可以?

你要是要是改成这样:
int a = 56;
short s = a;
你可以自己试试看能编译过不?

如果不行 你再改成
int a = 56
short s = (short) a;
这次看看可以了不?


谢谢你打了这么多字 一个简单而有趣的类型转换问题

但我还是有些疑问,你说56是个地道的常量,没有超出short范围,所以可以直接赋给short类型的变量对吧。那我想知道3.14是个地道的常量么?它超出float的范围了么?那它为什么不能直接赋给float类型的变量呢?你要是想说3.14默认是double类型的,高精度向低精度赋值要强制类型转换,那我就会继续问56默认是什么类型的?它为什么可以直接赋值给short类型的变量呢? 
我怎么总感觉整型和浮点型的赋值规则不一样啊。呵呵

#15


大家不要嫌烦啊 一个简单而有趣的类型转换问题

没事的时候扣扣细节呗。也挺好玩的不是么~

#16


心中的这个结 始终解不开啊!
看来今天晚上要失眠了 一个简单而有趣的类型转换问题

#17


#18


楼主  你这就不存在类型转换的问题吧?!   只是变量的赋值,你如果在3.14后面加了f就能编译过了吧

#19


float f = 3.14f;

#20


引用 14 楼 u010134240 的回复:
Quote: 引用 10 楼 acefr 的回复:

Java语言是一种强类型的语言。强类型的语言有以下几个要求:
变量或常量必须有类型
要求声明变量或常量时必须声明类型,而且只能在声明以后才能使用。
赋值时类型必须一致
值的类型必须和变量或常量的类型完全一致。
运算时类型必须一致
参与运算的数据类型必须一致才能运算。

在整数之间进行类型转换时,数值不发生改变, jvm会自己做个隐式转换的
Java常用的数据类型,都是有固定顺序的,低类型向高类型转,可以认为是隐式;高类型要转成低类型,必须要显示的转换。

你在

int a = 56; //数值56默认为int类型 ?? 你这是定义a是int类型
short s = 56; //你这是定义s是short类型 

56是个常量 

从汇编角度讲,常量是在指令上的量,就像指令中的立即数寻址,系统取到指令后不需要通过地址再去取数据,它不占空间,也就没有地址的概念,当然有人认为系统对常量和变量都有空间存储,只是对待不同。
而变量是在内存中有个空间对它进行存储,指令保存它的地址。

我们可以认为,常量在编译后所占用的内存大小已经确定,所以常量1在内存里就是二进制1,而变量需要在运行时进行分配,因此要根据变量的数据类型进行空间开辟,也就是先根据数据类型来n个0,然后把1塞进去

需要注意的一点就是int a = 56;这一句,a是a,56是56,虽然值一样。
只看a和56,它们两个都是存放在栈内存中。
我们知道存放在栈中的数据大小与生存期必须是确定的,所以a根据它的数据类型int占用4字节,看到的二进制就是00000000 00000000 00000000 00000000。
再看56,他是个地道的常量,他所占用的栈内存空间就是由它本身确定也就是111000。
然后将56赋值给a,就是将a指向到56,但不管a也好还是56也好,他们本身的内存空间大小都没有发生改变,所以我们看到a的二进制就是00000000 00000000 00000000 00111000,而56则是111000

综上,我们看到的a和56的内存空间是两块不同的内存空间。

你用short s = 56 也是一样的这个步骤,那么既然56 这个常量没有超出short的范围,那么这么定义编译通过有什么不可以?

你要是要是改成这样:
int a = 56;
short s = a;
你可以自己试试看能编译过不?

如果不行 你再改成
int a = 56
short s = (short) a;
这次看看可以了不?


谢谢你打了这么多字 一个简单而有趣的类型转换问题

但我还是有些疑问,你说56是个地道的常量,没有超出short范围,所以可以直接赋给short类型的变量对吧。那我想知道3.14是个地道的常量么?它超出float的范围了么?那它为什么不能直接赋给float类型的变量呢?你要是想说3.14默认是double类型的,高精度向低精度赋值要强制类型转换,那我就会继续问56默认是什么类型的?它为什么可以直接赋值给short类型的变量呢? 
我怎么总感觉整型和浮点型的赋值规则不一样啊。呵呵


晚上不上线的,刚上来, 不好意思哈, 你这个问题其实涉及到jvm。 jvm是基于栈的机器,几乎所有的指令都与操作数栈相关。栈操作包括把常量压入操作数栈、执行通用的栈操作、在操作数栈和局部变量之间往返传输值。常量值隐含包含在操作码内部。
比如我敲下如下代码编译一下:
int a  = 56;
short s = 57;//为了区别于a,这边用57
s = (short)(s+1);//你这里可以试试,不加short会怎样?
s+=1;//这里为什么可以,在反汇编生成的字节码里面就看出来了
double d = 3.14;
float f = 3.15f;//如果不加f 为什么会不过,在字节码里面也可以看到
编译一下, 然后用反汇编器看看java编译器为我们生成的字节码。这样就可以对照源代码和字节码,从而了解很多编译器内部的工作。 反汇编后如图
一个简单而有趣的类型转换问题

看见没有, 是bipush,实际上一开始认为常量56也好或者57也好, 都是当做byte 隐式转换上来的 没有超过short的范围,当然可以通过。
那么接下来, 我们如果加一句,看看结果又会变成什么样子?

一个简单而有趣的类型转换问题
这里9999为什么用sipush?

说明在赋值常量的时候是从低到高的。你甚至可以认为,在jvm里面,常量池的数据类型跟每个数据类型取值范围的定义是一样的,有兴趣的话, 你可以试试看int a =2147483647,看看生成的字节码是什么?

#21


大神真多啊 一个简单而有趣的类型转换问题

#22


引用 20 楼 acefr 的回复:
Quote: 引用 14 楼 u010134240 的回复:

Quote: 引用 10 楼 acefr 的回复:

Java语言是一种强类型的语言。强类型的语言有以下几个要求:
变量或常量必须有类型
要求声明变量或常量时必须声明类型,而且只能在声明以后才能使用。
赋值时类型必须一致
值的类型必须和变量或常量的类型完全一致。
运算时类型必须一致
参与运算的数据类型必须一致才能运算。

在整数之间进行类型转换时,数值不发生改变, jvm会自己做个隐式转换的
Java常用的数据类型,都是有固定顺序的,低类型向高类型转,可以认为是隐式;高类型要转成低类型,必须要显示的转换。

你在

int a = 56; //数值56默认为int类型 ?? 你这是定义a是int类型
short s = 56; //你这是定义s是short类型 

56是个常量 

从汇编角度讲,常量是在指令上的量,就像指令中的立即数寻址,系统取到指令后不需要通过地址再去取数据,它不占空间,也就没有地址的概念,当然有人认为系统对常量和变量都有空间存储,只是对待不同。
而变量是在内存中有个空间对它进行存储,指令保存它的地址。

我们可以认为,常量在编译后所占用的内存大小已经确定,所以常量1在内存里就是二进制1,而变量需要在运行时进行分配,因此要根据变量的数据类型进行空间开辟,也就是先根据数据类型来n个0,然后把1塞进去

需要注意的一点就是int a = 56;这一句,a是a,56是56,虽然值一样。
只看a和56,它们两个都是存放在栈内存中。
我们知道存放在栈中的数据大小与生存期必须是确定的,所以a根据它的数据类型int占用4字节,看到的二进制就是00000000 00000000 00000000 00000000。
再看56,他是个地道的常量,他所占用的栈内存空间就是由它本身确定也就是111000。
然后将56赋值给a,就是将a指向到56,但不管a也好还是56也好,他们本身的内存空间大小都没有发生改变,所以我们看到a的二进制就是00000000 00000000 00000000 00111000,而56则是111000

综上,我们看到的a和56的内存空间是两块不同的内存空间。

你用short s = 56 也是一样的这个步骤,那么既然56 这个常量没有超出short的范围,那么这么定义编译通过有什么不可以?

你要是要是改成这样:
int a = 56;
short s = a;
你可以自己试试看能编译过不?

如果不行 你再改成
int a = 56
short s = (short) a;
这次看看可以了不?


谢谢你打了这么多字 一个简单而有趣的类型转换问题

但我还是有些疑问,你说56是个地道的常量,没有超出short范围,所以可以直接赋给short类型的变量对吧。那我想知道3.14是个地道的常量么?它超出float的范围了么?那它为什么不能直接赋给float类型的变量呢?你要是想说3.14默认是double类型的,高精度向低精度赋值要强制类型转换,那我就会继续问56默认是什么类型的?它为什么可以直接赋值给short类型的变量呢? 
我怎么总感觉整型和浮点型的赋值规则不一样啊。呵呵


晚上不上线的,刚上来, 不好意思哈, 你这个问题其实涉及到jvm。 jvm是基于栈的机器,几乎所有的指令都与操作数栈相关。栈操作包括把常量压入操作数栈、执行通用的栈操作、在操作数栈和局部变量之间往返传输值。常量值隐含包含在操作码内部。
比如我敲下如下代码编译一下:
int a  = 56;
short s = 57;//为了区别于a,这边用57
s = (short)(s+1);//你这里可以试试,不加short会怎样?
s+=1;//这里为什么可以,在反汇编生成的字节码里面就看出来了
double d = 3.14;
float f = 3.15f;//如果不加f 为什么会不过,在字节码里面也可以看到
编译一下, 然后用反汇编器看看java编译器为我们生成的字节码。这样就可以对照源代码和字节码,从而了解很多编译器内部的工作。 反汇编后如图
一个简单而有趣的类型转换问题

看见没有, 是bipush,实际上一开始认为常量56也好或者57也好, 都是当做byte 隐式转换上来的 没有超过short的范围,当然可以通过。
那么接下来, 我们如果加一句,看看结果又会变成什么样子?

一个简单而有趣的类型转换问题
这里9999为什么用sipush?

说明在赋值常量的时候是从低到高的。你甚至可以认为,在jvm里面,常量池的数据类型跟每个数据类型取值范围的定义是一样的,有兴趣的话, 你可以试试看int a =2147483647,看看生成的字节码是什么?


short s = 57;//为了区别于a,这边用57
s = (short)(s+1);//你这里可以试试,不加short会怎样?

对啊,为什么+1,编译器又认为1是int类型了?等于是将short的57隐式的转换成了int型然后加int的1?这是为什么?