老王的JAVA基础课:第6课 JAVA基本数据类型

在这里插入图片描述

什么是基本数据类型

这节课我们来学习java的基本数据类型,首先来看Q&A:
Q: 何谓数据类型?
A: 程序的本质是处理各种数据,在计算机底层来讲数据本身没有类型。而数据类型则表示一个数据是以什么类型来表示。
Q: 何谓基本?
A: java中最基础的数据类型,存在于栈内存(死记硬背,以后会讲含义)。仅包含数据,可直接使用。与之相对的为引用类型(以后会讲到)。

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.0F3.4e+38 ~ 1.4e-45
double浮点型8字节0.0D1.8e+308 ~ 4.9e-324
char字符型2字节00 ~ 2^16-1
boolean布尔型1字节falsetrue/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为单精度浮点型数据类型,double为双精度浮点型数据类型。这两种类型都可以表示小数,实际上只有精度和取值范围区别。切记不可用于货币等关键数据的处理,因为浮点型数据无法表示准确地表示一个小数(同样以后再讲)。float的默认值为0.0f,而double的默认值为0.0d。注意最后的f和d。示例:

float data1 = 1.2f;
double data2 = 2.34d;

char类型

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

boolean类型

在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。就需要类型转换,类型转换分为自动类型转换强制类型转换两种。

1. 自动类型转换

将占内存空间小的类型转换为占内存空间大的类型时,不存在转换风险,java会替我们完成自动类型转换。示例:

int a = 1;
long b = a;

以上代码可以编译通过,因为int为4字节而long为8字节。如果颠倒顺序编译器将不会通过编译,示例:

long a = 1;
int b = a; //无法通过编译
2. 强制类型转换

既然java不会自动将长类型转化为短类型,我们有没有办法强行转为短类型呢?答案是有的。可以使用如下写法:

long a = 1;
int b = (int)a; //编译通过
3. 为什么java不自动转化所有类型?

因为将长类型转化为短类型有潜在风险,如果不小心将一个int a = 10000赋值给byte b而编译器又放行的话,这将很有可能带来严重问题。而java还是赋予了程序员显式转换的能力,但是在强制转换前一定要清楚地了解转换的风险。

灵魂拷问:将int a = 10000赋值给byte b = (byte) a,那么b是多少?

我们知道强制类型转换的潜在风险是精度丢失,那么究竟丢失了多少呢?我们来分析一下
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,滑到最上面左侧扫描二维码哦~

  • 19
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 20
    评论
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值