1.数据类型分类
Java 中的数据类型有两类:
- 值类型(又叫内置数据类型,基本数据类型)
- 引用类型(除值类型以外,都是引用类型,包括
String
、数组)
1.1值类型
Java 语言提供了 8 种基本类型,大致分为 4 类
-
整数型
-
byte
- 8 位。 -
short
- 16 位。 -
int
- 32 位。 -
long
- 64 位,赋值时一般在数字后加上l
或L
。
-
-
浮点型
-
float
- 32 位,直接赋值时必须在数字后加上f
或F
。 -
double
- 64 位,赋值时一般在数字后加d
或D
。
-
-
字符型
-
char
- 16 位,存储 Unicode 码,用单引号赋值。
-
-
布尔型
-
boolean
- 只有 true 和 false 两个取值。 - 注意:下面基本数据类型的默认值必须是在类中声明的静态变量,或者在类中定义的属性(在创建对象时候如果没有赋值,此时该属性会赋值为默认值),这时候才会自动赋值为默认值,定义在方法中的局部变量是不会自动赋值的。String类型的默认为null。
- 注意:char类型的默认值是一个空格。
-
- //String不是基本类型
- static String str1 = "";//生成一个String类型的引用,而且分配内存空间来存放"";
- static String str2; //只生成一个string类型的引用;不分配内存空间,默认为null
值类型和引用类型的区别
- 从概念方面来说
- 基本类型:变量名指向具体的数值。
- 引用类型:变量名指向存数据对象的内存地址。
- 从内存方面来说
- 基本类型:变量在声明之后,Java 就会立刻分配给他内存空间。
- 引用类型:它以特殊的方式(类似 C 指针)向对象实体(具体的值),这类变量声明时不会分配内存,只是存储了一个内存地址。
- 从使用方面来说
- 基本类型:使用时需要赋具体值,判断时使用
==
号。 - 引用类型:使用时可以赋 null,判断时使用
equals
方法。 2. 数据转换
Java 中,数据类型转换有两种方式: 自动转换 和 强制转换。
2.1 自动转换
一般情况下,定义了某数据类型的变量,就不能再随意转换。但是 JAVA 允许用户对基本类型做有限度的类型转换。如果符合以下条件,则 JAVA 将会自动做类型转换:
-
由小数据转换为大数据
显而易见的是,“小”数据类型的数值表示范围小于“大”数据类型的数值表示范围,即精度小于“大”数据类型。所以,如果“大”数据向“小”数据转换,会丢失数据精度。比如:long 转为 int,则超出 int 表示范围的数据将会丢失,导致结果的不确定性。反之,“小”数据向“大”数据转换,则不会存在数据丢失情况。由于这个原因,这种类型转换也称为扩大转换。
这些类型由“小”到“大”分别为:(byte,short,char) < int < long < float < double。
这里我们所说的“大”与“小”,并不是指占用字节的多少,而是指表示值的范围的大小。
-
转换前后的数据类型要兼容
由于 boolean 类型只能存放 true 或 false,这与整数或字符是不兼容的,因此不可以做类型转换。
整型类型和浮点型进行计算后,结果会转为浮点类型
示例:
long x = 30;
float y = 14.3f;
System.out.println("x/y = " + x/y);输出:
x/y = 1.9607843
-
- 基本类型:使用时需要赋具体值,判断时使用
2.2 强制转换
在不符合自动转换条件时或者根据用户的需要,可以对数据类型做强制的转换。
强制转换使用括号 ()
。
引用类型也可以使用强制转换。
float f = 25.5f;
int x = (int)f;
System.out.println("x = " + x);
3. 装箱和拆箱
3.1. 包装类、装箱、拆箱
Java 中为每一种基本数据类型提供了相应的包装类,如下:
Byte <-> byte
Short <-> short
Integer <-> int
Long <-> long
Float <-> float
Double <-> double
Character <-> char
Boolean <-> boolean
引入包装类的目的就是:提供一种机制,使得基本数据类型可以与引用类型互相转换。
基本数据类型与包装类的转换被称为装箱
和拆箱
。
-
装箱
(boxing)是将值类型转换为引用类型。例如:int
转Integer
- 装箱过程是通过调用包装类的
valueOf
方法实现的。
- 装箱过程是通过调用包装类的
-
拆箱
(unboxing)是将引用类型转换为值类型。例如:Integer
转int
- 拆箱过程是通过调用包装类的
xxxValue
方法实现的。(xxx 代表对应的基本数据类型)。
- 拆箱过程是通过调用包装类的
3.2 自动装箱、自动拆箱
基本数据(Primitive)型的自动装箱(boxing)拆箱(unboxing)自 JDK 5 开始提供的功能。
自动装箱与拆箱的机制可以让我们在 Java 的变量赋值或者是方法调用等情况下使用原始类型或者对象类型更加简单直接。
因为自动装箱会隐式地创建对象,如果在一个循环体中,会创建无用的中间对象,这样会增加 GC 压力,拉低程序的性能。所以在写循环时一定要注意代码,避免引入不必要的自动装箱操作。
JDK 5 之前的形式:
Integer i1 = new Integer(10); // 非自动装箱
JDK 5 之后:
Integer i2 = 10; // 自动装箱
Java 对于自动装箱和拆箱的设计,依赖于一种叫做享元模式的设计模式(有兴趣的朋友可以去了解一下源码,这里不对设计模式展开详述)。
3.3 装箱、拆箱的应用和注意点
装箱、拆箱应用场景
- 一种最普通的场景是:调用一个含类型为
Object
参数的方法,该Object
可支持任意类型(因为Object
是所有类的父类),以便通用。当你需要将一个值类型(如 int)传入时,需要使用Integer
装箱。 - 另一种用法是:一个非泛型的容器,同样是为了保证通用,而将元素类型定义为
Object
。于是,要将值类型数据加入容器时,需要装箱。 - 当
==
运算符的两个操作,一个操作数是包装类,另一个操作数是表达式(即包含算术运算)则比较的是数值(即会触发自动拆箱的过程)。
Integer i1 = 10; // 自动装箱
Integer i2 = new Integer(10); // 非自动装箱
Integer i3 = Integer.valueOf(10); // 非自动装箱
int i4 = new Integer(10); // 自动拆箱
int i5 = i2.intValue(); // 非自动拆箱
System.out.println("i1 = [" + i1 + "]");
System.out.println("i2 = [" + i2 + "]");
System.out.println("i3 = [" + i3 + "]");
System.out.println("i4 = [" + i4 + "]");
System.out.println("i5 = [" + i5 + "]");
System.out.println("i1 == i2 is [" + (i1 == i2) + "]");
System.out.println("i1 == i4 is [" + (i1 == i4) + "]"); // 自动拆箱
// Output:
// i1 = [10]
// i2 = [10]
// i3 = [10]
// i4 = [10]
// i5 = [10]
// i1 == i2 is [false]
// i1 == i4 is [true]
上面的例子,虽然简单,但却隐藏了自动装箱、拆箱和非自动装箱、拆箱的应用。从例子中可以看到,明明所有变量都初始化为数值 10 了,但为何会出现 i1 == i2 is [false
而 i1 == i4 is [true]
?
原因在于:
- i1、i2 都是包装类,使用
==
时,Java 将它们当做两个对象,而非两个 int 值来比较,所以两个对象自然是不相等的。正确的比较操作应该使用equals
方法。 - i1 是包装类,i4 是基础数据类型,使用
==
时,Java 会将两个 i1 这个包装类对象自动拆箱为一个int
值,再代入到==
运算表达式中计算;最终,相当于两个int
进行比较,由于值相同,所以结果相等。
//基本数据类型的常量池是-128到127之间。
// 在这个范围中的基本数据类的包装类可以自动拆箱,比较时直接比较数值大小。
public static void main(String[] args) {
//int的自动拆箱和装箱只在-128到127范围中进行,超过该范围的两个integer的 == 判断是会返回false的。
Integer a1 = 128;
Integer a2 = -128;
Integer a3 = -128;
Integer a4 = 128;
System.out.println(a1 == a4); //false
System.out.println(a2 == a3); //true
Byte b1 = 127;
Byte b2 = 127;
Byte b3 = -128;
Byte b4 = -128;
//byte都是相等的,因为范围就在-128到127之间
System.out.println(b1 == b2); //true
System.out.println(b3 == b4); //true
//
Long c1 = 128L;
Long c2 = 128L;
Long c3 = -128L;
Long c4 = -128L;
System.out.println(c1 == c2); //false
System.out.println(c3 == c4); //true
//char没有负值
//发现char也是在0到127之间自动拆箱
Character d1 = 128;
Character d2 = 128;
Character d3 = 127;
Character d4 = 127;
System.out.println(d1 == d2); //false
System.out.println(d3 == d4); //true
装箱、拆箱应用注意点
- 装箱操作会创建对象,频繁的装箱操作会造成不必要的内存消耗,影响性能。所以应该尽量避免装箱。
- 基础数据类型的比较操作使用
==
,包装类的比较操作使用equals
方法。 3.4 字符串和基本类型之间的转换
-
一、由基本数据型态转换成String
String 类别中已经提供了将基本数据型态转换成 String 的 static 方法 ,也就是 String.valueOf() 这个参数多载的方法
有以下几种
(1)String.valueOf(boolean b) : 将 boolean 变量 b 转换成字符串
(2)String.valueOf(char c) : 将 char 变量 c 转换成字符串
(3)String.valueOf(char[] data) : 将 char 数组 data 转换成字符串
(4)String.valueOf(char[] data, int offset, int count) : 将 char 数组 data 中 由 data[offset] 开始取 count 个元素 转换成字符串(5)String.valueOf(double d) : 将 double 变量 d 转换成字符串
(6)String.valueOf(float f) : 将 float 变量 f 转换成字符串
(7)String.valueOf(int i) : 将 int 变量 i 转换成字符串
(8)String.valueOf(long l) : 将 long 变量 l 转换成字符串
(9)String.valueOf(Object obj) : 将 obj 对象转换成 字符串, 等于 obj.toString()用法如下:
int i = 10;
String str = String.valueOf(i);
这时候 str 就会是 "10"二、 由 String 转换成 数字的基本数据型态
要将 String 转换成基本数据型态转 ,大多需要使用基本数据型态的包装类别
比如说 String 转换成 byte ,可以使用 Byte.parseByte(String s) ,这一类的方法如果无法将 s 分析 则会丢出 NumberFormatException
(1)byte : Byte.parseByte(String s) : 将 s 转换成 byte
(2)Byte.parseByte(String s, int radix) : 以 radix 为基底 将 s 转换为 byte ,例 Byte.parseByte("11", 16) 得到 17
(3)double : Double.parseDouble(String s) : 将 s 转换成 double
(4)float : Double.parseFloat(String s) : 将 s 转换成 float
(5)int : Integer.parseInt(String s) : 将 s 转换成 int
(6)long : Long.parseLong(String s)
(7)chars: str.toCharArray() :将字符串转换为字符数组
4.小结
面试题:
第一题:
byte b1=3,b2=4,b;
b=b1+b2;//出错因为在JAVA虚拟机中默认是int类型转换,虚拟机不知道b1 ,b2 中的数值到底是多少,所有会抛出可能损失精度的错误;
//虚拟机会把 b1,b2 转换成 int类型在进行运算,两个int类型的数值相加结果任然是int类型,int类型 不能赋值给 byte类型
b=3+4;
哪句是编译失败的呢?为什么呢?
第二题:
byte by = 130;有没有问题?有问题如何解决?结果是多少呢? byte 的数值范围是 126~-127 130已经超出byte取值范围 运算是会砍掉前面的 三个8位
结果会变成-126
第三题:
byte b = 10;
b++;//这句 java虚拟机会做一个自动转换动作 相当于 b=(byte)(b+1)所以不会报错
b = b + 1;//这句java虚拟机会把,b转换成int类型 相当于 int b + int 类型的1 然后赋值给Byte类型 int是4个字节 byte是1个字节 所有会抛出损失精度
short s1=1; s1=s1+1; 是错的,由于1是int类型,因此s1+1运算结果也是int类型,需要强制类型转换才能赋值给short类型。
short s2=1;s2+=1; 这里是正确的,因为s2+=1;相当于s2=(short)(s2+1);其中有隐含的强制类型转换。
第四题:
java中float f = 3.4;是否正确?
不正确,3.4是双精度数,将双精度型(double)赋值给浮点型(float)属于向下转型会造成精度损失,因此需要强制类型转换float f = (float)3.4;或者写成 float f = 3.4f;才可以。
全部评论