Java中的集合

 

       面向对象语言对事物的体现是对象的形式,为了方便操作多个对象,就对对象进行存储。集合应运而生。

       集合特点:

      1、只存储对象(存对象引用,内存地址值);

      2、长度可变;

      3、可存不同类型对象;

       因为集合对数据的存储方式(数据结构)都有不同;故产生了很多集合;

       各种集合不断向上抽取过程中,形成了一个Collection接口,这个接口中有所有集合的共性。

 

-------------------------------------------------------------

Collection

       |--List:元素有序,可以重复,此集合体系有索引。

             |--ArrayList:底层是数组结构;特点:查询速度快,但增删稍慢;线程不同步;效率高;

             |--LinkedList:底层使用链表数据结构;特点:增删快,查询慢;

             |--Vector:与ArrayList一样,但线程是同步的;被ArrayList取代了;用枚举取出其中元素;

       |--Set:元素无序(存入取出的顺序不一定一致),元素不可重复;

       |--Map:一次存俩元素,存在映射关系;每个键映射一个值,键要保证唯一;

 

       共性方法:

       1、添加元素-->boolean add(E e):参数类型是ObjectE代表任意类型元素,是JDK1.5之后出现的新特性--泛型。

       2、获取个数-->int size():集合长度;

       3、删除元素-->boolean remove(Object o):删除单个元素;

             -->clear():清空集合

       4、判断元素-->boolean contains(Object o):判断o是否存在

             -->boolean isEmpty():不包含元素返回true

       retainAll(Collection c);取交集

       removeAll(Collection c);移除c中也有的元素

       addAll(Collection c);c中所有元素添加到调用方法的集合中;

       containsAll(Collection c);调用者身上有c中全部元素,返回true

       Iterator iterator();返回此集合的迭代器,用于取出集合中元素;

 

------------------------------------------------------------

       一、迭代器Itertor这是什么?-->取出元素的方式。每个集合的数据结构不一样,存取方式也是不一样的,每个集合

       中都将取出的动作封装成一个内部类,里面就封装了取出判断移除的方法。这样做就可以直接访问集合内的元素。

 

              通过集合中的方法来获得对象:Iterator it = 集合引用.iterator();

             Iterator中有三个方法:

                    boolean hasNext():若还有元素可以迭代就返回true

                    E naxt():返回迭代下一个元素;

                    void remove():移除迭代器返回的最后一个元素;

              可用结合for循环取出全部元素;如下

                    for(Iterator it=集合引用.iterator();it.hasNxet();)

                            {

                                     it.next();

//此时如果元素有偶数个,就不会异常,但是有奇数个的话,就会抛出异常;

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

                                    

}

                     用循环时要注意,每次判断最好只取一次,取多次会有java.util.NoSuchElementException异常。

-------------------------------------------------------------

       二、泛型:JDK1.5出现的新特性。用于解决安全问题的安全机制。集合框架中很常见。

              使用格式:通过<>来定义要操作的引用数据类型;<>就是用来接收类型的;

              好处:

             1、将运行时期出现的问题ClassCastException转移到编译时期,方便程序员解决问题,让运行时更加安全,问题更少。

             2,、避免了强制转换;

             -----

              泛型类:当类中要操作的引用数据类型不确定时,早期定义Object来完成扩展,现在定义泛型来完成扩展;

                     明确具体类型后,类中所有方法操作类型都确定了。

                     例:

                    //定义一个Tool

                    class Tool<HH>//通过<>来定义,HH随意定义,意为引用数据类型;

                    {

                           private HH h;//引用数据类型引用

                           public HH getHH(){//获取引用数据类型引用

                                  return h;

                           }

                    }

              泛型方法:方法返回值前加<>;类上不加<>了。

              静态方法泛型:不能访问类上定义的泛型;可定义在方法上;

             -----

              泛型限定:通配符“?”,上限:<? extends E>--->可以接受E类型或者E的子类型;

                            下限:<? super E>--->可以接受E类型或E类型的子类;(TreeSet集合中有个构造函数是这样干的)

                    

 

