蒋振飞的博客 - Java入门11:集合与泛型   
正在加载蒋振飞的博客...
V3.0
蒋振飞的博客

Java入门11:集合与泛型

发布时间: 2018年10月08日 发布人: 蒋振飞 热度: 424 ℃ 评论数: 0

一、集合体系结构

1.集合体系图

20181008.png

2.集合的体系结构

    ①由于不同的数据结构(数据的组织,存储方式),所以Java为我们提供了不同的集合。
    ②但是不同的集合他们的功能都是相似,不断的向上提取,将共性抽取出来,这就是集合体系结构形成的原因。

3.Collection中的常用功能

    ①boolean add(Object e):向集合中添加元素。
    ②void clear():清空集合中所有元素。
    ③boolean contains(Object o):判断集合中是否包含某个元素。
    ④boolean isEmpty():判断集合中的元素是否为空。
    ⑤boolean remove(Object o):根据元素的内容来删除某个元素。
    ⑥int size():获取集合的长度。
    ⑦Object[] toArray():能够将集合转换成数组并把集合中的元素存储到数组中。

4.使用Collection案例代码

package day10;
import java.util.ArrayList;
import java.util.Collection;
 

public class CollectionDemo2 {
    public static void main(String[] args) {       
        // 创建集合对象
        // Collection c = new Collection();// Collection是接口,不能实例化
        Collection c = new ArrayList();// 多态,父类引用指向子类对象  
       
        // boolean add(E e)  
        System.out.println(c.add("hello"));// 永远可以添加成功,因为ArrayList他允许重复
        System.out.println(c.add("world"));
       
        // void clear():清空集合
        // c.clear();
       
        // boolean contains(Object o)  :判断集合中是否包含指定元素
        // System.out.println(c.contains("java"));
       
        // boolean isEmpty() :是否为空
        // System.out.println(c.isEmpty());
       
       
        // boolean remove(Object o) :删除元素
        // System.out.println(c.remove("java"));
       
        // int size() :返回集合中的元素个数
        // System.out.println(c.size());
       
        // Object[] toArray()  :将集合转换成一个Object类型的数组
        Object[] objs = c.toArray();
        for (int i = 0; i < objs.length; i++) {
            System.out.println(objs[i]);
        }
        System.out.println(c);
    }
}

二、迭代器

1.迭代器

    Collection集合元素的通用获取方式:在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续在判断,如果还有就再取出出来。一直把集合中的所有元素全部取出。这种取出方式专业术语称为迭代。

2.Iterator接口的常用方法如下

    ①hasNext()方法:判断集合中是否有元素可以迭代。
    ②next()方法:用来返回迭代的下一个元素,并把指针向后移动一位。

3.集合的遍历方式

    ①toArray(),可以把集合转换成数组,然后遍历数组即可。
    ②iterator(),可以返回一个迭代器对象,我们可以通过迭代器对象来迭代集合。

4.使用Iterator接口代码

package day10;
 
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
 
/*
 *  注意:Exception in thread "main" java.util.NoSuchElementException
 *      使用next方法获取下一个元素,如果没有元素可以获取,则出现NoSuchElementException
 */
 
public class IteratorDemo {
    public static void main(String[] args) {
        // method();
        // 创建集合对象
        Collection c = new ArrayList();
        //添加元素
        c.add("hello");
        c.add("world");
        c.add("java");
       
        // 获取迭代器对象
        Iterator it = c.iterator();
       
        // Object next()  :返回下一个元素
        // boolean hasNext()  :判断是否有元素可以获取
       
        /*if(it.hasNext())
            System.out.println(it.next());
        if(it.hasNext())
            System.out.println(it.next());
        if(it.hasNext())
            System.out.println(it.next());
        if(it.hasNext())
            System.out.println(it.next());*/
       
        while(it.hasNext()) {
            System.out.println(it.next());
        }
    }
 
    private static void method() {
        // 创建集合对象
        Collection c = new ArrayList();
        // 添加元素
        c.add("hello");
        c.add("world");
        c.add("java");
        // 获取数组
        Object[] objs = c.toArray();
        // 遍历数组
        for (int i = 0; i < objs.length; i++) {
            System.out.println(objs[i]);
        }
    } 
}

5.并发修改异常

    迭代器是依赖于集合的,相当于集合的一个副本,当迭代器在操作的时候,如果发现和集合不一样,则抛出异常。

package day10;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

