其他分享
首页 > 其他分享> > 三十四、泛型

三十四、泛型

作者:互联网

1、概述

1.1 泛型含义

泛型是一种类型参数,专门用来保存类型用的

最早接触泛型是在ArrayList,这个 E 就是所谓的泛型了。使用ArrayList时,只要给 E 指定某一个类型,里面所有用到泛型的地方都会被指定对应的类型。

ArrayList<String> list1 = new ArrayList<>();    // E = String

ArrayList<Integer> list2 = new ArrayList<>();    // E = Integer

ArrayList list3 = new ArrayList<>();      // E = Object
如果没有给泛型变量设定一个类型,默认表示Object。

1.2 使用泛型的好处

不用泛型带来的问题:

集合若不指定泛型,默认就是Object。存储的元素类型自动提升为Object类型。获取元素时得到的都是Object。若要调用特有方法需要转型,给我们编程带来麻烦。

使用泛型带来的好处:

  1. 将运行时期的 Exception,转移到了编译时期的编译失败。
  2. 避免了类型强转的麻烦
// 泛型没有指定类型,默认是Object
ArrayList arr = new ArrayList();

arr.add("Hello");
arr.add("World");
arr.add(100);
arr.add(false);

// 集合中的数据就比较混乱,会给获取数据带来麻烦
for (Object o : arr) {
    String str = (String)o;

    // 当遍历到非String类数据,就会报异常
    // java.lang.ClassCastException
    System.out.println(str);
}

1.3 注意

  1. 泛型的代码在运行的时,泛型会被擦除。后面学习反射的饿时候,可以实现在代码运行的过程中添加其他类型的数据到集合
  2. 泛型里面只能放引用数据类型

2、泛型的定义和使用

泛型,用来灵活的将数据类型应用到不同的类、接口、方法中。将数据类型作为参数进行传递。

2.1 自定义泛型类

使用场景:

当一个类中定义属性的时候,不确定属性具有什么类型时,就可以使用泛型表示该属性的类型

定义格式:

在类型名后面加上一对尖括号,里面定义泛型,一般使用一个英文大写字母表示,如果有多个泛型,使用逗号分隔。

权限修饰符 class 类名<泛型名>{
    类型内部,就可以把泛型名当做是某一种类型使用了。
}

public class Student<X,Y>{
    X xObj;
}

泛型的确认:

在创建对象的时候,确认泛型类中泛型的数据类型

ArrayList<String> list = new ArrayList<>();

2.2 自定义泛型接口

使用场景:

当定义接口时,内部方法中其参数类型,返回值类型不确定时,就可以使用泛型替代了。

定义格式:

权限修饰符 interface 接口名<泛型名>{
    类型内部,就可以把泛型名当做是某一种类型使用了。
}

public interface Collection<E>{
    public boolean add(E e);
}

泛型的确认:

  1. 可以在实现类实现接口时,确认接口中的泛型的类型

    public class MyImp1 implements MyGenericInterface<String> {
    	@Override
        public void add(String e) {
            // 省略...
        }
    
    	@Override
    	public String getE() {
    		return null;
    	}
    }
    
  2. 如果实现类和接口不指定具体的类型,继续使用泛型指定,那就变成含有泛型的类使用

    public class MyImp2<E> implements MyGenericInterface<E> {
    	@Override
    	public void add(E e) {
           	 // 省略...
    	}
    
    	@Override
    	public E getE() {
    		return null;
    	}
    }
    
    /*
     * 使用
     */
    public class GenericInterface {
        public static void main(String[] args) {
            MyImp2<String>  my = new MyImp2<String>();  
            my.add("aa");
        }
    }
    

2.3 自定义泛型方法

使用场景:

当定义方法时,方法中参数类型,返回值类型不确定时,就可以使用泛型替代了

定义格式:

可以在方法的返回值类型前,加上泛型

权限修饰符 <泛型名> 返回值类型 方法名(参数列表){
    ....
} 

public interface Collection<E> extends Iterable<E>{
    ...
    <T> T[] toArray(T[] a);     //将集合变成数组
}

泛型的指定:

调用含有泛型的方法时,传入的数据其类型就是泛型的类型

3、泛型通配符

当我们对泛型的类型确定不了,而想要表达的可以是任意类型,可以使用泛型通配符给定。符号就是一个问号: 表示任意类型,用来给泛型指定的一种通配值。

3.1 通配符基本使用

泛型通配符搭配集合使用一般在方法的参数中比较常见

方法中的参数是一个集合,集合如果携带了通配符,要特别注意如下:

  1. 集合的类型会提升为Object类型
  2. 方法中的参数是一个集合,集合如果携带了通配符,那么此集合不能进行添加和修改操作,可以删除和获取。
public static void main(String[] args) {
    ArrayList<Number>  list1 = new ArrayList<>();
    ArrayList<Object>  list2 = new ArrayList<>();
    ArrayList<String>  list3 = new ArrayList<>();
    ArrayList<Integer> list4 = new ArrayList<>();
    
    // ... 添加数据
    
    useList3(list1);
    useList3(list2);
    useList3(list3);
    useList3(list4);
}
// 方法的参数是一个List , 泛型为通配符 , 那么此参数可以接收任意类型泛型的List集合
public static void useList3(ArrayList<?> list){
    // 方法中的参数是一个集合,集合如果携带了通配符 , 集合中的元素默认是Object类型
    // Object o = list.get(0);

    // 方法中的参数是一个集合,集合如果携带了通配符 , 那么此集合不能进行添加和修改操作 , 可以删除和获取
    // list.add(new Object());
    // list.add("");
    // list.add(10);
    // list.set(0 , "");

    System.out.println(list);
    list.remove(1);
    Object o = list.get(1);
}

3.2 受限泛型

介绍:

受限泛型是指,在使用通配符的过程中,对泛型做了约束,给泛型指定类型时,只能是某个类型父类型或者子类型。

<? super 类型> :只能是某一类型,及其父类型,其他类型不支持

<? extends 类型> : 只能是某一类型,及其子类型,其他类型不支持

【代码体现】
public static void main(String[] args) {
    Collection<Integer> list1 = new ArrayList<Integer>();
    Collection<String> list2 = new ArrayList<String>();
    Collection<Number> list3 = new ArrayList<Number>();
    Collection<Object> list4 = new ArrayList<Object>();
    
    getElement1(list1);
    getElement1(list2);//报错
    getElement1(list3);
    getElement1(list4);//报错
  
    getElement2(list1);//报错
    getElement2(list2);//报错
    getElement2(list3);
    getElement2(list4);
}
// 泛型的上限:此时的泛型?,必须是Number类型或者Number类型的子类
public static void getElement1(Collection<? extends Number> coll){}
// 泛型的下限:此时的泛型?,必须是Number类型或者Number类型的父类
public static void getElement2(Collection<? super Number> coll){}

泛型没有继承说法案例:

标签:ArrayList,Object,类型,三十四,泛型,new,public
来源: https://www.cnblogs.com/6ovo6/p/14940760.html