2

例如,我使用一种方法Measure.doubleValue(Unit<?> unit)返回double测量值,用指定的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 ?(或任何其他数字)的含义,以及是否有一种优雅的方法来摆脱这个,我将不胜感激。到目前为止,我删除了<?>并设置了调用方法@SuppressWarnings("unchecked")(所以我通过了 uncheckedUnit而不是 a Unit<?>)并且一切都按预期工作,但我只是对此感到好奇,我觉得抑制警告不是一个好习惯(不是它有点像空的 catch 块?)。

谢谢!

编辑:添加一些代码。

(对不起,这很长,但它详细解释了我坚持的内容。)

我正在使用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”。但我收到警告“ Measure 是原始类型。对泛型类型 Measure<Q> 的引用应该参数化”超过第一次Measure出现和警告“类型安全:方法 doubleValue(Unit) 属于原始类型 Measurable。对泛型类型的引用Measurable<Q> 应该被参数化为“over 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”是什么意思。它可以是 a Length,也可以是 aMass或 a Time。所以我得到:

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或只是忽略它们。是不是很奇怪?

4

4 回答 4

3

度量类看起来像这样吗?

class Measure<T> {

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

}

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

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


更新:

valueOf(CharSequence)返回未知类型的Measure—a Measure<?>。要将其安全地转换为Measure您期望的类型,您必须使用该Measure.asType()方法。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类文档中的示例。他们将提供一些额外的深度。

于 2010-01-27T23:23:52.287 回答
2

Java 泛型中的通配符表示“未知类型”。在这里,您将doubleValue()方法定义为接受方法未指定的Unit<something1>a 。something1然后,您传递一个调用者知道的值作为Unit<something2>一些 unknown something2。编译器错误消息意味着没有任何东西可以保证 thesomething1something2指定相同的东西。

试试这个:

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

这意味着doubleValue() 不关心是什么T

于 2010-01-27T22:36:58.280 回答
1

要扩展其他(优秀)答案,但要更具体一点 JSR-275(我目前正在将它用于一个项目)。

这一点很有趣

修复建议:@SuppressWarnings 我宁愿避免(我猜是出于偏执的原因)。

你偏执是对的,但想想看:你是在告诉Measure班级解析一个任意的String,并返回Measure任何类型的 a 。显然,在这种情况下,您可能会或可能不会得到 a Measure<Length>(您可能会传递“3 kg”),所以图书馆剩下的唯一选择是 return Measure<?>。如果你想要一个Measure<Length>,那么你必须以某种方式强制它为一个 - 这不可能在编译时保证安全。

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

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

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

asTypeMeasure如果解析单元的维度不是长度,则返回适当的通用版本,或者失败并出现异常——这几乎肯定是你想要的,对吧?

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

于 2010-01-28T04:50:02.740 回答
0

我无法重现您的问题,即以下编译良好(至少使用 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>());
}
于 2010-01-27T22:48:59.047 回答