Reputation: 21
I try to implement Generic linked list but I get an error:
required type T, Provided Object in the line T val = head.val;
DDLinkedList class:
public class DDLinkedList <T>{
private ListElement head;
private ListElement tail;
protected <T> void addToHead(T val){
if (this.isEmpty()){
head = new ListElement(val,head);
tail = head;
}else {
head = new ListElement(val, head);
head.next.prev = head;
}
}
protected <T> T removeFromHead(){
if(this.isEmpty()){
return null;
}
T val = head.val;
head = head.next;
return val;
}
}
the List Element class:
public static class ListElement<T> {
private ListElement next;
private ListElement prev;
private T val;
public ListElement(){
this(null, null, null);
}
public ListElement(T val){
this(val, null, null);
}
public ListElement(T val, ListElement next, ListElement prev){
this.val = val;
this.next = next;
this.prev = prev;
}
}
What can be the problem?
Upvotes: 1
Views: 7844
Reputation: 7290
Let's have a look at your code (and the changes I suggest regarding Generics):
public class DDLinkedList<T> {
private ListElement<T> head;
private ListElement<T> tail;
Here, you want head
and tail
to be specific ListElement
s containing a T
value, not just any raw ListElement
. That's what ListElement<T>
expresses.
protected void addToHead(T val){
Don't use protected <T> void addToHead(T val){
, as the <T>
introduces a new variable type, incidentally also called T
, but unrelated to the intended list element type T
.
if (this.isEmpty()){
head = new ListElement<T>(val, head, null);
You'll want to declare that you create a ListElement
of element type T
. (Your version surely gives warnings on using raw types.) And there's no two-argument constructor for ListElement
.
tail = head;
}else {
head = new ListElement<T>(val, head, null);
head.next.prev = head;
}
}
protected T removeFromHead(){
if(this.isEmpty()){
return null;
}
T val = head.val;
As a result of declaring private ListElement<T> head;
, the compiler now knows that head.val
is of type T
head = head.next;
return val;
}
}
public static class ListElement<T> {
private ListElement<T> next;
private ListElement<T> prev;
In a list with element type T
, the next
and prev
ListElement
s will surely also contain T
.
private T val;
public ListElement(){
this(null, null, null);
}
public ListElement(T val){
this(val, null, null);
}
public ListElement(T val, ListElement<T> next, ListElement<T> prev){
this.val = val;
this.next = next;
this.prev = prev;
}
}
Then, there is the issue that you have private fields in ListElement
, but access them from outside. A solution is to keep the fields private, to introduce getters and setters for the fields, and to use the getters and setters instead of the direct field access. Or even better, move the linking logic into the ListElement
class, so you don't need the setters at all.
Upvotes: 1
Reputation: 4460
Change the following lines
private ListElement<T> head;
private ListElement<T> tail;
Upvotes: 0
Reputation: 6473
The error is caused because you have redeclared the type T
in removeFromHead()
; T
is already declared in the class declaration so the compiler is trying to equate two different types of the same name.
Redeclare the method to: protected T removeFromHead()
and that error should go away. (And you also have the same issue in the other class method.)
As the commenters have noted, you have also missed the type parameter T
off all occurrences of ListElement
within the declaration of ListElement
, which generates separate warnings.
Upvotes: 1