泛型概念

泛型指不确定的类的类型。最常见是:

List<String> list = new ArrayList()
List<Integerr> list2 = new ArrayList()
List<User> list3 = new ArrayList()

上面 <T> 可指定List存放的类型,就是泛型。

泛型类和泛型接口

举例:ArrayList

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{

    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
	
    public E get(int index) {
        rangeCheck(index);
        checkForComodification();
        return ArrayList.this.elementData(offset + index);
    }
}

一般定义泛型类,有两个用途:

  1. 被继承。子类中指定泛型,子类使用父类的方法。举例:
public abstract class OptimizeExcelUtil<T> {
	public void importExcel(InputStream is, List<T> list) throws Exception {
		...
	}
}

public class UserServiceImpl extends OptimizeExcelUtil<<User> {
    public UserServiceImpl() {
        super(User.class);
    }
}
  1. 创建泛型类对象,指定泛型,直接使用。如ArrayList

泛型方法

先给大家看个方法:

public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

大家觉得这是泛型方法吗?不是,这是泛型类的一个带有泛型的普通方法。真正的泛型方法是下面的结构:

public <T> T beanToMap(T bean) {

}

大家看出区别没有,是不是在返回类型的前面多了个<T>?<T>没有任何功能,他仅仅表示这个方法是泛型方法,和泛型类没有任何关系,再强调一遍,泛型类没有任何关系

关键是泛型方法是可以声明为静态的。泛型里的带有泛型的方法不能声明为静态,是因为先创建对象确定类的泛型,才能确定方法的。而泛型方法和泛型类没有关系,直接调用时就指定了类型,因此是允许的。

   public static <T> Map<String, Object> beanToMap(T bean) {
        Map<String, Object> map = Maps.newHashMap();
        if (bean != null) {
            BeanMap beanMap = BeanMap.create(bean);
            for (Object key : beanMap.keySet()) {
                map.put(key+"", beanMap.get(key));
            }
        }
        return map;
    }

注意事项

  1. 异常类不能声明泛型
  2. 声明泛型的类,其静态方法不能指定任何泛型。因为泛型的指定是在创建对象时,接着才确定普通方法的泛型。而静态方法很多时候是在初始化实例前就执行了,此时没指定具体类型是不合理的

泛型和通配符的区别

泛型和通配符都是不确定的类型,但泛型指定后,类所在的方法形参和返回值类型就确定下来了,而通配符不会。比如说:

public void addList(List<?> list){

}

在外部调用的时候,泛型在指定后,多次调用都只能添加一种类型list。而通配符能允许多种。
其实各有优缺,泛型比较专注,方法内限制没那么大,而通配符很大,因为不知道传啥类型,具体方法实现很受限制