java笔记十三——集合的遍历及泛型

一、Collections类

​ Collections类是单列集合Collection的工具类,Collections工具类为集合提供了许多静态方法,常用方法如下

二、迭代器Iterator

  • 在对集合进行迭代的过程中,不要进行增删操作!!!
  • 对ArrayList集合中的元素进行修改或删除时,先遍历找到对应元素的索引,遍历结束以后根据索引进行修改或删除

迭代器Iterator是用来遍历Collection集合的,Map集合不能直接使用Iterator迭代器遍历集合元素。

自定义对象并迭代
测试类:

public static void main(String[] args) {
        Person p1 = new Person("张三", 20);
        Person p2 = new Person("李四", 21);
        Person p3 = new Person("王五", 22);
        Person p4 = new Person("赵六", 23);

        ArrayList<Person> list = new ArrayList<>();
        list.add(p1);
        list.add(p2);
        list.add(p3);
        list.add(p4);

        Iterator<Person> iterator = list.iterator();
        while (iterator.hasNext()) {
            Person per = iterator.next();
            System.out.println(per);
        }
    }

Person.java

public class Person {
    private String name;
    private int age;

    public Person() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

三、Map集合的遍历

3.1 keySet()遍历

实现思想:

1、Map接口定义了方法 keySet() ,可以利用这个方法获取Map集合中所有键的Set集合。

2、使用Iterator迭代器遍历Set集合。

3、利用步骤2中获取的key,调用Map集合的get()方法,获取键对应的值。

 /**
     * - Map接口定义了方法  keySet() 所有的键,存储到Set集合
     * - 遍历Set集合
     * - 取出Set集合元素 **Set集合的元素是Map集合的键**
     * - Map集合方法get()传递键获取值
     */
public static void mapKeySet(){
    Map<String,String> map = new HashMap<String, String>();
    map.put("a","java");
    map.put("b","c++");
    map.put("c","php");
    map.put("d","python");
    map.put("e","erlang");
    //Map接口定义了方法  keySet() 所有的键,存储到Set集合
    Set<String> set = map.keySet();
    //遍历Set集合
    Iterator<String> it = set.iterator();
    //取出Set集合元素 **Set集合的元素是Map集合的键**
    while (it.hasNext()){
        String key = it.next();
        //Map集合方法get()传递键获取值
        String value =  map.get(key);
        System.out.println(key+"==="+value);
    }
}

3.2 entrySet()遍历

实现思想:

1、调用Map接口的方法 Set< Map.Entry<Key,Value> > entrySet()

  • 方法返回Set集合,集合中存储的元素,比较特别
  • 存储的是Map集合中,键值对映射关系的对象 , 内部接口 Map.Entry

2、利用Iterator迭代器遍历Set集合

3、取出Set集合中的元素

  • 是Map.Entry接口对象
  • 接口的对象方法: getKey() ,getValue()
 public static void mapEntrySet(){
     Map<String,String> map = new HashMap<String, String>();
     map.put("a","java");
     map.put("b","c++");
     map.put("c","php");
     map.put("d","python");
     map.put("e","erlang");
     //Map接口的方法 Set< Map.Entry<Key,Value> > entrySet()
     Set<Map.Entry<String,String>>  set = map.entrySet();
     //- 遍历Set集合
     Iterator<Map.Entry<String,String>> it = set.iterator();
     while (it.hasNext()){
         //取出Set集合的元素
         Map.Entry<String,String> entry =  it.next();
         //- 接口的对象方法: getKey() ,getValue()
         String key = entry.getKey();
         String value = entry.getValue();
         System.out.println(key +"==="+ value);
     }
 }

四、增强for循环

JDK1.5出现的特性 : 循环的特性 (少些代码)

Collection是单列集合的顶级接口,但是到JDK1.5后,为Collection找了个爹

java.lang.Iterable接口 : 实现接口,就可以成为 "foreach"语句的目标

Collection,List,Set都实现了接口,包括数组。

map接口及其子类没有实现该接口。

4.1 for的格式

for(数据类型 变量名 : 集合或者数组){}
  • 遍历数组
 /**
     * for循环遍历数组
     * for(数据类型 变量名 : 集合或者数组){}
     */
    public static void forArray(){
        int[] arr = {1,3,5,7,9};
        for(int i : arr){
            System.out.println(i+1);
        }
        System.out.println("arr=="+arr[0]);
    }
  • 遍历集合
/** for循环遍历集合
     */
    public static void forList(){
        List<String> list = new ArrayList<>();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");

        for(String s : list){
            System.out.println(s);
        }
    }

五、泛型

5.1 泛型的概念

​ 泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。

​ 这样说可能也比较抽象,用一句话总结泛型的作用:强制集合存储固定的数据类型

5.2 泛型的格式

集合类<存储的数据类型>  变量名 = new 集合类<存储的数据类型>();
                                       类型可以不写:钻石操作符

加入泛型后,程序的安全性提高了

public static void main(String[] args) {
        /**
         *  JDK没有泛型技术,就是这样写
         *  集合可以存储任何数据类型
         *  添加元素的数据类型是Object
         */
        List<String> list = new ArrayList<String>();
        list.add("a");
        list.add(1); //编译错误,数据类型不匹配

        Iterator<String> it = list.iterator();
        while (it.hasNext()){
            String obj =it.next(); //类型转换不需要
            System.out.println(obj);
        }
    }

5.3 泛型的好处

