I tried to create a class the defines a tree, where the tree nodes can be tagged, and the tags are inherited by the descendant nodes, basically creating a taxonomy of things.
Then I had the idea, that sometimes tags shouldn't be inherited (exceptions like penguins can't fly), but I wanted to create a separate class for this, as there might be applications where the overhead of handling exceptions is wasted. So I created another class, NodeWithException. I wanted this tree to be of the same type of nodes, but have it as extensible as Node was.
My problem is with the line of
public class NodeWithException<TYPE_PARAM extends NodeWithException<?>>
It will introduce raw types. But if I don't put "?" there, I would go down in a rabbit hole of infinite recursion. Is there a more elegant solution that avoids using raw types?
Code can be read below or downloaded from here: https://drive.google.com/file/d/0Bzgrcf36fidPWVlFdk9qdmdfT1E/view?usp=sharing
My classes:
Node.java
package tags_and_tax.model;
import java.util.HashSet;
import java.util.Set;
public class Node<TYPE_PARAM extends Node> {
TYPE_PARAM parent = null;
final Set<TYPE_PARAM> children = new HashSet<>();
final Set<Tag> tags = new HashSet<>();
public void addChild(TYPE_PARAM child){
child.setParent(this);
}
public void setParent(TYPE_PARAM newParent){
if (parent != null){
parent.children.remove(this);
}
parent = newParent;
newParent.children.add(this);
}
public Set<Tag> getAllTags(){
Set<Tag> result = new HashSet<>(tags);
TYPE_PARAM node = parent;
while(node != null){
result.addAll(node.tags);
node = (TYPE_PARAM) node.parent;
}
return result;
}
public Set<Tag> getTags(){
return tags;
}
}
NodeWithExceptions.java
package tags_and_tax.model;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;
@SuppressWarnings("rawtypes")
public class NodeWithException<TYPE_PARAM extends NodeWithException<?>> extends Node<TYPE_PARAM> {
final Set<Tag> removeTags = new HashSet<>();
public Set<Tag> getRemoveTags() {
return removeTags;
}
@SuppressWarnings("unchecked")
@Override
public Set<Tag> getAllTags(){
Set<Tag> result = new HashSet<>(tags);
LinkedList<TYPE_PARAM> parents = new LinkedList<>();
parents.add((TYPE_PARAM) this);
TYPE_PARAM node = parent;
while(node != null){
parents.add(node);
node = (TYPE_PARAM) node.parent;
}
while(parents.size() > 0){
node = parents.removeLast();
result.addAll(node.tags);
result.removeAll(node.removeTags);
}
return result;
}
}
Tag.java (this isn't that interesting, only here for the sake of completeness)
package tags_and_tax.model;
import java.util.HashMap;
import java.util.Map;
/**
* Should be a "singletons" i.e. no two instances with the same name. Why not
* use enums? Because they can't be created during runtime.
* */
public class Tag {
private final String name;
private final int id;
private static int idCounter = 0;
static Map<String, Tag> map = new HashMap<>();
private Tag(String name) {
this.name = name;
id = idCounter;
idCounter++;
}
public String getName() {
return name;
}
/** Only for debugging purposes (to see that things are really singletons.) */
public int getId() {
return id;
}
public static Tag getTag(Enum enum1) {
return getTag(enum1.name());
}
public static Tag getTag(String str) {
Tag result = map.get(str);
if (result == null) {
result = new Tag(str);
map.put(str, result);
}
return result;
}
/** Only needed if deserialization messes things up. */
@Override
public boolean equals(Object tag2) {
if (tag2 == null)
return false;
return name.equals(((Tag) tag2).name);
}
/* Generated by IDE */
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public String toString() {
return "name: " + name;
}
}
I downloaded your code and I can't even compile Test1
class because of error: Error:(9, 27) java: type argument tags_and_tax.model.NodeWithException is not within bounds of type-variable TYPE_PARAM
As @immibis already answered you can use NodeWithException<T extends NodeWithException<T>>
then you will get sth similar to Enum
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.