JAVASE(基础)泛型

一:什么是泛型?

(1)为什么要使用泛型?

例如:MyArray类中实现只能保存int类型的数据,对于其他类型的数据比如:double、 String或者自定义类型的对象,根本无法存储。 所有会使用泛型。

(2)定义:泛型可以写与类型无关的代码,即编写的代码可以被很多不同类型的对象所重用,经常用在一些通用的代码实现中,比如:Collection<E>,List<E>,ArrayList<E>,这个<E>就是类型参数,即泛型。

(3)本质:类型参数化。类似函数传参一样,传递不同的实参,函数运行完将会产生不同的结果。

二:泛型的分类

分类:泛型类、泛型方法和泛型接口。

(1)泛型类:

1.语法示例:

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

2.解释:

<类型形参>一般使用一个大写字母表示,常用的名称有:

E 表示 Element

K 表示 Key

V 表示 Value

N 表示 Number

T 表示 Type

S, U, V 等等 - 第二、第三、第四个类型

3.运用泛型类语法举例:

// 在实现MyArray泛型类时,E具体代表什么类型实现者不关心
// 当对泛型类进行实例化时,编译器才知道E具体代表什么类型
public class MyArray<E> {
    private E[] array = null;
    private int size;
    private int capacity;
    public MyArray(int capacity){
        // 此处为什么new Object[],为什么需要强转后文中会解释
        array = (E[])new Object[capacity];
        size = 0;
        this.capacity = capacity;
   }
    public void add(E data){
        if(size < capacity)
            array[size++] = data;
   }
    public E get(int index){
        return array[index];
   }
    public int size(){
        return  size;
   }
}

4.泛型类的实例化:

泛型类 变量名; 定义一个泛型类引用。 new 泛型类(构造方法实参); 实例化一个泛型类对象。

public static void main(String[] args) {
    // 将泛型类使用String类型来实例化,表明m中只能存放String类型的对象
    MyArray<String> m = new MyArray<>(10);
    m.add("Peter");
    m.add("David");
    m.add("Jim");
    // 编译失败:因为在实例化时,已经明确其内部只能存储String类型的对象
    // Person对象和String对象之间不能转换
    // m.add(new Person("Lily"));
    for(int i = 0; i < m.size(); ++i){
        // 此处从m中获取到的成员,再不需要进行强制类型转换了
        String s = m.get(i);
        System.out.print(s + " ");
   }
}

注意:左侧<>中的类型不能省略,右侧<>中的类型可以省略,不用写类型,但是<>不能省略

MyArray<String> m = new MyArray<>(10);

(2)泛型类的使用—通配符

1.定义:?用于在泛型的使用,即为通配符。

2.代码示例:

public class MyArray<E> {...}
// 可以传入任意类型的 MyArray
public static void printAll(MyArray<?> m) {
   ...
}
// 以下调用都是正确的
printAll(new MyArray<String>());
printAll(new MyArray<Integer>());
printAll(new MyArray<Double>());
printAll(new MyArray<Number>());
printAll(new MyArray<Object>());

3.通配符—上界

语法:

<? extends 上界>

代码示例:

// 传入类型实参是 Animal 子类的任意类型的 MyArray
public static void printAll(MyArray<? extends Animal> m) {
   ...
}
// 以下调用都是正确的
printAll(new MyArray<Cat>());
printAll(new MyArray<Dog>());
// 以下调用是编译错误的
printAll(new MyArray<String>());
printAll(new MyArray<object>());

4.通配符—下界

语法:

<? super 下界>

代码示例:

// 可以传入类型实参是 Cat 父类的任意类型的 MyArray
public static void printAll(MyArray<? super Cat> list) {
   ...
}
// 以下调用都是正确的
printAll(new MyArrayList<Cat>());
printAll(new MyArrayList<Animal>());
printAll(new MyArrayList<Object>());
// 以下调用是编译错误的
printAll(new MyArrayList<String>());
printAll(new MyArrayList<Dog>());

(3)泛型中的父子类型(需要使用通配符<?>来确定父子类型)

1.MyArray<Object>不是 MyArray<Animal >的父类型

2. MyArray<Animal > 也不是 MyArray <Cat>的父类型

4. MyArray<?> 是 MyArray<?extends Animal> 的父类型

5.MyArray<? extends Animal> 是 MyArrayList<Dog> 的父类型

三:泛型方法

(1)语法格式:

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

(2)代码示例:

public class Util {
    public static <E> void swap(E[] array, int i, int j) {
        E t = array[i];
        array[i] = array[j];
        array[j] = t;
   }
}
// 没有显式指定类型,编译期间需要进行类型推到
Integer[] a = { ... };
swap(a, 0, 9);
String[] b = { ... };
swap(b, 0, 9);
// 显式指定类型,编译期间,不用进行类型推导
Integer[] a = { ... };
Util.<Integer>swap(a, 0, 9);
String[] b = { ... };
Util.<String>swap(b, 0, 9);

四:泛型的优缺点

(1)优点:

1. 提高代码的复用性

2. 提高开发效率

3. 可以实现一些通用类型的容器或算法

(2)缺点:

1. 泛型类型参数不支持基本数据类型

2. 无法实例化泛型类型的对象

3. 无法使用泛型类型声明静态的属性

4. 无法使用 instanceof 判断带类型参数的泛型类型

5. 无法创建泛型类数组

6. 无法 create、catch、throw 一个泛型类异常(异常不支持泛型)

7. 泛型类型不是形参一部分,无法重载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值