一、数据类型
从下图中,我们可以很清晰的看出Java中的类型,其中红色方框中的是Java的4种基本数据类型:
下面我们来详细讲解上图中的基本类型:
1.整数类型
1) 在Java中,整数类型共有4种,它们有固定的表述范围和字段长度,且不受具体的操作系统的影响,保证了Java的跨平台性
2) Java语言中,整数有三种表现形式,分别是:
a. 十进制整数,如 120, -31, 0
b. 八进制整数,要求以0开头(注意这是数字0,不是字母o),如:012,
c. 十六进制整数,要求以0x开头(注意这是数字0,不是字母o),如: 0x12
3) Java语言中,默认的整数类型是int类型,声明long类型的时候,后面必须要加个l(字母L的小写,不是大写字母I,也不是数字1)或者L,建议使用大写L,防止和数字1,大写字母I混淆,如:30L, 30l
4) Java中四种整数类型的表述范围:
2.浮点类型
1) 与整数类型一样,同样有固定的表述范围和字段长度,且不受具体的操作系统的影响,保证了Java的跨平台性
2) Java语言中,浮点类型有两种表现形式,分别是:
a. 十进制数形式, 如3.14
b. 科学计数法,如,3.14e2, 3.14e-2, -3.14E2
3) Java语言中,默认的浮点数类型是double,声明float类型的时候,后面必须添加字母f或者F,如3.14F,3.14f
4) Java中两种浮点类型的表述范围:
3. 字符类型
1) 字符类型是用''单引号括起来的单个字符,例如char c = 'w'; char a = '中';
2) Java字符采用Unicode(全球语言统一编码)编码,每个字符占两个字节,因而可用16进制编码形式表示,如:char c = '\u0061'
3) Java中允许使用转义字符'\'将其后面的字符转换成其他含义, 如: char c = '\n'; //表示换行
4.布尔类型
1) boolean类型的值只有两种:true, false
2) boolean类型不可以转换为其他的数据类型
5.基本数据类型的转换
1) boolean不可以转换为其他的数据类型
2) 整数型,浮点类型,字符型是可以相互转换的,转换时遵守下面的原则:
a. 容量小的类型自动转换为大的类型,数据类型按容量大小排序为:
byte, short, char < int < long <float < double
b. byte, short, char 三种类型间不会相互转换,他们三者在计算时,首先会转换为int类型
c. 容量大的类型在转换为小的类型的时候,必须加上强制转换符,此时可能造成精度降低或者溢出问题
d. 有多种数据类型混合计算的时候,系统首先自动转换为容量最大的那个类型再来继续计算
e. 实数类型默认为double类型,如, 1.2; 整数类型默认为int类型,如 1
二、JVM对基本类型的处理
1.常量池技术
1) java中基本类型的包装类的大部分都实现了常量池技术,这些类是Byte,Short,Integer,Long,Character,Boolean,另外两种浮点数类型的包装类则没有实现。
2) Byte,Short,Integer,Long,Character这5种整型的包装类也只是在对应值小于等于127时才可使用对象池
下面我们主要使用Long类型来进行讲解吧。
首先我们先写一个测试类:
LongTypeTest.java
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
1 package com.kevin.basetype; 2 3 public class LongTypeTest { 4 5 public static void main(String[] args) { 6 long longParam = 30L; 7 Long longParam2 = 30L; 8 } 9 }
我们通过javac命令编译后,再通过jad命令生成编译文件来查看编译信息,如下:
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
1 // Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov. 2 // Jad home page: http://www.kpdus.com/jad.html 3 // Decompiler options: packimports(3) annotate 4 // Source File Name: LongTypeTest.java 5 6 package com.kevin.basetype; 7 8 9 public class LongTypeTest 10 { 11 12 public LongTypeTest() 13 { 14 // 0 0:aload_0 15 // 1 1:invokespecial #1 <Method void Object()> 16 // 2 4:return 17 } 18 19 public static void main(String args[]) 20 { 21 long longParam = 30L; 22 // 0 0:ldc2w #2 <Long 30L> 23 // 1 3:lstore_1 24 Long longParam2 = Long.valueOf(30L); 25 // 2 4:ldc2w #2 <Long 30L> 26 // 3 7:invokestatic #4 <Method Long Long.valueOf(long)> 27 // 4 10:astore_3 28 // 5 11:return 29 } 30 }
从第26行,我们可以看到,使用包装类初始化的时候,调用的是Long类中的valueOf方法,下面我们看看,Long类中的该方法是怎样的。
1 public static Long valueOf(long l) { 2 final int offset = 128; 3 //当 l >= -128 && l <= 127 时,返回常量池中缓存的数据 4 if (l >= -128 && l <= 127) { // will cache 5 return LongCache.cache[(int)l + offset]; 6 } 7 //否则初始化一个新的Long对象 8 return new Long(l); 9 }
从代码中看出,当 l 的值小于127的时候,将会调用LongCache.cache()中获取常量池中的数值。其中,LongCache是一个内部类
1 //Long类中的私有类 2 private static class LongCache { 3 //私有的构造方法,不允许初始化 4 private LongCache(){} 5 //static final类型,它的值在编译期间将会确定下来并且被存储到常量池中 6 static final Long cache[] = new Long[-(-128) + 127 + 1]; 7 //静态代码块,为cache数组赋值 8 static { 9 for(int i = 0; i < cache.length; i++) 10 cache[i] = new Long(i - 128); 11 } 12 }
其他Byte,Short,Integer,Long,Character,Boolean都是差不多的,具体就不在此重复讲了。
我们在Double中的valueOf中我们可以看到源代码是这样子的:
1 public static Double valueOf(double d) { 2 //直接初始化并返回一个Double对象 3 return new Double(d); 4 }
Float亦是如此。
2.short, int, char -> byte(char)
看到这个,估计大家都很奇怪,这个标题究竟是什么意思呢?下面我们就来讲解下:
1) 当short, int, char 的数值小于127大于-128时,编译器在内存中会使用byte类型来进行记录。
2) 当short, int, char 的值大于127却小于 215-1时,编译器在内存中会使用char类型来进行记录。
换句话来说,byte, short, int, char四个基本类型,编译器在内存中将会使用最小的单位去存储他们的值的内容。
接着我们先写个测试类来验证下:
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
1 package com.kevin.basetype; 2 3 public class BaseType { 4 5 public static void main(String[] args) { 6 byte bytePram = 10; 7 Byte bytePram2 = 10; 8 9 short shortParam = 40; 10 Short shrotParam2 = 40; 11 12 int intParam = 20; 13 int intParam2 = 20; 14 Integer integerParam = 20; 15 16 long longParam = 30; 17 Long longParam2 = 30L; 18 19 double doubleParam = 20.0; 20 double doubleParam4 = 20.0; 21 Double doubleParam2 = 20.0; 22 Double doubleParam3 = 20.0; 23 24 float floatParam = 20.0f; 25 Float floatParam2 = 20.0f; 26 27 boolean booleanParam = true; 28 Boolean booleanParam2 = true; 29 30 char charParam = 'a'; 31 char charParam2 = 'a'; 32 Character characterParam = 'a'; 33 } 34 }
2)继续查看编译信息:
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
1 // Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov. 2 // Jad home page: http://www.kpdus.com/jad.html 3 // Decompiler options: packimports(3) annotate 4 // Source File Name: BaseType.java 5 6 package com.kevin.basetype; 7 8 9 public class BaseType 10 { 11 12 public BaseType() 13 { 14 // 0 0:aload_0 15 // 1 1:invokespecial #1 <Method void Object()> 16 // 2 4:return 17 } 18 19 public static void main(String args[]) 20 { 21 byte byte0 = 10; 22 // 0 0:bipush 10 23 // 1 2:istore_1 24 Byte byte1 = Byte.valueOf((byte)10); 25 // 2 3:bipush 10 26 // 3 5:invokestatic #2 <Method Byte Byte.valueOf(byte)> 27 // 4 8:astore_2 28 byte byte2 = 40; 29 // 5 9:bipush 40 30 // 6 11:istore_3 31 Short short1 = Short.valueOf((short)40); 32 // 7 12:bipush 40 33 // 8 14:invokestatic #3 <Method Short Short.valueOf(short)> 34 // 9 17:astore 4 35 byte byte3 = 20; 36 // 10 19:bipush 20 37 // 11 21:istore 5 38 byte byte4 = 20; 39 // 12 23:bipush 20 40 // 13 25:istore 6 41 Integer integer = Integer.valueOf(20); 42 // 14 27:bipush 20 43 // 15 29:invokestatic #4 <Method Integer Integer.valueOf(int)> 44 // 16 32:astore 7 45 long l = 30L; 46 // 17 34:ldc2w #5 <Long 30L> 47 // 18 37:lstore 8 48 Long long1 = Long.valueOf(30L); 49 // 19 39:ldc2w #5 <Long 30L> 50 // 20 42:invokestatic #7 <Method Long Long.valueOf(long)> 51 // 21 45:astore 10 52 double d = 20D; 53 // 22 47:ldc2w #8 <Double 20D> 54 // 23 50:dstore 11 55 double d1 = 20D; 56 // 24 52:ldc2w #8 <Double 20D> 57 // 25 55:dstore 13 58 Double double1 = Double.valueOf(20D); 59 // 26 57:ldc2w #8 <Double 20D> 60 // 27 60:invokestatic #10 <Method Double Double.valueOf(double)> 61 // 28 63:astore 15 62 Double double2 = Double.valueOf(20D); 63 // 29 65:ldc2w #8 <Double 20D> 64 // 30 68:invokestatic #10 <Method Double Double.valueOf(double)> 65 // 31 71:astore 16 66 float f = 20F; 67 // 32 73:ldc1 #11 <Float 20F> 68 // 33 75:fstore 17 69 Float float1 = Float.valueOf(20F); 70 // 34 77:ldc1 #11 <Float 20F> 71 // 35 79:invokestatic #12 <Method Float Float.valueOf(float)> 72 // 36 82:astore 18 73 boolean flag = true; 74 // 37 84:iconst_1 75 // 38 85:istore 19 76 Boolean boolean1 = Boolean.valueOf(true); 77 // 39 87:iconst_1 78 // 40 88:invokestatic #13 <Method Boolean Boolean.valueOf(boolean)> 79 // 41 91:astore 20 80 byte byte5 = 97; 81 // 42 93:bipush 97 82 // 43 95:istore 21 83 byte byte6 = 97; 84 // 44 97:bipush 97 85 // 45 99:istore 22 86 Character character = Character.valueOf('a'); 87 // 46 101:bipush 97 88 // 47 103:invokestatic #14 <Method Character Character.valueOf(char)> 89 // 48 106:astore 23 90 // 49 108:return 91 } 92 }
看完上面以后,大家可能会有这么一个疑问:short, char都是两个字节,为什么存储的时候,会选择使用char类型来进行存储二不选择short呢?
解答:因为short是有符号的,而char类型是无类型的,可以表示的数值范围比short大,所以虽然同样是两个字节,但是却选择了char类型而不选择short类型进行值存储。
3.final, Number, Comparable与基础类型包装类的关系
1) 所有的基本类型的包装类都使用了final来进行修饰,保证了系统的安全性,试想一下,假设有人也自定义了这么一个java.lang.Integer同时继承了jdk中的java.lang.Integer,并且在里面实现了一些破坏性的代码,那后果将不堪设想了对吧。
2) 除了Character,Boolean以外,其他的基本类型包装类都继承了抽象类Number。这个抽象类要求继承类必须实现将当前类型的值转换为其他类型的值方法
3)所有的基本类型包装类都实现了接口Comparable。这个接口的作用是:
a. 当List/Array中的对象实现了该接口的话,可以直接用Collections.sort()方法进行自动排序
b. 当一个普通的Object对象实现了该接口,那么将可以用作具有自动sort作用(例如TreeMap)的Map集合中的排序依据key或者具有自动sort作用的Set集合中的排序根据对象