Java 泛型: T和?的使用和区别

一.定义

T表示泛型,代表一种数据类型

?是通配符,表示不确定的数据类型

jdk为了便于理解,K代表键,V代表值,E代表枚举类型,T代表数据类型,这四个都是符号,只是表示了泛型的名称,换成其他字母也没问题,只不过要提前声明。


二.使用

通常得先在类里面声明了这个泛型

方法里面的参数就可以用泛型来表示了

< T extends Record>

< ? extends Record>

表示的是 限制 T , ? 类型 必须是Record的本类或者子类

注意:继承的父类或者是实现的接口里面的参数都必须是一个具体的类型

/**
 *
 * @param <T> Report record class
 * @param <C> Report context class
 */
public abstract class CrystalReportDataPrepare<T extends Record, C extends CrystalReportContext> implements DataPrepare<C> {

    @Override
    public ReportData prepareData(C reportContext)  {
        return getCrystalReportData(reportContext);
    }

    private CrystalReportData getCrystalReportData(C reportContext) {
        CrystalReportData crystalReportData = new CrystalReportData();
        ReportParams reportParams = reportContext.getReportParams();

        crystalReportData.setRecordList(getRecordList(reportContext));
        crystalReportData.setRecordListGenericClass(getRecordListGenericClass());
        crystalReportData.setAdditionalProperties(getAdditionalProperties(reportContext));
        crystalReportData.setAsOfDate(reportContext.getAsOfDate());
        crystalReportData.setReportTitle(reportParams.getTitle());
        crystalReportData.setFileName(reportParams.getName());

        String resetCompanyName = reportContext.getCompanyName();
        if (CharSequenceUtil.isNotBlank(resetCompanyName)) {
            crystalReportData.setCompanyName(resetCompanyName);
        }

        return crystalReportData;
    }

    private Class<T> getRecordListGenericClass() {
        Class<?>[] clazzArray = GenericTypeResolver.resolveTypeArguments(this.getClass(), CrystalReportDataPrepare.class);
        if (Objects.isNull(clazzArray)) {
            return null;
        }
        return (Class<T>) clazzArray[0];
    }

    protected abstract List<T> getRecordList(C reportContext);


    protected Map<String, Object> getAdditionalProperties(C reportContext) {
        return new HashMap<>();
    }
}
public static void test(){
    List<Student> list1 = new ArrayList<>();
    list1.add(new Student("张三",18));
//这里如果add(new Teacher(...))就会报错,因为我们已经给List指定了数据类型为Student


//这里我们并没有给List指定具体的数据类型,?泛指可以存放多种类型
    List<?> list2 = new ArrayList<>();
    list2.add(new Student("李四",20));
    list2.add(new Teacher("王五",40));
}

如果有泛型方法和非泛型方法,同事都满足条件,则执行非泛型方法

public void show (String S) {
    System.out.println("非泛型show");
}

public void show (T s) {
    System.out.println("泛型show");
}

三.区别

使用场景:

<T> :声明一个泛型类或者泛型方法,代表的是某一种具体的数据类型

<?>:使用泛型类或者泛型方法(更多是使用在方法体里面),代表的是泛指所有的对象类型

public <T> List<T> getList(){
//错误,传入T的参数给ArrayList,返回的结果也应该是T类型的
    List<?> list = new ArrayList<T>();
//因为ArrayList必须是一种类型,得到的也是同一种类型
    List<?> list = new ArrayList<?>();
//正确
    List<T> list = new ArrayList<T>();

    return list;
}