美文网首页
Java的框架学习笔记

Java的框架学习笔记

作者: 宝塔山上的猫 | 来源:发表于2016-12-14 00:24 被阅读39次

    在java中Collection以及Map集合框架起着很大的作用,它是用于存储数据的一个框架,更多的理论知识可以查看Thinking in java这本书。

    其中集合分为两大类,Collection和Map,其中Collection可以直接存储数据,而Map则是使用key-value的方式来存取数据的。

    Collection框架

    Collection是一个接口类,它底下有两个小弟,List和Set

    Collection
        |--List:元素是有序的,元素可以重复。因为该集合体系有索引。
            |--ArrayList:底层的数据结构使用的是数组结构。特点:查询速度很快。但是增删稍慢。线程不同步。
            |--LinkedList:底层使用的链表数据结构。特点:增删速度很快,查询稍慢。线程不同步。
            |--Vector:底层是数组数据结构。线程同步。被ArrayList替代了。因为效率低。枚举是Vector特有的取出方式(nextElement())(因名称及方法名过长,最终被迭代器取代)
    
        |--Set:元素是无序(存入和取出的顺序不一定一致),元素不可以重复。、
            |--HashSet:底层数据结构是哈希表。是线程不安全的。不同步。
                HashSet是如何保证元素唯一性的呢?
                是通过元素的两个方法,hashCode和equals来完成。
                如果元素的HashCode值相同,才会判断equals是否为true。
                如果元素的hashcode值不同,不会调用equals。
    
                注意,对于判断元素是否存在,以及删除等操作,依赖的方法是元素的hashcode和equals方法。
                因为hashCode不同,所以有可能在HashSet中存入相同对象(属性相同,但是是new出来的)
    
            |--TreeSet:可以对Set集合中的元素进行排序。
                底层数据结构是二叉树。
                保证元素唯一性的依据:
                compareTo方法return 0.
    
                TreeSet排序的第一种方式:让元素自身具备比较性。
                元素需要实现Comparable接口,覆盖compareTo方法。
                这种方式也称为元素的自然顺序,或者叫做默认顺序。
    
                TreeSet的第二种排序方式。
                当元素自身不具备比较性时,或者具备的比较性不是所需要的。
                这时就需要让集合自身具备比较性。
                在集合初始化时,就有了比较方式。
    
        Set集合的功能和Collection是一致的。
    

    上面就是Collection的组成,那么Collection是父类,就应该有一些公共的方法是大家都拥有的,以下是Collection以及它的子类所拥有的方法:

    Collection定义了集合框架的共性功能。

    1,添加
        add(e);
        addAll(collection);
    
    2,删除
        remove(e);
        removeAll(collection);
        clear();
    
    3,判断。
        contains(e);
        isEmpty();
    
    4,获取
        iterator();
        size();
    
    5,获取交集。
        retainAll();
    
    6,集合变数组。
        toArray();
    
    1,add方法的参数类型是Object。以便于接收任意类型对象。
    
    2,集合中存储的都是对象的引用(地址)
    
    什么是迭代器呢?
    其实就是集合的取出元素的方式。
    
    迭代器是取出方式,会直接访问集合中的元素。
    所以将迭代器通过内部类的形式来进行描述。
    通过容器的iterator()方法获取该内部类的对象。
    

    这些方法都可以在List和Set中能够使用。

    需要特别注意的是迭代器Iterator的使用,其使用方法如下:

        ArrayList al = new ArrayList();
    
        // 1,添加元素。
        al.add("java01");// add(Object obj);
        al.add("java02");
        al.add("java03");
        al.add("java04");
    
        /*
         * Iterator it = al.iterator();//获取迭代器,用于取出集合中的元素。
         * 
         * while(it.hasNext()) { sop(it.next()); }
         */
    
        for (Iterator it = al.iterator(); it.hasNext();) {
            sop(it.next());
        }
    

    List集合

    List:特有方法。凡是可以操作角标的方法都是该体系特有的方法。

    增
        add(index,element);
        addAll(index,Collection);
    
    删
        remove(index);
    
    改
        set(index,element);
    查
        get(index):
        subList(from,to);
        listIterator();
        int indexOf(obj):获取指定元素的位置。
        ListIterator listIterator();
    
        注意:List集合特有的迭代器。ListIterator是Iterator的子接口。
        
        在迭代时,不可以通过集合对象的方法操作集合中的元素。
        因为会发生ConcurrentModificationException异常。
        
        所以,在迭代器时,只能用迭代器的方法操作元素,可是Iterator方法是有限的,
        只能对元素进行判断,取出,删除的操作,
        如果想要其他的操作如添加,修改等,就需要使用其子接口,ListIterator。
        
        该接口只能通过List集合的listIterator方法获取。
    

    ArrayList集合

    数组集合,常见的一种是用方式。

    在容器中,判断对象是否相同是调用Object中的equals()方法,也就是只有保存同一个对象才是相同的。这就导致了如果你新建了一个对象的实例,而实例中的内容是相同的,调用equals的时候也会被判断为不同。
    所以如果要依据对象的内容判断对象是否相同,则需要在对象内部重新equals()方法。

    示例如下:

    class Person {
        private String name;
        private int age;
    
        Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        // 重写Object的equals方法
        public boolean equals(Object obj) {
    
            if (!(obj instanceof Person))
                return false;
    
            Person p = (Person) obj;
            // System.out.println(this.name+"....."+p.name);
            // 通过判断姓名和年龄是否相同来判断是否同一个Person
            return this.name.equals(p.name) && this.age == p.age;
        }
    
        /**/
        public String getName() {
            return name;
        }
    
        public int getAge() {
            return age;
        }
    }
    
    class ArrayListTest2 {
        public static void sop(Object obj) {
            System.out.println(obj);
        }
    
        public static void main(String[] args) {
            ArrayList al = new ArrayList();
    
            al.add(new Person("lisi01", 30));// al.add(Object obj);//Object obj =
                                                // new Person("lisi01",30);
            // al.add(new Person("lisi02",32));
            al.add(new Person("lisi02", 32));
            al.add(new Person("lisi04", 35));
            al.add(new Person("lisi03", 33));
            // al.add(new Person("lisi04",35));
    
            // al = singleElement(al);
    
            sop("remove 03 :" + al.remove(new Person("lisi03", 33)));// remove方法底层也是依赖于元素的equals方法。
    
            Iterator it = al.iterator();
    
            while (it.hasNext()) {
                // Object obj=it.next();//迭代器只能识别Object
                // Person p=Person(obj);
                Person p = (Person) it.next();
                sop(p.getName() + "::" + p.getAge());
            }
        }
    
        public static ArrayList singleElement(ArrayList al) {
            // 定义一个临时容器。
            ArrayList newAl = new ArrayList();
    
            Iterator it = al.iterator();
    
            while (it.hasNext()) {
                Object obj = it.next();
    
                if (!newAl.contains(obj))// 底层是依赖于元素的equals方法。
                    newAl.add(obj);
    
            }
    
            return newAl;
        }
    }
    

    LinkedList集合

    LinkedList:特有方法:

    堆栈:先进后出 使用addFirst();
    队列:先进先出

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

    Vector集合

    枚举就是Vector特有的取出方式。
    发现枚举和迭代器很像。
    其实枚举和迭代是一样的。

    因为枚举的名称以及方法的名称都过长。
    所以被迭代器取代了。
    枚举郁郁而终了。

    代码示例:

    class VectorDemo {
        public static void main(String[] args) {
            Vector v = new Vector();
    
            v.add("java01");
            v.add("java02");
            v.add("java03");
            v.add("java04");
    
            Enumeration en = v.elements();
    
            while (en.hasMoreElements()) {
                System.out.println(en.nextElement());
            }
        }
    }
    

    Set集合

    HashSet集合

    Set集合是无序的,并且元素不能相同。但在实际操作过程成如果在ArrayList中的示例一样,创建两个具有相同内容的Person对象存入,却仍旧能保存进去,这是因为对于判断元素是否存在,以及删除等操作,依赖的方法是元素的hashcode和equals方法。因为hashCode不同,所以有可能在HashSet中存入相同对象(属性相同,但是是new出来的)。
    所以在保存对象的时候需要重写元素的hashcode和equals方法。
    示例代码如下:

    //先比较hash表中的对象地址值(HashCode值)如果地址值相同
    //再通过equals()方法比较对象内容,如果地址值不同,
    //不需要调用equals比较内容
    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("a3", 13));
            // hs.add(new Person("a2",12));
            // hs.add(new Person("a4",14));
    
            // sop("a1:"+hs.contains(new Person("a2",12)));
    
            // hs.remove(new Person("a4",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;
        }
    
        public int hashCode() {
            System.out.println(this.name + "....hashCode");
            return name.hashCode() + age * 37;
        }
    
        public boolean equals(Object obj) {
    
            if (!(obj instanceof Person))
                return false;
            
            Person p = (Person) obj;
            System.out.println(this.name + "...equals.." + p.name);
    
            return this.name.equals(p.name) && this.age == p.age;
        }
    
        public String getName() {
            return name;
        }
    
        public int getAge() {
            return age;
        }
    }
    

    TreeSet集合

    TreeSet集合会对元素进行排序,因此在使用TreeSet的时候要让元素具有比较性,所以元素需要实现Comparable接口,覆盖compareTo方法。同时在排序时,当主要条件相同时,一定判断一下次要条件,否则会误判为是相同对象而不被保存。

    示例代码:

    class TreeSetDemo {
        public static void main(String[] args) {
            TreeSet ts = new TreeSet();
            ts.add(new Student("lisi02", 22));
            ts.add(new Student("lisi007", 20));
            ts.add(new Student("lisi09", 19));
            ts.add(new Student("lisi08", 19));
            // ts.add(new Student("lisi007",20));
            // ts.add(new Student("lisi01",40));
    
            Iterator it = ts.iterator();
            while (it.hasNext()) {
                Student stu = (Student) it.next();
                System.out.println(stu.getName() + "..." + stu.getAge());
            }
        }
    }
    
    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) {
    
            // return 0;
            if (!(obj instanceof Student))
                throw new RuntimeException("不是学生对象");
            Student s = (Student) obj;
    
            System.out.println(this.name + "....compareto....." + s.name);
            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;
        }
    }
    

    当元素自身不具备比较性,或者具备的比较性不是所需要的(元素是其他人写的,自己不能实现)。
    这时需要让容器自身具备比较性。
    定义了比较器,将比较器对象作为参数传递给TreeSet集合的构造函数。

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

    定义一个类,实现Comparator接口,覆盖compare方法。
    String类 : int compareTo(String anotherString)按字典顺序比较两个字符串
    Comparable 接口:int compareTo(T o) 比较此对象与指定对象的顺序。
    返回:负整数、零或正整数,根据此对象是小于、等于还是大于指定对象
    Comparator 接口:int compare(T o1, T o2)方法比较用来排序的两个参数,
    返回:根据第一个参数小于、等于或大于第二个参数分别返回负整数、零或正整数。

    示例代码如下(让学生对象从按照年龄排序转为按照姓名排序):

    // Strudent对象没有变化
    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) {
    
            // return 0;
            if (!(obj instanceof Student))
                throw new RuntimeException("不是学生对象");
            Student s = (Student) obj;
    
            // System.out.println(this.name+"....compareto....."+s.name);
            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) {
            // 使用自定义的Compare方法
            TreeSet ts = new TreeSet(new MyCompare());
            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));
            // ts.add(new Student("lisi007",20));
            // ts.add(new Student("lisi01",40));
    
            Iterator it = ts.iterator();
            while (it.hasNext()) {
                Student stu = (Student) it.next();
                System.out.println(stu.getName() + "..." + stu.getAge());
            }
        }
    }
    // 实现Comparator接口,覆盖compare方法
    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()));
                /*
                 * if(s1.getAge()>s2.getAge()) return 1;
                 * if(s1.getAge()==s2.getAge()) return 0; return -1;
                 */
            }
    
            return num;
        }
    }
    

    Map集合框架

    Map与Collection框架在外部并没有什么必然的联系,但是其内部却稍微有些联系,因为Map集合也可以保持List集合。

    当数据之间存在这映射关系时,就要先想map集合。

    Map集合:该集合存储键值对。一对一对往里存。而且要保证键的唯一性。

    1,添加。
        put(K key, V value) 
        putAll(Map<? extends K,? extends V> m) 
    
    2,删除。
        clear() 
        remove(Object key) 
    
    3,判断。
        containsValue(Object value) 
        containsKey(Object key) 
        isEmpty() 
    
    4,获取。
        get(Object key) 
        size() 
        values() 
    
        entrySet() 
        keySet() 
    

    Map

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

    和Set很像。
    其实大家,Set底层就是使用了Map集合。

    map集合的两种取出方式:

    1,Set<k> keySet:将map中所有的键存入到Set集合。因为set具备迭代器。
        所有可以迭代方式取出所有的键,在根据get方法。获取每一个键对应的值。
            
    
        Map集合的取出原理:将map集合转成set集合。在通过迭代器取出。
    
    
    2,Set<Map.Entry<k,v>> entrySet:将map集合中的映射关系存入到了set集合中,
                    而这个关系的数据类型就是:Map.Entry
    
                    Entry其实就是Map中的一个static内部接口。
                    为什么要定义在内部呢?
                    因为只有有了Map集合,有了键值对,才会有键值的映射关系。
                    关系属于Map集合中的一个内部事物。
                    而且该事物在直接访问Map集合中的元素。
    

    Map集合取出元素示例代码如下:

    class MapDemo2 {
        public static void main(String[] args) {
            Map<String, String> map = new HashMap<String, String>();
    
            map.put("02", "zhangsan2");
            map.put("03", "zhangsan3");
            map.put("01", "zhangsan1");
            map.put("04", "zhangsan4");
    
            // 将Map集合中的映射关系取出。存入到Set集合中。
            Set<Map.Entry<String, String>> entrySet = map.entrySet();
    
            Iterator<Map.Entry<String, String>> it = entrySet.iterator();
    
            while (it.hasNext()) {
                Map.Entry<String, String> me = it.next();
                String key = me.getKey();
                String value = me.getValue();
    
                System.out.println(key + ":" + value);
    
            }
    
            /*
            //先获取map集合的所有键的Set集合,keySet();
            Set<String> keySet = map.keySet();
    
            //有了Set集合。就可以获取其迭代器。
            Iterator<String> it = keySet.iterator();
    
            while(it.hasNext())
            {
                String key = it.next();
                //有了键可以通过map集合的get方法获取其对应的值。
                String value  = map.get(key);
                System.out.println("key:"+key+",value:"+value);
            }
    
            */
    
        }
    }
    

    集合中的工具类

    Collections:集合框架的工具类。里面定义的都是静态方法。

    Collections和Collection有什么区别?
    Collection是集合框架中的一个顶层接口,它里面定义了单列集合的共性方法。

        它有两个常用的子接口,
        List:对元素都有定义索引。有序的。可以重复元素。
        Set:不可以重复元素。无序。
    

    Collections是集合框架中的一个工具类。该类中的方法都是静态的

        提供的方法中有可以对list集合进行排序,二分查找等方法。
        通常常用的集合都是线程不安全的。因为要提高效率。
        如果多线程操作这些集合时,可以通过该工具类中的同步方法,将线程不安全的集合,转换成安全的。
    

    Collections的使用:

    class CollectionsDemo {
        public static void main(String[] args) {
            sortDemo();
    
        }
    
        public static void binarySearchDemo() {
            List<String> list = new ArrayList<String>();
    
            list.add("abcd");
            list.add("aaa");
            list.add("zz");
            list.add("kkkkk");
            list.add("qq");
            list.add("z");
            // 排序
            Collections.sort(list, new StrLenComparator());
    
            sop(list);
    
            // int index = Collections.binarySearch(list,"aaaa");
            // int index = halfSearch(list,"cc");
            int index = halfSearch2(list, "aaaa", new StrLenComparator());
            sop("index=" + index);
        }
    
        public static int halfSearch(List<String> list, String key) {
            int max, min, mid;
            max = list.size() - 1;
            min = 0;
    
            while (min <= max) {
                mid = (max + min) >> 1;// /2;
    
                String str = list.get(mid);
    
                int num = str.compareTo(key);
                if (num > 0)
                    max = mid - 1;
                else if (num < 0)
                    min = mid + 1;
                else
                    return mid;
            }
            return -min - 1;
        }
    
        public static int halfSearch2(List<String> list, String key, Comparator<String> cmp) {
            int max, min, mid;
            max = list.size() - 1;
            min = 0;
    
            while (min <= max) {
                mid = (max + min) >> 1;// /2;
    
                String str = list.get(mid);
    
                int num = cmp.compare(str, key);
                if (num > 0)
                    max = mid - 1;
                else if (num < 0)
                    min = mid + 1;
                else
                    return mid;
            }
            return -min - 1;
        }
    
        public static void maxDemo() {
            List<String> list = new ArrayList<String>();
    
            list.add("abcd");
            list.add("aaa");
            list.add("zz");
            list.add("kkkkk");
            list.add("qq");
            list.add("z");
            Collections.sort(list);
            sop(list);
            String max = Collections.max(list/* ,new StrLenComparator() */);
            sop("max=" + max);
        }
    
        public static void sortDemo() {
            List<String> list = new ArrayList<String>();
    
            list.add("abcd");
            list.add("aaa");
            list.add("zz");
            list.add("kkkkk");
            list.add("qq");
            list.add("z");
    
            sop(list);
    
            // Collections.sort(list);
            Collections.sort(list, new StrLenComparator());
            // 互换
            // Collections.swap(list,1,2);
            sop(list);
    
        }
    
        public static void sop(Object obj) {
            System.out.println(obj);
        }
    }
    
    class StrLenComparator implements Comparator<String> {
        public int compare(String s1, String s2) {
            if (s1.length() > s2.length())
                return 1;
            if (s1.length() < s2.length())
                return -1;
            return s1.compareTo(s2);
        }
    }
    

    集合变数组

    Collection接口中的toArray方法。

    示例代码如下:

    class CollectionToArray {
        public static void main(String[] args) {
            ArrayList<String> al = new ArrayList<String>();
    
            al.add("abc1");
            al.add("abc2");
            al.add("abc3");
    
            /*
             * 1,指定类型的数组到底要定义多长呢? 当指定类型的数组长度小于了集合的size,那么该方法内部会创建一个新的数组。长度为集合的size。
             * 当指定类型的数组长度大于了集合的size,就不会新创建了数组。而是使用传递进来的数组。 所以创建一个刚刚好的数组最优。
             * 
             * 
             * 2,为什么要将集合变数组? 为了限定对元素的操作。不需要进行增删了。
             * 
             */
    
            String[] arr = al.toArray(new String[al.size()]);
    
            System.out.println(Arrays.toString(arr));
    
        }
    }
    

    关于Arrays

    Arrays:用于操作数组的工具类,里面都是静态方法。
    asList:将数组变成list集合

    使用示例代码:

    class ArraysDemo {
        public static void main(String[] args) {
            // int[] arr = {2,4,5};
            //
            // System.out.println(Arrays.toString(arr));
    
            String[] arr = { "abc", "cc", "kkkk" };
    
            // 把数组变成list集合有什么好处?
            /*
             * 可以使用集合的思想和方法来操作数组中的元素。 例如:当查找数组中的某一元素时直接用集合方便
             * 注意:将数组变成集合,不可以使用集合的增删方法。 因为数组的长度是固定。 contains。 get indexOf()
             * subList();
             * 
             * 如果你增删。那么会反生UnsupportedOperationException,
             * 
             */
            List<String> list = Arrays.asList(arr);
            // sop("contains:"+list.contains("cc"));
            // list.add("qq");//UnsupportedOperationException,
    
            // sop(list);
    
            // int[] nums = {2,4,5};
            Integer[] nums = { 2, 4, 5 };
    
            List<Integer> li = Arrays.asList(nums);
    
            /*
             * 如果数组中的元素都是对象。那么变成集合时,数组中的元素就直接转成集合中的元素。
             * 如果数组中的元素都是基本数据类型,那么会将该数组作为集合中的元素存在。
             */
            sop(li);
    
        }
    
        public static boolean myContains(String[] arr, String key) {
            for (int x = 0; x < arr.length; x++) {
                if (arr[x].equals(key))
                    return true;
            }
            return false;
        }
    
        public static void sop(Object obj) {
            System.out.println(obj);
        }
    
    }

    相关文章

      网友评论

          本文标题:Java的框架学习笔记

          本文链接:https://www.haomeiwen.com/subject/zzlbmttx.html