Java三类ArrayList声明方式差异及接口优先声明的原因
Java集合基础问题解答
问题1:三种ArrayList声明语句的具体差异
三种不会报错的声明语句如下:
a) List l = new ArrayList<String>();
b) List<String> l = new ArrayList<String>();
c) List<String> l = new ArrayList<>();
三者差异如下:
- 写法a:属于*原始类型(Raw Type)*用法,泛型信息仅在右侧初始化时定义,赋值给原始类型List后,编译器会直接丢失泛型校验能力。后续往列表中插入Integer、Object等非String类型元素都不会触发编译报错,只有运行时才可能抛出类型转换异常,仅在兼容JDK1.5之前的老代码时使用,日常开发完全不推荐。
- 写法b:是JDK1.5~JDK1.6版本的标准泛型声明写法,左右两侧都明确指定泛型参数为String,编译器会执行完整的类型校验,插入非String类型元素会直接编译报错,类型完全安全。
- 写法c:是JDK1.7及以上版本推出的*钻石语法(Diamond Operator)*用法,右侧<>中的泛型类型会自动根据左侧变量的泛型类型推断,运行效果和写法b完全一致,仅简化了代码冗余,是当前主流JDK版本中最常用的写法。
问题2:两种集合初始化写法的差异,以及日常开发优先选p的原因
两种写法如下:
p) List<String> l = new ArrayList<String>();
q) ArrayList<String> l = new ArrayList<String>();
核心差异
p是面向接口编程的写法,变量l的类型是List接口;q是面向实现编程的写法,变量l的类型是ArrayList实现类。
优先选择p的原因
- 降低耦合:后续如果需要替换列表实现,比如要换成支持高频插入的LinkedList、或者不可变列表,只需要修改右侧new后的实现类即可,左侧变量声明、所有调用该变量的上层代码完全不需要改动,符合开闭原则。如果用q的写法,替换实现时需要同时修改变量类型,所有用到ArrayList特有方法的代码都要调整,维护成本极高。
- 提升灵活性:方法入参、返回值如果定义为List类型,可以兼容所有List接口的实现类,适用范围更广。比如定义一个遍历方法入参为List,调用方不管传ArrayList、LinkedList还是第三方工具包的List实现都可以正常处理,如果入参定义为ArrayList就只能接收这一种实现。
- 规范编码:用接口类型声明变量,只会暴露List接口定义的通用方法,避免开发者不小心用到ArrayList特有的非通用方法,导致代码和特定实现绑定,后期难以迁移。
内容的提问来源于stack exchange,提问作者Ankur
相关产品推荐
相关产品推荐

