java学习笔记(二十二)集合

来源:互联网 发布:淘宝客服网上人工服务 编辑:程序博客网 时间:2024/04/28 07:07

集合

面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,我们就需要对这多个对象进行存储。而目前为止我们学习过的可以存储多个元素的东西是数组,但是呢,数组长度固定,不能适应变化的需求,所以,Java就提供了集合类供我们使用。
集合和数组的区别:

数组:1.长度固定2.可以存储基本类型,也可以存储引用类型3.存储元素类型一致集合:1.长度可变2.只可以存储引用类型3.可以存储多种类型

集合体系图:
这里写图片描述
首先先介绍一下Collection这个接口
是集合的顶层结构,定义了集合的共性功能。
它有一些成员方法是所有集合所共有的:
成员方法:(看到E我们先把它理解为Object即可)

    A:添加功能        boolean add(Object obj):往集合中添加一个元素        boolean addAll(Collection c):往集合中添加多个元素    B:删除功能        void clear():清空所有元素        boolean remove(Object o):从集合中删除一个元素        boolean removeAll(Collection c):从集合中删除另一个集合的元素    C:判断功能        boolean contains(Object o):判断集合中是否包含指定的元素        boolean containsAll(Collection c):判断集合中是否包含另一个集合的元素        boolean isEmpty():判断集合是否为空。    D:交集功能        boolean retainAll(Collection c)    E:迭代器(集合特有的遍历方式)        Iterator iterator()    F:长度功能        int size():返回集合中元素的个数    G:集合转数组    Object[]toArray():把集合转成数组,然后遍历数组,其实就相当于遍历了集合。
public class CollectionDemo {    public static void main(String[] args) {//      A:添加功能//          boolean add(Object obj):往集合中添加一个元素//          boolean addAll(Collection c):往集合中添加多个元素        Collection<String> c1=new ArrayList<String>();//创建Collection集合        //向集合中添加元素        c1.add("人机交互");        c1.add("图像处理");        c1.add("微机原理");        //再创建一个集合对象        Collection<String> c2=new ArrayList<String>();        c2.add("c++");        c2.add("java");        //把集合c2的元素添加到c1中        c1.addAll(c2);        /*B:删除功能         *          void clear():清空所有元素         *          boolean remove(Object o):从集合中删除一个元素         *          boolean removeAll(Collection c):从集合中删除另一个集合的元素*/        c1.remove("c++");        //c1.removeAll(c2);        //c1.clear();        /*C:判断功能         *          boolean contains(Object o):判断集合中是否包含指定的元素         *          boolean containsAll(Collection c):判断集合中是否包含另一个集合的元素         *          boolean isEmpty():判断集合是否为空。*/        //boolean contains = c1.contains("c++");        boolean contains = c1.containsAll(c2);        System.out.println(contains);        /*D:交集功能         *          boolean retainAll(Collection c)*/        boolean retainAll = c1.retainAll(c2);//求出交集元素,并将没有交集的元素删除        System.out.println(retainAll);        //遍历集合c1        Object[] arr = c1.toArray();        for (int i = 0; i < arr.length; i++) {            System.out.println(arr[i]);        }        //遍历集合c2        Object[] arr1 = c2.toArray();        for (int i = 0; i < arr1.length; i++) {            System.out.println(arr1[i]);        }               }}

迭代器: Iterator iterator(),用来遍历集合中的元素

成员方法:        Object next():返回迭代的下一个元素,并移动指向的位置        boolean hasNext():判断是否有元素

迭代器是依赖于集合而存在的。所以,要想得到迭代器对象,必须先有集合对象。

    迭代步骤:        A:通过集合对象获取到迭代器对象        B:通过迭代器对象的hasNext()方法判断是否有元素        C:通过迭代器对象的next()方法获取元素

练习:创建狗对象(带参数),存储到集合,用迭代器进行遍历并打印对象的属性数据
分析:1。先写一个Dog类
2.然后在创建一个空的集合
3.创建Dog对象
4.向集合中添加Dog对象元素
5.使用while循环加迭代器进行遍历
Dog类:

public class Dog {    private String name;    private int age;    private String color;    public Dog(String name, int age, String color) {        super();        this.name = name;        this.age = age;        this.color = color;    }    public Dog() {        super();        // TODO Auto-generated constructor stub    }    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 String getColor() {        return color;    }    public void setColor(String color) {        this.color = color;    }}

然后写一个测试类:

public class CollectionDemo {    public static void main(String[] args) {        //创建狗对象        Dog d1 = new Dog("大黄",2,"黄色");        Dog d2 = new Dog("小黑",2,"黑色");        Dog d3 = new Dog("大花",2,"花色");        //创建集合对象        Collection c1=new ArrayList();        //集合中添加狗对象元素        c1.add(d1);        c1.add(d2);        c1.add(d3);        //创建迭代器对象        Iterator it = c1.iterator();        //遍历        while(it.hasNext()){            Dog d=(Dog) it.next();            System.out.println(d.getName()+" "+d.getAge()+" "+d.getAge());        }       }}

List接口:
(1)List集合的元素有序(存储和取出顺序一致),元素可重复

(2)List的特有功能:

