泛型:
类型参数化,解决不确定对象类型的问题。好处是代码复用性高。
作用范围:
类,方法,接口。 编译器通过识别尖括号内的字母来解析泛型。
约定俗成的泛型名: E (Element 集合中元素) , T (the Type of Object)某个类。
应用举例:
在没有使用泛型前:
//未使用 泛型,会出现强制类型转换报错风险
public static Object heap (Object food)
{
System.out.println(food + "is done");
return food;
}
public static void main(String[] args) {
// 加热肉
Meat meat = new Meat();
Meat me = (Meat)Stove.heap(meat);
// 加热汤
Soup soup = new Soup();
Soup soup = (Soup)Stove.heap(soup);
}
这里用 Object 来避免为每种食物都写一种加热的方法,但根据墨菲定律,会发生强制类型转换的危险。
使用泛型:
public static T heap (T food)
{
System.out.println(food + "is done");
return food;
}
public static void main(String[] args) {
// 加热肉
Meat meat = new Meat();
Meat me = Stove.heap(meat);
// 加热汤
Soup soup = new Soup();
Soup soup = Stove.heap(soup);
}
好处:不会出现类型转换的错误,代码复用性高。
泛型与集合的联合使用:
List, List , List<?> 这三个对象有啥区别?直接看代码:
public static void main(String[] args)
{
// 1 无泛型约束
List a1 = new ArrayList<>();
a1.add(new Integer(1));
a1.add(new Object());
a1.add("hello");
//将 a1 的引用赋值给 a2 , 但是在接受其他泛型赋值时会出现编译错误
List<Object> a2 = a1;
a2.add(new Integer(1));
a2.add(new Object());
a2.add("hello");
//将 a1 的引用赋值给 a3
List<Integer> a3 = a1;
a3.add(new Integer(1));
a3.add(new Object());
a3.add("hello");
//将 a1 的引用赋值给 a4
List<?>a4 = a1;
a4.add(new Object());
a4.remove(2);
a4.clear();
}
第一段,因为不存在类型约束,所以向集合内添加任何对象都不会报错。
第二段,泛型是 Object ,也可以添加任何类型的对象,但唯一的区别是在进行类型转化时会报错的风险。
第三段,泛型是 Integer, 此时就有了约束,不是 Integer 类型的就无法成功添加其中
第四段, 添加通配符,只能进行 删除和清理操作,不能进行添加操作。
我们可以发现,这几种用法只能添加一种泛型约束,那有没有添加多种泛型约束呢?
List<? extend> 与 List<? super> 的区别:
创建三个类,动物,狗,柯基。(柯基继承狗,狗继承动物):
List<Animal> animal = new ArrayList<>();
List<Dog> dog = new ArrayList<>();
List<keji>kj = new ArrayList<>();
animal.add(new Animal());
dog.add(new Dog());
kj.add(new keji());
// 只能赋值给 Dog 和子类(keji),所以此时会报错
List<? extends Dog>extendsDogFromAnimal = animal;
//只能赋值给 Dog 和父类
List<? super Dog> superDogFromAnimal = animal;
// 不能添加任何元素,会报错
extendsDogFromAnimal.add(new Dog());
// 可以添加元素
superDogFromAnimal .add(new Dog());
// 类型丢失,只能返回 对象类型
Object ob = superDogFromAnimal.get(0);
//返回类型不会擦除,子类对象被擦除
Dog do = extendsDogFromAnimal.get(0);
通过上面的代码可以发现,
List<?extends T>只能赋值给 自己和子类,上限是 T,不能添加元素,能返回父类和本类对象,但子类对象会被擦除。
List<? super T> 只能赋值自己和父类,下限是 T , 能添加元素,能返回 Object 类型的元素。
应用场景:
使用 <? extend T> 是 put 的功能受限,<? super T>是 get , 功能受限。
进行匿名投票时,向箱子里投票,在想拿出来时就会被告知 “”您以参与投票!“”,而这里就可以是使用 <? super T>
还可以拿上面的例子来说明 <?extend T> 适合放数据,<? super T>适合拿数据。
场景一: 当我们想放进一只狗时,你会向哪个箱子选择,是 动物箱子,还是狗箱子,抑或是 柯基箱子?
场景二: 当我们想拿出一只动物时,你会向哪个箱子选择,是 动物箱子,还是狗箱子,抑或是 柯基箱子?
总结:
花了些许的时间,介绍了 泛型,以及泛型和集合的联合使用。看了一位大佬的视屏说如果你想提高编程能力,使代码更富有条理性,利用 java 的泛型和反射 API 是最好的办法。