自在如风

java 集合框架

集合框架

一、体系概述


Collection定义了集合框架的共性功能。集合可以看作是一种容器,用来存储对象信息。所有集合类都位于java.util包下。
数组与集合的区别如下:

  1. 数组长度不可变而且无法保存具有映射关系的数据;集合类用于保存数量不确定的数据,以及保存具有映射关系的数据。
  2. 数组元素既可以是基本类型的值,也可以是对象;集合只能保存对象。

Java集合类主要由两个根接口Collection和Map派生出来的,Collection派生出了两个子接口:List、Set,因此Java集合大致也可分成List、Set、Map三种接口体系。
List代表了有序可重复集合,可直接根据元素的索引来访问;Set代表无序不可重复集合,只能根据元素本身来访问;Map代表的是存储key-value对的集合,可根据元素的key来访问value。

二、Collection常用方法

引用自 Java API

import java.util.*;

class TT {
    public static void main(String[] args) {
        //创建一个集合容器。使用Collection接口的子类。ArrayList
        ArrayList al = new ArrayList();
        //添加元素。
        al.add("java01");//add(Object obj);
        al.add("java02");
        al.add("java03");
        al.add("java04");
        //打印原集合。
        sop("原集合:" + al);
        //删除元素。
        al.remove("java02");
		sop(al);
        //al.clear();//清空集合。
        //判断元素。
        sop("java03是否存在:" + al.contains("java03"));
        sop("集合是否为空?" + al.isEmpty());
        //获取个数。集合长度。
        sop("size:" + al.size());
        //打印改变后的集合。
        sop(al);
    }

    public static void sop(Object obj) {
        System.out.println(obj);
    }
}

运行结果:
原集合:[java01, java02, java03, java04]
[java01, java03, java04]
java03是否存在:true
集合是否为空?false
size:3
[java01, java03, java04]

迭代器 Iterator

迭代器是取出方式,会直接访问集合中的元素。所以将迭代器通过内部类的形式来进行描述。通过容器的iterator()方法获取该内部类的对象。

import java.util.*;

class CollectionDemo {
    public static void main(String[] args) {
        ArrayList al = new ArrayList();
        al.add("java01");
        al.add("java02");
        al.add("java03");
        al.add("java04");
        Iterator it = al.iterator();//获取迭代器,用于取出集合中的元素。
        while (it.hasNext()) {
            sop(it.next());
        }
        /*用for循环也行
        for (Iterator it = al.iterator(); it.hasNext(); ) {
            sop(it.next());
        }*/
    }
    public static void sop (Object obj){
        System.out.println(obj);
    }
}

运行结果:
java01
java02
java03
java04

三、List集合

|--List:元素是有序的,元素可以重复。因为该集合体系有索引。
	|--ArrayList:底层的数据结构使用的是数组结构。特点:查询速度很快。但是增删稍慢。线程不同步。
	|--LinkedList:底层使用的链表数据结构。特点:增删速度很快,查询稍慢。线程不同步。
	|--Vector:底层是数组数据结构。线程同步。被ArrayList替代了。因为效率低。
  • 特有方法:凡是可以操作角标的方法都是该体系特有的方法。
  • 特有的迭代器:ListIterator(列表迭代器),Iterator的子接口。
//演示列表迭代器。
import java.util.*;

public class Test {
    public static void main(String[] args) {
        ArrayList al = new ArrayList();
        al.add("java01");
        al.add("java02");
        al.add("java03");
        System.out.println(al);
        ListIterator li = al.listIterator();
        while(li.hasNext())
        {
            Object obj = li.next();
            if(obj.equals("java02")) {
                li.set("java006");//把“java02”元素设置为“java006”
            }
        }
        System.out.println(al);
    }
}

运行结果:
[java01, java02, java03]
[java01, java006, java03]

ArrayList

它允许任何符合规则的元素插入甚至包括null。每一个ArrayList都有一个初始容量(10),该容量代表了数组的大小。随着容器中的元素不断增加,容器的大小也会随着增加。

常见方法的例子

import java.util.*;

