【问题标题】:How to write generics method in java that accepts any list of two object and returns list?如何在java中编写接受两个对象的任何列表并返回列表的泛型方法?
【发布时间】:2023-03-10 23:36:01
【问题描述】:

我有一个域类(DB):

public class PersonDoamin {
private String name;
private String age;

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public String getAge() {
    return age;
}

public void setAge(String age) {
    this.age = age;
}
}

我也有模型类:

public class PersonBean extends PersonDoamin {

}

所以当我转到 DAOImpl 类并查询 List 并将此列表传输到 List 并返回给用户时,因为我有 List getAllPerson() 的接口方法。所以当我从 List 传输所有数据时,我的问题就在这里。这里我有一些实用方法,可以像这样从一个 bean 复制到另一个:

List<PersonDoamin> list = PersonDAO.getAllPersons();
List<PersonBean> pbList = new ArrayList<PersonBean>();

/* this below logic is pretty much in the all DAO impl*/

for(PersonDoamin p : list){
PersonBean pb = new PersonBean();
CopyHelper.copyBean(p, pb);
pbList.add(pb);
}
return pbList;

我们是否可以用某种通用方法替换循环和复制以及添加到另一个列表并返回部分,该方法将获取任何对象两个列表并循环遍历一个并将其添加到另一个传递的列表参数并返回它。像下面这样的东西现在还不完美:

public static <T> List<T> listToArray(List<T> list,List<T> list2) {

    for(T element : list){
        list2.add(element);
    }
    return list2;
}

public static void main(String[] args) {
    List<PersonDoamin> personList = new ArrayList<PersonDoamin>();
    PersonDoamin p = new PersonDoamin();
    p.setName("aj");
    p.setAge("25");
    personList.add(p);
    List<PersonBean> personBeansToReturn = new ArrayList<PersonBean>();
    Test.listToArray(personList , personBeansToReturn );

}

【问题讨论】:

  • PECS 可能会有所帮助:stackoverflow.com/questions/2723397/…
  • 我想我看到的一个问题是您试图将PersonDomain 放入PersonBean 列表中,但这是行不通的。
  • 您在listToArray 中写的内容与您在原始循环中所做的不一致。您没有将域转换为 bean
  • 哦,也许这就是问题所在。 OP 是否正在寻找一种在泛型类型上调用 new T 的方法?

标签: java list generics collections


【解决方案1】:

如果您正在寻找一种在泛型类型上调用new 的方法,那么您可以。您必须使用反射并在 Class 对象上调用 newInstance。我不知道这对你是否可行。

另外,如果不使用一些重度反射,我也看不到实际实现您的 bean 复制方法。在下面的示例中,我只是通过强制转换为所需的类来伪造。

public class GenericCopyTest
{

   public static void main( String[] args ) throws Exception
   {
      List<PersonDoamin> personList = new ArrayList<PersonDoamin>();
      PersonDoamin p = new PersonDoamin();
      p.setName( "aj" );
      p.setAge( "25" );
      personList.add( p );
      List<PersonBean> personBeansToReturn = new ArrayList<PersonBean>();
      copyAndDowncast( personList, personBeansToReturn, PersonBean.class );
      System.out.println( personBeansToReturn );
   }

   public static <T,U extends T> List<U> copyAndDowncast( List<T> from, 
           List<U> to, Class<U> type ) 
           throws InstantiationException, IllegalAccessException
   {
      for( T element : from ) {
         U nu = type.newInstance();
         copyBean( element, nu );
         to.add( nu );
      }
      return to;
   }

   private static <X,Y extends X> void copyBean( X from, Y nu ) {
      ((PersonBean)nu).setName( ((PersonDoamin)from).getName() );
      ((PersonBean)nu).setAge( ((PersonDoamin)from).getAge() );
   }

}

class PersonDoamin {
   private String name;
   private String age;

   public String getName() {
       return name;
   }

   public void setName(String name) {
       this.name = name;
   }

   public String getAge() {
       return age;
   }

   public void setAge(String age) {
       this.age = age;
   }

   @Override
   public String toString()
   {
      return "PersonDoamin{" + "name=" + name + ", age=" + age + '}';
   }

}
class PersonBean extends PersonDoamin {

   @Override
   public String toString()
   {
      return "PersonBean{" + getName() + ',' + getAge()+ '}';
   }

}

输出:

run:
[PersonBean{aj,25}]
BUILD SUCCESSFUL (total time: 0 seconds)

【讨论】:

  • copyBean 方法使用 Spring BeanUtils 类的 Beanutils.copyProperties(source, destination) 方法将相同的属性从一个 bean 复制到另一个 bean。
  • 基于上述答案,我设法让它工作。 public static List getNewList(List from, List to, Class type) throws InstantiationException, IllegalAccessException { for (T element : from) { U dt = type .newInstance(); BeanUtils.copyProperties(element, dt); to.add(dt); } 还给; }
【解决方案2】:

有点跑题了,你的设计看起来有点奇怪,你有“Domain”类和“Bean”类,并且“Bean”扩展了“Domain”......

