首页 > 试题广场 >

以下说法错误的是()

[单选题]
以下说法错误的是()

  • 虚拟机中没有泛型,只有普通类和普通方法
  • 所有泛型类的类型参数在编译时都会被擦除
  • 创建泛型对象时请指明类型,让编译器尽早的做参数检查
  • 泛型的类型擦除机制意味着不能在运行时动态获取List<T>中T的实际类型
1、创建泛型对象的时候,一定要指出类型变量T的具体类型。争取让编译器检查出错误,而不是留给JVM运行的时候抛出类不匹配的异常。 2、JVM如何理解泛型概念 —— 类型擦除。事实上,JVM并不知道泛型,所有的泛型在编译阶段就已经被处理成了普通类和方法。 处理方法很简单,我们叫做类型变量T的擦除(erased) 。 总结:泛型代码与JVM ① 虚拟机中没有泛型,只有普通类和方法。 ② 在编译阶段,所有泛型类的类型参数都会被Object或者它们的限定边界来替换。(类型擦除) ③ 在继承泛型类型的时候,桥方法的合成是为了避免类型变量擦除所带来的多态灾难。 无论我们如何定义一个泛型类型,相应的都会有一个原始类型被自动提供。原始类型的名字就是擦除类型参数的泛型类型的名字。
发表于 2017-04-19 08:20:29 回复(25)
D 可以通过反射机制
发表于 2016-12-29 11:31:14 回复(8)
运用泛型编译器不建议使用raw原生类型,而是要指明具体类型List<String>,以便编译器作参数检查。
在编译阶段会采取擦除机制,将所有的泛型都编译成为原生类型List,因为虚拟机中没有泛型,只有普通类和普通方法。
那JVM是如何获取具体类型的呢,答案是强大的反射机制,也正因为有了反射才促生了泛型,所以D错。
-----------------------------------------------------------------------------------------------------
所以,如果你对自己的编程足够自信,你完全可以在写代码的时候只写原生类型而不用泛型,因为其实这只是为了编译器在检查代码的时候防止参数错误,到了编译期泛型都会被擦除,最终还是回到原生类型。
但是,并不建议这么做,因为虽然只写原生类型可以省略编译期泛型擦除这一步,但是这对性能的提升并没起多大哪怕一丁点的作用,反而可能导致我们写代码的时候由于粗心出错了而没有被IDE编译器检查出来,直到运行的时候才报错就得不偿失了。
编辑于 2019-09-29 11:08:00 回复(7)
// 通过反射得到T的真实类型
ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();
T的真是类型 = (Class) pt.getActualTypeArguments()[0];//取第一个泛型的类型

发表于 2017-04-17 21:49:37 回复(8)

Java编程思想这样理解泛型的擦除

  • Java泛型是使用擦除来实现的,这意味着当你在使用泛型时,任何具体的类型信息都被擦除了,你唯一知道的就是你在使用一个对象。因此List<String>和List<Integer>在运行时实际上是相同的类型。这两种类型都被擦除成它们的“原生”类型,即List。
发表于 2017-05-14 10:20:06 回复(0)
《java编程的逻辑》第8.1节

发表于 2020-03-21 11:08:14 回复(0)
先说一下,这题目的答案,也只能选D了,但并不是所有情况都能获得泛型的具体类型。
以下为具体测试:
List<String> list = new ArrayList<String>();//这里后面加不加String都是一样的,编译时会自动擦除:
Class clazz = list.getClass();
Type genType = clazz.getGenericSuperclass();
Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
if (!(params[0] instanceof Class)) {
    System.out.println("无法获得类型");
}else{
    System.out.println(((Class)params[0]).getName());
}
输出结果:无法获得类型
为什么呢?
    因为编译时会自动擦除类型。泛型等同于Object。这种情况是没有办法在运行时获得泛型的具体类型。
什么情况下可以获得泛型的具体类型呢?
    如果一个类实现泛型接口时直接指定了泛型参数的类型,那么在这个类的内部会自动保存泛型参数的类型。所以以下方法是可以获得类型的:
List<String> list = new ArrayList<String>(){ //这里必须指明String类型,创建一个匿名类实现泛型接口
};
Class clazz = list.getClass();
...同上
输出结果:java.lang.String
通过创建一个指明了泛型参数类型的匿名类,保存泛型的具体类型。这样可以取得泛型的具体类型。
WTF?? 这样实际上已经生成另一个具体的类,根本就不是泛型类了!
用类型擦除实现的泛型真的太不方便了。

