Java的框架学习笔记

2016-12-14  本文已影响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);
    }

}
上一篇下一篇

猜你喜欢

热点阅读