Java 的八大基本类型及其包装类型(超级详细)

news2024/11/18 14:51:05

        Java 中有八种内置的基本数据类型,他们分别是 byte、short、int、long、float、double、char 和 boolean,其中,byte、short、int 和 long 都是用来表示整数,float 和 double 是用来表示浮点数的,那它们之间有什么区别和联系呢?除了这八种基本类型(primitive type)外,其余的类型都是引用类型(reference type)。但是包装类型(wrapper class) Integer 和 Long 也可以用来表示整数,那它们与 int 和 long 又有什么区别和联系呢?这八种基本类型之间的运算关系又是怎样的呢?

一、基本类型

基本类型的表示范围

八种基本类型中,char 类型是用来表示字符的,boolean 类型是用来表示布尔值的,除此之外的 6 种都是用来表示数字的。byte、short、int 和 long 是用来表示整数的,float 和 double 是用来表示浮点数的。下面是每一种类型能表示的范围:

基本类型位数最小值最大值
byte8-128 (-2^7)127 (2^7-1)
short16-32,768 (-2^15)32,767 (2^15-1)
int32-2,147,483,648 (-2^31)2,147,483,647 (2^31-1)
long64-9,223,372,036,854,775,808 (-2^63)9,223,372,036,854,775,807 (2^63-1)
float32

1.4E-45 (0x0.000002P-126)

3.4028235E38 (0x1.fffffeP+127)
double64

4.9E-324 (0x0.0000000000001P-1022)

1.7976931348623157E308 (0x1.fffffffffffffP+1023)

char16\u0000 (0)\uFFFF (65,535)
boolean1falsetrue

定义变量时超过对应数据类型最大的表示范围的话将报错。位数越大,单个该数据类型的变量所占用的内存就越多。

每一种类型的最大最小值都保存在了其对应包装类型的属性中,如 Integer.MAX_VALUE 的值为 2147483647,关于包装类型,下面会做详细说明。

类型的默认值

每一种类型都有一个默认值,除基本类型外,其他的类型的默认值都是 null,因为它们都是引用类型。整数默认为 int 类型,浮点数默认为 double 类型。

类型默认值
byte0
short0
int0
long0L
float0.0f
double0.0
char'\u0000'
booleanfalse
String、Integer 等引用类型null

当我们定义静态的基本类型变量时,它们将采用默认值:

public class Test {
    static byte b;
    static short s;
    static int i;
    static long l;
    static float f;
    static double d;
    static char c;
    static boolean bool;
    static String str;

    public static void main(String[] args) {
        System.out.println("byte " + b);  // byte 0
        System.out.println("short " + s);  // short 0
        System.out.println("long " + l);  // long 0
        System.out.println("int " + i);  // int 0
        System.out.println("float " + f);  // float 0.0
        System.out.println("double " + d);  // double 0.0
        System.out.println("char " + c);  // char '\u0000' (这个显示不出来)
        System.out.println("boolean " + bool);  // boolean false
        System.out.println("String " + str);  // String null
    }
}

类型之间的转换

类型之间的转换有自动类型转换和强制类型转换两种。自动类型转换也称隐式转换,是编译器自动进行的,强制类型转换称为显式转换,是写代码时显式地完成的。

自动类型转换(隐式转换) 

在八种基本数据类型中,除开 boolean 类型,其他的七种都是可以互相进行运算的(如加减法运算)。不同的类型在进行运算的时候,低位的数据类型会向高位的转化,最后的计算结果将是整个运算过程中数据类型位数最大的,这就是自动类型转换。

int a = 1;
long b = 2;
int c = a + b;  // Error
long c = a + b;  // Right

但要注意一点,比 int 类型数据小的数据类型在做运算的时候,会转换成 int 类型然后再做运算,尽管计算结果能被 byte 或 short 类型表示:

short c = 1, d = 2;
short e = c + d;  // Error
int e = c + d;  // Right

自动类型转换的规则可以总结为如下: 

若有一个变量是 double 类型,则另一个也会被隐式转换为 double 类型;否则,若有一个变量是 float 类型,则另一个也会被隐式转换为 float 类型;否则,若有一个变量是 long 类型,则另一个也会被隐式转换为 long 类型;否则,若有一个变量是 int 类型,则另一个也会被隐式转换为 int 类型。特别的,boolean 类型无法转换(包括自动类型转换和强制类型转换)

即,自动类型转换优先级为:double > float > long > int > short = char = byte (boolean 不可转换)

注意:在 short、byte 和 char 之间不会发生自动类型转换,它们运算时都会先转换成 int 类型,结果最终也是 int 类型,所以前面说,比 int 还小的类型在运算时会被自动转换为 int 类型。

强制类型转换(显式转换)

