Java 泛型 "capture of ?"

46

我正在使用一个 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)代替“?”,但没有帮助。

有人能解释一下如何处理这个问题吗?

谢谢。

编辑:

我收集了更多信息...TreeTableColumn<S,T>CellFactory应该是Callback<TreeTableColumn<S,T>,TreeTableCell<S,T>>,但是我正在使用的TreeTableColumn是作为原始类型创建的(在库中)。

使用原始类型Callback可以正常工作。但是还有其他方法可以解决这个问题吗?


1
我尝试使用特定的类(如String)代替“?”,但是仍然没有帮助。你可能想展示你具体尝试了什么,并且你可能需要包括你如何定义匿名实例的代码。 - Thomas
`setCellFactory(new Callback<TreeTableColumn<A, ?>, TreeTableCell<A, ?>>() { @Override public TreeTableCell call(TreeTableColumn param) { return null; } });` 或者用 "String" 替代 "?"。 - kotycheese
1
setCellFactory 的签名是什么? - newacct
而且这一列是没有泛型的,是这样创建的:TreeTableColumn col = new TreeTableColumn("name")); - kotycheese
3
@kotycheese:你需要将最后一条评论中的信息编辑到你的问题中,因为那是你问题的关键所在!你正在使用原始类型,这会完全禁用泛型。(它基本上相当于将所有泛型类型参数擦除为其擦除形式,例如 Object,但有重要区别。)如果你始终使用正确地参数化的类型,则此问题应该会消失。查看此问题以获取更多信息:https://dev59.com/m3E85IYBdhLWcg3wdDIM - Daniel Pryden
显示剩余2条评论
2个回答

37

通配符代表未知类型。

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

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

在哪里

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

在这里,当调用shuffle方法时,未知的?值将绑定到新类型变量T,允许shuffle方法引用该类型。Java编译器通过捕获匿名类型变量来表示通配符的值,它称之为"capture of ?" (实际上,javac将它们称为"capture #1 of ?",因为不同的?用法可能指向不同的类型,因此具有不同的捕获)。你代码中的问题是什么?你试图调用一个方法。
<S,T> setCellFactory(Callback<TreeTableColumn<S,T>, TreeTableCell<S,T>> factory);

使用

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

在方法签名中,类型参数T代表一个单一的类型,必须由调用者提供。作为一种方便,编译器会自动尝试推断出适当的值(即类型推断)。您的编译错误意味着编译器无法这样做。
在这种情况下,这不是类型推断的缺点,因为实际上无法为T分配适当的值,因为两个?都需要是T的子类型,但编译器无法知道这两个?是否表示相同的类型,甚至是相关的类型。
要成功调用此方法,您的参数类型必须在所有T的出现中使用相同的类型。如果您已经有这样一个类型,请使用它。否则,您可以使用通配符捕获引入一个。
setCellFactory(newFactory());

在哪里

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

3
从我在什么是捕获转换oracle捕获通用文档中发现的信息来看,似乎您面临了一些问题,编译器无法找到所需的helper类,或者尝试将Object放置在那里,但您给他的内容无法安全转换。
编辑:
DEFAULT_CELL_FACTORY
如果在TreeTableColumn实例上未指定cellFactory,则默认使用此方法。目前,如果item属性是Node,则它仅在graphic属性中呈现TableCell项目属性;如果不为空,则直接调用toString()并将结果字符串设置在text属性中。

setCellFactory

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

设置属性cellFactory的值。 属性描述: 此列中所有单元格的单元格工厂。 单元格工厂负责为单个TreeTableColumn中包含的每个TreeTableCell呈现所包含的数据。 默认情况下,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()));

这些代码片段来自于这个StackOverflow主题

最后,这个链接也可能对你有帮助: TableView Cell教程

因此,这应该能够为你解决问题提供更多的帮助。


你有什么想法可以让它正常工作吗? - kotycheese
我更新了我的回答,试图帮助你解决问题。我从未使用过JavaFX或TreeTableView,所以我只能通过研究和阅读文档来帮助你 :) 希望这可以帮到你 @kotycheese - Nico
非常感谢您,您帮了我很多。我更新了我的问题并添加了更多信息,这有助于解决问题吗? - kotycheese

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接