Java 泛型、单例和静态方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7982129/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 22:33:22  来源:igfitidea点击:

Java generics, singletons and static methods

javagenericsinheritancestaticsingleton

提问by Metalstorm

So I have a few 'Manager' classes, for example GroupManager. All these Managers are singletons.

所以我有一些“Manager”类,例如 GroupManager。所有这些管理器都是单身人士。

Using this method for instancing:

使用此方法进行实例化:

private static GroupManager groupManager = null;

private GroupManager()
{

}

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

I'm thinking I should start to use some inheritance as they have a lot of copied methods.

我想我应该开始使用一些继承,因为他们有很多复制的方法。

The Instance() methods for each Manager is the same.

每个 Manager 的 Instance() 方法都是相同的。

So for inheritance i can do this (obviously):

所以对于继承,我可以这样做(显然):

GroupManager extends Manager

Is it possible to use generics to use the same Instance method for all managers, something like:

是否可以使用泛型为所有管理器使用相同的 Instance 方法,例如:

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

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

}

I think that makes sense :)

我认为这是有道理的:)

So then you would do GroupManager.Instance() like normal.

那么你会像往常一样做 GroupManager.Instance() 。

回答by Shivan Dragon

You don't understand how generics and statics work. If you have a static field or method (such as "instance" or instance()), which can be called without instantiating the class Manager, how do you expect the JVM (and the compiler even) to know what type E is supposed to be?

你不了解泛型和静态是如何工作的。如果您有一个静态字段或方法(例如“实例”或实例()),可以在不实例化类管理器的情况下调用它们,您如何期望 JVM(甚至编译器)知道 E 应该是什么类型是?

Here's an example, as per G_H's suggestion:

这是一个例子,根据 G_H 的建议:

GeneralManager and AreaManager both extend Manager

GeneralManager 和 AreaManager 都扩展了 Manager

The Manager class is the only one that has the getInstance() static method:

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;
            }
        }
    }

回答by G_H

Nope, it's not gonna work. Java uses generics at compile time for type checking, but doesn't generate extra classes or retain info regarding type parameters at runtime.

不,这行不通。Java 在编译时使用泛型进行类型检查,但不会在运行时生成额外的类或保留有关类型参数的信息。

When you declare Manager<E>with that type parameter E, that's something that will only play a role in an actual instance. You could have a subclass like GroupManager extends Manager<String>or whatever, but that's not magically gonna generate a variety of the static method.

当您Manager<E>使用该类型参数进行声明时E,它只会在实际实例中发挥作用。你可以有一个类似的子类GroupManager extends Manager<String>,但这不会神奇地生成各种静态方法。

Static methods and members belong with a class, not an instance. So trying to use generics there, which are intended for typing instances, isn't gonna fly.

静态方法和成员属于一个类,而不是一个实例。因此,尝试在那里使用泛型(用于键入实例)不会成功。

回答by Reid Mac

If you make your group manager class as follows then you can call your instance method.

如果按如下方式创建组管理器类,则可以调用实例方法。

public class GroupManager extends Manager<GroupManager>{}

And in your Manager class try this...

在你的经理课上试试这个......

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;  
}

Or if you know the object you want an instance for, just make the method generic

或者,如果您知道要为其实例化的对象,只需将方法设为通用

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;
    }

I havn't tried any of this so not sure if it will work.

我还没有尝试过任何这些,所以不确定它是否会起作用。

回答by user976283

Injecting the constructor in a generic context. Cash is not thread safe, but is only used in static context so its fine if you don't miss use it

在通用上下文中注入构造函数。Cash 不是线程安全的,但仅在静态上下文中使用,因此如果您不要错过使用它就可以了

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;
        }
    }
}

回答by Lohith Ravi

public class Manager<E>{

private static Object instance = null;

    public static E Instance() {
       if (instance == null)
       {
        instance = new E();
       }
       return (E)instance;
   }
} 
public class Manager<E>{

private static Object instance = null;

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