黑马程序员----集合collection

集合框架详解
本文详细介绍了Java集合框架的基本概念,包括Collection、List、Set、Map等核心接口及其具体实现类的特点和应用场景,同时还探讨了如何使用工具类进行集合操作。

------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------

 

Collection: 表示一组对象,这些对象也称为 collection 的元素。一些 collection 允许有重复的元素,而另一些则不允许。


一些 collection 是有序的,而另一些则是无序的。JDK 不提供此接口的任何直接 实现:它提供更具体的子接口(如 Set 和 List)实现。


接口通常用来传递 collection,并在需要最大普遍性的地方操作这些 collection。



数组和集合类的区别:

 

 

数组虽然也可以存储对象,但长度是固定的;集合长度是可变的。



数组中可以存储基本数据类型,集合只能储对象。

 

集合类的特点:


 

集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。


 

Collection接口:


 

List接口:可存放重复元素,元素存取是有序的。


 

Set:不可以存放重复元素,元素存取是无序的。

 

 

 add方法的参数类型是Object,以便于接受任意类型对象。

 

 

集合中存储的都是对象的引用(地址)。

 

 

什么是迭代器:

 

 

其实就是集合的取出元素的方式。

 

 

迭代器的内部实现:

 

 

把取出方式定义在集合的内部,这样取出方式就可以直接访问集合内部的元素。那么取出方式就被定义成了内部类。

 

 

而每一个容器的数据结构不同,所以取出的动作细节也不一样。但是都有共性内容判断和取出。那么可以将共性抽取。

 

  

Collection:

 

 

List:元素是有序的,元素可以重复。因为该集合体系有索引。

 

 

ArrayList:底层的数据结构使用的是数组结构。特点:查询速度很快。但是增删稍慢。线程不同步。

 

 

当元素超过10个,则自动延长,50%延长。

 

 

LinkedList:底层使用的链表数据结构。特点:增删速度很快,查询稍慢。线程不同步。

 

 

Vector:底层是数组数据结构。线程同步。被ArrayList替代了。因为效率低。当元素超出10个,100%延长。

 

 

List集合功能:

 


 1、添加:


 add(index,element);


 addAll(index,Collection);

 

 

2、删除:


 remove(index);

 

 

3、修改:


 set(index,element);

 


4、查询:


 get(index);


 subList(from,to);


 listIterator();


 int indexOf(obj):获取指定元素的位置。


 ListIterator listIterator();

 


List集合特有的迭代器。ListIterator是Iterator的子接口。 

 

 

在迭代时,不可以通过集合对象的方法操作集合中的元素。

 


因为会发生ConcurrentModificationException异常。

 

 

所以,在迭代器时,只能用迭代器的方法操作元素,可是Iterator方法是有限的,只能对元素进行判断,

 

 

出,删除的操作,如果想要其他的操作如添加,修改等,就需要使用其子接口,ListIterator。

 

 

该接口只能通过List集合的listIterator方法获取。

 

 

在迭代过程中,准备添加或者删除元素。

 

 

Java代码  

Iterator it = al.iterator();  

  

        while(it.hasNext())  

        {  

            Object obj = it.next();  

  

            if(obj.equals("java02"))  

                al.add("java008");  

                  

        }  

  

此时将抛出ConcurrentModificationException异常  

 

 

 枚举就是Vector的特殊取出方式。

 

Java代码  

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());  

        }  

    }  

 

 

LinkedList:

 

 

LinkedList的特有方法:

 

 

addFirst();

 

addLast();

 

getFirst();

 

getLast();获取元素,但不删除元素。如果集合中没有元素,则抛出异常。

 

 

removeFirst();

 

removeLast();获取元素,但是元素被删除,如果集合中没有元素,则抛出异常。

 

 

在JDK 1.6出现了替代方法:

 

 

offerFirst();

 

offerLast();

 

 

peekFirst();

 

peekLast();获取元素,但不删除元素。如果集合中没有元素,返回null。

 

 

pollFirst();

 

