I have spent a few hours reading Java documentation/Stackoverflow answers on generics and type erasure but I still don't understand the topic fully. The problem is implementing the following simple interface:
public interface Stack {
void push(Object element); }
I have implemented this in a simple generic class:
public class NodeStack<T> implements Stack {
private Node<T> top;
private int size;
public void push(T value) {
if(this.size == 0) {
this.top = new Node<>(value, null);
} else {
this.top = new Node<>(value, this.top);
}
this.size++;}
}
When I attempt to compile this I get the compiler error messages:
NodeStack.java:10: error: NodeStack is not abstract and does not override abstract method push(Object) in Stack
public class NodeStack<T> implements Stack {
^
NodeStack.java:63: error: name clash: push(T) in NodeStack and push(Object) in Stack have the same erasure, yet neither overrides the other
public void push(T value) {
^
where T is a type-variable:
T extends Object declared in class NodeStack
2 errors
I think this problem occurs because of type erasure - the push method in the class and the push method in the interface have the same signature after type erasure. What I don't understand is why this would be a problem. The push method implementation should have the same signature as the interface method, right? What am I missing here? Any help is greatly appreciated.
You are trying to use method signature which has object and generic T, both are different does not match.
public interface Stack<T>
{
void push(T element);
}
And now your NodeStack class will be
public class NodeStack<T> implements Stack<T> {
The push method in the class and the push method in the interface have the same signature after type erasure.
This as I understand it, is the crux of the problem.
Your class is clashing it's method signature with that of the interface, but the method signature of the class at a source level is much more strict/defined then the object type on the interface. So they both don't match before, as well as matching afterwards due to erasure, so you get a compile error.
It could get objects, other then subtypes of T passed to it, and it wouldn't be able to deal with it, yet the interface says it's fine at a source level.
Even if this would work, it would be a bad idea, as the interface says it can accept any object, when the implementation can only take types of T.
If we allowed this to work, you could potentially store and get a string into a Stack<Integer>
by using the interface method, then elsewhere a reference to Stack<Integer>
would end up getting a String, breaking type safety.
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