包装类:
在学习泛型之前我们一定要认识包装类。
在Java 中,由于基本类型不是继承自 Object ,为了在泛型代码中可以支持基本类型, Java 给每个基本类型都对应了一个包装类型。
除了int类型和char类型的包装类不是它们对应的基本类型的大写之外,其他的都是将基本类型的首字母大写!
包装类中也有对应的许多方法,例如:将字符串类型转为整型:
我们以Integer包装类为例研究。
拆箱和装箱:
拆箱和装箱也被称为拆包和装包:
装箱:
也就是将基本类型变成包装类的过程:
例如:
此时就对基本类型完成了装箱过程:
需要调用Integer的静态方法完成装箱:
这个静态方法是什么意思呢?
可以一起看看,源码如下:
public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);}
首先进入源码有一个if语句,我们看看能能不能看懂。
Integer.low和Integer.high是什么意思呢?
我们同样找到low和high中,发现low是-128,high是127,也就是当我们传过来的参数如果小于-128或者大于127,这时候先调用Integer的构造函数之后就直接new一个新的Integer对象返回。
将类中的value初始化,完成整个装箱过程!!
但是如果此时我输入的值在-128和127之间会发生什么?
继续来看:
此时返回一个数组对应的值,cache是该类一开始就定义的一个Integer数组类型的成员变量:
那么这个数组中放的是什么呢?
在一开始的静态代码块中有初始化:
发现这个数组中首先只有(127+128+1 = 256)的大小,j = -128;之后将参数为-128 - 127的Integer类型的放在数组中,下标从0 - 255!!
这时候就明白了,原来这个数组中存放的就是-128到127的Integer类型的变量。
所以当我们传参如果大于127或者小于-128的时候,这时候会计算一个位置然后返回,如果是3,那么就返回3+128 = 131位置的对应的Integer对象,131位置上Integer初始化的value正好是3。
如上就是原理图!!
拆箱:
就是将包装类变成基本类型:
例如:
public static void main(String[] args) {Integer i = Integer.valueOf(10);int a = i.intValue();System.out.println(a);}
这就是拆箱过程,也就是调用封装对象的intValue方法。
源码如下;:
这个通俗易懂直接返回一个int类型的值。
自动拆箱和装箱:
名表了拆箱和装箱的原理,也知道拆线和装箱需要调用哪个方法。
但是此时我写这样的代码,看看编译器能否通过编译!
首先没有报错,再其次打印结果如下:
此时有两个问题:
1.Integer引用类型为什么可以直接接受一个int类型的变量?
2.为什么我直接打印Integer引用类型变量,打印结果是一个10?
接下来一一解答该问题:
1.编译器会为我们自动完成拆箱和装箱的过程!
2.Integer包装类中已经重写了toString方法!!
自动拆箱演示过程:
泛型:
什么是泛型:
泛型:就是适用于许多许多类型。从代码上讲,就是对类型实现了参数0化。
语法:
class 泛型类名称 < 类型形参列表 > {// 这里可以使用类型参数}class ClassName < T1 , T2 , ..., Tn > {}
class 泛型类名称 < 类型形参列表 > extends 继承类 /* 这里可以使用类型参数 */ {// 这里可以使用类型参数}class ClassName < T1 , T2 , ..., Tn > extends ParentClass < T1 > {// 可以只使用部分类型参数}
class MyArray<T> {
public T[] array = (T[])new Object[10];//1
public T getPos(int pos) {
return this.array[pos];
}
public void setVal(int pos,T val) {
this.array[pos] = val;
}
}
public class TestDemo {
public static void main(String[] args) {
MyArray<Integer> myArray = new MyArray<>();//2
myArray.setVal(0,10);
myArray.setVal(1,12);
int ret = myArray.getPos(1);//3
System.out.println(ret);
myArray.setVal(2,"bit");//4
}
}
class 泛型类名称 < 类型形参列表 > extends 继承类 /* 这里可以使用类型参数 */ {// 这里可以使用类型参数}class ClassName < T1 , T2 , ..., Tn > extends ParentClass < T1 > {// 可以只使用部分类型参数}class MyArray < T > {public T [] array = ( T []) new Object [ 10 ]; //1public T getPos ( int pos ) {return this . array [ pos ];}public void setVal ( int pos , T val ) {this . array [ pos ] = val ;}}public class TestDemo {public static void main ( String [] args ) {MyArray < Integer > myArray = new MyArray <> (); //2 当编译器可以根据上下文推导出类型实参 时,可以省略类型实参的填写myArray . setVal ( 0 , 10 );myArray . setVal ( 1 , 12 );int ret = myArray . getPos ( 1 ); //3System . out . println ( ret );myArray . setVal ( 2 , "bit" ); //4}}T [] ts = new T [ 5 ]; // 是不对的