首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >类型擦除泛型

类型擦除泛型
EN

Stack Overflow用户
提问于 2022-04-17 07:56:43
回答 2查看 93关注 0票数 0

在编译时,新的T5会发生错误,称为=>错误:泛型数组的创建,据我的理解,数组是在编译时创建的,而且由于我们在编译时不知道T的类型,所以不能实例化数组。但是,如果T在编译时被擦除并更改对象,那么为什么还会发生此错误呢?因为我们可以创建一个对象数组。

代码语言:javascript
复制
// Before Compiling 
public class GenericClass<T> {
    GenericClass(){
        T[] obj = new T[5];
    }
}

// After Compiling
public class GenericClass {
GenericClass() {
Object[] obj = new Object[5];
}
}

类似的情况,就像,

代码语言:javascript
复制
public class GenericClass<T> {
        GenericClass(){
            T obj = new T(); }}

/*  error :required: class
  found:    type parameter T
  where T is a type-variable:
  T extends Object declared in class GenericClass*/
EN

回答 2

Stack Overflow用户

发布于 2022-04-17 08:17:53

根据我的理解,数组是在编译时创建的。

不,数组是在运行时创建的。

由于我们在编译时不知道T的类型,所以不能实例化数组。

对,是这样。

,但是如果T在编译时被擦除并更改对象,那么为什么还会发生此错误呢?

因为“它在编译时被擦除并更改对象”被过度简化。

而且,泛型和数组之间并不友好。问题是,在删除泛型部分的地方,数组不像那个那样工作。你可以这样做:

代码语言:javascript
复制
String[] x = new String[10];
tellMeTheTypeOfMyArray(x);

void tellMeTheTypeOfMyArray(Object[] o) {
  System.out.println("Your array's component type is: " + o.getClass().getComponentType());
}

此代码将编译和工作良好,没有错误,并打印:

代码语言:javascript
复制
Your array's component type is: java.lang.String

与泛型不同,在泛型中,不能编写这种方法。你不可能这样做:

代码语言:javascript
复制
List<String> x = new ArrayList<String>();
tellMeTheTypeOfMyList(x);

void tellMeTheTypeOfMyList(List<?> o) {
  System.out.println("Your list's component type is: " + ??????);
}

工作。这里不可能有java代码,您不能用任何东西来代替?打印字符串,因为该信息在运行时根本不存在。

想象一下这段代码:

代码语言:javascript
复制
// This is written by Wahab today.

class Example<T> {
  protected T[] arr;

  Example() {
    this.arr = new T[10];
  }
}

照你想的那样做了。那我就做:

代码语言:javascript
复制
// Written by me, a year later
class Uhoh extends Example<String> {
  Uhoh() {
    super();
  }

  void hmmm() {
    System.out.println(this.arr.getComponentType());
  }
}

我显然期望,不,要求--这个打印java.lang.String,但是它不可能这样做,。因为这是奇怪和令人困惑的,java有一条规则:如果您编译代码而没有看到任何关于泛型问题的警告(并且没有@SuppressWarnings ),那么这种混淆是不可能发生的。

允许您编写new T[],而这只是编写new Object[]的一种愚蠢的方式,这被认为是远远不够的。

那么,如何在泛型类型中使用数组呢?

java.util.ArrayList一样:在这里不使用泛型()。如果您打算在泛型代码中创建数组,那么数组几乎不应该有T类型。如果您的代码库中任何地方都有一个T[],那么这意味着您永远不应该为它做任何事情--让代码的调用者为您做这件事。如果您确实希望自己创建新的数组,不要使用T,使用new作为类型,并在需要时转换为T。这就是java内置的ArrayList类的工作原理。一些摘录是从原著中直接粘贴过来的:

代码语言:javascript
复制
    transient Object[] elementData; // non-private to simplify nested class access

    public E get(int index) {
        Objects.checkIndex(index, size);
        return elementData(index);
    }

    @SuppressWarnings("unchecked")
    E elementData(int index) {
        return (E) elementData[index];
    }

这里有一个例子,同样直接来自ArrayList的源代码(或者更确切地说,java.util.Collection定义了它,ArrayList继承了它),在这里,您可以让调用者为您提供代码来生成数组:

代码语言:javascript
复制
    default <T> T[] toArray(IntFunction<T[]> generator) {
        return toArray(generator.apply(0));
    }

在这里,调用方提供了一个将int转换为T[]的函数--它接受了执行new String[10]的概念,并将其转化为函数,然后将其传递给toArray方法,后者将使用它(尽管您可以忽略它在这里的使用方式,这是一个有点奇怪的解决方案。它起作用了,只是--不确定你是否应该从中吸取教训)。

你就这样用它:

代码语言:javascript
复制
List<String> listOfStrings = ...;
String[] convertedToArray = listOfStrings.toArray(String[]::new);
票数 1
EN

Stack Overflow用户

发布于 2022-05-01 06:48:00

Java数组在运行时知道它们的组件类型。创建数组时,必须在运行时提供组件类型。但是在您的GenericClass中,它不能这样做,因为它不知道T在运行时是什么。如果它创建了一个Object[],那么该对象将有错误的运行时类,并且如果T[]不是Object,那么该实例与T类型不兼容。你是对的,在课堂上,没有什么是立即错的。但是,如果变量是T[]的声明暴露在外部作用域中,期望T是更特定的类型,则会导致ClassCastException

代码语言:javascript
复制
// Before type erasure 
class GenericClass<T> {
    T[] obj;
    GenericClass() {
        obj = new T[5]; // if hypothetically you could do this
    }
    T[] getObj() {
        return obj;
    }
}
class MyCode {
    public static void main(String[] args) {
        GenericClass<String> foo = new GenericClass<>();
        String[] strings = foo.getObj(); // no casts needed; no warnings
    }
}

// After type erasure
class GenericClass {
    Object[] obj;
    GenericClass() {
        obj = new Object[5];
    }
    Object[] getObj() {
        return obj;
    }
}
class MyCode {
    public static void main(String[] args) {
        GenericClass foo = new GenericClass();
        String[] strings = (String[]) foo.getObj(); // ClassCastException at runtime
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71900220

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档