一.开篇
泛型是我到目前为止觉得很难啃的硬骨头之一。我一直认为学习这些东西,所花费的时间和要达到的效果短期内是不成正比的,但从长远来看,要写出好的代码,这些基础必须掌握。这也是为什么我准备花一个月的时间,再次学习Java基础的原因。
二.泛型术语
- 泛型(Generic):适应于许多许多的类型。泛型类和泛型接口统称为泛型。比喻List<E>。
- 泛型类:一个类可以适应于许多许多的类型。
- 泛型接口:一个接口可以适应于许多许多的类型。和泛型类没什么区别。
- 泛型方法:一个方法可以适应于许多许多的类型。比喻static <E> List<E> asList(E[] a)
- 原生态类型(raw type):不带任何实际类型参数的泛型名称。每一个泛型都有一个原生态类型,与List<E>相对应的原生态类型是List。
- 形式类型参数:既然一个类(或接口或方法)可以适应于许多许多的类型,那总该有一个东西来标识这个类型吧,就是形式类型参数。K键 V值 E异常 T类型 这些都是形式类型参数。
- 实际类型参数:形式类型参数的值,比喻String。
- 参数化的类型:比喻List<String>。
- 其它术语将在后文介绍。
三.泛型类和泛型方法
- 是否拥有泛型方法,与其所在的类是否是泛型没有关系。
- 泛型类里没有定义泛型方法想要的形式类型参数,泛型方法需要自己定义。
- 泛型类里定义了形式类型参数,泛型方法可以使用这些形式类型参数。
- 无论何时,只要你能做到,就应该使用泛型方法代替泛型类,缩写泛型的范围,使这个类的表达更加清楚。
- 泛型类里定义了形式类型参数,static方法不能使用这些形式类型参数,需要自己定义。
- 使用泛型类时,必须在创建对象的时候指定形式类型参数的值(即实际类型参数);而使用泛型方法的时候,通常不必指明形式类型参数的值,因为编译器会为我们找出具体的类型,这被称为“类型参数推断”。
- 类型推断只对赋值操作有效,对传递无效。编译器认为,调用泛型方法后的返回结果具体类型将由Object取代。可以通过显式的类型说明解决。
- 显式的类型说明:
- 类.<实际类型参数...>method()
- 对象.<实际类型参数...>method()
- this.<实际类型参数...>method()
四.说明例子
- 说明2356的例子
package com.jyz.study.jdk.generic; /** * Java泛型里,static方法是无法访问泛型类的形式类型参数(T)的. * 需要自己定义 * @author JoyoungZhang@gmail.com * */ public class StaticMethodGeneric<T> { // compile error, can not access T // public static T test1(T obj){ // return obj; // } //泛型类里定义了形式类型参数,static方法不能使用这些形式类型参数,需要自己定义 public static <T> T test1(T obj){ return obj; } //泛型类里定义了形式类型参数T,泛型方法可以使用这些形式类型参数 private T test2(T obj){ return obj; } //泛型类里没有定义泛型方法想要的形式类型参数TT,泛型方法需要自己定义 private <TT> TT test3(TT obj){ return obj; } public static void main(String[] args) { //使用泛型方法的时候,通常不必指明形式类型参数的值, //因为编译器会为我们找出具体的类型,这被称为“类型参数推断”。 System.out.println(StaticMethodGeneric.test1("sa")); System.out.println(StaticMethodGeneric.test1(1)); //使用泛型类时,必须在创建对象的时候指定形式类型参数的值; System.out.println(new StaticMethodGeneric<String>().test2("sa")); System.out.println(new StaticMethodGeneric<Integer>().test2(1)); } }
- 说明78的例子
package com.jyz.study.jdk.generic; import java.util.HashMap; import java.util.Map; /** * GnericMethodReturnObject * 显式的类型说明 * @author JoyoungZhang@gmail.com * */ public class ExplicitTypeSpecification { static class NewCollections1{ public static <K, V> Map<K, V> map(){ return new HashMap<K, V>(); } } class NewCollections2{ public <K, V> Map<K, V> map(){ return new HashMap<K, V>(); } } public <K, V> Map<K, V> map(){ return new HashMap<K, V>(); } static void test1(Map<Integer, String> map){ } public void main() { //compile error, NewCollections.map() return Map<Object, Object>, but test1 requried Map<Integer, String> test1(NewCollections1.map()); //compile ok. 等价于Map<Integer, String> map = NewCollections1.<Integer, String>map(); test1(NewCollections1.<Integer, String>map()); //compile error, NewCollections.map() return Map<Object, Object>, but test1 requried Map<Integer, String> test1(new NewCollections2().map()); //compile ok. 等价于Map<Integer, String> map2 = new NewCollections2().<Integer, String>map(); test1(new NewCollections2().<Integer, String>map()); //compile error, this.map() return Map<Object, Object>, but test1 requried Map<Integer, String> test1(this.map()); //compile ok. 等价于Map<Integer, String> map = this.<Integer, String>map(); test1(this.<Integer, String>map()); } }