There is an important lesson I realized w.r.t. using Generics vs. Interfaces in Java today. It has to do with this:
Another benefit of using generics is that you don’t need to typecast all the time when using fields or methods from a superclass — you personally know their types, but Java doesn’t have that type information stored anywhere. An additional benefit is that all your getter / setter methods can use the generic parameters and expose a more sensible front to other objects which rely on the fact that you set up specialised fields in the aforementioned object.
but what does this mean? Let’s take an example. Create following files:
SomeInterface.java
public interface SomeInterface {}
InterfaceImpl.java
public class InterfaceImpl implements SomeInterface {
public String s;
public InterfaceImpl(String s) {
this.s = s;
}
}
Foo.java
public class Foo<T extends SomeInterface> {
public T t;
public Foo(T t) {
this.t = t;
}
}
Main.java
public class Main {
public static void main(String[] args) {
InterfaceImpl obj = new InterfaceImpl("hello world");
Foo<InterfaceImpl> foo = new Foo<>(obj);
InterfaceImpl x = foo.t;
System.out.println(x.s);
}
}
Now compile and run:
% javac Foo.java SomeInterface.java InterfaceImpl.java Main.java
% java -cp . Main
hello world
It works. But now consider what happens if we were using interfaces. Create following classes:
Bar.java
public class Bar {
public SomeInterface t;
public Bar(SomeInterface t) {
this.t = t;
}
}
Main2.java
public class Main2 {
public static void main(String[] args) {
InterfaceImpl obj = new InterfaceImpl("hello world");
Bar bar = new Bar(obj); // ok
InterfaceImpl x = bar.t; // won't compile
System.out.println(x.s);
}
}
Try to compile and run:
% javac Foo.java SomeInterface.java InterfaceImpl.java Main.java Main2.java
Main2.java:6: error: incompatible types: SomeInterface cannot be converted to InterfaceImpl
InterfaceImpl x = bar.t; // won't compile
^
1 error
You will have to do an explicit cast which is ugly and error-prone. An ArrayList (more specific type) can be assigned to a List (superclass) but a List (superclass) cannot be assigned to an ArrayList. This is what is happening above and now we understand what they mean by:
Another benefit of using generics is that you don’t need to typecast all the time when using fields or methods from a superclass — you personally know their types, but Java doesn’t have that type information stored anywhere. An additional benefit is that all your getter / setter methods can use the generic parameters and expose a more sensible front to other objects which rely on the fact that you set up specialised fields in the aforementioned object.
Its a nifty difference where generics trump interfaces. In my case the way I ran into this was SomeInterface was an interface I wrote to encapsulate a generic id and InterfaceImpl was a concrete implementation that used a String to represent an id (some other programmer could use an int). The downside is the ugly code with all the angle brackets you have to deal with.
Another downside of generics is that you can’t do things like new T() where T is the generic parameter. This limitation does not exist in C#.