自定义消费者和每个消费者所需的 JavaFX 泛型类型不兼容
JavaFX generics incompatible types between custom Consumer and required forEach Consumer
我在泛型方面遇到了一些问题,尽管找到了解决方法,但我不明白是什么阻止了我的代码编译。
我有一个显示 TreeTableView 的 JavaFX 项目:
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxapplication7.FXMLController">
<children>
<TreeTableView fx:id="tree" layoutX="43.0" layoutY="30.0" prefHeight="200.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<columns>
<TreeTableColumn id="date" prefWidth="399.0" text="Date" />
<TreeTableColumn id="dateType" minWidth="0.0" prefWidth="200.0" text="Type" />
</columns>
</TreeTableView>
</children>
</AnchorPane>
树仅显示一个对象数组 "Date",第一列包含字符串,第二列包含图像:
public enum DateType {
WORKDAY("work.jpg"),
HOLIDAY("holiday.jpg");
private Image image;
DateType(String imgPath) {
image = new Image(FXMLController.class.getResourceAsStream(imgPath));
}
public Image getImage() {
return image;
}
}
public class Date {
public LocalDate date;
public DateType dayType;
public String getDate() {
return date.toString();
}
public ImageView getDateType() {
return new ImageView(dayType.getImage());
}
}
我有一个自定义消费者 class 可以执行所有 TreeTableView 配置:
import java.util.Comparator;
import java.util.function.Consumer;
import javafx.scene.Node;
import javafx.scene.control.TreeTableCell;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.cell.TreeItemPropertyValueFactory;
public class TreeTableColumnConfigurator<S, E extends Enum<E>, N extends Node> implements Consumer<TreeTableColumn<S, N>> {
@Override
public void accept(TreeTableColumn<S, N> t) {
t.setCellValueFactory(new TreeItemPropertyValueFactory(t.getId()));
t.setCellFactory(column -> {
TreeTableCell cell = TreeTableColumn.DEFAULT_CELL_FACTORY.call(column);
return cell;
});
if ("dateType".equals(t.getId())) {
t.setComparator(Comparator.<N, E>comparing(
node -> (E) node.getUserData()
));
}
}
}
与 FXML 关联的控制器引发编译错误:
import java.net.URL;
import java.time.LocalDate;
import java.util.ResourceBundle;
import java.util.function.Consumer;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TreeTableView;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
public class FXMLController implements Initializable {
@FXML
private TreeTableView<Date> tree;
/**
* Initializes the controller class.
*/
@Override
public void initialize(URL url, ResourceBundle rb) {
/* working workaround */
Consumer consumer = new TreeTableColumnConfigurator<Date, DateType, ImageView>();
tree.getColumns().stream().forEach(consumer);
/* not compiling code */
tree.getColumns().stream().forEach(new TreeTableColumnConfigurator<Date, DateType, ImageView>());
}
}
方法的最后一行 "initialize" 引发了以下错误:
FXMLController.java:32: error: incompatible types: TreeTableColumnConfigurator<Date,DateType,ImageView> cannot be converted to Consumer<? super TreeTableColumn<Date,?>>
tree.getColumns().stream().forEach(new TreeTableColumnConfigurator<Date, DateType, ImageView>());
我不明白为什么同一个方法的前 2 行根本不引发任何东西,在功能上它们做同样的事情?
您的 Consumer
实例使用 raw type 当您使用原始类型时,编译器会忽略泛型类型检查,这就是它不会在此行抛出错误的原因:
Consumer consumer = new TreeTableColumnConfigurator<Date, DateType, ImageView>();
但是,如果您将上面的行更改为...
Consumer<TreeTableColumn<Date, ImageView>> consumer = new TreeTableColumnConfigurator<Date, DateType, ImageView>();
...并尝试以这种方式编译它,由于已为 Consumer
实例提供了类型参数,因此会出现与第二行相同的错误。
为什么会出现这个错误? tree.getColumns().stream()
returns 一个 Stream<TreeTableColumn<Date, ?>>
,并且 forEach
期望一个 Consumer<TreeTableColumn<Date, ?>>
。然而,重要的是要注意 TreeTableColumn<Date, ?>
和 TreeTableColumn<Date, ImageView>
并不相同 ,就像 List<Object>
和 List<?>
不同一样相同;这就是为什么,正如编译器提到的,Consumer<TreeTableColumn<Date, ImageView>>
不能转换为 Consumer<TreeTableColumn<Date, ?>>
.
虽然在这种情况下可以使用原始类型,但您应该想出一个适合您需要的通用解决方案(例如,保留通配符)(如果存在的话)。
我在泛型方面遇到了一些问题,尽管找到了解决方法,但我不明白是什么阻止了我的代码编译。
我有一个显示 TreeTableView 的 JavaFX 项目:
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxapplication7.FXMLController">
<children>
<TreeTableView fx:id="tree" layoutX="43.0" layoutY="30.0" prefHeight="200.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<columns>
<TreeTableColumn id="date" prefWidth="399.0" text="Date" />
<TreeTableColumn id="dateType" minWidth="0.0" prefWidth="200.0" text="Type" />
</columns>
</TreeTableView>
</children>
</AnchorPane>
树仅显示一个对象数组 "Date",第一列包含字符串,第二列包含图像:
public enum DateType {
WORKDAY("work.jpg"),
HOLIDAY("holiday.jpg");
private Image image;
DateType(String imgPath) {
image = new Image(FXMLController.class.getResourceAsStream(imgPath));
}
public Image getImage() {
return image;
}
}
public class Date {
public LocalDate date;
public DateType dayType;
public String getDate() {
return date.toString();
}
public ImageView getDateType() {
return new ImageView(dayType.getImage());
}
}
我有一个自定义消费者 class 可以执行所有 TreeTableView 配置:
import java.util.Comparator;
import java.util.function.Consumer;
import javafx.scene.Node;
import javafx.scene.control.TreeTableCell;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.cell.TreeItemPropertyValueFactory;
public class TreeTableColumnConfigurator<S, E extends Enum<E>, N extends Node> implements Consumer<TreeTableColumn<S, N>> {
@Override
public void accept(TreeTableColumn<S, N> t) {
t.setCellValueFactory(new TreeItemPropertyValueFactory(t.getId()));
t.setCellFactory(column -> {
TreeTableCell cell = TreeTableColumn.DEFAULT_CELL_FACTORY.call(column);
return cell;
});
if ("dateType".equals(t.getId())) {
t.setComparator(Comparator.<N, E>comparing(
node -> (E) node.getUserData()
));
}
}
}
与 FXML 关联的控制器引发编译错误:
import java.net.URL;
import java.time.LocalDate;
import java.util.ResourceBundle;
import java.util.function.Consumer;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TreeTableView;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
public class FXMLController implements Initializable {
@FXML
private TreeTableView<Date> tree;
/**
* Initializes the controller class.
*/
@Override
public void initialize(URL url, ResourceBundle rb) {
/* working workaround */
Consumer consumer = new TreeTableColumnConfigurator<Date, DateType, ImageView>();
tree.getColumns().stream().forEach(consumer);
/* not compiling code */
tree.getColumns().stream().forEach(new TreeTableColumnConfigurator<Date, DateType, ImageView>());
}
}
方法的最后一行 "initialize" 引发了以下错误:
FXMLController.java:32: error: incompatible types: TreeTableColumnConfigurator<Date,DateType,ImageView> cannot be converted to Consumer<? super TreeTableColumn<Date,?>>
tree.getColumns().stream().forEach(new TreeTableColumnConfigurator<Date, DateType, ImageView>());
我不明白为什么同一个方法的前 2 行根本不引发任何东西,在功能上它们做同样的事情?
您的 Consumer
实例使用 raw type 当您使用原始类型时,编译器会忽略泛型类型检查,这就是它不会在此行抛出错误的原因:
Consumer consumer = new TreeTableColumnConfigurator<Date, DateType, ImageView>();
但是,如果您将上面的行更改为...
Consumer<TreeTableColumn<Date, ImageView>> consumer = new TreeTableColumnConfigurator<Date, DateType, ImageView>();
...并尝试以这种方式编译它,由于已为 Consumer
实例提供了类型参数,因此会出现与第二行相同的错误。
为什么会出现这个错误? tree.getColumns().stream()
returns 一个 Stream<TreeTableColumn<Date, ?>>
,并且 forEach
期望一个 Consumer<TreeTableColumn<Date, ?>>
。然而,重要的是要注意 TreeTableColumn<Date, ?>
和 TreeTableColumn<Date, ImageView>
并不相同 ,就像 List<Object>
和 List<?>
不同一样相同;这就是为什么,正如编译器提到的,Consumer<TreeTableColumn<Date, ImageView>>
不能转换为 Consumer<TreeTableColumn<Date, ?>>
.
虽然在这种情况下可以使用原始类型,但您应该想出一个适合您需要的通用解决方案(例如,保留通配符)(如果存在的话)。