Дженерики Java, синглтоны и статические методы - PullRequest
7 голосов
/ 02 ноября 2011

Итак, у меня есть несколько классов 'Manager', например GroupManager. Все эти менеджеры - одиночки.

Использование этого метода для создания экземпляров:

private static GroupManager groupManager = null;

private GroupManager()
{

}

public static GroupManager Instance()
{
    if (groupManager == null)
    {
        groupManager = new GroupManager();
    }
    return groupManager;
}

Думаю, мне следует начать использовать какое-то наследование, поскольку у них много скопированных методов.

Методы Instance () для каждого менеджера одинаковы.

Так что для наследования я могу сделать это (очевидно):

GroupManager extends Manager

Можно ли использовать дженерики для использования одного и того же метода экземпляра для всех менеджеров, например:

public class Manager<E>
{
    private static E instance = null;

    public static E Instance()
    {
        if (instance == null)
        {
            instance = new E();
        }
        return instance;
    }

}

Думаю, в этом есть смысл:)

Итак, вы бы сделали GroupManager.Instance () как обычно.

Ответы [ 5 ]

9 голосов
/ 02 ноября 2011

Вы не понимаете, как работают дженерики и статики.Если у вас есть статическое поле или метод (например, «instance» или instance ()), которые можно вызывать без создания экземпляра менеджера классов, как вы ожидаете, что JVM (и даже компилятор) узнает, какой тип E долженбыть?

Вот пример, согласно предложению G_H:

GeneralManager и AreaManager оба расширяют Manager

Класс Manager - единственный, который имеет статический метод getInstance ():

    public class Manager {

        private static Map<Class<? extends Manager>,Manager> INSTANCES_MAP = new java.util.HashMap<Class<? extends Manager>, Manager>();

//Also, you will want to make this method synchronized if your application is multithreaded,
//otherwise you mihgt have a race condition in which multiple threads will trick it into
//creating multiple instances
        public static <E extends Manager> E getInstance(Class<E> instanceClass) throws InstantiationException, IllegalAccessException {
            if(INSTANCES_MAP.containsKey(instanceClass)) {
                return (E) INSTANCES_MAP.get(instanceClass);
            } else {
                E instance = instanceClass.newInstance();
                INSTANCES_MAP.put(instanceClass, instance);
                return instance;
            }
        }
    }
2 голосов
/ 02 ноября 2011

Нет, это не сработает.Java использует обобщенные элементы во время компиляции для проверки типов, но не генерирует дополнительные классы и не сохраняет информацию о параметрах типов во время выполнения.

Когда вы объявляете Manager<E> с этим параметром типа E, это то, что будетиграют роль только в реальном случае.У вас может быть подкласс типа GroupManager extends Manager<String> или любой другой, но это не волшебным образом сгенерирует множество статических методов.

Статические методы и члены принадлежат классу, а не экземпляру.Поэтому попытка использовать там дженерики, предназначенные для набора экземпляров, не даст результатов.

0 голосов
/ 10 октября 2015

public class Manager<E>{

private static Object instance = null;

    public static E Instance() {
       if (instance == null)
       {
        instance = new E();
       }
       return (E)instance;
   }
} 

0 голосов
/ 02 ноября 2011

Внедрение конструктора в общий контекст.Денежные средства не являются потокобезопасными, но используются только в статическом контексте, поэтому хорошо, если вы не пропустите их использовать

public class Example {

    public static class MySingletonClass {
    }

    public interface Provider<T> {
        T get();
    }

    static final Provider<MySingletonClass> myClassInstanceProvider = new Cash<MySingletonClass>(new Provider<MySingletonClass>() {
            @Override
            public MySingletonClass get() {
                return new MySingletonClass();
            }
        }); 


    public static class Cash<T> implements Provider<T> {
        private Provider<T> provider;

        public Cash(Provider<T> provider) {
            this.provider = provider;
        }

        @Override
        public T get() {

            final T t = provider.get();
            provider = new Provider<T>() {

                @Override
                public T get() {
                    return t;
                }
            };
            return t;
        }
    }
}
0 голосов
/ 02 ноября 2011

Если вы создадите класс менеджера группы следующим образом, вы можете вызвать метод экземпляра.

public class GroupManager extends Manager<GroupManager>{}

И в своем классе менеджера попробуйте это ...

public class Manager<E>
{
private static E instance = null;

public static E Instance()
{
                  try {
            return instance.newInstance();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return null;  
}

Или, если вы знаете объект, для которого вы хотите создать экземпляр, просто сделайте метод универсальным

public static <T> T getInstance(Class<T> t){
             try {
            return t.newInstance();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return null;
    }

Я не пробовал ничего из этого, поэтому не уверен, что это сработает.

...