1、为什么需要泛型
先举个例子:List list=new ArrayList();(list中参数是Object类型,所以可以添加任何类型的元素(子类))
则list.add(“lucy”);
list.add(1);
list.add(new Person()); 所以这个列表中就有三种不同类型的元素了,因为元素类型不同,所以他们可以执行不同的操作。每对一个元素进行一系列操作时都要使用for(int i=0;i<list.size();i++){ }判断元素的类型,才能执行不同的操作,这样会耗费大量的资源。
并且以上操作存在一些问题:当我们将一个对象放入集合中,集合不会记住此对象的类型,当再次从集合中取出此对象时,这个对象的编译类型变成了Object类型,但其运行时类型依然为其本身类型。因此,取出集合元素时需要人为的强制类型转化到具体的目标类型,且很容易出现
“java.lang.ClassCastException”异常。
那么有没有什么办法可以使集合能够记住集合内元素各类型,且能够达到只要编译时不出现问题,运行时就不会出现“java.lang.ClassCastException”异常呢?答案就是使用泛型。
2、什么是泛型
泛型(Generic),此技术的最大特点是类中的属性的类型可以由外部决定。泛型,即“参数化类型”。通俗的讲,就是讲类型变成参数,在使用时将其传入具体类型。
Java源码中就有许多示例,例如:
Comparator这个接口就使用了泛型。
又或者使用了泛型的列表:
3、自定义泛型接口、泛型类
用法示例:
public class Demo {
private static Object Demo;
public static void main(String[] args) {
person1<String> p =new person1<String>();
System.out.println(p.play("张飞"));
}
}
class person1<T>
{
T name;
int age;
public person1() {
}
public person1(T name, int age) {
this.name = name;
this.age = age;
}
public T getName()
{
return name;
}
}
interface play<T>
{
public T play();
}
运行结果:
张飞
4、通配符
问题:
person1<Number> a1 = new person1<Number>(); person1<Integer> a2 = new person1<Integer>(); a1=a2;
此时发现转换异常,虽然Integer是Number的子类,但是此时不能转换。
public static void getData(Node<Number> data) {
System.out.println("data :" + data.getData());
}
此时,我们可以使用通配符来解决
“?”表示的是可以接收任意的泛型类型,但是只是接收输出,并不能修改。
public static void getData(Node<?> data) {
System.out.println("data :" + data.getData());
}
<?>只提供了一个只读的功能,它去除了增加具体元素的能力,只保留与具体类型无关的功能。
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.*;
public class Demo {
private static Object Demo;
public static void main(String[] args) {
person1<Number> p =new person1<>(10,18);
person1<Integer> p1 =new person1<>(20,18);
p.getData1(p);
p.getData1(p1);
}
}
class person1<T> implements play<T>
{
T name;
int age;
public person1() {
}
public person1(T name, int age) {
this.name = name;
this.age = age;
}
public void setName(T name) {
this.name = name;
}
public T getName()
{
return name;
}
@Override
public T play(T name) {
return name;
}
public void getData1(person1<?> p){
System.out.println(p.name);
}
}
interface play<T>
{
public T play(T name);
}
运行结果:
10
20
5、泛型方法
泛型除了在类中定义之外,还可以在方法上定义,而且在方法上使用泛型,此方法所在的类不一定是泛型的操作类。
定义一个方法,实现任意类型数组中两个位置值的调换
public static <T> T[] func(T[] array,int i,int t){
T temp = array[i];
array[i] = array[t];
array[t] = temp;
return array;
}
6、泛型的嵌套使用
Java在Map中的entrySet实现了Set接口,里面存放的是键值对。一个K对应一个V
Set<Map.Entry<K, V>> entrySet();
传入具体类型后: Set<Map.Entry<Integer, String>> entrySet = map.entrySet();
这就属于泛型的嵌套使用。