public class TT {
    public static void main(String[] args) {
        ArrayList al = new ArrayList();
        //添加元素
        al.add("java01");
        al.add("java02");
        al.add("java03");
        sop("原集合是:" + al);
        //在指定位置添加元素。
        al.add(1, "java09");
        //删除指定位置的元素。
        //al.remove(2);
        //修改元素。
        //al.set(2,"java007");
        //通过角标获取元素。
        sop("get(1):" + al.get(1));
        sop(al);
        //通过indexOf获取对象的位置。
        sop("index=" + al.indexOf("java02"));
        //返回列表中指定的 。
        List sub = al.subList(1, 3);
        sop("sub=" + sub);
    }

    public static void sop(Object obj) {
        System.out.println(obj);
    }
}

LinkedList

LinkedList的实现机制与ArrayList的实现机制完全不同,ArrayLiat内部以数组的形式保存集合的元素,所以随机访问集合元素有较好的性能;LinkedList内部以链表的形式保存集合中的元素,所以随机访问集合中的元素性能较差,但在插入删除元素时有较好的性能。

特有方法

  • addFirst();
  • addLast();
  • getFirst();
  • getLast();

获取元素,但不删除元素。如果集合中没有元素,会出现NoSuchElementException

  • removeFirst();
  • removeLast();
    获取元素,但是元素被删除。如果集合中没有元素,会出现NoSuchElementException
    在JDK1.6出现了替代方法。
  • offerFirst();
  • offerLast();
  • peekFirst();
  • peekLast();
    获取元素,但不删除元素。如果集合中没有元素,会返回null。
  • pollFirst();
  • pollLast();
    获取元素,但是元素被删除。如果集合中没有元素,会返回null。
import java.util.*;

class LinkedListDemo {
    public static void main(String[] args) {
        LinkedList link = new LinkedList();
        link.addLast("java01");
        link.addLast("java02");
        sop("link: " + link);
        sop(link.getFirst());
        sop(link.getLast());
        sop(link.removeLast());
        sop("link: " + link);
        LinkedList link1 = new LinkedList();
        link1.addLast("java01");
        link1.addLast("java02");
        link1.addLast("java03");
        sop("link1: " + link1);
        sop(link.offerFirst("java01"));
        sop(link1.peekLast());
        sop("link1: " + link1);
    }

    public static void sop(Object obj) {
        System.out.println(obj);
    }
}

运行结果:
link: [java01, java02]
java01
java02
java02
link: [java01]
link1: [java01, java02, java03]
true
java03
link1: [java01, java02, java03]

Process finished with exit code 0

Vector

与ArrayList相似,但是Vector是同步的。所以说Vector是线程安全的动态数组。它的操作与ArrayList几乎一样。

Set

Set:无序,不可以重复元素。

  • TreeSet:可以对Set集合中的元素进行排序。底层数据结构是二叉树。
    保证元素唯一性的依据:compareTo方法return 0.

HashSet

注意:对于判断元素是否存在以及删除等操作,依赖的方法是元素的hashcode和equals方法。

特点

  1. 不能保证元素的顺序。
  2. 线程不同步的。
  3. 集合元素值可以是null。
  4. 数据结构是哈希表。

存储原理:

当向集合存储一个元素时,HashSet会调用该对象的hashCode()方法得到其hashCode值,然后根据hashCode值决定该对象的存储位置。

查找原理

基于存储原理,在查找元素时,HashSet先计算元素的HashCode值(也就是调用对象的hashCode方法的返回值),然后直接到hashCode值对应的位置去取出元素。

判断两个元素相等的标准

  1. 两个对象的hashCode()方法返回值相等。
  2. 两个对象通过equals()方法比较返回true;

因此,如果1和2有一个不满足条件,则认为这两个对象不相等,可以添加成功。如果两个对象的hashCode()方法返回值相等,但是两个对象通过equals()方法比较返回false,HashSet会以链式结构将两个对象保存在同一位置,这将导致性能下降,因此在编码时应避免出现这种情况。
保证元素唯一性的原理:判断元素的hashCode值是否相同。如果相同,继续判断元素的equals方法,是否为true。

例子

/*
往hashSet集合中存入自定义对象
若姓名和年龄相同为同一个人,重复元素。
*/

import java.util.*;

class HashSetTest {
    public static void sop(Object obj) {
        System.out.println(obj);
    }

