【问题标题】:how to create a generic singleton class in java?如何在java中创建一个通用的单例类?
【发布时间】:2021-02-16 16:32:49
【问题描述】:

我想在 java 中创建一个通用的单例类,女巫给出了我传入方法参数的类的单例对象。类似下面的代码:请帮助

public final class Listener<T extends Object>  {
    private Listener() {
    }

    public static <T> Listener<?> getInstance(Class<T> clazz) {
        return SingletonHolder.INSTANCE;
    }

    private static class SingletonHolder {
        public static final Listener INSTANCE = new Listener();
        // private static final Map<Class<? extends Runnable>,Listener<? extends
        // Runnable> INSTANCE = new ...;
    }
}

【问题讨论】:

  • 为什么需要它是通用的?在您的示例中,您没有以任何方式使用 T。
  • 这个结果会不会违背单例所基于的整个想法(只有该类的一个实例)?
  • 您到底想达到什么目标?如果它是一个真正的单例,它就不可能是真正的泛型,因为你必须在创建时选择类型参数。还是您想要每个 T 类型一个实例?
  • 顺便说一句,一个泛型的单例绝对是有意义的——只要它不获取或给出其泛型参数的实例。 Collections.empty[List|Map|Set]() 如果您尝试添加或获取任何元素,则返回失败的单例实例。 emptyList (etc) 方法具有未经检查的强制转换,可将单例转换为 List&lt;T&gt;(其他集合接口相同)。

标签: java generics


【解决方案1】:

创建一个只有一个值的enumINSTANCE 等。即时单例。

如果我理解正确,我认为您希望您的单例实现一些通用接口?比如:

interface ListenerInterface<T> {
    void handleEvent(T event);
}

在这种情况下,您可以使用未经检查的强制转换以通用方式返回您的枚举作为单例。只要您的单例实际上不使用实例(或者,只假设它是一个对象),这是安全的。

public enum MySingleton implements ListenerInterface<Object> {
    INSTANCE;

    @SuppressWarnings("unchecked")
    public static <T> ListenerInterface<T> getListener() {
        return (ListenerInterface<T>) INSTANCE;
    }

    public void handleEvent(Object event) {
        System.out.println("I am a singleton. An event happened: " + event);
    }

}

如果接口是生产者而不是消费者——也就是说,它返回一个T——那么你只能安全地返回null。否则,其他人在尝试使用 T 时会收到 ClassCastException,他们认为这是一个 Foo,但实际上只是一个 Object。

【讨论】:

【解决方案2】:

这将是评论,但由于字符限制,我认为最好是一个答案,

再深入思考一下,真的有可能创建一个通用的单例类吗?

单例类不能被实例化,也不应该被克隆。

要赋予任何类这种行为,您必须创建all the constructors private and clone method will have to be overridden to throw an exception。现在,如果您要更改所有类以实现此行为,那么您创建单例的方式真的是通用的吗?

如果我对问题的解释有误,请见谅

【讨论】:

    【解决方案3】:

    您可以这样做,但恕我直言不可靠:

    public class SimpleSingleton {
    private Map<String, Object> counter = new HashMap<String, Object>();
    
    public <T> T getInstance(Class<T> clazz) throws IllegalAccessException, InstantiationException {
        T singleton = (T) counter.get(clazz.getName());
        if (singleton == null) {
            singleton = clazz.newInstance();
            counter.put(clazz.getName(), singleton);
        }
        return singleton;
    }
    

    }

    【讨论】:

      【解决方案4】:

      我对这个问题的解决方案是这样设计的:

      public interface IListener<T extends Object>  {
          void handle(T event);
      }
      
      public final class Listener implements IListener<Object> {
          private static Listener instance = new Listener();
      
          private Listener() {
          }
      
          public static Listener getInstance() {
              return instance;
          }
      
          @Override
          public void handle(Object event) {
              //TODO Do stuff
          }
      }
      

      【讨论】:

        【解决方案5】:

        我不确定我是否完全理解您的问题,但如果您想将单例集成到通用层次结构中,您必须作弊(就像我们在 this topic 中所做的那样):

        interface Listener<T>{
            // ...
        }
        
        @SuppressWarnings("unchecked")
        final class SingletonListener {
        
            private SingletonListener() {
                assert false : "Uninstantiable";
            }
        
            public static <T> Listener<T> instance() {
                return SingletonListenerInstance.INSTANCE;
            }
        
            // Note - implements Listener without specifying type parameters!
            private enum SingletonListenerInstance implements Listener {
                INSTANCE;
                // Insert listener methods here
            }
        }
        
        
        // Usage:
        Listener<Pony> ponyListener = SingletonListener.instance();
        

        那么如果这个实现接收T 类型的参数,或者预期返回(或相关)T 类型的值,它会做什么呢?好吧,不多,但比没有更重要!这是一个带有示例实现的更充实的版本:

        interface Listener<T> {
            void receive(T something);
        
            T process(T something);
        
            T produce();
        
            List<T> produceMany();
        }
        
        @SuppressWarnings("unchecked")
        final class SingletonListener {
        
            private SingletonListener() {
                assert false : "Uninstantiable";
            }
        
            public static <T> Listener<T> instance() {
                return SingletonListenerInstance.INSTANCE;
            }
        
            // Note - implements Listener without specifying type parameters!
            private enum SingletonListenerInstance implements Listener {
                INSTANCE;
                // Insert listener methods here
        
                @Override
                public void receive(Object something) {
                    // We can log what we receive because we know everything is an Object
                    // and so has a toString method; we can also use other Object methods,
                    // do reflection (or just ignore it and leave a no-op implementation)
                    System.out.println("Received " + something);
                }
        
                @Override
                public Object process(Object something) {
                    // We can return something we know to be of the right type, which in our
                    // case typically is arguments we've received
                    return something;
                }
        
                @Override
                public Object produce() {
                    // Null is a valid value for all types
                    return null;
                }
        
                @Override
                public List produceMany() {
                    // Don't need any instances of the generic type to create an empty list
                    return Collections.EMPTY_LIST;
                }
            }
        }
        

        【讨论】:

        • 不应该是final class SingletonListener&lt;T&gt; {吗?
        • 此代码不会编译,即使您修改它以使其编译,它也无法与包含具有通用参数或返回类型的方法的 Listener 一起使用。因此它只适用于 Listener,而不适用于 Listener。这不是一个通用的解决方案。
        • @user1677663 感谢您指出不可编译性,已修复。至于这些方法可以做什么,事实证明你实际上可以做一些事情!当然,这对虚拟/无操作实现非常有用,并且您必须跟踪什么是什么,否则您最终会在客户端代码中得到令人惊讶的ClassCastExceptions,但是可以设想这很有用的极端情况。
        • 感谢您将其充实到让人们可以看到他们实际使用这种方法所做的事情!
        猜你喜欢
        • 1970-01-01
        • 2010-12-02
        • 2014-08-01
        • 1970-01-01
        • 2020-10-16
        • 1970-01-01
        • 2021-03-23
        • 2015-12-14
        • 1970-01-01
        相关资源
        最近更新 更多