Comparator编译类型推断失败原因

Comparator类型推断失败原因

话不多说直接上(出问题的)代码

public static void main(String[] args) {
    List<String> list = Arrays.asList("nihao","hello","world","welcome");
    // 编译器无法进行类型推断
    Collections.sort(list, Comparator.comparingInt(item -> item.length()).reversed());
  	// 必须显示的指定类型
    Collections.sort(list, Comparator.comparingInt( (String item) -> item.length()).reversed());
    System.out.println(list);

}

编译器成功推断类型的方式

Collections.sort(list,Comparator.comparingInt(item -> item.length()));

编译器无法类型推断的方式

Collections.sort(list, Comparator.comparingInt(item -> item.length()).reversed());

以上的两种方式只是多了一个reversed()方法的原因就导致了类型推断失败

// 这个是jdk Collections.sort()方法
@SuppressWarnings({"unchecked", "rawtypes"})
public static <T> void sort(List<T> list, Comparator<? super T> c) {
  list.sort(c);
}

从以上的源码上看在传入集合后就确定了Comparator<? super T>比较器类型,因为以上的例子是String类型的集合,所以比较器Comarator类型可能是String或者是Object

// 这个是jdk reversed源码。去反
default Comparator<T> reversed() {
  return Collections.reverseOrder(this);
}

从以上的源码来看,返回一个Comparator<T>类型的比较器,因为这地方的调用返回的是固定T类型的比较器,所以编译器在没有指定类型的比较器以Object(通用的类型)从而返回一个Object比较器,因为是Object的比较器

### 类型擦除的概念 类型擦除是指编译器在编译期间移除泛型类型信息的过程,使得运行时无法获取具体的类型参数。这一机制主要用于向后兼容旧版本的Java虚拟机以及简化字节码中的类型管理[^1]。 对于编程语言而言,在引入泛型支持之前就已经存在大量代码库的情况下,采用类型擦除能够确保新老代码之间的互操作性。具体来说: - **向后兼容**:允许不带泛型的老版程序继续正常工作而不必修改。 - **性能优化**:减少了由于额外存储泛型信息带来的开销,尤其是在内存敏感的应用环境中尤为重要。 然而值得注意的是,虽然类型擦除有助于保持与早期版本的一致性和效率考虑,但它也带来了一些局限性,例如不允许在同一类中定义多个具有相同签名但不同类型参数的方法重载形式。 ### 应用场景 类型擦除广泛应用于各种需要动态处理数据结构而又希望保留一定层次抽象能力的情境之中,特别是在框架开发领域更为常见。以下是几个典型的应用实例: #### Java集合框架 ```java List<String> stringList = new ArrayList<>(); // 编译期检查, 运行时stringList实际上是一个Object[]数组 ``` 这里`ArrayList<T>`内部实现上并不真正保存T类型的元素列表;相反它只维护了一个对象数组(`Object[]`)用于容纳所有可能被加入到该容器内的项目。因此即使声明为特定类型的列表,在执行层面它们都被视为最通用的基础类别——即Object。 #### 泛型接口和服务提供者模式 当构建服务注册表或者插件系统时,经常利用类型擦除特性来创建高度灵活的服务查找机制。这允许客户端以统一的方式访问不同种类的具体实现而无需关心其确切的身份标识。 ```java public interface Service { void execute(); } @ServiceProvider(Service.class) public class ConcreteService implements Service { @Override public void execute() {} } ``` 尽管上述例子展示了如何通过注解处理器自动生成必要的桥接逻辑,但在底层依然依赖于类型擦除让这些组件能够在不知道彼此真实身份的前提下协同作业。 #### 函数式接口与Lambda表达式 随着lambda语法糖的支持,匿名内部类变得不再必要,取而代之的是更加简洁直观的写法。此时同样会涉及到类型推断和最终由JVM实施的类型擦除过程。 ```java Comparator<Integer> comparator = (a,b)->Integer.compare(a,b); ``` 这段代码片段里,比较器的实际形态是在编译阶段决定并转换成基础形式以便高效执行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值