泛型的使用
前言
Github:https://github.com/HealerJean
1、泛型标识
E - Element
(在集合中使用,因为集合中存放的是元素) 以下都是表示泛型名称。换成其他字母都没关系
标识 | 代表 | 说明 |
---|---|---|
T | Type | Java 类,T 的使用,可以直接当做方法使用哦,函数里面可以对T进行操作 |
? | Type | 表示不确定的java类型 |
K | Key | 键 |
V | Value | 值 |
N | Number | 数值类型 |
1.1、泛型中<?>
和<T>
有什么区别
<T>
:的使用,可以直接当做方法使用哦,函数里面可以对T进行操作
<?>
:表示不确定的java类型
/**
* T 的使用,可以直接当做方法使用哦,函数里面可以对T进行操作
*/
public static <T> void printT(ArrayList<T> al){
Iterator<T> it = al.iterator();
while(it.hasNext())
{
T it1 = it.next();
System.out.println(it1.toString());
}
}
/**
* ? 的使用
*/
public static void printColl(ArrayList<?> al){
Iterator<?> it = al.iterator();
while(it.hasNext())
{
System.out.println(it.next().toString());
}
}
2、泛型的使用以及存在时期
2.1、泛型的简单使用List
、ArrayList
//1、可以打印
List list = new ArrayList();
list.add(1);
list.add("String");
Iterator iterator = list.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());//正常打印
}
2.2、泛型存在于编译时期
Java
中编译后的class
不会包含泛型信息,泛型只在编译阶段有效,成功编译过后的class
文件中是不包含任何泛型信息的。泛型信息不会进入到运行时阶段
private static void testEquals() {
ArrayList<String> a = new ArrayList<String>();
ArrayList b = new ArrayList();
Class c1 = a.getClass();
Class c2 = b.getClass();
System.out.println(c1 == c2); //true 表示已经经过编译了,没有任何泛型信息
System.out.println(a == b); //false
}
2.3、利用反射调用arrylist
private static void invokeMethod() {
ArrayList<String> a = new ArrayList<String>();
Class c = a.getClass();
a.add("CSDN_SEU_Cavin");
try{
Method method = c.getMethod("add",Object.class);
method.invoke(a,100);
System.out.println(a); //[CSDN_SEU_Cavin, 100]
}catch(Exception e){
e.printStackTrace();
}
}
3、自建反射对象的使用
3.1、具有泛型,T
public static class FX<T> {
private T ob; // 定义泛型成员变量
public FX(T ob) {
this.ob = ob;
}
public T getOb() {
return ob;
}
public void showTyep() {
System.out.println("T的实际类型是: " + ob.getClass().getName());
}
}
public static void main(String[] args) {
FX<Integer> intOb = new FX(100);
intOb.showTyep();
System.out.println("value = " + intOb.getOb());
System.out.println("----------------------------------");
FX<String> strOb = new FX("CSDN_SEU_Calvin");
strOb.showTyep();
System.out.println("value = " + strOb.getOb());
}
T : java.lang.Integer
value = 100
----------------------------------
T : java.lang.String
value = CSDN_SEU_Calvin
3.2
、new
的实现,没有泛型
public static class FX {
private Object ob; // 定义泛型成员变量
public FX(Object ob) {
this.ob = ob;
}
public Object getOb() {
return ob;
}
public void showTyep() {
System.out.println("T的实际类型是: " + ob.getClass().getName());
}
}
object =: java.lang.Integer
value = 100
----------------------------------
object =: java.lang.String
value = CSDN_SEU_Calvin
public static void main(String[] args) {
FX intOb = new FX(new Integer(100));
intOb.showTyep();
System.out.println("value= " + intOb.getOb());
System.out.println("----------------------------------");
FX strOb = new FX("CSDN_SEU_Calvin");
strOb.showTyep();
System.out.println("value= " + strOb.getOb());
}
4、注意事项:
4.1、确定的泛型类型,传参必须确定类型才能成功
public class ThreeMain {
public static void main(String[] args) {
FX<Number> ex_num = new FX<Number>(100);
getData(ex_num);
FX<Integer> ex_int = new FX<Integer>(200);
// getData(ex_int);//编译错误
}
//此行若把Number换为“?”或者“T” getData(ex_int);编译通过
public static void getData(FX<Number> temp) {
//do something...
}
public static class FX<T> {
private T ob;
public FX(T ob) {
this.ob = ob;
}
}
}
4.2、<? extends Number>
和<? supers Number>
<? extends Number>
:表示继承Number
的都能够使用
<? supers Number>
:表示父类以上都能够使用
public class ThreeMain {
public static void main(String[] args) {
FX<Number> ex_num = new FX<Number>(100);
getUpperNumberData(ex_num);
FX<Integer> ex_int = new FX<Integer>(200);
getUpperNumberData(ex_int);
}
public static void getUpperNumberData(FX<? extends Number> temp){
System.out.println("class type :" + temp.getClass());
}
public static class FX<T> {
private T ob;
public FX(T ob) {
this.ob = ob;
}
}
4.3、不能对确切的泛型类型使用instanceof
操作
public class FourMain {
public static void main(String[] args) {
FX<Number> ex_num = new FX<Number>(100);
FX<Integer> ex_int = new FX<Integer>(200);
// 报错,不能对确切的泛型类型使用instanceof操作。如下面的操作是非法的,编译时会出错。不确定的应该使用 ?
if(ex_num instanceof FX<Number>){
}
if(ex_num instanceof FX<?>){ //使用T也是错误的,以为T也是已知的java类型
}
}
public static class FX<T> {
private T ob;
public FX(T ob) {
this.ob = ob;
}
}
}
5、泛型的使用
5.1、DTO
@Data
@Accessors(chain = true)
public class Bean03DTO<A, N> {
private A age;
private N name;
}
@Data
@Accessors(chain = true)
public class Bean03OtherDTO<F> {
private F friend;
}
public class Bean31ParentDTO<P> {
private P parent;
}
@Data
public class Bean31SonDTO<S extends Bean31ParentDTO>{
private S son;
}
5.2、泛型使用
public class GenericService {
/**
* 1、有多少泛型,前面放多少个
*/
public static <A, N> A invokeOne(Bean03DTO<A, N> bean03DTO) {
return bean03DTO.getAge();
}
/**
* 2、有多少泛型,前面放多少个
*/
public static <A, N, F> Pair<Bean03DTO<A, N>, Bean03OtherDTO<F>> invokeTwo(Bean03DTO<A, N> dto,
Bean03OtherDTO<F> other) {
Pair<Bean03DTO<A, N>, Bean03OtherDTO<F>> pair = new Pair<>(dto, other);
return pair;
}
/**
* 3、继承中的泛型引用
*/
public static <S extends Bean31ParentDTO<String>> S invokeThree(Bean31SonDTO<S> bean31SonDTO){
return bean31SonDTO.getSon();
}
/**
* 3、继承中的泛型引用,前面放多少个
*/
public static <S extends Bean31ParentDTO<String>, A, N> S invokeThree(Bean31SonDTO<S> bean31SonDTO,
Bean03DTO<A, N> bean03DTO){
return bean31SonDTO.getSon();
}
}
@Slf4j
public class TestMain {
@Test
public void test(){
Bean03DTO<Integer, String> bean03DTO = new Bean03DTO<>();
bean03DTO.setAge(11);
bean03DTO.setName("HealerJean");
log.info("invoke:{}", GenericService.invokeOne(bean03DTO));
Bean03OtherDTO<String> bean03OtherDTO = new Bean03OtherDTO();
bean03OtherDTO.setFriend("friend");
log.info("invoke:{}", GenericService.invokeTwo(bean03DTO,bean03OtherDTO));
}
}
6、instanceof
instanceof
操作符用于判断一个引用类型所引用的对象是否是一个类的实例。
public void instanceOf(Object object) {
/**
* ==
*/
if(Long.class == object.getClass()){
System.out.println("Long.class == object.getClass()");
}
/**
* equals
*/
if(Long.class.equals(object.getClass()) ){
System.out.println("Long.class.equals(object.getClass()) ");
}
/**
* instance Of
*/
if(object instanceof Long){
System.out.println("object instanceof Long");
}
}
==
和 equals
比较的实际的 Class
类,没有考虑继承,instanceof
和 isInstance
考虑继承
class Father{}
class Son extends Father{}
public void fatherAndSon(){
Father son = new Son(); //和 Son son = new Son(); 一样
Father father = new Father();
//son.getClass() == father.getClass() :false
System.out.println("son.getClass() == father.getClass() :" +
(son.getClass() == father.getClass()) );
//son.getClass().equals(father.getClass()) :false
System.out.println("son.getClass().equals(father.getClass()) :" +
(son.getClass().equals(father.getClass())) );
//son instanceof Father :true
System.out.println("son instanceof Father :" +(son instanceof Father ));
//father instanceof Son :false //父类不能 instanceof 子类
System.out.println("father instanceof Son :" +(father instanceof Son ));
//father instanceof Father :true
System.out.println("father instanceof Father :" +(father instanceof Father ));
//son.getClass().isInstance(father):false //子类不能 isInstance 父亲
System.out.println("son.getClass().isInstance(father):"+son.getClass().isInstance(father));
//father.getClass().isInstance(son):true
System.out.println("father.getClass().isInstance(son):"+father.getClass().isInstance(son));
//son.getClass().isInstance(son)true
System.out.println("son.getClass().isInstance(son)"+son.getClass().isInstance(son));
}
@Test
public void testFatherAndSon(){
fatherAndSon();
}
7、ResolvableType
7.1、JDK
@Test
public void test() throws NoSuchFieldException {
Type genericType = D003ResolvableType.class.getDeclaredField("param").getGenericType();
ParameterizedType type = (ParameterizedType) genericType;
Type[] typeArguments = type.getActualTypeArguments();
System.out.println("从 HashMap<String, List<Integer>> 中获取 String:" +
typeArguments[0]);
// 从 HashMap<String, List<Integer>> 中获取 String:class java.lang.String
System.out.println("从 HashMap<String, List<Integer>> 中获取 List<Integer> :" +
typeArguments[1]);
// 从 HashMap<String, List<Integer>> 中获取 List<Integer> :java.util.List<java.lang.Integer>
System.out.println("从 HashMap<String, List<Integer>> 中获取 List :" +
((ParameterizedType) typeArguments[1]).getRawType());
// 从 HashMap<String, List<Integer>> 中获取 List :interface java.util.List
System.out.println("从 HashMap<String, List<Integer>> 中获取 Integer:" +
((ParameterizedType) typeArguments[1]).getActualTypeArguments()[0]);
// 从 HashMap<String, List<Integer>> 中获取 Integer:class java.lang.Integer
Field param = D003ResolvableType.class.getDeclaredField("param");
System.out.println("从 HashMap<String, List<Integer>> 中获取父类型:"+
param.getType().getGenericSuperclass());
// 从 HashMap<String, List<Integer>> 中获取父类型:java.util.AbstractMap<K, V>
}
7.2、Spring
@Test
public void test2() throws NoSuchFieldException {
ResolvableType param = ResolvableType.forField(D003ResolvableType.class.getDeclaredField("param"));
System.out.println("从 HashMap<String, List<Integer>> 中获取 String:" +
param.getGeneric(0).resolve());
// 从 HashMap<String, List<Integer>> 中获取 String:class java.lang.String
System.out.println("从 HashMap<String, List<Integer>> 中获取 List<Integer> :" +
param.getGeneric(1));
// 从 HashMap<String, List<Integer>> 中获取 List :interface java.util.List
System.out.println("从 HashMap<String, List<Integer>> 中获取 List :" +
param.getGeneric(1).resolve());
// 从 HashMap<String, List<Integer>> 中获取 List :interface java.util.List
System.out.println("从 HashMap<String, List<Integer>> 中获取 Integer:" +
param.getGeneric(1,0));
// 从 HashMap<String, List<Integer>> 中获取 Integer:java.lang.Integer
System.out.println("从 HashMap<String, List<Integer>> 中获取父类型:" +
param.getSuperType());
// 从 HashMap<String, List<Integer>> 中获取父类型:java.util.AbstractMap<java.lang.String, java.util.List<java.lang.Integer>>
}
8、获取接口中抽象的泛型
public abstract class AbstractFileTaskHandler<T extends DownloadQueryBO>
private T convertQueryParams(String queryParams) {
Type genericSuperType = getClass().getGenericSuperclass();
if (genericSuperType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) genericSuperType;
Type type = parameterizedType.getActualTypeArguments()[0];
try {
T t = JSONObject.parseObject(queryParams, type);
if (null == t) {
throw new RuntimeException("数据转换对象为空");
}
return t;
} catch (Exception e) {
UmpAlarm.alarmThrowEx("转换查询对象失败", queryParams);
}
}
return null;
}