/*
 * 需求:判断集合中是否包含元素java,如果有则添加元素android
 * Exception in thread "main" java.util.ConcurrentModificationException:并发修改异常
 * 
 * 解决方案:
 *      别使用迭代器
 *      在使用迭代器进行遍历的时候使用迭代器来进行修改
 */
 
public class IteratorDemo3 {
    public static void main(String[] args) {
        // method();
       
        // 创建集合对象
        // Collection c = new ArrayList();
        List c = new ArrayList();
        // 添加元素
        c.add("hello");
        c.add("world");
        c.add("java");
       
        // 我们可以通过遍历来获取集合中的每一个元素,然后进行比较即可
        /*Iterator it = c.iterator();
        while(it.hasNext()) {
            String s = (String)it.next();
            if(s.equals("java")) {
                c.add("android");
            }
        }*/
       
         // 使用ListIterator类就可以使用修改
        ListIterator lit = c.listIterator();
        while(lit.hasNext()) {
            String s = (String)lit.next();
            if(s.equals("java")) {
                lit.add("android");
            }
        }
       
        System.out.println(c);
    }
 
    private static void method() {
        // 创建集合对象
        Collection c = new ArrayList();
        //添加元素
        c.add("hello");
        c.add("world");
        c.add("java");
        // 判断集合中是否包含元素java
        if(c.contains("java")) {
            c.add("android");
        }
        System.out.println(c);
    }
}

6.并发修改异常解决方案

    ①不使用迭代器遍历集合,就可以在遍历的时候使用集合的方法进行增加或删除。
    ②依然使用迭代器遍历,那么就需要使用Iterator的子接口ListIterator来实现向集合中添加。

三、泛型

1.泛型的引入 

    集合中是可以存放任意对象的,只要把对象存储集合后,那么这时他们都会被提升成Object类型。当取出每一个对象,并且进行相应的操作,这时必须采用类型转换。

