Search code examples
javaclassgenericssetterincompatibletypeerror

Generic setter method incompatible type error


I'm a newbie to generics and I'm trying to implement a linked list using the generic class SinglyLinkedNode. When I run my setData() and setNext() methods, however, I get the following error:

.\singlyLinkedList\SinglyLinkedNode.java:13: error: incompatible types: T#1 cannot be 
converted to T#2
this.data = d;
            ^
where T#1,T#2 are type-variables:
  T#1 extends Object declared in method <T#1>setData(T#1)
  T#2 extends Object declared in class SinglyLinkedNode
.\singlyLinkedList\SinglyLinkedNode.java:21: error: incompatible types: 
SinglyLinkedNode<T#1> cannot be converted to SinglyLinkedNode<T#2>
this.next = n;
            ^
where T#1,T#2 are type-variables:
  T#1 extends Object declared in method <T#1>setNext(SinglyLinkedNode<T#1>)
  T#2 extends Object declared in class SinglyLinkedNode

It seems to me that the error is thrown because there is a potential scenario in which the types of the preexisting this.data or this.next do not match up with d or n. How can I get around this? Is there some way I can overwrite the type of T#1 (the preexisting datum) with T#2 (the new datum)? Here is the class with my constructor and my setter methods:

public class SinglyLinkedNode<T> {
  private T data;
  private SinglyLinkedNode<T> next;

  SinglyLinkedNode(T d) {
    this.data = d;
    this.next = null;
  }

  public <T> void setData(T d) {
    this.data = d;
  }

  //...

  public <T> void setNext(SinglyLinkedNode<T> n) {
    this.next = n;
  }

  //...

}

I appreciate any help you can offer. Thanks in advance!

Edit: Thanks for your help! I've removed from my methods, but I'm still getting the following errors when I run setNext() from my SinglyLinkedList class:

.\singlyLinkedList\SinglyLinkedList.java:63: error: method setNext in class SinglyLinkedNode<T#2> cannot be applied to given types;
    curr.setNext() = toBeRemoved.getNext();
        ^
  required: SinglyLinkedNode<T#1>
  found: no arguments
  reason: actual and formal argument lists differ in length
  where T#1,T#2 are type-variables:
    T#1 extends Object declared in class SinglyLinkedList
    T#2 extends Object declared in class SinglyLinkedNode
.\singlyLinkedList\SinglyLinkedList.java:79: error: method setNext in class SinglyLinkedNode<T#2> cannot be applied to given types;
    prev.setNext() = this.head;
        ^
  required: SinglyLinkedNode<T#1>
  found: no arguments
  reason: actual and formal argument lists differ in length
  where T#1,T#2 are type-variables:
    T#1 extends Object declared in class SinglyLinkedList
    T#2 extends Object declared in class SinglyLinkedNode
.\singlyLinkedList\SinglyLinkedList.java:82: error: method setNext in class SinglyLinkedNode<T#2> cannot be applied to given types;
        prev.setNext() = curr.getNext();
            ^
  required: SinglyLinkedNode<T#1>
  found: no arguments
  reason: actual and formal argument lists differ in length
  where T#1,T#2 are type-variables:
    T#1 extends Object declared in class SinglyLinkedList
    T#2 extends Object declared in class SinglyLinkedNode

So it seems to my like getNext() (from SinglyLinkedNode) and head (from SinglyLinkedList) aren't returning any values, even though they should both be returning SinglyLinkedNode objects.

Here is the code in question. I've marked where the errors arise.

public class SinglyLinkedList<T> {
  private int size;
  private SinglyLinkedNode<T> head;
  private SinglyLinkedNode<T> tail;

  SinglyLinkedList() {
    this.size = 0;
    this.head = null;
    this.tail = null;
  }

  //...

  public SinglyLinkedNode<T> remove(int i) {
    SinglyLinkedNode<T> curr = this.head;
    for(int counter = 0; counter < i; counter++) {
      curr = curr.getNext();               //<---------------
    }
    SinglyLinkedNode<T> toBeRemoved = curr.getNext();
    curr.setNext() = toBeRemoved.getNext();
    this.size--;
    return toBeRemoved;
  }

  //...

  public SinglyLinkedNode<T> remove(T d) {
    if(this.head == null) {
      return null;
    }
    if(this.head.getData() == d) {
      SinglyLinkedNode<T> toBeRemoved = this.head;
      this.head = this.head.getNext();
      return toBeRemoved;
    }
    SinglyLinkedNode<T> curr = this.head;
    SinglyLinkedNode<T> prev = null;
    prev.setNext() = this.head;           //<---------------
    while(curr.getNext() != null) {
      if(curr.getData() == d) {
        prev.setNext() = curr.getNext();  //<---------------
        return curr;
      }
    }
    return null;
  }

  //...

If anyone still comes across this post, I'd appreciate it if they could help me with this. Thanks again!

Edit: I fixed this error as well; it's

curr.setNext(toBeRemoved.getNext());

not

curr.setNext() = toBeRemoved.getNext()

Solution

  • The problem you're facing is actually really simple. Basically, you need to understand that generic methods are completely independent from generic classes.

    public <T> void setData(T d) {
    this.data = d;
    }
    
    public <T> void setNext(SinglyLinkedNode<T> n) {
        this.next = n;
    }
    

    When you put a <T> in the modifier for a method, you are making it a generic method. The type T in your generic method is different, and overriding the type T of the entire class, meaning that you can enter an object of any type and the method will use that as its local T value, which can be completely different from the global type T.

    Removing the <T> from your methods modifiers will make them regular setter methods and default to the class type T, which is guaranteed to match the required type.