Error : Type mismatch: cannot convert from List<Integer> to ArrayList<Integer>

Error : Type mismatch: cannot convert from List<Integer> to ArrayList<Integer>

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];
    }

}

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

您正在将 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 的概念,因此下面的代码片段会给您编译时错误:

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

注一

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

   List<Integer> l = list[a];

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

您可以显式向下转换数组访问:

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

或者,更惯用的是,如果您不依赖任何特定方法 ArrayList List 接口中不存在该方法,您可以将 l 声明为List<Integer>:

List<Integer> l = list[a];

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

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

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

另一种不那么惯用的方法是将 list 变量的类型从 List<Integer>[] 更改为 ArrayList<Integer>[]。此更改将导致您的变量分配按照已写的方式工作。

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

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

像这样的转换并不理想,因为它取消了编译器保证所使用的所有类型在 运行 时有效的保证。但是,也有必要和适当的时候。

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