Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/369.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/wix/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么可以';t您是否使用“创建泛型类型的实例”;新";操作人员_Java_Generics_Type Erasure - Fatal编程技术网

Java 为什么可以';t您是否使用“创建泛型类型的实例”;新";操作人员

Java 为什么可以';t您是否使用“创建泛型类型的实例”;新";操作人员,java,generics,type-erasure,Java,Generics,Type Erasure,我找到了很多关于如何克服这个限制的帖子,但没有一篇是关于为什么存在这个限制的(除了,其中只提到它与类型擦除有关) 那么为什么不能创建泛型类型的实例呢 澄清一下,我的问题不是如何做到这一点。我知道这在C#中是可能的,那么为什么不在Java中呢?我很好奇为什么Java人员没有实现类似的机制?为什么要强迫Java开发人员使用可能导致运行时错误的笨拙变通方法?这种机制是否存在任何潜在危险 记住泛型类型是关于编译时安全的。编译时类型检查允许编译器就代码问题向您发出警告/错误。这对你的问题没有直接的帮助,但

我找到了很多关于如何克服这个限制的帖子,但没有一篇是关于为什么存在这个限制的(除了,其中只提到它与类型擦除有关)

那么为什么不能创建泛型类型的实例呢


澄清一下,我的问题不是如何做到这一点。我知道这在C#中是可能的,那么为什么不在Java中呢?我很好奇为什么Java人员没有实现类似的机制?为什么要强迫Java开发人员使用可能导致运行时错误的笨拙变通方法?这种机制是否存在任何潜在危险

记住泛型类型是关于编译时安全的。编译时类型检查允许编译器就代码问题向您发出警告/错误。这对你的问题没有直接的帮助,但是让编译时和运行时的概念保持清晰是很重要的

您不能说,“
返回新的t()
”,因为编译器无法知道如何执行此操作。如果没有特定的类型,编译器就不知道调用什么构造函数,甚至不知道它是否存在。另外,为了“新建”类型为
T
的实例,您需要调用一些东西
T
只是一个符号。它不是
对象
。除非您提供关于
T
是什么样的实例(例如
List
)的信息,否则编译器无法执行您试图执行的操作

类型只是确保给定和返回的类型在编译时正确匹配的一种方法。只有在指定类型细节时,才能创建它的实例。这就是为什么您通常会在接口上看到完全开放的类型(例如
List
Function
等)。因此,接口的实现者可以指定将使用什么类型

也许考虑像模板这样的泛型会有所帮助。不是软件开发模式,而是更抽象的概念。模板的概念是,这种结构没有任何内部细节。如果你想按照模板创建这个东西,可以使用模板作为起点,但是你必须填写细节来制作这个东西。泛型类型有点像这样——它允许你构造一些东西,但不提供任何关于该结构中发生了什么的细节


我知道当泛型被引入时,我在这方面做了很多努力。起初,我发现先为特定类型编写实现,然后再使用泛型将其抽象出来是最容易的。在我开始研究泛型之后,我发现从泛型接口开始,然后实现它更容易。

从泛型接口创建类。请注意,这取决于被参数化的类。这将返回泛型的类对象,通过它可以对其执行进一步的反射以创建对象

 public static <T> Class<T> getClassFromGeneric(
            Object parentObj,
            int oridnalParamterizedTypeIndex) throws Exception{
          Type[] typeArray = getParameterizedTypeListAsArray(parentObj);
          return (Class<T>)typeArray[oridnalParamterizedTypeIndex];
    }

    public static <T> Type[] getParameterizedTypeListAsArray(Object parentObj){
        try{
            return  ((ParameterizedType) parentObj.getClass()
                    .getGenericSuperclass())
                    .getActualTypeArguments();
        }
        catch(ClassCastException e){
            logger.log(Level.SEVERE, "Most likely, somewhere in your inhetirance chain,"
                    + "there is a class that uses a raw type and not the generic param."
                    + "See: http://stackoverflow.com/questions/23074446/java-lang-classcastexception-java-lang-class-cannot-be-cast-to-java-lang-reflec"
                    + " for more info",e);
            throw e;
        }
    }
公共静态类getClassFromGeneric(
对象parentObj,
int OridnalParameterizedTypeIndex)引发异常{
类型[]typeArray=GetParameteredTypeListAsArray(parentObj);
返回(类)类型数组[OridnalParameterizedTypeIndex];
}
公共静态类型[]GetParameteredTypeListAsArray(对象parentObj){
试一试{
return((ParameterizedType)parentObj.getClass()
.getGenericSuperclass())
.getActualTypeArguments();
}
catch(ClassCastException e){
logger.log(Level.severy,“很可能,在你的遗传链中的某个地方,”
+“存在一个使用原始类型而不是泛型参数的类。”
+“见:http://stackoverflow.com/questions/23074446/java-lang-classcastexception-java-lang-class-cannot-be-cast-to-java-lang-reflec"
+“更多信息”,e);
投掷e;
}
}
用法:

public class GenericBaseClass<T>{}
public class GenericImpl extends GenericBaseClass<String>{
    public static void main(String[] args){
        new GenericImpl();
    }

    public GenericImpl(){
        Class tClazz = getClassFromGeneric(this,0);
        Constructor constructor = tClazz.getConstructor();
        T newT = constructor.newInstance();
    }
}
公共类GenericBaseClass{}
公共类GenericImpl扩展了GenericBaseClass{
公共静态void main(字符串[]args){
新的GenericImpl();
}
公共泛型mpl(){
类tClazz=getClassFromGeneric(这个,0);
Constructor=tClazz.getConstructor();
T newT=constructor.newInstance();
}
}

与流行的观点相反,课堂上的一般信息不会被“删除”。

简短回答: Java是一个变量,这意味着您的字节码在运行时是常量。如果
E
未知,则无法为
new E()
生成字节码

说明:通用信息为:

这里应该生成什么字节码
.class
文件是在编译时立即生成的,但我们不知道
E
类型是什么

所以。。
new T()
是否可以替换为
new Object()
?坏主意,class
BoxWithPresent
不会喜欢它,因为它期望
E
Present

是否可以用
class.newInstance()
替换它?同样是否,方法范围中没有
变量

这就是为什么新的E()不可能的原因。

但是将
作为参数传递还是有一些解决办法的。

最简单的答案是泛型类型参数在运行时不存在

泛型在版本5中被改装成Java语言。为了保持与现有代码库的向后兼容性,它们通过擦除实现

泛型类型参数在编译时存在于源代码中,但在编译过程中,字节码中几乎删除了它们的所有证据。之所以选择这种泛型实现,是因为它维护了前泛型代码和Java5+泛型代码之间的互操作性。因此,泛型的类型安全性在很大程度上只是编译时的现象。如果您的通用代码符合
public class Container<E> {
     private E item;
     public E getItem() {return item;}
}
class BoxWithPresent extends Container<Present> {
}
class SimpleBox extends Container {
}
public class Container<E> {
    public <E> E createE() {
        return new E(); // imagine if that was allowed
    }
}
T myObject = new T();
public <T> T newInstance(Class<T> cls) {
    T myObject = cls.newInstance();
    return myObject;
}