1.泛型(Generic) 和C++中的模板有些相似。
从 JDK 1 5 以后 Java 引入了 参数化类型 Parameterized type 的概念允许我们在创建集合时再指定集合元素
的类型 正如: List<String>
这表明该 List 只能保存字符串类型的对象 。
集合中使用泛型总结:
1 2 3 4 5 6 * ① 集合接口或集合类在jdk5.0 时都修改为带泛型的结构。 * ② 在实例化集合类时,可以指明具体的泛型类型 * ③ 指明完以后,在集合类或接口中凡是定义类或接口时,内部结构(比如:方法、构造器、属性等)使用到类的泛型的位置,都指定为实例化的泛型类型。 * 比如:add(E e) --->实例化以后:add(Integer e) * ④ 注意点:泛型的类型必须是类,不能是基本数据类型。需要用到基本数据类型的位置,拿包装类替换 * ⑤ 如果实例化时,没指明泛型的类型。默认类型为java.lang.Object类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 ArrayList<Integer> list = new ArrayList<Integer>(); list.add(12 ); list.add(234 ); list.add(345 ); list.add(45 ); for (Integer integer:list){ int score = integer; } Iterator<Integer> iterator = list.iterator(); while (iterator.hasNext()){ int score = iterator.next(); System.out.println(score); } -------- Map<String,Integer> map = new HashMap<String,Integer>(); map.put("tom" ,12 ); Set<Map.Entry<String,Integer>> entry = map.entrySet(); Iterator<Map.Entry<String, Integer>> iterator = entry.iterator(); while (iterator.hasNext()){ Map.Entry<String, Integer> next = iterator.next(); System.out.println(next); } -------- public class Person implements Comparable <Person > { @Override public int compareTo (Person o) { return this .name.compareTo(o.name); } }
2.如何自定义泛型结构 自定义泛型类、泛型接口、泛型方法。
泛型的主要优点是能够在编译时而不是在运行时检查错误。
泛型类的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 @Test public void test5 () { Order<String> order = new Order<>("sda" ,12 ,"dfs" ); subOrder suborder = new subOrder(); Order<String> order = new Order<>(); Integer[] arr = new Integer[]{1 ,2 ,3 }; List<Integer> list = order.copyFromArrayToList(arr); } public class Order <T > { String ordername; int orderId; T orderT; public Order () { T[] arr = (T[]) new Object[10 ]; } public Order (String ordername,int orderId,T orderT) { this .orderId = orderId; this .ordername = ordername; this .orderT = orderT; } public void show () { } public T getOrderT () { return orderT; } public void setOrderT (T orderT) { this .orderT = orderT; } public static <E> List<E> copyFromArrayToList (E[] arr) { ArrayList<E> list = new ArrayList<>(); for (E e : arr){ list.add(e); } return list; } } class subOrder extends Order <Integer > {}
3.泛型在继承方面的体现 注意泛型的继承关系:可以把ArrayList<Integer>
向上转型为List<Integer>
(T
不能变!),但不能把ArrayList<Integer>
向上转型为ArrayList<Number>
(T
不能变成父类)。
虽然类A是类B的父类,但是G 和G二者不具备子父类关系,二者是并列关系
补充:类A是类B的父类,A 是 B的父类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 @Test public void test1 () { Object obj = null ; String str = null ; obj = str; Object[] arr1 = null ; String[] arr2 = null ; arr1 = arr2; List<Object> list1 = null ; List<String> list2 = new ArrayList<String>(); show(list1); show1(list2); } public void show1 (List<String> list) {} public void show (List<Object> list) {} @Test public void test2 () { AbstractList<String> list1 = null ; List<String> list2 = null ; ArrayList<String> list3 = null ; list1 = list3; list2 = list3; List<String> list4 = new ArrayList<>(); }
4.通配符的使用 通配符:?
类A是类B的父类,G和G是没关系的,二者共同的父类是:G<?>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 @Test public void test3 () { List<Object> list1 = null ; List<String> list2 = null ; List<?> list = null ; list = list1; list = list2; List<String> list3 = new ArrayList<>(); list3.add("AA" ); list3.add("BB" ); list3.add("CC" ); list = list3; list.add(null ); Object o = list.get(0 ); System.out.println(o); } public void print (List<?> list) { Iterator<?> iterator = list.iterator(); while (iterator.hasNext()){ Object obj = iterator.next(); System.out.println(obj); } }
有限制的通配符:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 @Test public void test6 () { List<? extends Person> list1 = null ; List<? super Person> list2 = null ; List<Student> list3 = new ArrayList<>(); List<Person> list4 = new ArrayList<>(); List<Object> list5 = new ArrayList<>(); list1 = list3; list1 = list4; list2 = list4; list2 = list5; list1 = list3; Person p = list1.get(0 ); list2 = list4; Object obj = list2.get(0 ); }
5.类型擦除 详见《Java核心技术卷一》P333。
下面内容参考自廖雪峰java教程 。
泛型是一种类似”模板代码“的技术,不同语言的泛型实现方式不一定相同。
Java语言的泛型实现方式是擦拭法(Type Erasure)。
所谓擦拭法是指,虚拟机对泛型其实一无所知,所有的工作都是编译器做的。
例如,我们编写了一个泛型类Pair<T>
,这是编译器看到的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class Pair <T > { private T first; private T last; public Pair (T first, T last) { this .first = first; this .last = last; } public T getFirst () { return first; } public T getLast () { return last; } }
而虚拟机根本不知道泛型。这是虚拟机执行的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class Pair { private Object first; private Object last; public Pair (Object first, Object last) { this .first = first; this .last = last; } public Object getFirst () { return first; } public Object getLast () { return last; } }
因此,Java使用擦拭法实现泛型,导致了:
编译器把类型<T>
视为Object
;
编译器根据<T>
实现安全的强制转型。
使用泛型的时候,我们编写的代码也是编译器看到的代码:
1 2 3 Pair<String> p = new Pair<>("Hello" , "world" ); String first = p.getFirst(); String last = p.getLast();
而虚拟机执行的代码并没有泛型:
1 2 3 Pair p = new Pair("Hello" , "world" ); String first = (String) p.getFirst(); String last = (String) p.getLast();
所以,Java的泛型是由编译器在编译时实行的,编译器内部永远把所有类型T
视为Object
处理,但是,在需要转型的时候,编译器会根据T
的类型自动为我们实行安全地强制转型。