Java有8种基本类型:大致分为3类:字符,布尔,数值类型(在java中数值是不存在无符号的,这一点不像C/C++,他们的取值范围是固定的,不会随着机器硬件的环境或者操作系统的改变而改变)
1.Java决定了每种简单类型的大小。这些大小并不随着机器结构的变化而变化。这种大小的不可更改正是Java程序具有很强移植能力的原因之一。下表列出了Java中定义的简单类型、占用二进制位数及对应的封装器类。
基本类型 | 二进制位数 | 包装器类 |
---|---|---|
boolean | 1 | Boolean |
byte | 8 | Byte |
char | 16 | Character |
short | 16 | Short |
int | 32 | Integer |
long | 64 | Long |
float | 32 | Float |
double | 64 | Double |
2.对于取值范围,在对应的包装器类中有常量记载,直接调用就可以了,无需记忆
Java基本类型存储在栈中,因此它们的存取速度要快于存储在堆中的对应包装类的实例对象。从Java5.0(1.5)开始,JAVA虚拟机(Java Virtual Machine)可以完成基本类型和它们对应包装类之间的自动转换。因此我们在赋值、参数传递以及数学运算的时候像使用基本类型一样使用它们的包装类,但这并不意味着你可以通过基本类型调用它们的包装类才具有的方法。另外,所有基本类型(包括void)的包装类都使用了final修饰,因此我们无法继承它们扩展新的类,也无法重写它们的任何方法。
3.基本类型出现的原因
在Java编程思想的第一章就讲到:万物皆对象,new一个对象存储在堆中,我们通过堆栈的引用来使用这些对象,但是对于经常用到的一系列类型如int,如果我们用new将其存储在堆里就不是很有效——特别是简单的小的变量。所以就出现了基本类型,同C++一样,Java采用了相似的做法,对于这些类型不是用new关键字来创建,而是直接将变量的值存储在堆栈中,因此更加高效。
4.包装类型出现的原因
Java是一个面向对象的语言,基本类型并不具有对象的性质,为了与其他对象“接轨”就出现了包装类型(如我们在使用集合类型Collection时就一定要使用包装类型而非基本类型),它相当于将基本类型“包装起来”,使得它具有了对象的性质,并且为其添加了属性和方法,丰富了基本类型的操作。
5.关于基本类型和包装类型的总结
import java.text.SimpleDateFormat;
import java.util.Date;
public class Demo01 {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
//1.自动转换
byte b1 = 12;
int a = b1*2; //这里发生了自动转换
//2.强制转换测试
byte byte1 = 12;
byte byte2 = 1;
byte i =(byte)(byte1 + byte1); //显示不能从byte转换成int 这里需要强制转换
//3.包装器过渡转换
String s = "123";
int value = Integer.parseInt(s); //方法返回int值赋给value
//4.字符串和其他类型的转换
int num = 2017;
String time= ""+num; //右边最终结果是String
String str1 = "123";
int value1 = Integer.valueOf(str1); //结果是int 123
//5.Date与其他数据类型的相互转换
Date date = new Date();
SimpleDateFormat format = new SimpleDateFormat("yyyyMMDD");
String timeString = format.format(date);
}
}
总结:只有boolean不参与数据类型的转换
a.常数在表数范围内是能够自动类型转换的
b.数据范围小的能够自动数据类型大的转换(注意特例)int到float,long到float,long到double 是不会自动转换的,不然将会丢失精度
c.引用类型能够自动转换为父类的
d.基本类型和它们包装类型是能够互相转换的
Java有 5种引用类型(对象类型):类 接口 数组 枚举 标注
引用类型:底层结构和基本类型差别较大
JVM的内存空间:
(1). Heap 堆空间:分配对象 new Student()
(2). Stack 栈空间:临时变量 Student stu
(3).Code 代码区 :类的定义,静态资源 Student.class
Student stu = new Student(); //new 在内存的堆空间创建对象
stu.study(); //把对象的地址赋给stu引用变量
上例实现步骤:
a.JVM加载Student.class 到Code区
b.new Student()在堆空间分配空间并创建一个Student实例
c.将此实例的地址赋值给引用stu, 栈空间
public static void main(String[] args) {
Integer a = new Integer(100);
Integer b = new Integer(100);
/* compareTo返回值:若a>b则返回1;若a==b则返回0;若a
int result = a.compareTo(b);
System.out.println(a > b);
System.out.println(a == b);
System.out.println(a > b);
System.out.println(result);
}
运行结果:
false
false
false
0
为什么(a==b)返回值会是false呢?
通过对比字符串比较来理解,基本类型100通过包装类Integer包装后生产一个Integer对象的引用a,而“==”使用来判断两个操作数是否有相等关系。如果是基本类型就直接判断其值是否相等。若是对象就判断是否是同一个对象的引用,显然我们new了两个不同的对象。但注意:对于”<”,”>” 只是用来判断两个基本类型的数值的大小关系。在进行”(a < b)运算时,实际上是根据其 intValue方法的返回对应的数值来进行比较的。因此返回肯定是false.
知道问题原因,解决起来就容易了。两种方法:
第一种: a.intValue()==b.intValue();
第二种: a.compareTo(b);//返回-1代码(a
public int compareTo(Integer object) {
int thisValue = value;
int thatValue = object.value;
return thisValue < thatValue ? -1 : (thisValue == thatValue ? 0 : 1);
}
public static void main(String[] args) {
//常量池的测试
System.out.println("Integer的测试");
Integer a = 127;
Integer b = 127;
System.out.println(a == b);
a = 128;
b = 128;
System.out.println(a == b);
a = -128;
b = -128;
System.out.println(a == b);
a = -129;
b = -129;
System.out.println(a == b);
// 测试Boolean
System.out.println("测试Boolean");
Boolean c = true;
Boolean d = true;
System.out.println(c == d);
d = new Boolean(true);
System.out.println(c == d);
}
程序运行结果
Integer的测试
true
false
true
false
测试Boolean
true
false
当我们给Integer赋值时,实际上调用了Integer.valueOf(int)方法(编译期进行装箱),查看源码,其实现如下:
public static Integer valueOf(int i) {
if(i >= -128 && i <= IntegerCache.high)
return IntegerCache.cache[i + 128];
else
return new Integer(i);
}
而IntegerCache实现如下
private static class IntegerCache {
static final int high;
static final Integer cache[];
static {
final int low = -128;
// high value may be configured by property
int h = 127;
if (integerCacheHighPropValue != null) {
// Use Long.decode here to avoid invoking methods that
// require Integer's autoboxing cache to be initialized
int i = Long.decode(integerCacheHighPropValue).intValue();
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - -low);
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
}
private IntegerCache() {}
}
注意cache数组是静态的。
下面的语句不会缓存常量:
Integer integer = new Integer(127);
因为使用了new关键字,一定是创建了一个新的对象,无法进行缓存优化。
public class IntegerCompareTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Object obj = new Integer(1024);
if(Integer.valueOf(obj.toString())==1024){
System.out.println("Integer.valueOf(obj.toString())==1024 is true");
}
}
}
通过Javap.exe进行反编译得到的JVM指令如下所示
Classfile /C:/Users/JIN/Documents/GitHub/JavaBasePractice/bin/com/jinwen/basetype/IntegerCompareTest.class
Last modified 2017-7-19; size 906 bytes
MD5 checksum d0968e0c73408dd3cb83daddfe8e1a1b
Compiled from "IntegerCompareTest.java"
public class com.jinwen.basetype.IntegerCompareTest
SourceFile: "IntegerCompareTest.java"
minor version: 0
major version: 50
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Class #2 // com/jinwen/basetype/IntegerCompareTest
#2 = Utf8 com/jinwen/basetype/IntegerCompareTest
#3 = Class #4 // java/lang/Object
#4 = Utf8 java/lang/Object
#5 = Utf8 <init>
#6 = Utf8 ()V
#7 = Utf8 Code
#8 = Methodref #3.#9 // java/lang/Object."":()V
#9 = NameAndType #5:#6 // "":()V
#10 = Utf8 LineNumberTable
#11 = Utf8 LocalVariableTable
#12 = Utf8 this
#13 = Utf8 Lcom/jinwen/basetype/IntegerCompareTest;
#14 = Utf8 main
#15 = Utf8 ([Ljava/lang/String;)V
#16 = Class #17 // java/lang/Integer
#17 = Utf8 java/lang/Integer
#18 = Methodref #16.#19 // java/lang/Integer."":(I)V
#19 = NameAndType #5:#20 // "":(I)V
#20 = Utf8 (I)V
#21 = Methodref #3.#22 // java/lang/Object.toString:()Ljava/lang/String;
#22 = NameAndType #23:#24 // toString:()Ljava/lang/String;
#23 = Utf8 toString
#24 = Utf8 ()Ljava/lang/String;
#25 = Methodref #16.#26 // java/lang/Integer.valueOf:(Ljava/lang/String;)Ljava/lang/Integer;
#26 = NameAndType #27:#28 // valueOf:(Ljava/lang/String;)Ljava/lang/Integer;
#27 = Utf8 valueOf
#28 = Utf8 (Ljava/lang/String;)Ljava/lang/Integer;
#29 = Methodref #16.#30 // java/lang/Integer.intValue:()I
#30 = NameAndType #31:#32 // intValue:()I
#31 = Utf8 intValue
#32 = Utf8 ()I
#33 = Fieldref #34.#36 // java/lang/System.out:Ljava/io/PrintStream;
#34 = Class #35 // java/lang/System
#35 = Utf8 java/lang/System
#36 = NameAndType #37:#38 // out:Ljava/io/PrintStream;
#37 = Utf8 out
#38 = Utf8 Ljava/io/PrintStream;
#39 = String #40 // Integer.valueOf(obj.toString())==1024 is true
#40 = Utf8 Integer.valueOf(obj.toString())==1024 is true
#41 = Methodref #42.#44 // java/io/PrintStream.println:(Ljava/lang/String;)V
#42 = Class #43 // java/io/PrintStream
#43 = Utf8 java/io/PrintStream
#44 = NameAndType #45:#46 // println:(Ljava/lang/String;)V
#45 = Utf8 println
#46 = Utf8 (Ljava/lang/String;)V
#47 = Utf8 args
#48 = Utf8 [Ljava/lang/String;
#49 = Utf8 obj
#50 = Utf8 Ljava/lang/Object;
#51 = Utf8 StackMapTable
#52 = Utf8 SourceFile
#53 = Utf8 IntegerCompareTest.java
{
public com.jinwen.basetype.IntegerCompareTest();
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #8 // Method java/lang/Object."":()V
4: return
LineNumberTable:
line 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/jinwen/basetype/IntegerCompareTest;
public static void main(java.lang.String[]);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=2, args_size=1
0: new #16 // class java/lang/Integer
3: dup
4: sipush 1024
7: invokespecial #18 // Method java/lang/Integer."":(I)V
10: astore_1
11: aload_1
12: invokevirtual #21 // Method java/lang/Object.toString:()Ljava/lang/String;
15: invokestatic #25 // Method java/lang/Integer.valueOf:(Ljava/lang/String;)Ljava/lang/Integer;
18: invokevirtual #29 // Method java/lang/Integer.intValue:()I
21: sipush 1024
24: if_icmpne 35
27: getstatic #33 // Field java/lang/System.out:Ljava/io/PrintStream;
30: ldc #39 // String Integer.valueOf(obj.toString())==1024 is true
32: invokevirtual #41 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
35: return
LineNumberTable:
line 10: 0
line 11: 11
line 12: 27
line 14: 35
LocalVariableTable:
Start Length Slot Name Signature
0 36 0 args [Ljava/lang/String;
11 25 1 obj Ljava/lang/Object;
StackMapTable: number_of_entries = 1
frame_type = 252 /* append */
offset_delta = 35
locals = [ class java/lang/Object ]
}
分析:code的标号15:确实是调用静态的valueOf方法解析字符串为Integer实例,但其后标号18:有调用了Integer实例的intValue()方法返回了该实例相应的int值,从而最后比较的实际是int和int进行比较,所以比较结果是true;
通过上述分析可以确定 “包装对象==相应值” 这样的比较是可行的,但却不是推荐的。因为解析String实例为Integer实例,然后在去Integer实例里面去取的int值进行比较,在此Integer实例就多此一举了,还不如直接使用parseInt解析字符为相应的int值直接进行比较,节省创建一个Integer实例所浪费的资源。