Java:使用非默认构造函数实例化通用对象

时间:2017-05-09 16:27:57

标签: java generics constructor instantiation dto

在我正在进行的项目中,我必须多次创建他们的DTO中的不同对象。试图遵循不重复代码的原则,我试图创建一个像这样的通用类:

$cars->whereHas("finance", function ($query) {
   $query->where('deposit', 1000)->where('term', 48)
     ->whereBetween('payment', 50, 200);
})->where('active', 1)->get();

但是,我无法直接实例化通用对象。

我想知道,我可以用什么方法来解决这个问题。

提前致谢

2 个答案:

答案 0 :(得分:4)

你不能这样做,因为编译器和运行时都不能知道T和Tdto的具体类型,因此甚至不知道是否存在这样的构造函数。

但您可以改为Function<Tdto, T>

public List<T> tFromDto(List<Tdto> tdtoList, Function<Tdto, T> constructor){
    List<T> tList = new ArrayList<>();
    for(Tdto tdto : tdtoList){
        tList.add(constructor.apply(tdto));
    }
    return tList;
}

您可以通过以下方式致电:

List<Foo> dtos = assemble.tFromDto(fooDTOs, Foo::new)

请注意,此方法不需要在泛型类中。它可以是通用的,可以是静态的(并使用流简化):

public static <T, D> List<T> fromDTOs(List<D> dtoList, Function<D, T> constructor){
    return dtoList.stream().map(constructor).collect(Collectors.toList());
}

鉴于此方法的简单性,您甚至可以完全删除它。

答案 1 :(得分:0)

实际上,用非默认构造函数实现泛型对象是不可能的。

免责声明:我不是说这是最好的方法,特别是因为它涉及反思。您可能需要考虑使用JB Nizet建议的简化静态版本。然而,假设这只是一个最小的工作玩具示例,我将基于OP代码回答原始问题,并表明使用非默认构造函数构建通用对象确实是可能的。

版本1,直接使用通用程序集类

<强> AssembleObjectFromDto.java:

import java.util.List;
import java.util.Arrays;
import java.util.ArrayList;
import java.lang.NoSuchMethodException;
import java.lang.InstantiationException;
import java.lang.IllegalAccessException;
import java.lang.reflect.InvocationTargetException;
import static java.lang.System.out;

class AssembleObjectFromDto<T, Tdto>
{
    public List<T> tFromDto(Class<T> clsT, Class<Tdto> clsTdto, List<Tdto> tdtoList)
        throws NoSuchMethodException, InstantiationException,
               IllegalAccessException, InvocationTargetException
    {
        List<T> tList = new ArrayList<>();
        for(Tdto tdto : tdtoList)
            tList.add(clsT.getConstructor(clsTdto).newInstance(tdto));
        return tList;
    }

    public static void main(String[] args)
    {
        AssembleObjectFromDto<Obj, Dto> assembler = new AssembleObjectFromDto<>();
        List<Dto> lstDto = Arrays.asList(new Dto(), new Dto(), new Dto(), new Dto());
        try
        {
            List<Obj> lstObj = assembler.tFromDto(Obj.class, Dto.class, lstDto);
            for(Obj o : lstObj)
                System.out.println(o.getClass().getName());
        }
        catch(NoSuchMethodException | InstantiationException | IllegalAccessException |
              InvocationTargetException ex)
        {
            System.out.println(ex);
        }
    }
}

<强> Dto.java:

class Dto {}

<强> Obj.java:

class Obj
{
    private Dto dto;

    public Obj(Dto dto)
    {
        this.dto = dto;
    }
}

版本2,使用通用/模板专业化:

为了避免将前两个Class参数传递给tFromDto(Class<T>, Class<Tdto>, List<Tdto>),可以使AssembleObjectFromDto定义一个重载tFromDto(List<Tdto>)的抽象类和两个抽象的getter来检索实际类型通用参数TTdto然后为所有必需类型专门化类。这应该使代码更具可读性,代价是有更多的类。此外,专业化应该易于使用代码生成工具自动化。

<强> AssembleObjectFromDto.java:

import java.util.List;
import java.util.ArrayList;
import java.lang.NoSuchMethodException;
import java.lang.InstantiationException;
import java.lang.IllegalAccessException;
import java.lang.reflect.InvocationTargetException;

abstract class AssembleObjectFromDto<T, Tdto>
{
    protected abstract Class<T> getProductClass();
    protected abstract Class<Tdto> getAssemblerClass();

    public List<T> tFromDto(List<Tdto> tdtoList)
        throws NoSuchMethodException, InstantiationException,
               IllegalAccessException, InvocationTargetException
    {
        return tFromDto(getProductClass(), getAssemblerClass(), tdtoList);
    }

    private List<T> tFromDto(Class<T> clsT, Class<Tdto> clsTdto, List<Tdto> tdtoList)
        throws NoSuchMethodException, InstantiationException,
               IllegalAccessException, InvocationTargetException
    {
        List<T> tList = new ArrayList<>();
        for(Tdto tdto : tdtoList)
            tList.add(clsT.getConstructor(clsTdto).newInstance(tdto));
        return tList;
    }
}

<强> AssembleObjFromDto.java:

import java.util.List;
import java.util.Arrays;
import static java.lang.System.out;
import java.lang.NoSuchMethodException;
import java.lang.InstantiationException;
import java.lang.IllegalAccessException;
import java.lang.reflect.InvocationTargetException;

class AssembleObjFromDto extends AssembleObjectFromDto<Obj, Dto>
{
    @Override
    protected Class<Obj> getProductClass() { return Obj.class; }

    @Override
    protected Class<Dto> getAssemblerClass() { return Dto.class; }

    public static void main(String[] args)
    {
        AssembleObjFromDto assembler = new AssembleObjFromDto();
        List<Dto> lstDto = Arrays.asList(new Dto(), new Dto(), new Dto(), new Dto());
        try
        {
            List<Obj> lstObj = assembler.tFromDto(lstDto);
            for(Obj o : lstObj)
                System.out.println(o.getClass().getName());
        }
        catch(NoSuchMethodException | InstantiationException | IllegalAccessException |
              InvocationTargetException ex)
        {
            System.out.println(ex);
        }
    }
}

Dto.java,Obj.java: 与版本1相比保持不变。