磨刀不误砍材工 - Java的基础语言要素(从变量/常量切入,看8种基本数据类型)

变量与常量是一个Java程序组成的重要部分。

我们可以将变量与常量理解为数据的载体,而从名称上我们也可以看出二者的不同:

常量代表不能改变的数据值,而变量的值则存在可变性


在我们回顾Java中的关键字的使用时,说道:被Java中的关键字final所修饰的变量,其值一经初始化,便不能再次进行赋值。该特性恰恰符合常量的定义。

        String var = "字符串变量";
	//java中,关键字final用于声明数据常量
	final String CONSTANT = "字符串常量";


既然我们知道了变量与常量是作为数据的载体使用;那么,就如同我们如果使用一个杯子作为载体,那么其搭载的介质可能是水,咖啡,果汁等等一样;

我们自然要了解Java中的变量与常量作为数据载体,其搭载的数据究竟有哪些?

大体来说,Java的数据类型分为:基本数据类型,对象数据类型以及数组,但数组实际也属于对象。

所以,Java中的变量/常量就是用以作为基本数据类型对象数据类型载体的。


对象数据类型的回顾需要结合一个关键的概念:类。

所以在这里,我们先将变量和常量作为切入点,首先来重新系统的总结一下Java中的8种基本数据类型的特性及使用。

总的来说,Java中的8种数据类型可以分为三类:数字类型,字符类型和一种特殊的数据类型布尔型。


一、数字数据类型

数字数据类型共有6种,其中4种用于表示整数,2种用于表示浮点数。


首先需要明确的是:Java中的6种数字类型都是有符号数,也就是说它们都有正负之分。而具体又是如何区别表示正数与负数的呢?

我们知道所谓的“1”,“3”,“101”这样的数,是我们日常生活中习惯使用的十进制数。

但在计算机中,所有数字都是以二进制数来表示的,也就是说,是一串由“0”和“1”组成的数字。

这样的一串数字中,其最高有效位是用于表示符号的,就是所谓的符号位。

符号位为“0”,代表是一个正数;符号位为“1”,代表是一个负数。而剩余位则用于表示值。


1.1、整数类型

Java中,用于表示整数的4种数字类型分别为:byte(字节型)、short(短整型)、int(整型)、long(长整形)

我们说在计算机中,数字都是由二进制形式表示的,那么自然的,其位数越多,可能的取值范围就越大。

所以我们看到从byte到long,随着所占位数的增加,其取值范围也就越大。

计算机中,一个字节等于8个比特位。而byte长度正是8位,这也是为什么它被取名为字节型;

而剩下的short,int,long分别对应2个字节,4个字节和8个字节。


进制转换:

我们刚刚已经说到了二进制和十进制,而在Java中,整数还有另外两种进制表现形式,分别是:八进制和十六进制。

在了解进制转换之前,我们先通过一段简单的代码了解一下Java中八进制和十六进制数的声明形式是怎么样的:

		// 十进制定义形式
		int num_10 = 10;
		// 八进制定义形式,以“0”作为前缀,表示定义的是一个八进制整数
		int num_8 = 012;
		// 十六进制定义形式,以“0x”作为前缀,表示定义的是一个十六进制整数
		int num_16 = 0xef;


了解了不同进制的定义形式,我们就可以看一下进制之间的相互转换了。首先我们应该知道,所谓进制,其实原理都是一样的:

所谓二进制,就是指“逢二进一”,也就是说二进制中只可能存在“0”和“1”两种可能值;

而所谓十进制,就是指“逢十进一”,也就是说只可能存在0-9的可能值;

那么同样的,八进制就是指“逢八进一”,所以只可能存在0-7的可能值;

同理的,十六进制就存在0-15的可能值。但传统定义数字中,“9”已经是单位的最大可能值,所以十六进制中以英文字母a - f分别代表 10 - 15。


那么,进制之间究竟是如何完成相互之间的转换工作的呢?