pollLast();获取元素,但是元素被删除,如果集合中没有元素,则返回null。

 

 

 练习:使用LinkedList模拟一个堆栈或者队列数据结构。

 

 

Java代码  

class DuiLie  

{  

    private LinkedList link;  

  

    DuiLie()  

    {  

        link = new LinkedList();  

    }  

      

    public void myAdd(Object obj)//添加元素进入队列  

    {  

        link.addFirst(obj);  

    }  

    public Object myGet()//拿出元素,并移除这个元素  

    {  

        return link.removeFirst();  

    }  

    public boolean isNull()//判断队列中是否有元素  

    {  

        return link.isEmpty();  

    }  

  

}  

  

  

  

class  LinkedListTest  

{  

    public static void main(String[] args)   

    {  

        DuiLie dl = new DuiLie();//初始化并添加元素  

        dl.myAdd("java01");  

        dl.myAdd("java02");  

        dl.myAdd("java03");  

        dl.myAdd("java04");  

  

        while(!dl.isNull())//如果队列不为空,则取出元素  

        {  

            System.out.println(dl.myGet());  

        }  

    }  

}  

 

 

 练习:去除ArrayList集合中的重复元素。

 

 

Java代码  

class ArrayListTest   

{  

  

    public static void sop(Object obj)  

    {  

        System.out.println(obj);  

    }  

    public static void main(String[] args)   

    {  

        ArrayList al = new ArrayList();//初始化一个ArrayList对象  

  

        al.add("java01");//并添加元素  

        al.add("java02");  

        al.add("java01");  

        al.add("java02");  

        al.add("java01");  

  

        sop(al);//打印原集合  

          

        al = singleElement(al);  

  

        sop(al);//打印去掉重复元素的集合  

          

  

    }  

  

    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))//如果新集合不包含这个元素则存入新集合  

                newAl.add(obj);  

  

        }  

  

        return newAl;  

    }  

}  

 

 

 

Set集合:

 

 

Set:元素是无序(存入和取出的顺序不一定一致),元素不可以重复。

 


HashSet:底层数据结构是哈希表。是线程不安全的。不同步。

 


   HashSet保证元素的唯一性:

 

 

   1、是通过元素的两个方法,hashCode和equals来完成。

 


   2、如果元素的HashCode值相同,才会判断equals是否为true。

 


   3、如果元素的hashcode值不同,不会调用equals。

 

 

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

 

 

Set集合的功能和Collection是一致的。

 


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

 

 

Java代码  

class HashSetTest   

{  

    public static void sop(Object obj)  

    {  

        System.out.println(obj);  

    }  

    public static void main(String[] args)   

    {  

        HashSet hs = new HashSet();//定义一个HashSet  

          

        //向这个集合中添加自定义元素  

        hs.add(new Person("a1",11));  

        hs.add(new Person("a2",12));  

        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;  

    }  

      

    //覆盖hashCode值和equals方法  

    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集合:

 

 

 可以对Set集合中的元素进行排序。底层数据结构是二叉树。

 

 

保证元素唯一性的依据:compareTo方法return 0.

 

 

TreeSet排序的第一种方式:让元素自身具备比较性。

 


元素需要实现Comparable接口,覆盖compareTo方法。

 


也种方式也成为元素的自然顺序,或者叫做默认顺序。

 

 

TreeSet的第二种排序方式:

 


当元素自身不具备比较性时,或者具备的比较性不是所需要的。这时就需要让集合自身具备比较性。在集合

 

 

初始化时,就有了比较方式。定义了比较器,将比较器对象作为参数传递给TreeSet集合的构造函数。

 

 

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

 

 

练习:按字符串长度排序

 

Java代码  

class  TreeSetTest  

{  

    public static void main(String[] args)   

