我有以下课程:
class TreeItem<T extends TreeItem<?>>{
private final ObservableList<T> childs;
private T parent;
public void addChild(T unit){
childs.add(unit);
unit.setParent(this);
}
public <T> void setParent(T parent){
this.parent = parent;
}
}
我在setParent上收到此消息:
不兼容的类型。
必填: T
发现: T
我该如何解决这个问题?
答案 0 :(得分:4)
Rewrite this:
public <T> void setParent(T parent){
this.parent = parent;
}
With this:
public void setParent(T parent){
this.parent = parent;
}
Also I would suggest to remove the wildcare in the class name declaration, as the code would not compile.
So replace this:
class TreeItem<T extends TreeItem<?>>
With this:
class TreeItem<T extends TreeItem>
You have a final variable in your class. So it should be initialized either in constructor or inline. As long as you use generic variable and generic type is resolved when you instantiate a new object, the right way to do is to initialize it in constructor like this:
public TreeItem(ObservableList<T> childs) {
this.childs = childs;
}
When you are done with the above proposed changes you may notice that the compiler warns you with the message: Unchecked call to 'setParent(T)'
. That means that the compiler does not guarantee the code is safe during runtime and possible heap pollution may occure.
I will illustrate it with an example. The following code while running ends up with ClassCastException
as we set parent
variable with the type which is not T
(it is possible due to type erasure).
class ChildTreeItem<T extends TreeItem> extends TreeItem<T> {
public ChildTreeItem(ObservableList childs) {
super(childs);
}
}
public class TreeItem<T extends TreeItem>{
private final ObservableList<T> childs;
private T parent;
public TreeItem(ObservableList<T> childs) {
this.childs = childs;
}
public void addChild(T unit){
childs.add(unit);
unit.setParent(this);
}
public void setParent(T parent){
this.parent = parent;
}
public T getParent() {
return parent;
}
public static void main(String[] args) {
ChildTreeItem<ChildTreeItem> treeItem =
new ChildTreeItem<>(new ObservableSequentialListWrapper<>(new ArrayList<>()));
TreeItem<ChildTreeItem> parentItem =
new TreeItem<>(new ObservableSequentialListWrapper<>(new ArrayList<>()));
parentItem.addChild(treeItem);
List<ChildTreeItem> itemList = new ArrayList<>();
itemList.add(treeItem.getParent()); //<------------------- Heap pollution
ChildTreeItem childTreeItem = itemList.get(0); //<-------- ClassCastException
}
}
The possible solution to this problem is to not parametrize the variable parent
but to make it TreeItem
type:
public class TreeItem<T extends TreeItem>{
private final ObservableList<T> childs;
private TreeItem parent;
public TreeItem(ObservableList<T> childs) {
this.childs = childs;
}
public void addChild(T unit){
childs.add(unit);
unit.setParent(this);
}
public void setParent(TreeItem parent){
this.parent = parent;
}
public TreeItem getParent() {
return parent;
}
}
Hope this helps.
答案 1 :(得分:0)
Since you have define already in your class level of Generic type. It is not clear why you put before your setParent function. But let's assume you want to define a generic type in function level, then when you call it, you need to specify the type
Ex:
TreeItem<String> treeItem = new TreeItem<String>();
treeItem.<String>setParent("something");