【问题标题】:Design Pattern: Lazy Singleton, Generics and Inheritance: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType设计模式:惰性单例、泛型和继承:java.lang.Class 不能强制转换为 java.lang.reflect.ParameterizedType
【发布时间】:2013-01-06 08:44:52
【问题描述】:

我正在尝试使用泛型和继承来实现 Lazy Singleton。我创建了一个 abstract 超类并声明了一个 Map ,它将存储该类的子类的所有实例。

这里是:

public abstract class AbstractXMLParser<T> {
    @SuppressWarnings("rawtypes")
    private static final Map<Class<? extends AbstractXMLParser>, AbstractXMLParser> INSTANCES = new HashMap<>();

    public AbstractXMLParser() {
        throw new UnsupportedOperationException("Cannot instantiate");
    }

    private static class SingletonHolder<T> {       
        @SuppressWarnings({ "unchecked"})
        private static <T> T getInstance() throws InstantiationException, IllegalAccessException {
            Class<T> clazz = (Class<T>) ((ParameterizedType) SingletonHolder.class.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
            return clazz.newInstance();
        }
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static <T extends AbstractXMLParser> T getInstance() throws InstantiationException, IllegalAccessException {
        Class<T> clazz = (Class<T>) ((ParameterizedType) AbstractXMLParser.class.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        if(INSTANCES.containsKey(clazz)) {
            return (T) INSTANCES.get(clazz);
        } else {
            T instance = SingletonHolder.getInstance();
            INSTANCES.put(clazz, instance);
            return instance;
        }
    }
}

其中一个子类是:

public class ActivityTypeXMLParser extends AbstractXMLParser<ActivityTypeXMLParser>{
    private ActivityTypesXMLModel activityTypes;

    private ActivityTypeXMLParser() {

    }

    public static void main(String... strings) throws InstantiationException, IllegalAccessException {
        ActivityTypeXMLParser.getInstance();

    }
}

main 方法用于测试目的。但我得到了例外:

Exception in thread "main" java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
    at com.edfx.adb.xml.parser.AbstractXMLParser.getInstance(AbstractXMLParser.java:25)
    at com.edfx.adb.xml.parser.ActivityTypeXMLParser.main(ActivityTypeXMLParser.java:30)

现在调试后发现

Class<T> clazz = (Class<T>) ((ParameterizedType) AbstractXMLParser.class.getClass().getGenericSuperclass()).getActualTypeArguments()[0];

是异常的原因,因为AbstractXMLParser.class.getClass().getGenericSuperclass() 正在返回class java.lang.Object。我需要在这里获取Class&lt;T&gt;。如何在AbstractXMLParserAbstractXMLParserSingletonHolder 类中提取它?

【问题讨论】:

    标签: java generics inheritance singleton lazy-evaluation


    【解决方案1】:

    此代码存在多个问题:

    • static 方法不会被继承。 AbstractXMLParser.getInstance() 不知道它是在 ActivityTypeXMLParser 的上下文中调用的 ActivityTypeXMLParser.getInstance()

    • AbstractXMLParser.class.getClass() 返回您班级的Class' ofClass, notClass`。

    • 不清楚为什么你需要AbstractXMLParser&lt;T&gt; 是通用的。注意AbstractXMLParserSingletonHoldergetInstance()中的Ts是不同的类型参数。

    您需要将相关类隐式传递给getInstance()

    getInstance(ActivityTypeXMLParser.class);
    

    .

    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static <T extends AbstractXMLParser> T getInstance(Class<T> clazz) 
        throws InstantiationException, 
        ...
    }
    

    【讨论】:

    • 感谢您的回复。但现在我收到另一个错误 java.lang.IllegalAccessException for clazz.newInstance()。因为 ActivityTypeXMLParser 有私有构造函数。我该如何克服这个问题?
    • 如果确实需要使用反射访问private构造函数,请使用setAccessible(true)
    【解决方案2】:

    这是我制作的完整解决方案,对某人有帮助。

    abstract super-class:

    @SuppressWarnings({"all"})
    public abstract class AbstractXMLParser<T> {    
        private static final Map<Class<? extends AbstractXMLParser>, AbstractXMLParser> INSTANCES = new HashMap<>();
    
        public AbstractXMLParser() {
    
        }
    
        private static class SingletonHolder<T> {               
            private static <T> T getInstance(Class<T> clazz) throws InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
                Constructor<T> constructor = (Constructor<T>) clazz.getDeclaredConstructors()[0];
                constructor.setAccessible(true);            
                return constructor.newInstance(null);
            }
        }
    
        protected static <T extends AbstractXMLParser<T>> T getInstance(Class<T> clazz) throws InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {      
            if(INSTANCES.containsKey(clazz)) {
                return (T) INSTANCES.get(clazz);
            } else {
                T instance = SingletonHolder.getInstance(clazz);
                INSTANCES.put(clazz, instance);
                return instance;
            }
        }
    
        protected static <T extends AbstractXMLParser<T>> void putInstance(Class<T> clazz, T instance) {
            if(!INSTANCES.containsKey(clazz)) {
                INSTANCES.put(clazz, instance);
            }
        }
    }
    

    还有一个子类:

    public class ActivityTypeXMLParser extends AbstractXMLParser<ActivityTypeXMLParser>{
    
        private ActivityTypeXMLParser() {
    
        }   
    
        public static ActivityTypeXMLParser getInstance() {
            ActivityTypeXMLParser activityTypeXMLParser = null;
    
            try {
                activityTypeXMLParser = getInstance(ActivityTypeXMLParser.class);
            } catch (Exception exception) {
            }
    
            if(activityTypeXMLParser == null) {
                activityTypeXMLParser = new ActivityTypeXMLParser();
                putInstance(ActivityTypeXMLParser.class, activityTypeXMLParser);
            }
    
            return activityTypeXMLParser;
        }
    }
    

    【讨论】:

      【解决方案3】:

      您似乎想要获取作为抽象类的子类的类的泛型类型。但是你得到了

      AbstractXMLParser.class.getClass()
      

      这是抽象类的类,总是Class 而你应该只使用getClass() 到具体类的类。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-11-30
        • 1970-01-01
        相关资源
        最近更新 更多