对泛型的全面认识
【1】什么是泛型(Generic):
泛型就相当于标签
形式:<>
集合容器类在设计阶段/声明阶段不能确定这个容器到底实际存的是什么类型的对象,所以在JDK1.5之前只能把元素类型设计为Object,
JDK1.5之 后使用泛型来解决。因为这个时候除了元素的类型不确定,其他的部分是确定的,例如关于这个元素如何保存,如何管理等是确定的,因此此时把元素的类型设计成一个参数,这个类型参数叫做泛型。
Collection, List, ArrayList 这个就是类型参数,即泛型。
【2】泛型类和接口
类的定义和实例化
package com.test02;
/**
* GenericTes就是一个普通的类
* GenericTest<E> 就是一个泛型类
* <>里面就是一个参数类型,但是这个类型是什么呢?这个类型现在是不确定的,相当于一个占位
* 但是现在确定的是这个类型一定是一个引用数据类型,而不是基本数据类型
*/
public class GenericTest<E> {
int age;
String name;
E sex;
public void a(E n){
}
public void b(E[] m){
}
}
class Test{
//这是main方法,程序的入口
public static void main(String[] args) {
//GenericTest进行实例化:
//(1)实例化的时候不指定泛型:如果实例化的时候不明确的指定类的泛型,那么认为此泛型为Object类型
GenericTest gt1 = new GenericTest();
gt1.a("abc");
gt1.a(17);
gt1.a(9.8);
gt1.b(new String[]{"a","b","c"});
//(2)实例化的时候指定泛型:---》推荐方式
GenericTest<String> gt2 = new GenericTest<>();
gt2.sex = "男";
gt2.a("abc");
gt2.b(new String[]{"a","b","c"});
}
}
继承情况
1.父类指定泛型
class SubGenericTest extends GenericTest<Integer>{
}
class Demo{
//这是main方法,程序的入口
public static void main(String[] args) {
//指定父类泛型,那么子类就不需要再指定泛型了,可以直接使用
SubGenericTest sgt = new SubGenericTest();
sgt.a(19);
}
}
2.父类不指定泛型
如果父类不指定泛型,那么子类也会变成一个泛型类,那这个E的类型可以在创建子类对象的时候确定:
class SubGenericTest2<E> extends GenericTest<E>{
}
class Demo2{
//这是main方法,程序的入口
public static void main(String[] args) {
SubGenericTest2<String> s = new SubGenericTest2<>();
s.a("abc");
s.sex = "女";
}
}
运用泛型类须注意的几点:
(1)泛型类可以定义多个参数类型
(2)不同的泛型的引用类型不可以相互赋值
(3)泛型如果不指定,那么就会被擦除,反应对应的类型为Object类型
(4)反省类中的静态方法不能使用类的泛型
(5)不能直接使用E[]的创建:
public void Set(A a,B b,C c){
//不能为A[] i=new A[10];
A[] i=(A[])new Object[10];
}
【3】泛型方法
package com.test04;
/**
* 1.什么是泛型方法:
* 不是带泛型的方法就是泛型方法
* 泛型方法有要求:这个方法的泛型的参数类型要和当前的类的泛型无关
* 换个角度:
* 泛型方法对应的那个泛型参数类型 和 当前所在的这个类 是否是泛型类,泛型是啥 无关
* 2.泛型方法定义的时候,前面要加上<T>
* 原因:如果不加的话,会把T当做一种数据类型,然而代码中没有T类型那么就会报错
* 3.T的类型是在调用方法的时候确定的
* 4.泛型方法可否是静态方法?可以是静态方法
*/
public class TestGeneric<E> {
//不是泛型方法 (不能是静态方法)
public static void a(E e){
}
//是泛型方法
public static <T> void b(T t){
}
}
class Demo{
//这是main方法,程序的入口
public static void main(String[] args) {
TestGeneric<String> tg = new TestGeneric<>();
tg.a("abc");
tg.b("abc");
tg.b(19);
tg.b(true);
}
}
【4】通配符
在没有通配符的时候:
下面的a方法,相当于方法的重复定义,报错
public class Test {
/*public void a(List<Object> list){
}
public void a(List<String> list){
}
public void a(List<Integer> list){
}*/
}
引入通配符后
public class Demo {
//这是main方法,程序的入口
public static void main(String[] args) {
List<Object> list1 = new ArrayList<>();
List<String> list2 = new ArrayList<>();
List<Integer> list3 = new ArrayList<>();
List<?> list = null;
list = list1;
list = list2;
list = list3;
}
}
//发现: A 和 B是子类父类的关系,
//G<A>和G<B>不存在子类父类关系,是并列的
//加入通配符?后,G<?>就变成了 G<A>和G<B>的父类
使用通配符:
package com.test06;
import java.util.ArrayList;
import java.util.List;
public class Test {
/*public void a(List<Object> list){
}
public void a(List<String> list){
}
public void a(List<Integer> list){
}*/
public void a(List<?> list){
//内部遍历的时候用Object即可,不用?
for(Object a:list){
System.out.println(a);
}
}
}
class T{
//这是main方法,程序的入口
public static void main(String[] args) {
Test t = new Test();
t.a(new ArrayList<Integer>());
t.a(new ArrayList<String>());
t.a(new ArrayList<Object>());
}
}