I want to define the following Java class:
public class DummyTemplate<S, D extends DummyTemplate<S,D>> {
S value;
D next;
public DummyTemplate(S value, D next) {
super();
this.value = value;
this.next = next;
}
public static DummyTemplate<String, DummyTemplate> factory(){
return new DummyTemplate<String, DummyTemplate>("wohoo", null);
}
}
created so i can subclass:
public class DummyTemplateSubclass<S, D extends DummyTemplateSubclass<S,D>> extends DummyTemplate<S, D>
(and the factoty of subclass returns DummyTemplateSubclass).
But the definition creates compile error:
Bound mismatch: The type DummyTemplate is not a valid substitute for the bounded parameter <D extends DummyTemplate<S,D>> of the type DummyTemplate<S,D>
Probably because the DummyTemplate must have parameters, how to define it then?
i get the error
it compiles howewer only :
public static<D extends DummyTemplate<String,D>> D factory()
but then i got trouble on subclass:
public static<D extends DummyTemplateSubclass<String,D>> D factory(){
Name clash: The method factory() of type DummyTemplateSubclass has the same erasure as factory() of type DummyTemplate but does not hide it
When you make a self-referencing template parameter like that, you can't use the template directly, because it's ever-expanding:
DummyTemplate<String, DummyTemplate<String, DummyTemplate<String, ...>>>
To use it, you must create a subclass:
public class DummyTemplate<S, D extends DummyTemplate<S,D>> {
S value;
D next;
public DummyTemplate(S value, D next) {
this.value = value;
this.next = next;
}
}
public class StringTemplate extends DummyTemplate<String, StringTemplate> {
public StringTemplate(String value, StringTemplate next) {
super(value, next);
}
public static StringTemplate factory() {
return new StringTemplate("wohoo", null);
}
}
Because the factory method is static and the second parameter of DummyTemplate is D extends DummyTemplate<S, D>, you need to declare a new generic type, as follows:
public static <T extends DummyTemplate<String, T>> DummyTemplate<String, T> factory() {
return new DummyTemplate<String, T>("wohoo", null);
}
Then the subclass compiles just fine:
public class DummyTemplateSubclass<S, D extends DummyTemplateSubclass<S, D>> extends DummyTemplate<S, D> {
public DummyTemplateSubclass(S value, D next) {
super(value, next);
}
public static <T extends DummyTemplateSubclass<String, T>> DummyTemplateSubclass<String, T> factorySubclass() {
return new DummyTemplateSubclass<String, T>("wohoo", null);
}
}
If you want to remove the static keyword from factory, then the code simplifies:
public class DummyTemplate<S, D extends DummyTemplate<S, D>> {
S value;
D next;
public DummyTemplate(S value, D next) {
this.value = value;
this.next = next;
}
public DummyTemplate<String, D> factory() {
return new DummyTemplate<String, D>("wohoo", null);
}
}
public class DummyTemplateSubclass<S, D extends DummyTemplateSubclass<S, D>> extends DummyTemplate<S, D> {
public DummyTemplateSubclass(S value, D next) {
super(value, next);
}
#Override
public DummyTemplateSubclass<String, D> factory() {
return new DummyTemplateSubclass<String, D>("wohoo", null);
}
}
Related
I have this simple interface:
public interface Node<E extends Node<E>>
{
public E getParent();
public List<E> getChildren();
default List<E> listNodes()
{
List<E> result = new ArrayList<>();
// ------> is this always safe? <-----
#SuppressWarnings("unchecked")
E root = (E) this;
Queue<E> queue = new ArrayDeque<>();
queue.add(root);
while(!queue.isEmpty())
{
E node = queue.remove();
result.add(node);
queue.addAll(node.getChildren());
}
return result;
}
}
I see that this is always an instance of Node<E> (by definition).
But I can't imagine a case where this is not an instance of E...
Since E extends Node<E>, shouldn't Node<E> also be equivalent to E by definition??
Can you give an example of an object that's an instance of Node<E>, but it's not an instance of E??
Meanwhile, my brain is melting...
The previous class was a simplified example.
To show why I need a self-bound, I'm adding a bit of complexity:
public interface Node<E extends Node<E, R>, R extends NodeRelation<E>>
{
public List<R> getParents();
public List<R> getChildren();
default List<E> listDescendants()
{
List<E> result = new ArrayList<>();
#SuppressWarnings("unchecked")
E root = (E) this;
Queue<E> queue = new ArrayDeque<>();
queue.add(root);
while(!queue.isEmpty())
{
E node = queue.remove();
result.add(node);
node.getChildren()
.stream()
.map(NodeRelation::getChild)
.forEach(queue::add);
}
return result;
}
}
public interface NodeRelation<E>
{
public E getParent();
public E getChild();
}
An easy example to illustrate the problem: a node of a different type of node:
class NodeA implements Node<NodeA> {
...
}
And:
class NodeB implements Node<NodeA> {
...
}
In this case, E root = (E) this would resolve to NodeA root = (NodeA) this, where this is a NodeB. And that's incompatible.
Without <E extends Node<E>>, you could have either of these cases:
Node<Integer>
where the generic type isn't a Node at all, or
Node<DifferentNode>
where the generic bounds don't match.
That said, it's not typical to see a bound this way, as Node<E> is expected to be a node that contains some value of type E, and children would be a List<Node<E>>, not a List<E>.
The problem is not in E root = (E) this. It might work well until you start iterating through result of listNodes().
That example demonstrates where exactly ClassCastException will be thrown:
public interface Node<E extends Node<E>> {
List<E> getRelatedNodes();
default List<E> getAllNodes() {
List<E> result = new ArrayList<>();
result.add((E) this); //<--that cast is not a problem because of type erasure
return result;
}
}
class NodeA implements Node<NodeA> {
public NodeA() {
}
#Override
public List<NodeA> getRelatedNodes() {
return null;
}
}
class NodeB implements Node<NodeA> {
private List<NodeA> relatedNodes;
public NodeB(List<NodeA> relatedNodes) {
this.relatedNodes = relatedNodes;
}
#Override
public List<NodeA> getRelatedNodes() {
return relatedNodes;
}
}
Execute:
List<NodeA> nodes = new NodeB(Arrays.asList(new NodeA())).getAllNodes(); //according to generic it is list of NodeA objects
for (NodeA node : nodes) { //ClassCastException will be thrown
System.out.println(node);
}
With this sort of situation it is often useful to have a getThis method that (by convention) returns this.
I would do the following
public interface Node<E extends Node<E, R>,
R extends NodeRelation<E, R>>
{
public List<R> getParents();
public List<R> getChildren();
public List<E> listDescendants() ;
}
public interface NodeRelation<E extends Node<E, R>,
R extends NodeRelation<E, R>>
{
public E getParent();
public E getChild();
}
abstract class ANode<E extends ANode<E,R>,
R extends ARelation<E,R>>
implements Node<E,R> {
abstract protected E getThis() ;
public List<E> listDescendants()
{
List<E> result = new ArrayList<>();
E root = getThis() ;
...
return result;
}
}
abstract class ARelation<E extends ANode<E,R>,
R extends ARelation<E,R>>
implements NodeRelation<E,R> {
}
class CNode extends ANode<CNode, CRelation> {
public CNode getThis() { return this ; }
...
}
class CRelation extends ARelation<CNode, CRelation> {
...
}
Although I might not bother with having both abstract class and interface layers.
I would like to implement generic graph classes. These are what I came up with:
public abstract class VertexBase<V extends VertexBase<V, E>, E extends EdgeBase<V, E>> {
public final HashMap<V, E> inEdges = new HashMap<>();
public final HashMap<V, E> outEdges = new HashMap<>();
}
public abstract class EdgeBase<V extends VertexBase<V, E>, E extends EdgeBase<V, E>> {
public final V fromVertex;
public final V toVertex;
public EdgeBase(V from, V to) {
fromVertex = from;
toVertex = to;
from.outEdges.put(to, get());
to.inEdges.put(from, get());
}
protected abstract E get();
}
Now the problem is that I have to implement Edge::get everywhere:
#Override
protected Edge get() {
return this;
}
And the compiler complains that I am calling overridable method in the constructor.
Is there a way to better implement these?
When you implement new class that extends EdgeBase, you need to replace all E type to Edge and Edge must be extends EdgeBase < V, Edge >, for example:
public class EdgeBaseImpl<V extends VertexBase<V, Edge>> extends EdgeBase<V, Edge> {
...
#Override
protected Edge get() {
return this;
}
}
So, I have this public interface NodeLevel<E extends NodeLevelEnum>, which has methods public E getParent() and public E getEnum(). An implementing abstract public class NodeLevelAbstract<E extends NodeLevelEnum> implements NodeLevel<E> delegates to instances of class A that implements public interface NodeLevelEnum<E extends NodeLevelEnum>. The last declaration should mean that instances of classes that implement NodeLevelEnum can do something with instances of classes that implement NodeLevelEnum.
Now, this is NodeLevelAbstract#getParent():
#Override
public E getParent() {
return this.getEnum().getParent();
}
Results in a compiler error (I use NetBeans 7.2, btw):
incompatible types
required: E
found: NodeLevelEnum
where E is a type-variable:
E extends NodeLevelEnum declared in class NodeLevelAbstract
To me, this means that a descendant of NodeLevelEnum is required, but NodeLevelEnum is found, which, given that the bound in Java Generics includes itself, sounds like absolute bollocks.
Why are these types incompatible? And is there any graceful way to do what I mean to do?
Thanks in advance. =)
Update 1
Btw, NodeLevelEnum#getParent() returns <E extends NodeLevelEnum>, and not NodeLevelEnum, which the error says it does.
Update 2
abstract public class NodeLevelAbstract<E extends NodeLevelEnum> implements
NodeLevel<E> {
protected E _enum;
#Override
public E getEnum() {
return this._enum;
}
#Override
public E getParent() {
return this.getEnum().getParent();
}
public static <E extends NodeLevelEnum<E>> E[] getEnumLineage(E _enum) {
ArrayList<E> ancestors = new ArrayList<>();
E currentEnum = _enum;
do {
ancestors.add(currentEnum);
currentEnum = currentEnum.getParent();
} while (currentEnum != null);
return (E[]) ancestors.toArray();
}
public static <E extends NodeLevelEnum<E>> HashMap<String, String>
getEnumLineageValueMap(
E _enum) {
HashMap<String, String> map = new HashMap<>();
for (E e : getEnumLineage(_enum)) {
map.put(e.getCode(), e.getValue());
}
return map;
}
}
public interface NodeLevel<E extends NodeLevelEnum> {
public E getEnum();
public E getParent();
}
public interface NodeLevelEnum<E extends NodeLevelEnum> {
public E getParent();
}
public interface FilestructureLevel<E extends NodeLevelEnum<E>> extends
NodeLevel<E> {
public String getPathPrefix();
}
public class FileLevel<E extends NodeLevelEnum<E>> extends NodeLevelAbstract<E>
implements FilestructureLevel<E> {
protected String _pathPrefix;
#Override
public String getPathPrefix() {
return this._pathPrefix;
}
public HashMap<String, String> getValueMap(Boolean withPath) {
return getEnumLineageValueMap(this.getEnum(), withPath);
}
public static <E extends NodeLevelEnum<E>> HashMap<String, String>
getEnumLineageValueMap(
E _enum) {
return getEnumLineageValueMap(_enum, false);
}
public static <E extends NodeLevelEnum<E>> HashMap<String, String>
getEnumLineageValueMap(
E _enum, Boolean withPath) {
HashMap<String, String> map = new HashMap<>();
FileLevelEnum[] lineage = (FileLevelEnum[]) getEnumLineage(_enum);
for (FileLevelEnum e : lineage) {
String value = !withPath ? e.getValue() : e.getPathPrefix()
+ e.getValue();
map.put(e.getCode(), value);
}
return map;
}
}
I have this class
public class Tree<T> {
//List of branches for this tree
private List<Tree<? super T>> branch = new ArrayList<Tree<? super T>>();
public Tree(T t){ this.t = t; }
public void addBranch(Tree< ? super T> src){ branch.add(src); }
public Tree<? extends T> getBranch(int branchNum){
return (Tree<? extends T>) branch.get(branchNum);
}
private T t;
}
And I am trying to create a variable out of this class using this
public static void main(String[] args){
Tree<? super Number> num2 = new Tree<? super Number>(2);
}
and it is giving me this error
Cannot instantiate the type Tree<? super Number>
While instantiating generics should be replaced with corresponding objects.
Ex:
Tree<Integer> num2 = new Tree<Integer>(2);
Wildcards ? cannot be used when creating new instances. You should change your code to something like that
import java.util.ArrayList;
import java.util.List;
public class Test1 {
public static void main(String[] args){
Tree<? super Number> num2 = new Tree<Number>(2);
num2.addBranch(new Tree<Number>(1));
Tree<? super Number> num3 = (Tree<? super Number>) num2.getBranch(0);
System.out.println(num3);
}
}
class Tree<T> {
//List of branches for this tree
private List<Tree<? super T>> branch = new ArrayList<Tree<? super T>>();
public Tree(T t){ this.t = t; }
public void addBranch(Tree<Number> src){ branch.add((Tree<? super T>) src); }
public Tree<? extends T> getBranch(int branchNum){
return (Tree<? extends T>) branch.get(branchNum);
}
public String toString(){
return String.valueOf(t);
}
private T t;
}
What signature should I have on my insert-method? I'm struggling with the generics. In a way, I want both Comparable<T> and T and I have tried with <Comparable<T> extends T>.
public class Node<T> {
private Comparable<T> value;
public Node(Comparable<T> val) {
this.value = val;
}
// WRONG signature - compareTo need an argument of type T
public void insert(Comparable<T> val) {
if(value.compareTo(val) > 0) {
new Node<T>(val);
}
}
public static void main(String[] args) {
Integer i4 = new Integer(4);
Integer i7 = new Integer(7);
Node<Integer> n4 = new Node<>(i4);
n4.insert(i7);
}
}
Not sure what you are trying to achieve, but should you not include that in the declaration of the class?
public static class Node<T extends Comparable<T>> { //HERE
private T value;
public Node(T val) {
this.value = val;
}
public void insert(T val) {
if (value.compareTo(val) > 0) {
new Node<T>(val);
}
}
}
Note: it is good practice to use <T extends Comparable<? super T>> instead of <T extends Comparable<T>>