1 基本概述
- 泛型的本质就是”参数化类型”。一提到参数,最熟悉的就是定义方法的时候需要形参,调用方法的时候,需要传递实参。那”参数化类型”就是将原来具体的类型参数化
泛型的出现避免了强转的操作,在编译器完成类型转化,也就避免了运行的错误。
2 泛型的目的
Java泛型也是一种语法糖,在编译阶段完成类型的转换的工作,避免在运行时强制类型转换而出现ClassCastException,类型转化异常。
3、实例随着JDK 1.5时 增加了泛型
3.1、不使用泛型
public static void main(String[] args){
List list = new ArrayList();
list.add(11);
list.add("哈哈");
for (int i = 0 ; i < list.size(); i++) {
System.out.println((String)list.get(i));
}
}
运行结果:
因为list类型是Object。所以int,String类型的数据都是可以放入的,也是都可以取出的。但是上述的代码,运行的时候就会抛出类型转化异常.
3.2、使用泛型
public static void main(String[] args){
List<String> list = new ArrayList();
list.add(11);
list.add("哈哈");
for(int i = 0;i<list.size();i++){
Systerm.out.println((String)list.get(i));
}
}
从代码中看出,集合只能添加String类型的。
4、泛型的三种使用
4.1、泛型类
public class 类名 <泛型类型1,...> {
}
泛型类型必须是引用类型(非基本数据类型)
4.2、泛型方法
public <泛型类型> 返回类型 方法名(泛型类型 变量名) {
}
注意要点:
方法声明中定义的形参只能在该方法里使用,而接口、类声明中定义的类型形参则可以在整个接口、类中使用。当调用fun()方法时,根据传入的实际对象,编译器就会判断出类型形参T所代表的实际类型。 ```java public class FanDemo {
//定义方法 public
T fun(T t){ // 可以接收任意类型的数据
return t; // 直接把参数返回
}public static void main(String[] args) { FanDemo f = new FanDemo(); String str = f.fun(“嘿嘿”); System.out.println(str); int i = f.fun(10); System.out.println(i); }
}
<a name="GAqC9"></a>
#### 4.3、泛型接口
```java
public interface 接口名<泛型类型> {
}
实例:
E一般用来表示集合类型中的元素的类型,例如List接口的定义,public interface List
- E——Element 表示元素 特性是一种枚举
- T——Type 类,是指Java类型
- K—— Key 键
- V——Value 值
?——在使用中表示不确定类型
/**
* 泛型接口的定义格式: 修饰符 interface 接口名<数据类型> {}
*/
public interface Inter<T> {
public abstract void show(T t) ;
}
public class InterImpl<E> implements Inter<E> {
@Override
public void show(E e) {
System.out.println(e);
}
public static void main(String[] args) {
Inter<String> inter = new InterImpl<String>();
inter.show("hello");
}
}
4.4、源码中泛型的使用,List接口和ArrayList类的代码片段
//定义接口时指定了一个类型形参,该形参名为E
public interface List<E> extends Collection<E> {
//在该接口里,E可以作为类型使用
public E get(int index) {}
public void add(E e) {}
}
//定义类时指定了一个类型形参,该形参名为E
public class ArrayList<E> extends AbstractList<E> implements List<E> {
//在该类里,E可以作为类型使用
public void set(E e) {
.......................
}
}
5、高级通配符
5.1、上界通配符
<? extends T>表示的是类型的上界【包含自身】,因此通配的参数化类型可能是T或T的子类。
它表示集合中的所有元素都是Animal类型或者其子类
List<? extends Animal>
这就是所谓的上限通配符,使用关键字extends来实现,实例化时,指定类型实参只能是extends后类型的子类或其本身。
这样就确定集合中元素的类型,虽然不确定具体的类型,但最起码知道其父类。然后进行其他操作。
//Cat是其子类
List<? extends Animal> list = new ArrayList<Cat>();
5.2、下界通配符
下界通配符<? super T>表示的是参数化类型是T的超类型(包含自身),层层至上,直至Object
它表示集合中的所有元素都是Cat类型或者其父类
List <? super Cat>
这就是所谓的下限通配符,使用关键字super来实现,实例化时,指定类型实参只能是extends后类型的子类或其本身
//Animal是其父类
List<? super Cat> list = new ArrayList<Animal>();
5.3、无界通配符
- 任意类型,如果没有明确,那么就是Object以及任意的Java类了
- 无界通配符用<?>表示,?代表了任何的一种类型,能代表任何一种类型的只有null(Object本身也算是一种类型,但却不能代表任何一种类型,所以List和List的含义是不同的,前者类型是Object,也就是继承树的最上层,而后者的类型完全是未知的)