[Java]基本数据类型与引用类型赋值的底层分析的小结
【版权声明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权)
https://www.cnblogs.com/cnb-yuchen/p/17969159
出自【进步*于辰的博客】
1、关于赋值
参考笔记一,P74.1。
一个小结:
所有引用都存于栈,而对象存于堆。引用所指向的可能存于栈,也可能存于方法区常量池。
1.1 基本数据类型赋值
在final int a
中a是常量,在int a
中a是变量。
示例:int a = 10;
a是变量,10是常量(a与10都存于栈)。令a = 20
,是将a的值直接由10改为20。
1.2 String类型赋值
在String s = "abc"
中,s是引用(也是变量,存于栈),"abc"
是字符串常量,存于方法区的字符串常量池。令s = "123"
,是将s由指向"abc"
转为指向"123"
,若"abc"
没有其他引用指向就会被回收。
2、关于String赋值
参考笔记一,P74.2。
2.1 情形一
以下两种形式的定义的结果都相同,而底层分析略有不同。
形式一:
示例:
String s1 = "csdn", s2 = "csdn";
s2 = "2023";
sout s1;// 打印:csdn
sout s2;// 打印:2023
若方法区的字符串常量池中存在字符串常量“csdn”
,则不会重新创建,直接将s1
和s2
指向“csdn”
。
令s2 = "2023"
,同样先判断是否存在"2023"
。若不存在,则创建,然后将s2
由指向"csdn"
转为指向"2023"
。
因此,最终s1
指向"csdn"
,s2
指向"2023"
。
形式二:
示例:
String s1 = "csdn", s2 = s1;
s2 = "2023";
sout s1;// 打印:csdn
sout s2;// 打印:2023
若存在“csdn”
,则不会重新创建,直接将s1
指向“csdn”
,然后将s2
指向s1
的指向。
后续步骤同上,故结果相同。
这就是为何明明s2 = s1
,而s2 = "2023"
,结果s2
改变、s1
不变的原因。
2.2 情形二
示例:
String s1 = "csdn", s2 = s1 + "2023", s3 = "csdn2023";
s2.equals(s3);// 结果:true
令s2 = s1 + "2023"
,会先获取s1
的指向,是"csdn"
。
然后为"csdn"
复制一个副本,再转为 StringBuffer,后执行append("2023")
,最后调用toString()
,返回“csdn2023”
。
此时再判断字符串常量池中是否存在字符串常量"csdn2023"
,若不存在,则创建,然后将s2
指向csdn2023”
。
因此,s2
与s3
的结果相同。
3、关于String与char[]的比较
如果大家想要了解String类的底层,看这里 → String类。
参考笔记一,P74.3。
示例:
String s1 = "csdn";
char[] arr = {'c', 's', 'd', 'n'};
s1.equals(arr);// 结果:false-------A
s1.toString().equals(arr.toString());// 结果:false-------B
// 注:第一个toString()多余,第二个toString()是在底层调用
// 我这么写是为了方便大家理解
String类重写了equals()
,在底层会先调用toString()
,返回值后再判断;而char[]
不是具体类型,不存在重写。当然,仍会调用toString()
,即示例中的A与B等效,但调用的是Object类的toString()
(返回地址),故不等。
4、不同类型引用分析
参考笔记一,P36.5;笔记二,P38.1。
4.1 int
示例:
int a = 100, b = a;
a、b、100都存于栈,令a = 20
,是直接将a的值改为20,b的值仍为100。
4.2 Integer
关于八位有符号二进制的表示范围,可查阅博文《关于二进制的原码、补码和反码,以及表示范围、常见位运算符和进制转换的理解与简述》的第1.2项。
Integer 类的“自动装箱”和“自动拆箱”机制是什么?
- 包装类都具有自动装箱和自动拆箱的功能(以代码的角度上说,就是会在底层调用某个方法)。
- 为包装类Integer赋值时,自动装箱是底层调用了
valueOf()
。这里存在一个溢出问题。因为整型常量存储于方法区的整型常量池,而整型常量池使用8位有符号二进制表示整型。8位有符号二进制的表示范围是-128 ~ 127
。若整型超出此此范围,就是“溢出”。 - “溢出”规定:若整型在范围内,
valueOf()
底层创建整型常量,存储于整型常量池;否则创建 Integer 对象,存储于堆。
示例:
关于
valueOf()
,可参考Integer类的第4.33项。
Integer i1 = 1;
Integer i2 = new Integer(1);
Integer i3 = Integer.valueOf(1);
i1 == i2;// false
i1 == i3;// true
i2 == i3;// false
Integer i4 = 128;
Integer i5 = new Integer(128);
Integer i6 = Integer.valueOf(128);
i4 == i5;// false
i4 == i6;// false
i5 == i6;// false
底层分析:
i1
指向整型常量1
;i2
指向new Integer(1)
;由于1
在表示范围内,故valueOf(1)
返回整型常量1
,则i3
也指向整型常量1
。- 由于整型常量池仅能存储
-128 ~ 127
的整型常量,故i4
指向new Integer(128)
;i5
指向new Integer(128)
;由于128
超出表示范围,故valueOf(128)
返回new Integer(128)
。
扩展一点:
i1.equals(i2);// true
i1.equals(i3);// true
i2.equals(i3);// true
i4.equals(i5);// true
i4.equals(i6);// true
i5.equals(i6);// true
为何结果都为true
?
关于
equals()
,可参考Integer类的第4.6项。
4.3 int[]
示例:
int[] arr1 = {1, 2, 3}, arr2 = arr1;
arr1
、arr2
以及数组内所有的值都存于栈,{1, 2, 3}
存储于堆。
令arr1[0] = 10
,是直接将1改为10,则arr1是{10, 2, 3}
;arr2与arr1指向相同,故arr2也是{10, 2, 3}
。
4.4 Integer[]
示例:
Integer[] arr1 = {1, 2, 3}, arr2 = arr1;
与int[]
不同的是,Integer[]
内的所有元素都不是直接的值,而是引用,并且是 Integer 引用,指向整型常量池或堆。
不过,无论指向哪里,由于arr2与arr1始终指向相同,因此,令arr1[0] = 10
,则arr1是{10, 2, 3}
,arr2同样是{10, 2, 3}
。
5、最后
本文中的例子是为了方便大家理解java基本数据类型和引用类型赋值时的底层而简单举例的,不一定有实用性。
PS:
大家在看完这篇文章后肯定想吐槽:“你说了这么多,示例结果还不是与我们平时使用时的结果无差别,有什么意义。”
哈哈......结果当然相同了,因为我阐述的是底层分析。这些呢在平时工作中一般是用不到的,因此,目的是为了让大家对java基本数据类型和引用类型赋值时的底层有进一步的理解。
本文完结。
[Java]基本数据类型与引用类型赋值的底层分析的小结的更多相关文章
- Java之数据类型,变量赋值
Java中的基础数据类型(四类八种): 1.整数型 byte----使用byte关键字来定义byte型变量,可以一次定义多个变量并对其进行赋值,也可以不进行赋值.byte型是整型中所分配的内存空间是最 ...
- java原生数据类型和引用类型
java 中String 是个对象,是引用类型基础类型与引用类型的区别是,基础类型只表示简单的字符或数字,引用类型可以是任何复杂的数据结构基本类型仅表示简单的数据类型,引用类型可以表示复杂的数据类型, ...
- java基本数据类型和引用类型
这些基本的数据类型是点不出东西来的 3种引用类型 类class 接口interface 数组array 第一个 : 类 Integer Long Boolean Byte Characte ...
- java基本数据类型与引用类型
基本数据类型: byte:Java中最小的数据类型,在内存中占8位(bit),即1个字节,取值范围-128~127,默认值0 short:短整型,在内存中占16位,即2个字节,取值范围-32768~3 ...
- Java基本数据类型之间赋值与运算归纳
前言:面对“byte b1=3;byteb2=7;byte b=b1+b2;”报错,而“int i1=3;int i2=7;int i=i1+i2;”不报错,进行了深入探究,从而引申出java基本类型 ...
- Java中的基本数据类型和引用类型
一.基本数据类型: byte:Java中最小的数据类型,在内存中占8位(bit),即1个字节,取值范围-128~127,默认值0 short:短整型,在内存中占16位,即2个字节,取值范围-32768 ...
- Java中构造函数传参数在基本数据类型和引用类型之间的区别
Java中构造函数传参数在基本数据类型和引用类型的区别 如果构造函数中穿的参数为基本数据类型,如果在函数中没有返回值,在调用的时候不会发生改变:而如果是引用类型,改变的是存储的位置,所有不管有没有返回 ...
- Java基本数据类型总结
基本类型,或者叫做内置类型,是JAVA中不同于类的特殊类型.它们是我们编程中使用最频繁的类型.java是一种强类型语言,第一次申明变量必须说明数据类型,第一次变量赋值称为变量的初始化. 1. Java ...
- Java基本数据类型及其封装器的一些千丝万缕的纠葛
一些概念 想必大家都知道Java的基础数据类型有:char.byte.short.int.long.float.double.boolean 这几种,与C/C++等语言不同的是,Java的基础 ...
- Java基本数据类型总结(转载)
Java基本数据类型总结 基本类型,或者叫做内置类型,是JAVA中不同于类的特殊类型.它们是我们编程中使用最频繁的类型.java是一种强类型语言,第一次申明变量必须说明数据类型,第一次变量赋值称为变量 ...
随机推荐
- NC16610 [NOIP2009]Hankson的趣味题
题目链接 题目 题目描述 Hanks博士是BT(Bio-Tech,生物技术)领域的知名专家,他的儿子名叫Hankson.现在,刚刚放学回家的Hankson正在思考一个有趣的问题. 今天在课堂上,老师讲 ...
- Centos7 和 Centos8 升级内核
从yum安装kernel-ml 对于Centos7 rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org yum install htt ...
- STM32 printf 方法重定向到串口UART
在嵌入式系统中调试代码是很麻烦的一件事, 如果能方便地输出调试信息(与调试者交互), 能使极大加快问题排查的过程. 串口在嵌入式领域是一个比较重要的通讯接口. 因为没有显示设备, 在单片机的程序里调用 ...
- Oracle如何限制非法调用包中过程
原文:http://www.oracle.com/technetwork/issue-archive/2015/15-jan/o15plsql-2398996.html 假如我有一个包P_A,其中封装 ...
- Modbus协议入门
1.Modbus协议是不是开源的,免费的? 标准.开放,用户可以免费.放心地使用Modbus协议,不需要交纳许可证费,也不会侵犯知识产权. 2.怎么传输,有线还是无线? 既可以有线传输如双绞线.光纤, ...
- 参数替换xargs
由于很多命令不支持管道|来传递参数,xargs用于产生某个命令的参数,xargs可以读入stdin的数据,并且以空格符或回车符将stdin的数据分隔为参数 示例: 创建10个用户 echo user{ ...
- 【LeetCode数组#2双指针法】移除元素、删除有序数组中的重复项、移动0
移除元素 力扣27题目链接(opens new window) 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度. 不要使用额外的数组 ...
- 【Azure Function】Function本地调试时遇见跨域问题(blocked by CORS policy)
问题描述 在本地调试Azure Function时,遇见了跨域问题: Access to XMLHttpRequest at 'http://localhost:7071/api/HttpTrigge ...
- 【Azure Function App】在ADF(Azure Data Factory)中调用 Azure Function 时候遇见 Failed to get MI access token
问题描述 在ADF(Azure Data Factory)中,调用Azure Function App中的Function,遇见了 Failed to get MI access token Ther ...
- 【Azure 应用服务】Azure Function在执行Function的时候,如果失败了,是否可以重试呢?
问题描述 Azure Function在执行Function的时候,如果失败了,是否可以重试呢? 问题解答 Function app默认是不开启重试的,但是可以修改 host.json 文件来定义重试 ...