    {  

        TreeSet ts = new TreeSet(new StrLenComparator());//创建一个TreeSet,并传入一个比较器  

  

        ts.add("abcd");//添加元素  

        ts.add("cc");  

        ts.add("cba");  

        ts.add("aaa");  

        ts.add("z");  

        ts.add("hahaha");  

  

        Iterator it = ts.iterator();//遍历打印这个集合,查看排序结果  

  

        while(it.hasNext())  

        {  

            System.out.println(it.next());  

        }  

    }  

}  

  

class StrLenComparator implements Comparator  

{  

    public int compare(Object o1,Object o2)//覆盖compare方法  

    {  

        String s1 = (String)o1;  

        String s2 = (String)o2;  

              

        int num = new Integer(s1.length()).compareTo(new Integer(s2.length()));//字符串按长度从短到长排序  

        if(num==0)  

            return s1.compareTo(s2);  

  

        return num;  

    }  

}  

  

 

 

 

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()

 

 

Hashtable:底层是哈希表数据结构,不可以存入null键null值。该集合是线程同步的。jdk1.0.效率低。

 

 

HashMap:底层是哈希表数据结构,允许使用 null 值和 null 键,该集合是不同步的。将hashtable替代,jdk1.2.效率高。

 

 

TreeMap:底层是二叉树数据结构。线程不同步。可以用于给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集合中的元素。

 

 

Java代码  

interface Map  

{  

    public static interface Entry  

    {  

        public abstract Object getKey();  

        public abstract Object getValue();  

  

    }  

}  

  

class HashMap implements Map  

{  

    class Hahs implements Map.Entry  

    {  

        public  Object getKey(){}  

        public  Object getValue(){}  

    }  

      

}  

 

 

 Map的取出方式:

 

 

Java代码  

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); 

        } 

 

        */  

  

    }  

}  

 

 

Map练习:

 


每一个学生都有对应的归属地。学生Student,地址String。

 


学生属性:姓名,年龄。

 

 

注意:姓名和年龄相同的视为同一个学生。保证学生的唯一性。

 

 

Java代码  

class Student implements Comparable<Student>  

{  

    //定义学生的属性  

    private String name;  

    private int age;  

    Student(String name,int age)  

    {  

        this.name = name;  

        this.age = age;  

    }  

    //学生实现了Comparable接口,覆盖compareTo方法  

    //按年龄排序,如果年龄相等,则比较姓名  

    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;  

    }  

  

    //重写hashCode()和equals方法  

    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,并加入元素  

        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);  

        }  

    }  

}  

 
 

 练习:

 


"sdfgzxcvasdfxcvdf"获取该字符串中的字母出现的次数。

 

 

希望打印结果:a(1)c(2).....

 

 

Java代码  

class  MapTest3  

{  

    public static void main(String[] args)   

    {  

        String s = charCount("ak+abAf1c,dCkaAbc-defa");  

        System.out.println(s);  

    }  

      

    public static String charCount(String str)  

    {  

        char[] chs = str.toCharArray();//把字符串变为一个字符数组  

  

        TreeMap<Character,Integer> tm = new TreeMap<Character,Integer>();//建立TreeSet  

  

          

        int count = 0;//初始化计数器  

        for(int x=0; x<chs.length; x++)  

        {  

              

  

            //判断是否为字母  

            if(!(chs[x]>='a' && chs[x]<='z' || chs[x]>='A' && chs[x]<='Z'))  

                continue;  

              

            //取出计数器的值  

            Integer value = tm.get(chs[x]);  

  

            //如果存在,则计数器+1保存  

            if(value!=null)  

                count = value;  

            count++;  

            tm.put(chs[x],count);//直接往集合中存储字符和数字,为什么可以,因为自动装箱。  

  

            count = 0;  

      

        }  

          

        StringBuilder sb = new StringBuilder();//按顺序将键值对保存进sb中  

  

        Set<Map.Entry<Character,Integer>> entrySet = tm.entrySet();  

        Iterator<Map.Entry<Character,Integer>>  it = entrySet.iterator();//遍历entry  

  

        while(it.hasNext())  

        {  

            Map.Entry<Character,Integer> me = it.next();  

            Character ch = me.getKey();  

            Integer value = me.getValue();  

            sb.append(ch+"("+value+")");  

        }  

  

  

  

        return sb.toString();  

    }  

}  

 

 

