<< IntelliJ IDEA 4.5: New Logo | Home | Jython Inventor To Join Microsoft >>

Java Generics Question

In my quest to develop a generic singleton class, I encountered this problem:

[weiqi@gao] $ cat Singleton.java
public class Singleton<T> {
  private static T instance;
  public static T getInstance() {
    if (instance == null) {
      instance = new T();
    }
    return instance;
  }
}
[weiqi@gao] $ javac Singleton.java
Singleton.java:2: non-static class T cannot be referenced from a static context
    private static T instance;
                   ^
Singleton.java:3: non-static class T cannot be referenced from a static context
    public static T getInstance() {
                  ^
Singleton.java:5: non-static class T cannot be referenced from a static context
            instance = new T();
                           ^
3 errors

Why? (Both C++ and C# allow similar constructs.)



Re: Java Generics Question

Works for me. I had to add in a return statement for getInstance() though.

Re: Java Generics Question

Oops. I did not escape the "<T>" type parameter, and I missed the return statement. Fixed both.

Re: Java Generics Question

those are the limitations people are nagging about java generics. I'm kind of disappointed by the half ass approach.

Re: Java Generics Question

Java 5.0 generics differ in concept from those in C# version 2. In Java there is only one class per class no matter how many parameters it has. Therefore static members are not affected by generic parameters of their class. So you would need to do something like this (not tested):

import java.util.Map;

public class Singleton<T> {
    private static Map<Class<?>,Object> instanceMap =
        new java.util.HashMap<Class<?>,Object>();
    public static synchronized <T> T getInstance(
        Class<T> clazz
    ) throws InstantiationException,
                     IllegalAccessException
    {
        T instance = clazz.cast(instanceMap.get(clazz));
        if (instance != null) {
            return instance;
        }
        
        try {
            instance = clazz.cast(clazz.newInstance());
        } catch (InstantiationException exc) {
            throw new IllegalArgumentException(exc);
        } catch (IllegalAccessException exc) {
            throw new IllegalArgumentException(exc);
        } catch (ClassCastException exc) {
            throw new IllegalArgumentException(exc);
        }
        
        instanceMap.put(clazz, instance);
        
        return instance;
    }
}

But we all know singletons are evil. If there's no state in the class, then you can simply cast a single instance, as Collections.emptySet does.


Add a comment Send a TrackBack