无论如何,回到你的问题,你想做的是:

  1. 你有一个List&lt;Domain&gt;
  2. 您希望将列表中的每个域转换为一个 Bean(通过使用一些 util 方法)
  3. 将生成的 Bean 放入列表并返回

让我们一步一步来。

(顺便说一句,您编写的 listToArray 方法与您的原始循环不符,因为它没有进行转换(第 2 点)。我猜是错字?)

(所有伪代码,因为我手头没有环境来编译它。我猜概念应该是正确的)


第 1 步:Person 的 Util 方法

您原始 util 方法的一个最大问题是,将 Parent 对象实例放入 Child 列表是非法的(应该很容易自己弄清楚原因)。

util 方法应如下所示:

List<PersonBean> toBeans(List<PersonDomain> domains) {
    List<PersonBean> beans = new ArrayList<>(domains.size());
    for (PersonDomain domain: domains) {
        PersonBean bean = new PersonBean(); 
        CopyHelper.copyBean(domain, bean);
        beans.add(bean);
    }
    return beans;
}

第 2 步:使其通用

上面的问题是它只适用于Person。如果你想让它通用,你还需要提供将 Domain 转换为 Bean 的函数:

(假设您使用的是Java8,如果您使用的是旧版本,那么制作自己的界面应该很简单)

<D,B> List<B> toBeans(List<D> domains, Function<B,D> mapper) {
    List<PersonBean> beans = new ArrayList<>(domains.size());
    for (PersonDomain domain: domains) {
        beans.add(mapper.apply(domain));
    }
    return beans;
}

以便您可以通过以下方式使用它:

return toBeans(personDomains, (domain) -> {
                         PersonBean bean = new PersonBean(); 
                         CopyHelper.copyBean(domain, bean);
                         return bean;
                     });

(如果在大多数情况下你要使用CopyHelper方式,你可以考虑包装函数)

<D,B> List<B> toBeansByBeanCopy(List<D> domains, Class<B> beanClass) {
    return toBeans(domains, (domain)-> {
                         B bean = beanClass.newInstance(); 
                         CopyHelper.copyBean(domain, bean);
                         return bean;
                     });
}

这样你就可以把它当作

return toBeansByBeanCopy(personDomains, PersonBean.class);

第 3 步:Java 已经为您完成了

其实你上面要做的,Java 8中已经提供了Java。你可以简单地做:

return personDomains.stream()
    .map(d -> {
        PersonBean bean = new PersonBean(); 
        CopyHelper.copyBean(domain, bean);
        return bean;
        })
    .collect(Collectors.toList());

如果是标准方法,您可以编写一个小方法在 lambda 表达式中使用。

return personDomains.stream()
    .map(BeanMapper.mapper(PersonBean.class))
    .collect(Collectors.toList());

(将实现留作练习)

【讨论】:

  • 我使用的技术是JSF 2.0,primefaces,带有ibatis的spring 3.2.9,并且域类是使用ibatis工具自动生成的。因此,我决定扩展它,而不是定义具有与域类相同的属性的 bean,以便不会有任何具有相同名称的重复属性。而 CopyHelper.copyBean 方法是使用 spring bean util 的 BeanUtils.copyProperties 方法将相同的属性从一个 bean 复制到另一个。
  • 这里我只是想避免键入相同的代码,我循环遍历从调用数据库获得的域类列表并将其放在扩展域 bean 的 bean 列表中并将其返回给控制器。:
  • 我仍然不认为您选择的域/bean 设计是合理的。无论如何,它是题外话:) 你正在寻找的应该已经很好地解决了我在这里的建议。
  • 对于你的情况,你应该简单地在函数中创建“to list”
【解决方案3】:

如果你想在同一个列表中放置多个 bean 类, 如何使用父类 PersonDoamin 创建列表,然后,您可以存储 PersonDoamin 和 PersonBean 类。

public static void main(String[] args) {
    List<PersonDoamin> personList = new ArrayList<PersonDoamin>();
    PersonDoamin p = new PersonDoamin();
    p.setName("aj");
    p.setAge("25");
    personList.add(p);

    // Changed here. PersonBean => PersonDoamin
    List<PersonDoamin> personBeansToReturn = new ArrayList<PersonDoamin>();

    Test.listToArray(personList, personBeansToReturn);

    // also you can insert PersonBean into the list
    personBeansToReturn.add(new PersonBean());

}

【讨论】:

    【解决方案4】:

    为什么不直接使用addAll() 呢?它会做你想做的事,而且它已经是系统库的一部分。

    请记住,您可以将 PersonBean 添加到 PersonDomain 列表中,但反之则不行。

    public class GenericCopyTest
    {
       public static void main( String[] args ) {
          List<PersonDoamin> personList = new ArrayList<PersonDoamin>();
          List<PersonBean> personBeansToReturn = new ArrayList<PersonBean>();
          personList.addAll( personBeansToReturn );
          personBeansToReturn.addAll( personList );  // <-- FAILS
                                                     // No suitable method found
       }
    }
    
    class PersonDoamin {}
    class PersonBean extends PersonDoamin {}
    

    【讨论】:

      猜你喜欢
      • 2010-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-01
      • 1970-01-01
      • 2021-01-25
      • 1970-01-01
      相关资源
      最近更新 更多