泛型
泛型:泛型是Java SE 1.5的新特性,本质就是参数化类型,它的最简单的理解就是原本我们在使用一个类或者方法的时候需要提前确定好类或者方法的返回值类型或者参数类型,有了泛型这个语法之后,你就可以在使用的时候再通过像传参一样把类型传过来,实现动态的修改类型,这样我们就可以减少很多重载的方法,做到一个方法,可以有不同类型的参数,不同的返回值类型。减少代码的编写。
泛型的应用可以是在类上、接口上、方法上,分别被称为泛型类、泛型接口、泛型方法。我们常见的应用就是在集合中。
泛型类
public class Person<T> { private String name; private T zhiwei; }
泛型接口
public interface Map<K, V> { public void put(K key, V value); public V get(K key); } 当声明或者实例化一个泛型的对象时,必须指定类型参数的值: Map<String, String> map = newHashMap<String, String>();
泛型方法
public <T> void f(T x){ System.out.println(x.getClass().getName()); }
常见问题
1、泛型的擦除
package generics; import java.util.*; public class ErasedTypeEquivalence { public static void main(String[] args) { Class c1 = new ArrayList<String>().getClass(); Class c2 = new ArrayList<Integer>().getClass(); System.out.println(c1 == c2); } } /* * Output: true */// :~
虽然我们使用了泛型,但在ArrayList内部是没有显示的,他们两个在本质上还是同一个数据类型
2、可以创建泛型数组吗?相应的应用场景怎么处理?
package generics; public class Erased<T> { private final int SIZE = 100; public static void f(Object arg) { if (arg instanceof T) { } // Cannot make a static reference to the non-static type T T var = new T(); // Error T[] array = new T[SIZE]; // Error T[] array = (T) new Object[SIZE]; // Unchecked warning } } /// :~
我们无法直接创建泛型数组,不过可以先定义一个Object数组,再强制类型转换
3、我们无法在静态方法中使用泛型,因为此时泛型的参数还没构建,要想在静态方法中使用泛型,我们的静态方法也必须是泛型方法。
泛型中的通配符
泛型中的通配符是英文的 ? 。
通配符的作用是解决当泛型类或泛型接口作为参数类型传递给方法调用时,不确定泛型的类型时做统一处理的。
即:可以解决当具体类型不确定的时候,这个通配符就是 ? ;当操作类型时,不需要使用类型的具体功能时,只使用Object类中的功能。那么可以用 ? 通配符来表未知类型,比如遍历,然后给对象的属性赋值。
例如:
List<Integer> list1 = new ArrayList<Integer> List<String> list2 = new ArrayList<String> list2不能把值赋给list1 当我们在遍历集合的时候就不必为每一种泛型的集合创建一个迭代器了,可以通用一个去解决了 public void print(List<?> list){ Iterator<?> it = list.iterator(); where(it.hasNext()){ Object obj = iterator.next(); System.out.println(obj); } }
通配符的上下边界
表示泛型里面的T的类型要在Number的上面,要是Number或者Number的父类 public class Generic<T super Number>{ private T key; public Generic(T key) { this.key = key; } public T getKey(){ return key; } } 表示泛型里面的T的类型要在Number的下面,要是Number或者Number的子类 public class Generic<T extends Number>{ private T key; public Generic(T key) { this.key = key; } public T getKey(){ return key; } }