Currently as an exercise to practicing SOLID principles and basic data structures, I am trying to implement linked list type structures with as much code reuse as possible. Currently, I have:
package structures.linked;
public class SingleNode<T> {
private T data;
private SingleNode<T> next;
public SingleNode(T data, SingleNode<T> next) {
this.data = data;
this.next = next;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public SingleNode<T> getNext() {
return next;
}
public void setNext(SingleNode<T> next) {
this.next = next;
}
}
and...
package structures.linked;
public class DoubleNode<T> extends SingleNode<T> {
private DoubleNode<T> prev;
public DoubleNode(T data, DoubleNode<T> next, DoubleNode<T> prev) {
super(data, next);
this.prev = prev;
}
public DoubleNode<T> getPrev() {
return prev;
}
public void setPrev(DoubleNode<T> prev) {
this.prev = prev;
}
public DoubleNode<T> getNext() {
return (DoubleNode<T>) super.getNext();
}
public void setNext(DoubleNode<T> next) {
super.setNext(next);
}
}
It seems to me that getNext() inside of DoubleNode<T> is a violation of Liskov's substitution principle. Is this the case? Is there a better way to implement this while still reusing the code in SingleNode<T> and without breaking SOLID principles?
You can do this by using an abstract class with additional generic parameter:
public abstract class AbstracteNode<T, B extends AbstracteNode<T, ?>> {
private T data;
private B nextNode;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public void setNext(B inNextNode){
this.nextNode = inNextNode;
}
public B getNext() {
return nextNode;
}
}
Then extending it with the correct types for B:
(In case of SingleNode you do this only for the reason that developers using it have only to provide T)
public class SingleNode<T> extends AbstracteNode<T, SingleNode<T>>{}
And
public class DoubleNode<T> extends AbstracteNode<T, DoubleNode<T>> {
private DoubleNode<T> previousNode;
public DoubleNode<T> getPrevious() {
return previousNode;
}
public void setPrevious(DoubleNode<T> inPreviousNode) {
this.previousNode = inPreviousNode;
}
}
Now your test should work without code duplication and without casting:
public class Test {
public static void main(String argv[]){
SingleNode<Integer> singleNode = new SingleNode<>();
SingleNode<Integer> nextForSingle = singleNode.getNext();
DoubleNode<Double> doubleNode = new DoubleNode<>();
DoubleNode<Double> previousForDouble = doubleNode.getPrevious();
DoubleNode<Double> nextForDouble = doubleNode.getNext();
}
}
Related
This one our first class AbstractLinkedList<T>
public abstract class AbstractLinkedList<T> {
public class Node<T> {
public T value;
Node<T> next;
public Node(T value, Node<T> next) {
this.value = value;
this.next = next;
}
}
Node<T> head;
public Node<T> getHead() {
return head;
}
public void addFirst(T value) {
head = new Node<>(value, head);
}
public void addLast(T value){
if(head==null)
head = new Node<>(value, null);
else {
Node<T> node = head;
while (node.next!=null)
node = node.next;
node.next = new Node<>(value, null);
}
}
public void print(){
System.out.println(toString());
}
#Override
public String toString(){
if(head==null) return "boş";
String r="";
Node<T> node=head;
while(node!=null) {
r += node.value + (node.next!=null?" ":"");
node=node.next;
}
return r;
}
public abstract void insertInOrder(T value);
public abstract AbstractLinkedList<T> reverse();
public abstract AbstractLinkedList<T> concatenate(AbstractLinkedList<T> list);
}
This is second one Odev1LinkedList implements Comparable<T>> extends AbstractLinkedList<T>
public class Odev1LinkedList<T extends Comparable<T>> extends AbstractLinkedList<T> {
#Override
public AbstractLinkedList<T> reverse() {
Odev1LinkedList a = new Odev1LinkedList();
Node<T> root = new Node(this, head);
Node<T> iter = root;
Node<T> temp ;
a.head = null;
do {
temp = iter;
a.addFirst(temp.value);
iter = iter.next;
}while (temp !=root );
return a;
}
When I run this code example.reverse should make reverse and return LinkedList without changing ORIGINAL LinkedList.
But its return without reversing
You can't use the < operator on arbitrary objects. It's only defined for primitive numbers. Take a look into the specification.
If your object of type T implements Comparable<T> you can use head.value.compareTo(value) < 0.
If you want your objects of type T to implement Comparable<T> you have to go to your class declaration and write
public class MyLinkedList<T extends Comparable<T>> { ... }
I want to write a custom iterator for BinaryTree. This iterator should return Node<?> objects. I get compile error in file InorderIterator in lines with recursive call to fillList: fillList(currentNode.getLeft());
The error is: Error:(14, 37) java: incompatible types: rclib.Node cannot be converted to T
Can somebody explain me why my approach doesn't work? Or how to fix it
Node.java
package rclib;
public class Node<T extends Comparable<T>> {
T key;
Node<T> left;
Node<T> right;
public Node(T key, Node left, Node right) {
this.key = key;
this.left = left;
this.right = right;
}
public Node(T key) {
this(key, null, null);
}
public Node<T> getLeft() {
return left;
}
public Node<T> getRight() {
return right;
}
public T getKey() {
return key;
}
}
InorderIterator.java
package rclib;
import java.util.*;
public class InorderIterator<T extends Node<?>> implements Iterator<T> {
LinkedList<T> list;
public InorderIterator(T root) {
list = new LinkedList<T>();
fillList(root);
}
public void fillList(T currentNode) {
if (currentNode == null) return;
fillList(currentNode.getLeft());
list.add(currentNode);
fillList(currentNode.getRight());
}
#Override
public boolean hasNext() {
return !list.isEmpty();
}
#Override
public T next() {
return list.removeFirst();
}
}
AVLTree.java
package rclib;
public class AVLTree<T extends Comparable<T>> implements Iterable<Node<T>>{
private Node<T> root;
#Override
public Iterator<Node<T>> iterator() {
return new InorderIterator<Node<T>>(root);
}
}
You should perhaps do something like that:
package rclib;
import java.util.*;
public class InorderIterator<T extends Comparable<T>> implements Iterator<Node<T>> {
LinkedList<Node<T>> list;
public InorderIterator(Node<T> root) {
list = new LinkedList<Node<T>>();
fillList(root);
}
public void fillList(Node<T> currentNode) {
if (currentNode == null) return;
fillList(currentNode.getLeft());
list.add(currentNode);
fillList(currentNode.getRight());
}
#Override
public boolean hasNext() {
return !list.isEmpty();
}
#Override
public Node<T> next() {
return list.removeFirst();
}
}
You have to explicitly specify that you use Node and not ? extends Node which might finally be not qualified for the correct usage.
public static class InorderIterator<T extends Comparable<T>> implements Iterator<Node<T>> {
LinkedList<Node<T>> list;
public InorderIterator(Node<T> root) {
list = new LinkedList<>();
fillList(root);
}
public void fillList(Node<T> currentNode) {
if (currentNode == null) return;
fillList(currentNode.getLeft());
list.add(currentNode);
fillList(currentNode.getRight());
}
#Override
public boolean hasNext() {
return !list.isEmpty();
}
#Override
public Node<T> next() {
return list.removeFirst();
}
}
I am doing lab, I viewed a lot of Java Generics example, but I cannot understand it. My goal is achieving Linked Stack. It have 2 files: IntStack.java and IntNode.java. The part of these code is:
public class IntNode {
private int element = 0;
private IntNode next = null;
public IntNode(final int data, final IntNode next) {
this.element = data;
this.next = next;
}
public class IntStack {
private IntNode top = null;
public boolean isEmpty() {
return this.top == null;
}
How to convert them to generics type? I know it should use <T>,and I write these code, it is correct or not?
public class Node<T> {
private T element;
private Node<T> next = null;
public Node(final T data,final Node next) {
this.element = data;
this.next = next;
}
}
You are close. The Node parameter of the Node constructor should also be parameterized:
public class Node<T> {
private T element;
private Node<T> next = null;
public Node(final T data,final Node<T> next) {
this.element = data;
this.next = next;
}
}
I did this code:
import java.util.LinkedList;
public class Node<T> {
private T data;
private LinkedList<T> children;
public Node(T data) {
this.data = data;
this.children = new LinkedList<T>();
}
public T getData() {
return this.data;
}
public LinkedList<T> getChildren(){
return this.children;
}
}
public class Graph <T> implements Network<T> {
private Node source;
private Node target;
private ArrayList<Node> nodes = new ArrayList<Node>();
public Graph(T source,T target) {
this.source = new Node(source);
this.target = new Node(target);
}
public T source() {
return source.getData();
}
public T target() {
return target.getData();
}
I get this error on source() and target(): required T found java.lang.Object why? the type of return of getData() function it's T(generic type of return)
private Node source;
private Node target;
These should be Node<T>. Likewise on a few of the following lines. The compiler will have given you a warning. Take note of it. (When you mix raw types and generics, the Java Language Spec often requires the compiler to give up.)
Replace Node with Node<T> in your Graph class
public class Graph<T> implements Network<T> {
private Node<T> source;
private Node<T> target;
private ArrayList<Node> nodes = new ArrayList<Node>();
public Graph(T source, T target) {
this.source = new Node<T>(source);
this.target = new Node<T>(target);
}
public T source() {
return source.getData();
}
public T target() {
return target.getData();
}
}
As a homework I'm creating a SingleLinkedNode class that implements a Node interface.
Node Interface
public interface Node <T> {
static final String NULL_NODE_ERROR = "Node can't be null";
public void setNextNode(Node nextNode) throws NullPointerException;
public void setIndex(int index);
public int getIndex();
public T getData();
public Node getNextNode();
}
SingleLinkedNode class
public class SingleLinkedNode<T> implements Node<T> {
private int index;
private T data;
private SingleLinkedNode nextNode;
public SingleLinkedNode() {
}
public SingleLinkedNode(int index) {
this.index = index;
}
public SingleLinkedNode(int index, SingleLinkedNode nextNode) {
this.index = index;
this.nextNode = nextNode;
}
#Override
public void setNextNode(SingleLinkedNode nextNode) throws NullPointerException{
if (nextNode == null){
throw new NullPointerException(NULL_NODE_ERROR);
}
this.nextNode = nextNode;
}
#Override
public void setIndex (int index){
this.index = index;
}
#Override
public int getIndex() {
return this.index;
}
#Override
public T getData() {
return this.data;
}
#Override
public SingleLinkedNode getNextNode() {
return this.nextNode;
}
}
In the setNextNode(SingleLinkedNode nextNode) method of the class it says that I'm not implementing the setNextNode(Node nextNode) method of the interface even though SingleLinkedNode implements Node.
But if I leave the class method exactly as the interface one it says that Node can't be converted to SingleLinkedNode, pretty obvious.
Is there any right way of overriding this method and being sure that the method only accepts SingleLinkedNode objects as arguments?
I thought about casting but I'm not sure if that the right way.
Thank you all the solution was as follows
#Override
public void setNextNode(Node nextNode) throws NullPointerException, IllegalArgumentException{
if (nextNode == null){
throw new NullPointerException(NULL_NODE_ERROR);
}
if ( ! (nextNode instanceof SingleLinkedNode) ) {
throw new IllegalArgumentException ("Node is not SingleLinkedNode");
}
this.nextNode = (SingleLinkedNode) nextNode;
}