为什么我不能在接收参数化参数的方法中使用通配符?

发布于 2024-08-20 02:06:17 字数 2940 浏览 4 评论 0原文

例如,我使用方法 Measure.doubleValue(Unit unit) ,该方法返回测量的 double 值,以指定的 Unit< /代码>。如果我向它传递一个 Unit 变量,我会收到(对我来说)仍然非常神秘的错误消息:

方法 doubleValue(Unit) 中 类型 Measurable不适用于参数 (单元)

如果有人能解释 #27-of ? (或任何其他数字)的含义,以及是否存在摆脱这个的优雅方法。到目前为止,我删除了 并设置了调用方法 @SuppressWarnings("unchecked") (因此我传递了一个未经检查的 Unit 而不是 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 is a raw type.References to generic type Measureshould beparameterized”,并收到警告“Type safety” :方法 doubleValue(Unit) 属于原始类型 Measurable。对泛型类型 Measurable的引用应该通过 measure.doubleValue(Unit.valueOf("km")) 进行参数化。 >。

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

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

然后我在分配的右侧部分收到错误消息“类型不匹配:无法从 Measure转换为 Measure< ;长度>”。它(Eclipse)让我将正确的部分投射到(Measure。但随后我在右侧部分收到警告消息“类型安全:未检查从 Measure到 Measure的转换”。修复建议:@SuppressWarnings 我宁愿避免(我猜是出于偏执的原因)。

因此,我回到 Measuremeasure = Measure.valueOf("3 m"); 并尝试为 Measure 提供通配符,显然,它不知道什么“3m”表示此刻。它可以是长度,也可以是质量时间。所以我得到:

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

这一行没有警告或错误;极好的。但是,在第二行:

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

我收到 doubleValue 的错误消息:“The method doubleValue(Unit) in the type Measurable不适用于参数 (Unit)”。它建议将 Unit.valueOf("km") 转换为 (Unit)。美好的。现在,我在完全相同的位置收到错误消息:“Measurable类型中的方法 doubleValue(Unit) 不适用于参数 (单元)”。请注意,数字已发生变化,因此参数不完全相同,但原因相似。然后它执行完全相同的建议,这不会导致代码发生任何更改,因为它已经完成了。

这就是困扰我的问题。让它工作的唯一方法似乎是 @SuppressWarnings 或忽略它们。是不是很奇怪?

For example, I use a method Measure.doubleValue(Unit<?> unit) which returns the double value of a measurement, expressed in the specified Unit. If I pass a Unit<?> variable to it, I get the still very cryptic (to me) error message:

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

I would appreciate if someone could explain what that #27-of ? (or any other number) means, and if there is an elegant way to get rid of this. Thus far, I remove the <?> and set the calling method @SuppressWarnings("unchecked") (so I pass an unchecked Unit instead of a Unit<?>) and everything works as desired, but I'm just curious about this, and I feel like suppressing warnings is not a good practice (isn't it a little like empty catch blocks?).

Thanks!

Edit: Adding some code.

(I'm sorry, this is quite long, but it explains in details what I'm stuck on.)

I am using JSR-275 version 0.9.4 (most recent).

So... If I write this (very dumb example):

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

It works and prints "0.0030 km". But I get warning "Measure is a raw type. References to generic type Measure<Q> should be parameterized" over the first Measure occurrence and warning "Type safety: The method doubleValue(Unit) belongs to the raw type Measurable. References to generic type Measurable<Q> should be parameterized" over measure.doubleValue(Unit.valueOf("km")).

Seeing these warnings, I thought I could adjust this way (first line only):

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

And then I get error message on right part of assignation "Type mismatch: cannot convert from Measure<capture#1-of ?> to Measure<Length>". It (Eclipse) offers me to cast the right part to (Measure<Length>). But then I get warning message over the right part "Type safety: Unchecked cast from Measure<capture#1-of ?> to Measure<Length>". Fix suggested: @SuppressWarnings which I would prefer to avoid (for paranoid reasons I guess).

So, I step back to Measure measure = Measure.valueOf("3 m"); and try to give wildcard to Measure, as obviously, it doesn't know what "3 m" means at this moment. It could be a Length, but also a Mass or a Time. So I get:

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

And no warning or error on this line; fantastic. But, on the second line:

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

I get and error message for doubleValue: "The method doubleValue(Unit<capture#3-of ?>) in the type Measurable<capture#3-of ?> is not applicable for the arguments (Unit<capture#4-of ?>)". It suggests to cast Unit.valueOf("km") as a (Unit<?>). Fine. Now I get error message at the exact same location: "The method doubleValue(Unit<capture#3-of ?>) in the type Measurable<capture#3-of ?> is not applicable for the arguments (Unit<capture#5-of ?>)". Notice that the numbers have changed, so that's not the exact same parameters, but a similar reason. Then it does the exact same suggestion which leads to no change whatsoever in the code, since it has already been done.

So that's what is bugging me. The only way to get it working seems to @SuppressWarnings or just ignore them. Isn't it strange?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

叹倦 2024-08-27 02:06:17

度量类看起来像这样吗?

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 类似。

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 类文档中的示例。他们将提供一些额外的深度。

Does the measure class look something like this?

class Measure<T> {

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

}

In that case, have a reference type of Measure<?> doesn't mean that you are allowed to pass any type of Unit to the doubleValue method. Rather, it means that the Measure instance has an unknown generic type, and it isn't safe to pass a Unit to its doubleValue method because the compiler cannot ensure that the types are compatible.

A wildcard does not mean "any type"; it means "unknown type".


Update:

The valueOf(CharSequence) returns an unknown type of Measure—a Measure<?>. To convert this safely to the type of Measure you expect, you must use the Measure.asType() method. Likewise with the target Unit, created by the Unit.valueOf(CharSequence) method.

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);

