为何代码片段报错:ArrayList<String>无法转换为匿名ArrayList<String>?
为什么用var声明的匿名内部类实例无法重新赋值为父类类型?
先看触发报错的代码:
public class AnonymousAssign { public static void main(String[] args) { new AnonymousAssign().testAnonymousAssign(); } public void testAnonymousAssign() { var list1 = new ArrayList<String>() {{ add(""); }}; list1 = new ArrayList<String>(); // 此行触发报错 System.out.println(list1.getClass()); // 输出 class AnonymousAssign$1 } }
对应的报错信息:
error: incompatible types: ArrayList<String> cannot be converted to <anonymous ArrayList<String>> list1 = new ArrayList<String>();
原因解析
- var的类型推断逻辑是严格基于等号右侧实例的实际类型,不会自动向上推断到父类或接口。这里用双大括号初始化创建的是
ArrayList<String>的匿名子类,所以var会把list1的类型推断为这个匿名子类(也就是AnonymousAssign$1),而不是父类ArrayList<String>。 - Java的类型转换规则是:子类实例可以赋值给父类类型变量,但反过来不行。试图把普通
ArrayList<String>实例赋值给类型为匿名子类的list1,本质是父类对象转子类类型,属于非法的向下转型,编译器直接报错。 list1.getClass()输出AnonymousAssign$1也能证明这一点:变量的实际类型就是这个匿名内部类,而非java.util.ArrayList本身。
解决办法
如果需要支持重新赋值为普通ArrayList实例,有两种方案:
- 显式声明变量类型:放弃var,直接把变量类型指定为
ArrayList<String>,这样不管右侧是匿名子类还是普通父类实例,都能兼容:ArrayList<String> list1 = new ArrayList<String>() {{ add(""); }}; list1 = new ArrayList<String>(); // 正常编译 - 去掉匿名子类初始化:如果不需要匿名子类的特性(比如只是初始化添加元素),直接用普通的
ArrayList创建方式,这样var推断的类型就是ArrayList<String>,自然可以重新赋值:var list1 = new ArrayList<String>(); list1.add(""); list1 = new ArrayList<String>(); // 正常编译
内容的提问来源于stack exchange,提问作者djy
相关产品推荐
相关产品推荐

