将泛型转换为子类型

时间:2017-01-04 11:10:27

标签: java generics casting

这是对my previous question

的跟进

我的以下代码行不起作用:

IAccount account = (AccountModel) new AccountRepository().getByEmail(emailaddress);

...getByEmail(...)的返回类型为Model<Account>AccountModel延伸Model<Account>
然而,当我测试时,我得到java.lang.ClassCastException: models.Model cannot be cast to models.AccountModel。我知道这是因为每个AccountModel都是Model<Account>,但不是相反 有什么方法可以确保我可以解决这个问题(或解决它)。

public class AccountRepository extends Repository<Account> {

    public AccountRepository() {
        super(Account.class);
    }

    public Model<Account> getByEmail(String emailAddress) {
        return this.getCustomHqlSingle("FROM Account a WHERE a.emailAddress = '" + emailAddress + "'");
    }
}

public abstract class Repository<T> implements Serializable {
    protected final Model<T> getCustomHqlSingle(String hql) {
        List<Model<T>> t = this.getCustomHqlList(hql);
        if (t != null && !t.isEmpty()) {
            return t.get(0);
        } else {
            return null;
        }
    }

    protected final List<Model<T>> getCustomHqlList(String hql) {

        Session session = SESSION_FACTORY.openSession();

        try {
            session.beginTransaction();
            List<T> entities = session.createQuery(hql).getResultList();
            List<Model<T>> result = new ArrayList<>();
            for (T t : entities) {
                result.add(this.getByEntity(t));
            }
            return result;
        } finally {
            session.close();
        }
}

对于将此问题标记为重复的人,让我从我的问题中重新措辞以下句子:

  

我知道这是因为每个AccountModel都是Model<Account>,但是   不是相反。

  

我知道这是因为每个Dog都是Animal,而不是另一个public abstract class BaseConnection<T> { protected T _stream; protected TcpClient _client; public abstract void Connect(); public abstract void Disconnect(); } public class Connection<T> : BaseConnection<T> where T: Stream { public override void Connect(){/*Do somthing*/} public override void Disconnect(){/*Do somthing*/} public void Reconnect() { Disconnect(); Connect(); } }   四处走动。

2 个答案:

答案 0 :(得分:1)

您必须设计一种方法,将Model<Account>转换为AccountModel。从您的其他问题中获取代码,您可以为AccountModel类添加构造函数:

public class AccountModel extends Model<Account> implements IAccount {
    private static final AccountRepository REPOSITORY = new AccountRepository();

    public AccountModel(Account entity) {
        super(entity, REPOSITORY);
    }

    public AccountModel(Model<Account> model) { // <---
        super(model._entity, REPOSITORY);
    }

    // Method implementations...
}

然后更改您的AccountRepository课程,以便从AccountModel返回getByEmail

public AccountModel getByEmail(String emailAddress) {
    return new AccountModel(this.getCustomHqlSingle("FROM Account a WHERE a.emailAddress = '" + emailAddress + "'"));
}

使用新构造函数将Model<Account>转换为AccountModel

还有另一种选择。您可以让实现类实现一个返回所需new Model<T>(...)类型的抽象方法,而不是在Repository中调用Model

public abstract class Repository<T, R> implements Serializable

...

public Repository(Class<T> repositoryClass) {

    if (!Repository._initiated) 
        setup();

    this.cons = cons;
}

protected abstract R getModel(T entity, Repository<T> repo); // <--

然后在工厂方法的某处:

public R getByFoo(...) {
   ...
   T t = session.get(_repositoryClass, ...);
   return getModel(t, this);
}

AccountRepository将返回新的AccountModel

public class AccountRepository extends Repository<Account, AccountModel> {

    public AccountRepository() {
        super(Account.class);
    }

    @Override
    protected AccountModel getModel(Account entity, Repository<Account> repo) {
        return new AccountModel(entity);
    }

}

答案 1 :(得分:0)

既然你说你理解为什么会出现错误,那么让我试着解释一下有关投射的其他内容。

除了一些有限的情况,铸造操作员不会更改正在施放的物品。 Casting只是对编译器的指令,说&#34;我的逻辑保证了转换对象的类型与编译器可以确定的不同,所以当你(编译器)告诉我这是一个错误时,我是确定,在运行时,它会没事的。所以不要给我一个错误&#34;。

它没有说&#34;把这个对象转换成另一个类似的对象&#34;。感谢天堂,这种操作在Java中是不可能的。