繁体   English   中英

为什么不能将通配符与接收参数化参数的方法一起使用?

[英]Why can't I use wildcard with methods receiving a parameterized argument?

例如,我使用Measure.doubleValue(Unit<?> unit)方法,该方法返回以指定Unit表示的度量的double Measure.doubleValue(Unit<?> unit)值。 如果我将Unit<?>变量传递给它,则会收到仍然非常隐秘的错误消息:

The method doubleValue(Unit<capture#27-of ?>) in the type Measurable<capture#27-of ?> is not applicable for the arguments (Unit<capture#28-of ?>)

如果有人可以解释#27-of ?内容,我将不胜感激#27-of ? (或任何其他数字)的意思,并且是否有一种优雅的方法可以消除这种情况。 到目前为止,我删除了<?>并设置了调用方法@SuppressWarnings("unchecked") (因此我传递了一个未经检查的Unit而不是Unit<?> ),并且一切都按预期进行,但是我对此感到很好奇,我觉得抑制警告不是一个好习惯(不是有点像空的捕获块吗?)。

谢谢!

编辑:添加一些代码。

(很抱歉,这很长,但是详细说明了我遇到的问题。)

我正在使用JSR-275 0.9.4版 (最新)。

所以...如果我写这个(非常愚蠢的例子):

Measure measure = Measure.valueOf("3 m");
measure = Measure.valueOf(measure.doubleValue(Unit.valueOf("km")), Unit.valueOf("km"));
System.out.println(measure);

它可以工作并打印“ 0.0030 km”。 但我得到警告“ 措施是一个原始类型引用泛型类型测量<Q>应进行参数设置。”在第一Measure发生和警告“ 类型安全:该方法的doubleValue(单位)所属的原始类型可测量引用通用。类型Measurable <Q>应该在measure.doubleValue(Unit.valueOf("km")) ”上进行参数化

看到这些警告,我想我可以这样调整(仅第一行):

Measure<Length> measure = Measure.valueOf("3 m");

然后我在分配的右侧收到错误消息“ 类型不匹配:无法从Measure <capture#1-of?>转换为Measure <Length> ”。 它(Eclipse)为我提供了将正确的部分转换为(Measure&lt;Length>) 但是然后我在右侧部分收到警告消息“ 类型安全:未经检查的从Measure <capture#1-of转换为Measure <Length> ”。 建议修复: @SuppressWarnings ,我希望避免使用(我想是出于偏执的原因)。

因此,我返回到Measure measure = Measure.valueOf("3 m"); 并尝试将通配符赋予Measure ,显然,此刻不知道“ 3 m”是什么意思。 它可以是Length ,也可以是MassTime 所以我得到:

Measure<?> measure = Measure.valueOf("3 m");

在这条线上没有警告或错误; 太棒了。 但是,在第二行:

measure = Measure.valueOf(measure.doubleValue(Unit.valueOf("km")), Unit.valueOf("km"));

我收到doubleValue错误消息:“ 类型为Measurable <capture#3-of的方法doubleValue(Unit <capture#3-of?>)不适用于参数(Unit <capture#4-of? >) “。 建议将Unit.valueOf("km")(Unit<?>) 精细。 现在,我在完全相同的位置收到错误消息:“ 类型为Measurable <capture#3-of?>的方法doubleValue(Unit <capture#3-of?>)不适用于参数(Unit <capture#5 -of?>) ”。 请注意,数字已更改,因此这不是完全相同的参数,而是相似的原因。 然后,它执行完全相同的建议,因为它已经完成了,因此不会导致代码中的任何更改。

这就是困扰我的原因。 使它工作的唯一方法似乎是@SuppressWarnings或忽略它们。 奇怪吗?

度量值类看起来像这样吗?

class Measure<T> {

  double doubleValue(Unit<T> unit) {
    ...
  }

}

在这种情况下,引用类型为Measure<?>并不意味着您可以将任何类型的Unit传递给doubleValue方法。 相反,这意味着Measure实例具有未知的泛型类型,并且将Unit传递给其doubleValue方法并不安全,因为编译器无法确保类型兼容。

通配符并不意味着“任何类型”; 它的意思是“未知类型”。


更新:

valueOf(CharSequence)返回未知类型的Measure Measure<?> 要将其安全地转换为所需的Measure类型,必须使用Measure.asType()方法。 与由Unit.valueOf(CharSequence)方法创建的目标Unit Unit.valueOf(CharSequence)

Measure<?> unknownMeasure = valueOf("3 m");
Unit<?> unknownUnit = Unit.valueOf("km");
Measure<Length> length = unknownMeasure.asType(Length.class);
Unit<Length> kilometer = unknownUnit.asType(Length.class);
length.doubleValue(kilometer);

查看Measure类文档中的示例。 它们将提供一些额外的深度。

Java泛型中的通配符表示“未知类型”。 在这里,将doubleValue()方法定义为接受Unit<something1> ,其中方法未指定something1 然后,您将一些未知的something2的值传递给调用方,它称为Unit<something2> 编译器错误消息表示没有任何东西可以保证something1something2指定相同的内容。

尝试这个:

<T> double doubleValue(Unit<T> unit)
{
    ...
}

这意味着doubleValue() 不在乎 T是什么。

为了扩展其他(出色的)答案,但是要具体一些JSR-275(我现在正在将其用于项目)。

这一点很有趣

建议修复:@SuppressWarnings,我希望避免使用(我想是出于偏执的原因)。

您是对偏执的想法是正确的,但是请考虑一下:您要告诉Measure类解析任意String ,并返回任何类型的Measure 显然,在这种情况下,您可能会或可能不会获得Measure<Length> (可能会传递“ 3 kg”),因此,留给库的唯一选择是返回Measure<?> 如果您想要一个Measure<Length> ,那么您必须以某种方式将其强制为-可能无法保证在编译时是安全的。

在这种情况下,我认为@SuppressWarnings是完全可以接受的, 假设您知道字符串将始终是有效长度。 如果不是这样,您将不可避免的ClassCastException推迟到以后,这很糟糕。

但是 ,更好的(呼啦!)JSR-275确实为您提供了解决方法,将错误处理推到了正确的位置(在获得Measure ,而不是在使用它后的某个时候)。 尝试

Measure<Length> = Measure.valueOf("3 m").asType(Length.class);

asType返回相应的Measure通用类型,或者如果解析的单元的尺寸不是length,则失败,但异常-这几乎可以肯定是您想要的,对吧?

我认为这可以解决您的问题。

我无法重现您的问题,即以下代码可以正常编译(至少使用eclipse):

static double doubleValue(Unit<?> unit) {
    return 0;
}

static void bla(Unit<?> u) {
    doubleValue(u);
}

public static void main(String[] args) {
    doubleValue(new Unit<String>());
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM