当前位置: 首页 > 知识库问答 >
问题:

泛型类型的返回交集

尉迟龙光
2023-03-14

我想让一个函数返回一个保证实现两个接口的对象。编译时不一定知道确切的对象。我的代码看起来像:

class HelloWorld {

  public interface A {}
  public interface B {}

  public static class C implements A, B {}
  public static class D implements A, B {}

  public static <T extends A & B> void g(T t) {}

  public static <T extends A & B> T f(boolean b) {
    if (b)
      return new C(); // Doesn't compile
    return new D(); // Doesn't compile
  }

  public static void main(String []args){
    g(f(true));
    g(f(false));
    <what_should_I_write_here> x = f(<user_inputted_boolean>); 
  }
}

在尝试编译时,我遇到以下错误:

你好世界java:13:错误:不兼容的类型:C无法转换为T
返回新的C()
^
其中T是一个类型变量:
T扩展了方法f(布尔值)
HelloWorld中声明的a,B。java:14:错误:不兼容的类型:D无法转换为T
返回新的D()
^
其中T是一个类型变量:
T扩展了方法f(布尔值)中声明的a,B

这不起作用,因为不能从函数返回两种不同的类型,CD是不同的类型。

有什么方法可以让上面的代码编译吗?

共有2个答案

易自珍
2023-03-14

我同意霍尔格在回答中所说的一切。但我想补充一件事,因为棘手的类型非常有趣。

我相信你想做的是让交叉口返回类型为f,如下所示:

public static A & B f(boolean b)

然后f将返回实现AB的某个对象。这将检查方法类型的返回语句,您可以将其返回值分配给AB变量。

但这当然是不允许的,Java中的交集类型只允许在类型变量上使用。

你可以试试这个:

public static Optional<? extends A & B> f(boolean b)

在这里,交集类型是可以的,因为它实例化了可选的类型参数。但是无论如何这是不允许的,因为通配符只能有一个绑定,

Ceylon是一种非常有趣的编程语言,它支持第一类交集和并集类型。你可以用Ceylon写上面的例子。

看看,真的很有趣!

荣沈义
2023-03-14

你对类型变量有一个基本的误解。当你声明一个方法,比如

public static <T extends A & B> T f(boolean b) { … }

您可以声明一个类型变量T,调用者可以将实际类型(或调用者上下文的类型变量)分配给它。例如,呼叫方可以执行以下操作:

class SomethingCompletelyUnknownToF implements A,B {}

SomethingCompletelyUnknownToF var = f(trueOrFalse);

编译器将接受它,因为f的调用者用于T的类型somethingtompleunknowntof满足了类型必须实现AB的约束。当然,这在运行时会失败,因为无论是C还是D都不能分配给一些完全不知道的东西。事实上,f不可能实现返回它甚至不知道的特定类型的期望。

总之,类型变量不是方法可以分配类型的变量,类型变量是调用者选择的类型的占位符。

所以方法签名

public static <T extends A & B> void g(T t) { … }

更有意义的是,无论调用方为T选择什么实际类型,当作为参数传递时,它都将满足方法实现AB的期望。当然,g不能期望它是,DC,因为它可能是实现aB的一种完全未知的类型。

也就是说,在Java中,无法表示返回类型扩展了两种类型(除了声明扩展了这两种类型的具体类型)。对于随机访问,无论如何都不需要麻烦,因为它不会产生任何后果。请注意,当返回的列表保证实现这个标记接口时,JRE类也从不声明。这是通过从不期望它作为参数类型来实现的。类似地,Serializable从未在任何地方声明为返回或参数类型。

 类似资料:
  • 对于一堆带有泛型的包装类,我的继承结构遇到了一些麻烦。这基本上是结构: 这将与当前代码一起编译和工作,但是,这似乎很危险。如果调用方像这样使用这个方法:,它将很好地编译,但是如果findMiddle尝试返回SubBWrapper,则在运行时会有一个ClassCastException。我以为行得通却行不通的是: 所以我的问题基本上是,有没有正确的方法来编写编译、运行并遵循最佳实践的方法findMi

  • 问题内容: 背景 我曾经写过这种方法: 应该这样称呼它: 这很好用(尽管我在研究当前容易出错的问题时在这里的答案中已经看到)。 目前的情况 无论如何,现在我正在编写以下代码(在扩展javax.servlet.jsp.tagext.TagSupport的类中): 目的是可以这样称呼: 我的评估方法中的代码显然不起作用。的第二个参数应该是Class对象。这导致我: 我的问题 如何获得通用(返回)类型的

  • 问题内容: 我有一个旧类,该类本身不是泛型,但其方法返回类型之一使用泛型: 使用泛型返回字符串的集合。因此,我可以进行遍历,而无需将元素强制转换为: 但是,如果我将自己更改为通用名称,但其他所有内容均保持不变: 然后继续使用对的非泛型引用,不再返回,而是返回非类型。因此,客户端代码无法编译: 为什么是这样?有哪些解决方法? 我的猜测是,通过使用对泛型类的非泛型引用,Java将关闭整个类的所有泛型。

  • 我在我的Java程序中写了这个函数: 这就是我所说的: 它是有效的,但我觉得我应该能够省略第一个参数,并从返回类型(结果被分配到的类型)推断出它。这可能吗?如果是,语法是什么?

  • 我试图创建一个Java方法,它接受一个对象类型和它应该转换成的数据类型。 例如,如果我应该能够返回一个值1作为Int或双根据需要。我使用类传递数据类型作为参数。 问题:如何使方法泛型以接受基于输入参数的返回类型? 下面的代码只是一个示例,它可能在语法上不正确,用于解释我的问题。