java进阶 第十讲 集合与迭代器

java进阶 第十讲 集合与迭代器

1 集合

Collection 
	List Set
	ArrayList
	LinkedList
Set---> Map
	Set本质上是Map的Key部分。Value--存的是一个常量。

2 迭代器

什么是迭代器?
	Iterable:可迭代的,可遍历的,也就是说实现了Iterable接口的类所产生的对象是可以被迭代的,也就是说这个对象是可以被遍历的。
	循环遍历。
Iterable中的重要方法:
	Iterator<T> iterator()  
Iterable接口中有一个方法叫做iterator(),该方法返回值类型是Iterator<T>。
也就是说,iterator方法返回一个对象。返回的对象的类型是Iterator类型的
Iterator是一个接口,所以返回的必须是Iterator的实现类的对象。这就是多态。
父类型的引用指向子类型的对象。Iterator iter = iterator();
Iterator iter = new IteratorImpl();

研究Iterable接口,本质上就是要研究Iterator<E>接口:
	boolean hasNext():意味着元素还有没有下一个,如果有就返回true,没有就返回false
	E next()  :取出下一个元素
因为Iterator也是接口,我们要能够使用它,就必须要有实现类。只有在实现类中才有意义。
	Iterator真正被用到的地方是在哪里?也就是说Iterator接口是怎样被使用的?
	其实它真正被用到的地方是在Iterable接口中。只要实现了Iterable接口的类都要实现Iterator接口中的方法。
	Collection的实现类都实现了Iterable接口,因为Collection本身就是继承了Iterable接口。
	也就是说:集合的实现类所产生的对象都是可以被迭代的,但是Map不是。因为Map不是集合。集合才可以被迭代,Map不能被迭代。
	问,Map完全不能被迭代吗?可以迭代Key部分。Key部分就是Set集合。所以Key是可以被迭代的。

2.2 怎么实现迭代器

迭代器只能在集合中使用,集合是一种数据结构。常用的包括List和Set。
比如,对于一个List来讲,实现类有ArrayList、LinkedList等等。
ArrayList要实现迭代器的迭代功能该怎么做?
	 public Iterator<E> iterator() {
        return new Itr();
    }
    这个是Iterable接口中的方法,因为ArrayList实现了List接口,List接口继承自Collection
    Collection继承自Iterable
    所以:ArrayList一定要实现Iterable接口中所有的方法。
    Iterable接口中有Iterator接口,所以ArrayList还要实现Iterator接口。

在这里插入图片描述

//ArrayList中Iterator的具体实现:
private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = modCount;

        public boolean hasNext() {
            return cursor != size;
        }
		// 如果cursor == size,说明遍历到最后一个元素,没有下一个元素了
        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }

        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        @Override
        @SuppressWarnings("unchecked")
        public void forEachRemaining(Consumer<? super E> consumer) {
            Objects.requireNonNull(consumer);
            final int size = ArrayList.this.size;
            int i = cursor;
            if (i >= size) {
                return;
            }
            final Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length) {
                throw new ConcurrentModificationException();
            }
            while (i != size && modCount == expectedModCount) {
                consumer.accept((E) elementData[i++]);
            }
            // update once at end of iteration to reduce heap write traffic
            cursor = i;
            lastRet = i - 1;
            checkForComodification();
        }

        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }
解释说明:
Object[] elementData = ArrayList.this.elementData;
以前我们知道:类名.的方式是对于静态的属性和方法。ArrayList.this,这完全不符合类名.的方式。因为this不可能是静态的。这里的类名.的方式不是指调用方法或者是属性。而是强调。强调这个this.elementData数组是ArrayList类的成员属性。这种用法只在内部类中。防止与内部类中的属性重名,区分内部类和本类的属性或者是方法名。
如果在内部类中调用静态方法,就不会产生这个this关键字。有this就是用来区分的。
类名.this的用法表示强调,只在内部类中使用。
如果,我们自己定义了一个集合,那么我们就需要实现Collection接口。
如果实现上述接口,那么就一定要自己写Iterator的实现类,该实现类一般为内部类。
因为内部类可以作为成员属性。当然也可以定义为外部类,可以使用组合、聚合等方式使用。
那么,如果我们使用API中的集合呢?
	因为API提供给我们的集合都是写好了的,已经实现了Iterator接口的,那么我们只要拿到
	Iterator接口的实现类的对象,就可以访问实现类中所有的方法。
	使用的方式是多态,父类型的引用指向子类型的对象。然后通过父类型的引用调用子类型对象的方法。
	

public class Test {

