【问题标题】:Get generic parameter of generic parameter during inheritance继承时获取泛型参数的泛型参数
【发布时间】:2020-11-24 10:25:41
【问题描述】:

可以,如果可以,如何访问另一个泛型参数的泛型参数,而不指定它?

下面的例子是根据我目前的情况进行简化的。所有成员和方法都被省略,因为它们与情况无关。 LibraryRepository 是一个 JPA/Spring 类型,期望一个 ENTITY 和一个 ID

abstract class AbstractEntity<ID> {}

class ConcreteEntity extends AbstractEntity<Long> {}

interface AbstractRepository<ENTITY extends AbstractEntity<?????>> extends LibraryRepository<ENTITY, ?????> {}

//Desired declaration:
interface ConcreteRepository extends AbstractRepository<ConcreteEntity> {}

如果没有在AbstractRepository 上指定Long,那么写什么而不是两个?????,如果可能的话?


为了问题范围,请回答有关泛型的问题,而不是如何以更好的方式实现 spring-repositories。不过,我很高兴在 cmets 中获得有关这方面的提示。

【问题讨论】:

  • 无关:类型参数遵循 java 命名约定,它们通常是单个字符。
  • 这是示例。当类型有专有名称时,更容易争论类型。
  • “更容易”是主观的。大多数人习惯于遵循 java 标准,他们会发现多字符类型令人困惑。更糟糕的是,语言新手可能会把它们当作类名。

标签: java generics inheritance


【解决方案1】:

interface AbstractRepository&lt;ENTITY extends AbstractEntity&lt;?????&gt;&gt; extends LibraryRepository&lt;ENTITY, ?????&gt; {}

考虑泛型的一种(特别有用的)方式是它们将类型链接在一起。如果你声明一个新的类型变量并且只在一个地方使用它,因为擦除,那实际上是没有用的。在两个地方使用它,现在你告诉编译器你使用T 的两个地方是链接的:它们可以是任何东西,只要它们是相同的东西。

这种思维方式在这里也提供了一些见解:显然,您希望将您的第一个 ????? 链接到您的第二个 ?????:让他们平等。

那么,这样做的方法是声明一个新的类型变量并使用它:

interface AbstractRepository<ENTITY extends AbstractEntity<Q>, Q>
   extends LibraryRepository<ENTITY, Q> {}

不幸的是,这意味着 AbstractRepository 现在获得了一个类型变量,我猜你不希望这种情况发生。

不幸的是,没有类型变量,java 无法链接类型。

作为一般经验法则,如果您将类层次结构(扩展实现事物的事物)和大量泛型混合在一起,您最终会得到大量泛型参数,其中一些会感觉违反 DRY。解决方案是要么接受它,要么不做这两件事中的一件(使用组合而不是继承,或者减少你正在使用的类型变量,或者将它们移动到方法中),或者使用一堆hacky反射和'warning-casts' (您将内容转换为 typevar,它实际上不会对任何内容进行类型检查,并且往往会在奇怪的地方导致 ClassCastExceptions:在行中任何地方都没有演员表的地方,而不是有错误代码的地方。导致了漫长而艰巨的错误搜索练习。

【讨论】:

  • 感谢您的详细解释。好吧,一个人不可能拥有每一个蛋糕。这可能不是最糟糕的功能。
【解决方案2】:

也许这是您要避免的,但我认为您应该将AbstractEntity 的通用参数指定为AbstractRepository 中的参数,如下所示:

interface LibraryRepository<ENTITY, ID> {}

abstract class AbstractEntity<ID> {}

class ConcreteEntity extends AbstractEntity<Long> {}

interface AbstractRepository<ENTITY extends AbstractEntity<ID>, ID>
          extends LibraryRepository<ENTITY, ID> {}

interface ConcreteRepository extends AbstractRepository<ConcreteEntity, Long> {}

我不知道编译器如何才能对LibraryRepository 的泛型参数进行类型检查。

【讨论】:

  • 这将是我试图避免的。我想,既然ENTITY 已经知道ID,我可能可以在编写ConcreteRepository 的定义时跳过重新声明它。
  • 据我所知,不可能。 Java 泛型不是那么聪明或方便。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-09
  • 2015-11-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多