    public static void main(String[] args) {
        HashSet hs = new HashSet();
        hs.add(new Person("a1", 11));
        hs.add(new Person("a2", 12));
        hs.add(new Person("a1", 11));
        hs.add(new Person("a3", 13));
        Iterator it = hs.iterator();
        while (it.hasNext()) {
            Person p = (Person) it.next();
            sop(p.getName() + "::" + p.getAge());
        }
    }
}

class Person {
    private String name;
    private int age;

    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    //复写hasCode方法
    public int hashCode() {
        return name.hashCode() + age * 37;
    }
    //复写eauals方法
    public boolean equals(Object obj) {
        if (!(obj instanceof Person))//判断是不是Person类
            return false;
        Person p = (Person) obj;
        return this.name.equals(p.name) && this.age == p.age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

运行结果:
a3::13
a1::11
a2::12

TreeSet

TreeSet的排序方式

  1. 让元素自身具备比较性。元素需要实现Comparable接口,覆盖compareTo方法。这种方式也称为元素的自然顺序,或者叫做默认顺序。
  2. 当元素自身不具备比较性时,或者具备的比较性不是所需要的。这时就需要让集合自身具备比较性。在集合初始化时,就有了比较方式。
import java.util.*;

/*
当元素自身不具备比较性,或者具备的比较性不是所需要的。
这时需要让容器自身具备比较性。
定义了比较器,将比较器对象作为参数传递给TreeSet集合的构造函数。

当两种排序都存在时,以比较器为主。

定义一个类,实现Comparator接口,覆盖compare方法。


*/
class Student implements Comparable//该接口强制让学生具备比较性。
{
    private String name;
    private int age;

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

    public int compareTo(Object obj) {
        if (!(obj instanceof Student))
            throw new RuntimeException("不是学生对象");
        Student s = (Student) obj;
        if (this.age > s.age)
            return 1;
        if (this.age == s.age) {
            return this.name.compareTo(s.name);
        }
        return -1;
    }

    public String getName() {
        return name;

    }

    public int getAge() {
        return age;
    }
}

class TreeSetDemo2 {
    public static void main(String[] args) {
        TreeSet ts = new TreeSet();
        ts.add(new Student("lisi02", 22));
        ts.add(new Student("lisi02", 21));
        ts.add(new Student("lisi007", 20));
        ts.add(new Student("lisi09", 19));
        ts.add(new Student("lisi06", 18));
        ts.add(new Student("lisi06", 18));
        ts.add(new Student("lisi007", 29));
        Iterator it = ts.iterator();
        while (it.hasNext()) {
            Student stu = (Student) it.next();
            System.out.println(stu.getName() + "..." + stu.getAge());
        }
    }
}

class MyCompare implements Comparator {
    public int compare(Object o1, Object o2) {
        Student s1 = (Student) o1;
        Student s2 = (Student) o2;
        int num = s1.getName().compareTo(s2.getName());
        if (num == 0) {

            return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
        }
        return num;
    }
}

泛型

泛型格式:通过<>来定义要操作的引用数据类型。

? 通配符。也可以理解为占位符。
泛型的限定;
? extends E: 可以接收E类型或者E的子类型。上限。
? super E: 可以接收E类型或者E的父类型。下限。
  • 静态方法不可以访问类上定义的泛型。
  • 如果静态方法操作的应用数据类型不确定,可以将泛型定义在方法上。
  • 泛型类定义的泛型,在整个类中有效。如果被方法使用,
  • 那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。

为了让不同方法可以操作不同类型,而且类型还不确定。那么可以将泛型定义在方法上。

import java.util.*;

class GenericDemo2 {
    public static void main(String[] args) {
        TreeSet<String> ts = new TreeSet<String>(new LenComparator());
        ts.add("abcd");
        ts.add("cc");
        ts.add("cba");
        ts.add("aaa");
        ts.add("z");
        ts.add("hahaha");
        Iterator<String> it = ts.iterator();
        while (it.hasNext()) {
            String s = it.next();
            System.out.println(s);
        }
    }
}

class LenComparator implements Comparator<String> {
    public int compare(String o1, String o2) {
        int num = new Integer(o2.length()).compareTo(new Integer(o1.length()));

        if (num == 0)
            return o2.compareTo(o1);
        return num;
    }
}

Map集合

该集合存储键值对。一对一对往里存。而且要保证键的唯一性。
Map
|--Hashtable:底层是哈希表数据结构,不可以存入null键null值。该集合是线程同步的。jdk1.0.效率低。
|--HashMap:底层是哈希表数据结构,允许使用 null 值和 null 键,该集合是不同步的。将hashtable替代,jdk1.2.效率高。
|--TreeMap:底层是二叉树数据结构。线程不同步。可以用于给map集合中的键进行排序。

import java.util.*;

class MapDemo {
    public static void main(String[] args) {
        Map<String, String> map = new HashMap<String, String>();
        //添加元素,添加元素,如果出现添加时,相同的键。那么后添加的值会覆盖原有键对应值。
        //并put方法会返回被覆盖的值。
        System.out.println("put:" + map.put("01", "zhangsan1"));
        System.out.println("put:" + map.put("01", "wnagwu"));
        map.put("02", "zhangsan2");
        map.put("03", "zhangsan3");
        System.out.println("containsKey:" + map.containsKey("022"));
        //System.out.println("remove:"+map.remove("02"));
        System.out.println("get:" + map.get("023"));
        map.put("04", null);
        System.out.println("get:" + map.get("04"));
        //可以通过get方法的返回值来判断一个键是否存在。通过返回null来判断。
        //获取map集合中所有的值。
        Collection<String> coll = map.values();
        System.out.println(coll);
        System.out.println(map);
    }
}

运行结果:
put:null
put:zhangsan1
containsKey:false
get:null
get:null
[wnagwu, zhangsan2, zhangsan3, null]

Set keySet

将map中所有的键存入到Set集合。因为set具备迭代器。然后用迭代方式取出所有的键。再根据get方,获取每一个键对应的值。

Set<Map.Entry<k,v>> entrySet

将map集合中的映射关系存入到了set集合中,而这个关系的数据类型就是:Map.Entry。
Entry其实就是Map中的一个static内部接口。

例子

/*
每一个学生都有对应的归属地。
学生Student,地址String。
学生属性:姓名,年龄。
注意:姓名和年龄相同的视为同一个学生。
保证学生的唯一性。

1,描述学生。
2,定义map容器。将学生作为键,地址作为值。存入。
3,获取map集合中的元素。
*/

import java.util.*;

class Student implements Comparable<Student> {
    private String name;
    private int age;

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

    public int compareTo(Student s) {
        int num = new Integer(this.age).compareTo(new Integer(s.age));
        if (num == 0) {
            return this.name.compareTo(s.name);
        }
        return num;
    }

    public int hashCode() {
        return name.hashCode() + age * 34;
    }

    public boolean equals(Object obj) {
        if (!(obj instanceof Student)) {
            throw new ClassCastException("类型不匹配");
        }
        Student s = (Student) obj;
        return this.name.equals(s.name) && this.age == s.age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public String toString() {
        return name + ":" + age;
    }
}


class MapTest {
    public static void main(String[] args) {
        HashMap<Student, String> hm = new HashMap<Student, String>();
        hm.put(new Student("lisi1", 21), "beijing");
        hm.put(new Student("lisi1", 21), "tianjin");
        hm.put(new Student("lisi2", 22), "shanghai");
        hm.put(new Student("lisi3", 23), "nanjing");
        hm.put(new Student("lisi4", 24), "wuhan");
        //第一种取出方式 keySet
        Set<Student> keySet = hm.keySet();
        Iterator<Student> it = keySet.iterator();
        while (it.hasNext()) {
            Student stu = it.next();
            String addr = hm.get(stu);
            System.out.println(stu + ".." + addr);
        }


        //第二种取出方式 entrySet
        Set<Map.Entry<Student, String>> entrySet = hm.entrySet();
        Iterator<Map.Entry<Student, String>> iter = entrySet.iterator();
        while (iter.hasNext()) {
            Map.Entry<Student, String> me = iter.next();
            Student stu = me.getKey();
            String addr = me.getValue();
            System.out.println(stu + "........." + addr);
        }
    }
}

运行结果:
lisi4:24..wuhan
lisi2:22..shanghai
lisi1:21..tianjin
lisi3:23..nanjing
lisi4:24.........wuhan
lisi2:22.........shanghai
lisi1:21.........tianjin
lisi3:23.........nanjing

posted @ 2020-04-02 21:33  我是痕  阅读(197)  评论(0编辑  收藏  举报