集合

        集合就像一种容器,可以动态地把多个对象的引用放入容器中。

        集合中可以放多种类型的对象。

        集合中只能存放对象,不能存放基本类型的数据。如果看到可以直接添加数字,那一定是自动装箱了。

        集合分为Collection和Map(注意Map不属于Collection)。

        集合的长度是可变的,这点与数组不同。

1.Collection

        Collection接口是不按添加顺序存放对象的集合,集合内元素可以重复,即“无序可重复”。Collection接口中有两个常用的子接口List和Set。Collection接口中定义的方法可以操作List和Set。

 

1.1 List

        List接口中存放的元素有序并且可重复,并且其中的每个元素都有都有其对应的索引,就像动态的数组。 List接口中常用的实现类有ArrayList,LinkedList,Vector。

 

1.1.1 ArrayList

         ArrayList底层是用数组实现的。和数组一样,存放元素时是按添加顺序存放的,并且空间是连续的。因此,它遍历和添加元素的效率比较高,但是插入、删除的效率低。

         虽然ArrayList是线程不安全的,但是还是推荐使用它。

        通常用接口多态来创建一个集合对象:List list = new ArrayList();

        向list中添加一个元素:list.add(1);    //自动装箱了

        得到list的长度:list.size();       //没有length

 

1.1.2 LinkedList

        LinkedList底层是用链表实现的。和链表一样,存放元素时也是按添加顺序存放的,但是空间不是连续的。因此,它虽然遍历和添加元素的效率低,但是插入、删除的效率高。

 

1.1.3 Vector

        Vector比较古老。它和ArrayList没什么大的区别,区别之处就在于它是线程安全的,而且它比ArrayList慢。在使用时应尽量避免使用,一般都会选择ArrayList,即使ArrayList线程不安全,但是可以利用别的办法使线程安全。

 

1.1.4 测试

         List集合中的元素索引是从0开始的,并且是可以存放null的。当删除一个元素时,List集合会自动补全,长度减一。

        

         测试代码:    

         List list1 = new ArrayList();

         list1.add(null);

         System.out.println(list1.size());

         System.out.println(list1);

         list1.remove(0);         //0默认为元素的索引而不是元素。

        System.out.println(list1.size());

        System.out.println(list1);

 

         List list2 = new LinkedList();

         list2.add(null);

         System.out.println(list2.size());

         System.out.println(list2);

         list2.remove(0);

         System.out.println(list2.size());

         System.out.println(list2);

 

        测试结果:

         1

         [null]

         0

         []

         1

         [null]

        0

        []

 

1.2 Set

        Set接口中存放的元素是无序不可重复的,其中没有提供格外的方法,都是继承Collection接口的方法。 Set接口中常用的实现类有HashSet,TreeSet。

        Set集合不允许包含相同的元素,如果试把两个相同的元素加入同一个Set集合中,则添加操作失败。

        Set 判断两个对象是否相同不是使用 == 运算符,而是根据 equals 方法。

 

1.2.1 HashSet

         HashSet是Set接口的典型实现类,大多数时候使用Set集合时都使用这个实现类。HashSet不是线程安全的,并且不能保证元素的排列顺序。

         HashSet底层是数组实现的,不过是按Hash算法来存储集合中的元素,因此存放在它中的元素不是按照添加顺序存储的。当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法来得到该对象的 hashCode 值,然后根据 hashCode 值决定该对象在 HashSet 中的存储位置。

        也正是如此,HashSet具有很好的存取和查找性能,因为总是能根据哈希算法很快地找到要寻找的元素并进行操作。

         如果两个元素的 equals() 方法返回 true,但它们的 hashCode() 返回值不相等,hashSet 将会把它们存储在不同的位置,但依然可以添加成功。

         对于存放在Set容器中的对象,对应的类一定要重写equals(Object obj)和hashCode()方法,以实现对象相等规则。

         重写 hashCode() 方法的基本原则:

         ①在程序运行时,同一个对象多次调用 hashCode() 方法应该返回相同的值

         ②当两个对象的 equals() 方法比较返回 true 时,这两个对象的 hashCode() 方法的返回值也应相等

         ③对象中用作 equals() 方法比较的 Field,都应该用来计算 hashCode 值。

 

1.2.2 LinkedHashSet

 

         LinkedHashSet 是 HashSet 的子类

         LinkedHashSet 根据元素的 hashCode 值来决定元素的存储位置,但它同时使用链表维护元素的次序,这使得元素看起来是以插入顺序保存的。

         LinkedHashSet插入性能略低于 HashSet,但在迭代访问 Set 里的全部元素时有很好的性能。

         LinkedHashSet 不允许集合元素重复。

 

 

1.2.3 TreeSet

        TreeSet底层是用二叉树(红黑树)实现的,存放元素时自动排序,因此检索是效率非常高。

        这里需要注意的是,向TreeSet中添加的元素一定是能比较大小的元素,因为TreeSet底层是二叉树,在存放元素时是要排序的。如果一个元素不能比较大小就不能进行排序,也就不能添加到TreeSet集合中。那么问题来了,对象都不能大小,而集合中只能存放对象元素,那这不就矛盾了吗?

        事情总是有解决的办法的。既然对象不能比较大小,那么我们就按照对象中的某个属性的大小来决定对象的大小。而事实正是如此。比如要将Student对象放入TreeSet中,我们可以按照Student对象中age属性来决定Student对象的大小。年龄越大的Student对象越大。这时就需要重写Comparable接口的compareTo()方法或Comparator接口的compare()方法来进行对象比较的方法。

        注意,TreeSet比较大小不是依据equals()方法或hashCode()方法进行比较的,而是调用compareTo()方法进行比较。

        如果用到比较器Comparator,在创建TreeSet时需要将比较器对象当做TreeSet构造器的形参传入:

        Set set = new TreeSet(比较器对象);

 

