包装类和泛型的二三事

1 包装类

        在Java中,由于基本类型不是继承自Object,为了在泛型代码中可以支持基本类型,Java给每个基本类型都对应了 一个包装类型。

1.1 基本数据类型和对应的包装类

             包装类和泛型的二三事_第1张图片

        除了 Integer 和 Character, 其余基本类型的包装类都是在基本类型的基础上首字母大写即可。

1.2 装箱和拆箱

        1、 装箱操作,新建一个 Integer 类型对象,将 基本数据类型 i 的值放入到包装类对象的某个属性中 

        2、拆箱操作,将 Integer 对象中的值取出,放到一个基本数据类型中

 public static void main(String[] args) {
        int i = 10;
        // 装箱操作,新建一个 Integer 类型对象,将 i 的值放入对象的某个属性中
        Integer ii = Integer.valueOf(i);
        Integer ij = new Integer(i);
        // 拆箱操作,将 Integer 对象中的值取出,放到一个基本数据类型中
        int j = ii.intValue();
    }

        通过下面控制板和Interger.valueOf()的底层代码了解----装箱和拆箱

        下图为装箱:

包装类和泛型的二三事_第2张图片  下图为拆箱:包装类和泛型的二三事_第3张图片包装类和泛型的二三事_第4张图片

1.3 自动装箱和自动拆箱

public static void main(String[] args) {
        int i = 10;
        Integer ii = i; // 自动装箱
        Integer ij = (Integer)i; // 自动装箱
        int j = ii; // 自动拆箱
        int k = (int)ii; // 自动拆箱
    }

包装类和泛型的二三事_第5张图片 

        深入了解intreger包装类,运行以下代码且查看其结果:


    public static void main(String[] args) {

            Integer a = 127;
            Integer b = 127;
            System.out.println(a == b);
            Integer c = 128;
            Integer d = 128;
            System.out.println(c == d);
    }
}

//        true
//        false

        详细图解如下:

包装类和泛型的二三事_第6张图片         由上图所示IntergerCache.low=-128;IntergerCache.high=127;当我们用包装成interger类的int数据类型的数据在(-128,127)之间,我们最后包装类的分配引用和之前类型的数据结果是一样;但是如果我们要包装的数值结果不在上述这个区间,系统会进行当前数值+(-128)操作并返回给方法,这样的话会导致系统分配给包装类的引用不太一样。

2 泛型了解一下

        一般的类和方法,只能使用具体的类型: 要么是基本类型,要么是自定义的类。如果要编写可以应用于多种类型的 代码,这种刻板的限制对代码的束缚就会很大。

2.1 初闻泛型

         泛型是在JDK1.5引入的新的语法,泛型:就是适用于许多许多类型从代码上讲,就是对类型实现了参数化

        泛型的主要目的:就是指定当前的容器,要持有什么类型的对象。让编译器去做检查。此时,就需要把类型,作为参数传递。需要什么类型,就传入什么类型。

2.2 语法格式

包装类和泛型的二三事_第7张图片

包装类和泛型的二三事_第8张图片

         代码如下:

  class MyArray {
            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 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. 类名后的代表占位符,表示当前类是一个泛型类

        拓展:【**】类型形参一般使用一个大写字母表示,常用的名称有:

            包装类和泛型的二三事_第9张图片

        2. 注释1处,不能new泛型类型的数组,如下图所示:

           

        3. 注释2处,类型后加入 指定当前类型

        4. 注释3处,不需要进行强制类型转换

        5. 注释4处,代码编译报错,此时因为在注释2处指定类当前的类型,此时在注释4处,编译器会在存放元素的时 候帮助我们进行类型检查。

        上述代码泛型类改造之后:

class MyArray {
    public Object[] array = new Object[10];//1
    public T getPos(int pos) {
        return (T)array[pos];
    }
    public void setVal(int pos,T val) {
        this.array[pos] = val;
    }
}

3 泛型类的使用

3.1 语法格式

        代码展示:

        注意:泛型只能接受类,所有的基本数据类型必须使用包装类! 

3.2  裸类型(Raw Type)

        裸类型是一个泛型类但没有带着类型实参,例如 MyArrayList 就是一个裸类型,如下图所示:

                      

        小结:

        1. 泛型是将数据类型参数化,进行传递

        2. 使用 表示当前类是一个泛型类。

        3. 泛型目前为止的优点:数据类型参数化,编译时自动进行类型检查和转换

4 泛型如何编译的----擦除机制

        那么,泛型到底是怎么编译的?(面试题哦)

        通过命令:javap -c 查看字节码文件,所有的T都是Object。

包装类和泛型的二三事_第10张图片

        在编译的过程当中,将所有的T替换为Object这种机制,我们称为:擦除机制

        Java的泛型机制是在编译级别实现的。编译器生成的字节码在运行期间并不包含泛型的类型信息,下面详细了解一下擦除机制:

            包装类和泛型的二三事_第11张图片

        但是根据下图的getArray()所示:

              

        虽然我们创建的myarray1对象存储的数据是integer的,但是在使用getArray()方法时,我们将myarray1的存储的数据类型擦除,变为object类,所以将被擦除成object类的数据传给strings(被定义为integer时),会导致有的数据可能是非integer而系统报错。

        泛型类的使用时我们给的类型实参主要起两个作用:

        (1)存储数据的时候,可以帮我们进行自动的类型检查

        (2)获取数据的时候,可以帮我们进行类型转换

5 泛型的上界

        在定义泛型类时,有时需要对传入的类型变量做一定的约束,可以通过类型边界来约束。

 5.1 语法格式

         包装类和泛型的二三事_第12张图片

        代码eg:

public class MyArray {
...
}

 MyArray-------->意味着MyArray的数据类型是E,但是E只接受 Number 的子类型作为 E 的类型实参

MyArray l1; // 正常,因为 Integer 是 Number 的子类型
MyArray l2; // 编译错误,因为 String 不是 Number 的子类型

        当没有指定类型边界 E,可以视为 E extends Object 

5.2  泛型方法

5.2.1定义语法

方法限定符 < 类型形参列表 > 返 回值类型 方法名称 ( 形参列表 ) { ... }

public class Text2 {
    public static >  E Max(E[]arr) {
        E ret = arr[0];
        for (int i = 1; i < arr.length; i++) {
            if (ret.compareTo(arr[i]) < 0) {
                ret = arr[i];
            }
        }
        return ret;
    }
 
    public static void main(String[] args) {
        Integer[] arr={6,2,3,4,1000,1};
        System.out.println(Max(arr));
    }
}

        1、使用示例-可以类型推导 

Integer[] a = { ... };
Max(a, 0, 9);
String[] b = { ... };
Max(b, 0, 9);

         2、使用示例-不使用类型推导

Integer[] a = { ... };
Util.swap(a, 0, 9);
String[] b = { ... };
Util.swap(b, 0, 9);

ps:本次内容就到这里了,如果喜欢的话还请一键三连,后序有问题的话,我会修改的哦!!!

你可能感兴趣的:(java)