为什么JDK源码中,无限循环大多使用for(;;)而不是while(true)?

本文探讨了Java中使用for(;;)与while(true)作为无限循环条件的语法差异及其历史渊源,并通过具体示例展示了这两种写法在实际编译过程中的等效性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

作者:RednaxelaFX
链接:https://www.zhihu.com/question/52311366/answer/130090347
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

首先是先问是不是再问为什么系列。在JDK8u的jdk项目下做个很粗略的搜索:
mymbp:/Users/me/workspace/jdk8u/jdk/src
$ egrep -nr "for \\(\\s?;\\s?;" . | wc -l
     369
mymbp:/Users/me/workspace/jdk8u/jdk/src
$ egrep -nr "while \\(true" . | wc -l
     323

并没有差多少。

其次,for (;;) 在Java中的来源。个人看法是喜欢用这种写法的人,追根溯源是受到C语言里的写法的影响。这些人不一定是自己以前写C习惯了这样写,而可能是间接受以前写C的老师、前辈的影响而习惯这样写的。

在C语言里,如果不include某些头文件或者自己声明的话,是没有内建的_Bool / bool类型,也没有TRUE / FALSE / true / false这些_Bool / bool类型值的字面量的。
所以,假定没有include那些头文件或者自己define出上述字面量,一个不把循环条件写在while (...)括号里的while语句,最常见的是这样:
  while (1) {
    /* ... */
  }

…但不是所有人都喜欢看到那个魔数“1”的。
而用for (;;)来表达不写循环条件(也就是循环体内不用break或goto就会是无限循环)则非常直观——这就是for语句本身的功能,而且不需要写任何魔数。所以这个写法就流传下来了。

顺带一提,在Java里我是倾向于写while (true)的,不过我也不介意别人在他们自己的项目里写for (;;)。

=====================================

至于Java里while (true)与for (;;)哪个“效率更高”。这种规范没有规定的问题,答案都是“看实现”,毕竟实现只要保证语义符合规范就行了,而效率并不在规范管得着的范畴内。
以Oracle/Sun JDK8u / OpenJDK8u的实现来看,首先看javac对下面俩语句的编译结果:
  public void foo() {
    int i = 0;
    while (true) { i++; }
  }

/*
  public void foo();
    Code:
      stack=1, locals=2, args_size=1
         0: iconst_0
         1: istore_1
         2: iinc          1, 1
         5: goto          2
*/

  public void bar() {
    int i = 0;
    for (;;) { i++; }
  }

/*
  public void bar();
    Code:
      stack=1, locals=2, args_size=1
         0: iconst_0
         1: istore_1
         2: iinc          1, 1
         5: goto          2
*/
连javac这种几乎什么优化都不做(只做了Java语言规范规定一定要做的常量折叠,和非常少量别的优化)的编译器,对上面俩版本的代码都生成了一样的字节码。后面到解释执行、JIT编译之类的就不用说了,输入都一样,输出也不会不同。
<think>嗯,用户问的是JDK中的AbstractList是否实现了contains方法,以及如果没有实现的话,原因是什么。首先,我需要回忆一下Java集合框架的结构。AbstractList是一个抽象类,位于java.util包中,它是ArrayList等列表实现的基类。根据用户提供的引用[1]和[2],ArrayList继承自AbstractList并实现了List接口。而用户提到的问题是关于AbstractList是否实现了contains方法。 根据Java的文档,List接口定义了contains方法,而AbstractList作为抽象类,通常会对一些通用方法提供默认实现,以减少子类的重复代码。比如,contains方法可能依赖于迭代器遍历元素,检查是否存在目标对象。这时候需要检查AbstractList的源码,看看是否真的实现了contains。 查阅JDK8的源码,AbstractList并没有直接覆盖contains方法,而是继承自AbstractCollection。因为AbstractList继承自AbstractCollection,而AbstractCollection已经实现了contains方法。所以实际上,AbstractList并没有自己实现contains,而是使用父类AbstractCollection的实现。这个方法的实现逻辑通常是遍历集合中的元素,使用equals方法进行比较,如果找到匹配项则返回true,否则false。 用户提供的引用[5]中提到了ArrayList的构造方法,但可能和这个问题关联不大。而引用[3]提到了DualPivotQuicksort.sort,这可能与排序有关,但不涉及contains方法。引用[4]指出ArrayList是动态数组,属于集合框架的一部分,这确认了AbstractList在层次结构中的位置。 所以,结论应该是AbstractList没有自己实现contains方法,因为它继承了AbstractCollection中的实现。这样设计的原因可能是为了避免代码重复,保持层次结构的简洁性。AbstractList可能更关注于列表特有的方法,如get、set、add等,而通用的方法如contains、isEmpty等则由AbstractCollection处理。 另外,需要确认AbstractCollection中的contains实现。根据源码,AbstractCollection的contains方法确实是通过迭代器遍历所有元素,逐一比较。因此,AbstractList的子类如果没有覆盖contains方法,就会沿用这个实现。如果子类有更高效的方式,比如ArrayList基于数组的随机访问,可能不会覆盖,但根据实际情况,ArrayList可能并没有覆盖contains,因为默认实现已经足够,或者因为需要保持一致性。 总结一下,AbstractList本身没有实现contains方法,而是继承自AbstractCollection,这样设计是为了代码复用,让子类根据需要决定是否覆盖。而AbstractList更专注于列表操作的核心方法,如索引访问和修改。</think>### JDK AbstractList 的 `contains` 方法实现分析 #### 1. **AbstractList 是否实现了 `contains` 方法?** **答案:未独立实现,而是继承自 `AbstractCollection`。** `AbstractList` 继承自 `AbstractCollection`,而 `contains` 方法在 `AbstractCollection` 中已提供默认实现。因此,`AbstractList` 不需要重复实现该方法。以下是关键源码片段(基于 JDK8): ```java // AbstractCollection 中的 contains 实现 public boolean contains(Object o) { Iterator<E> it = iterator(); if (o == null) { while (it.hasNext()) { if (it.next() == null) return true; } } else { while (it.hasNext()) { if (o.equals(it.next())) return true; } } return false; } ``` `AbstractList` 的迭代器 `iterator()` 基于索引访问(例如 `get(int index)`),因此 `contains` 方法通过遍历元素逐一比较实现[^1][^4]。 --- #### 2. **为什么 `AbstractList` 不单独实现 `contains`?** **核心原因:避免重复代码,保持继承层级简洁。** - **继承复用**:`AbstractCollection` 已为所有集合类提供了通用的 `contains` 方法实现,依赖迭代器遍历元素。由于 `AbstractList` 是 `AbstractCollection` 的子类,直接继承该方法更高效[^4]。 - **关注点分离**:`AbstractList` 的核心职责是提供列表(List)特性的抽象(如索引操作 `get(int index)`、`set(int index, E element)`),而通用集合操作(如 `contains`、`isEmpty`)由 `AbstractCollection` 统一处理[^2]。 - **灵活性**:若子类需要优化 `contains`(例如通过哈希表快速查找),可自行覆盖该方法。例如 `LinkedHashSet` 通过哈希优化,但 `ArrayList` 沿用默认实现[^5]。 --- #### 3. **源码验证** 在 `AbstractList` 和 `ArrayList` 中均未找到对 `contains` 方法的覆盖实现,验证了其继承自 `AbstractCollection` 的结论[^2]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值