查看Arraylist源码可知,泛型被大量使用,一定要掌握

泛型有三种使用方式,分别为:泛型类、泛型接口、泛型方法

泛型类

泛型类型用于类的定义中,被称为泛型类。通过泛型可以完成对一组类的操作对外开放相同的接口。最典型的就是各种容器类,如:List、Set、Map。

定义的泛型类,就一定要传入泛型类型实参么?并不是这样,在使用泛型的时候如果传入泛型实参,则会根据传入的泛型实参做相应的限制,此时泛型才会起到本应起到的限制作用。如果不传入泛型类型实参的话,在泛型类中使用泛型的方法或成员变量定义的类型可以为任何的类型。

泛型接口

泛型接口与泛型类的定义及使用基本相同。泛型接口常被用在各种类的生产器中,可以看一个例子:

Test.java

package generics;
//定义一个泛型接口
public interface Test<T> {
    T next();
}

TestImpl1.java

/**
 * 未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中
 * 即:public class TestImpl1<T> implements Test<T>{
 * 如果不声明泛型,如:public class TestImpl1 implements Test<T>,编译器会报错:"Unknown class"
 */
package generics;

public class TestImpl1<T> implements Test<T>{
    @Override
    public T next() {
        return null;
    }
}

TestImpl2.java

/**
 * 传入泛型实参时:
 * 定义一个生产器实现这个接口,虽然我们只创建了一个泛型接口Test<T>
 * 但是我们可以为T传入无数个实参,形成无数种类型的Test接口。
 * 在实现类实现泛型接口时,如已将泛型类型传入实参类型,则所有使用泛型的地方都要替换成传入的实参类型
 * 即:Test<T>,public T next();中的的T都要替换成传入的String类型。
 */

package generics;

import java.util.Random;

public class TestImpl2 implements Test<String>{
    private String[] fruits = new String[]{"apple","banana","Pear"};
    @Override
    public String next() {
        Random random = new Random();
        return fruits[random.nextInt(3)];
    }
}
class Demo{
    public static void main(String[] args) {
        String str = new TestImpl2().next();
        System.out.println("str = " + str);
    }
}

java 一个方法两个泛型入参_Test

泛型方法

泛型类,是在实例化类的时候指明泛型的具体类型;泛型方法,是在调用方法的时候指明泛型的具体类型 。

package generics;

public class Methods {
    private <T> T method(Class<T> tClass) throws IllegalAccessException, InstantiationException {
        T t = tClass.newInstance();
        return t;
    }
    private <T> void method2(){
        System.out.println("sss");
    }
}

自定义泛型类(掌握)

泛型通配符(了解)

当使用泛型类或者接口时,传递的数据中,泛型类型不确定,可以通过通配符<?>表示。但是一旦使用泛型的通配符后,只能使用Object类中的共性方法,集合中元素自身方法无法使用。

通配符基本使用

类型通配符一般是使用?代替具体的类型实参,注意了,此处’?’是类型实参,而不是类型形参 。重要说三遍!此处’?’是类型实参,而不是类型形参 ! 此处’?’是类型实参,而不是类型形参 !再直白点的意思就是,此处的?和Number、String、Integer一样都是一种实际的类型,可以把?看成所有类型的父类。是一种真实的类型。

可以解决当具体类型不确定的时候,这个通配符就是 ? ;当操作类型时,不需要使用类型的具体功能时,只使用Object类中的功能。那么可以用 ? 通配符来表未知类型。

**泛型的通配符:**不知道使用什么类型来接收的时候,此时可以使用?,?表示未知通配符。

举个例子大家理解使用即可:

public static void main(String[] args) {
    Collection<Intger> list1 = new ArrayList<Integer>();
    getElement(list1);
    Collection<String> list2 = new ArrayList<String>();
    getElement(list2);
}
public static void getElement(Collection<?> coll){}
//?代表可以接收任意类型

tips:泛型不存在继承关系 Collection list = new ArrayList();这种是错误的。

通配符高级使用----受限泛型

之前设置泛型的时候,实际上是可以任意设置的,只要是类就可以设置。但是在JAVA的泛型中可以指定一个泛型的上限下限

泛型的上限

  • 格式类型名称 <? extends 类 > 对象名称例如:? extends Person :?代表的是一种类型,当前这个类型可以是Person本身,也可以是Person的子类。
  • 意义只能接收该类型及其子类

泛型的下限

  • 格式类型名称 <? super 类 > 对象名称例如: ? super Student :?代表当前的类型可以是Student类型,也可以是Student的父类类型。
  • 意义只能接收该类型及其父类型

ArrayList.java源码

/**
     * Constructs a list containing the elements of the specified
     * collection, in the order they are returned by the collection's
     * iterator.
     *
     * @param c the collection whose elements are to be placed into this list
     * @throws NullPointerException if the specified collection is null
     */
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }