Java泛型“捕获?”

时间:2016-10-24 11:30:48

标签: java generics wildcard capture

我正在使用TreeTable,在更换单元格工厂时,我需要传递

Callback<TreeTableColumn<A, capture of ?>, TreeTableCell<A, capture of ?>>

其中A是我正在使用的课程,但我不知道如何使用“捕获?”

我试图创建

new Callback<TreeTableColumn<A, ?>, TreeTableCell<A, ?>>

但IDEA显示警告

setCellFactory(Callback<TreeTableColumn<A, capture<?>>, TreeTableCell<A, capture<?>>>) in TreeTableColumn cannot be applied to (anonymous Callback<TreeTableColumn<A, ?>, TreeTableCell<A, ?>>)

我尝试使用特定的类(如String)而不是“?”同样,但没有任何帮助。

有人可以向我解释如何使用它吗?

谢谢。

编辑:

我收集了更多信息.. CellFactory的{​​{1}}应为TreeTableColumn<S,T>Callback<TreeTableColumn<S,T>,然而,我正在使用的TreeTableColumn已创建作为原始类型(在库中)。

使用原始类型回调有效。但是,还有其他选择如何解决这个问题吗?

2 个答案:

答案 0 :(得分:13)

通配符表示未知类型。

通配符捕获是将通配符类型的值绑定到新类型变量的过程。例如:

List<?> list = ...;
shuffle(list);

,其中

<T> void shuffle(List<T> list) {
    ...
}

这里,?的未知值在调用T方法时绑定到新类型变量shuffle,允许shuffle方法引用该类型。

Java编译器通过在匿名类型变量中捕获它来内部表示通配符的值,它称之为“捕获?” (实际上,javac称它们为“捕获#1?”,因为?的不同用法可能引用不同的类型,因此具有不同的捕获方式)。

好的,你的代码有什么问题?您正在尝试调用方法

<S,T> setCellFactory(Callback<TreeTableColumn<S,T>, TreeTableCell<S,T>> factory);

Callback<TreeTableColumn<S,?>, TreeTableCell<S, ?>> factory;

在方法签名中,类型参数T代表单个类型,必须由调用者提供。为方便起见,编译器自动尝试推断出合适的值( - &gt;类型推断)。编译错误意味着编译器无法执行此操作。

在这种情况下,这不是类型推断的缺点,因为实际上不可能为T分配合适的值,因为?都需要是T的子类型但是编译器无法知道两个?代表相同类型,甚至是相关类型。

要成功调用此方法,您的参数类型必须对所有出现的T使用相同的类型。如果您已经有这样的类型,请继续使用它。否则,您可以使用通配符捕获引入一个:

setCellFactory(newFactory());

,其中

<S,T> Callback<TreeTableColumn<S,T>, TreeTableCell<S,T>> newFactory() {
    return new Callback<TreeTableColumn<S,T>, TreeTableCell<S,T>> {
        ...
    }
}

答案 1 :(得分:2)

从我发现的 what is a capture conversionoracle capture generic docs 看起来你遇到了一些问题,编译器无法找到所需的辅助类,或者尝试将Object放在那里,但是你给他的东西不能安全转换。

编辑:

  

<强> DEFAULT_CELL_FACTORY

     

public static final Callback<TreeTableColumn<?,?>,TreeTableCell<?,?>>

     

如果在TreeTableColumn实例上没有指定cellFactory,那么   这个将默认使用。目前它只是呈现   如果项是a,则在图形属性中使用TableCell项属性   节点,或者它只是调用toString()如果它不为null,设置   结果字符串在text属性中。

  

<强> setCellFactory

     

public final void setCellFactory(Callback<TreeTableColumn<S,T>,TreeTableCell<S,T>> value)

     

设置属性cellFactory的值。   楼盘简介:   此列中所有单元格的单元工厂。单元工厂负责为每个TreeTableCell渲染包含在单个TreeTableColumn中的数据。   默认情况下,TreeTableColumn使用默认单元工厂,但可以使用自定义实现替换它,例如以不同方式显示数据或支持编辑。有很多关于在别处创建自定义单元工厂的文档(例如参见Cell和TreeTableView)。

     

最后,javafx.scene.control.cell包中有许多预先构建的单元工厂。

取自Java 8 API Doc

所以这样的事情应该朝着正确的方向发展:

public static <S> Callback<TableColumn<S,String>, TableCell<S,String>> forTableColumn() {
   return forTableColumn(new DefaultStringConverter());
}

或类似的东西,取决于你想要给予细胞的确切内容。

setCellFactory(TextFieldTableCell.<DataModel, Integer>forTableColumn(new IntegerStringConverter()));

这些代码段取自This StackOverflow Thread

最后这个链接也可以帮到你: TableView Cell Tutorial

所以这应该会让你更加清楚地了解可能导致问题的原因。