【问题标题】:Error : Type mismatch: cannot convert from List<Integer> to ArrayList<Integer>错误:类型不匹配:无法从 List<Integer> 转换为 ArrayList<Integer>
【发布时间】:2021-06-26 15:45:24
【问题描述】:
package set01;

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

public class DFTList {
    static List<Integer>[]   list;
    static boolean[] visited;
    
    public DFTList(int nodes) {
        list = new ArrayList[nodes];
        visited = new boolean[nodes];
        for(int i=0;i<nodes;i++) {
           list[i] = new ArrayList<>();
        }
    }

    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        System.out.println("Enter no. of nodes : ");
        int nodes = scan.nextInt();
        DFTList obj = new DFTList(nodes);
        System.out.println("Enter no.of vertex : ");
        int vertex = scan.nextInt();
        
        
        for(int i=0;i<vertex;i++) {
            int v1 = scan.nextInt();
            int v2 = scan.nextInt();
            list[v1].add(v2);
            list[v2].add(v1);
        }
        
        solve(0);
    }
    
    public static void solve(int a) {
        visited[a] = true;
        ArrayList<Integer> l = list[a];
    }

}

在上面的代码 sn-p 中,在DFTList 构造函数中,我在数组的所有索引处插入了ArrayList 对象。但是,当我尝试在 solve 方法 中检索相同的对象并将其存储在 same reference 下时,我遇到了一个错误,指出“类型不匹配:无法从列表到 ArrayList”。为什么会出现这个错误?

【问题讨论】:

  • 顺便说一句,每次创建新实例时(在构造函数中)设置静态字段意味着每个新实例都会覆盖前一个实例使用的字段。要解决此问题,应将字段和 solve 方法设为非静态。然后将在实例上进行所有操作,而不是静态方法:DFTList obj = new DFTList(nodes); ... obj.list[v1].add(v2); obj.list[v2].add(v1); ... obj.solve(0);。

标签: java casting compiler-errors


【解决方案1】:

list 变量是一个List&lt;Integer&gt;[],这意味着任何类型的List(ArrayList、LinkedList 等)都可以存储在其中。当从这个列表中检索一个元素时,Java 编译器只知道它是某种类型的List;它不知道List 的具体类型(即使您作为程序员知道您只是在数组中存储ArrayList 项)。因此,ArrayList&lt;Integer&gt; l = list[a] 是编译失败,因为编译器无法保证从数组中检索到的元素是 ArrayList 而不是不同的 List 类型。

有几种方法可以解决这个问题。假设您想将list 保留为数组,最惯用的方法是将其类型更改为List&lt;Integer&gt;[] 而不是ArrayList&lt;Integer&gt;[]。由于您没有使用特定于ArrayList 的任何方法或其他API,因此List 接口是此类型的更好选择。

    public static void solve(int a) {
        visited[a] = true;
        List<Integer> l = list[a];
    }

另一种不太惯用的方法是将list 变量的类型从List&lt;Integer&gt;[] 更改为ArrayList&lt;Integer&gt;[]。此更改将导致您的变量分配按已编写的方式工作。

public class DFTList {
    static ArrayList<Integer>[] list;
    ...
}

当您有一个接口类型的数组(在这种情况下为List&lt;Integer&gt;)时,您可以使用的最后一种方法是在将元素存储到变量时将其转换为具体类型。这基本上是在告诉编译器,您作为开发人员知道该元素属于该子类型,因此即使它不能保证分配,它也会允许它发生。这种方法推迟了类型检查——确保List 是ArrayList 子类型——直到代码实际运行(在运行时)。如果在运行代码时存储的元素是ArrayList 以外的子类型(例如,如果它是LinkedList),那么Java 将抛出ClassCastException,因为无法分配给ArrayList。

这样的强制转换并不理想,因为它消除了编译器对所有正在使用的类型都保证在运行时有效的保证。但是,有时它是必要和适当的。

    public static void solve(int a) {
        visited[a] = true;
        ArrayList<Integer> l = (ArrayList<Integer>) list[a];
    }

【讨论】:

    【解决方案2】:

    list 被声明为List&lt;Integer&gt;[](阅读:整数列表数组)。每个元素中的值实际上是 ArrayList 的事实是无关紧要的 - 就编译器而言,每个元素都是 List。

    您可以明确地向下转换数组访问:

    ArrayList<Integer> l = (ArrayList<Integer>)list[a];
    

    或者,更惯用的说法,如果您不依赖 ArrayList 接口中不存在的任何特定方法 List,您可以将 l 声明为 List&lt;Integer&gt;:

    List<Integer> l = list[a];
    

    【讨论】:

    • (读作:一个整数列表数组)没错,但 List 只是在 ArrayList/LinkedList 中完成的一个接口实际实现,对吧!那么为什么我不能使用 ArrayList l = list[a];我仍然很困惑,如果可能的话,请提供一些额外的解释/示例。并感谢您的回答!
    【解决方案3】:

    您正在将 C++ 与 Java 混合使用!

    检查以下可重现的代码:

        public class DFTList {
        static List<Integer>[]   list;
        static boolean[] visited;
        
        public DFTList(int nodes) {
            list = new ArrayList[nodes];
            visited = new boolean[nodes];
            for(int i=0;i<nodes;i++) {
               list[i] = new ArrayList<>();
            }
        }
    
        public static void main(String[] args) {
            Scanner scan = new Scanner(System.in);
            System.out.println("Enter no. of nodes : ");
            int nodes = scan.nextInt();
            DFTList obj = new DFTList(nodes);
            System.out.println("Enter no.of vertex : ");
            int vertex = scan.nextInt();
            
            
            for(int i=0;i<vertex;i++) {
                int v1 = scan.nextInt();
                int v2 = scan.nextInt();
                list[v1].add(v2);
                list[v2].add(v1);
            }
            
            solve(0);
        }
        
        public static void solve(int a) {
            visited[a] = true;
            List<Integer> l = list[a];
        }    
    }
    

    注意 0

    java 中没有类似pointer 的概念,因此遵循 sn-p 会导致编译时错误:

     * list[i] = new ArrayList<>();
    

    注 1

    您将List 接口分配给l 类型,因此请使用以下语法。

       List<Integer> l = list[a];
    

    【讨论】:

    • 对不起兄弟,是我的错误,我已经包含(*)来突出显示,并没有意识到人们可能认为它是指针的对应部分。现在,我编辑了帖子。
    猜你喜欢
    • 2018-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-18
    • 1970-01-01
    • 2019-08-24
    • 1970-01-01
    • 2017-04-17
    相关资源
    最近更新 更多