发表于 2019-01-29 11:58:09 回复(1)
1.虚拟机中没有泛型,只有普通类和普通方法
2.
所有泛型类的类型参数在编译时都会被擦除
3.
创建泛型对象时请指明类型,让编译器尽早的做参数检查(Effective Java,第23条:请不要在新代码中使用原生态类型)
4.
不要忽略编译器的警告信息,那意味着潜在的ClassCastException等着你。
发表于 2017-04-26 10:30:42 回复(0)
jvm中会提供一个名为signature的标识,来存放泛型的类型
发表于 2017-08-19 00:11:03 回复(0)
1.泛型是用擦除实现的,原因是为了解决移植兼容性,1.5之前不存在泛型,使用擦除实现允许泛化的代码与非泛化的代码共存;
2.泛型的类型参数编译时检查,运行时擦除;
3.使用原生态类型就会失去泛型的优势,<<efffective java>>也有指出不要在新代码中使用原生态类型;
4.泛型擦除意味着在运行时无法通过class.getTypeParameters()获得类型参数;但是可以通过擦除补偿机制来保存泛型参数类型,比如Class<T>,Class/Method/Filed的signature属性。

发表于 2020-08-18 10:00:48 回复(0)
,。。
发表于 2017-03-07 16:16:45 回复(0)
 public static void main(String[] args) throws IllegalAccessException, InstantiationException {
        List<String> a = new ArrayList<>();
        Class<? extends List> aClass = a.getClass();
        ParameterizedType genericSuperclass = (ParameterizedType)aClass.getGenericSuperclass();
        Type[] actualTypeArguments = genericSuperclass.getActualTypeArguments();
        for (int i = 0;i <actualTypeArguments.length;i++)
        System.out.println(actualTypeArguments[i]);

    }

发表于 2020-02-18 08:37:57 回复(0)
JVM虚拟机中运行的,也就是编译之后的字节码中,是没有泛型概念的,因为在源代码编译时就已经被擦除。
没有了泛型的概念不代表不能获取泛型类型,反射机制是很强大的:
ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();

发表于 2018-02-24 11:55:34 回复(0)
1、创建泛型对象的时候,一定要指出类型变量T的具体类型。争取让编译器检查出错误,而不是留给JVM运行的时候抛出类不匹配的异常。 2、JVM如何理解泛型概念 —— 类型擦除。事实上,JVM并不知道泛型,所有的泛型在编译阶段就已经被处理成了普通类和方法。 处理方法很简单,我们叫做类型变量T的擦除(erased) 。 总结:泛型代码与JVM ① 虚拟机中没有泛型,只有普通类和方法。 ② 在编译阶段,所有泛型类的类型参数都会被Object或者它们的限定边界来替换。(类型擦除) ③ 在继承泛型类型的时候,桥方法的合成是为了避免类型变量擦除所带来的多态灾难。 无论我们如何定义一个泛型类型,相应的都会有一个原始类型被自动提供。原始类型的名字就是擦除类型参数的泛型类型的名字。
发表于 2022-06-08 10:37:53 回复(0)
在编译时期泛型不是已经被擦除了吗? 为何通过反射还可以获取到T的实际类型?
发表于 2022-02-17 15:04:22 回复(1)
1、创建泛型对象的时候,一定要指出类型变量T的具体类型。争取让编译器检查出错误,而不是留给JVM运行的时候抛出类不匹配的异常。 2、JVM如何理解泛型概念 —— 类型擦除。事实上,JVM并不知道泛型,所有的泛型在编译阶段就已经被处理成了普通类和方法。 处理方法很简单,我们叫做类型变量T的擦除(erased) 。 总结:泛型代码与JVM ① 虚拟机中没有泛型,只有普通类和方法。 ② 在编译阶段,所有泛型类的类型参数都会被Object或者它们的限定边界来替换。(类型擦除) ③ 在继承泛型类型的时候,桥方法的合成是为了避免类型变量擦除所带来的多态灾难。 无论我们如何定义一个泛型类型,相应的都会有一个原始类型被自动提供。原始类型的名字就是擦除类型参数的泛型类型的名字。
发表于 2021-11-03 20:22:23 回复(0)
/* 通过反射在运行时动态获取List<t>中T的实际类型 */ 
public class GetGeneric {
    public List<String> list;
    public static void main(String[] args) throws NoSuchFieldException, SecurityException {
          Type t = GetGeneric.class.getDeclaredField("list").getGenericType();  
            if (ParameterizedType.class.isAssignableFrom(t.getClass())) {  
                for (Type t1 : ((ParameterizedType) t).getActualTypeArguments()) {  
                    System.out.print(t1);  
                }  
            } 
    }
}

编辑于 2018-06-06 22:06:57 回复(0)
求大牛解答!
发表于 2017-04-13 11:24:13 回复(0)
可以通过反射在运行期间得到泛型的类型

发表于 2023-08-10 09:52:36 回复(0)
可以通过反射获得泛型类赢
发表于 2019-04-17 07:05:10 回复(0)