深入Java基础——基本数据类型及其包装类

Posted huster-田浪

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入Java基础——基本数据类型及其包装类相关的知识,希望对你有一定的参考价值。

文章结构:

1. 基本数据类型的系统描述;

2.数据类型的包装类理解(含源码解析);

3.数据类型转换、装包拆包等一些小坑。

 

一、基本数据类型的系统描述:

1. 总述

Java基本数据类型分为两大类:boolean类型和数值类型。数值类型可分为整数类型和浮点类型,而其中字符类型可单独对待。所以Java只包含8种基本数据类型。

注意!字符串不是基本数据类型,字符串是一个类,是一个引用类型。

boolean 数值只有true和false,不能用0代替。其他数值类型不能转换成boolean。包装类–Boolean

byte 内存8位,无符号位时最大存储255,表数范围:-128~127。包装类–Byte

short 内存16位,无符号位时最大存储65536,表数范围:-32768~32767。包装类–Short

int 内存32位,无符号位时最大存储2的32次方减1,表数范围:负的2的31次方到正的2的31次方减1。包装类–Integer。

long 内存64位,无符号位时最大存储2的64次方减1,表数范围:负的2的63次方到正的2的63次方减1。包装类–Long。

float 内存32位,数据范围在3.4e-45~1.4e38,直接赋值时必须在数字后加上f或F。包装类–Float。

double 内存64位,数据范围在4.9e-324~1.8e308,赋值时可以加d或D也可以不加。包装类–Double。

char:16位,存储Unicode字符集,用单引号赋值。可以参与加减乘除运算的,也可以比较大小的!!包装类–Character。

二、数据类型的包装类理解(含部分源码解析)

Java会为每一个基础数据类型都提供一个相应包装类的目的,在于将Java的所有东西都抽象成对象,可以更方便的控制和使用。这就是面向对象!

对于包装类:

主要作用是:

1.作为和基本数据类型对应的类类型存在,方便涉及到对象的操作。

2.包含每种基本数据类型的相关属性如最大值、最小值等,以及相关的操作方法。