强制类型转换就是在程序中显式地将一个变量从某一类型强制转换成另一类型。从小位类型到大位类型的转换是向上转换,一般这是没有问题的,但反过来,从大位类型转换到小位类型,即向下转换,是有可能发生数据溢出或者精度损失的。

int a = 32768;
float b = 3.1415926f;
System.out.println((long)a);  // Right
// Output: 1

System.out.println((short)a);  // overflow
// Output: -32768

System.out.println((int)b);  // loss of accuracy
// Output: 3

数据溢出和精度损失

这里关于数据溢出和精度损失做一些简单的说明。

数据溢出

数据溢出之后变量也还是有值的,程序也不会报错,那溢出后的值是如何计算出来的?这实际上和数据存储的规则有关,涉及到原码、反码和补码等知识,这里不会详细说明这个规则,我们只需要一张图便能知道溢出后的值是如何计算得到的。

数据溢出解释图(以 short 类型为例)

举个例子,int 类型变量值为 131073,在强制类型转换为 short 类型后值就变为了 1。我们可以这样理解,上面的图是 short 类型变量所有的取值,从 0 开始,131073 一个一个去对应,到 32768 时发生数据溢出,变成了 -32768,继续顺时针旋转去对应每个数,最会对应两圈多两个数,然后 131073 对应到第三圈的第二个数字 1,因此,强制类型转换数据溢出后的结果为 1。

注意:131073 = 65536 * 2 + 1

int a = 131073;
System.out.println((short)a);  // Output: 1

精度损失

在数据存储长度比较长的数据转换为数据存储长度较短的类型时,就可能会发生精度损失,因为要把长数据变成短数据只能将数据后面多余的部分截断才行。因为转换方式采用的是截断多余的,因此我们可以认为当浮点型数据转换为整型数据时是做了一个向零取整的操作(直接舍去小数)。

float a = 3.14f, b = -3.14f;
System.out.println((int)a);  // Output: 3
System.out.println((int)b);  // Output: -3

隐含强制类型转换

除了前面提到的两种,还有一种隐含的强制类型转换,一个整数数字(int 表示范围之内的)会被隐含地转换成 int 类型,一个浮点数字会被隐含地转换成 double 类型。这也解释了为什么前面说整数默认是 int 类型,浮点数的默认类型是 double 类型了。所以,以后在用 float 类型时一定要在后面加上字母 f 或 F,long 类型后面要加上字母 l 或者 L

二、包装类型

基本数据类型并不是对象,但为了编程的方便,Java 还是引入了它们,也就是前面提到的八个基本类型,但要将其作为对象来操作的话,还是要用这八个基本类型对应的包装类型(wrapper class)。这个包装类型就是 Java 对基本类型的封装,使其能作为对象使用,它们与其他的类型并没有什么太多的区别,都是引用类型(reference type)。

基本类型包装类型

byte

Byte
shortShort
intInteger
longLong
floatFloat
doubleDouble
charCharacter
booleanBoolean

在 Java5 的时候引入了自动装箱/拆箱机制,使得基本类型和对应的包装类型之间可以相互转换。

基本类型和包装类型的区别

基本类型和包装类型在使用时所表示的值是一样的,表示的范围也是对应的,当 int 类型在转换为 Integer 类型的时候,实际上是调用了 Integer 的 valueOf 方法:

Integer a = 1;
Integer a = Integer.valueOf(1);
// the two are equivalent

下面我们列出基本类型和包装类型的一些区别:

  • 基本类型不是对象,而包装类型是对象(有属性和方法);
  • 基本类型不需要实例化,而包装类型需要实例化;
  • 基本类型是直接存储的值,而包装类型是对实例对象的引用;
  • 基本类型有特殊的默认值(如 int 的默认值是 0),而包装类型都是 null;
  • 基本类型所占用的内存比较少,包装类型占用内存较大;
  • 同一基本类型相同值的不同变量的内存地址一样,但实例化得到的同一包装类型相同值的不同变量的内存地址不一样;
  • 基本类型的运算是直接进行的,而包装类型的运算要先拆箱为基本类型才能进行运算。

对象有属性和方法,前面提到的 Integer.MAX_VALUE 就是包装类型的一个属性,上面提到的 Integer.valueOf() 就是一个方法,而基本类型 int 是没有这些的。

基本类型的值都是直接储存的,所以同一个基本类型、相同值的不同变量的地址是一样的:

int a = 1, b = 1;
System.out.println(a == b);  // Output: true

包装类型都是对象实例化的引用,一般每个对象都拥有不同的内存空间,它们的内存地址也就不一样:

Integer a = new Integer(100);
Integer b = new Integer(100);
System.out.println(a == b);  // Output: false

valueOf 方法的缓存机制

