一个相对的Java新手问题。
我有一些代码可以从二维列表ObservableList<TableModel>
中创建一个可观察列表Map<Integer, TableModel>
和一个哈希图List<List<Object>>
。
我想将代码转换为适用于任何表模型的通用方法。
但是,我坚持知道如何在代码的两个位置用通用类型参数替换特定类型。有人可以帮我吗?
我当前的非通用代码如下:
//A database table is loaded into resultSet
private static List<List<Object>> resultSet = new ArrayList<>();
//...
ObservableList<TableModel> olModel = FXCollections.observableArrayList();
Map<Integer, TableModel> mapModel = new HashMap<>();
resultSet.forEach(resultRow -> {
//Load the observable list
TableModel row = new TableModel();
row.addList(resultRow);
olModel.add(row);
//Load the hash map
mapModel.put(row.getPK(), row);
});
我正尝试按以下方式“通用化”它,并指出我被卡住的地方:
//Call a generic method
loadTableOLAndHM(olModel, mapModel, resultSet);
//...
private <S, T> void loadTableOLAndHM(ObservableList<S> ol, Map<T, S> hm, List<List<Object>> rs) {
rs.forEach(resultRow -> {
S row = new [WHAT-GOES-HERE?] (); //(1) STUCK HERE
row.addList(resultRow);
ol.add( (S) row);
hm.put( (T) row.getPK(), (S) row); //(2) STUCK HERE - GETS "incompatible types" ERROR
});
}
我可以通过更改getPK()
返回Integer
而不是int
来解决(2)处的“不兼容类型”错误,但是不知道这是否是正确的方法修复它。数据库主键也将是其他表的其他数据类型,因此我不确定该怎么做。
我不知道如何解决(1)。
我已经阅读并尝试了不同的方法来投射resultSet列表,但是似乎都没有用。我尝试过的另一件事是将TableModel.class
作为参数传递给泛型方法,但不知道如何使用它。
这是一个MVCE,它显示我当前正在做的事情以及我想做的事情。如果您有时间提供帮助,我将不胜感激。谢谢!
我正在使用JavaFX8,NetBeans 8.2和Scene Builder 8.3。
package test11;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class Test11 extends Application {
private static List<List<Object>> resultSet = new ArrayList<>();
private Parent createContent() {
BorderPane content = new BorderPane();
//Load dummy data into resultSet for testing
loadDummyData();
//***********************************************************************
//WHAT I'M CURRENTLY DOING
//Observable list and hash map for the loaded table
ObservableList<TableModel> olModel = FXCollections.observableArrayList();
Map<Integer, TableModel> mapModel = new HashMap<>();
resultSet.forEach(resultRow -> {
//Load the observable list
TableModel row = new TableModel();
row.addList(resultRow);
olModel.add(row);
//Load the hash map
mapModel.put(row.getPK(), row);
});
systemOutIt("***** CURRENT WAY ******", olModel, mapModel);
olModel.clear();
mapModel.clear();
//***********************************************************************
//WHAT I WOULD LIKE TO BE ABLE TO DO
loadTableOLAndHM(olModel, mapModel, resultSet);
systemOutIt("***** NEW WAY ******", olModel, mapModel);
return content;
}
private <S, T> void loadTableOLAndHM(ObservableList<S> ol, Map<T, S> hm, List<List<Object>> rs) {
rs.forEach(resultRow -> {
//==>STUCK GENERICISING THE FOLLOWING LINE:
//original line TableModel row = new TableModel();
// S row = new [WHAT-GOES-HERE?] ();
// row.addList(resultRow);
// ol.add( (S) row);
//==>STUCK GENERICISING THE FOLLOWING LINE
//Error "incompatible types: int cannot be converted to T"
//In the Map declaration, T is Integer.
//In TableModel, getPK() returns int.
// hm.put( (T) row.getPK(), (S) row);
});
}
public static class TableModel {
private final SimpleIntegerProperty PK;
private final SimpleStringProperty dataField;
private TableModel() {
this(0, "");
}
private TableModel(int PK, String dataField) {
this.PK = new SimpleIntegerProperty(PK);
this.dataField = new SimpleStringProperty(dataField);
}
public int getPK() {
return PK.get();
}
public void setPK(int PK) {
this.PK.set(PK);
}
public IntegerProperty PKProperty() {
return PK;
}
public String getDataField() {
return dataField.get();
}
public void setDataField(String dataField) {
this.dataField.set(dataField);
}
public StringProperty dataFieldProperty() {
return dataField;
}
public void addList(List<Object> list) {
this.PK.set( (int) list.get(0));
this.dataField.set( (String) list.get(1));
}
}
private void loadDummyData(){
for ( int i=1; i<4; i++ ) {
List<Object> resultSetRow = new ArrayList<>();
resultSetRow.add(i);
resultSetRow.add("string"+i);
resultSet.add(resultSetRow);
}
}
private void systemOutIt(String whichWay, ObservableList<TableModel> ol, Map<Integer, TableModel> hm) {
System.out.println(whichWay);
System.out.println("ObservableList, size is " + ol.size());
for ( int i=0; i<ol.size(); i++ ) {
System.out.println(" ol fields = " + ol.get(i).getPK() + ", " + ol.get(i).getDataField());
System.out.println(" map dataField value = " + hm.get(ol.get(i).getPK()).getDataField());
}
}
@Override
public void start(Stage stage) throws Exception {
stage.setScene(new Scene(createContent()));
stage.setTitle("Test");
stage.setHeight(250);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
答案 0 :(得分:1)
让我们分析一下您所需的功能:
List<Object>
创建对象(这可以分为两部分:创建对象和初始化对象)。至少对于对象创建,应使用提供实现的对象。如果要将其与初始化结合使用,可以使用Function<List<Object>, S>
,如果要分开使用,请使用Supplier<S>
。
要初始化和/或获取ID,您可以使用S
本身的方法,这要求您通过一个通用的基类或包含用于执行此操作的方法的接口来限制其类型。另外,您也可以使用包含实现的对象,即BiConsumer<S, List<Object>>
和Function<S, IdClass>
。
public interface DatabaseObject<T> {
void addList(List<Object> list);
T getId();
}
private static <K, E extends DatabaseObject<? extends K>> void loadTable(ObservableList<E> ol, Map<K, E> hm, List<List<Object>> rs, Supplier<E> factory) {
for (List<Object> resultRow : rs) {
E o = factory.get();
o.addList(resultRow);
hm.put(o.getId(), o);
ol.add(o);
}
}
如果用DatabaseObject<Integer>
实现TableModel
,则可以使用如下方法:
loadTable(olModel, mapModel, resultSet, TableModel::new);
private static <S, T> void loadTable(
ObservableList<S> ol,
Map<T, S> hm,
List<List<Object>> rs,
Supplier<? extends S> factory,
BiConsumer<? super S, List<Object>> initializer,
Function<? super S, ? extends T> idExtractor) {
for (List<Object> resultRow : rs) {
S o = factory.get();
initializer.accept(o, resultRow);
hm.put(idExtractor.apply(o), o);
ol.add(o);
}
}
loadTable(olModel, mapModel, resultSet, TableModel::new, TableModel::addList, TableModel::getPK);
注意:在Map
中存储基于可变属性的对象时要小心。对存储在地图中的对象调用setPK
可能很容易破坏您的代码...