增强型for循环是jdk1.5的新特性,使用更加方便,书写简洁。
比如:
int[] as = {
1,2,3,5
};
for (int a : as) {
System.out.println("a = " + a);
}
在比如:
List<Integer> integerList = new ArrayList<>();
for (Integer integer : integerList) {
System.out.println("integer = " + integer);
}
用这种方式代码更加简洁,可读性强。
这么方便的东西我们怎么能放过呢?接下来就一起实现一个自己的增强型for循环吧
首先看看List的继承图:
最上层是一个Iterable接口。看看它的源码注释的描述:
Implementing this interface allows an object to be the target of the "for-each loop" statement. See For-each Loop
显然这就是可以使用for循环的原因了,先贴出Iterable源码,接下来我们编写一个类来实现这个接口。
public interface Iterable<T> {
/**
* Returns an iterator over elements of type {@code T}.
*
* @return an Iterator.
*/
Iterator<T> iterator();
/**
* Performs the given action for each element of the {@code Iterable}
* until all elements have been processed or the action throws an
* exception. Unless otherwise specified by the implementing class,
* actions are performed in the order of iteration (if an iteration order
* is specified). Exceptions thrown by the action are relayed to the
* caller.
*
* @implSpec
* <p>The default implementation behaves as if:
* <pre>{@code
* for (T t : this)
* action.accept(t);
* }</pre>
*
* @param action The action to be performed for each element
* @throws NullPointerException if the specified action is null
* @since 1.8
*/
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
/**
* Creates a {@link Spliterator} over the elements described by this
* {@code Iterable}.
*
* @implSpec
* The default implementation creates an
* <em><a href="Spliterator.html#binding">early-binding</a></em>
* spliterator from the iterable's {@code Iterator}. The spliterator
* inherits the <em>fail-fast</em> properties of the iterable's iterator.
*
* @implNote
* The default implementation should usually be overridden. The
* spliterator returned by the default implementation has poor splitting
* capabilities, is unsized, and does not report any spliterator
* characteristics. Implementing classes can nearly always provide a
* better implementation.
*
* @return a {@code Spliterator} over the elements described by this
* {@code Iterable}.
* @since 1.8
*/
default Spliterator<T> spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
}
看源码知道实现这个接口,要实现方法iterator,返回值是Iterator<T>,这又是一个接口,我们可以在定义的类的内部编写内部类实现Iterator<T>。
下面贴出实现代码:
import java.util.Iterator;
public class MyList implements Iterable<Integer> {
private Integer[] integers;
public MyList(Integer[] integers) {
this.integers = integers;
}
@Override
public Iterator<Integer> iterator() {
return new MyIterable();
}
class MyIterable implements Iterator<Integer> {
private int index;
@Override
public boolean hasNext() {
return index < integers.length;
}
@Override
public Integer next() {
return integers[index++];
}
}
}
编写以下代码进行测试:
MyList integers = new MyList(new Integer[]{1, 2, 3});
for (Integer integer : integers) {
System.out.println("integer = " + integer);
}
到此就实现了自己的可使用增强型for循环的类,为了能更深入的理解,不妨给自己提一个问题。为什么可以这样,我们最开始学习java语法规则就只学过三种循环for(;;)
,while()
,do{}while()
,这个新出来的循环是怎么实现的呢?jvm层面还是编译器层面?
接下来我们来看看上面写的代码反编译后的样子(idea反编译):
MyList integers = new MyList(new Integer[]{1, 2, 3});
Iterator var2 = integers.iterator();
while(var2.hasNext()) {
Integer integer = (Integer)var2.next();
System.out.println("integer = " + integer);
}
idea反编译代码
其实我们编写的代码是编译器帮我们转换成了传统的循环了,这就是为什么要实现Iterable和Iterator接口了。
但是问题又来了,数组为什么可以用增强型for循环呢?它并没有实现这些接口啊,而且也不可能有next,hasNext方法。它是怎么实现的呢?
编写以下例子:
public static void main(String[] args) {
int[] as = {
1,2,3,5
};
for (int a : as) {
System.out.println("a = " + a);
}
}
下面是它反编译后的代码:
public static void main(String[] args) {
int[] as = new int[]{1, 2, 3, 5};
int[] var2 = as;
int var3 = as.length;
for(int var4 = 0; var4 < var3; ++var4) {
int a = var2[var4];
System.out.println("a = " + a);
}
}
看到这里所有迷团都解开了,简单说,对于JVM来说,增强型for循环其实就是传统循环。只是对于程序员来说有了变化。
这属于"挂羊头买狗肉"吗,哈哈,不过这样的确方便了不少,如果让我们写上反编译后的代码,那是有多麻烦啊。
网友评论