作为java.lang.Object结果的泛型不能转换为[Ljava.lang.Object]

作为java.lang.Object结果的泛型不能转换为[Ljava.lang.Object],java,generics,classcastexception,generic-list,Java,Generics,Classcastexception,Generic List,任何人都可以解释为什么泛型会导致ClassCastException(运行时异常!) 我知道所有的泛型都是在编译阶段删除的,对字节码没有任何影响,但似乎有些细微差别 下面是我的示例(本文简化): 我不明白这段代码出了什么问题。有人能解释一下这种行为吗?为什么要在对象数组列表中强制转换它 尝试对象列表,它将工作 import java.util.ArrayList; import java.util.List; public class CastTest { public static

任何人都可以解释为什么泛型
会导致
ClassCastException
(运行时异常!)

我知道所有的泛型都是在编译阶段删除的,对字节码没有任何影响,但似乎有些细微差别

下面是我的示例(本文简化):


我不明白这段代码出了什么问题。有人能解释一下这种行为吗?

为什么要在对象数组列表中强制转换它

尝试对象列表,它将工作

import java.util.ArrayList;
import java.util.List;

public class CastTest {
    public static void main(String[] args) {
        List a = new ArrayList();
        a.add(new Object());
        List<Object> b = a;
        b.get(0).toString();
    }
}
import java.util.ArrayList;
导入java.util.List;
公共类测试{
公共静态void main(字符串[]args){
列表a=新的ArrayList();
a、 添加(新对象());
清单b=a;
b、 get(0.toString();
}
}

为什么要在对象数组列表中强制转换它

尝试对象列表,它将工作

import java.util.ArrayList;
import java.util.List;

public class CastTest {
    public static void main(String[] args) {
        List a = new ArrayList();
        a.add(new Object());
        List<Object> b = a;
        b.get(0).toString();
    }
}
import java.util.ArrayList;
导入java.util.List;
公共类测试{
公共静态void main(字符串[]args){
列表a=新的ArrayList();
a、 添加(新对象());
清单b=a;
b、 get(0.toString();
}
}

如果您这样看,可能会更清楚:

import java.util.ArrayList;
import java.util.List;

class Dog { }
class Cat { }

public class CastTest {
    public static void main(String[] args) {
        List a = new ArrayList();
        a.add(new Dog());
        List<Cat> b = a;
        Cat c = b.get(0);
    }
}

$ java CastTest
Exception in thread "main" java.lang.ClassCastException: Dog cannot be cast to Cat
    at CastTest.main(CastTest.java:12)
如果确实希望它是一个对象数组列表,则必须添加一个对象数组:

import java.util.ArrayList;
import java.util.List;

public class CastTest {
    public static void main(String[] args) {
        List a = new ArrayList();
        a.add(new Object[]{});
        List<Object[]> b = a;
        System.out.println(b.get(0).toString());
    }
}

$ java CastTest
[Ljava.lang.Object;@65685e30
import java.util.ArrayList;
导入java.util.List;
公共类测试{
公共静态void main(字符串[]args){
列表a=新的ArrayList();
a、 添加(新对象[]{});
清单b=a;
System.out.println(b.get(0.toString());
}
}
$java CastTest
[Ljava.lang.Object;@65685e30

如果您这样看,可能会更清楚:

import java.util.ArrayList;
import java.util.List;

class Dog { }
class Cat { }

public class CastTest {
    public static void main(String[] args) {
        List a = new ArrayList();
        a.add(new Dog());
        List<Cat> b = a;
        Cat c = b.get(0);
    }
}

$ java CastTest
Exception in thread "main" java.lang.ClassCastException: Dog cannot be cast to Cat
    at CastTest.main(CastTest.java:12)
如果确实希望它是一个对象数组列表,则必须添加一个对象数组:

import java.util.ArrayList;
import java.util.List;

public class CastTest {
    public static void main(String[] args) {
        List a = new ArrayList();
        a.add(new Object[]{});
        List<Object[]> b = a;
        System.out.println(b.get(0).toString());
    }
}

$ java CastTest
[Ljava.lang.Object;@65685e30
import java.util.ArrayList;
导入java.util.List;
公共类测试{
公共静态void main(字符串[]args){
列表a=新的ArrayList();
a、 添加(新对象[]{});
清单b=a;
System.out.println(b.get(0.toString());
}
}
$java CastTest
[Ljava.lang.Object;@65685e30

正如其他人所说,因为
对象
不是
对象[]

短语
java.lang.Object中有提示,不能将其强制转换为[Ljava.lang.Object

根据,
[Ljava.lang.Object
的意思是:

  • [
    -数组
  • L
    -一个类

因此,
java.lang.Object不能转换为[Ljava.lang.Object
可以理解为对象不能转换为对象数组

,正如其他人所说,因为
对象
不是
对象[]

短语
java.lang.Object中有提示,不能将其强制转换为[Ljava.lang.Object

根据,
[Ljava.lang.Object
的意思是:

  • [
    -数组
  • L
    -一个类

因此,
java.lang.Object不能强制转换为[Ljava.lang.Object
可以被读取为对象不能强制转换为对象数组

您告诉编译器您要调用
Object[].toString()
。这就是编译器生成强制转换(
checkcast
)的原因:


您告诉编译器要调用
对象[]。toString()
。这就是编译器生成强制转换(
checkcast
)的原因:


这是因为编译器坏了

    b.get(0).toString();
深入

    Object[] temp = b.get(0);
    temp.toString();
    Object temp = b.get(0);
    temp.toString();
当被擦除时,具有对
对象[]
的强制转换

现在可以说,编译器也可以选择将其分解为

    Object temp = b.get(0);
    temp.toString();

因为引用仅用于调用
.toString()
是在
对象上声明的。如果它这样做了,它将避免强制转换。然而,为什么编译器会投入额外的分析工作,以不同的方式做一些事情,而这只在您使用错误的类型时才起作用呢?

这是因为编译器坏了

    b.get(0).toString();
深入

    Object[] temp = b.get(0);
    temp.toString();
    Object temp = b.get(0);
    temp.toString();
当被擦除时,具有对
对象[]
的强制转换

现在可以说,编译器也可以选择将其分解为

    Object temp = b.get(0);
    temp.toString();

因为引用仅用于调用
.toString()
是在
对象上声明的,如果它这样做了,它将避免强制转换。然而,为什么编译器会投入额外的分析工作,以不同的方式做一些事情,而这只会在您使用错误的类型时才起作用呢?

因为
a
包含
对象,而不是
对象[]
。这并不重要,我在本例中没有使用任何强制转换。它是隐式完成的。您能解释一下这是怎么可能的吗?因为类型擦除()不允许泛型在运行时执行某些操作,因为
对象[]对象的实例
true
,没有编译错误的原因。因为
a
包含
Object
,而不是
Object[]
。这不重要,我在本例中没有使用任何强制类型转换。它是隐式完成的。您能解释一下这是怎么可能的吗?因为类型擦除()不允许泛型在运行时执行某些操作,因为
Object[]对象的实例
true
,没有编译错误的原因。Why-它是另一个问题,让我们同意此强制转换需要某些原因:-)我理解如果我删除所有的将很好。Why-它是另一个问题,让我们同意此强制转换需要某些原因:-)我理解如果我删除所有的将很好ion,但没有回答为什么JVM在listHi中尝试强制转换项,@Akvel,请参阅我的最新编辑,以查看字节码中生成的强制转换,如您在上面提供的链接(docs.oracle.com/javase/tutorial/java/generics/erasure.html)中所述如果有必要,编译器将插入类型强制转换,以保持类型安全。这是一个解决方案,但没有回答为什么JVM在listHi中尝试强制转换项目,@Akvel,请参阅我的最新编辑以查看在字节码中生成的强制转换,如上面提供的链接所述(docs.oracle.com/javase/tutorial/java/generics/erasure.html)