Collections集合工具类:

 


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

 

 

Collections和Collection的区别:

 

 

 Collection是集合框架中的一个顶层接口,它里面定义了单列集合的共性方法。

 


 它有两个常用的子接口:

 


  List:对元素都有定义索引。有序的。可以重复元素。

 


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

 

 

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

 


 提供的方法中有可以对list集合进行排序,二分查找reverseOrder//reverseOrder(比较器)等方法。

 

 通常常用的集合都是线程不安全的。因为要提高效率。

 


 如果多线程操作这些集合时,可以通过该工具类中的同步方法,将线程不安全的集合,转换成安全的。

 

 

Arrays用于操作数组的工具类。

 

 

         asList:将数组变为一个List集合;将数组变成集合,不可以使用集合的增删方法。因为数组的长度是固定的。

 

 

如果数组中的元素都是对象。那么变成集合时,数组中的元素就直接转成集合中的元素。

 

 

如果数组中的元素都是基本数据类型,会将该数组作为集合中的元素存在。

 

 

Java代码  

class  ArraysDemo {  

    public static void main(String[] args) {  

  

        String[] arr = {"abc","cc","kkkk"};  

  

        List<String> list = Arrays.asList(arr);  

  

  

        //int[] nums = {2,4,5};  

        Integer[] nums = {2,4,5};  

  

        List<Integer> li = Arrays.asList(nums);  

  

  

        /* 

        如果数组中的元素都是对象。那么变成集合时,数组中的元素就直接转成集合中的元素。 

        如果数组中的元素都是基本数据类型,那么会将该数组作为集合中的元素存在。 

        */  

        sop(li);  

  

  

  

    }  

      

    public static void sop(Object obj)  

    {  

        System.out.println(obj);  

    }  

  

}  

 

 

集合变数组:

 

 

         Collection接口中的toArray()方法;

 

 

         1、指定类型的数组长度小于了集合的size,那么该方法内部会创建一个 新的数组,长度为集合的长度。

 

 

当指定类型的数组长度大于了集合的长度,就不会新创建数组,而是使用传递进来的数组。所以创建

 

 

一个刚刚好的数组最优。

 

        

         2、将集合变数组是为了限定对元素的操作。

 


 

### Java 高级集合进阶教程 #### Set 接口及其子类特性 Set接口是Java集合框架中的一个重要部分,它不允许存储重复元素。这使得`Set`非常适合用于去除重复项以及表示数学上的集合理论概念。 - **HashSet**: 实现了`Set`接口,内部基于哈希表实现[^3]。其特点是查找速度非常快,因为它是无序的,并且允许null值的存在(仅限一个)。为了保证元素唯一性,在向`HashSet`中添加对象时会调用该对象的`hashCode()`和`equals()`方法来判断是否已经存在相同元素。 ```java import java.util.HashSet; public class Student { private String name; public Student(String name){ this.name = name; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null || getClass() != obj.getClass()) return false; Student other = (Student) obj; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } } ``` - **LinkedHashSet**: 继承自`HashSet`,除了具备后者所有的性质外还保持了插入顺序不变。这意味着当你迭代这个set的时候,你会按照最初加入这些项目的次序得到它们。 - **TreeSet**: 提供了一种有序的方式去保存元素,底层采用红黑树结构实现了排序功能。可以通过自然排序(`Comparable`)或定制比较器(`Comparator`)两种方式定义元素之间的大小关系。 #### Collection 和 Map 的区别与联系 在Java中,`Collection`是一个顶层接口,代表一组单一类型的对象列表。而`Map`则用来映射键到值之间的一对一关联,即每一对键都对应着唯一的值[^4]。 对于想要深入了解高级集合特性的开发者来说: - `Collection`适用于处理单列数据; - `Map`更适合于管理具有键值对形式的数据。 了解两者间的差异有助于选择合适的数据容器以满足特定应用场景的需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值