Day03:小姐,你手上那是什麽?

昨天提到了一个奇怪的现象:

byte num = 128;

如上撰写,你的IDE将会在128底下亮出红线,并说:「Type mismatch: cannot convert from int to byte」

今天就会来探讨一下为什麽会发生这个奇怪的现象,不过在进入正题之前,想先谈谈何谓字面常量(literal constant)

昨天谈到了基本型别(primitive type),其实被宣告为基本型别的变数所储存的值就是各种字面常量,字面常量本身就代表了最纯粹的数值,没有经过记忆体位址的包装,1就是1,2就是2。不过字面常量就只有我们日常生活使用的十进位(decimal)数字吗?当然不止,还有十六进位(hexadecimal)、八进位(octet)、二进位(binary):

  • 十进位:10
  • 十六进位:0xA
  • 八进位:012
  • 二进位:0b1010

以上这些都是可以在Java程序中表达的字面常量,而且也都等於我们所谓的10这个数值。

欸,那还有一个字元(char)勒? 它是怎麽被储存的? 电脑真的会存进abcd吗?
实际上在Java,字元骨子里是一个16 bits范围的正数值,每个数值会再透过转换转成我们所看到的文字,所以当我们如下指派时:

int num = 'A';

num会变成65的int数值(JLS5.1.2),神奇吧。所以字元就像是一个萝卜一个坑,每个数字会代表一个文字,再查表对应出代表的文字(Unicode Table)

最後提点一下,昨天虽然有提到String字串不是基本型别,可是你应该有注意到我们指派给String型别变数的也是像字面常量的值,其实没错!我们在等号右边给它的字串也是一种字面常量,但字串比较特别一点,之後有机会再讨论。

好了,该进入正题了~ 到底为什麽JVM要说我们给byte变数一个int字面常量勒?
答案就是,就是这样...没有为什麽,这就是Java在字面常量上的潜规则,只要我们直接打出数字的数值,它预设就是int的型态。而之所以byte num = 127会可以编译成功是因为Java有自动针对byte, short, char, int常数narrowing conversion的功能(JLS5.2)

整数的常量会自动视为int型态,浮点数呢? 浮点数则是自动视为double型态,所以以下会编译不过哦:

float fNum = 1.5;

可是我就是想要存1.5到float型别的变数怎麽办? 这时候就有2种办法了:

float fNum01 = 1.5f;
float fNum02 = (float)1.5;

第一种办法是从字面常量下手,如果我们希望表示出float型态的浮点数,就得在最後面加上一个"f";
第二种办法是使用Java的转型(cast)语法,在值的前面用括号包住我们想转成的型别名称,就可以强制转过去了。这个转型水也是有点深度...之後可能需要花点篇幅说明,因为并不是可以无脑转型的,尤其之後又有非基本型别的状况时。

其实在整数也会有这样的情况,由於数字预设是int型别,那如果我们写下了一个超出int型别范围的数值,并预计用一个long型别的变数来装,要怎麽做到勒? 答案就是:

long num = 2147483648L;

在整数数值的最後面加上"L",就会把常量转换为long型态了。

好了,我们只剩最後一个部分要讲了,就是运算时常量的潜规则。

byte n1 = 1;
byte n2 = 2;
byte n3 = n1 + n2;

以上程序码在第三行会出错,诡异吧。这是因为Java预设在进行运算时,若运算元是小於int的型别,会先自动转化为int型别後,再进行运算。所以只要有加减乘除的运算,最後结果一定最小会是int的型别!那下面的话呢:

int n1 = 1;
long n2 = 2;
int n3 = n1 + n2;

这样的话第三行也还是最出错,因为现在最大的型别变成long了,这时Java会先把所有型别都提升到long,再进行运算。这种特性称为自动提升(promote)。
最後来个逗趣的东西:

int nn = 1 + 'A';

试试看nn会等於多少吧。

这篇有点长,来做个小结:

  1. 数字的字面常量除了十进位,也可以用十六进位(0x)、八进位(0)、二进位(0b)来写出数值
  2. 字元char骨子里其实是一个16 bits的数字,再透过查表将数字转换为文字
  3. 整数字面常量预设为int型别,若需要表达long型别的数值常量,要在最後面加上"L"
  4. 浮点数字面常量预设为double型别,若需要表达float型别的数值常量,要在最後面加上"f"
  5. 进行运算时会自动将运算元提升到int型别; 若有大於int型别的运算元则会以最大的型别为基准进行运算

天啊我把Java讲得好复杂哈哈,而且根本还没进到物件@@


<<:  [Day 1] php介绍+基础语法

>>:  Day1-为小学生撰写的网站小游戏

Angular#4 专案:路由 建置

Angular [目标] 启动程序先导入Login元件 1. 新增元件、模组 Syntax:ng h...

{DAY 14} NumPy 学习笔记(下)

前言 现在到了练习NumPy的最後一天,现在要开始跟资料分析的流程接轨 所以我决定从网路上的开源资...

Day03 安装环境

我们昨天有提到说,Django是一个Python的框架,理所当然的我们的电脑也要有Python才能运...

Day-2: Ruby on Rails 是什麽?

Ruby on Rails 是使用Ruby这套开放原始码(采用MIT授权)、 物件导向程序语言所开发...

# Day12--我们用协定说好要这样做了,你一定得OK!

协定的语法其实算是大量的使用在结构与类别中,尤其需要更底层的作用的时候,协定算是提供了一个共识,让程...