自学内容网 自学内容网

Java——包装类及认识泛型

包装类:

        在学习泛型之前我们一定要认识包装类。

        在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
}
}
代码解释:
1. 类名后的 <T> 代表占位符,表示当前类是一个泛型类
了解: 【规范】类型形参一般使用一个大写字母表示,常用的名称有:
E 表示 Element
K 表示 Key
V 表示 Value
N 表示 Number
T 表示 Type
S, U, V 等等 - 第二、第三、第四个类型
2. 注释 1 处,不能 new 泛型类型的数组:
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
}
}
T [] ts = new T [ 5 ]; // 是不对的
3. 注释 2 处,类型后加入 <Integer> 指定当前类型
4. 注释 3 处,不需要进行强制类型转换
5. 注释 4 处,代码编译报错,此时因为在注释 2 处指定类当前的类型,此时在注释 4 处,编译器会在存放元素的时候帮助我们进行类型检查。

原文地址:https://blog.csdn.net/m0_75235246/article/details/142351007

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!