    A:添加功能    void add(int index,Object obj):在指定的位置添加元素    B:删除功能    Object remove(int index):通过指定的索引删除元素,并把删除的元素返回    C:获取功能    get(int index) 返回列表中指定位置的元素。    D:替换功能    Object set(int index,Object obj)

下面写一些简单的代码对这些功能进行测试:

public class ListDemo {    public static void main(String[] args) {        //创建List集合对象        List<String> list = new ArrayList<String>();        //给集合添加元素        list.add("李白");        list.add("杜甫");        list.add("王维");        //遍历集合        print(list);        System.out.println("----------------------------");        //void add(int index,Object obj):在指定的位置添加元素        list.add(1, "白居易");        print(list);        System.out.println("----------------------------");        //Object remove(int index):通过指定的索引删除元素,并把删除的元素返回        String remove = list.remove(1);        print(list);        System.out.println("--------------------------");        System.out.println(remove);        System.out.println("-----------------------------");        //get(int index) 返回列表中指定位置的元素。        String str = list.get(0);        System.out.println(str);        System.out.println("----------------------");        //Object set(int index,Object obj)        list.set(0, "苏轼");        print(list);    }    public static void print(List<String> p){        Iterator<String> it = p.iterator();        while(it.hasNext()){            System.out.println(it.next());        }           }}

集合中还有一个集合工具类Collections类,可以实现List的倒序与洗牌与排序

    List中元素顺序可以被洗牌Collections.shuffle(list)    List中元素顺序可以被倒序Collections.reverse(list)    Collections.sort(list)对List元素排序
public class CollectionsDemo {    public static void main(String[] args) {        //创建List集合        List list = new ArrayList();        //给集合中添加元素        list.add(2);        list.add(8);        list.add(1);        list.add(3);        //List中元素顺序可以被洗牌Collections.shuffle(list)        //Collections.shuffle(list);        //List中元素顺序可以被倒序Collections.reverse(list)        //Collections.reverse(list);        //Collections.sort(list)对List元素排序(字母数字分别进行测试)        //如果是按字母是按照a-z的顺序进行排序        //Collections.sort(list);        //如果是按照数字进行排序,按照从小到大的顺序进行排列        Collections.sort(list);        //遍历集合        for (Object object : list) {            System.out.println(object);        }       }}

LinkedList:list集合接口的实现类
LinkedList特有功能:

    public void addFirst(E e)//向第一个位置添加元素    public void addLast(E e)//向最后一个位置添加元素    public E getFirst()//获取第一个元素    public E getLast()//获取最后一个元素    public E removeFirst()//移除第一个元素    public E removeLast()//移除最后一个元素

简单的进行测试:

public class LinkedListDemo {    public static void main(String[] args) {        //创建一个LinkedList的集合        LinkedList list = new LinkedList();        list.add("hello");        list.add("world");        list.add("java");        //          public void addFirst(E e)        //          public void addLast(E e)        //需求:在hello前面加上一个元素“c++”        list.addFirst("c++");        list.addLast("js");//              public E getFirst()//              public E getLast()//      Object first = list.getFirst();//      Object last = list.getLast();//      System.out.println(first);//      System.out.println(last);//              public E removeFirst()//              public E removeLast()        Object removeFirst = list.removeFirst();        Object removeLast = list.removeLast();        System.out.println(removeFirst);        System.out.println(removeLast);        System.out.println("---------------");        //遍历集合        for(Object obj:list){            System.out.println(obj);        }    }}

ArrayList与LinkedList的相同点与不同点

相同点:有顺序的,元素可以重复不同点:(1)ArrayList特点:    底层数据结构是数组,查询快,增删慢                                         线程不安全,效率高           (2)LinkedList特点:    底层数据结构是链表,查询慢,增删快    线程不安全,效率高

集合的遍历方式:

