前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java 中的变量类型、拆箱装箱及相互间的转换

Java 中的变量类型、拆箱装箱及相互间的转换

作者头像
matt
发布2022-10-25 15:35:16
5140
发布2022-10-25 15:35:16
举报
文章被收录于专栏:CSDN迁移

Java 中的变量类型、拆箱装箱及相互间的转换

一、Java 中变量类型

1.1 以数据类型划分

1.1.1 基本数据类型

  • 整数型变量

变量名

说明

byte

1字节,包装类为Byte

short

2字节,包装类为Short

int

4字节,包装类为Integer

long

8字节,赋值常量后面加L,包装类为Long

注意:1字节是8byte,以int为例,范围是[-2^31, 2^31-1],因为存在负数,故指数位要-1,正整数部分存在0,故要-1。0开头表示八进制,0x开头表示十六进制。

  • 浮点型 表示形式:十进制数形式(3.14)、科学记数法形式(314E-2)。 特点:
    1. 不精确,不能用于比较;(除非使用java.math包中的BigDecimal类)
    2. Java默认double为浮点数默认类型。

变量名

说明

float

4字节,赋值时加后缀F,包装类为Float

double

8字节,包装类为Double

浮点数的题外话
  1. 浮点数的内存存储方式
代码语言:javascript
复制
IEEE规定浮点数num = (-1)^S * M * 2^E,下面以32位的float类型为例:(double类型为1+11+52,精度为15-16位小数)

    |-|--------|-----------------------|
S(1bit) E(8bit)         M(23bit)

首先需要说明一下,任何数的科学计数法都可以表示为1.xxx*2^n(计算机中均以二进制存储),由于尾数部分第一位均以1开头,故在M中省略,即23位的尾数部分可以表示24bit精度,也就是小数点后6-7位,绝对保证的精度为6位。
S:符号位,0表示正数,1表示负数
E:指数位,可正可负,故第一位为符号位,实际范围为-128~127。采用偏移位存储,元数据为127(0111 1111表示0)
M:尾数位,实际数值为1.M,后面不足23为加0,注意小数转化为二进制的方法

举例:6.2的存储结构
整数部分:6的二进制为110
小数部分:0.2的二进制为0011 0011 0011 0011 0011…
	    这里的计算方法可以为:0.2 * 2 = 0.4 …… 0
	    				  0.4 * 2 = 0.8 …… 0
	    				  0.8 * 2 = 1.6 …… 1
	    				  0.6 * 2 = 1.2 …… 1
	    				  ……
	    从这个计算中可以看出,计算机在存储浮点数的时候是不精确的,0.2是一个无限循环小数。
规格化:110.00110011… = 1.1000110011 * 2^2
填充:S = 0
	 E = 2 + 127 = 129 = 10000001
	 M = 10001100
故6.2的float存储结果为:|0|1000 0001|100 0110 0110 0110 0110 0110|
  1. BigDecimal的使用 构造 BigDecimal 对象的方法:
代码语言:javascript
复制
BigDecimal bigDecimal = new BigDecimal(long a);  //不常用,不精确会变大
BigDecimal bigDecimal = new BigDecimal(String s);//常用
bigDecimal.valueOf(long a);                      //常用,是long转BigDecimal的方法

建议在使用 BigDecimal 的构造函数时最好采用基于整数或 String 的构造函数。 此外,BigDecimal 类型不能用使用一般的运算符号(±*/),需要使用对象的相应运算方法(如add())。

  1. Double中的两个特殊值 上面说到了浮点数的存储是不精确的,在 Double 类中就存在这样的两个数据:Double.NaN 和 Double.POSITIVE_INFINITY,Float 类同理。 3.1 i == i + 1 无穷大加1还是无穷大,在 Java 中如果你计算1/0结果会抛出 ArithmeticException,但是计算1.0/0结果会得到 Infinity,这是标准类库提供的常量。浮点数在计算时不会抛出异常。 3.2 i != i IEEE 754 浮点算术保留了一个特殊的值用来表示一个不是数字的数量:NaN(Not a Number),用于表示没有良好的数字定义的浮点计算,如0.0/0。任何浮点操作,只有它的一个或多个操作数为 NaN,其结果必然是 NaN,显然 NaNcy 与任何数比较结果均返回 false。但是如果使用 Double.compare() 函数来比较两个 NaN,则结果返回0(相等)。 这里有个神奇的现象,对于 0.0 与 -0.0,compare() 函数认为正0要比负0大。所以对于0的比较还是用 == 比较好。
  • 字符型 特点:使用Unicode字符集(’\uxxx’)。

变量名

说明

char

2字节,包装类为Charac

  • 逻辑型

变量名

说明

boolean

1字节,包装类为Boolean

1.1.2 引用数据类

  • 接口
  • 数组

1.2 以声明的位置为依据划分

1.2.1 成员变量

类中定义的变量,但是在方法、构造方法和语句块之外

  • 实例变量:不以static修饰
  • 类变量:以static修饰

1.2.2 局部变量

方法、构造方法和语句块中定义的变量

  • 形参:方法签名中定义
  • 方法局部变量:方法体内定义
  • 代码块局部变量:代码块中定义

二、拆箱与装箱机制

