关于泛型,掌握以下几点就够了
1,如何理解?
1,它是参数化类型,jdk1.5就推出了,如List,Map<K,V>,可以简单理解为形参。
2,它是编译时的一种类型,仅在编译阶段有效,比如List在运行时String会被擦除,系统会认定为Object。
2,为何使用?
它是进行类型设计或方法定义时的一种约束规范基于此规范可以:
1,提高编程时的灵活性(结合下面示例代码理解)
2,提高程序运行时的性能(在编译阶段解决一些运行时需要注意的点,例如类型强转)
注:泛型应用相对简单,难点在于利用泛型设计类和方法,通过这样的设计如何对现有的类进行“减法设计”,提高类或方法的通用性
3,应用类型?
1,常用定义方式:
a,泛型类:class A{}
b,泛型接口:inteface B{}
c,泛型方法:public T method(T t){} //方法的返回值左侧一定要有一个泛型,代码如下:
package com.amdr.java.generic;
import java.util.Collection;
import java.util.Date;
import java.util.List;
class ObjectFactory{
//泛型方法,基于字节码对象构建类的实例对象
public <T>T newInstance(Class<T> cls) throws Exception {
return cls.newInstance();
}
//判断一个对象是否是Collection类型
public <T>Boolean isCollection(Class<T> cls){
return Collection.class.isAssignableFrom(cls);
}
}
/**
* @Description 泛型方法测试
* @Author Amdr
* @Date 2023/10/9
*/
public class TestGeneric02 {
public static void main(String[] args) throws Exception {
ObjectFactory objectFactory = new ObjectFactory();
Date date = objectFactory.newInstance(Date.class);
Boolean b = objectFactory.isCollection(List.class);
System.out.println(date);//Mon Oct 09 15:30:42 CST 2023
System.out.println(b);//true
}
}
注:泛型类和泛型接口不能作用于静态方法
,如下写法是错误的!
class A<T> {
static void a(T t){
}
}
eg:分析如下代码,是否有问题?【笔试高频出现】
//类
class A<T>{}
class B extends A<T>{} //错误写法
class C<T> extends A<T>{} //正确写法
class D extends A<String>{} //正确写法
//接口
interface A<K,V>{}
class B implements A<K,V> //错误写法
class C<K,V> implements A<K,V> //正确写法
class D implements A<String,Object> //正确写法
class B<K> implements A<K,String> //正确写法
//
List<Object> list = new ArrayList<String>();//错误
List<? extends Object> list = new ArrayList<String>();//正确
List<> list = new ArrayList<Object>();//错误
List<? super String> list = new ArrayList<Object>();//正确
4,通配符“?”如何理解?
它是一种通用的类型,泛指一种不确定行类型,可以代表任意一种参数类型(实参),但是它只能应用于变量的定义,如:Class<?> cls;
package com.amdr.java.generic;
import java.util.ArrayList;
import java.util.List;
/**
* @Description 测试泛型通配符“?”语法
* @Author Amdr
* @Date 2023/10/9
*/
public class TestGeneric03 {
public static void main(String[] args) throws ClassNotFoundException {
Class<Object> c1 = Object.class;
//Class<Object> c2 = Class.forName("java.lang.Object"); //编译不通过只能写通配符
Class<?> c2 = Class.forName("java.lang.Object");
Class<?> c3 = String.class;
Class<?> c4 = Integer.class;
//List<?> list = new ArrayList<?>();//编译报错
List<?> list1 = new ArrayList<>();
List<?> list2 = new ArrayList<String>();
//如何对问号的值进行约束?可使用限定通配符
}
}
5,上下界问题?
一般应用于:方法参数变量的定义
,方法返回值类型的定义
。
上边界:?extends E
下边界:?super E
6,类型擦除?
仅在编译阶段有效,比如List在运行时String会被擦除,系统会认定为Object。
代码示例:
package com.amdr.java.generic;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
/**
* @Description 演示类型擦除机制
* @Author Amdr
* @Date 2023/10/9
*/
public class TestGeneric04 {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
List<String> list = new ArrayList<>();//虽然使用了String约束了List,但只是在编译期生效,运行时会统一转换为Object
list.add("sad");
//list.add(213); //编译报错可利用反射在运行时将213这个整数存储到集合中去
//1,获取List字节码对象
Class<? extends List> listClass = list.getClass();
//2,基于字节码对象获取方法对象
/**
* List.class 中的add方法为boolean add(E var1);
* 该方法为泛型参数,此时会触发泛型类型擦除,转化为Object类型
* 故getMethod方法第二个参数为Object.class
*/
Method method = listClass.getMethod("add",Object.class);
//执行list对象的add方法对象,放入213
method.invoke(list,213);
System.out.println(list);//[sad, 213] 可见数字类型也已成功放入
//根据以上结果,如果想将200添加到‘sad’前面去该怎么实现?去拿add(int index, A element)方法,第一个参数为指定位置,第二个参数是要添加的元素
Method methodNew = listClass.getMethod("add",int.class,Object.class);//最后一个参数可按需传入多个
methodNew.invoke(list,0,200);
System.out.println(list);//[200, sad, 213]可见200已经放入到最前面
}
}
以下代码片段摘自Class.class中getMethod方法
...
@CallerSensitive
public Method getMethod(String name, Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException {
Objects.requireNonNull(name);
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
this.checkMemberAccess(sm, 0, Reflection.getCallerClass(), true);
}
Method method = this.getMethod0(name, parameterTypes);
if (method == null) {
throw new NoSuchMethodException(this.methodToString(name, parameterTypes));
} else {
return getReflectionFactory().copyMethod(method);
}
}
...
注:方法参数中 'Class<?>...' 这是可变参数,它只能作为最后一个参数出现,传值的时候可将其视为数组