为什么我不能在接收参数化参数的方法中使用通配符?
例如,我使用方法 Measure.doubleValue(Unit unit)
,该方法返回测量的 double
值,以指定的 Unit< /代码>。如果我向它传递一个
Unit
变量,我会收到(对我来说)仍然非常神秘的错误消息:
方法 doubleValue(Unit
) 中 类型 Measurable 不适用于参数 (单元 )
如果有人能解释 #27-of ?
(或任何其他数字)的含义,以及是否存在摆脱这个的优雅方法。到目前为止,我删除了 并设置了调用方法
@SuppressWarnings("unchecked")
(因此我传递了一个未经检查的 Unit
而不是 Unit
),一切都按预期工作,但我只是对此感到好奇,而且我觉得抑制警告不是一个好的做法(是不是有点就像空的 catch 块?)。
谢谢!
编辑:添加一些代码。
(抱歉,这很长,但它详细解释了我所坚持的内容。)
所以...如果我写这个(非常愚蠢的例子):
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
。但随后我在右侧部分收到警告消息“类型安全:未检查从 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(UnitUnit.valueOf("km")
转换为 (Unit)
。美好的。现在,我在完全相同的位置收到错误消息:“Measurable
这就是困扰我的问题。让它工作的唯一方法似乎是 @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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
度量类看起来像这样吗?
在这种情况下,引用类型为
Measure
并不意味着您可以将任何类型的Unit
传递给doubleValue方法。相反,这意味着
Measure
实例具有未知的泛型类型,并且将Unit
传递给其doubleValue
方法并不安全,因为编译器无法确保类型兼容。通配符不表示“任何类型”;它的意思是“未知类型”。
更新:
valueOf(CharSequence)
返回未知类型的Measure
-Measure
。要将其安全地转换为您期望的Measure
类型,您必须使用Measure.asType()
方法。与由Unit.valueOf(CharSequence)
方法创建的目标Unit
类似。查看
Measure
类文档中的示例。他们将提供一些额外的深度。Does the measure class look something like this?
In that case, have a reference type of
Measure<?>
doesn't mean that you are allowed to pass any type ofUnit
to thedoubleValue
method. Rather, it means that theMeasure
instance has an unknown generic type, and it isn't safe to pass aUnit
to itsdoubleValue
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 ofMeasure
—aMeasure<?>
. To convert this safely to the type ofMeasure
you expect, you must use theMeasure.asType()
method. Likewise with the targetUnit
, created by theUnit.valueOf(CharSequence)
method.Look at the examples in the
Measure
class documentation. They will provide some additional depth.Java泛型中的通配符的意思是“未知类型”。此处,您将
doubleValue()
方法定义为接受Unit
,其中该方法未指定something1
。然后,您可以为某些未知的something2
传递一个调用者知道为Unit
的值。编译器错误消息意味着没有任何东西可以保证something1
和something2
指定相同的事物。试试这个:
这意味着
doubleValue()
不关心T
是什么。The wildcard in Java generics means "unknown type". Here, you define the
doubleValue()
method as accepting aUnit<something1>
where thesomething1
is not specified by the method. You then pass a value that the caller knows asUnit<something2>
for some unknownsomething2
. The compiler error message means that there is nothing which guarantees that thesomething1
and thesomething2
designate the same thing.Try this:
which means that
doubleValue()
does not care about whatT
is.为了扩展其他(优秀)答案,但要更具体一点 JSR-275(我目前正在将它用于一个项目)。
这一点很有趣
您的偏执是正确的,但想一想:您告诉
Measure
类解析任意String
,并返回一个Measure
> 任何类型。显然,在这种情况下,您可能会或可能不会获得Measure
(您可能会传递“3 kg”),因此库剩下的唯一选择是返回Measure< /代码>。如果您想要一个
Measure
,那么您必须以某种方式将其强制为一个 - 这在编译时不可能保证安全。在这种情况下,我认为 @SuppressWarnings 是完全可以接受的,假设您知道该字符串始终是有效长度。如果没有,您就会将不可避免的
ClassCastException
推迟到稍后,这是非常糟糕的。但是更好(万岁!)JSR-275 确实为您提供了解决此问题的方法,它将错误处理推到“正确”的位置(在获取
Measure
,而不是在使用之后的某个时刻)。尝试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
You're right to be paranoid, but think about it: you're telling the
Measure
class to parse an arbitraryString
, and return aMeasure
of any type. Obviously in that case you may or may not get aMeasure<Length>
(you might pass "3 kg") so the only option left to the library is returnMeasure<?>
. If you WANT aMeasure<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). TryasType
returns the appropriate generic version ofMeasure
, 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.
我无法重现您的问题,即以下编译正常(至少使用 Eclipse):
I can not reproduce your problem, i.e. the following compiles fine (at least with eclipse):