1.2.4 测试

        Set集合中的元素是没有索引的,不过也能存放null。但是,当删除一个元素时,Set集合长度会改变。

 

        测试代码:

         Set set1 = new HashSet();

         set1.add(null);

         System.out.println(set1.size());

         System.out.println(set1);

         set1.remove(null);          //其中的参数不是索引,而是具体元素

         System.out.println(set1.size());

         System.out.println(set1);

 

         测试结果:

         1

         [null]

         0

         []

        

         测试代码:

         Set set2 = new TreeSet();

         //set2.add(null);        //会报错

         set2.add(2);

         System.out.println(set2.size());

         System.out.println(set2);

         set2.remove(2);            //这个1不是索引,而是元素本身

         System.out.println(set2.size());

         //String a = "你好";         //字符串因为无法比较,所以添加时会报错

         //String b = "好你";

         //set2.add(a);

         //set2.add(b);

         System.out.println(set2);

 

        测试结果:

         1

         [2]

         0

         []

 

2. Map

         Map与Collection并列存在。用于保存具有映射关系的数据:Key-Value

         Map 中的 key 和 value 都可以是任何引用类型的数据

         Map 中的 key 用 Set 来存放,不允许重复,即同一个 Map 对象所对应的类,须重写hashCode()和equals()方法。

         key 和 value 之间存在单向一对一关系,即通过指定的 key 总能找到唯一的、确定的 value。

        

         创建一个Map集合:Map map = new HashMap();

         向Map集合中添加一个元素:map.put(Object key, Object value);

         从一个Map集合中得到一个元素:map.get(key);

         删除Map中的一个元素:map.remove(key);

         得到Map结合中的所有Key: Set keys = map.keySet();

         Map接口的常用实现类:HashMap、 TreeMap 和 Properties。

 

2.1 HashMap

         HashMap是 Map 接口使用频率最高的实现类。

         允许使用null键和null值,与HashSet一样,不保证映射的顺序。

         HashMap 判断两个 key 相等的标准是:两个 key 通过 equals() 方法返回 true,hashCode 值也相等。

         HashMap 判断两个 value相等的标准是:两个 value 通过 equals() 方法返回 true。

 

2.2 TreeMap

         TreeMap存储 Key-Value 对时,需要根据 key-value 对进行排序。TreeMap 可以保证所有的 Key-Value 对处于有序状态。

         TreeMap 的 Key 的排序:

         ①自然排序:TreeMap 的所有的 Key 必须实现 Comparable 接口,而且所有的 Key 应该是同一个类的对象,否则将会抛出 ClasssCastException。

         ②定制排序:创建 TreeMap 时,传入一个 Comparator 对象,该对象负责对 TreeMap 中的所有 key 进行排序。此时不需要 Map 的 Key 实现 Comparable 接口。

         TreeMap判断两个key相等的标准:两个key通过compareTo()方法或者compare()方法返回0。

         若使用自定义类作为TreeMap的key,所属类需要重写equals()和hashCode()方法,且equals()方法返回true时,compareTo()方法应返回0。

 

2.3 Properties

         Properties类是HashTable类的子类,用于处理属性文件。

         在使用时需要在当前工程下简历xxx.properties配置文件,文件中的内容都是键值对,中间用=隔开。

         由于属性文件里的 key、value 都是字符串类型,所以 Properties 里的 key 和 value 都是字符串类型。

         存取数据时,建议使用setProperty(String key,String value)方法和getProperty(String key)方法。

         在程序中使用:

         Properties properties = new Properties();

         properties.load(new FileInputStream("xxx.properties"));    //加载properties文件

         String user = properties.get("key");

         注意,在xxx.properties文件中修改配置属性时,不用重启程序,会自动加载。

        

         Hashtable是个古老的 Map 实现类,线程安全。

         与HashMap不同,Hashtable 不允许使用 null 作为 key 和 value。

         与HashMap一样,Hashtable 也不能保证其中 Key-Value 对的顺序。

         Hashtable判断两个key相等、两个value相等的标准,与hashMap一致。

        

3. 遍历集合

3.1 foreach

         和遍历数组一样。

3.2 Iterator接口

         Iterator对象称为迭代器(设计模式的一种),主要用于遍历 Collection 集合中的元素。

         所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象。

         Iterator 仅用于遍历集合,Iterator 本身并不提供承装对象的能力。如果需要创建 Iterator 对象,则必须有一个被迭代的集合。

 

         Iterator接口中有两个常用方法:

         hasNext()方法:询问集合中有无下一个元素,迭代器指针不移动。

         next()方法:得到当前元素,指针移到下一个元素。

         在调用it.next()方法之前必须要调用it.hasNext()进行检测。若不调用,且下一条记录无效,直接调用it.next()会抛出NoSuchElementException异常。

         使用如下:

         Iterator iterator = coll.iterator();

         while (iterator.hasNext()) {

                  Object obj = iterator.next();

                  System.out.println(obj);

         }

 

3.3 Map集合的遍历

         Map集合的遍历比较特殊,需要通过遍历Map对象的键的集合来遍历。

         Set keys = map.keySet();

         for(Object key : keys){

                   map.get(key);

         }

 

4. Collections类

         和数组有Arrays工具类一样,集合也有Collections工具类,其中的方法也都是静态方法,因此调用时不需要创建对象,直接Collections.方法名();即可。

 

 

                                                                                                                                   by Karl

 

转载于:https://my.oschina.net/karl0/blog/776734

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值