在Java中创建泛型类型的实例时,参数化类型通过层次?(Create instance of gen

2019-10-18 14:18发布

我一直在读的问题的答案:

在Java中创建泛型类型的实例?

我已经实现了由拉尔斯·博尔建议的方法。 我适应了他的代码如下:

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

public class ParameterizedTypeEg<E> {
    public Class<E> getTypeParameterClass() {
        Type type = getClass().getGenericSuperclass();
        ParameterizedType paramType = (ParameterizedType) type;
        return (Class<E>) paramType.getActualTypeArguments()[0];
    }
    private static class StringHome extends ParameterizedTypeEg<String> {
        private String _string;
        StringHome (String string) {
            _string = string;
        }
    }
    public static void main(String[] args)
        throws InstantiationException, IllegalAccessException {
        String str = new StringHome("my string").getTypeParameterClass().newInstance();
        String str2 = new ParameterizedTypeEg<String>().getTypeParameterClass().newInstance();
    }
}

这种方法的str变量工作正常。 然后STR2与这似乎我是相同类型的(ParameterizedTypeEg <字符串>,这基本上是一样的东西作为StringHome)创建。 然而,这种方法不适用于STR2工作,当我尝试投则抛出ClassCastException(ParameterizedType)型。

尽管对STR2,我已参数ParameterizedTypeEg用字符串,getGenericSuperclass()返回的东西比STR很大的不同。 此外,方法中STR2显示“这个”作为ParameterizedTypeEg,而对于海峡,“这”是一个ParameterizedTypeEg $ StringHome。 我想这是问题的根源。 为什么Java的看不到泛型类型已经确定STR2也?

我有什么会出现在参数化类型是通过多个层次传递到出现同样的问题? 即,B类<T>包含A <T>和我实例化一个B.内的,我无法通过使用上述方法确定所述参数化的类型A的创建一个字符串对象。 该方法产生在包含层次结构的情况下的异常,以及。 这引起了我一个问题,因为我希望能够通过遏制和/或继承的多层次传递参数化类型,并具有相同的方式产生在所有情况下的一般类型的实例。

谢谢,约翰

Answer 1:

用下面的改变,你的代码将工作:

  String str2 = new ParameterizedTypeEg<String>().getTypeParameterClass().newInstance();

   String str2 = new ParameterizedTypeEg<String>(){}.getTypeParameterClass().newInstance();

这将创建ParameterizedTypeEg的匿名子类。 你打电话时

getClass().getGenericSuperclass();

在StringHome,你会得到一个ParameterizedTypeEg <java.lang.String中>,这是你想要的。 如果创建STR2像你一样,该呼叫只是返回的对象,所以它转换为一个paremeterized类型的尝试失败:

异常在线程“主要” java.lang.ClassCastException:java.lang.Class中不能转换为java.lang.reflect.ParameterizedType

创建一个匿名子类,使得这个回报ParameterizedTypeEg <java.lang.String中>

这是公司在使用同样的伎俩类型令牌在谷歌吉斯番石榴库类,顺便说一句。 你写,例如

new TypeToken<List<String>>() {}

并不是

 new TypeToken<List<String>>()  


Answer 2:

然而,这种方法不适用于STR2工作,则抛出ClassCastException当我尝试投(ParameterizedType)型
...........为什么Java的看不到泛型类型已经确定STR2也?

作为Oracle文档指定ParameterizedType :

ParameterizedType表示参数类型,例如Collection<String>

但是,超类的ParameterizedTypeEg为对象,这是不是泛型类型。 所以, Type由归国getClass().getGenericSuperclass();Class本身的对象。 和非参数化类型的类型铸造ParameterizedType是给你ClassCastExceptionstr



Answer 3:

为什么Java的看不到泛型类型已经确定STR2也?

在运行时的对象不具有任何类型的参数信息。 基本上,你做.newInstance()创建一个对象,你需要有在运行时类对象,这意味着你必须在一些地方保存它的方式得到它。

它的工作原理的原因, str正是因为类型String存储的地方-在类的元数据。 类具有元数据,其包括超类和超接口,封闭类,如果它是一个内部类,和类型的字段和方法(返回类型和参数类型的方法)的。 所有这些信息都存储,使用泛型,在字节码在运行时(这种情况的原因是,在Java文件可单独编译,所以编译使用一个类从已编译的文件一个文件时,编译器必须能够看看类文件,看看泛型信息),并在运行时可通过类对象上反射。

因此,基本上,在StringHome类作为“存储”为String类对象,因为String被硬编码为在编译时其超类的类型参数。 因此,在运行时,你可以把它弄出来这个“存储”的。

即,B类<T>包含A <T>和我实例化一个B.内的,我无法通过使用上述方法确定所述参数化的类型A的创建一个字符串对象。

从上面我的讨论,你可能回升的关键就是以某种方式“搞定”在运行时类对象为是类T 。 使该子类的一类A<T>不会帮助的,因为该点是实际的类是在编译时硬编码,这需要知道在编译时的类。 我们不知道是什么类T是在编译的时候,所以我们不能把它变成了元数据; 我们只能把“T”,即一个类型变量。

所以,再一次,这个问题可以追溯到需要找到某种方式来传递或传送类对象的类型参数代表的类。 你可以不依赖于任何基于编译时的机制了。 所以,你必须在它传递一个额外的参数什么的。



Answer 4:

getClass().getGenericSuperclass(); 给你超类的细节。 因此,如果你继承一个参数化的超类的用户才能使用。 如果实例化参数的超定类类型参数它不会工作。



文章来源: Create instance of generic type in Java when parameterized type passes through hierarchies?