什么是包装类?
包装类:就是将8种基本数据类型,装换成对应的8种包装引用类型。
为什么需要将8种基本数据类型转换为8中包装类型呢?
原因在于8种基本的数据类型不够用
实例代码举例:
/**
* @author Jason
* @create 2020-04-30 16:10
*/
public class StringTest07 {
public static void main(String[] args) {
MyInt myInt = new MyInt(100);
doSome(myInt);
}
public static void doSome(Object object){
System.out.println(object.toString());
}
}
/**
* @author Jason
* @create 2020-04-30 16:11
*/
public class MyInt {
int value;
public MyInt() {
}
public MyInt(int value) {
this.value = value;
}
@Override
public String toString() {
return String.valueOf(value);
}
}
通过上面的实例,会发现,调用doSome方法,该方法需要的是Object类型的参数,但是如果我们此时传入的是基本类型的数字肯定是无法接收的,那我们该怎么办?其实就是用包装类的方法解决:用构造方法的形式将基本类型的数据包装成包装类型的数据。
8种基本数据类型对应的包装类型名是什么?
基本数据类型 | 包装类型 |
byte | java.lang.Byte(父类Number) |
short | java.lang.Short(父类Number) |
int | java.lang.Integer(父类Number) |
long | java.lang.Long(父类Number) |
float | java.lang.Float(父类Number) |
double | java.lang.Double(父类Number) |
boolean | java.lang.Boolean(父类Object) |
char | java.lang.Character(父类Object) |
8中包装类型中有6种都是数字类型的包装类,他们的父类都是Number,那么Number中的公共方法都有哪些呢?
- byte byteValue() 以 byte 形式返回指定的数值。
- abstract double doubleValue()以 double 形式返回指定的数值。
- abstract float floatValue()以 float 形式返回指定的数值。
- abstract int intValue()以 int 形式返回指定的数值。
- abstract long longValue()以 long 形式返回指定的数值。
- short shortValue()以 short 形式返回指定的数值。
这些方法其实所有的数字包装类的子类都有,这些方法是负责拆箱的。
具体的实例代码:
/**
* @author Jason
* @create 2020-04-30 16:29
* 拆装箱
*/
public class StringTest08 {
public static void main(String[] args) {
//装箱
Integer i = new Integer(123);
//拆箱
float v = i.floatValue();
System.out.println(v);
//拆箱
int i1 = i.intValue();
System.out.println(i1);
}
}
8种包装类的构造方法有哪些呢?(以Integer为例)
- Integer(int)
- Integer(String)
/**
* @author Jason
* @create 2020-04-30 16:43
* Integer包装类的构造方法
*/
public class StringTest09 {
public static void main(String[] args) {
Integer a = new Integer(100);
System.out.println(a);//100 这里当然重写了toString方法
Integer b = new Integer("111");
System.out.println(b);//111
}
}
什么是自动拆箱,自动装箱?
自动装箱:基本数据类型自动转换成包装类。
自动拆箱:包装类自动转换成基本数据类型。
有什么好处呢?
方便编码
具体实例代码:
/**
* @author Jason
* @create 2020-04-30 17:14
* 自动拆箱,自动装箱
*/
public class StringTest0 {
public static void main(String[] args) {
//自动装箱
Integer a = 100;
System.out.println(a);
//自动拆箱
int b = a;
System.out.println(b);
Integer c = 10;
System.out.println(c+1);
Integer d = 222;
Integer e = 222;
System.out.println(d == e);//false
}
}
分析:
Integer c = 10;
System.out.println(c+1);
这里的c是一个引用,一个变量,保存的是一个对象的内存地址,在进行c+1的时候为什么没有报错呢?
原因在于:加号两边要求的是基本数据类型的数字,c是包装类,不属于基本的数据类型,这里会进行自动拆箱,将c装换成基本的数据类型
Integer d = 222;// Integer d = new Integer(222); d是个引用,保存内存地址指向对象
Integer e = 222;// Integer e = new Integer(222); e是个引用,保存内存地址指向对象
System.out.println(d == e);//false
这个为什么没有自动拆箱呢?
- == 比较的是对象的内存地址,d和e两个引用中保存的对象内存地址不同。
- == 这个运算符不会触发自动拆箱机制。(只有+ - * /等运算的时候才会。)
在看一个实例:
/**
* @author Jason
* @create 2020-05-01 19:42
* 自动拆箱问题
*/
public class StringTest {
public static void main(String[] args) {
Integer x = 100;
Integer y = 100;
System.out.println(x == y); //true
Integer a = 128;
Integer b = 128;
System.out.println(a == b); //false
}
}
通过这个实例可以非常清楚的发现一个问题,那就是不是“==”号两边的所有数据都不能自动拆箱。
那到底什么样的数据能自动拆箱,什么样的数据不能自动拆箱呢?
其实通过源码很容易发现在加载的时候有-128~127已经被加载到了缓存当中,当我们用到这些数字的时候JVM就自动的帮助我们拆箱了,这样一来方便了我们的开发。但是只要超过这个范围的数字JVM就不会帮助我们拆箱。
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
}
8种包装类中都有哪些常用方法?(以Integer举例)
- parseInt
- valueOf
- toBinaryString
- toHexString
下面先来看实例代码:
/**
* @author Jason
* @create 2020-05-01 20:03
* 常用方法
*/
public class StringTest13 {
public static void main(String[] args) {
Integer a = new Integer("111");
System.out.println(a); //111
/*Integer b = new Integer("c");
System.out.println(b); //NumberFormatException异常*/
//其实它的底层就是这个静态方法,将String类型的数字转换成int类型的
/*public static int parseInt(String s) throws NumberFormatException {
return parseInt(s,10);
}*/
int i = Integer.parseInt("222");
System.out.println(i+111); //333
double v = Double.parseDouble("3.14");
System.out.println(v+2); //5.140000000000001
//他的底层是这个方法,将int类型的转化成Integer类型的
/*public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}*/
Integer i1 = Integer.valueOf(128);
System.out.println(i1); //128
Integer i2 = Integer.valueOf("100");
System.out.println(i2); //100
}
}
通过上面的实例很容易的发现parseInt和valueOf有很多的类似之处,他们的区别在于:
先看他们的示例代码:
//valueOf和parseInt的区别
Integer a1 = Integer.valueOf("100");
Integer a2 = Integer.valueOf("100");
System.out.println(a1 == a2); //true
Integer a3 = Integer.valueOf("128");
Integer a4 = Integer.valueOf("128");
System.out.println(a3 == a4); //false
System.out.println("+++++++++++++++++");
int a5 = Integer.parseInt("100");
int a6 = Integer.parseInt("100");
System.out.println(a5 == a6); //true
int a7 = Integer.parseInt("128");
int a8 = Integer.parseInt("128");
System.out.println(a7 == a8); //true
通过上面可以看到,他们的执行结果还是有很多的不一样的,调用vauleOf的时候如果超过127他在“==”判断时候出现false,但是在调用parseInt的时候就不会。这是为什么呢?
原因在于:valueOf在缓存中存有(-128~127),他只要在这个范围内“==”JVM就会自动的拆箱,但是超过了这个范围就不会了,而parseInt就没有这个功能,所有在使用这两个常用方法的时候需要注意。请见源码:
valueOf的源码:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
parseInt的源码:
public static int parseInt(String s) throws NumberFormatException {
return parseInt(s,10);
}