Look at the examples in the Measure class documentation. They will provide some additional depth.

恋竹姑娘 2024-08-27 02:06:17

Java泛型中的通配符的意思是“未知类型”。此处,您将 doubleValue() 方法定义为接受 Unit,其中该方法未指定 something1。然后,您可以为某些未知的 something2 传递一个调用者知道为 Unit 的值。编译器错误消息意味着没有任何东西可以保证 something1something2 指定相同的事物。

试试这个:

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

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

The wildcard in Java generics means "unknown type". Here, you define the doubleValue() method as accepting a Unit<something1> where the something1 is not specified by the method. You then pass a value that the caller knows as Unit<something2> for some unknown something2. The compiler error message means that there is nothing which guarantees that the something1 and the something2 designate the same thing.

Try this:

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

which means that doubleValue() does not care about what T is.

家住魔仙堡 2024-08-27 02:06:17

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

这一点很有趣

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

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

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

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

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

asType 返回 Measure 的适当通用版本,或者如果解析单位的维度不是长度,则失败并抛出异常 - 这几乎肯定是您想要的,对吧?

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

To expand on the other (excellent) answers, but be a bit more JSR-275 specific (I'm using it for a project at the moment).

This bit is interesting

Fix suggested: @SuppressWarnings which I would prefer to avoid (for paranoid reasons I guess).

You're right to be paranoid, but think about it: you're telling the Measure class to parse an arbitrary String, and return a Measure of any type. Obviously in that case you may or may not get a Measure<Length> (you might pass "3 kg") so the only option left to the library is return Measure<?>. If you WANT a Measure<Length>, then you have to coerce it to one somehow -- this can't possibly be guaranteed safe at compile-time.

In this case, I would argue that @SuppressWarnings is perfectly acceptable, assuming you know that the string will always be a valid length. If not, you're delaying an inevitable ClassCastException until later, which is pretty bad.

But even better (hooray!) JSR-275 does give you a way around this, which pushes the error handling to the 'right' place (at the time of obtaining the Measure, not at some point afterwards when it's used). Try

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

asType returns the appropriate generic version of Measure, or fails with an exception if the dimension of the parsed unit is NOT length -- this is almost certainly what you want, right?

I think this solves your problem.

花桑 2024-08-27 02:06:17

我无法重现您的问题,即以下编译正常(至少使用 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>());
}

I can not reproduce your problem, i.e. the following compiles fine (at least with 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>());
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文