如果一个 Integer 实例对象是由基本类型转换而来的,值处于 -128 ~ 127 之间时,之前的代码输出结果就为 true 。是因为转换时调用的 valueOf 方法有一个缓存机制。 这个判断范围 -128 ~ 127 是默认的,可以在 JVM 提供的配置 (-XX:AutoBoxCacheMax) 进行修改。

为什么要有这个缓存机制?这是因为处于这个区间的值比较小,而且又比较常用,因此编译器就提前将其缓存了,需要时就直接从缓存里拿,既能提高速度,又能在同样值的包装类型较多的时候节省内存。所以,两个值在 -128 ~ 127 之间,且由基本类型 int 转换而来的 Integer 就是同一个对象。这对于包装类型 Byte、Short 和 Long 也是一样的。

Integer a = 100, b = 100;
System.out.println(a == b);  // Output: true

Integer c = 128, d = 128;
System.out.println(c == d);  // Output: false

与此类似的还有包装类型 Boolean,它一共就只有两种可能,true 和 false,因此也被提前缓存了。包装类型 Character 在 '\u0000' ~ '\u007F' 之间的值(0 ~ 127)也是被提前缓存了。不过包装类型 Float 和 Double 的 valueOf 方法就没有这个缓存机制了。

基本类型和包装类型的联系

为什么包装类型叫做“包装类型”呢?顾名思义,就是对基本类型的一个封装,从名字里我们就能知道,基本类型和包装类型之间的实际上有个装箱与拆箱的关系。

直接由基本类型 int 转化而来的 Integer 对象是对 int 类型的装箱操作,而由 Integer 对象转换来的 int 类型变量就是对 Integer 对象的拆箱操作。

Integer a = 1;  // 装箱
Integer a = Integer.valueOf(1);  // 等价形式

int b = a;  // 拆箱
int b = a.intValue();  // 等价形式

实例化生成的 Integer 类型变量与基本类型转化而来的 integer 类型变量尽管值相同,但内存地址并不相同(非 new 生成的 Integer 对象指向 Java 常量池中的对象),不是同一个对象,所以在比较的时候输出 false。但是当二者与基本类型相同值的变量去比较时却都输出 true。

Integer a = 1;
Integer b = new Integer(1);
System.out.println(a == b);  // Output: false

int c = 1;
System.out.println(c == a);  // Output: true
System.out.println(c == b);  // Output: true

这是因为包装类型 Integer 与基本类型在比较的时候会自动拆箱为 int 类型,然后再去比较,这样所得到的结果就是一样的,因此输出 true。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/541832.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++】哈希/散列详细解析

前言:上篇文章介绍了unordered_set和unordered_map序列关联式容器,它们之所以效率比较高,是因为其底层使用了哈希结构。,所以这篇文章我们就来详细讲解一下哈希表。有关unordered序列关联式容器的知识,请移步至这篇文章…

单片机--USART

目录 【2】USART 【3】串口通信协议 【4】相关寄存器 串口控制寄存器 波特率寄存器 中断和状态寄存器 ​编辑 数据发送寄存器 数据接收寄存器 【5】 USART功能框图 【6】串口发送实验 实验要求 1.观察实物 2.分析原理图 3.STM32CubeMX配置 7、不定长接收 8、重定向 【1】…

2022 CCPC-final 总结

