Java基本类型和包装类型总结

1.Java的基本类型及其对应的包装器类

Java有8种基本类型:大致分为3类:字符,布尔,数值类型(在java中数值是不存在无符号的,这一点不像C/C++,他们的取值范围是固定的,不会随着机器硬件的环境或者操作系统的改变而改变)

  • byte:8位,最大存储数据量是255,存放的数据范围是-128~127之间。
  • short:16位,最大数据存储量是65536,数据范围是-32768~32767之间。
  • int:32位,最大数据存储容量是2的32次方减1,数据范围是负的2的31次方到正的2的31次方减1。
  • long:64位,最大数据存储容量是2的64次方减1,数据范围为负的2的63次方到正的2的63次方减1。
  • float:32位,数据范围在3.4e-45~1.4e38,直接赋值时必须在数字后加上f或F。
  • double:64位,数据范围在4.9e-324~1.8e308,赋值时可以加d或D也可以不加。
  • boolean:只有true和false两个取值。

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.对于取值范围,在对应的包装器类中有常量记载,直接调用就可以了,无需记忆

  • 基本类型byte 二进制位数:Byte.SIZE最小值:Byte.MIN_VALUE最大值:Byte.MAX_VALUE
  • 基本类型short二进制位数:Short.SIZE最小值:Short.MIN_VALUE最大值:Short.MAX_VALUE
  • 基本类型char二进制位数:Character.SIZE最小值:Character.MIN_VALUE最大值:Character.MAX_VALUE
  • 基本类型double 二进制位数:Double.SIZE最小值:Double.MIN_VALUE最大值:Double.MAX_VALUE

Java基本类型存储在栈中,因此它们的存取速度要快于存储在堆中的对应包装类的实例对象。从Java5.0(1.5)开始,JAVA虚拟机(Java Virtual Machine)可以完成基本类型和它们对应包装类之间的自动转换。因此我们在赋值、参数传递以及数学运算的时候像使用基本类型一样使用它们的包装类,但这并不意味着你可以通过基本类型调用它们的包装类才具有的方法。另外,所有基本类型(包括void)的包装类都使用了final修饰,因此我们无法继承它们扩展新的类,也无法重写它们的任何方法。

3.基本类型出现的原因
在Java编程思想的第一章就讲到:万物皆对象,new一个对象存储在堆中,我们通过堆栈的引用来使用这些对象,但是对于经常用到的一系列类型如int,如果我们用new将其存储在堆里就不是很有效——特别是简单的小的变量。所以就出现了基本类型,同C++一样,Java采用了相似的做法,对于这些类型不是用new关键字来创建,而是直接将变量的值存储在堆栈中,因此更加高效。

4.包装类型出现的原因
Java是一个面向对象的语言,基本类型并不具有对象的性质,为了与其他对象“接轨”就出现了包装类型(如我们在使用集合类型Collection时就一定要使用包装类型而非基本类型),它相当于将基本类型“包装起来”,使得它具有了对象的性质,并且为其添加了属性和方法,丰富了基本类型的操作。

5.关于基本类型和包装类型的总结

  • 基本类型的优势:数据存储相对简单,运算效率比较高
  • 包装类的优势:有的容易,比如集合的元素必须是对象类型,满足了java一切皆是对象的思想
  • 声明方式不同,基本类型不适用new关键字,而包装类型需要使用new关键字来在堆中分配存储空间;
  • 存储方式及位置不同,基本类型是直接将变量值存储在堆栈中,而包装类型是将对象放在堆中,然后通过引用来使用;
  • 初始值不同,基本类型的初始值如int为0,boolean为false,而包装类型的初始值为null
  • 使用方式不同,基本类型直接赋值直接使用就好,而包装类型在集合如Collection、Map时会使用到

2.Java类型转换

  • 1.自动转换
  • 2.强制转换
  • 3.包装器过渡类型转换
  • 4.字符串与其他类型之间的转换
  • 5.Date和其他数据类型之间的转换
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不参与数据类型的转换

  • (1).自动类型的转换:

a.常数在表数范围内是能够自动类型转换的
b.数据范围小的能够自动数据类型大的转换(注意特例)int到float,long到float,long到double 是不会自动转换的,不然将会丢失精度
c.引用类型能够自动转换为父类的
d.基本类型和它们包装类型是能够互相转换的

  • (2).强制类型转换:用圆括号括起来目标类型,置于变量前

3.Java引用类型

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, 栈空间

4.Java包装类的一些常见知识点归纳

  • 1.Java包装器比较大小(很有意思的问题)
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);
}
  • 2.Java包装类常量池
    Java的8种基本类型(Byte, Short, Integer, Long, Character, Boolean, Float, Double), 除Float和Double以外, 其它六种都实现了常量池, 但是它们只在大于等于-128并且小于等于127时才使用常量池。
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关键字,一定是创建了一个新的对象,无法进行缓存优化。

- 3.Java基本类型和包装类型使用运算符 == 进行比较的底层细节? 是引用还是至比较值?

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实例所浪费的资源。

你可能感兴趣的:(Java复习)