这节课我们来学习java的基本数据类型,首先来看Q&A:
Q: 何谓数据类型?
A: 程序的本质是处理各种数据,在计算机底层来讲数据本身没有类型。而数据类型则表示一个数据是以什么类型来表示。
Q: 何谓基本?
A: java中最基础的数据类型,存在于栈内存(死记硬背,以后会讲含义)。仅包含数据,可直接使用。与之相对的为引用类型(以后会讲到)。
计算机中数据的最小单位是比特(bit),由于计算机系统的电路设计它只能表示为0或1,8个比特位组成一个字节(byte),byte是数据存储的最小单位。以下是java中基本数据类型以及各类型取值范围。
数据类型 | 类型区分 | 占用空间 | 默认值 | 取值范围 |
---|---|---|---|---|
byte | 整形 | 1字节 | 0 | -2^7 ~ 2^7-1 |
short | 整形 | 2字节 | 0 | -2^15 ~ 2^15-1 |
int | 整形 | 4字节 | 0 | -2^31 ~ 2^31-1 |
long | 整形 | 8字节 | 0L | -2^63 ~ 2^63-1 |
float | 浮点型 | 4字节 | 0.0F | 3.4e+38 ~ 1.4e-45 |
double | 浮点型 | 8字节 | 0.0D | 1.8e+308 ~ 4.9e-324 |
char | 字符型 | 2字节 | 0 | 0 ~ 2^16-1 |
boolean | 布尔型 | 1字节 | false | true/false |
以上内容非常简单,前三列记住即可。你可能疑惑为什么取值范围都是乱七八糟的。现在来学习为什么取值范围都不是我们预料的整数。
我们前面提到byte是数据存储的最小单位,而byte作为基本数据类型的一种,它的长度就是1byte,而1byte=8bit
。以byte为例,byte在内存中表示如下:
整形数据的最高位为符号位,0表示正数,1表示负数。后面的bit为数据位,byte可以表示7个数据位长度的数据。那么7个数据位可以表示的正数范围如下:
我们知道1bit最大只能表示1,那么2bit最大可以表示2^1+1 = 3
,以此类推7位可表示的最大值为上图中依次相加,就等于2^7-1,也即十进制的127。在计算机中,数据的表示都是以“补码”展现,正数的补码是其本身(本身又叫“原码”),而负数的补码需要将原码除符号位之外的每一位取反(0变成1,1变成0)后得到反码,然后加1,略微复杂。初学可能不太好理解,在后续的课程中会推出专门的课题来介绍原码、补码、以及反码。
由以上得知负数的补码为原码除符号位外按位取反后+1,我们来看byte1类型的-1在内存中是如何表示的:
因为负数的符号位为1,所以-1的原码为10000001
,符号位不变,其他位取反得到反码11111110
,而补码为反码+1,那么-1的补码表示11111111
。大家可能会注意到整形数据的最大值和最小值的绝对值并不是一样的,例如byte的最大值为127,而最小值为-128,这是怎么做到的呢?
注意到+0表示为00000000
,而-0可以表示为10000000
。但在现实中+0与-0都是表示0。为了不必要的浪费。在计算机系统中,10000000
表示为最小值,如果是byte那么最小值就表示为-128.
由此我们可以推演到short、int、long都是如此。
float为单精度浮点型数据类型,double为双精度浮点型数据类型。这两种类型都可以表示小数,实际上只有精度和取值范围区别。切记不可用于货币等关键数据的处理,因为浮点型数据无法表示准确地表示一个小数(同样以后再讲)。float的默认值为0.0f,而double的默认值为0.0d。注意最后的f和d。示例:
float data1 = 1.2f;
double data2 = 2.34d;
char类型是一个单一的 16 位 Unicode 字符,注意其不存在符号位(最高位也是数据位),所以其范围为0~2^16-1(65535)
。char可以存储任何字符,注意其存储的是字符数据而非整形数据。假如我们以如下方式赋值,输出结果并不是想当然的65,如下:
char c = 65;
System.out.println(c);
-----------输出结果-------------
A
这是因为65在Unicode中表示A这个字符,如果我们想赋值A到char c,我们可以使用单引号括起来。
char c = 'A';
System.out.println(c);
-----------输出结果-------------
A
在Java中所有基本类型都有一个与之对应的类。比如int类型对应Integer类,double类型对应Double类。这些类被称为包装器类(wrapper)。Java有8种基本类型,有9个包装器,分别为:Intger、Long、Short、Byte、Double、Float、Character、Boolean以及Void。
那么问题又来了,为什么需要包装器类型?我们知道基本数据类型仅包含了数据,在实际开发中其他系统可能传入一个数值过来,如果使用基本数据类型我们无从判断这个值是否存在。这个时候必须要用到包装器类型,因为包装器类型允许值为null,可以通过值是否为null来判断这个值是否真实存在。另外包装器类型提供了许多便捷的方法,避免我们重复造轮子。
以下是各数据类型的基础示例:
public class TestDataType {
public static void main(String[] args) {
// byte
System.out.println("基本数据类型byte 所占bit数:" + Byte.SIZE);
System.out.println("byte的包装器类型为:java.lang.Byte");
System.out.println("最小值:" + Byte.MIN_VALUE);
System.out.println("最大值:" + Byte.MAX_VALUE);
System.out.println("-------------------------------------------");
// short
System.out.println("基本数据类型short 所占bit数:" + Short.SIZE);
System.out.println("short的包装器类型为:java.lang.Short");
System.out.println("最小值:" + Short.MIN_VALUE);
System.out.println("最大值:" + Short.MAX_VALUE);
System.out.println("-------------------------------------------");
// int
System.out.println("基本数据类型int 所占bit数:" + Integer.SIZE);
System.out.println("int的包装器类型为:java.lang.Integer");
System.out.println("最小值:" + Integer.MIN_VALUE);
System.out.println("最大值:" + Integer.MAX_VALUE);
System.out.println("-------------------------------------------");
// long
System.out.println("基本数据类型long 所占bit数:" + Long.SIZE);
System.out.println("long的包装器类型为:java.lang.Long");
System.out.println("最小值:" + Long.MIN_VALUE);
System.out.println("最大值:" + Long.MAX_VALUE);
System.out.println("-------------------------------------------");
// float
System.out.println("基本数据类型float 所占bit数:" + Float.SIZE);
System.out.println("float的包装器类型为:java.lang.Float");
System.out.println("最小值:" + Float.MIN_VALUE);
System.out.println("最大值:" + Float.MAX_VALUE);
System.out.println("-------------------------------------------");
// double
System.out.println("基本数据类型double 所占bit数:" + Double.SIZE);
System.out.println("double的包装器类型为:java.lang.Double");
System.out.println("最小值:" + Double.MIN_VALUE);
System.out.println("最大值:" + Double.MAX_VALUE);
System.out.println("-------------------------------------------");
// char
System.out.println("基本数据类型char 所占bit数:" + Character.SIZE);
System.out.println("char的包装器类型为:java.lang.Character");
// 以数值形式输出
System.out.println("最小值:" + (int) Character.MIN_VALUE);
System.out.println("最大值:" + (int) Character.MAX_VALUE);
}
}
编译执行后输出:
基本数据类型byte 所占bit数:8
byte的包装器类型为:java.lang.Byte
最小值:-128
最大值:127
-------------------------------------------
基本数据类型short 所占bit数:16
short的包装器类型为:java.lang.Short
最小值:-32768
最大值:32767
-------------------------------------------
基本数据类型int 所占bit数:32
int的包装器类型为:java.lang.Integer
最小值:-2147483648
最大值:2147483647
-------------------------------------------
基本数据类型long 所占bit数:64
long的包装器类型为:java.lang.Long
最小值:-9223372036854775808
最大值:9223372036854775807
-------------------------------------------
基本数据类型float 所占bit数:32
float的包装器类型为:java.lang.Float
最小值:1.4E-45
最大值:3.4028235E38
-------------------------------------------
基本数据类型double 所占bit数:64
double的包装器类型为:java.lang.Double
最小值:4.9E-324
最大值:1.7976931348623157E308
-------------------------------------------
基本数据类型char 所占bit数:16
char的包装器类型为:java.lang.Character
最小值:0
最大值:65535
Java支持二进制,八进制,十进制,十六进制的数值表示,我们可以以如下方式定义一个整形数值:
//二进制,以0b或0B开头
int binary = 0b100;
//八进制,以0开头
int octal = 0100;
//十进制,无特殊写法
int decimal = 100;
//十六进制,以0x或0X开头
int hex = 0x100;
System.out.println("二进制下100的十进制表示:" + binary);
System.out.println("八进制下100的十进制表示:" + octal);
System.out.println("十进制下100的十进制表示:" + decimal);
System.out.println("十六进制下100的十进制表示:" + hex);
以上代码编译输出结果:
二进制下100的十进制表示:4
八进制下100的十进制表示:64
十进制下100的十进制表示:100
十六进制下100的十进制表示:256
假如需要将一个long类型数据转化为int,或将byte类型数据转为int。就需要类型转换,类型转换分为自动类型转换
与强制类型转换
两种。
将占内存空间小的类型转换为占内存空间大的类型时,不存在转换风险,java会替我们完成自动类型转换。示例:
int a = 1;
long b = a;
以上代码可以编译通过,因为int为4字节而long为8字节。如果颠倒顺序编译器将不会通过编译,示例:
long a = 1;
int b = a; //无法通过编译
既然java不会自动将长类型转化为短类型,我们有没有办法强行转为短类型呢?答案是有的。可以使用如下写法:
long a = 1;
int b = (int)a; //编译通过
因为将长类型转化为短类型有潜在风险,如果不小心将一个int a = 10000
赋值给byte b
而编译器又放行的话,这将很有可能带来严重问题。而java还是赋予了程序员显式转换的能力,但是在强制转换前一定要清楚地了解转换的风险。
我们知道强制类型转换的潜在风险是精度丢失,那么究竟丢失了多少呢?我们来分析一下
a为int类型占4字节,在内存中表示如下:
00000000 00000000 00100111 00010000
而byte为1个字节,java类型强制转换实际上是丢弃多余的bit,可以理解为截断超过需要被赋值的类型的长度。现在很容易得到byte b在内存中表示如下:
00010000
以十进制表示,b的值为16。我们来执行一下以上代码:
public static void main(String[] args) {
int a = 10000;
byte b = (byte) a;
System.out.println(b);
}
编译运行输出结果:16
与我们预料的没差,验证了我们前面的猜测。
这节课我们学习了java基本数据类型的相关知识,着手多练习有助于快速提高哦,下一节我们将学习变量类型。
老王的JAVA基础课:序言
老王的JAVA基础课:第1课 计算机基础知识
老王的JAVA基础课:第2课 JDK安装和环境变量配置
老王的JAVA基础课:第3课 IDEA的安装和使用
老王的JAVA基础课:第4课 以hello world学习基础语法
老王的JAVA基础课:第5课 面向对象
2020年高效搬砖必备的IDEA插件(附安装包)
详解从p12证书提取RSA公私钥和序列号(小白向)
本教程同时发布在我的公众号:Java学步园,欢迎加入JAVA初级交流群:757443185,滑到最上面左侧扫描二维码哦~