Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does the javac error "(x) cannot be applied to (y)", happen when both parameters and arguments match up? (inner-class calling outer-class method)

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

like image 208
Boy George Avatar asked Apr 25 '16 05:04

Boy George


1 Answers

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.

like image 108
Rohit Jain Avatar answered Nov 04 '22 11:11

Rohit Jain