zoukankan      html  css  js  c++  java
  • 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]
    {01=wnagwu, 02=zhangsan2, 03=zhangsan3, 04=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

  • 相关阅读:
    BCD码、十六进制与十进制互转
    UNIX环境高级编程 使用方法
    Windows下NFS服务器SFU设置(可以共享linux系统)
    Linux学习之CentOS(一)--CentOS6.4环境搭建
    WORKGROUP无法访问,您可能没有权限使用网络资源,请与这台服务器的管理员联系以....
    嵌入式学习步骤
    asp.net core-6.Bind读取配置文件到C#实例中
    asp.net core-5.控制台读取json文件
    asp.net core-4.命令行配置
    asp.net core-3.应用程序部署到iis
  • 原文地址:https://www.cnblogs.com/hen-java/p/12623097.html
Copyright © 2011-2022 走看看