泛型类型接口使用报错求助:Repository调用saveAll方法失败
错误根源
你遇到的类型错误核心在于Map的泛型声明无法建立键与值之间的类型约束,以及通配符的独立捕获问题:
通配符的独立性
你定义的Map<Class<?>, Repository<?, ?>>中,Repository<?, ?>的两个通配符?是完全独立的捕获类型。当你调用daos.get(Account.class)时,编译器只能推断出返回的是一个未知类型的Repository,无法关联这个Repository的第一个泛型参数就是Account。
而saveAll方法的泛型约束是<S extends T> void saveAll(Iterable<S>),此时T是编译器捕获的未知类型,传入的List<Account>无法证明是这个未知T的子类型,因此触发类型不匹配错误。键值类型无绑定
当前Map的键是任意Class<?>,值是任意Repository<?,?>,没有声明“键对应的Class必须是值中Repository的实体类型T”这一约束,导致编译器无法进行有效的类型推断。
解决方法
方法1:通过泛型方法安全获取DAO
添加一个泛型方法来封装Map的get操作,让编译器能根据传入的Class<T>推断出对应的Repository<T,K>类型:
class Main { private static Map<Class<?>, Repository<?, ?>> daos = new HashMap<>(); // 泛型方法获取DAO @SuppressWarnings("unchecked") private static <T, K> Repository<T, K> getDao(Class<T> clazz) { return (Repository<T, K>) daos.get(clazz); } public void init() { daos.put(Account.class, new AccountDAO()); List<Account> accounts = new ArrayList<Account>(); // ... 使用Faker创建Account实例 // 调用泛型方法获取DAO,类型匹配 getDao(Account.class).saveAll(accounts); } }
这里的@SuppressWarnings("unchecked")是安全的,因为你存入Map的AccountDAO确实实现了Repository<Account, String>,和传入的Account.class完全对应。
方法2:用泛型Holder类封装DAO(更严谨)
如果想从根源上避免无约束的Map,可以用一个泛型Holder类来存储键值对,确保Class和Repository的类型绑定:
class Main { // 用泛型Holder存储DAO,确保Class与Repository的类型关联 private static class DaoHolder<T, K> { final Class<T> entityClass; final Repository<T, K> repository; DaoHolder(Class<T> entityClass, Repository<T, K> repository) { this.entityClass = entityClass; this.repository = repository; } } private static List<DaoHolder<?, ?>> daos = new ArrayList<>(); // 泛型方法获取DAO @SuppressWarnings("unchecked") private static <T, K> Repository<T, K> getDao(Class<T> clazz) { for (DaoHolder<?, ?> holder : daos) { if (holder.entityClass.equals(clazz)) { return (Repository<T, K>) holder.repository; } } throw new IllegalArgumentException("找不到对应类型的DAO: " + clazz.getName()); } public void init() { daos.add(new DaoHolder<>(Account.class, new AccountDAO())); List<Account> accounts = new ArrayList<Account>(); // ... 使用Faker创建Account实例 getDao(Account.class).saveAll(accounts); } }
这种方式从存储阶段就保证了Class和Repository的类型一致性,比直接用无约束的Map更严谨。
内容的提问来源于stack exchange,提问作者Amaury Le Roux Dupeyron