    public static void main(String[] args) {

        ArrayList<Integer> arrayList = new ArrayList<>();

        arrayList.add(1);
        arrayList.add(2);
        arrayList.add(3);
        arrayList.add(4);

        for (int i = 0; i <arrayList.size(); i++ ) {
            System.out.println(arrayList.get(i));
        }

        Iterator iterator = arrayList.iterator();// return new Itr();
        //拿到arrayList中的迭代器,实际上是Itr的对象
        // Iterator iterator = new Itr();
        System.out.println(iterator.hasNext());


        // 遍历整个ArrayList
        while(iterator.hasNext()) {
            System.out.println(iterator.next());
        }
// foreach 增强for循环。
        for (Integer i : arrayList) {
            //遍历arrayList数组中的每一个Integer类型的元素
            System.out.println(i);
        }

        int[] ints = {1,2,3,4,5,6};
        for (int anInt : ints) {//在ints这个数组中要遍历每一个anInt元素
            System.out.println(anInt);
        }
    }
}

3 总结

以后,如果是调用API中的集合,使用迭代器的时候我们可以通过iterator()直接拿到一个迭代器,通过这个迭代器可以直接迭代集合中的元素。
当然也可以使用增强for循环,也就是foreach,迭代集合中的元素。

在应用中,往往需要我们自己去定义一个集合,定义一种集合类型的数据结构,这时候我们需要自己实现Iterator接口(或者实现Iterable接口)。我们可以使用内部类的方式或者是外部类的方式。
实现了之后才能使用迭代器。

foreach增强for循环,一定是在集合中使用的,如果是自定义的,一定要实现Iterable(Iterator)接口。

如果是使用API中的集合,用到迭代器的时候,三部曲:
第一步:new一个集合对象
第二步:调用该对象的iterator()方法,返回一个迭代器对象
第三步:通过这个迭代器对象来访问hasNext()和next()方法


如果是自定义的集合,要实现Itrable接口,重写iterator()方法,返回一个Iterator对象
那么要重新定义Iterator接口的实现类,重写Iterator接口中的方法,核心是重写hasNext()和next()方法
重写方式有三种,外部类、成员内部类和局部内部类
用得比较多的且容易理解的是成员内部类。
具体的方式如下:
package com.tj.generic;


import java.util.Iterator;
import java.util.NoSuchElementException;

/**
 * @program: Study
 * @description:
 * @author: tianjie
 * @create: 2021-02-06 10:54
 */
public class LinkList<T> implements Iterable {
    Node head;
    int size = 0;
    // 顺序添加,也就是在尾结点上添加元素
    void add(T elem) {
        if (head == null) {
            head = new Node(elem, null);
        }
        Node current = head;
        while (current.next != null) {
            current = current.next;
        }
        current.next = new Node(elem,null);
        size++;
    }

    public T get (T elem) {
        if (head == null) {
            throw new NullPointerException("链表不存在");
        }
        Node curr = head;
        while (curr.next != null) {
            if (curr.elment != elem) {
                curr = curr.next;
            }else if (curr.elment == elem){
                break;
            }
        }
        return (T)curr.elment;
    }


    @Override
    public Iterator iterator() {
        int cursor = 0;
        //这是局部内部类的写法
        return new Iterator() {
            @Override
            public boolean hasNext() {
                return cursor != size;
            }

            @Override
            public Object next() {
                int i = cursor;
                if (i >= size) {
                    throw  new NoSuchElementException();
                }
				;;
                return null;
            }
        };
    }
}

// 成员内部类的方式如下:
 @Override
    public Iterator iterator() {
        return new Itr();
    }


    private class Itr implements Iterator {
        @Override
        public boolean hasNext() {
            return false;// 业务逻辑自己写
        }

        @Override
        public Object next() {
            return null;// 业务逻辑自己写
        }
    }

4 Properties

这是一个很重要的类,Properties:属性
Properties是一个特殊的Map,它的key和value都是String类型的。
Properties类表示一组持久的属性。 
Properties可以保存到流中或从流中加载。 这句话很重要,这是我们以后常用到的
属性列表中的每个键及其对应的值都是一个字符串。 
这个类常用来读取配置文件。
有一些常用的东西比如:IP和端口,固定的,192.168.0.1:8080
conn(IP,port)
......................
张三=192.168.0.1:8080
李四=192.168.5.1:8080
王五=192.168.8.1:8080
......................
读取上述的文件来获得其中的key和value

网站注册登录:
填账号和密码
username=“zhangsan”
passwd="123456"
mysql=3306
..........

key=value
zhangsan=123
lisi=567
public class Test {

    public static void main(String[] args) {

        Properties properties = new Properties();
        try {
            properties.load(new FileInputStream("F:\\IdeaProjects\\Study\\src\\com\\tj\\propertiesTest\\pro"));
            String property = properties.getProperty("2019404518");
            System.out.println(property);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
 Properties();
        try {
            properties.load(new FileInputStream("F:\\IdeaProjects\\Study\\src\\com\\tj\\propertiesTest\\pro"));
            String property = properties.getProperty("2019404518");
            System.out.println(property);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值