Java 中一切皆对象,为了方便编程引入了基本数据类型,但是每个类型都引入了对应的包装类型,Java 5 开始引入了自动装箱/拆箱机制,使得二者可以互相转换。但是注意 Ingeter 初值为 null,而 int 初值为 0。

注意:所有的包装类都是final类,即不可变类。虽然在代码A处看起来是改变了counter的值,但实际上是创建了另一个对象,并将方法内的counter参数的引用指向了这个新创建的对象,由于是不同的引用,所以不会对方法外的引用有任何的影响。

装箱:

代码语言:javascript
复制
//二者等价
Integer a = 123;
Integer a = Integer.valueOf(123);

拆箱:

代码语言:javascript
复制
Integer a = new Integer(123);
int b = a;
//等价于 b = a.intValue();

深入理解:

代码语言:javascript
复制
Integer a = new Integer(123);
Integer b = new Integer(123);
Integer c = 123;
Integer d = 123;
Integer e = 128;
Integer f = 128;
//逻辑表达式(a == b)为false,因为栈中的对象a、b指向不同的堆中对象
//逻辑表达式(a == c)为true,因为自动拆箱的原因,实际比较的是两个int型数值
//逻辑表达式(c == d)为true,因为自动装箱时IntegerCache类在初始化时,生成了一个-128-127的Integer类型的常量池,如果值在此范围内则不会再生成新的对象
//逻辑表达式(e == f)为falsed,理由同上

一个 String 的例子

这样就不难理解 String 不是基本数据类型,而是一个对象,但是需要注意的是 String 可以直接赋值创建,而 StringBuilder 必须通过 new 来创建。 为了更进一步了解 Java 中的 String 请先看以下代码:

代码语言:javascript
复制
final String c1  = "a";
String c2  = "a";

String s1 = "abc";
String s2 = "abc";
String s3 = new String("abc");
String s4 = new String("abc");
String s5 = c1 + "bc";
String s6 = c2 + "bc";

在JVM里,考虑到垃圾回收(Garbage Collection)的方便,将heap(堆)划分为三部分:young generation(新生代)、tenured generation (old generation)(旧生代)、permanent generation(永生代)。 字符串为了解决字符串重复问题,生命周期长,存于pergmen中。

  • 逻辑表达式s1 == s2为 true 因为String s1 = "abc"可能创建一个或不创建对象,如果 “abc” 这个字符串在 Java String 池中不存在,则会在 JVM 的字符串池中创建一个 String 对象 “abc”,然后将 s1 指向这个内存地址,以后在创建值为 “abc” 的字符串对象,始终只有一个内存地址被分配,其余的都是 String 的拷贝。 所以这里比较的是两个变量名实际指向的 String 对象地址。

Java 中成为“字符串驻留”:所有的字符串常量都会在编译之后自动地驻留。

  • 逻辑表达式s3 == s4为 false 因为String s3 = new String("abc")创建一个或两个对象,由于 new 关键字的存在,会在堆中创建一个 String 类型的 s3 对象,它的值为 “abc”(创建与否同上)。 所以这里比较的是堆中两个 String 对象的地址。如果想要比较值,应使用s3.equals(s4),内部逐项进行比较。
  • 逻辑表达式s1 == s5为 true,逻辑表达式s1 == s6为 false 因为将一个字符串连接表达式赋给字符串变量时,如果这个字符串连接表达式的值可以在编译时就确定下来,那么 JVM 会在编译时确定字符串变量的值,并让它指向字符串池中对应的字符串。这里 final 关键字在编译时对 c1 进行了宏替换,在编译时可以确定 s5 的值。

建议:在使用字符串、基本数据类型包装实例时,进行使用直接复制,而不是通过 new、包装类实例化,这样可以保证更好的性能。

三、相互间的转换

代码语言:javascript
复制
/* int与String的互转
 */
int i = 123;
String s1 = String.valueOf(i);  //方法1
String s2 = Integer.toString(i);//方法2

String s = "123";
int i1 = Integer.parseInt(s);//方法1,返回的是int类型,常用(性能和Integer常量池范围限制问题)
int i2 = Integer.valueOf(s); //方法2,返回的是Integer类型,调用了parseInt的方法,如果要变为int型,还要进行一次装箱操作intValue()


/* StringBuilder与String的互转
 */
String s = "abc";
StringBuilder sb1 = new StringBuilder(s);//方法1
StringBuilder sb2 = new StringBuilder(); //方法2
sb2.append(s);

String s1 = sb.toString();//方法1
String s2 = "" + sb;      //方法2

/* char[]与String的互转
 */
String str = "abc";
char[] ca = str.toCharArry();

char[] ca = {'a','b','c'};
String s1 = String.valueOf(ca); //方法1,这里的valueOf函数可以有三个参数,截取字符数组范围
String s2 = Arrays.toString(ca);//方法2,但是输出格式为[, , ,]

//char[]转StringBuilder只能利用循环硬转
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-04-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Java 中的变量类型、拆箱装箱及相互间的转换
  • 一、Java 中变量类型
    • 1.1 以数据类型划分
      • 1.1.1 基本数据类型
      • 1.1.2 引用数据类
    • 1.2 以声明的位置为依据划分
      • 1.2.1 成员变量
        • 1.2.2 局部变量
          • 一个 String 的例子
      • 二、拆箱与装箱机制
      • 三、相互间的转换
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档