-----------------------------------

       三、List:元素有序,可以重复,此集合体系有索引。

              体系下特有方法:所有可以操作角标的方法都是此体系特有方法。

              --> add(index,element);指定位置插入指定元素

                    boolean addAll(index,Collection);指定位置开始,将指定集合中所有元素插入列表

              --> remove(index);

              -->set(index,element);将指定角标的元素修改为element

              --> get(index);返回指定角标的元素可用for循环得到

                    List<E> subList(from,to);获得从from开始到to元素

             listIterator():迭代时不能用集合对象的方法操作集合中元素,因为会发

                     ConcurrentModificationException异常,此时List体系中有个ListIterator子接口,

                     可以对集合进行更多操作。只能通过List集合的listIterator方法获得对象。

                     多的方法:hasPrevious()-->逆向遍历;

                                         set(E e);指定元素替换返回的最后一个元素。等等

              List集合判断集合是否相同,依据的是元素的equals方法。所以很多时候要重写自定义的类的这个方法;除了contains调用元素equals方法,remove也调用了。

 

             ArrayList类代码参考:

             class ArrayListListDemo

             {

                    public static void main(String[] args)

                    {

                           ArrayList al1 = new ArrayList();

                           ArrayList al2 = new ArrayList();

                            //集合al2中添加三个元素;

                           al2.add("java1");

                           al2.add("java2");

                           al2.add("java3");

                           //集合al1中添加元素;

                           al1.add("haha1");

                           al1.add(1,"haha3");//指定位置插入元素;

                           al1.addAll(1,al2);//将集合al2中的元素插入al1中,从1角标开始;

                           al1.set(2,"nihao");//将角标为2的元素修改成“nihao;

                           al1.get(3);//获得角标3的元素;

                           al1.subList(2,5);//获得[2,5)的元素;

                    }

             }

       ---------------------------

       LinkedList

              特有方法:

             addFirst():在集合头部添加---getFirst();获取第一个

             getLast():在集合后面添加---getLast();获取最后一个

             removeFirst();removeLast();获取第一个和最后一个,并删除集合中的这个元素;

                     以上getremove在调用时,集合中没有元素,将出现NoSuchElementException异常;

                     JDK1.6中出现了替代方法:offerFirstpeekFirstpollFirst。没有元素时,返回null

