什么是泛型
泛型其实可以理解为一种广泛的类型,啥类型都型,当然,这种泛是指定义时可以广泛,但是使用时必须确定类型。也就是说,当不清楚未来使用哪种类型时,定义为泛型。可以支持泛型类,泛型接口,泛型方法,泛型成员变量。
泛型的好处
- 泛型可以将类型作为参数进行传递,即类型可以像参数一样实现参数化。
- 泛型能提高代码的重用。
- 在编译的时候检查类型安全,把运行期的问题提前展现出来。
- 泛型中的强制转换都是自动和隐式的
下面用几个示例来表明这几种好处:
下面的代码表示的是代码重用的案例,几个传入不同类型的a都可以用泛型T表示。
public void show(int a){ System.out.println(a); } public void show(Boolean a){ System.out.println(a); } public void show(String a){ System.out.println(a); } public void show(T a){ System.out.println(a); }
下面这段代码在编译期间是不会出错的,因为集合中可以传入任何对象,但是一运行就会出错,因为后面遍历时进行强制转换为Integer,String是不能强转为Integer的。
List s = new ArrayList(); s.add(1); s.add(2); s.add("hello"); Iterator it = s.iterator(); int sum = 0; while (it.hasNext()){ Integer i = (Integer) it.next(); sum += i; }
但是由于ArrayList是泛型类,如果在定义的时候提前确定将来要存储在List中的类型,则可以提前提示出错误,这个就类似我们定义数组,刚开始就确定了数组的类型。
自动强制用的最多的地方就是在Iterator时规定了迭代的类型,所以在遍历时不用做强转工作,会自动强转。
List<Integer> s = new ArrayList(); s.add(1); s.add(2); // s.add("hello"); Iterator<Integer> it = s.iterator(); int sum = 0; while (it.hasNext()){ // Integer i = (Integer) it.next(); sum += it.next();//由于Integer中规定了类型,这里会自动强制转换 }
泛型类(Object和泛型类的区别--思考引入泛型的原因)
Object也可以代替任何类型,那Object是否可以取代泛型呢?接下来看一个示例程序:
public class Test { public static void main(String[] args) { Animal animal = new Animal(); animal.setAttr(3); Integer age = (Integer) animal.getAttr(); System.out.println(age); System.out.println("---------------------"); animal.setAttr("dog"); String kind = (String) animal.getAttr(); System.out.println(kind); System.out.println("---------------------"); animal.setAttr("kity"); Integer name = (Integer) animal.getAttr();//不按常规出牌,编译不报错 System.out.println(name); } } class Animal { private Object attr; public Animal() { } public Object getAttr() { return attr; } public void setAttr(Object attr) { this.attr = attr; } }
明显Test中最后一段设置姓名是String,但是做强转可能没搞清楚,偏偏转到Integer了,但是这个时候是不会报错的,因为编译期间Object是可以向子类Integer向下转型的。但是运行时就会报错,所以利用Object来写这种程序是不安全的。但是如果将Object替换为泛型,则会在编译期间就会报错。
上述代码,如果将Animal定义为泛型类,即将Object都替换为泛型支持,并在Animal后面加上尖括号<T>,于此同时保持测试代码不变,依然编译期间不会报错,这说明,如果不指定T的类型,默认应该还是将T换成了Object。
但是,泛型类的使用规则是需要你定义的时候就规定将来的类型的,在定义时讲T确定为Integer后,上述代码有三行编译出错。
public class Test { public static void main(String[] args) { Animal<Integer> animal = new Animal<>(); animal.setAttr(3); Integer age = (Integer) animal.getAttr(); System.out.println(age); System.out.println("---------------------"); animal.setAttr("dog");//编译不通过 String kind = (String) animal.getAttr();//编译不通过 System.out.println(kind); System.out.println("---------------------"); animal.setAttr("kity");//编译不通过 Integer name = (Integer) animal.getAttr(); System.out.println(name); } } class Animal<T> { private T attr; public Animal() { } public T getAttr() { return attr; } public void setAttr(T attr) { this.attr = attr; } }
泛型方法
泛型类有一个特点,就是需要在实例化类的时候明确泛型的类型,不然有警告(不然就是当作Object),一旦定义了,接下来类中的所有泛型的T都确定了。也就是说如果实例化的时候将T定义为String,则类中所有的T都是String,这样不是太灵活。所以引入了泛型方法。
泛型方法的定义特征:public static <T> List<T> asList(T... a)
这里用Arrays中的asList方法来举例说明,泛型方法是将以前泛型类中的<T>放到了方法返回值前面。这样asList方法以后可以接受任何类型的传参了。
ps:这篇文章对泛型方法进行了更深入的总结http://www.cnblogs.com/iyangyuan/archive/2013/04/09/3011274.html
泛型接口
泛型接口和泛型类类似,只是实现泛型接口的类一般也是继续泛型下去,如若不然,则泛型接口的灵活性就没有被突显了。
public interface Animal<T> { public abstract void show(T a); }
public class Dog<T> implements Animal<T>{ @Override public void show(T a) { System.out.println(a); } }
泛型的高级运用-通配符
1. ?: 任意类型,如果没有明确,那么就是Object以及任意的Java类了
2. ? extends E: 向下限定,E及其子类
3. ? super E: 向上限定,E极其父类
public class GenericDemo { public static void main(String[] args) { // 泛型如果明确的写的时候,前后必须一致 Collection<Object> c1 = new ArrayList<Object>(); // Collection<Object> c2 = new ArrayList<Animal>(); // Collection<Object> c3 = new ArrayList<Dog>(); // Collection<Object> c4 = new ArrayList<Cat>(); // ?表示任意的类型都是可以的 Collection<?> c5 = new ArrayList<Object>(); Collection<?> c6 = new ArrayList<Animal>(); Collection<?> c7 = new ArrayList<Dog>(); Collection<?> c8 = new ArrayList<Cat>(); // ? extends E:向下限定,E及其子类 // Collection<? extends Animal> c9 = new ArrayList<Object>(); Collection<? extends Animal> c10 = new ArrayList<Animal>(); Collection<? extends Animal> c11 = new ArrayList<Dog>(); Collection<? extends Animal> c12 = new ArrayList<Cat>(); // ? super E:向上限定,E极其父类 Collection<? super Animal> c13 = new ArrayList<Object>(); Collection<? super Animal> c14 = new ArrayList<Animal>(); // Collection<? super Animal> c15 = new ArrayList<Dog>(); // Collection<? super Animal> c16 = new ArrayList<Cat>(); } } class Animal { } class Dog extends Animal { } class Cat extends Animal { }