  • 安全性提高了
  • 程序的代码量减少
  • 避免了类型的强制转换
  • 程序的问题,由运行时期,提前到编译时期

5.4 自定义泛型类

/**
 *  定义类,类名叫工厂
 *  自定义泛型类
 *  Factory<什么都可以写> 只是变量名而已
 */
public class Factory<QQ> {
    private QQ q;

    public void setQ(QQ q){
        this.q = q;
    }

    public QQ getQ(){
        return q;
    }
}
public static void main(String[] args) {
    //创建对象Factory类对象
    // Factory factory = new Factory();//没有泛型,QQ就是Object

    Factory<String> factory = new Factory<String>();
    factory.setQ("abc");
    String s = factory.getQ();
    System.out.println(s);

    Factory<Double> factory2 = new Factory<Double>();
    factory2.setQ(1.5);
    Double q = factory2.getQ();
    System.out.println(q);
}

5.5 自定义泛型方法

/**
 * 泛型的方法,方法参数上
 */
public class Factory<Q> {

    /*
     * 静态方法
     * Q是非静态的, Q的数据类型,是new的时候指定的
     *
     * 静态方法参数中的泛型,不能和类一样
     * 静态方法的泛型,需要在方法上单独定义
     * 写在返回值类型的前面
     */
    public static <T> void staticMethod(T q){
        System.out.println(q);
    }

    public void print(Q q){
        System.out.println(q);
    }
}

5.6 泛型接口

1、实现类实现接口,不指定泛型的具体的类型

2、实现类实现接口,指定泛型的具体类型

//泛型接口
public interface Inter <T> {
    public abstract void inter(T t);
}

/**
 * 实现接口,不理会泛型
 * 对象创建的时候,指定类型
 */
public class InterImpl<T> implements Inter<T>{
    public void inter(T t){
        System.out.println(t);
    }
}
/**
 * 实现接口,同时指定泛型
 */
public class InterImpl2 implements Inter<String> {

    public void inter(String s) {
        System.out.println("s=="+s);
    }
}
public class GenericTest {
    public static void main(String[] args) {
        Inter<String> in = new InterImpl<String>();
        in.inter("ok");

        Inter in2 = new InterImpl2();
        in2.inter("kkk");
    }
}

5.7 泛型通配符

//泛型的通配符
public class GenericTest {
    public static void main(String[] args) {
        List<String> stringList = new ArrayList<String>();
        stringList.add("abc");
        stringList.add("bbc");

        List<Integer> integerList =  new ArrayList<Integer>();
        integerList.add(1);
        integerList.add(2);

        each(stringList);
        each(integerList);
    }
    /**
     * 定义方法,可以同时迭代器 遍历这两个集合
     * 方法的参数,是要遍历的集合,不确定是哪个集合
     * 定义参数,写接口类型,不要写实现类
     */
    public static void each(List<?> list){
        Iterator<?> it = list.iterator();
        while (it.hasNext()){
            Object obj = it.next();
            System.out.println(obj);
        }
    }
}

5.8 泛型限定

泛型限定 : 限制的是数据类型

