【Java基础】Java数据类型

数据分类

Java数据类型分为:基本数据类型 和 对象(引用)数据类型。程序中需要处理许多数据,对于不同数据都有其对应的数据类型,其实就是在内存中开辟一个存储空间来存放数据,不同数据所开辟的内存大小也会不一样。

数据存储的单位

位(bit)、字节(byte)是计算机数据存储的单位。位是最小的存储单位,每一个位存储一个1位的二进制码(即每一个逻辑0或者1便是一个位),一个字节由8位组成。

Java数据类型
类型名称 关键字 占用内存 取值范围
字节型 byte 1 字节 -128 ~ 127(-27 ~ 27-1)
短整型 short 2 字节 -32768 ~ 32767(-215 ~ 215-1)
整型 int 4 字节 -231 ~ 231-1
长整型 long 8 字节 -263 ~ 263-1
单精度浮点型 float 4 字节 -231 ~ 231-1(6~7 个有效位)
双精度浮点型 double 8 字节 -263 ~ 263-1 (15 个有效位)
字符型 char 2 字节 0 ~ 216 -1(ISO 单一字符集)
布尔型 boolean 1 字节 true 或 false

字节(B)是计算机信息技术用于计量存储容量和传输容量的一种计量单位,1个字节等于8位二进制,即1B=8bit。

// 整数
byte v1 = 123; // 十进制
short v2 = 0b11001; // 0B11001; 二进制(以 0b 或 0B 开头)
int v3 = 0xF78A; // 0XF78A、0Xf78a; 十六进制(以 0x 或 0X 开头)
long v4 = 199L; // 199l; long 类型以 L 或者 l 结尾

// 浮点数
float v5 = 123.4F;  // 123.4f;float 类型以 F 或者 f 结尾
double v6 = 123.4D; // 123.4d;double 类型以 D 或者 d 结尾
double v7 = 123.4;  // 默认就是 double 类型,可以省略 D 和 d 结尾符
// 可以用科学计数法(E 或 e 表示的是 10 的多少次方)
float v8 = 1.234E2F;  // 表示的是 1.234F × 10^2
double v9 = 1.234e2;  // 表示的是 1.234 × 10^2

// 字符和字符串
char ch = 'A'; // 单引号表示字符
String str = "ABCD"; // 双引号表示字符串

// 在数字中使用下划线(从Java 7开始,可以给数字添加下划线增强可读性)
int a = 1_0000_0000; // 100000000

// 注意1:不能在数字的前后使用下划线
// int x = _123;
// int x = 123_;
// 注意2:不能在小数点、X、B、F、D、L、E等特殊字符的前后使用下划线
// byte x = 0x_12;
// byte x = 0_b10010;
// float x = 1._23;
// float x = 1.23F_;
// long x = 189_L;

原码、反码、补码

数据在计算机中都是用 二进制 表示的,并且是用 补码 进行数据计算。在学习原码、反码和补码之前,需要先了解机器数和真值的概念。

  1. 机器数:表示一个数在计算机的二进制表示形式。机器数它是带符号的,在最高位用来存放符号,正数为0,负数为1。

  2. 真值:带符号表示的机器数对应的真正的数值称为真值。
    因为第一位是符号位,所以机器数的形式值就不等于真正的数值。

如:有符号数10000011,其最高位1代表负,其真正数值是-3,而不是形式值131(10000011转换成十进制等于131)

  1. 原码:就是符号位加上其真值的绝对值,即用第一位表示符号,其余位表示值。
// 举个例子:
+1的原码:00000001
-1的原码:10000001
  1. 反码:如果是正数,正数的反码等于原码;如果是负数,除符号位不变,其它位按位取反(1变0;0变1)。
// 举个例子:
+1的反码:00000001 ===> 00000001
-1的反码:10000001 ===> 11111110
  1. 补码:如果是正数,正数的补码等于原码;如果是负数,在原码基础上符号位不变,其它各位取反,最后再+1。
// 举个例子:
+1的原码:00000001
+1的反码:00000001
+1的补码:00000001
 
-1的原码:10000001
-1的反码:11111110
-1的补码:11111111
  1. 数据(±1)在内存中存储细节
