数据结构 泛型

本文探讨了Java中的包装类及其在面试中的应用。讲解了装箱和拆箱的过程,强调了隐式和显式之分,并通过一个面试题解释了为何在某些情况下,包装类的对象会有所不同,这涉及到缓存和对象创建的细节。
摘要由CSDN通过智能技术生成
泛型:就是适用于许多许多类型。从代码上讲,就是对类型实现了参数
化。
泛型的主要目的:就是指定当前的容器,要持有什么类型的对象。让编译
器去做检查。此时,就需要把类型,作为参数传递。需要什么类型,就传入什么类型。
泛型的意义:
1.自动对类型进行检查
2.自动对类型进行强制类型的转换
泛型是作用在编译期间的一种机制,即运行期间没有泛型的概念

关于Object[] 强制类型转换的思考 - 简书

力扣(找到小镇的法官)

力扣(.二维网格迁移)


包装类

包装类的使用

 装箱和拆箱有隐式,显式之分:


下面看一个面试题:

为什么会出现下面这种情况?

我们看下源码,我们会发现如果满足>=low且<=high,那么会放到cache数组中,如果不满足这个范围,则会新建一个对象,这就是为什么上面两个结果不一样


泛型语法:(有两种)
1.
class 泛型类名称<类型形参列表> {
  // 这里可以使用类型参数
}
class ClassName<T1, T2, ..., Tn> {
}
2.
class 泛型类名称<类型形参列表> extends 继承类/* 这里可以使用类型参数 */ {
  // 这里可以使用类型参数
}
class ClassName<T1, T2, ..., Tn> extends ParentClass<T1> {
  // 可以只使用部分类型参数
}
<T> 代表占位符,表示当前类是一个泛型类

看这段代码:
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.不能new泛型类型的数组,即:T[] ts = new T[5];//是不对的
注释1虽然没有报错,但也是不好的,因为擦除机制(下面有擦除机制的介绍),泛型在编译时T会替换为Object,Object可以是任意类型(int、String...),但泛型是要指定类型(总结2中有写),所以如果像注释1这样也不行
2.注释2的Integer表示指定了泛型的当前类型是Integer,因此注释3处不需要像不同的类那样进行强制类型转换
3.注释4代码编译报错,因为在注释2处指定类当前的类型,此时在注释4处,编译器会在存放元素的时候帮助我们进行类型检查。

泛型类的使用:
泛型类<类型实参> 变量名; // 定义一个泛型类引用
new 泛型类<类型实参>(构造方法实参); // 实例化一个泛型类对象
例子: MyArray<Integer> list = new MyArray<Integer>();
注意: 泛型只能接受类,所有的基本数据类型必须使用包装类!

裸类型(了解即可)
裸类型是一个泛型类但没有带着类型实参,例如 MyArrayList 就是一个裸类型

擦除机制
编译 的过程当中,将 所有的T替换为Object这种机制 ,我们称为:擦除机制。
泛型机制是在编译级别实现的

创建泛型数组的正确写法:
 /**
  * 通过反射创建,指定类型的数组
  * @param clazz
  * @param capacity
  */
  public MyArray(Class<T> clazz, int capacity) {
    array = (T[])Array.newInstance(clazz, capacity);
 }

泛型的上界
class 泛型类名称<类型形参 extends 类型边界> {
 ...
}
例子1:
public class MyArray<E extends Number> {// E可以是Number或Number的子类
 ...
}
例子2(比较特殊的): public class MyArray<E extends Comparable<E>> {
 ...
}// E必须是实现了Comparable接口的
例子3 :class MyArray<T> {//这种没有指定边界的,默认为: E extends Object
}

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

泛型中的父子类关系
public class MyArrayList<E> { ... }
// MyArrayList<Object> 不是 MyArrayList<Number> 的父类型
// MyArrayList<Number> 也不是 MyArrayList<Integer> 的父类型
因为泛型只在编译时才有,运行时泛型已经被擦除了,因此像上面的<Object>和<Number>也被擦除了

通配符
? 用于在泛型的使用,即为通配符
泛型和通配符的不同之处:
通配符是用来解决泛型无法协变的问题的(通配符用来解决泛型不能解决的父子类关系的),协变指的就是如果 Student 是 Person 的子类,那么 List<Student> 也应该是 List<Person> 的子类。但是泛型是不支持这样的父子类关系的。
泛型 T 是确定的类型,一旦你传了我就定下来了,而通配符则更为灵活或者说是不确定,更多的是用于扩
充参数的范围.
泛型T就像是个变量,等着你将来传一个具体的类型,而通配符则是一种规定,
规定你能传哪些参数。
来看一下代码上泛型和通配符的区别:
public static<T> void printList1(ArrayList<T> list) {
  for ( T x:list) {
    System.out.println(x);
 }
}
public static void printList2(ArrayList<?> list) {
  for ( Object x:list) {
    System.out.println(x);
 }
}
通配符上界
<? extends 上界>
<? extends Number>// 可以传入的实参类型是Number或者Number的子类
通配符的上界-父子类关系
// 需要使用通配符来确定父子类型
MyArrayList<? extends Number> 是 MyArrayList <Integer>或者 MyArrayList<Double>的父类类型
MyArrayList<?> 是 MyArrayList<? extends Number> 的父类型
通配符的上界-特点
适合读取数据,不适合写入数据
原因是此时的list可以引用的对象有很多,编译器无法确认具体的类型
比如下面举一个例子:
ArrayList<Integer> arrayList1 = new ArrayList<>();
ArrayList<Double> arrayList2 = new ArrayList<>();
List<? extends Number> list = arrayList1;
// list.add(1,1);//报错
Number a = list.get(0);//可以通过
Integer i = list.get(0);//编译错误,只能确定是Number子类
通配符下界
<? super 下界>
<? super Integer>//代表 可以传入的实参的类型是Integer或者Integer的父类类型
通配符下界-父子类关系
MyArrayList<? super Integer> 是 MyArrayList<Integer>的父类类型
MyArrayList<?> 是 MyArrayList<? super Integer>的父类类型
通配符下界-特点
适合写入数据,不适合读取数据
ArrayList<? super Person> list = new ArrayList<Person>();
// ArrayList<? super Person> list2 = new ArrayList<Student>();//编译报错,list2只能引用Person或者Person父类类型的list
list.add(new Person());//添加元素时,只要添加的元素的类型是Person或者Person的子类就可以
list.add(new Student());
Student s = list.get(0);//error
Object s = list.get(0);//可以
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值