Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typescript/9.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 迭代参数化列表(在原始列表类型赋值之后)_Java_Generics_Classcastexception_Foreach - Fatal编程技术网

Java 迭代参数化列表(在原始列表类型赋值之后)

Java 迭代参数化列表(在原始列表类型赋值之后),java,generics,classcastexception,foreach,Java,Generics,Classcastexception,Foreach,语言:Java 编译器版本:1.6 在下面的代码中,我尝试执行以下操作: 创建一个列表 添加一个字符串 将列表分配给原始列表 创建一个列表 将原始列表分配给列表 添加一个整数 使用get()@索引1和2检索值并打印它们 所有语句都在编译(带有警告)并正常运行 但是如果我尝试使用for循环遍历列表,我会得到一个ClassCastException。我只是想知道为什么它允许我使用list.get()方法,但不允许我迭代它 输出:(如果我使用未注释的for循环运行)abcd 200 这是我的密码 im

语言:Java
编译器版本:1.6

在下面的代码中,我尝试执行以下操作:

  • 创建一个
    列表
  • 添加一个
    字符串
  • 列表
    分配给原始
    列表
  • 创建一个
    列表
  • 将原始
    列表
    分配给
    列表
  • 添加一个
    整数
  • 使用
    get()
    @索引1和2检索值并打印它们
  • 所有语句都在编译(带有警告)并正常运行

    但是如果我尝试使用
    for
    循环遍历
    列表
    ,我会得到一个
    ClassCastException
    。我只是想知道为什么它允许我使用
    list.get()
    方法,但不允许我迭代它

    输出:(如果我使用未注释的for循环运行)abcd 200

    这是我的密码

    import java.util.*;
    import java.io.*;
    class CheckRawTypeAdd
    {
        public static void main(String[] sr)
        {   
            List<String> list_str = new ArrayList<String>();
            list_str.add("abcd");
            List<Integer> list_int = new ArrayList<Integer>();  
            List list_raw; 
            list_raw=list_str;
            list_int=list_raw;
            list_int.add(200);
            Object o1 = list_int.get(0);
            Object o2 = list_int.get(1);        
            System.out.println(o1);
            System.out.println(o2);
            //for(Object o : list_int)
            //{
            //  System.out.println("o value is"+o);
            //}
        }
    }
    
    import java.util.*;
    导入java.io.*;
    类CheckRawTypeAdd
    {
    公共静态void main(字符串[]sr)
    {   
    List_str=new ArrayList();
    添加列表(“abcd”);
    List_int=new ArrayList();
    原始列表;
    list_raw=list_str;
    list_int=list_raw;
    补充清单(200);
    对象o1=list_int.get(0);
    对象o2=list_int.get(1);
    系统输出打印项次(o1);
    系统输出打印Ln(o2);
    //用于(对象o:list_int)
    //{
    //System.out.println(“o值为”+o);
    //}
    }
    }
    
    代码

        for(Object o : list_int)
        {
          System.out.println("o value is"+o);
        }
    
    相当于这样的东西:

    for (Iterator<Integer> it = list.iterator(); it.hasNext();) {
        Integer o = it.next();
        System.out.println("o value is"+o);
    }
    
    for(Iterator it=list.Iterator();it.hasNext();){
    整数o=it.next();
    System.out.println(“o值为”+o);
    }
    
    如您所见,
    Iterator
    是泛型的,因此将值强制转换为其参数类型(
    Integer
    我们的案例)

    因此,行
    整数o=it.next()幕后执行以下操作:

    Integer o=(Integer)it.next()

    我认为现在很明显,
    ClassCastException
    是如何产生的。实际上,您成功地将字符串值插入到列表中,因此当
    it.next()
    返回字符串时,转换失败

    所以,“您是如何将字符串插入int列表的”这个问题仍然存在。 答案是泛型是编译器的魔力。他们的另一个名字是擦除。Java字节码不包含有关列表类型的信息。它只包含在需要时浇铸成混凝土类型。这就是您设法将参数化列表分配给原始列表,然后向其中添加sting的原因


    正如您正确提到的,您看到了警告。结论是“不要忽视编译警告”。

    < P>我会认为这是一个编译器错误,在代码> javac 。正在插入选中的强制类型转换。我们可以使用
    javap-c CheckRawTypeAdd
    来反汇编类(cast是101;注意,我在编译之前去掉了一些不需要的代码行,因此代码点会有所不同):

    但是,指示此强制转换应为
    对象
    ,而不是
    整数
    。首先通过语法定义术语:

    EnhancedForStatement:
        for ( FormalParameter : Expression ) Statement
    
    FormalParameter:
        VariableModifiersopt Type VariableDeclaratorId
    
    VariableDeclaratorId:
        Identifier
        VariableDeclaratorId []
    
    所以在我们的例子中,
    Type
    Object
    。然后它接着说这会转化成什么:

    for (I #i = Expression.iterator(); #i.hasNext(); ) {
        VariableModifiersopt TargetType Identifier =
            (TargetType) #i.next();
        Statement
    }
    
    因此,这里相关的是
    TargetType
    的分辨率。这在JLS中也有定义:

    如果Type(在FormalParameter产品中)是引用类型,那么TargetType就是Type

    由于
    对象
    肯定是引用类型,那么
    目标类型
    就是
    对象
    ,因此选中的强制转换应该是
    对象
    ,而不是
    整数

    此线程中的其他人进一步证明了这是一个bug,并指出,如果使用
    ecj
    (Eclipse的编译器),则不会出现此问题。但是,我知道这对于Oracle编译器团队来说是一个低优先级的bug,因为您必须滥用泛型来执行它。人们几乎会说这是一个功能,而不是一个bug

    随访 为了最终确认这是一个bug,这里有一个关于这个问题的现有bug报告:

    另外,我应该注意两件事首先,我上面给出的JLS参考是在最新的JLS中,而Java 7的这一部分实际上已经改变了(为了响应这个bug!)

    以下是增强型for语句应该翻译成的内容:

    如您所见,这里没有指定选中的强制转换。因此,
    javac
    中的缺陷不是它做了错误的转换,而是它做了任何转换

    Second,在Java 7中,
    javac
    根据JLS SE 7规范正确编译代码(这就是我上面引用的)。因此,以下代码起作用:

    List<String> list_str = new ArrayList<String>();
    ((List) list_str).add(new StringBuilder(" stringbuilder"));
    for (CharSequence o : list_str) {
       System.out.println("o value is" + o);
    }
    
    List\u str=new ArrayList();
    添加(新的StringBuilder(“StringBuilder”);
    用于(字符序列o:列表\u str){
    System.out.println(“o值为”+o);
    }
    

    正确的转换为
    字符序列
    ,而不是
    字符串
    。我最初使用的是JDK 6进行编译,而不是JDK 7。

    密切相关:@assylias,我尝试了搜索功能,但无法访问此链接。我现在正在经历它。谢谢。这是一个轶事,但为什么它会是
    整数o=it.next()
    而不是
    对象o=it.next()
    ?同样与您所说的相反,
    Iterator
    不强制转换任何内容,因为泛型是一个仅编译时的构造。它运行时没有任何异常。我想OP在for循环中用
    对象
    替换了
    整数
    。@Bhesh,不,我遇到了运行时故障。您正在使用Eclipse编译器吗?我在使用javac。@MarkPeters:是的,我在使用Eclipse编译器。+1回答得很好。我错过了部分
    如果Type(在FormalParameter产品中)是参考类型,那么TargetType是Type
    for (I #i = Expression.iterator(); #i.hasNext(); ) {
        VariableModifiersopt TargetType Identifier =
            (TargetType) #i.next();
        Statement
    }
    
    for (I #i = Expression.iterator(); #i.hasNext(); ) {
            VariableModifiersopt Type Identifier = #i.next();
       Statement
    }
    
    List<String> list_str = new ArrayList<String>();
    ((List) list_str).add(new StringBuilder(" stringbuilder"));
    for (CharSequence o : list_str) {
       System.out.println("o value is" + o);
    }