package day10;
 
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
 
           
public class GenericDemo {
    public static void main(String[] args) {
        // 创建集合对象
        Collection  c = new ArrayList();
        // 创建元素对象
        Student s = new Student("zhangsan",18);
        Student s2 = new Student("lisi",19);
        // 添加元素对象
        c.add(s);
        c.add(s2);
        // 遍历集合对象
       
        Iterator  it = c.iterator();
        while(it.hasNext()) {
             String str = (String)it.next();
             System.out.println(str);

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

    以上代码会发生强制转换异常,原因就是String str = (String)it.next() ,存入集合的是Student,而强转为String,String与Student之间没有任何子父关系不能强转,未使用泛型前有可能发声强制转换异常的问题。

2.什么是泛型

    ①使用集合存储自定义对象并遍历。
    ②由于集合可以存储任意类型的对象,当我们存储了不同类型的对象,就有可能在转换的时候出现类型转换异常。
    ③所以java为了解决这个问题,给我们提供了一种机制,叫做泛型。

3.泛型好处

    ①避免了类型转换的问题。
    ②可以减少黄色警告线。
    ③可以简化我们代码的书写。

4.泛型的使用

    ①当类上定义<>的时候就可以使用泛型,例如ArrayList类的定义。
    ②class  ArrayList<E>,那么我们在创建ArrayList对象的时候就可以指定<>中E的类型。
    ③ArrayList<String> al=new ArrayList<String>(),那么String就把E替换掉了。

5.使用泛型代码

package day10;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
 

public class GenericDemo {
    public static void main(String[] args) {
        // 创建集合对象
        Collection<Student> c = new ArrayList<Student>();
        // 创建元素对象
        Student s = new Student("zhangsan",18);
        Student s2 = new Student("lisi",19);
        // 添加元素对象
        c.add(s);
        c.add(s2);
        // 遍历集合对象
       
        Iterator<Student> it = c.iterator();
        while(it.hasNext()) {
            //String str = (String)it.next();
            //System.out.println(str);
           
            Student stu = it.next();
            System.out.println(stu.name);
        }
    }
}
 
class Student {
    String name;
    int age;
   
    public Student(String name,int age) {
        this.name = name;
        this.age = age;
    }
}

四、List子体系

1.List子体系特点

    ①有序的(存储和读取的顺序是一致的) 。
    ②有整数索引。 
    ③允许重复的。

2.List的特有功能

    ①void add(int index, E element) :将元素添加到index索引位置上。
    ②E get(int index) :根据index索引获取元素。
    ③E remove(int index) :根据index索引删除元素。
    ④E set(int index, E element):将index索引位置的的元素设置为element。

3.使用List案例

package day10;
import java.util.ArrayList;
import java.util.List;


public class ListDemo {
    public static void main(String[] args) {
        // 创建的列表对象
        List list = new ArrayList();
       
        // void add(int index, E element)  : 在指定索引位置添加指定元素
        list.add(0, "hello");
        list.add(0, "world");
        list.add(1, "java");
       
        // E get(int index)  :根据索引返回元素
        /*System.out.println(list.get(0));
        System.out.println(list.get(1));
        System.out.println(list.get(2));*/
        // System.out.println(list.get(3));
       
        /*for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }*/
       
        // E remove(int index)  : 删除指定元素并返回
       
        // System.out.println(list.remove(5));
       
        // E set(int index, E element) : 将指定索引位置的元素替换为指定元素,并将原先的元素返回
        System.out.println(list.set(0, "android"));
       
        System.out.println(list);
    }
}

4.LinkedList特有功能

    LinkedList底层使用的是链表结构,因此增删快,查询相对ArrayList较慢。
    ①void addFirst(E e) :向链表的头部添加元素。
    ②void addLast(E e):向链表的尾部添加元素。
    ③E getFirst():获取链头的元素,不删除元素。
    ④E getLast():获取链尾的元素,不删除元素。
    ⑤E removeFirst():返回链头的元素并删除链头的元素。
    ⑥E removeLast():返回链尾的元素并删除链尾的元素。

5.List的常用子类

    ①ArrayList:底层是数组结构,查询快,增删慢。
    ②LinkedList:底层结构是链表,查询慢,增删快。

6.如何选择使用不同的集合

    ①如果查询多,增删少,则使用ArrayList。
    ②如果查询少,增删多,则使用LinkedList。
    ③如果不知道使用什么,则使用ArrayList。

7.使用LinkedList案例

package day09;
import java.util.LinkedList;
 

public class LinkedListDemo {
    public static void main(String[] args) {
        LinkedList list = new LinkedList();
        list.add("hello");
        list.add("world");
       
        // void addFirst(E e)  :将元素添加到索引为0的位置
        // void addLast(E e) :将元素添加到索引为size()-1的位置
        list.addFirst("java");
        list.addLast("android");
           
        // E getFirst()  :获取索引为0的元素
        // E getLast()  :获取索引为size()-1的元素
        // System.out.println(list.getFirst());
        // System.out.println(list.getLast());
           
        // E removeFirst() :删除索引为0的元素并返回
        // E removeLast() :删除索引为size()-1的元素并返回
        System.out.println(list.removeFirst());
        System.out.println(list.removeLast());
           
        System.out.println(list);
    }
}

四、HashSet集合

1.Set接口的特点   

    ①存入集合的顺序和取出集合的顺序不一致
    ②没有索引
    ③存入集合的元素没有重复

2.HashSet的使用

    使用增强for进行遍历

public class HashSetDemo {
    public static void main(String[] args) {
        // 创建集合对象
        HashSet<Student> hs = new HashSet<Student>();
    
        // 创建元素对象
        Student s = new Student("zhangsan",18);
        Student s2 = new Student("lisi",19);
        Student s3 = new Student("lisi",19);
    
        // 添加元素对象
        hs.add(s);
        hs.add(s2);
        hs.add(s3);
    
        // 遍历集合对象
        for (Student student : hs) {
            System.out.println(student);
        }
    }
}

3.HashSet唯一性原理

    规则:新添加到HashSet集合的元素都会与集合中已有的元素一一比较。
    ①首先比较哈希值(每个元素都会调用hashCode()产生一个哈希值)。
    ②如果新添加的元素与集合中已有的元素的哈希值都不同,新添加的元素存入集合。
    ③如果新添加的元素与集合中已有的某个元素哈希值相同,此时还需要调用equals(Object obj)比较。
    ④如果equals(Object obj)方法返回true,说明新添加的元素与集合中已有的某个元素的属性值相同,那么新添加的元素不存入集。
    ⑤如果equals(Object obj)方法返回false, 说明新添加的元素与集合中已有的元素的属性值都不同,那么新添加的元素存入集合。

4.自定义对象去重(如Student)

    以上方法并不能使自定义对象达到去重的效果,因为它们的hash值不同,则会直接添加,需要重写equals方法和hasCode方法。

package day10;
 
import java.util.HashSet;
 
 
public class HashSetDemo2 {
    public static void main(String[] args) {
    
        // 创建集合对象
        HashSet<Student> hs = new HashSet<Student>();
        
        // 创建元素对象
        Student s = new Student("zhangsan",18);
        Student s2 = new Student("lisi",19);
        Student s3 = new Student("lisi",19);
        
        // 添加元素对象
        hs.add(s);
        hs.add(s2);
        hs.add(s3);
        
        // 遍历集合对象
        for (Student student : hs) {
            System.out.println(student);
        }
    }     
}
 
class Student {
    String name;
    int age;
   
    public Student(String name,int age) {
        this.name = name;
        this.age = age;
    }
 
    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + "]";
    }
 
    @Override
    public boolean equals(Object obj) {
    
        // System.out.println("-------------------");
        Student s = (Student)obj;// 向下转型,可以获取子类特有成员
       
        // 比较年龄是否相等,如果不等则返回false
        if(this.age != s.age) {
            return false;
        }
       
        // 比较姓名是否相等,如果不等则返回false
        if(!this.name.equals(s.name)) {
            return false;
        }
       
        // 默认返回true,说明两个学生是相等的
        return true;
    }
   
    @Override
    public int hashCode() {
        return 1;
    }
}

5.优化hashCode方法

    ①如果让hashCode()方法返回一个固定值,那么每个新添加的元素都要调用equals(Object obj)方法比较,那么效率较低。
    ②只需要让不同属性的值的元素产生不同的哈希值,那么就可以不再调用equals方法比较提高效率。

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + age;
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    return result;
}

6.Collections中的方法

