Java——包装类、泛型简介

一、包装类

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

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

基本数据类型包装类
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
charCharacter
booleanBoolean

除了 Integer 和 Character ,其余基本类型的包装类都是首字母大写

1.2 装箱(装包)和拆箱(拆包)

1.2.1 概念:

把 基本数据类型 变为 包装类类型 的过程叫做 装箱

把 包装类类型 变为 基本数据类型 的过程叫做 拆箱

tip:快速打开代码存储位置

out目录下有class文件,在地址栏输入cmd,打开cmd窗口,输入javap -c,查看源码


1.2.2 装箱:

通过源码可以发现,显示装箱和自动装箱都是调用了valueOf方法


1.2.3 拆箱:


1.2.4 面试题:

    public static void main(String[] args) {
        Integer a = 100;
        Integer b = 100;
        System.out.println(a == b);
        
        Integer c = 200;
        Integer d = 200;
        System.out.println(c == d);
    }

运行结果:

解析:

该段代码涉及到了装箱,我们查看 valueOf 方法的源码

通过查看源码,得出初步结论:i 应该在一个范围内时,返回某个数组中的值,不在这个范围时,返回新对象,新对象用 == 进行比较,比较的是地址,肯定不一样了

继续查看源码,发现low = -128,high = 127,共256个数字

构成一个256个元素的缓存数组

所以代码中当元素范围为-128~127时,是传值比较,当超出这个范围,就是创建新对象,传址比较了 

二、泛型

泛型是JDK1.5引入的新的语法

通俗讲:泛型就是适用于许多类型

代码上讲:就是对类型实现了参数化

2.1 示例:

实现一个类,类中包含一个数组成员,使得数组中可以存放任何类型的数据,也可以根据成员方法返回数组中某个下标的值

思路:所有类的父类默认为Object,所以创建一个Object数组符合需求

代码:

解析:每次获得数组元素都需要强制类型转换

上面的代码太乱了,什么类型都能存放,要用的时候,都需要强转,而更过的情况下,我们只希望他能够只持有一种数据类型,而不是同时持有多种类型,因此就引入了泛型

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

2.2 泛型语法

class 泛型类名称<类型形参列表> {
    // 这里可以使用类型参数
}
 
class ClassName<T1, T2, ..., Tn> {  
}

class 泛型类名称<类型形参列表> extends 继承类/* 这里可以使用类型参数 */ {
    // 这里可以使用类型参数
}
 
class ClassName<T1, T2, ..., Tn> extends ParentClass<T1> {
    // 可以只使用部分类型参数
}

引入泛型,上述示例代码可改为:

class MyArray<E> {
    public Object[] array = new Object[10];

    public void setVal(int pos,E val) {
        this.array[pos] = val;
    }

    public E getVal(int pos) {
        return (E)this.array[pos];
    }
}
public class Test {

    public static void main(String[] args) {
        MyArray<Integer> myArray = new MyArray<>();
        myArray.setVal(0,10);
        myArray.setVal(1,20);
        //myArray.setVal(2,"hello");//编译器会自动类型检查
        Integer a = myArray.getVal(1);//自动类型转换

        System.out.println("======");

        MyArray<String> myArray1 = new MyArray<>();
        myArray1.setVal(0,"hello");
        myArray1.setVal(2,"abc");
    }
}

解析:

类名后的<E>代表占位符,表示当前类是一个泛型类


2.3 泛型类使用的注意事项:


2.4 泛型的擦除机制

在编译的过程中,将所有的 E 替换为 Object ,这种机制称为擦除机制

Java的泛型机制是在编译级别实现的,编译器生成的字节码在运行期间并不包含泛型的类型信息


2.5 泛型的上界

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

2.5.1 语法:

class 泛型类名称<类型形参 extends 类型边界> {
    ...
}

2.5.2 示例:

public class MyArray<E extends Number> {
    ...
 }

只接收 Number 的子类型作为 E 的类型实参

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

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

2.5.3 复杂示例:

public class MyArray<E extends Comparable<E>> {
    ...
}

E 必须是实现了Comparable 接口的

示例:写一个泛型类,其中有个方法,可以求数组最大值

class Alg<E> {
    public E findMax(E[] array) {
        E max = array[0];
        for (int i = 1; i < array.length; i++) {
            if(max < array[i]) {//error
                max = array[i];
            }
        }
        return max;
    }
}
public class Test2 {
    public static void main(String[] args) {
        Integer[] array = {1,2,3,4,5,6,7,8};
        Alg<Integer> alg = new Alg<>();
        int a = alg.findMax(array);
        System.out.println(a);
    }
}

发现比较方法会报错:

这是因为并不知道E的具体类型是什么,而且当我们没有规定的时候,当程序运行时,Java会将E擦除成 Object 引用类型,也不能用 < 或 > 做比较,想要此引用类型可以比较。让 E 实现 Comparable 接口,声明 E 可以被比较,代码改为如下:

class Alg<E extends Comparable<E>> { //E实现Comparable接口
    public E findMax(E[] array) {
        E max = array[0];
        for (int i = 1; i < array.length; i++) {
            if(max.compareTo(array[i]) < 0) {  //使得该数组元素类型可以使用compareTo方法进行比较
                max = array[i];
            }
        }
        return max;
    }
}

2.6 泛型方法 

借用上面的例子,将泛型方法放在普通类里,区别如下:

当把泛型方法为静态时,就不需要创建对象来调用了,直接使用类名调用,如下:

  • 38
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值