-----------------------------------

       四、Set元素无序(存入取出的顺序不一定一致),元素不可重复;

                     功能与Collection一致。底层使用Map集合。

       -------------------------------

       HashSet底层数据结构是哈希表;按哈希值来存元素的。

                     它是如何保证元素唯一性呢?通过元素两个方法:hashCodeequals

                     如果元素HashCode值相同,才会判断equals是否true;不同不调用。

              判断删除依据:依赖方法是元素的hashcodeequals方法;

              重写hashCodeequals方法代码示例:

 

             //自定义一个Person类,重写了hashCodeequals方法

             class Person

             {

                    private int age;

                    private String name;

                    public Person(int age,String name){

                           this.age = age;

                           this.name = name;

                    }

                    //重写hashCode方法

                    public int hashCode(){

                           //HashSet集合判断首要条件,相同时就调用重写后的equals方法判断次要条件;

                           return this.name.hashCode()+age*14;

                    }

                    //重写equals方法

                    public boolean equals(Object o){

                           if(!(o instanceof Person))

                                  throw new ClassCastException("类型不匹配!");

                           Person p = (Person)o;

                           return this.name.equals(p.name) && this.age == p.age;

                    }

             }

       -------------------------------

       TreeSet可对Set集合中元素进行排序;排序时,主要条件一样,要判断次要条件。

              二叉树数据结构:小的放左边,大的放右边(左小右大)。取的时候从最小开始取。

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

              第一种排序方式:让元素自身具备比较性,即元素需要实现Comparable接口,并覆盖

                    compareTo方法。这中方式成为元素的自然排序。

              第二种排序方式:当元素自身不具备或所具比较性不是所需,这时就让集合自身具备比较性;

                     定义比较器(类),实现Comparator接口,实现compare方法;集合在初始化时传入比较器对象。

              两种方式代码示例:

             //自定义一个Person类,实现了Comparable接口中compareTo方法;让元素具备比较性

             class Person implements Comparable

             {

                    private int age;

                    private String name;

                    public Person(int age,String name){

                           this.age = age;

                           this.name = name;

                    }

                    //实现compareTo方法,定义比较方式

                    public int compareTo(Object obj){

                           if (!(obj instanceof Person))

                                  throw new ClassCastException("类型错误!");

                           Person p = (Person)obj;

                           if(this.age > p.age)

                                  return 1;

                           if(this.age == p.age)

                                  //判断次要条件

                                  return this.name.compareTo(p.name);

                           return -1;

                    }

                    public int getAge(){   return age; }

                    public String getName(){return name; }

             }

 

             //定义一个比较器,实现了接口中的compare方法

             class com implements Comparator

             {

                    public int compare(Object obj1,Object obj2){

                           if(!(obj1 instanceof Person && obj2 instanceof Person))

                                  throw new ClassCastException("类型错误!");

                           Person p1 = (Person)obj1;

                           Person p2 = (Person)obj2;

                            //先判断name的顺序,再判断次要条件age

                           int num = p1.getName().compareTo(p2.getName());

                           if(num==0){

                                  return new Integer(p1.getAge()).compareTo(new Integer(p2.getAge()));

                           }

                           return num;

                            /*

                           if(p1.getAge() > p2.getAge())

                                  return 1;//先判断age,在判断name

                           if(p1.getAge() == p2.getAge())

                                  return p1.getName().compareTo(p2.getName());//判断次要条件name

                           return -1;

                            */

                    }

             }

 

--------------------------------------------------------------------

       五、Map一次存俩元素,存在映射关系;每个键映射一个值,键要保证唯一;

              |--Hashtable底层哈希表数据结构,不可存nullnull值,线程同步;效率低;

             |--HashMap:底层也是哈希表数据结构,可存nullnull值,线程不同步;jdk1.2开始有,效率高;

              |--TreeMap底层二叉树数据结构,线程不同步,可对map集合中的键进行排序。

              共性方法:

             1、添加

                    V put(K key,V value);添加键对值(添加时出现相同键,新键会覆盖旧的,put会返回被覆盖值)

             2、删除

                    void clear();移除所有映射关系

             3、判断:

                    boolean containsValue(Object value);

                    boolean containsKey(Object key);

                    isEmpty();

             4、获取

                    V get(Object key);根据key获得value,可以根据是否返回null来判断一个键是否存在;

                    int size();获取长度;

                    Collection<V> values();获取map集合中所有的值

 

              Map集合两种取出的特殊方法:

                     取出原理:将map集合转成set,再用迭代器迭代。

                    1Set<K> keySet();map中所有键存入Set集合,用Set集合的迭代器取出所有键,再用get获取每个键对应的值;

                    HashMap代码参考:

                    import java.util.*;

                    class MapDemo {

                           public static void main(String[] args) {

                                  //创建一个HashMap集合,存储了字符串键对值

                                  HashMap<String,String> hm = new HashMap<String,String>();

                                  hm.put("04","Java04");

                                  hm.put("02","Java02");

                                  hm.put("01","Java01");

                                  hm.put("03","Java03");

                                  Set<String> setKey = hm.keySet();//获得hm中所有的键并存入集合setKey

                                  Iterator<String> it = setKey.iterator();//获得Set集合迭代器

                                  while(it.hasNext()){

                                         String str = hm.get(it.next());//每获得一个键就取出一值并打印

                                         System.out.println(str);

                                  }

                           }

                    }

                    2Set<Map.Entry><K,V> entrySet();获得映射关系Map.Entry;将键值对取出当做一个元素存入set;这个方法里面封装了取出键值的方法:getKey()getValue();

                            关于Map.Entry接口:是Map接口中的接口,算是内部接口,里面封装了取出键值和修改

                            值(V setValue(V value))等方法;这个关系时随着集合生成才有的,故内部类形式定义;

                     代码参考:

                    import java.util.*;

                    class MapDemo2 {

                           //创建一个HashMap集合,存储了字符串键对值

                           HashMap<String,String> hm = new HashMap<String,String>();

                           hm.put("04","Java04");

                           hm.put("02","Java02");

                           hm.put("01","Java01");

                           hm.put("03","Java03");

                           //获得hm集合中的键值关系Map.entry,并存入Set集合中

                           Set<Map.Entry<String,String>> setEn = hm.entrySet();

                           Iterator<Map.Entry<String,String>> itEn = setEn.iterator();

                           while(itEn.hasNext()){

                                  Map.Entry<String,String> entry = itEn.next();//得到映射关系

                                  String key = entry.getKey();//取出Key

                                  String value = entry.getValue();//取出value

                                  System.out.println(key+"-----"+value);

                           }

                    }

 

 