public class TestClass {

    public static void main(String[] args) {
        // 数据±11在内存中存储细节:在计算机中存储的是一个数的补码
        byte a = 0b00001011;        // 11的补码        (机器数)
        byte b = (byte) 0b11110101; // -11的补码       (机器数)
        byte c = (byte) 0b10001011; // -117的补码      (机器数)
        System.out.println(a); // 打印结果:11         (真值)
        System.out.println(b); // 打印结果:-11        (真值)
        System.out.println(c); // 打印结果:-117       (真值)
    }
    
    // 真值:+11
    // 原码:00001011
    // 反码:00001011 (取反)
    // 补码:00001011 (加1)---->是+11在内存中存储的数(机器数)
    
    // 真值:-11   
    // 原码:10001011
    // 反码:11110100 (取反)
    // 补码:11110101 (加1)---->是-11在内存中存储的数(机器数)
    
    // 补码:0b10001011    -------->是-117在内存中存储的数(机器数)
    // 反码:0b10001010 (补码-1)
    // 原码:0b11110101 (取反)
    // 真值:-117
}
  1. 为什么要设计反码、补码?

因为计算机 只有加法,没有减法。在做减法运算的时候,可以认为是加上一个负数,这样可以 减少计算机电路的复杂度

举例说明:

十进制的加法:1+1=2;
二进制的加法:1+1=00000001+00000001=00000010=2;
 
十进制的减法:1-1=0;
二进制的减法:1-1=1+(-1)=00000001+10000001=10000010=-2

从上面的运算中,我们使用的是原码的方式进行计算,加法没问题,但是减法结果居然为-2,于是针对这个情况(原码做减法),出现了反码,我们来看看效果:

十进制的加法:1+1=2;
二进制的原码加法:1+1=00000001+00000001=00000010=2;
二进制的反码加法:1+1=00000001+00000001=00000010=2;
 
 
十进制的减法:1-1=0;
二进制的原码减法:1-1=1+(-1)=00000001+10000001=10000010=-2;
二进制的反码减法:1-1=1+(-1)=00000001[反]+11111110[反]=11111111[反]=10000000[原]=-0;

这里可以得到反码11111111,然后我们需要将其反码换成人看得懂的原码,11111111[反]=10000000[原]=-0。通过反码计算确实可以得到正确答案,这也就是为什么要有反码的出现。

但是,还有一个问题:就是 00000000 可以表示 +0,10000000 可以表示 -0,从人的角度来说 +0 和 -0 是一样的,0带符号没有任何意义,用2个编码实在是浪费。

于是补码的出现,解决了0的符号以及两个编码的问题

十进制的减法:1-1=0;
二进制的原码减法:1-1=1+(-1)=00000001+10000001=10000010=-2;
二进制的反码减法:1-1=1+(-1)=00000001[反]+11111110[反]=11111111[反];
二进制的补码减法:1-1=1+(-1)=00000001[补]+11111111[补]=00000000[补]=00000000[原];

得到结果是 00000000,为什么是 00000000 而不是 100000000,因为一个字节只能装8位,现在后面的8位就是 00000000,于是就得到了0,而以前出现问题的 -0 则不存在了。

而且可以用 1000 0000(-0的补码) 表示-128, 所以-128并没有原码和反码表示。于是我们的计算机当中规定-0的补码就是-128在计算机当中的存储方式(即规定用10000000来代表-128的补码参与计算),这样也可好可以满足计算机当中的计算。

使用补码,不仅仅修复了0的符号以及存在两个编码的问题,而且还能够多表示一个最低数。这就是为什么8位二进制,使用原码或者反码表示的范围是[-127 ~ 127],而使用补码表示的范围为[-128 ~ 127]。

-128为什么可以用100000000表示?
这里我分析的是byte,它就8位。在无符号位的二进制中128的表示为1000 0000。有符号位的情况下byte好像无法表示+128或-128。

如果我们假设byte不是占用8位,而是9位,最高位是符号位。你们-128的表示为1 10000 0000,计算其补码也是1 1000 0000,很神奇吧,一样的。-128补码尾8位就是1000 0000。那就规定1000 0000是-128的补码,而-128是没有原码和反码的,即不能利用10000 0000反推其反码和原码。