赛前 去年 CCPC-final 拿了银牌第二。赛后,我选择退役,另一位队友 George_Plover 选择继续。 今年他队友 Kieray 去组女队了,于是邀请我替补参赛。 赛前一个月,约定好每周末组队训一场(在 cf 和 qoj 上&#xff0…

Spring Boot集成Swagger2

文章目录 1.什么是Swagger22.SpringBoot集成Swagger23.Swagger2配置管理(1)对Swagger2信息进行更改(2)swagger配置扫描接口(3)配置api文档分组(分组无非就是多个Docket)(4)实体类的配置 面试题:如果我们希望Swagger在某一个环境中使用&#x…

自学黑客(网络安全),看完这篇,再去追你的黑客梦!

今天专题是替一些想入门网络安全,但还迷茫不知所措的同学解一解惑。想30天零基础入门网络安全,这些你一定要搞清楚。 一、学习网络安全容易造成的误区 1、把编程当作目的,忽略了它的工具职能 千万不要抱着“以编程为目的,再开始…

C++(2):变量和基本类型

基本内置类型 C定义了一套包括算术类型(arithmetic type)和空类型(void)在内的基本数据类型。其中算术类型包含了字符、整型数、布尔值和浮点数。空类型不对应具体的值。 算数类型 算数类型分为两类:整型&#xff0…

Cesium教程(二):Cesium默认控件详解

Cesium初始界面在默认情况下,附带了一些有用的小控件,如下图所示,可以执行一些基本的功能。 1、①Geocoder Geocoder是一种定位搜索工具,它可以定位到查询位置。默认使用微软的Bing地图,若更换其他底图可能出现查找不到…

pnpm命令介绍

一、安装pnpm npm install -g pnpm 二、设置镜像源 pnpm config set registry https://registry.npm.taobao.org/ # 检查 pnpm config get registry 三、常用命令 # 查看ts-node的所有版本 pnpm view ts-node versions # 等价与npm i nodemon -g pnpm add nodemon -g # npm i p…

《深入理解Java虚拟机》 JAVA 字节码指令 基础

1.操作数栈 解释时,JVM会为方法分配一个栈帧,而栈帧又由 局部变量表,操作数帧,方法引用,动态链接 组成 方法中的每条指令执行时,要求该指令的操作数已经压入栈中;执行指令时会将操作数从栈中弹…

美团面试,被拷打了一小时....

刚从美团走出来,被拷打了一小时…越想越觉得可惜,回想面试经过,好好总结了几个点,发现面试没过的主要原因是在几个关键的问题没有给到面试官想要的答案。从而失去了这次宝贵的机会。 根据你的工作经历,说说你对质量保证…

python基础语法(print、数据类型、变量、注释、输入、条件语句)

一、初识编码(密码本) 计算机中所有的数据本质上都是用0和1的组合来存储的。编码就相当于密码本,在计算机中有多个密码本:utf-8编码、gbk编码等 注意事项:在计算机中若以某个编码形式进行保存文件,以后也…

ERP系统数据丢失的潜在经济损失

随着ERP系统的普及和涉及的范围越来越广,基本覆盖所有行业,ERP系统的数据安全也越来越被重视,关系到企业生命的机密信息都被存储在ERP系统中。 因此,ERP系统里存储的数据一旦泄露和丢失是一件非常可怕的事件。 那么,…

通俗易懂的教你如何使用Java实现快速排序

文章目录 快速排序🔒题目💡分析🔑题解 快速排序 🔒题目 题目链接:785.快速排序-Acwing题库 💡分析 基本思想:分治主要步骤 Step1:确定主元。从要划分的数组中选取一个元素作为主元…

python3+pytest+requests+allure+yaml测试框架搭建

目录 设计框架的原则 1.框架整体结构 2.框架各个模块说明 3.示例 3.1 先写一个测试用例 3.2 对上面的用例进行分层封装(可根据业务复杂度分两层或者三层,此处演示分三层) 3.3生成allure测试报告并查看 设计框架的原则 封装基类方法 对…

第十八章 使用LNMP架构部署动态网站环境

文章目录 第十八章 使用LNMP架构部署动态网站环境一、源码包程序1、源码包的优势2、基本步骤(1)、下载及解压源码包文件(2)、编译源码包代码(3)、生成二进制安装程序(4)、运行二进制…

VS2022调试Win-flex bison生成的C语言程序

Win-flex bison是flex和bison在Windows平台的一个移植版本,它支持flex(快速词法分析器)和bison(GNU解析器生成器)。 Win-flex bison的下载及安装可参看“Windows中使用Lex(Win flex-bison)”&a…

CIBF2023深圳电池展圆满结束!昂视期待与您下次相会

5月18日,CIBF2023深圳电池展圆满结束,展会为期三天,各位参展商展示了最新技术与产品,并在展位上开展花式互动,现场气氛火热。 作为电池行业的权威展会,CIBF2023深圳电池展为国内外用户、采购商、经销商提供…

cuda编程学习——第二个cuda程序(官方案例分析)!干货向(二)

前言: 最近在做三维重建,尤其是Nerf方面多视角合成工作的时候,意识到了cuda的编程计算可以大大提高其中渲染的计算,最明显的例子是Instant-ngp,Plenoxels等文章,因此后面会学Cuda一段时间,同时…

Python代码最好的加密.pyd——easycython(Windows系统)

1 安装easycython 1.1 建议选用python 3.6及其以下的版本!! 1.2 CMD命令行 pip install easycython2 安装Visual Studio 2.1 下载 点击链接 https://visualstudio.microsoft.com/zh-hans/free-developer-offers/ 2.2 安装注意事项 记得勾选红色下图的…

渗透测试--3.1.社会工程学攻击

目录 社会工程学攻击 SET介绍 一、建立克隆钓鱼网站收集目标凭证 二、set工具集之木马欺骗实战反弹链接 三、后渗透阶段 1.查看主机系统信息 2.到处用户密码的hash值 3.获得shell控制台 日志清除 四、钓鱼邮件 1、测试邮箱的连通性 2、参数说明 3、Kali 内置了s…