1.深入boolean基本类型、Boolean类以及细节点:

 1 //看接口是可序列化,是一个final修饰的类
 2 public final class Boolean implements java.io.Serializable,
 3                                       Comparable<Boolean>{
 4      //看这两个对应的原始对象。享元模式的使用,达到多个对象都使用一份内存。至于什么是享元,以及它与单例的区别,这里就不多说了。
 5      public static final Boolean TRUE = new Boolean(true);
 6      public static final Boolean FALSE = new Boolean(false);
 7      private final boolean value;
 8      //两个构造器,可见它是可以为null的啦,使用Boolean这个类的话
 9      public Boolean(boolean value) {
10         this.value = value;
11     }
12      public Boolean(String s) {
13         this(parseBoolean(s));
14     }
15      public static boolean parseBoolean(String s) {
16         return ((s != null) && s.equalsIgnoreCase("true"));
17     }
18     //jdk文档建议用valueOf代替new方式来创建Boolean类对象。new创建的Boolean对象是不断的新创建一个实例对象,而valueOf则是返回Boolean类里的静态成员变量,也就是使用享元模式的那个对象。
19     public static Boolean valueOf(String s) {
20         return parseBoolean(s) ? TRUE : FALSE;
21     }
22 
23     //下面是令人困惑的设计了,我也是看了下stackoverflow里面讨论才有点懂。
24     //原汁原味链接:http://stackoverflow.com/questions/3912303/boolean-hashcode
25     //1. 使用质素是因为假如要把Boolean指插入到hashtable中,如果不是质素的话可能会比较容易造成哈希冲突。符合对象计算hashcode的时候通常会把各个属性的hashcode相加然后再做hash,如果是比较小的质素,容易造成hash分布不均匀。
26     //2. Maps是可以包裹Boolean的,而如果map除了包含Boolean对象,还包含其他对象,那么如果不适当处理,就很容易有冲突了
27      public static int hashCode(boolean value) {
28         return value ? 1231 : 1237;
29     }

总括下:

1.boolean是基础数据类型,而Boolean是一个类。

2.boolean一般存在于桟空间中,而Boolean对象存在堆空间中。

3.boolean有true和false俩种值,Boolean除了true和false外,还有null。

 

 1 public class Main {
 2     public static void main (String []args)
 3     {
 4         Boolean bool1 = Boolean.valueOf(true);       //这里均使用valueof创建对象,new创建的Boolean对象是不断的新创建一个实例对象,而valueOf则是返回Boolean类里的静态成员变量
 5         Boolean bool2 = Boolean.valueOf("True");    //这里上一句代码验证使用String变量作为参数时,不区分大小写的。
 6         Boolean bool3 = Boolean.valueOf("ASD");
 7         boolean x1 = bool1.booleanValue();
 8         boolean x2 = bool2.booleanValue();
 9         System.out.println("bool1:" + x1 + ",bool2:" + x2 + ",bool3:" + bool3);
10         boolean x3 = bool1.equals(bool2);       //这个就是验证享元模式,使用的是同一个对象
11         boolean x4 = bool1.equals(bool3);       //肯定不是同一对象啦。
12         System.out.println("bool1.equals(bool2):" + x3 + ",bool1.equals(bool3):" + x4);
13         String str1 = Boolean.toString(bool1);      //可见Boolean对象是可以转换成字符的
14         String str2 = Boolean.toString(false);      
15         String str3 = bool3.toString();
16         System.out.println("bool1:" + str1 + ",str2:" + str2 + ",bool3:" + str3);
17         boolean x5 = Boolean.parseBoolean("ASD");         //源码是直接判断然后与true对比,因此打印为false
18         System.out.println(x5);
19     }
20 }

 

2.深入byte基本类型

 1 //也可以看到是一个final修饰的类,只能用,不能被继承咯
 2 public final class Byte extends Number implements Comparable<Byte>{
 3     public static final int SIZE = 8;   //只能是一个字节咯
 4     //两个构造器
 5     public Byte(byte value) {
 6         this.value = value;   //传入的要为Byte类型的值
 7     }
 8     public Byte(String s) throws NumberFormatException {
 9         this.value = parseByte(s, 10);  //传入的要求是可转换成Byte的字符串
10     }
11     //这个Byte做了缓存
12     private static class ByteCache {
13         private ByteCache(){}
14 
15         static final Byte cache[] = new Byte[-(-128) + 127 + 1];//声明缓存数组的长度为256
16 
17         static {
18             for(int i = 0; i < cache.length; i++)
19                 cache[i] = new Byte((byte)(i - 128));//然后将-128~127进行缓存
20         }
21     }
22     //两个解析字符串方法
23     public static byte parseByte(String s, int radix)
24         throws NumberFormatException {
25         //radix是解析字符串时候的基数,在此方法下有个解析基数的含义。
26         int i = Integer.parseInt(s, radix);//解析字符串并返回,所以s必须是-128~127的字符,至于为什么用这个方法int的包装类方法来解析,一会我们会谈到。
27         if (i < MIN_VALUE || i > MAX_VALUE)
28             throw new NumberFormatException(
29                 "Value out of range. Value:\\"" + s + "\\" Radix:" + radix);
30         return (byte)i;
31     }
32     //也是解码转码方法,将String转为Byte
33     public static Byte decode(String nm) throws NumberFormatException {
34         int i = Integer.decode(nm);//一会重点讲解Integer的系列方法
35         if (i < MIN_VALUE || i > MAX_VALUE)
36             throw new NumberFormatException(
37                     "Value " + i + " out of range from input " + nm);
38         return valueOf((byte)i);
39     }
40 }

解释radix的作用

b[0] = Byte.parseByte(“11”, 2) = 3

表示 字符串11以2为基数表示为10进制的byte值是 3 ,这里的11表示的是一个2进制数

b[0] = Byte.parseByte(“11”, 3) = 4

表示 字符串11以3为基数表示为10进制的byte值是 4 ,这里的11表示的是一个3进制数

3、int和Integer

 

  1 public final class Integer extends Number implements Comparable<Integer> {
  2 
  3      public static final Class<Integer>  TYPE = (Class<Integer>) Class.getPrimitiveClass("int");//原始类型int的Class实例。
  4      //所有可能的将数字表示为字符串的字符集合做缓存。
  5      final static char[] digits = {
  6         \'0\' , \'1\' , \'2\' , \'3\' , \'4\' , \'5\' ,
  7         \'6\' , \'7\' , \'8\' , \'9\' , \'a\' , \'b\' ,
  8         \'c\' , \'d\' , \'e\' , \'f\' , \'g\' , \'h\' ,
  9         \'i\' , \'j\' , \'k\' , \'l\' , \'m\' , \'n\' ,
 10         \'o\' , \'p\' , \'q\' , \'r\' , \'s\' , \'t\' ,
 11         \'u\' , \'v\' , \'w\' , \'x\' , \'y\' , \'z\'
 12     };
 13     //两个构造器
 14      public Integer(int value) {
 15         this.value = value;
 16     }
 17     public Integer(String s) throws NumberFormatException {
 18         this.value = parseInt(s, 10);//涉及了String转换成int,一会仔细讨论这个。
 19     }
 20     //像上面Byte类型中解释的那样的方法,返回第二个参数所指定的进制数的第一个参数的字符串表示形式。处理各种进制的Integer.
 21     public static String toString(int i, int radix) {
 22         if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)             
 23         radix = 10;//默认为10进制 
 24         /* Use the faster version */         
 25         if (radix == 10) {             
 26             return toString(i);         
 27         }
 28         char buf[] = new char[33];         
 29         boolean negative = (i < 0);         
 30         int charPos = 32;
 31         //统一转为负数去处理
 32         if (!negative) {             
 33             i = -i;         
 34         }
 35         while (i <= -radix) {             
 36             buf[charPos--] = digits[-(i % radix)];             
 37             i = i / radix;         
 38         }         
 39         buf[charPos] = digits[-i];
 40         if (negative) {             
 41             buf[--charPos] = \'-\';         
 42         }
 43         return new String(buf, charPos, (33 - charPos));     
 44     }
 45     //一会有事例代码演示这个,这个其实就是把int型包装成Integer然后再转化成String字符串
 46      public static String toString(int i) {
 47         if (i == Integer.MIN_VALUE)
 48             return "-2147483648";
 49         int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
 50         char[] buf = new char[size];
 51         getChars(i, size, buf);
 52         return new String(buf, true);
 53     }
 54     //与toString组合形成一方法去转换成字符串咯
 55     static void getChars(int i, int index, char[] buf) {
 56         int q, r;
 57         int charPos = index;
 58         char sign = 0;
 59 
 60         if (i < 0) { //如果i为负数,则设置i的符号字符为\'-\'。
 61             sign = \'-\';  //确定正负数
 62             i = -i;  //将负数转化为正数处理,提高效率 
 63         }
 64 
 65         // Generate two digits per iteration
 66         while (i >= 65536) { //如果i大于65536,则每一次都获取十位和个位上的数字对应的字符。将值判断大小后取每个数字,较大的数字一次取两位(大数字运算消耗大)
 67             q = i / 100;
 68         // really: r = i - (q * 100);
 69             r = i - ((q << 6) + (q << 5) + (q << 2)); //利用位运算,每次获得i的最后两位数,不断循环提取处理
 70             i = q;//重新赋值,准备下一次循环 
 71             buf [--charPos] = DigitOnes[r]; //存储r中在个位数集合中对应的字符
 72             buf [--charPos] = DigitTens[r]; //存储r中在十位数集合中对应的字符
 73         }
 74 
 75         // Fall thru to fast mode for smaller numbers
 76         // assert(i <= 65536, i);
 77         for (;;) { //i<65536的情况,小数字运算消耗较小,故一次只取一位
 78             q = (i * 52429) >>> (16+3);//52429/(2*19)约等于1,此处这样设计是为了提高精度
 79             r = i - ((q << 3) + (q << 1));  // r = i-(q*10) ... //每次获得i的最后两位数
 80             buf [--charPos] = digits [r];//取最后一位的数字  
 81             i = q;//重新赋值,准备下一次循环  
 82             if (i == 0) break;
 83         }
 84         if (sign != 0) {
 85             buf [--charPos] = sign; //设置符号
 86         }
 87     }
 88     //下面两个是用来确定字符串长度的。
 89     //定义sizeTable表示int中每个位数中最大的数,用于简便确定int数的长度。
 90     final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
 91                                       99999999, 999999999, Integer.MAX_VALUE };
 92     //使用上面的sizeTable定义来确定int数的字符串表示长度。           
 93     static int stringSize(int x) {
 94         for (int i=0; ; i++)
 95             if (x <= sizeTable[i])
 96                 return i+1;
 97     }
 98     //炒鸡重要的方法啦!!parseInt(String s,int radix)使用第二个参数指定的基数,将字符串参数解析为有符号的整数。 parseInt(String s)只能将数字字符串转化十进制数
 99      public static int parseInt(String s, int radix)
