什么是泛型?
泛型是JDK1.5新加入的,解决数据类型的安全性问题,其主要原理是在类声明时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。这样在类声明或实例化时只要指定好需要的具体的类型即可。
为什么要有泛型?
java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生ClassCastException异常。同时,代码更加简洁、健壮。
java中的泛型只有在编译阶段有效。在编译过程中,正确检验泛型结果后,会将泛型的相关信息檫出,并且在对象和离开方法的边界处添加类型检查和类型转换的方法。也就是说,泛型信息不会进入到运行阶段。
举个例子:在利用泛型声明一个集合之后,例如List<String> list = new ArrayList<String>();在进行list.add(1);时就会提示:The method add(int, String) in the type List<String> is not applicable for the arguments (int),此时仍处于编译阶段。
怎么使用泛型?
1.泛型类
package collections; import java.util.ArrayList; import java.util.List; public class Test6 { public static void main(String[] args) { A<String> a1 = new A<String>(); //这里setKey中接受的参数为String类型,因为在实例化的时候声明了String泛型 a1.setKey("a"); System.out.println(a1.getKey()); A<Integer> a2 = new A<Integer>(); //这里setKey中接受的参数为Integer类型,因为在实例化的时候声明了Integer泛型 a2.setKey(1); System.out.println(a2.getKey()); A a3 = new A(); //假设不指定泛型,那么默认接受为Object a3.setKey(1); System.out.println(a3.getKey()); //同样的类,指定了不同的泛型,就不能进行相互赋值,比如a1=a2 } } //此处的泛型T可以任意取名,一般用T,表示Type class A<T>{ private T key; public void setKey(T key){ this.key = key; } public T getKey(){ return this.key; } }
2.泛型接口
package collections; public class Test7 { public static void main(String[] args) { Mm<Integer> mm = new Mm<Integer>(); mm.test(1); //这种情况下不能指定泛型 Mn mn = new Mn(); mn.test("a"); } } interface M<T>{ T test(T t); } //未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需要将泛型的声明也一起加入到类中 class Mm<T> implements M<T>{ @Override public T test(T t) { // TODO Auto-generated method stub return null; } } //传入实参时,则需要都修改成实参 class Mn implements M<String>{ @Override public String test(String t) { // TODO Auto-generated method stub return null; } }
3.泛型方法
package collections; public class Test8 { public static void main(String[] args) { P<Object> p = new P<Object>(); p.test("aa"); //泛型方法在调用前没有固定的数据类型 //在调用时,传入的参数是什么类型,就会把泛型改成什么类型 p.test1(1); p.test1(true); } } class P<E>{ //在类上定义的泛型,可以在普通方法中使用 private E e; public static <T> void test3(T t) { //在静态方法中不能使用类定义的泛型,如果要使用泛型,只能使用静态方法自己定义的泛型 System.out.println(t); } //无返回值的泛型 public <T> void test(T t) { } //有返回值的泛型 public <T> T test1(T s) { System.out.println(this.e); return s; } //带有可变参数方法的泛型 public <T> void test2(T... args) { for(T arg:args) { System.out.println(arg); } } }
4.通配符?
package collections; import java.util.ArrayList; import java.util.List; public class Test9 { public static void main(String[] args) { Q q = new Q(); List<String> list1 = new ArrayList<String>(); q.test(list1); List<Integer> list2 = new ArrayList<Integer>(); q.test(list2); } } class Q{ //test里面需要传递一个集合List,但是不知道List里面参数的类型 public void test(List<?> list) { } }
有限制的通配符:
- <? extends Person> [无穷小, Person] 只允许泛型为Person及Person子类的引用调用
- <? super Person> [Person, 无穷大] 只允许泛型为Person及Person父类的引用调用
- <? extends Comparable 只允许泛型为Comparable接口的实现类引用调用
package collections; import java.util.ArrayList; import java.util.List; public class Test9 { public static void main(String[] args) { Q q = new Q(); List<B1> b1 = new ArrayList<B1>(); List<C1> c1 = new ArrayList<C1>(); List<D1> d1 = new ArrayList<D1>(); //q.test1(b1);传入b1会报错 q.test1(c1); q.test1(d1); //q.test2(d1);传入d1会报错 List<M1Impl> m1Impl = new ArrayList<M1Impl>(); q.test3(m1Impl); } } class Q{ //test里面需要传递一个集合List,但是不知道List里面参数的类型 public void test(List<?> list) { } //参数的元素数据类型为C1及其子类 public void test1(List<? extends C1> list) {} //参数的元素数据类型为C1及其父类 public void test2(List<? super C1> list) {} //参数的元素数据类型为C1及其父类 public void test3(List<? extends M1> list) {} } class A1{ } class B1 extends A1{} class C1 extends B1{} class D1 extends C1{} interface M1{} class M1Impl implements M1{}