Reputation: 2830
I like the idea of the null object pattern and force me to use it until it really feels normal and good. At the moment I don't see how to use it in generic types. I know the possibility to define a second generic type and to pass in the class to construct a default object, but this feels really too much overhead for this pattern. Is there a good way?
public class GenericExample<T> {
public static final GenericExample NULL = ???;
private T attribute;
public GenericExample(T attribute) {
this.attribute = attribute;
}
}
public class HoldGeneric {
private GenericExample<String> name = GenericExample.NULL;
public initLater(String name) {
this.name = new GenericExample<String>(name);
}
}
Upvotes: 5
Views: 2908
Reputation: 6718
Without passing in the class of T
there's no way to properly implement it. The closest you could do, abusing type erasure, would be:
class GenericExample<T>
{
private static final GenericExample<Object> NULL = new GenericExample<Object>();
public static <T> GenericExample<T> nil()
{
@SuppressWarnings("unchecked")
final GenericExample<T> withNarrowedType = (GenericExample<T>)NULL;
return withNarrowedType;
}
}
However, you have to accept that GenericExample.<Apple>nil()
would be the same as GenericExample.<Orange>nil()
.
Upvotes: 1
Reputation: 1223
Based on my understanding of your question, I would go with the following.
public class GenericExample<T> {
public static final GenericExample<?> NULL = new GenericExample<Object>(new Object()) {
public void print() {
}
};
private T attribute;
public GenericExample(T attribute) {
this.attribute = attribute;
}
public void print() {
System.out.print(attribute.toString());
}
@SuppressWarnings("unchecked")
public static <X> GenericExample<X> nil() {
return (GenericExample<X>) NULL;
}
}
public class Test {
private static GenericExample<String> name = GenericExample.nil();
public static void main(String[] args) {
String x = "blah";
name.print();
if (name == GenericExample.NULL) {
name = new GenericExample<String>(x);
}
name.print();
}
}
Upvotes: 2
Reputation: 31648
You can follow what the JDK does and use a static method to infer the generic type and do an unchecked cast.
java.util.Collections
implements Null objects for empty lists and sets. In Java Pre-generics, there is a public static field.
public static final List EMPTY_LIST = new EmptyList();
Post generics: There are now static methods that infer the generic type and perform the unchecked casting for you to cast it to the correct type. The type doesn't really matter since the collections are empty but it makes the compiler happy.
@SuppressWarnings("unchecked")
public static final <T> List<T> emptyList() {
return (List<T>) EMPTY_LIST;
}
Upvotes: 4