1、二进制数、八进制数、十六进制数转十进制数
有一个公式:二进制数、八进制数、十六进制数的各位数字分别乖以各自的基数的(N-1)次方,其和相加之和便是相应的十进制数。例如:

二进制数:0000-0110转换为十进制数:1*2的2次方+1*2的1次方+0*2的0次方=0+4+2+0=6,也就是说转换为十进制数的值为:6。

2、十进制数转二进制数、八进制数、十六进制数

方法是对应的的,即整数部分用除取余的算法,小数部分用乘基取整的方法,然后将整数与小数部分拼接成一个数作为转换的最后结果。

3、二进制数转换为八进制数或十六进制数

其原理很简单:我们已经知道了八进制只有0-7的可能值,十六进制则只有0-15这的可能值。

而我们观察到这样一种情况,对于一个二进制的数来说:

如果只取一个有效位的数,所能能表达的最大数为:1;

而取两个有效位的数,所能表达的最大值则为:“11”,也就是十进制的3;

取三个有效位的数,能表达的最大的数为“111”,则是十进制的7;

而取四个有效位的数“1111”,则正是十进制的15.


由此我们发现:

如果将二进制数每三位取出,则正好能表示一个八进制的数;

而将二进制数每四位取出,则正好能表示一个十六进制数。


而事实上,二进制与八进制和十六进制的转换原理也正是这样的。

举例来说,以二进制数:0000-1010为例:

转换为八进制数为:000/001/010,也就是12;

而如果转换为十六进制则为:0000/1010,也就是a。


1.2、浮点数类型

正如数学中数字分为整数和小数一样,Java中也是一样的。但Java不称为小数,称为浮点数。

而Java中,用于表示浮点数的两种种数字类型分别为:float(单精度浮点型)和double(双精度浮点型)。

Java里默认的浮点数形式是双精度形式,也就是double。

所以在定义一个float时,必须加上后缀F(f):float f = 2.3F。

而定义double,后缀D(d)的添加则是可选的。


到了这里,我们已经了解了Java中所有的数字类型。

之所以了解它们各自不同的特性,是为了在实际编写代码的过程中,可以根据实际需求选取最合适的数据类型来定义自己的变量(常量)。

举例来说:

如果想要表示全世界的人口数量,那么可能选择long型来表示更为合适;

而如果要表示某个公司的职员每月的工资情况,那么选用float可能更为合适。


三、字符类型

Java中,另一种基本数据类型:char型,代表字符类型。

在开发中,可能经常需要存储一些字符,如‘A’,‘c’等等。char型就是用于存储单个字符的数据类型。

同时,char型数据也可以通过Unicode码表示字符;

简单的来说,就是我们也可以通过在Unicode码表中有效的整数来表示一个字符。

其实很好理解,就像我们在小时候学习拼音的时候,可能都会接触到“拼音字母学习表”一样:

Unicode码表也是类似于这样的一张字符编码表,所谓编码就是对表中的每一个字符编排一个“号码”。

这个号码就像我们每个人的身份证,是独特对应的关系,通过身份证号码就可以查出我们每个人的信息。

到了这里就不难理解了,就假设:我们以97表示一个字符,Java会根据该值到Unicode码表中进行查询,然后发现号码“97”对应的字符是"a"。


Unicode码是用'\uxxxx'表示的。x表示的是16进制数值。

并且Unicode编码字符是用16位无符号整数表示的。也就是说,Unicode码表共有0-65535的编码值。


四、布尔类型

Java中一种特殊的数据类型,只有“true”和”false“两种可能值。通常用于关系运算或条件判断表达式返回的结果。


数据类型的转换

Java自身是一门强数据类型语言,所以在遇到不同数据类型同时操作,就需要进行数据类型的转换。

数据类型转换需要满足的最基本的要求,就是数据类型必须兼容。例如要将一个布尔型的数据转换为整数类型,肯定是不能成功的。

而在Java中,数据类型的转换又分为两种:自动类型转换和强制类型转换。