    1.for(普通for)(list集合专有,因为有get()方法)    2.Iterator(迭代器)    3.foreach(增强for)

foreach的格式:

for(集合中的元素类型   变量名:集合名){    }

需求:用List集合存储3个汽车对象,然后遍历。(用三种方式进行遍历)
分析:
1.创建汽车集合
2.创建汽车对象
3.创建list集合对象
4.向集合中添加对象元素
5.遍历

Car类:

public class Car {    private String brand;    private int price;    private String color;    public Car() {        super();        // TODO Auto-generated constructor stub    }    public Car(String brand, int price, String color) {        super();        this.brand = brand;        this.price = price;        this.color = color;    }    public String getBrand() {        return brand;    }    public void setBrand(String brand) {        this.brand = brand;    }    public int getPrice() {        return price;    }    public void setPrice(int price) {        this.price = price;    }    public String getColor() {        return color;    }    public void setColor(String color) {        this.color = color;    }}
public class ListDemo {    public static void main(String[] args) {        //创建汽车对象        Car c1 = new Car("大众",20000,"黑色");        Car c2 = new Car("奥迪",40000,"红色");        Car c3 = new Car("奔驰",60000,"白色");        //创建集合对象        List list =new ArrayList();        //集合中添加元素        list.add(c1);        list.add(c2);        list.add(c3);        //使用迭代器遍历        Iterator it = list.iterator();        while(it.hasNext()){            Car c=(Car) it.next();            System.out.println(c.getBrand()+" "+c.getPrice()+" "+c.getColor());        }        System.out.println("---------------------------");        //使用for循环遍历        for (int i = 0; i <list.size(); i++) {            Car c=(Car) list.get(i);            System.out.println(c.getBrand()+" "+c.getPrice()+" "+c.getColor());        }        System.out.println("---------------------------");        //增强for循环        for(Object obj:list){            Car c=(Car) obj;            System.out.println(c.getBrand()+" "+c.getPrice()+" "+c.getColor());        }    }}

结果:
这里写图片描述
set集合中的hashset
HashSet 元素顺序:元素唯一,但是无序(它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变)
如何保证元素的唯一性的呢?
通过分析源码,我们知道HashSet集合保证元素的唯一性和add()方法相关。
如何我们想深入的了解,就必须看add()方法的源码,看它的底层依赖什么内容?

     if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {...}   左边:e.hash == hash            比较对象的哈希值。       右边:((k = e.key) == key || key.equals(k))            左边:(k = e.key) == key                比较对象的地址值。            右边:key.equals(k)            比较的是对象的内容是否相同。默认情况下比较的是地址值    结论:    底层数据结构是哈希表。    哈希表依赖两个方法:hashCode()和equals()    执行流程:        首先判断哈希值是否相同,如果不同,就直接添加到集合。        如果相同,继续执行equals(),看其返回值,        如果是false,就直接添加到集合。        如果是true,说明元素重复不添加。

所以我们在使用hashset集合时想要保住元素的唯一性,就必须重写hashCode()和equals()这两个方法。至于如何重写,eclipse提供了自动生成的方法

练习:创建一个HashSet集合,添加元素(学生对象元素),保证其唯一性。
Student类:在这个类中重写hashCode()和equals()这两个方法

public class Student {    private String name;    private int age;    public Student(String name, int age) {        super();        this.name = name;        this.age = age;    }    public Student() {        super();        // TODO Auto-generated constructor stub    }    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;    }    @Override    public String toString() {        return "Student [name=" + name + ", age=" + age + "]";    }    //重写hashCode(),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;    }    @Override    public boolean equals(Object obj) {        if (this == obj)            return true;        if (obj == null)            return false;        if (getClass() != obj.getClass())            return false;        Student other = (Student) obj;        if (age != other.age)            return false;        if (name == null) {            if (other.name != null)                return false;        } else if (!name.equals(other.name))            return false;        return true;    }}

测试类:

public class HashSetDemo {    public static void main(String[] args) {        //创建集合        HashSet<Student> hs = new HashSet<Student>();        //创建学生对象        Student s1 = new Student("郭德纲", 50);        Student s2 = new Student("刘德华", 55);        Student s3 = new Student("张学友", 56);        Student s4 = new Student("黎明", 57);        Student s5 = new Student("郭德纲", 50);        //给集合中添加元素        hs.add(s1);        hs.add(s2);        hs.add(s3);        hs.add(s4);        hs.add(s5);        //遍历集合        for (Student student : hs) {            System.out.println(student);        }    }}

这里写图片描述
通过分析发现:郭德纲这个对象只出现了一次,保证了元素的唯一性
TreeSet
首先看一下它的两个构造方法:

    public TreeSet()    //构造一个新的空 set,该 set 根据其元素的自然顺序进行排序。    TreeSet(Comparator<? super E> comparator)       构造一个新的空 TreeSet,它根据指定比较器进行排序

元素顺序:使用元素的自然顺序对元素进行排序,或者根据创建 set时提供的 Comparator进行排序,具体取决于使用的构造方法。
底层算法:二叉树
元素要求, 加入自定义JavaBean
对java中已有数据类型的存入:

 1.如果是Integer类型的数据,按大小顺序存入 2.如果是String类型的数据,按首字母a-z的顺序存入

练习:创建集合存储Integer类型的元素(20,18,23,22,17,24,19,18,24)

public class TreeSetDemo {    public static void main(String[] args) {        //创建一个TreeSet集合        TreeSet<Integer> ts = new TreeSet<Integer>();        //给集合中存储元素        //(20,18,23,22,17,24,19,18,24)        ts.add(20);        ts.add(18);        ts.add(23);        ts.add(22);        ts.add(17);        ts.add(24);        ts.add(19);        ts.add(18);        ts.add(24);        //遍历集合        for (Integer integer : ts) {            System.out.print(integer+" ");        }    }}//结果:17 18 19 20 22 23 24 

分析:TreeSet集合特点:

      1.元素唯一      2.元素有序

这里写图片描述
那么在存入自定义对象元素时如何保证元素有序呢?分析Integer类和String类之后发现这两个类实现了一个Comparable接口,并重写comparaTo()方法,所以我们在存入自定义对象元素是也需要重写这个方法,就可以保证元素有序.当然还有另外一种方法,我们首先看一下第二种构造方法,它需要一个比较器实现类对象,那么我们可以用匿名类部类重写比较器中的Compare方法进行比较来保证元素有序。

练习:创建集合存储Student类型的元素,并保证其有序性
方式一:
1.创建Student类并实现Comparable接口,并重写comparaTo()方法
2.创建学生对象
3.使用无参构造创建空TreeSet集合
4.添加学生元素
5.遍历
学生类中实现的compareto方法

public int compareTo(Student s) {        //就是写的是元素的比较规则,由你自己去动手写出        //按照学生的年龄进行排序        /**         * 两个对象进行比较:         * s         * this         */        int num = this.age - s.age;        //判断年龄是否相同,如果相同比较姓名        /**         * 写这个比较规则的时候注意两点:         * 1.他有主要条件,先按照主要条件进行排序         * 2.如果主要条件相同,就需要你自己分析出来他的次要条件,再去按照次要条件进行比较         */        int num2 = num==0?this.name.compareTo(s.name):num;        return num2;    }

测试类:

public class TreeSetDemo {    public static void main(String[] args) {        //创建TreeSet集合,存储自定义对象        TreeSet<Student> ts = new TreeSet<Student>();        //给集合中添加Student对象        Student s = new Student("guodegang", 50);        Student s6 = new Student("liuyifei", 50);        Student s2 = new Student("zhangxueyou", 55);        Student s3 = new Student("amu", 45);        Student s4 = new Student("tf-boys", 18);        Student s5 = new Student("wangfeng", 49);        ts.add(s);        ts.add(s2);        ts.add(s3);        ts.add(s4);        ts.add(s5);        ts.add(s6);        //遍历集合        for (Student student : ts) {            System.out.println(student);        }    }}

这里写图片描述
方法二
1.创建Student类
2.创建学生对象
3.使用使用带选择器的有参构造创建空TreeSet集合
4.匿名类部类重写比较器中的Compare方法进行比较来保证元素有序。
5.添加学生元素
6.遍历

public class TreeSetDemo {    public static void main(String[] args) {        //使用匿名内部类来进行改进        TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {            @Override            public int compare(Student s1, Student s2) {                int num = s1.getAge() - s2.getAge();                int num2 = num==0?s1.getName().compareTo(s2.getName()):num;                return num2;            }        });        //创建对象存入集合        Student s = new Student("guodegang", 50);        Student s6 = new Student("liuyifei", 50);        Student s2 = new Student("zhangxueyou", 55);        Student s3 = new Student("amu", 45);        Student s4 = new Student("tf-boys", 18);        Student s5 = new Student("wangfeng", 49);        ts.add(s);        ts.add(s2);        ts.add(s3);        ts.add(s4);        ts.add(s5);        ts.add(s6);        //遍历集合        for (Student student : ts) {            System.out.println(student);        }    }}

两者结果完全相同
HashSet与TreeSet的相同点与不同点
相同点:

单列集合,元素不可重复

不同点:

1. 底层存储的数据结构不同    HashSet底层用的是HashMap哈希表结构存储,而TreeSet底层用的是TreeMap树结构存储2.存储时保证数据唯一性依据不同   HashSet是通过复写hashCode()方法和equals()方法来保证的,而TreeSet通过Compareable接口的compareTo()方法来保证的3.有序性不一样 HashSet无序,TreeSet有序

Map:将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。

Map接口中的方法概述(创建集合测试方法):

    A:删除功能        void clear():移除集合中的所有键值对元素        V remove(Object key):根据键移除键值对元素,并返回值    B:判断功能        boolean containsKey(Object key):判断集合中是否包含指定的键        boolean containsValue(Object value):判断集合中是否包含指定的值        boolean isEmpty():判断集合是否为空    C:获取功能        Set<Map.Entry<K,V>> entrySet():获取键值对对象的集合,遍历键值对对象,        利用getKey(),getValue()取出键和值(理解即可)        V get(Object key):根据键获取值        Set<K> keySet():获取所有的键        Collection<V> values():获取所有的值    D:添加功能        V put(K key,V value):集合添加键值对    E:长度功能        int size():键值对对数。

进行功能测试:

public class MapDemo {    public static void main(String[] args) {        //创建一个Map集合        //键是学号--值是姓名        Map<Integer,String> map = new HashMap<Integer,String>();        //V put(K key,V value):集合添加键值对        map.put(1, "周杰伦");        map.put(2, "郭德纲");        map.put(3, "刘德华");        map.put(4, "张学友");        //void clear():移除集合中的所有键值对元素        //map.clear();        //V remove(Object key):根据键移除键值对元素,并返回值        //String remove = map.remove(1);        //System.out.println(remove);        //boolean containsKey(Object key):判断集合中是否包含指定的键        //boolean containsKey = map.containsKey(2);        //System.out.println(containsKey);        //boolean containsValue(Object value):判断集合中是否包含指定的值        //boolean containsValue = map.containsValue("周杰伦");        //System.out.println(containsValue);        //boolean isEmpty():判断集合是否为空        //System.out.println(map.isEmpty());        //int size():键值对对数。        //System.out.println(map.size());        //Collection<V> values():获取所有的值        /*        Collection<String> values = map.values();        Iterator<String> it = values.iterator();        while (it.hasNext()) {            System.out.println(it.next());        }*/        //Set<Map.Entry<K,V>> entrySet():获取键值对对象的集合,遍历键值对对象,        //利用getKey(),getValue()取出键和值(理解即可)        Set<Entry<Integer,String>> entrySet = map.entrySet();        for (Entry<Integer, String> entry : entrySet) {            System.out.println(entry.getKey()+"  "+entry.getValue());        }        System.out.println("--------------------");        //Set<K> keySet():获取所有的键        Set<Integer> keys = map.keySet();        for (Integer key : keys) {            //V get(Object key):根据键获取值            System.out.println(key+"  "+map.get(key));        }    }}

HashMap

 元素顺序:元素顺序不可预测 底层算法:哈希算法 对键没有要求(仅仅相对于TreeMap来说)
public class HashMapDemo {    public static void main(String[] args) {        // 1.存入(String,String)主要讲解遍历方式,键:丈夫  值:妻子        HashMap<String, String> hm = new HashMap<String,String>();        //给键值对集合存入元素        hm.put("文章", "马伊琍");        hm.put("黄晓明", "baby");        hm.put("汪老师", "章子怡");        hm.put("周杰伦", "昆凌");        //hm.put("文章", "姚笛");,当后面存入的元素和前面的键的值相同的时候,前面的元素的值会被后面的元素的值代替        //遍历,通过建找值        Set<String> keys = hm.keySet();        for (String key : keys) {            System.out.println(key+"  "+hm.get(key));        }        System.out.println("-------------");        //通过找到结婚证,来分别找到丈夫和妻子        Set<Entry<String,String>> entrySet = hm.entrySet();        for (Entry<String, String> entry : entrySet) {            System.out.println(entry.getKey()+"  "+entry.getValue());        }    }}

Treemap

 元素顺序:元素顺序与键的排序规则有关底层算法:Tree算法

.HashMap与TreeMap的相同点与不同点

相同点:主要用于存储键(key)值(value)对,根据键得到值,因此键不允许键重复,但允许值重复。 不同点:    1.HashMap里面存入的键值对在取出的时候是随机的,也是我们最常用的一个Map.根据键可以直接获取它的值,具有很快的访问速度。在Map 中插入、删除和定位元素,HashMap 是最好的选择。      2.TreeMap取出来的是排序后的键值对。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。 
0 0
原创粉丝点击