英文:
Preventing certain moves using ValueSelector results in ClassCastException
问题
我有一个名为 Lecture
的类,其中包含一个 startTime
计划变量和一个固定的持续时间。我尝试筛选掉导致结束时间超过16:00的移动。
我已经编写了一个选择过滤器:
public class LectureOutOfBoundsSelectionFilter
implements SelectionFilter< Schedule, Lecture > {
@Override
public boolean accept(ScoreDirector< Schedule > sd, Lecture lecture) {
return !lecture.isOutOfBounds();
}
}
我将其配置如下:
<changeMoveSelector>
<filterClass>package.PinnedTimeslotChangeMoveFilter</filterClass>
<valueSelector>
<filterClass>packager.LectureOutOfBoundsSelectionFilter</filterClass>
</valueSelector>
</changeMoveSelector>
但我遇到了与 Lecture
中不同计划变量相关的类转换异常。我尝试添加 variableName="startTime"
,但这触发了不同的类转换异常。
我是否在正确的方向上,variableName
属性实际上是如何工作的?
英文:
I have a Lecture
class with a startTime
planning variable and a fixed duration. I'm trying to filter out moves that causes the end time to go past 16:00.
I have written a selection filter:
public class LectureOutOfBoundsSelectionFilter
implements SelectionFilter<Schedule, Lecture> {
@Override
public boolean accept(ScoreDirector<Schedule> sd, Lecture lecture) {
return !lecture.isOutOfBounds();
}
}
Which I configure as follows
<changeMoveSelector>
<filterClass>package.PinnedTimeslotChangeMoveFilter</filterClass>
<valueSelector>
<filterClass>packager.LectureOutOfBoundsSelectionFilter</filterClass>
</valueSelector>
</changeMoveSelector>
But I'm getting a class cast exception related to a different planning variable in Lecture
. I've tried adding variableName="startTime"
but this triggers a different class cast exception.
Am I on the right track here, and how does the variableName
attribute actually work?
答案1
得分: 1
I'll start off your additional comment, where you explain further:
> With variableName="startTime"
I'm getting java.lang.ClassCastException: class package.ImmutableTimeslot cannot be cast to class package.Lecture
. Without variableName set, I get java.lang.ClassCastException: class package.Room cannot be cast to class package.Lecture
.
There is an explanation for this behavior, although it is not really very intuitive:
- 当您在值选择器上没有设置变量名时,两种变量类型都会传递到过滤器。在这种情况下,
ImmutableTimeslot
和Room
。由于您的过滤器期望一个Lecture
,两者之一会引发异常。 - 当您指定选择器的变量名为
startTime
时,这不再会触发对room
变量值的值选择器;因此,您会得到ImmutableTimeslot
与Lecture
不匹配的异常。
在这两种情况下,问题似乎是您的过滤器期望 Lecture
实例(实体),但求解器发送的是 ImmutableTimeslot
或 Room
(计划变量的值)。这可以说是值选择器的正确行为(强调“值”这个词)。
我之所以称之为“不太直观”的原因有两个部分:
- 无论应用于移动选择器、实体选择器还是值选择器,都始终需要相同的
SelectionFilter
接口。因此,根据您打算使用它的位置,所需的通用类型不同,这令人困惑(分别是移动、实体或值)。 - 在多个变量的情况下(就像您的情况),如果在选择器上不指定
variableName
,则泛型参数需要为Object
,因为该过滤器将接收两种类型的值,这是避免您遇到的异常的唯一方法。
总的来说,这不是最佳的设计;它来自2012年,由于保持向后兼容性并且我们实际上不鼓励使用选择过滤器,它一直没有改变,一直延续到现在。
英文:
I'll start off your additional comment, where you explain further:
> With variableName="startTime"
I'm getting java.lang.ClassCastException: class package.ImmutableTimeslot cannot be cast to class package.Lecture
. Without variableName set, I get java.lang.ClassCastException: class package.Room cannot be cast to class package.Lecture
.
There is an explanation for this behavior, although it is not really very intuitive:
- When you put the filter on the value selector without a variable name, both variable types will reach the filter. In this case
ImmutableTimeslot
andRoom
. Since your filter expects aLecture
, either of the two throws the exception. - When you specify the selector's variable name to be
startTime
, this no longer triggers the value selector on values of theroom
variable; therefore, you are getting an exception whereImmutableTimeslot
doesn't matchLecture
.
In both cases, the problem appears to be that your filter is expecting Lecture
instances (the entities), but the solver is sending either ImmutableTimeslot
or Room
(values of the planning variables). This is arguably the correct behavior of a value selector (emphasis on the word "value").
The reason why I'm calling this "not really intuitive" comes in two parts:
- The same
SelectionFilter
interface is always required, regardless if applied to a move selector, an entity selector or a value selector. So, based on where you intend to use it, the generic type required is different and that is confusing. (A move, an entity or a value respectively.) - In cases with multiple variables (such as yours) without specifying a
variableName
on the selector, the generic parameter needs to beObject
, because that filter will be receiving both types of values and that is the only way to avoid the exception you are getting.
All in all, not the best design; it comes from 2012 and due to maintaining backwards compatibility and us actually discouraging the use of selection filters, it has survived unchanged until the present day.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论