解决Java中静态方法的早期绑定

时间:2019-10-29 04:02:45

标签: java static-binding

我有一个AbstractBaseRepository。我所有的存储库都来自此类。我创建了另一个类RepositoryFactory来创建任何Repository实例。由于静态方法的早期绑定,我面临着问题。

public abstract class AbstractBaseRepository {
    public static <T extends AbstractBaseRepository> T getNewInstance(EntityManagerFactory entityManagerFactory) {
        throw new RuntimeException("Override and provide valid initialization");
    }
    ...
}

public class RepositoryFactory {
    public static <T extends AbstractBaseRepository>  T getRepository(Class<T> cls) {       
        return T.getNewInstance(entityManagerFactory);
    }
    ...
}

示例子类

public class DeviceModelRepo extends AbstractBaseRepository {

    public static DeviceModelRepo getNewInstance(EntityManagerFactory entityManagerFactory) {
        return new DeviceModelRepo(entityManagerFactory);
    }
    ...
}

每当我使用AbstractBaseRepository的有效子类调用getRepository()时,都会引发运行时异常。这是由于静态方法的早期绑定。在编译期间,getNewInstance与AbstractBaseRepository绑定,而不是在运行时使用类的实际类型。有什么好的解决方法?

2 个答案:

答案 0 :(得分:0)

我的第一个建议是使用Spring。获取通过特定接口创建的所有bean的列表非常容易。

此外,如果您将存储库实例视为一种“插件”,则可能会看到Java的ServiceLoader类如何提供帮助。

另外,另一种方法是在工厂中使用switch语句并为每种情况创建实例,而不是在Repository子类上使用静态方法。

最后,我不推荐反射解决方案,但是有一些方法可以根据类的名称加载类并以反射方式创建新实例。

但是无法覆盖静态方法。

答案 1 :(得分:0)

通过查看您的代码,我了解到的是,您希望拥有不同的AbstractBaseRepository实现,例如DeviceModelRepo。然后,您需要一个工厂类来创建AbstractBaseRepository的特定实现的实例。这里的主要问题是您尝试覆盖永远不会被覆盖但子类将隐藏父实现的静态方法。请不要使用静态方法进行覆盖。您可以按照以下说明更改实现,此问题将得到解决。

Streaming

然后在下面实现子类。

public abstract class AbstractBaseRepository {
    public AbstractBaseRepository(EntityManagerFactory entityManagerFactory){
        ...
    }
    //removed method getNewInstance(EntityManagerFactory entityManagerFactory) 
    ...
}

现在,我为您提供了两个工厂类的实现。 一种方法是为每个实现使用不同的方法,例如getDeviceModelRepository()。 另一种解决方案是使用反射并通过传递实现存储库类来获取存储库实例。

public class DeviceModelRepo extends AbstractBaseRepository {

    public DeviceModelRepo(EntityManagerFactory entityManagerFactory) {
        super(entityManagerFactory);
        ...
    }
    //removed method getNewInstance(EntityManagerFactory entityManagerFactory) 
    ...
}

使用反射解决方案,您可以获得如下所示的存储库实例。

public class RepositoryFactory {
    //Solution-1, create separate method for each of repository like below
    public static AbstractBaseRepository getDeviceModelRepository() {       
        return new DeviceModelRepo(entityManagerFactory);
    }
    //Solution-2, use reflection to get instance of specific implementation
    //of AbstractBaseRepository
    public static <T extends AbstractBaseRepository> T 
        getRepository(Class<T> repoClass) throws Exception{

        return repoClass.getConstructor(EntityManagerFactory.class)
            .newInstance(entityManagerFactory);
    }
    ...
}