  • 传递E类型或者是E的子类,泛型上限限定 - 传递类型可以是Company或者是他的子类
  • 传递E类型或者是E的父类,泛型下限限定
public static void main(String[] args) {
    //创建集合,存储员工对象

    //开发部的
    List<Development> devList = new ArrayList<Development>();
    //存储开发部员工对象
    Development d1 = new Development();
    d1.setName("张三");
    d1.setId("开发部001");

    Development d2 = new Development();
    d2.setName("张三2");
    d2.setId("开发部002");
    devList.add(d1);
    devList.add(d2);

    //财务部集合
    List<Financial> finList = new ArrayList<Financial>();
    Financial f1 = new Financial();
    f1.setName("李四");
    f1.setId("财务部001");

    Financial f2 = new Financial();
    f2.setName("李四2");
    f2.setId("财务部002");
    finList.add(f1);
    finList.add(f2);
    System.out.println(devList);
    System.out.println(finList);

    each(devList);
    each(finList);

    //        List<Integer> integerList = new ArrayList<>();
    //        integerList.add(1);
    //        each(integerList);
}
/**
     * 要求 : 定义方法
     * 同时遍历2个集合
     * 遍历的同时取出集合元素,调用方法work()
     * ? 接收任何一个类型
     * 只能接收 Company和子类对象
     * 明确父类,不能明确子类
     */
public static void each(List<? extends Company> list){
    Iterator<? extends Company> it = list.iterator();
    while (it.hasNext()){
        //取出元素
        Company obj =it.next();
        obj.work();
    }
}

六、Properties集合

6.2 Properties集合的特点

  • 继承Hashtable,实现Map接口
  • 底层是哈希表结构
  • 线程是安全的,运行速度慢
  • 集合没有泛型的写法,键和值的数据类型锁定为String类型
  • 集合有自己的特有方法
  • 此集合可以和IO流对象结合使用,实现数据的持久化存储

6.3 Properties集合的常用方法

6.3.1 添加获取

  • public Object setProperty(String key,String value):向集合内添加数据
  • public String getProperty(String key):使用指定的键获取集合中的值
	private static void show01() {
        // setProperty() 通过该方法向Properties内添加一对字符串键值对
        Properties properties = new Properties();
        properties.setProperty("kelvin", "180");
        properties.setProperty("jack", "168");
        properties.setProperty("siri", "170");

        // stringPropertyNames() 通过该方法获取Properties集合内的所有键组成的set集合
        Set<String> strings = properties.stringPropertyNames();
        for (String key : strings) {
            String value = properties.getProperty(key);
            System.out.println(key + "--" + value);
        }
    }

6.3.2 store()方法持久化集合数据

  • public void store(OutputStream out,String comments):将此 Properties 表中的属性列表(键和元素对)写入输出流。
// store() 持久化数据
    private static void show02() throws IOException {
        /*
        持久化数据步骤:
         1 创建Properties对象,存储数据
         2 创建字节输出流/字符输出流对象,指定将数据持久化的位置(字节流不能持久化中文)
         3 调用Properties对象的store()方法,将集合中的临时数据持久化到指定位置
         4 释放资源
        */
        Properties properties = new Properties();
        properties.setProperty("kelvin", "180");
        properties.setProperty("jack", "168");
        properties.setProperty("siri", "170");

        FileWriter fw = new FileWriter("prop.txt");
        properties.store(fw, "store data");
        fw.close();
    }

6.3.3 load()方法加载文件数据到集合

  • public void load(InputStream inStream):从输入流中读取属性列表(键和元素对)。
/*
        加载数据步骤:
             1 创建Properties对象
             2 调用load方法加载指定文件
             3 遍历Properties集合
        注意事项:
            1 存储键值对的文件中,可以使用=,空格或其他符号进行连接
            2 存储键值对的文件中,可以使用#进行注释,注释内容不会加载
            3 读取内容默认是字符串格式
        */
    private static void show03() throws IOException {
        Properties properties = new Properties();
        properties.load(new FileReader("prop.txt"));
        Set<String> strings = properties.stringPropertyNames();
        for (String key : strings) {
            String value = properties.getProperty(key);
            System.out.println(key + "--" + value);
        }

    }
posted @ 2021-05-08 21:24  沙滩拾贝  阅读(214)  评论(0编辑  收藏  举报