所谓自动转换就是指无需认为做任何额外的工作,虚拟机会自动的完成对数据类型的转换工作。

而强制转换则是指我们必须人为的进行声明后,才能完成想要的数据类型转换。

也就是说,自动数据类型转换是隐式的转换,而强制类型转换则是显式的转换


那么首先来看一下自动类型转换

第一种情况:低位数的数据类型可以自动转换为高位数的数据类型。

		// 低位数的数据类型自动转换为高位数的数据类型
		byte b = 1;
		short s = b;
		int i = s;
		long l = i;
		float f = 1.5f;
		double d = f;
		/*
		 * 另外,Java中整数的默认形式为int型, 
		 * 所以下面的声明形式实际也是: 
		 * 虚拟机自动完成了一次隐式的数据转换工作
		 */
		long num = 1000;

第二种情况:整数类型可以自动转为浮点数类型,但是这种转换后的值可能会出现误差。

第三种情况:字符类型可以自动转换为整型或长整形。这是因为Java中char型数据也可以通过Unicode码表示,长度为16位,所以也可以转换为长度更大的int和long型。

           char c1 = 'a';
           int i1= c1;
           
           char c2 = 'b';
           int i2 = c2 + 10;
           
           char c3 = 'c';
           long l = c3;

接下来,就是Java中的强制类型转换:强制转换的格式为:(type)value。

第一种情况:对应于自动转换,那么当高位数的数据类型转换为低位数的数据类型时,就需要做强制转换。


既然我们看到了”强制",那可能我们自然就会想到在这样的转换过程中,是不是存在一定的“风险”?

Java自身是一门严谨的编程语言,如果不存在风险,为何还需要我们作人为的"强制“性转换呢?

而事实上也正是如此。我们首先应当了解,Java中对一个高位数数据转换为低位数数据类型时,实际上是在对二进制表现形式做有效位的截取。

我们知道一个二进制数的位数越多,其取值范围也就越大,也就是说它的可能值越多。

这也就意味着,如果将一个高位数的数据类型转换为低位数的数据类型,那么便可能发生:很多高位数能够表达的可能值,低位数表达不了的情况。

这也正是其”风险“所在:转换的过程中,可能造成数据丢失!


我们举个例子来说:

假设我们有一个int型的变量,值为128。相应的,我们将其转换为二进制表现形式就是:0000 0000 - 0000 0000 - 0000 0000 - 1000 0000。

如果我们要将其转换为byte类型。那么byte类型的数据长度为8位,所以我们进行有效位的截取后,值变为了:1000 0000。

我们知道二进制数的最高有效位用以表示符号,所以这里转后的值的实际值变为了十进制当中的-128。所以128在这个转换中,值由原本的128变为了-128。


既然高位数数据类型转换低位数数据类型存在这样的风险,那么作为一门健壮的语言,Java自然是不支持这样的转换的。

所以,为我们了提供了(type)value这样的强制转换方式,我们这样做的意义就在于,告诉编译器,我了解这样做可能承担风险,但这个风险由我来承担。

最后,我们通过代码来验证我们刚刚的转换过程:

           int i1 = 127;
           byte b1 = (byte) i1;
           System.out.println("b1="+b1);
           
           int i2 = 128;
           byte b2 = (byte) i2;
           System.out.println("b2="+b2);

其运行的输出结果为:

b1=127

b2=-128

通过其结果恰恰验证了我们提到的转换过程。

因为127本身在byte的取值范围之内,所以强制转换过后,数据仍然正确。但128超出了byte的取值范围,所以在经过有效位的截取之后,值发生了变化,变为了-128.


第二种情况:浮点数类型转换为整数类型需要进行强制转换,因为小数点后的数在转换过程中会被丢弃

            double d = 128.123;
            //转换后的值变为了128
            int i = (int) d;
            System.out.println(i);


到此,我们以Java的变量(常量)为切入点,又重新回顾了Java中8种基本数据类型的特点和使用。


  • 7
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值