100                 throws NumberFormatException
101     {
102         /*
103          * WARNING: This method may be invoked early during VM initialization
104          * before IntegerCache is initialized. Care must be taken to not use
105          * the valueOf method.
106          */
107 
108         if (s == null) {//参数检验,调用方法前检查参数的正确性。
109             throw new NumberFormatException("null");
110         }
111 
112         if (radix < Character.MIN_RADIX) {
113             throw new NumberFormatException("radix " + radix +
114                                             " less than Character.MIN_RADIX");
115         }
116 
117         if (radix > Character.MAX_RADIX) {
118             throw new NumberFormatException("radix " + radix +
119                                             " greater than Character.MAX_RADIX");
120         }
121 
122         int result = 0;
123         boolean negative = false;
124         int i = 0, len = s.length();//i表示当前遍历的s的位数
125         int limit = -Integer.MAX_VALUE;//设置最小值为负的Integer的最大值
126         int multmin;
127         int digit;
128 
129         if (len > 0) {//如果字符串长度大于0,则进行转换
130             char firstChar = s.charAt(0);//获取第一位字符
131             if (firstChar < \'0\') { // Possible leading "+" or "-"
132                 if (firstChar == \'-\') {//判断是否为负数 
133                     negative = true; 
134                     limit = Integer.MIN_VALUE;//将限制转换为Integer的最小值,不能小于Integer的最小值  
135                 } else if (firstChar != \'+\')
136                     throw NumberFormatException.forInputString(s);//第一个char不为+也不为-,则抛出异常  
137 
138                 if (len == 1) // Cannot have lone "+" or "-"
139                     throw NumberFormatException.forInputString(s);//若只有一个符号,则抛出异常
140                 i++;
141             }
142             multmin = limit / radix;//设定不同进制下的极限值  
143             while (i < len) {//进行进制的转换
144                 // Accumulating negatively avoids surprises near MAX_VALUE
145                 digit = Character.digit(s.charAt(i++),radix);//将数字字符串转换成要求的进制数,使用工具类,每次遍历对一个字符进行操作转换  
146                 if (digit < 0) {
147                     throw NumberFormatException.forInputString(s);
148                 }
149                 if (result < multmin) {
150                     throw NumberFormatException.forInputString(s);
151                 }
152                 result *= radix;
153                 if (result < limit + digit) {
154                     throw NumberFormatException.forInputString(s);
155                 }
156                 result -= digit;
157             }
158         } else {
159             throw NumberFormatException.forInputString(s);
160         }
161         return negative ? result : -result;//根据符号返回正数还是负数
162     }
163     //看吧,我们经常用的parseInt只是个帮我们制定好10进制规则的静态方法
164     public static int parseInt(String s) throws NumberFormatException {
165         return parseInt(s,10);
166     }
167     //强大的内部类缓存机制吗,内部字符缓存类
168     private static class IntegerCache {
169         //缓存的下界,-128,不可变  
170         static final int low = -128;
171          //缓存上界,暂为null
172         static final int high;
173         static final Integer cache[];//利用数组来缓存
174         //原理:初始化数组将一定范围的整数放到cache数组中,然后在调valueOf方法的时候首先判断范围然后从缓存数组中去抓取数据
175 
176         static {
177             // high value may be configured by property
178             // 缓存上届,可以通过JVM属性来配置
179             int h = 127;
180             String integerCacheHighPropValue =
181                 sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
182             //获取,得到上界
183             if (integerCacheHighPropValue != null) {
184                 try {
185                     int i = parseInt(integerCacheHighPropValue);
186                     i = Math.max(i, 127);
187                     // Maximum array size is Integer.MAX_VALUE
188                     h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
189                 } catch( NumberFormatException nfe) {
190                     // If the property cannot be parsed into an int, ignore it.
191                 }
192             }
193             high = h;
194             //获取Integer中所有能保存的数据,初始化缓存数组
195             cache = new Integer[(high - low) + 1];
196             int j = low;
197             //缓存所有Integer的数据
198             for(int k = 0; k < cache.length; k++)
199                 cache[k] = new Integer(j++);
200 
201             // range [-128, 127] must be interned (JLS7 5.1.7)
202             assert IntegerCache.high >= 127;
203         }
204 
205         private IntegerCache() {}
206     }
207     //还有这个我们经常用的,官方也推荐使用这个方法去创建对象的
208        public static Integer valueOf(i

以上是关于深入Java基础——基本数据类型及其包装类的主要内容,如果未能解决你的问题,请参考以下文章

深入Java基础--哈希表HashMap应用及源码详解

深入浅出 Java 中的包装类

Java语言学习总结 扩展篇 包装类的概念及其使用

Java连载76-基础数据类型包装类型及其方法简介

Java包装类及其他类

3.6 java基础总结①包装类,基本数据类型,String相互间转换