foreach只能用于数组和实现了Iterable接口的类数组
//Iterable JDK源码
//能够经过成员内部类,方法内部类,甚至匿名内部类去实现Iterator
public interface Iterable<T> { Iterator<T> iterator(); }
包含3个方法: hasNext , next , remove。remove按需求实现,通常它不多用到,以致于Eclipse接口方法自动补全时,都忽略了remove放方法。ide
//Iterator接口的JDK源码,注释为整理建议使用Iterator的正确姿式
public interface Iterator<E> { boolean hasNext(); //每次next以前,先调用此方法探测是否迭代到终点 E next(); //返回当前迭代元素 ,同时,迭代游标后移 /*删除最近一次已近迭代出出去的那个元素。 只有当next执行完后,才能调用remove函数。 好比你要删除第一个元素,不能直接调用 remove() 而要先next一下( ); 在没有先调用next 就调用remove方法是会抛出异常的。 这个和MySQL中的ResultSet很相似 */ void remove()
{ throw new UnsupportedOperationException("remove"); } }
须要理解的地方函数
一、hasNext , next , remove 的调用顺序this
二、迭代出来的是原集合元素拷贝!spa
下面是手动迭代的例子,foreach的原理和它同样。3d
public static void main(String[] args) { List<Integer> li = new ArrayList<>(); li.add(1); li.add(2); li.add(3);
//不使用foreach 而手动迭代 Iterator<Integer> iter = li.iterator(); //获取ArrayList 的迭代器 while(iter.hasNext()) //①先探测可否继续迭代 { System.out.println(iter.next()); //②后取出本次迭代出的元素 //invoke remove() //③最后若是须要,调用remove } }
AbstractList中实现的迭代器类,能够借鉴参考。指针
咱们实现本身的迭代器的状况不多,毕竟JDK集合足够强大。code
源码中有一些保护机制,为了便于理解我删改了。对象
private class Itr implements Iterator<E>
{ /*
AbstractList 中实现的迭代器,删除了一些细节。不影响理解
Itr为一个priavate成员内部类
*/ int cursor = 0; //立刻等待被迭代元素的index //最近一次,已经被迭代出的元素的index,若是这个元素迭代后,被删除了,则lastRet重置为-1 int lastRet = -1; public boolean hasNext() { return cursor != size(); //当前游标值 等于 集合的size() 说明已经不能再迭代了。 } public E next() { int i = cursor; E next = get(i); lastRet = i; //lastRet 保存的是最近一次已经被迭代出去的元素索引 cursor = i + 1; //cursor为立刻等待被迭代的元素的索引 return next; } public void remove() { if (lastRet < 0) //调用remove以前没有调用next throw new IllegalStateException(); //则抛异常。这就是为何在使用remove前,要next的缘由 OuterList.this.remove(lastRet); //从集合中删除这个元素 if (lastRet < cursor) //集合删除元素后,集合后面的元素的索引会都减少1,cursor也要同步后移 cursor--; lastRet = -1; //重置 } }
迭代出来的元素都是原来集合元素的拷贝blog
Java集合中保存的元素实质是对象的引用(能够理解为C中的指针),而非对象自己。
迭代出的元素也就都是 引用的拷贝,结果仍是引用。那么,若是集合中保存的元素是可变类型的,咱们就能够经过迭代出的元素修改原集合中的对象。
而对于不可变类型,如String 基本元素的包装类型Integer 都是则不会反应到原集合中。
为了便于理解,画张图:
验证代码:
public class Main { public static void main(String[] args) { List<Person> li = new ArrayList<>(); Person p = new Person("Tom"); li.add(p); for(Person ap: li) { ap.setName("Jerry"); } System.out.println(li.get(0).getName()); //Jerry not Tom } } class Person { public Person(String name) { this.name = (name==null?"":name); } private String name; public String getName() { return name; } public void setName(String name) { if(name == null) name = ""; this.name = name; } }
小试牛刀,让本身的类支持迭代。
public class Main { public static void main(String[] args) { MyString s = new MyString("1234567"); for(char c:s) { System.out.println(c); } } } class MyString implements Iterable<Character> { private int length = 0; private String ineers = null; public MyString(String s) { this.ineers = s; this.length = s.length(); } @Override public Iterator<Character> iterator() { class iter implements Iterator<Character> //方法内部类 { private int cur= 0; @Override public boolean hasNext() { return cur != length; } @Override public Character next() { Character c = ineers.charAt(cur); cur++; return c; } public void remove() { // do nothing } } return new iter(); //安装Iterable接口的约定,返回迭代器 } }