-----------------------------------

       Collections:操作集合的工具类

             static <T extends Comparable<? super T>> void sort(List<T>list):List集合进行排序的方法;

             static <T> void sort(List<T> list, Comparator<? super T> c):指定比较器进行排序;

             static <T extends Object & Comparable<? super T>> T max(Collection<?extends T> coll):获得集合中最大元素;(同有min

             static <T> int binarySearch(List<? extends T> list, T key,Comparator<? super T> c)

             reverse():反转指定列表中元素的顺序。

             static <T> void fill(List<? super T> list, T obj) :用指定元素替换调用者全部元素;

             static <T> Comparator<T> reverseOlder(Comparator<T> cmp):强行逆转自然排序;

             static <T> Comparator<T> reverseOrder(Comparator<T> cmp):返回一个比较器,它强行逆转指定比较器的顺序。

       Arrays:操作数组的工具类

              asList():将数组变成List集合,可以使用集合思想和方法来操作数组中的元素;

                     但是,数组转成集合不能使用集合的增删方法,因为数组长度固定的;增删会发生java.lang.UnsupportedOperationException异常;

                     将基本数据类型数组转List集合时,这个数组会作为集合中的元素存在;数组中元素是对象时,就正常转成集合;

              集合变数组:Collection接口中的toArray方法;创建数组时要调用集合的size获得长度来设置长度,在内存中最优。

                     为何将集合边数组?为了限定对元素的操作。不需要进行增删了。

       ------------

总结:

 

集合就是用来存储对象用的,方便管理;

集合与数组有几点区别:可用集合多种,每个集合可以存储不同类型的对象;

集合的长度是可变的,就是说可以存一个集合长度就变长一个单位;

且集合可用方法很多,相比数组丰富多了;

 

 

JDK1.5之前,程序员都是按照自己的主观去判断集合里面存的什么类型对象,这样很不安全,

于是“泛型”应运而生;泛型对集合中存储的元素进行限定,规定这个集合只能存储规定的类型

的对象;

 

除了Map集合,Set和List两大派系的集合都可以使用迭代器Iterator对集合进行迭代;

Map集合存储的是键对值,一个键只能对应一个值,一个值可以对应多个键;

 

List集合存储的元素可以重复,是个有序的集合,可以使用工具类Collections中的sort方法进行自然排序

 

Set集合中的方法和Collection中的方法是一致的;与List集合刚刚相反,元素不可重复,无序;

对于HashSet集合存储自定义类的对象,需要重写hashCode方法和equals方法,当hashCode一样时,才去调用元素的equals方法判断;

对于TreeSet集合,就需要实现接口Comparable并重写CompareTo方法,对集合元素进行排序,当元素的排序不是咱需要的时,可以自

己写一个比较器:定义一个类并实现Comparator,重写方法compare;

 

对于这么多的集合,改怎么选择呢?这得看有什么需求,需要有序,元素可能重复,那么就选用List集合;不许自然顺序,并不可重复,就选Set;

若需要存储键对值,那么必然首选Map集合;这三大派系的集合都各有特点,使用时选择最需要最方便的无疑是最好的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值