Java generics self-reference: is it safe? - java

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.

Related

How to easily iterate over all super classes/interfaces

What is the most elegant way to iterate over all super classes/interfaces of a given Class<?> object? I am basically looking for a recursive getSuperclass() and getInterfaces() method, collecting the whole class hierarchy.
Lets assume our inheritance looks like follows (where Cn are classes and In are interfaces):
I3
↗ ↖
C2 I1 I2
↖ ↖ ↗
C1 I0
↖ ↗
C0
It should catch all classes displayed above. If possible, the iteration order should be breadth first, so something like this:
C0 -> C1 -> I0 -> C2 -> I1 -> I2 -> I3
Is there a built in method or a library providing creating a Collection<Class<?>>, Stream<Class<?>> or an Iterator<Class<?>>?
Any help is appretiated.
Given that you already seem to use Guava, here's a solution using Guava's Graph Traversal utilities.
public static Iterable<Class<?>> getClassHierarchy(Class<?> baseClass) {
return Traverser.forGraph(
(SuccessorsFunction<Class<?>>) node -> {
Class<?> superclass = node.getSuperclass();
List<Class<?>> interfaces = Arrays.asList(node.getInterfaces());
return superclass == null ? interfaces
: Iterables.concat(interfaces, Collections.singleton(superclass));
}
).breadthFirst(baseClass);
}
This solution implements an Iterator<Class<?>>. If you are OK with using libraries, I would recommend checking out the accepted answer.
public static class HierarchyIterator implements Iterator<Class<?>> {
private Queue<Class<?>> remaining = new LinkedList<>();
private Set<Class<?>> visited = new LinkedHashSet<>();
public HierarchyIterator(Class<?> initial) {
append(initial);
}
private void append(Class<?> toAppend) {
if (toAppend != null && !visited.contains(toAppend)) {
remaining.add(toAppend);
visited.add(toAppend);
}
}
#Override
public boolean hasNext() {
return remaining.size() > 0;
}
#Override
public Class<?> next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
Class<?> polled = remaining.poll();
append(polled.getSuperclass());
for (Class<?> superInterface : polled.getInterfaces()) {
append(superInterface);
}
return polled;
}
}
If you need a Collection<Class<?>>, you can use Google Guava for:
public static Set<Class<?>> getClassHierarchy(Class<?> forClass) {
Set<Class<?>> result = new LinkedHashSet<>();
Iterators.addAll(result, new HierarchyIterator(forClass));
return result;
}
calling:
System.out.println(getClassHierarchy(LinkedList.class));
yields
[class java.util.LinkedList, class java.util.AbstractSequentialList, interface java.util.List, interface java.util.Deque, interface java.lang.Cloneable, interface java.io.Serializable, class java.util.AbstractList, interface java.util.Collection, interface java.util.Queue, class java.util.AbstractCollection, interface java.lang.Iterable, class java.lang.Object]
I take your question more or less like a game, and I noticed that the breadth first requirement is not mandatory, so here is my solution.
It uses reflection.
It uses recursion.
It uses functional programming.
It is not very long.
It implements an internal iterator - forEach style.
You need Java 9 to compile it.
It is just a programming game :)
public class ClassIterator {
public void forEachSuperclasses(final Class<?> initialClass, final Consumer<Class<?>> action) {
generateStream(initialClass).distinct().forEach(action);
}
private Stream<Class<?>> generateStream(final Class<?> clazz) {
if (clazz == null) {
return Stream.empty();
}
return Stream.concat(
Stream.concat(Stream.of(clazz), generateStream(clazz.getSuperclass())),
Arrays.stream(clazz.getInterfaces()).flatMap(this::generateStream));
}
}
How to call it:
interface I3 {};
class C2 implements I3 {};
interface I1 extends I3 {};
interface I2 {};
class C1 extends C2 {};
interface I0 extends I0, I0 {};
class C0 extends C1 implements I0 {};
void testForEachSuperclasses() {
final ClassIterator iterator = new ClassIterator();
iterator.forEachSuperclasses(C1.class, System.out::println);
}
Output:
class com.example.classiterator.C0
class com.example.classiterator.C1
class com.example.classiterator.C2
class java.lang.Object
interface com.example.classiterator.I3
interface com.example.classiterator.I0
interface com.example.classiterator.I1
interface com.example.classiterator.I2
Here's another solution without external libraries, but which still works lazily and visits every class exactly once:
public static Iterable<Class<?>> getClassHierarchy(Class<?> baseClass) {
return () -> new Iterator<Class<?>>() {
private Class<?> nextValue;
private Queue<Class<?>> remaining = new LinkedList<>(Collections.singleton(baseClass));
private Set<Class<?>> visited = new HashSet<>();
#Override
public boolean hasNext() {
while (nextValue == null && !remaining.isEmpty()) {
Optional.ofNullable(remaining.poll())
.ifPresent((Class<?> type) -> {
visited.add(type);
Stream.concat(
streamOptional(Optional.ofNullable(type.getSuperclass())),
Arrays.stream(type.getInterfaces())
).filter(visited::add)
.forEach(remaining::offer);
nextValue = type;
});
}
return nextValue != null;
}
private <T> Stream<T> streamOptional(final Optional<T> optional) {
return optional.map(Stream::of).orElse(Stream.empty());
}
#Override
public Class<?> next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
Class<?> value = this.nextValue;
this.nextValue = null;
return value;
}
};
}
Note: writing this was a pain (in Java 8), because unfortunately, there is no Optional.stream() method and Stream.generate(supplier) can't be terminated so I couldn't use it.
Here is a quick Breadth First Hierarchy transverse:
public class ClassHierarchy {
private Queue<Class<?>> queue;
//a collection of "visited" classes,
//which is also the result of the search
private Set<Class<?>> visited;
public Set<Class<?>> getClassHierarchy(Class<?> cls){
visited = new LinkedHashSet<>(); //initialize visited log
bfs(cls);
return visited;
}
//breadth first traverse on hierarchy
private void bfs(Class<?> cls) {
if(cls == null){ return; }
queue = new LinkedList<>(); //initialize queue
queue.add(cls);
while (! queue.isEmpty()) {
cls = queue.poll();
//loop over super classes
for(Class<?> nextClass : getSuperClasses(cls)){
if((nextClass != null) && visited.add(nextClass)) {
queue.add(nextClass); //add class to the queue
}
}
}
return;
}
private List<Class<?>> getSuperClasses(Class<?> cls) {
List<Class<?>> superCs = new ArrayList<>();
superCs.addAll(Arrays.asList(cls.getInterfaces()));
superCs.add(cls.getSuperclass());
return superCs;
}
private boolean isVisited(Class<?> cls) {
return !(visited.add(cls));
}
public static void main(String[] args) {
ClassHierarchy ch = new ClassHierarchy();
System.out.println(ch.getClassHierarchy(LinkedList.class));
}
}
(Please check carefully. I did not have time yet to debug and improve. Will look at it later)

