Java中如何创建类型由变量决定的泛型对象?含Dagger注入问题
解决Java中根据变量类型创建泛型对象的问题
你的核心问题源于Java的泛型擦除机制——编译后泛型参数会被移除,没法直接通过Class对象动态生成带具体泛型参数的实例。结合你的场景(Map<Class<? extends Entity>, Config<? extends Entity>> + Dagger依赖注入),可以用以下两种方案解决:
方案一:泛型工厂方法(基础解法,不依赖Dagger)
通过泛型方法+类型令牌(Class<T>)来确保类型安全,同时利用你已有的entityClassToConfigMap获取对应配置:
1. 定义泛型工厂方法
@SuppressWarnings("unchecked") public <T extends Entity> Repository<T> createRepository(Class<T> entityClass) { // 因为你的Map保证了Class<T>对应Config<T>,所以强制转换是安全的 Config<T> config = (Config<T>) entityClassToConfigMap.get(entityClass); return new Repository<>(config); // 假设Repository构造器接收Config参数 }
2. 遍历Map创建实例
for (Map.Entry<Class<? extends Entity>, Config<? extends Entity>> entry : entityClassToConfigMap.entrySet()) { Class<? extends Entity> entityClass = entry.getKey(); Repository<?> repository = createRepository(entityClass); // 处理生成的Repository实例 }
注:
@SuppressWarnings("unchecked")是安全的,因为你明确维护了Class<T>与Config<T>的一一对应关系,不会出现类型不匹配的情况。
方案二:Dagger正确绑定泛型Map(解决注入失效问题)
你之前用@IntoMap+@ClassKey失效,大概率是泛型参数绑定不规范。以下是正确的绑定方式:
1. 绑定每个Entity对应的Repository Provider
为每个具体的Entity子类(如EntityA、EntityB)编写Provider方法,通过@IntoMap和@ClassKey将其绑定到Map中:
// 绑定EntityA的Repository @Provides @IntoMap @ClassKey(EntityA.class) public Repository<EntityA> provideEntityARepository(Config<EntityA> config) { return new Repository<>(config); } // 绑定EntityB的Repository @Provides @IntoMap @ClassKey(EntityB.class) public Repository<EntityB> provideEntityBRepository(Config<EntityB> config) { return new Repository<>(config); }
2. 注入泛型Map并使用
注入时要使用Provider<Repository<? extends Entity>>作为Map的值类型(避免Dagger因泛型擦除导致的绑定冲突):
@Inject Map<Class<? extends Entity>, Provider<Repository<? extends Entity>>> repositoryProviderMap; // 遍历创建实例 for (Map.Entry<Class<? extends Entity>, Provider<Repository<? extends Entity>>> entry : repositoryProviderMap.entrySet()) { Repository<?> repository = entry.getValue().get(); // 处理Repository实例 }
3. 封装成类型安全的工厂(可选)
如果需要更简洁的类型安全调用,可以封装一个工厂类:
public class RepositoryFactory { private final Map<Class<? extends Entity>, Provider<Repository<? extends Entity>>> providerMap; @Inject public RepositoryFactory(Map<Class<? extends Entity>, Provider<Repository<? extends Entity>>> providerMap) { this.providerMap = providerMap; } @SuppressWarnings("unchecked") public <T extends Entity> Repository<T> getRepository(Class<T> entityClass) { Provider<Repository<? extends Entity>> provider = providerMap.get(entityClass); if (provider == null) { throw new IllegalArgumentException("未找到对应" + entityClass.getName() + "的Repository"); } return (Repository<T>) provider.get(); } }
使用时直接调用getRepository(entityClass)即可获取类型正确的Repository<T>。
关键注意事项
- 泛型擦除无法绕过,必须通过
Class<T>这类类型令牌来标记泛型参数,确保类型安全。 - Dagger绑定泛型Map时,必须保证
@ClassKey的类型与返回的Repository泛型参数严格对应,否则会出现类型转换异常。 - 所有
unchecked警告只要基于明确的类型对应关系,都是安全的,可以通过注解消除。
内容的提问来源于stack exchange,提问作者Megha Agarwal
相关产品推荐
相关产品推荐