    ①static void swap(List list, int i, int j) :将指定列表中的两个索引进行位置互换。
    ②static void  sort(List<T> list) :按照列表中元素的自然顺序进行排序。
    ③static void shuffle(List list):傻否,随机置换。
    ④static void reverse(List list) :反转。
    ⑤static void fill(List list, Object obj) :使用指定的对象填充指定列表的所有元素。
    ⑥static void copy(List dest, List src) :是把源列表中的数据覆盖到目标列表。
    ⑦static int  binarySearch(List list, Object key) :使用二分查找法查找指定元素在指定列表的索引位置。

7.Collection和Collections的区别

    ①Collection是集合体系的最顶层,包含了集合体系的共性
    ②Collections是一个工具类,方法都是用于操作Collection 

package day10;
 
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
 

public class CollectionsDemo {
    public static void main(String[] args) {
        // static void swap(List list, int i, int j) :将指定列表中的两个索引进行位置互换
        List<Integer> list = new ArrayList<Integer>();
        list.add(1);
        list.add(4);
        Collections.swap(list, 0, 1);
       
        System.out.println(list);
   
    }
 
    private static void method6() {
        // static void  sort(List<T> list) :按照列表中元素的自然顺序进行排序
        List<Integer> list = new ArrayList<Integer>();
        list.add(1);
        list.add(4);
        list.add(3);
        list.add(2);
       
        Collections.sort(list);
        System.out.println(list);
    }
 
    private static void method5() {
        // static void shuffle(List list):傻否,随机置换  
        List<Integer> list = new ArrayList<Integer>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        Collections.shuffle(list);
        System.out.println(list);
    }
 
    private static void method4() {
        // static void reverse(List list)  :反转
        List<Integer> list = new ArrayList<Integer>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
       
        Collections.reverse(list);
        System.out.println(list);
    }
 
    private static void method3() {
        // static void fill(List list, Object obj) :使用指定的对象填充指定列表的所有元素
        List<String> list = new ArrayList<String>();
        list.add("hello");
        list.add("world");
        list.add("java");
        System.out.println(list);
       
        Collections.fill(list, "android");
       
        System.out.println(list);
    }
 
    private static void method2() {
        // static void copy(List dest, List src) :是把源列表中的数据覆盖到目标列表
        // 注意:目标列表的长度至少等于源列表的长度
        // 创建源列表
        List<String> src = new ArrayList<String>();
        src.add("hello");
        src.add("world");
        src.add("java");
       
        // 创建目标列表
        List<String> dest = new ArrayList<String>();
        dest.add("java");
        dest.add("java");
        dest.add("java");
        dest.add("java");
        Collections.copy(dest, src);
        System.out.println(dest);
    }
 
    private static void method() {
        // static int  binarySearch(List list, Object key) 使用二分查找法查找指定元素在指定列表的索引位置 
        List<Integer> list = new ArrayList<Integer>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
       
        int index = Collections.binarySearch(list, 4);
        System.out.println(index);
    }
}

五、HashMap集合

1.Map接口概述

