深入理解泛型

关于泛型,掌握以下几点就够了

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

image.png

下边界:?super E

img

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<?>...' 这是可变参数,它只能作为最后一个参数出现,传值的时候可将其视为数组
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值