用10000000来代表-128的补码参与计算,举例说明:

// 例1:
-128 + 127 = 1000 0000(补码)+ 0111 1111(补码)= 1111 1111(补码)= 1111 1110(反码) =  1000 0001(原码)= -1
// 例2:
十进制:-1+(-127)=-128
二进制原码:10000001+11111111
二进制反码:11111110+10000000
二进制补码:11111111+10000001=10000000[只保留8位]

所以在原码和反码中, byte 的范围是[-127,127];在使用补码后,不仅可以解决±0的符号以及两个编码的问题,而且还能多一个最低数-128(人为规定用 10000000 来占 -128 这个位置,即10000000就是-128的补码),这就是为什么 byte 的范围是[-128,127]。

  1. 总结:
  • 原码是人能理解的,反码和补码需要转换为原码我们才能看懂;
  • 反码是为了解决减法运算。
  • 补码是为了解决反码产生的±0的问题。
  • 在原码、反码、补码相互转换以及求对应的十进制求值时,符号位是绝不参与的;但是在加减过程中,是参与位运算的。
  • 对于一个数,计算机要使用一定的编码方式进行存储;原码、反码、补码是机器存储一个具体数字的编码方式;
  • 数据在计算机内部是以补码的形式储存的。

ASCII码

ASCII(American Standard Code for Information Interchange,美国信息互换标准代码)是一套基于拉丁字母的字符编码,共收录了 128 个字符,用一个字节就可以存储,它等同于国际标准 ISO/IEC 646。

  • 常用ASCII 编码:
十进制 字符
48 '0'
65 'A'
97 'a'

进制

  1. 基本概念

进制:是一种计数的方式,数值的表示形式

//  十进制:逢十进一        (如:13 == 1 * 10 + 3)
//  八进制:逢八进一        (如:15 == 1 * 8 + 5)
//  二进制:逢二进一        (如:1101 == 1 * 2 * 2 * 2  + 1 * 2 * 2 + 0 * 2+ 1)
//  十六进制:逢十六进一    (0 ~ 9  A ~  F     如:d  ==  13)

int num = 12; // 默认就是10进制
int num1 = 014; // 在前面加上一个0就代表八进制
System.out.format("%d\n", num1); // %d是以十进制的方式输出一个整数
System.out.format("%o\n", num); // %o是以八进制的方式输出一个整数

int num2 = 0b1100; // 在数值前面加上0b或0B就代表二进制
System.out.format("%d\n", num2); // 在C语言中没有提供二进制的输出格式符

int num3 = 0x6c; // 在数值前面加上0x就代表十六进制
System.out.format("%d\n", num3);
System.out.format("%x\n", num); // %x是以十六进制的方式输出一个整数
  1. 常见的进制转换

10 转 2:除2取余法,把10进制数除以2,然后取得余数的序列,再倒序。

方法:整数部分“除2取余法”,小数部分“乘2取整法”,高位补0,将得到的余数倒序得到的序列就是二进制的形式。

例如:将十进制(97)转换为二进制数(1100001)

10进制 转 2进制

2 转 10:所有位的位权相加:101 = 1 * 20 + 0 * 21 + 1 * 22
2 转 16:4合1法。把一个二进制数,整数部分从右向左(小数部分从左向右)4位结合成1位,不足部分补0。

2进制 转 16进制

16 转 2:1拆4法,16进制的1位拆成二进制的4位。

16进制 转 2进制

2 转 8:3合1

2进制 转 8进制

8 转 2:1拆3
10 转 8:除8取余

位运算符

位运算:用于整数的二进制位之间的运算。

  • 计算机是以其补码的形式存储数据;
  • 位运算是补码之间的运算,运算结果是补码;
  • 最后要补码 转 原码,根据原码去算十进制数值。
  1. & 按位与
& 按位与
  1. | 按位或
| 按位或
  1. ~ 按位取反
~ 按位取反
  1. ^ 按位异或
^ 按位异或
  1. << 左移位
<< 左移位
  1. >> 右移位
>> 右移位
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容