Learning about Java iterators and general data structures via means of homework.
I have built a doubly-linked list (LinkedList) which uses Nodes (LinkedList$Node) and has an Iterator (LinkedList$LinkedListIterator) All classes make use of generics.
Within LinkedListIterator's @Overridden remove() method I am making use of a method of the outer-class, i.e., the LinkedList class.
I get the following compile-time error:
./LinkedList.java:170: deleteNode(LinkedList<T>.Node<T>,LinkedList<T>.Node<T>,LinkedList<T>.Node<T>) in LinkedList<T> cannot be applied to (LinkedList<T>.Node<T>,LinkedList<T>.Node<T>,LinkedList<T>.Node<T>)
deleteNode(nodeToBeRemoved, next, prev);
My (primitive) understanding is that the types don't match up, however I cannot see how that is so.
Here is my complete class code:
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.ConcurrentModificationException;
public class LinkedList<T> implements Iterable<T> {
private Node<T> sentinel;
private long modCount; //apparently no unsigned int's in Java.
public LinkedList() {
modCount = 0;
sentinel = new Node<T>(null);
sentinel.setNext(sentinel);
sentinel.setPrev(sentinel);
}
public void append(T t) {
/*
APPEND:
...
[-----]
| |
[-1st-]
| |
inFront-> [SENTL]
| | <-- [newNode]
behind--> [-----]
| |
[-----]
...
*/
Node<T> newNode = new Node<T>(t);
Node<T> inFront = sentinel;
Node<T> behind = sentinel.prev();
//now actually insert:
insertNode(newNode, inFront, behind);
}
public void prepend(T t) {
/*
PREPEND:
...
[-----]
| |
inFront-> [-1st-]
| | <-- [newNode]
behind--> [SENTL]
| |
[-----]
| |
[-----]
*/
Node<T> newNode = new Node<T>(t);
Node<T> behind = sentinel;
Node<T> inFront = sentinel.next();
//now actually insert:
insertNode(newNode, inFront, behind);
}
public void removeHead() {
/*
REMOVE-FIRST:
...
inFront --> [-----]
| |
[-1st-] <-- *delete*
| |
behind ---> [SENTL]
| |
[-----]
| |
[-----]
...
*/
Node<T> inFront = sentinel.next().next();
Node<T> behind = sentinel;
Node<T> toDelete = sentinel.next();
// now actually delete
deleteNode(toDelete, inFront, behind);
}
private void insertNode(Node<T> newNode, Node<T> inFront, Node<T> behind) {
newNode.setNext(inFront);
newNode.setPrev(behind);
inFront.setPrev(newNode);
behind.setNext(newNode);
modCount++;
}
private void deleteNode(Node<T> toDelete, Node<T> inFront, Node<T> behind) {
inFront.setPrev(behind);
behind.setNext(inFront);
toDelete.setNext(null);
toDelete.setPrev(null);
modCount++;
}
@Override
public Iterator<T> iterator() {
return new LinkedListIterator<T>(sentinel);
}
/*
..:: MyIterator ::..
private inner class
*/
public class LinkedListIterator<T> implements Iterator<T> {
private Node<T> cursor;
private Node<T> lastReturned;
private long iterModCountPerspective;
public LinkedListIterator(Node<T> sentinel) {
cursor = sentinel.next();
lastReturned = null;
iterModCountPerspective = modCount;
}
private boolean hasBodhi() {
// bodhi: in Buddhism, bodhi is the understanding of the "true nature of things".
return (iterModCountPerspective == modCount);
}
@Override
public boolean hasNext() {
if (cursor == sentinel)
return false;
return true;
}
@Override
public T next() {
if (!this.hasNext()) {
throw new NoSuchElementException();
} else if (!hasBodhi()) {
throw new ConcurrentModificationException();
} else {
T aux = cursor.data();
lastReturned = cursor;
cursor = cursor.next();
return aux;
}
}
@Override
public void remove() {
//check we're allowed to remove:
if (lastReturned == null) {
throw new IllegalStateException();
}
if (!hasBodhi()) {
throw new ConcurrentModificationException();
}
//setup vars to perform deletion:
Node<T> nodeToBeRemoved = lastReturned;
Node<T> next = nodeToBeRemoved.next();
Node<T> prev = nodeToBeRemoved.prev();
// now delete
deleteNode(nodeToBeRemoved, next, prev);
iterModCountPerspective++;
//now setup vars for exit:
cursor = next;
lastReturned = null; // illegal to remove yet-again before first calling next()
}
}
/* ..:: Node ::..
private, compositional inner class
Interface:
void setNext(Node n) // change the Node in front of this Node
void setPrev(Node p) // change the Node behind this Node
Node next() // returns the Node in front of this Node
Node prev() // returns the Node behind this Node
T data() // returns the data stored inside this Node
*/
private class Node<T> {
private T data;
private Node<T> next;
private Node<T> prev;
public Node(T d) {
data = d;
next = null;
prev = null;
}
/*
METHOD setNext(Node<T> n)
This method takes the parameter Node
passed-in and puts it in front of this
Node.
input - Node n
output - none
eg: node4.setNext(node5);
*/
public void setNext(Node<T> n) {
next = n;
}
/*
METHOD setPrev(Node<T> n)
This method takes the parameter Node
passed-in and puts it behind of this
Node.
input - Node p
output - none
eg: node5.setPrev(node4);
*/
public void setPrev(Node<T> p) {
prev = p;
}
/*
METHOD next()
This method returns the Node in
front of this Node.
input - none
output - Node infront of this (this.next)
eg: Node nodeInFrontOfNode4 = node4.next();
*/
public Node<T> next() {
return next;
}
/*
METHOD prev()
This method returns the Node
behind of this Node.
input - none
output - Node behind of this (this.prev)
eg: Node nodeBehindOfNode4 = node4.prev();
*/
public Node<T> prev() {
return prev;
}
/*
METHOD data()
This method returns the data
inside of this Node.
input - none
output - Data inside of this Node
eg: PlanarShape shape4 = node4.data();
*/
public T data() {
return data;
}
}
}
Comp-sci student, first time poster. Thank you to all SO gurus. You've helped my peers and I many times
That is happening, because you're defining 3 different type parameters there. Whenever you declare a class as:
class X<T> {}
... you define a new type parameter T
, whether that is an inner class or outer class. So, in the below scenario:
class X<T> {
class Y<T> {
}
}
both the T's
are different. You can do something like this:
X<String> x = new X<String>();
Y<Double> y = x.new Y<Double>();
So, consider a case here:
class X<T> {
public void helloThere(T obj) { }
class Y<T> {
// Ignore any syntactical error about method calling.
public void callHelloThere(T obj) {
helloThere(obj);
}
}
}
that will certainly not work for:
y.callHelloThere(2.5);
Because then, you are passing a Double
type to a method that accepts a String
, since you instantiated X<String>
.
This is the same scenario you're facing in your example.
Solution? Change class Y<T>
to class Y
, and you're all set.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With