Implement generic vertex and edge classes

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;
}
}

comparing generic type E node objects

I have a class
private class BSTNode<E extends Comparable<E>> implements Comparable<E> {
BSTNode<E> left, right;
E data;
with constructor and compairTo method
but when I want instantiate the BSTNode class I face problem.
public class BST {
private BSTNode<E> root;
/* Constructor */
public BST() {
root = new BSTNode<E>();
}
how should I use BSTNode in my BST class ? Thanks
Something on these lines (not full fledge or concrete):
public class BST<E extends Comparable<E>>
{
private class BSTNode<E extends Comparable<E>> implements Comparable<E> {
BSTNode<E> left, right;
E data;
#Override
public int compareTo(E o) {
return 0;//implement method here
}
}
private BSTNode<E> root;
public BST() {
root = new BSTNode<E>();//while comparing you would need to case E to comparable and call compareTo method
}
public static void main(String[] args)
{
BST<String> messages = new BST<String>();
}
}
Your class header means that your BTSNode may only be instantiated with classes E which implement the Comparable interface.
As such, you should be able to use it as below:
public class BST {
private BSTNode<Integer> root;
/* Constructor */
public BST() {
root = new BSTNode<Integer>();
}
}
Integer may be replaced with any of the other implementing classes listed here or your even own custom implementation.

Inheritance: Incompatible Generic Types with Same Bound

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;
}
}

Java binary tree which return type for iterator over nodes, interface or class?

I'm writing a class for a binary tree, and in the tree interface this function is defined:
/** Returns an iterable collection of the the nodes. */
public Iterable<Position<E>> positions();
The problem is that the type of the node is MY class implementing the position interface in the task. Not the interface itself, Position. That is why I'm having trouble returning an iterable list of the nodes.
#Override
public Iterable<Position<E>> positions() {
ArrayList<Posisjon<E>> liste = new ArrayList<Posisjon<E>>();
liste = dumpings(liste,root);
System.out.println(liste.get(0));
return (Iterable<Position<E>>) liste.Iterator(); //PROBLEM HERE!
}
I use a recursive helper function to extract the elements and add them to an ArrayList and then just return the iterator for the list. "liste" here is of type my class "Posisjon" and the expected return for the function is the interface "Position". Why can't I just use return type "Posisjon" since it is implementing interface "Position"? Nor can I change the return type because the return type is specified in the tree interface which I must implement.
Here is the interface "Position" and my class "Posisjon" in case it helps you to understand the problem. (Node interface and Node class if you will).
public interface Position<E> {
/** Return the element stored at this position. */
E element();
}
public class Posisjon<E> implements Position<E> {
private E element;
private Posisjon<E> parenten;
private Posisjon<E> rightChildren;
private Posisjon<E> leftChildren;
#Override
public E element() {
return element;
}
public E setElement(E ting){
E tmpElement = element;
this.element = ting;
return tmpElement;
}
public Posisjon<E> leftChild(){
return leftChildren;
}
public Posisjon<E> rightChild(){
return rightChildren;
}
public Posisjon<E> parent(){
return parenten;
}
public Posisjon(E element){
this.element = element;
}
public void setLeftChild(Posisjon<E> ting){
this.leftChildren = ting;
}
public void setRightChild(Posisjon<E> ting){
this.rightChildren = ting;
}
}
You want
public Iterable<? extends Position<E>> positions();
There are very good reasons why Iterable<A> does not extend Iterable<B> when A extends B. The solution in Java is to use wildcards as above.
You should define your method as:
public Iterable<? extends Position<E>> positions();

Categories

Resources