八种数据类型
数据类型是指数据的类型。
Java中主要有八种基本数据类型:byte、short、int、long、float、double、boolean、char。
概念:
byte:
- 8位、有符号的以二进制补码表示的整数
- min : -128(-2^7)
- max: 127(2^7-1)
- default: 0
- 对应包装类:Byte
- 占用1个字节
short:
- 16位、有符号的以二进制补码表示的整数
- min : -32768(-2^15)
- max: 32767(2^15 - 1)
- default: 0
- 对应包装类:Short
- 占用2个字节
int:
- 32位、有符号的以二进制补码表示的整数
- min : -2,147,483,648(-2^31)
- max: 2,147,483,647(2^31 - 1)
- default: 0
- 对应包装类:Integer
- 占用4个字节
long:
- 64位、有符号的以二进制补码表示的整数
- min : -9,223,372,036,854,775,808(-2^63)
- max: 9,223,372,036,854,775,807(2^63 -1)
- default: 0
- 对应的包装类:Long
- 占用8个字节
float:
- 单精度、32位、符合IEEE 754标准的浮点数
- float 在储存大型浮点数组的时候可节省内存空间
- 浮点数不能用来表示精确的值,如货币
- default: 0.0f
- 对应的包装类:Float
- 占用4个字节
double:
- 双精度、64位、符合IEEE 754标准的浮点数
- 浮点数的默认类型为double类型
- double类型同样不能表示精确的值,如货币
- default: 0.0d
- 对应的包装类:Double
- 占用8个字节
char:
- char类型是一个单一的 16 位 Unicode 字符
- 最小值是 \u0000(即为0)
- 最大值是 \uffff(即为65,535)
- char 数据类型可以储存任何字符
- 对应的包装类:Character
- 占用2个字节
注意:char型(文本型)用于存放字符的数据类型,占用2个字节,采用unicode编码
boolean:
- boolean数据类型表示一位的信息
- 只有两个取值:true 和 false
- 这种类型只作为一种标志来记录 true/false 情况
- 对应的包装类:Boolean
- 在Oracle的JVM下,单个Boolean值被编译为int,boolean数组被编译成byte数组
1. 为什么需要数据类型?
很多人都告诉我们学好基本类型很重要,但就是没人告诉我们要掌握基本类型哪些知识,这里,我们还是从最基本的一个问题出发,我们要基本类型做什么?答:为了描述这个世界。
我们遇到的数字,字节,等是不是都可以拆成一个一个的字符,《淮南子·本经训》:“昔者苍颉作书,而天雨粟,鬼夜哭。”,自苍颉造字后,我们便用这一个一个的字符组成的一个大字符去交流沟通。后来,我们发现,有些字符,有更具体的操作和意义,由此演化出了数字,到现代计算机世界,我们发现了二进制的妙用。于是,慢慢的,我们发现,任世间再多变,我们也可以用这八个基本类型,给描述出来,他们分别是:long,int,short,byte,char,float,double,boolean.
基本类型是为了描述这个世界,那如何去描述呢?答:记录某一状态 ,如double记录小数
2.记录在哪里?
基本类型存在哪里,在java中,无非就两个地方,一个是栈, 一个是堆。我们通常都说,基本类型都是在栈中直接分配的,其实这个要看场景。如果是在方法内部,在声明一个基本类型时,是在栈中分配的。如果是在一个全局的场景下声明了一个基本类型,这时候,是在堆里分配的。
3.数据类型有什么用?
数据类型的出现是为了把数据分成所需内存大小不同的数据,编程的时候需要用大数据的时候才需要申请大内存,就可以充分利用内存。
4.自动类型转换 小转大
自动类型转换,也称隐式类型转换,是指不需要书写代码,由系统自动完成的类型转换。由于实际开发中这样的类型转换很多,所以 Java 语言在设计时,没有为该操作设计语法,而是由 JVM自动完成。
-
转换规则:从存储范围小的类型到存储范围大的类型。
-
具体规则为:byte→short(char)→int→long→float→double
也就是说 byte 类型的变量可以自动转换为 short 类型,示例代码:
byte b=10;
short sh=b;
这里在给sh赋值时,JVM首先将b的值转换成short类型然后再赋值给sh。
当然,在类型转换的时候也可以跳跃,就是byte也可以自动转换为int类型的。
注意问题:在整数之间进行类型转换的时候数值不会发生变化,但是当将整数类型特别是比较大的整数类型转换成小数类型的时候,由于存储精度的不同,可能会存在数据精度的损失。
5.强制类型转换 大转小
强制类型转换,也称显式类型转换,是指必须书写代码才能完成的类型转换。该类类型转换很可能存在精度的损失,所以必须书写相应的代码,并且能够忍受该种损失时才进行该类型的转换。
-
转换规则:从存储范围大的类型到存储范围小的类型。
-
具体规则为:double→float→long→int→short(char)→byte
语法格式为:
(转换到的类型)需要转换的值
double d=3.14;
int i=(int) d;
结果:
i=3
表示一个数据是byte型的,可以在数据后面加上“B
表示一个数据是short型的,可以在数据后面加上“S
表示一个数据是long型的,可以在数据后面加上“L
表示一个数据是float型的,可以在数据后面加上“F
int不用加
表示一个数据是double型的,可以在数据后面加上"D"
注意问题:强制类型转换通常都会存储精度的损失,所以使用时需要谨慎
6.string类型是基本数据类型吗?
在java中 String 不再是 基本的数据类型! Java为每个原始类型提供了封装类。String是个封装类!就像Int是java的原始数据类型,Integer是java为int提供的封装类。 但是string没有对应的原始类型!
没写完 写关于string类型方面的。
包装器类型
包装器类型:Boolean,Character,Integer,Byte,Short,Long,Float,Double
定义: 在某些场合不能使用基本类型必须使用包装类,比如集合能接收的类型为Object,基本类型是无法添加进去的,还有范型也必须使用包装类。
另外假设我们要定义一个变量表示分数 如果用基本类型表示的话:int score;
默认值为零,如果我想表示分数为空也就是没有参加考试就没法表现了因为值类型是无法赋空值的,如果使用包装类型Integer score,就可以表示这种情况,因为Integer的默认值为空。
包装类型是引用类型,说白了就是一个类,既然是类,里面可以有属性和方法,它里面有哪些属性和方法呢?每个包装类型和基本数据类型都是大同小异的,我们拿Integer 和 int来举例说明:
假设有这样一个场景,我接收到一个String型的数据想把它转换为整型,如果没有包装类这个操作是无法完成的,有了包装类我们可以这样做:
String num1 = "123";
int num2 = Integer.parseInt(num1);
parseInt就是Integer包装类提供的一个将字符串转成int型的方法。
包装类还有一个很重要的特新就是数据缓存:
还是拿Integer来举例,在-128127区间的数会被缓存,当类加载的时候就创建这256个数对应的对象,并放到名为cache的数组中,调用valueOf()方法时会先判断该数是否在-128127的区间,如果在则直接获取数组中该对象的引用,如果不在则创建该对象。valueOf()方法的源码如下:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
这里IntegerCache.low为-128,IntegeCache.high为127,IntegerCache.cache为数组存储的就是-128到127的Integer对象。
在自动装箱的时候调用的就是valueOf方法。
我们来看下面这段代码:
public static void main(String[] args) {
Integer num1 = 4;
Integer num2 = 4;
System.out.println(num1 == num2);
System.out.println(num1.equals(num2));
Integer num3 = 145;
Integer num4 = 145;
System.out.println(num3==num4);
System.out.println(num3.equals(num4));
}
运行结果是:
true
true
false
true
为什么会是这个结果呢?
Integer num1 = 4,这里发生了自动装箱,调用了ValueOf()方法,因为4在-128~127之间所以num1和num2都指向了缓存中的同一地址,所以用 == 比较和equls比较返回的都是true.
Integer num3 = 145,因为145不在这个范围区间,所以会在堆中生成对象num3和num4分别指向两个不同地址的对象,所以== 返回false。从这个例子我们可以看出,如果要进行比较最好使用equals,如果使用 == 在数值范围不同的情况下得到的结果也是不同的。
各包装类缓存的取值范围:
· Boolean:使用静态 final 定义;
· Byte:缓存区 -128~127
· Short:缓存区 -128~127;
· Character:缓存区 0~127;
· Long:缓存区 -128~127;
· Integer:缓存区 -128~127。
Float 和 Double 不会有缓存。
那么具体什么时候使用基本数据类型什么时候使用包装类呢?
有一个典型的场景,比如在控制器中接收一个参数该参数定义成了基本数据类型int那么传过来的参数如果为空则会报空指针错误,如果定义为其包装类型Integer则不会报错,而是得到一个null值。所以在RPC方法里面参数和返回值类型都需要用包装类。
我们再来看一个情况:Pojo类中如果定义成基本类型,数据库中对应的字段为空的时候映射时会出问题。因为基本类型不能赋null。所以在Pojo类中数据类型都需要定义成包装类。
如果是局部变量我们一般定义成基本类型,因为基本类型存储在栈上,方法执行完毕,栈上的内存空间也随之释放。
总结
为什么会有包装类?
-
包装类里面有一些很有用的方法和属性,如HashCode,ParseInt
-
基本类型不能赋null值,某些场合需要。
-
有些地方不能直接用基本类型,比如集合
什么时候用包装类,什么时候用基本类型?
-
在pojo类中定义的属性用包装类
-
在rpc方法中定义参数和返回值的类型用包装类
-
定义局部变量用基本类型
经典面试题
1、short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 +=1;有什么错?
答:对于short s1=1;s1=s1+1来说,在s1+1运算时会自动提升表达式的类型为int,那么将int赋予给short类型的变量s1会出现类型转换错误。
对于short s1=1;s1+=1来说 +=是java语言规定的运算符,java编译器会对它进行特殊处理,因此可以正确编译。
2、char类型变量能不能储存一个中文的汉子,为什么?
char类型变量是用来储存Unicode编码的字符的,unicode字符集包含了汉字,所以char类型当然可以存储汉字的,还有一种特殊情况就是某个生僻字没有包含在unicode编码字符集中,那么就char类型就不能存储该生僻字。
3、Integer和int的区别
int是java的8种内置的原始数据类型。Java为每个原始类型都提供了一个封装类,Integer就是int的封装类。
int变量的默认值为0,Integer变量的默认值为null,这一点说明Integer可以区分出未赋值和值为0的区别,比如说一名学生没来参加考试,另一名学生参加考试全答错了,那么第一名考生的成绩应该是null,第二名考生的成绩应该是0分。关于这一点Integer应用很大的。Integer类内提供了一些关于整数操作的一些方法,例如上文用到的表示整数的最大值和最小值。
4、switch语句能否作用在byte上,能否作用在long上,能否作用在string上?
byte的存储范围小于int,可以向int类型进行隐式转换,所以switch可以作用在byte上
long的存储范围大于int,不能向int进行隐式转换,只能强制转换,所以switch不可以作用在long上
string在1.7版本之前不可以,1.7版本之后switch就可以作用在string上了
5.是否存在 x>x+1?为什么?
这就是临界值,当x=最大值 时; 再加1(根据二进制运算+1)就超过了它的临界值,刚好会是它最小值。
举个例子吧,byte 8位, -128 ~ 127
127 二进制: 0111 1111
1 二进制 : 0000 0001
相加结果: 1000 0000
byte 8位 有符号, 1000 0000 刚好 为 -128
public class Test {
public static void main(String[] args) {
// int
System.out.println("基本类型:int 二进制位数:" + Integer.SIZE);
System.out.println("包装类:java.lang.Integer");
System.out.println("最小值:Integer.MIN_VALUE=" + Integer.MIN_VALUE);
System.out.println("最大值:Integer.MAX_VALUE=" + Integer.MAX_VALUE);
System.out.println(Integer.MAX_VALUE+1);
}
}
结果:
基本类型:int 二进制位数:32
包装类:java.lang.Integer
最小值:Integer.MIN_VALUE=-2147483648
最大值:Integer.MAX_VALUE=2147483647
-2147483648