代码之家  ›  专栏  ›  技术社区  ›  PaquitoSoft

我可以做这个通用的事情吗?

  •  4
  • PaquitoSoft  · 技术社区  · 16 年前

    public abstract DefaultDAO<T,V> {
      private EntityManager manager;
    
      public BaseDAO(EntityManager em) {
        this.manager = em;
      }
    
      public void create(T entity) {
        manager.persist(entity);
      }
    
      // You know the others...
    
      public T read(V pk) {
        // Now, here is the problem. 
        // EntityManager signature is: public <T> T find(Class<T> entityClass, Object primaryKey);
        // So I must provide the type of the object this method will be returning and 
        // the primary key.
        // resulting object will be T typed and pk type is V type (although is not needed to type it since the method expects an Object)
        // So... I expected to be allowed to do something like this
        return manager.find(T, pk); // But it's not allowed to use T here. T is not an instance
      }   
    }
    

    public PersonDAO extends DefaultDAO<PersonEntity, Long> {
      public PersonDAO(EntityManager em) {
        super(em);
      }
      // CRUD methods are inherited
    }
    

    EntityManager manager = ...
    PersonDAO dao = new PersonDAO(manager);
    Long pk = .....
    PersonEntity person = dao.find(pk); // DAO would return a PersonEntity
    

    当客户端执行代码时,BaseDAO知道它必须返回的实体的类型以及该实体的主键的类型,因为我在特定的dao上设置了它,但我不知道如何正确地编写read()方法。

    5 回复  |  直到 16 年前
        1
  •  14
  •   Tiny user825402    10 年前

    类型擦除 .

    Class<T>

    public abstract class DefaultDAO<T, V> {
    
        private EntityManager manager;
        private final Class<T> clazz;
    
        public DefaultDAO(EntityManager em, Class<T> clazz) {
            this.manager = em;
            this.clazz = clazz;
        }
    
        public T read(V pk) {
            return manager.find(clazz, pk);
        }
    }
    
        2
  •  3
  •   Daff    16 年前

    Java在运行时不再具有泛型类信息(称为类型擦除)。我所做的就是给我的抽象道类一个泛型类的实例。

    public abstract DefaultDAO<T,V> {
    
      protected Class<T> genericClass;
      private EntityManager manager;
    
      protected BaseDAO(EntityManager em, Class<T> implclass) {
        this.manager = em;
      }
    
      public void create(T entity) {
        manager.persist(entity);
      }
    
      // You know the others...
    
      public T read(V pk) {
        return manager.find(this.getGenericClass(), pk); // But it's not allowed to use T here. T is not an instance
      }
    
      public Class<T> getGenericClass()
      {
        return genericClass;
      }
    }
    
    public class Blubb
    {
        private String id;
    
        // Getters and Stuff...
    }
    
    public class BlubbDao extends DefaultDAO<Blubb, String>
    {
        public BlubbDao(EntityManager em)
        {
            super(em, Blubb.class);
        }
    }
    

        3
  •  3
  •   Cowan    16 年前

    有一种方法可以使用反射来实现这一点,只要你的类在泛型方面遵循一致的类层次结构(即你的基类和具体类之间的继承层次结构中的任何中间类都以相同的顺序使用相同的泛型参数)。

    private Class getBeanClass() {
        Type daoType = getClass().getGenericSuperclass();
        Type[] params = ((ParameterizedType) daoType).getActualTypeArguments();
        return (Class) params[0];
    }
    

    这闻起来有点臭,但用在构造函数中从具体实现中传递.class的讨厌来换取坚持以这种方式保持类型层次结构一致的讨厌。

        4
  •  3
  •   FedericoAlvarez    11 年前

    我认为你可以做到:

     public <T> T find(Class<T> clazz, Object id) {
            return entityManager.find(clazz, id);
        }
    
        5
  •  2
  •   Drew    16 年前