在 java 中绕过静态方法的早期绑定
Get around early binding of static methods in java
我有一个 AbstractBaseRepository。我所有的存储库都来自这个 class。我创建了另一个 class 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);
}
...
}
子示例class
public class DeviceModelRepo extends AbstractBaseRepository {
public static DeviceModelRepo getNewInstance(EntityManagerFactory entityManagerFactory) {
return new DeviceModelRepo(entityManagerFactory);
}
...
}
每当我使用 AbstractBaseRepository 的有效子 class 调用 getRepository() 时,都会抛出运行时异常。这是由于静态方法的早期绑定。在编译时,getNewInstance 与 AbstractBaseRepository 绑定,而不是在运行时与 class 的实际类型绑定。有什么好的解决方法吗?
我的第一个建议是使用 Spring。很容易得到一个特定接口创建的所有bean的列表。
此外,如果您将 Repository 实例视为 "plug-in" 的一种类型,您可能会看到 Java 的 ServiceLoader class 如何提供帮助。
此外,另一种方法是在工厂中使用 switch 语句并为每种情况创建实例,而不是在 Repository 子classes 上使用静态方法。
最后,我不推荐反射解决方案,但有一些方法可以根据其名称加载 class 并反射创建一个新实例。
但是无法覆盖静态方法。
通过查看您的代码,我了解到您希望拥有 AbstractBaseRepository 的不同实现,例如 DeviceModelRepo。那么你想要一个工厂class来创建AbstractBaseRepository具体实现的实例。这里的主要问题是您尝试覆盖永远无法覆盖的静态方法,但 subclass 将隐藏父实现。请不要使用静态方法进行覆盖。您可以按如下所示更改实施,此问题将得到解决。
public abstract class AbstractBaseRepository {
public AbstractBaseRepository(EntityManagerFactory entityManagerFactory){
...
}
//removed method getNewInstance(EntityManagerFactory entityManagerFactory)
...
}
然后下面是 subclass 的实现。
public class DeviceModelRepo extends AbstractBaseRepository {
public DeviceModelRepo(EntityManagerFactory entityManagerFactory) {
super(entityManagerFactory);
...
}
//removed method getNewInstance(EntityManagerFactory entityManagerFactory)
...
}
现在我为您提供工厂的两个实现class。
一种是为每个实现使用不同的方法,例如 getDeviceModelRepository()。
另一种解决方案是使用反射并通过传递实现存储库 class.
来获取存储库实例
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);
}
...
}
通过反射解决方案,您可以获得如下所示的存储库实例。
RepositoryFactory.getRepository(DeviceModelRepo.class)
我有一个 AbstractBaseRepository。我所有的存储库都来自这个 class。我创建了另一个 class 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);
}
...
}
子示例class
public class DeviceModelRepo extends AbstractBaseRepository {
public static DeviceModelRepo getNewInstance(EntityManagerFactory entityManagerFactory) {
return new DeviceModelRepo(entityManagerFactory);
}
...
}
每当我使用 AbstractBaseRepository 的有效子 class 调用 getRepository() 时,都会抛出运行时异常。这是由于静态方法的早期绑定。在编译时,getNewInstance 与 AbstractBaseRepository 绑定,而不是在运行时与 class 的实际类型绑定。有什么好的解决方法吗?
我的第一个建议是使用 Spring。很容易得到一个特定接口创建的所有bean的列表。
此外,如果您将 Repository 实例视为 "plug-in" 的一种类型,您可能会看到 Java 的 ServiceLoader class 如何提供帮助。
此外,另一种方法是在工厂中使用 switch 语句并为每种情况创建实例,而不是在 Repository 子classes 上使用静态方法。
最后,我不推荐反射解决方案,但有一些方法可以根据其名称加载 class 并反射创建一个新实例。
但是无法覆盖静态方法。
通过查看您的代码,我了解到您希望拥有 AbstractBaseRepository 的不同实现,例如 DeviceModelRepo。那么你想要一个工厂class来创建AbstractBaseRepository具体实现的实例。这里的主要问题是您尝试覆盖永远无法覆盖的静态方法,但 subclass 将隐藏父实现。请不要使用静态方法进行覆盖。您可以按如下所示更改实施,此问题将得到解决。
public abstract class AbstractBaseRepository {
public AbstractBaseRepository(EntityManagerFactory entityManagerFactory){
...
}
//removed method getNewInstance(EntityManagerFactory entityManagerFactory)
...
}
然后下面是 subclass 的实现。
public class DeviceModelRepo extends AbstractBaseRepository {
public DeviceModelRepo(EntityManagerFactory entityManagerFactory) {
super(entityManagerFactory);
...
}
//removed method getNewInstance(EntityManagerFactory entityManagerFactory)
...
}
现在我为您提供工厂的两个实现class。 一种是为每个实现使用不同的方法,例如 getDeviceModelRepository()。 另一种解决方案是使用反射并通过传递实现存储库 class.
来获取存储库实例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);
}
...
}
通过反射解决方案,您可以获得如下所示的存储库实例。
RepositoryFactory.getRepository(DeviceModelRepo.class)