    ①Collection中的集合,元素是孤立存在的(理解为单身),向集合中存储元素采用一个个元素的方式存储。
    ②Map中的集合,元素是成对存在的(理解为夫妻)。每个元素由键与值两部分组成,通过键可以找对所对应的值。
    ③需要注意的是,Map中的集合不能包含重复的键,值可以重复;每个键只能对应一个值。

2.Map常用功能

    1) 映射功能

        ①V put(K key, V value) :以键=值的方式存入Map集合。

    2) 获取功能

        ①V get(Object key):根据键获取值。
        ②int size():返回Map中键值对的个数。

    3) 判断功能

        ①boolean containsKey(Object key):判断Map集合中是否包含键为key的键值对。
        ②boolean containsValue(Object value):判断Map集合中是否包含值为value键值对。
        ③boolean isEmpty():判断Map集合中是否没有任何键值对。

    4) 删除功能

        ①void clear():清空Map集合中所有的键值对。
        ②V remove(Object key):根据键值删除Map中键值对。

    5) 遍历功能

        ①Set<Map.Entry<K,V>> entrySet():将每个键值对封装到一个个Entry对象中,再把所有Entry的对象封装到Set集合中返回。
        ②Set<K> keySet() :将Map中所有的键装到Set集合中返回。
        ③Collection<V> values():返回集合中所有的value的值的集合。

3.Map的使用

package day10;
 
import java.util.HashMap;
import java.util.Map;
 

public class MapDemo2 {
    public static void main(String[] args) {
        // 创建Map对象
        Map<String,String> map = new HashMap<String,String>();
       
        // V put(K key, V value) :就是将key映射到value,如果key存在,则覆盖value,并将原来的value返回
        System.out.println(map.put("ITCAST001", "张三"));
        System.out.println(map.put("ITCAST002", "李四"));
        System.out.println(map.put("ITCAST001", "王五"));
       
        // void clear() : 清空所有的对应关系  
        // map.clear();
       
        // V remove(Object key) :根据指定的key删除对应关系,并返回key所对应的值,如果没有删除成功则返回null
        // System.out.println(map.remove("ITCAST005"));
       
        // boolean containsKey(Object key) : 判断指定key是否存在
        // System.out.println(map.containsKey("ITCAST003"));
       
        // boolean containsValue(Object value):判断指定的value是否存在
        // System.out.println(map.containsValue("王五"));
       
        // boolean isEmpty() : 判断是否有对应关系
        // System.out.println(map.isEmpty());
       
        // int size() : 返回对应关系的个数
        // System.out.println(map.size());
       
        // V get(Object key) : 根据指定的key返回对应的value
        System.out.println(map.get("ITCAST002"));
       
        System.out.println(map);
    }
}

4.Map的两种遍历方式

    1) 利用keySet()方法遍历

 package day10;
 
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
 

public class MapDemo4 {
    public static void main(String[] args) {
        // 创建Map对象
        Map<String,String> map = new HashMap<String,String>();
        // 添加映射关系
        map.put("谢婷疯", "张箔纸");
        map.put("陈关西", "钟欣桶");
        map.put("李亚碰", "王飞");
        // 遍历Map对象
       
        // 首先召集所有的丈夫
        Set<String> keys = map.keySet();
        // 遍历所有的丈夫
        for (String key : keys) {
            // 让每个丈夫去找他自己的媳妇就可以了
            String value = map.get(key);
            System.out.println("丈夫:" + key + "---" + "媳妇:" + value);
        }
       
    }
}

    2) 利用entrySet()方法遍历

public class MapDemo5 {
    public static void main(String[] args) {
    
        // 创建Map对象
        Map<String,String> map = new HashMap<String,String>();
        //添加映射关系
        map.put("尹志平", "小龙女");
        map.put("令狐冲", "东方菇凉");
        map.put("玄慈", "叶二娘");
        // 获取所有的结婚证对象
        Set<Map.Entry<String,String>> entrys = map.entrySet();
        // 遍历包含了结婚证对象的集合
        for (Map.Entry<String, String> entry : entrys) {
            // 获取每个单独的结婚证对象
            // 通过结婚证对象获取丈夫和媳妇
            String key = entry.getKey();
            String value = entry.getValue();
            System.out.println("丈夫:" + key + "---" + "媳妇:" + value);
        }
       
    }
}

打赏 蒋振飞

取消

感谢您的支持,我会继续努力的!

扫码支持
一分也是爱     一块不嫌多

点击 支付宝 或 微信 打赏蒋振飞

打开支付宝扫一扫,即可进行扫码打赏哦

评论列表