Search code examples
javalinked-listreferencenodes

Java, make a reference point to another reference


In Java (or any OOP language), I can make a nested class "Node", that represents some object that contains int data. I can then declare a "Node" reference with variable named "head":

public class ListNode {

    class Node {
        int value;
        Node next = null;

    public Node(int value) {
        this.value=value;
        }
    }

Node head;
}

I can then do something like:

head = new Node(42);

...which should make the "head" reference point to a new Node object with int value 42, and a reference inside of it pointing to null:

enter image description here

But how can I actually make another reference that points to the "head" reference? I don't think its possible, but it would look like this: enter image description here

I know that if I make another reference, like Node another_ref; and then do another_ref = head, all that will happen is another_ref will point to whatever head was pointing to (Node that contains 42 in this case), so I will be left with 2 references pointing at a Node object with int value = 42, and Node next reference that points to null.

I know that I can take head.next's reference, which is the Node object's reference pointing to null, and I can point it back at itself by doing head.next = head;, but it doesn't seem like I can get anything to point back to the Node head reference.

Am I missing something here? Can you not "chain" or "link" together references like this? Obviously I can create a bunch of new Nodes(integer values...) with various integer values to chain-together a linked list, but just curious about this.


Solution

  • In C++, you can have pointers to pointers; you don't have that in Java. You can simulate it though:

    Say you have the following Ref template interface:

    public interface Ref<T> {
        T get();
        void set(T newValue);
    }
    

    Your Node class could have a method that returns a reference to it's next field:

        public Ref<Node> getRefToNext() {
            return new Ref<Node>(){
                @Override
                public Node get() {
                    return next;
                }
                @Override
                public void set(Node newValue) {
                    next = newValue;
                }
            };
        }
    

    And class ListNode could have a method that returns a reference to it's head field:

    public Ref<Node> getRefToHead() {
        return new Ref<Node>(){
            @Override
            public Node get() {
                return head;
            }
    
            @Override
            public void set(Node newValue) {
                head = newValue;
            }
        };
    }
    

    Now if you want to write a method that inserts a new node while keeping the list sorted, you can do:

    public void insert(int value) {
        Ref<Node> ref = getRefToHead();
        Node node;
        while ((node = ref.get()) != null && value < node.value) {
            ref = node.getRefToNext();
        }
        Node newNode = new Node(value);
        newNode.next = node;
        ref.set(newNode);
    }
    

    But of course, it's much slower than with C++ pointers.

    UPDATE

    It allows you to reuse common code: Let's say you define a locate method as follows:

    private Ref<Node> locate(int value) {
        Ref<Node> ref = getRefToHead();
        Node node;
        while ((node = ref.get()) != null && value < node.value) {
            ref = node.getRefToNext();
        }
        return ref;
    }
    

    You can use it to find a node:

    public Node find(int value) {
        return locate(value).get();
    }
    

    And to insert a new node:

    public void insert(int value) {
        Ref<Node> ref = locate(value);
        Node newNode = new Node(value);
        newNode.next = ref.get();
        ref.set(newNode);
    }
    

    The same principle can be used for binary trees.