Java技能树之“泛型”
泛型在java中有很重要的地位,无论是开源框架还是JDK源码都能看到它。
毫不夸张的说,泛型是通用设计上必不可少的元素,所以真正理解与正确使用泛型,是一门必修课。
一:泛型本质
Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。
泛型的本质是参数化类型,即给类型指定一个参数,然后在使用时再指定此参数具体的值,那样这个类型就可以在使用时决定了。这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。
二:为什么使用泛型
泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。
泛型类派生子类
父类派生子类的时候不能在包含类型形参,需要传入具体的类型
- 错误的方式:
public class A extends Container<K, V> {}
- 正确的方式:
public class A extends Container<Integer, String> {}
- 也可以不指定具体的类型,系统就会把K,V形参当成Object类型处理
public class A extends Container {}
2.7 高级通配符
2.7.1背景:
2.7.2 <? extends T> 上界通配符
-
上界通配符顾名思义,<? extends T>表示的是类型的上界【包含自身】,因此通配的参数化类型可能是T或T的子类。
- 正因为无法确定具体的类型是什么,add方法受限(可以添加null,因为null表示任何类型),但可以从列表中获取元素后赋值给父类型。如上图中的第一个例子,第三个add()操作会受限,原因在于List和List是List<? extends Animal>的子类型。
-
它表示集合中的所有元素都是Animal类型或者其子类 -
List<? extends Animal> -
复制代码
-
这就是所谓的上限通配符,使用关键字extends来实现,实例化时,指定类型实参只能是extends后类型的子类或其本身。
- 例如:
- 这样就确定集合中元素的类型,虽然不确定具体的类型,但最起码知道其父类。然后进行其他操作。
-
//Cat是其子类 -
List<? extends Animal> list = new ArrayList<Cat>(); -
复制代码
2.7.3 <? super T> 下界通配符
-
下界通配符<? super T>表示的是参数化类型是T的超类型(包含自身),层层至上,直至Object
- 编译器无从判断get()返回的对象的类型是什么,因此get()方法受限。但是可以进行add()方法,add()方法可以添加T类型和T类型的子类型,如第二个例子中首先添加了一个Cat类型对象,然后添加了两个Cat子类类型的对象,这种方法是可行的,但是如果添加一个Animal类型的对象,显然将继承的关系弄反了,是不可行的。
-
它表示集合中的所有元素都是Cat类型或者其父类 -
List <? super Cat> -
复制代码
-
这就是所谓的下限通配符,使用关键字super来实现,实例化时,指定类型实参只能是extends后类型的子类或其本身
- 例如
-
//Animal是其父类 -
List<? super Cat> list = new ArrayList<Animal>(); -
复制代码
2.7.4 <?> 无界通配符
- 任意类型,如果没有明确,那么就是Object以及任意的Java类了
- 无界通配符用<?>表示,?代表了任何的一种类型,能代表任何一种类型的只有null(Object本身也算是一种类型,但却不能代表任何一种类型,所以List和List的含义是不同的,前者类型是Object,也就是继承树的最上层,而后者的类型完全是未知的)
/**
*
* @param t 传入泛型的参数
* @param <T> 泛型的类型
* @return T 返回值为T类型
* 说明:
* 1)public 与 返回值中间<T>非常重要,可以理解为声明此方法为泛型方法。
* 2)只有声明了<T>的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法。
* 3)<T>表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T。
* 4)与泛型类的定义一样,此处T可以随便写为任意标识,常见的如T、E等形式的参数常用于表示泛型。
*/
public <T> T genercMethod(T t){
System.out.println(t.getClass());
System.out.println(t);
return t;
}
public static void main(String[] args) {
GenericsClassDemo<String> genericString = new GenericsClassDemo("helloGeneric"); //这里的泛型跟下面调用的泛型方法可以不一样。
String str = genericString.genercMethod("hello");//传入的是String类型,返回的也是String类型
Integer i = genericString.genercMethod(123);//传入的是Integer类型,返回的也是Integer类型
}
- 点赞
- 收藏
- 关注作者
评论(0)