>我有一个带有泛型参数的方法:
public static void addActionColumnAndSetSelectionListener(Grid<? extends UpdatableRecord<?>> grid,
EditDialog<? extends UpdatableRecord<?>> dialog,
Callback afterSave, Supplier<UpdatableRecord<?>> onNewRecord,
Consumer<? extends UpdatableRecord<?>> insteadOfDelete) {
Button buttonAdd = new Button(grid.getTranslation("Add"));
buttonAdd.addClickListener(event -> dialog.open(onNewRecord.get(), afterSave));
grid.addComponentColumn(record -> {
Button delete = new Button(grid.getTranslation("Delete"));
delete.addThemeVariants(ButtonVariant.LUMO_ERROR);
delete.addClickListener(event -> {
getBean(TransactionTemplate.class).executeWithoutResult(transactionStatus -> {
try {
if (insteadOfDelete != null) {
insteadOfDelete.accept(record);
} else {
getBean(DSLContext.class).attach(record);
}
record.delete();
} catch (DataAccessException e) {
Notification.show(e.getMessage());
}
});
});
HorizontalLayout horizontalLayout = new HorizontalLayout(delete);
horizontalLayout.setJustifyContentMode(FlexComponent.JustifyContentMode.END);
return horizontalLayout;
}).setTextAlign(ColumnTextAlign.END).setHeader(buttonAdd);
grid.addSelectionListener(event -> event.getFirstSelectedItem().ifPresent(record -> dialog.open(record, afterSave)));
}
问题是行insteadOfDelete.accept(record);
没有编译:
Error:(47, 52) java: incompatible types: org.jooq.UpdatableRecord<capture#1 of ?> cannot be converted to capture#2 of ? extends org.jooq.UpdatableRecord<?>
我不明白这个问题。如果我改变
Consumer<? extends UpdatableRecord<?>> insteadOfDelete
自
Consumer<UpdatableRecord<?>> insteadOfDelete
它编译。
递归泛型的乐趣...在UpdatableRecord
类型层次结构中使用它们可以被视为jOOQ的设计缺陷。应在方法的泛型类型变量中捕获通配符。虽然在使用? extends UpdatableRecord<?>
甚至只是UpdatableRecord<?>
时它可能在某种程度上起作用,但我认为使用<R>
类型变量,您将获得更干净的代码。
这可能有效(我只更改了参数并添加了<R>
类型变量,没有别的(:
public static <R extends UpdatableRecord<R>> void addActionColumnAndSetSelectionListener(
Grid<R> grid,
EditDialog<R> dialog,
Callback afterSave,
Supplier<R> onNewRecord,
Consumer<R> insteadOfDelete
) {
Button buttonAdd = new Button(grid.getTranslation("Add"));
buttonAdd.addClickListener(event -> dialog.open(onNewRecord.get(), afterSave));
grid.addComponentColumn(record -> {
Button delete = new Button(grid.getTranslation("Delete"));
delete.addThemeVariants(ButtonVariant.LUMO_ERROR);
delete.addClickListener(event -> {
getBean(TransactionTemplate.class).executeWithoutResult(transactionStatus -> {
try {
if (insteadOfDelete != null) {
insteadOfDelete.accept(record);
} else {
getBean(DSLContext.class).attach(record);
}
record.delete();
} catch (DataAccessException e) {
Notification.show(e.getMessage());
}
});
});
HorizontalLayout horizontalLayout = new HorizontalLayout(delete);
horizontalLayout.setJustifyContentMode(FlexComponent.JustifyContentMode.END);
return horizontalLayout;
}).setTextAlign(ColumnTextAlign.END).setHeader(buttonAdd);
grid.addSelectionListener(event -> event.getFirstSelectedItem().ifPresent(
record -> dialog.open(record, afterSave)));
}
此外,我还删除了各个方法参数的协方差,因为我认为您可能不需要它。否则,请记住Supplier
是协变的,Consumer
是逆变的。这个答案在这里很好地解释了它。这解释了你的观察,当你有一个不变的消费者时,事情突然编译了。