当前位置: 首页 > 知识库问答 >
问题:

为什么不能使用“new”运算符创建泛型类型的实例?

范成周
2023-03-14

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

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

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

共有3个答案

有德业
2023-03-14

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

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

用法:

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

与普遍的看法相反,类级别的通用信息并没有被“删除”。

融焕
2023-03-14

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

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

泛型类型参数在编译时存在于源代码中,但在编译期间,它们的几乎所有证据都在字节代码中被移除。选择这种泛型实现是因为它维护了前泛型代码和Java 5泛型代码之间的互操作性。因此,泛型的类型安全在很大程度上只是编译时现象。如果您的泛型代码编译时没有错误和警告,那么您就可以确信您的代码是类型安全的。

然而,由于擦除,有两种类型(从Java 5开始):

>

  • 可赔偿的。例如,StringInteger等。可重写类型在编译时具有与运行时相同的类型信息。

    不可偿还。例如<code>列表

    不能将 new 运算符用于不可重用的类型,因为在运行时,JVM 没有类型安全的方式来生成正确类型的对象。

    源代码:

    T myObject = new T();
    

    以上不编译。在运行时,< code>T已被擦除。

    规避类型擦除和 Java 泛型的一些问题的策略是使用类型标记。此策略在以下用于创建新的 T 对象的泛型方法中实现:

    public <T> T newInstance(Class<T> cls) {
        T myObject = cls.newInstance();
        return myObject;
    }
    

    泛型方法从作为参数传递的Class对象中捕获类型信息。此参数称为类型标记。不幸的是,类型标记本身必须始终是可实现的(因为您无法为不可实现的类型获取Class对象),这会限制它们的有用性。

  • 韩夕
    2023-03-14

    简而言之:Java是一种编译的编程语言,这意味着字节码在运行时是恒定的。如果<code>E

    解释:通用信息在运行时被删除:

    public class Container<E> {
         private E item;
         public E getItem() {return item;}
    }
    class BoxWithPresent extends Container<Present> {
    }
    class SimpleBox extends Container {
    }
    

    在字节码中,类< code>BoxWithPresent包含类型< code>Present的字段< code>item,但类< code>SimpleBox包含类型< code>Object的字段< code>item(因为未指定类型< code>E)。

    现在您编写抽象实例化方法:

    public class Container<E> {
        public <E> E createE() {
            return new E(); // imagine if that was allowed
        }
    }
    

    这里应该生成什么字节码?<代码>。class文件是在编译时生成的,但是我们不知道什么是< code>E类型。

    所以。。新的 T() 可以用新的 Object() 替换吗?坏主意,类BoxWithPresent不会喜欢它,因为它期望E存在

    可以用< code>class.newInstance()替换吗?同样,在方法范围内没有< code>class变量。

    这就是为什么<code>新的E()但是,通过将<code>类

     类似资料:
    • 问题内容: 我读到从Java 7开始,像在第一条语句中那样在右侧指定类型来创建Collections是不好的样式,因为编译器可以从左侧推断类型。 我的问题是,当像这样初始化列表时,编译器找不到类型,并且我收到未经检查的类型警告: 问题答案: 编译器不会 推断 类型,因为您正在实例化 raw 。但是它足够聪明,可以警告您在使用此(原始)对象时可能会出现问题。 值得一提的是此警告背后的原因。由于类型擦

    • 问题内容: 我正在使用泛型编写某些东西,令我惊讶的是,我发现这行不通: 那我不能实例化泛型吗?没有任何方法可以做到这一点吗? 问题答案: 是的,这真是令人讨厌。 我使用的解决方法是强制客户端在构造新类时传递类-即 然后您可以使用。

    • 问题内容: 我有一个通用的抽象模板类。我以为如果创建特定于类型的生产者,则可以直接在通用类中注入一些DAO服务。但是我不能。 为什么?我该如何解决? 当我注入一个例如它完美地工作。但是没有泛型… 问题答案: 当您要求 容器知道您要一个类型为的bean 。如果存在这样的bean并且其类型信息已知,则容器可以满足注入。例如,类型信息保留在带注释的方法中 容器使用反射来检索该参数化的类型,并将其与请求的

    • 问题内容: 下列类定义了两种方法,它们在直观上都具有相同的功能。每个函数都有两个类型和一个布尔值的列表来调用,该值指定应将这些列表中的哪个分配给局部变量。 根据,有效而无效。它抱怨: 我知道查找包含三元运算符()的表达式类型的规则非常复杂,但是据我了解,它选择了最具体的类型,第二个和第三个参数都可以转换为该类型,而无需显式投。在这里,应该是,但不是。 我想解释一下为什么不是这种情况,最好参考 Ja

    • 问题内容: 是否可以在Java中创建泛型类型的实例?我正在根据我所看到的答案进行思考no(由于类型擦除),但是如果有人能看到我所缺少的内容,我将很感兴趣: 编辑:事实证明,超级类型令牌可以用于解决我的问题,但是它需要很多基于反射的代码,如下面的一些答案所示。 问题答案: 你是对的。你做不到。但你可以将其更改为 但这有效。以工厂模式包装它会使它更具容忍性。

    • 如何将Java7类型推断用于泛型实例创建功能?使用这种新样式有什么好处?