Java学习系列(七)Java面向对象之集合框架详解(上)

Java集合

有时也将集合称为容器类,它的作用就是用来“装对象”的。这里要注意的是集合也可以是对象。下面先看一张图:

HashSet:底层用一个数组存元素 --而且这个数组的长度永远是2的N次方。

HashSet底层就是HashMap实现的。
HashSet的构造器:HashSet(int initialCapacity, float loadFactor)
--initialCapacity:控制底层数组的长度。
如果传入数组长度不是2的N次方,HashSet会自动扩展到2的N次方。
--loadFactory:当HashSet感觉到底层数组快满时,它会再次创建一个长度是原来数组长度2倍的数组。原有的数组就变成垃圾,并且要把原有数组中的元素复制到新数组中,这个过程也叫“重hash”。loadFactory越小,越耗内存;loadFactory越大,性能越低。

举例说明1:

 

Java代码   收藏代码
  1. public class Test {  
  2.     public static void main(String[] args) {  
  3.         //没有泛型限制的集合  
  4.         Collection c1 = new HashSet();    
  5.         c1.add(1);//本来1不是对象,无法装入集合,但由于jdk提供的自动装箱功能,它会将1包装成对象  
  6.         c1.add(new Date());  
  7.         //加入泛型限制的集合,意味着该集合只能装“指定类型”的对象。  
  8.         //jdk1.7可使用"菱形语法"将new HashSet<String>换成new HashSet<>  
  9.         Collection<String> c2 = new HashSet<String>();  
  10.         //c2.add(1);错误:只能装String类型的对象  
  11.         c2.add("张三");  
  12.         c2.add("李四");  
  13.         c2.add("王五");  
  14.         //判断集合是否包含指定元素  
  15.         System.out.println(c2.contains("张三"));  
  16.         System.out.println(c2.contains("赵六"));  
  17.         //遍历Set集合,有两种方式:1)foreach循环,2)迭代器  
  18.         System.out.print("使用foreach循环遍历:");  
  19.         for(String e : c2){  
  20.             System.out.print(e+" ");  
  21.         }  
  22.         Iterator<String> it = c2.iterator();  
  23.         System.out.print("\n使用迭代器遍历:");  
  24.         while(it.hasNext()){  
  25.             System.out.print(it.next()+"  ");  
  26.         }  
  27.         System.out.println();  
  28.         Collection<String> c3 = new HashSet<String>();  
  29.         c3.add("张三");  
  30.         c3.add("王五");  
  31.         c3.add("赵六");  
  32.         //求差集c2-c3  
  33. //      c2.removeAll(c3);  
  34. //      System.out.println("c2与c3差集:"+c2);  
  35.         //求并集  
  36. //      c2.addAll(c3);  
  37. //      System.out.println("c2与c3并集"+c2);  
  38.         //求交集  
  39.         c2.retainAll(c3);  
  40.         System.out.println("c2与c3交集:"+c2);  
  41.     }  
  42. }  

 

举例说明2:

 

Java代码   收藏代码
  1. public class TestHashSet {  
  2.     public static void main(String[] args) {  
  3.         HashSet<String> hs = new HashSet<String>(3);//底层数组容量会自动会展到4(注意:2的N次方)  
  4.         hs.add("1");  
  5.         hs.add("2");  
  6.         hs.add("3");  
  7.         hs.add("4");  
  8.         hs.add("5");  
  9.         //当HashSet感觉到底层数组快满时,它会再次创建一个长度是原来数组长度2倍的数组,此时新的数组长度为8  
  10.         System.out.println(hs);  
  11.     }  
  12. }  

 

HashSet存入机制:

1)当有元素加进来时,HashSet会调用该对象的hashCode()方法,得到一个int值;

2)根据hashCode()返回的int值,计算出它在HashSet的存储位置(数组中的索引);

3)如果要加入的位置是空的,直接方法即可。如果要加入的位置已经有元素,此处就会形成“链表”,数组越满,就越有可能出现链表。

HashSet取元素机制:

1)当有元素加进来时,HashSet会调用该对象的hashCode()方法,得到一个int值;

2)根据hashCode()返回的int值,计算出它在HashSet的存储位置(数组中的索引);

3)如果该位置恰好是要找的元素,直接取出即可。如果该位置有“链表”,HashSet要“挨个”地搜索链表里的元素。

HashSet怎么才会认为两个对象是相等的?(要求自定义类的hashCode()和equals()方法是一致的,即方法中所用到的关键属性要一致)

1、两个对象的hashCode()返回值相等;

2、两个对象通过equals比较返回true。

LinkedHashSet(HashSet的一个子类):它与HashSet的存储机制相似,但LinkedHashSet额外地有一个链表,这个链表可以保证LinkedHashSet能记住元素的添加顺序。

TreeSet(sortedset接口的实现类):它保证Set里添加的元素后是“大小排序”的。底层用一个“红黑树”存放元素。

举例说明(使用TreeSet要求集合元素必须是可以比较大小的):

 

Java代码   收藏代码
  1. public class TestTreeSet1 {  
  2. public static void main(String[] args) {  
  3. TreeSet<Integer> ts = new TreeSet<Integer>();  
  4. ts.add(3);  
  5. ts.add(1);  
  6. ts.add(2);  
  7. ts.add(5);  
  8. ts.add(4);  
  9. System.out.println(ts);  
  10. }  
  11. }  
Java代码   收藏代码
  1. public class TestTreeSet2 {  
  2.     public static void main(String[] args) {  
  3.         TreeSet<String> ts = new TreeSet<String>();  
  4.         ts.add("t");  
  5.         ts.add("r");  
  6.         ts.add("e");  
  7.         ts.add("e");  
  8.         System.out.println(ts);//字符串的大小  
  9.     }  
  10. }  

TreeSet元素存入、检索的性能也比较好。
Java的比较大小有两种方式:
A. --自然排序。所有集合元素要实现Comparable接口。
B. --定制排序。要求创建TreeSet时,提供一个Comparator对象(负责比较元素大小)。
举例说明:

 

 

Java代码   收藏代码
  1. class Apple implements Comparable<Apple> {  
  2.     private double weight;// 规定:苹果重量大的苹果越大  
  3.   
  4.     public Apple(double weight) {  
  5.         this.weight = weight;  
  6.     }  
  7.   
  8.     @Override   //自然排序  
  9.     public int compareTo(Apple obj) {  
  10.         return this.weight > obj.weight ? 1 : this.weight < obj.weight ? -1 : 0;  
  11.     }  
  12.        
  13.     @Override  
  14.     public String toString() {  
  15.         return "Apple[weight=" + this.weight + "]";  
  16.     }  
  17. }  
  18.   
  19. public class TreeSetTest {  
  20.   
  21.     public static void main(String[] args) {  
  22.         TreeSet<Apple> set = new TreeSet<Apple>();  
  23.         set.add(new Apple(2.3));  
  24.         set.add(new Apple(1.2));  
  25.         set.add(new Apple(3.5));  
  26.         for (Apple ele : set) {  
  27.             System.out.println(ele);  
  28.         }  
  29.     }  
  30. }  
Java代码   收藏代码
  1. class Bird {  
  2.     private String name;  
  3.   
  4.     public String getName() {  
  5.         return name;  
  6.     }  
  7.   
  8.     public Bird(String name) {  
  9.         this.name = name;  
  10.     }  
  11.   
  12.     @Override  
  13.     public String toString() {  
  14.         return "Bird[name=" + name + "]";  
  15.     }  
  16. }  
  17.   
  18. public class TreeSetTest2 {  
  19.   
  20.     public static void main(String[] args) {  
  21.         // 如果集合元素本身没有实现Comparable接口  
  22.         // 那就要求创建TreeSet时传入一个Comparator对象  
  23.         TreeSet<Bird> set = new TreeSet<Bird>(new Comparator<Bird>() {  
  24.             @Override  
  25.             public int compare(Bird o1, Bird o2) {  
  26.                 if (o1.getName().compareTo(o2.getName()) > 0) {  
  27.                     return -1;  
  28.                 } else if (o1.getName().compareTo(o2.getName()) < 0) {  
  29.                     return 1;  
  30.                 } else {  
  31.                     return 0;  
  32.                 }  
  33.             }  
  34.         });  
  35.         set.add(new Bird("aabc"));  
  36.         set.add(new Bird("abc"));  
  37.         set.add(new Bird("Z"));  
  38.         set.add(new Bird("dx"));  
  39.         System.out.println(set);   
  40.     }  
  41. }  

ArrayList(JDK1.2)与Vector(JDK1.0,已经过时)都是基于数组实现的,它们的区别如下:
ArrayList(可根据索引来存取元素)是线程不安全的,Vector是线程安全的。
--ArrayList的性能比Vector要好,即使在多线程环境下,可以使用Collections集合工具类的synchronizedXxx方法把ArrayList包装成线程安全的。

 

而LinkedList底层是基于链表实现的,通常认为它的性能比不上ArrayList,它们的区别如下:

ArrayList:由于可以根据底层数组的索引存取元素,所以性能非常快,但当插入元素、删除元素时性能低。

LinkedList:由于底层采用了链表来存储元素,因此根据索引存取元素性能较慢,但当插入、删除元素时性能非常快。
举例说明:

 

Java代码   收藏代码
  1. public class Test {  
  2.     public static void main(String[] args) {  
  3.         List<String> list = new ArrayList<String>();  
  4.         list.add("2");  
  5.         list.add("1");  
  6.         list.add("5");  
  7.         list.add("3");  
  8.         System.out.println(list);  
  9.         list.add(2,"在索引2处插入元素");  
  10.         System.out.println(list);  
  11.         list.set(2,"在索引2处替换的元素");  
  12.         System.out.println(list);  
  13.         list.remove(2);  
  14.         System.out.println(list);  
  15.         //遍历list(类似数组)  
  16.         for(int i =0;i<list.size();i++){  
  17.             System.out.print(list.get(i)+"   ");  
  18.         }  
  19.     }  
  20. }  

Deque集合:功能被限制的线性表。

 

Java代码   收藏代码
  1. //把Deque当成栈用  
  2. public class Test {  
  3.     public static void main(String[] args) {  
  4.         //把Deque当成栈用  
  5.         Deque<String> dq = new ArrayDeque<String>();  
  6.         //进栈(压栈):后进先出  
  7.         dq.push("a");  
  8.         dq.push("b");  
  9.         dq.push("c");  
  10.         dq.push("d");  
  11.         //打印首先出栈的元素  
  12.         System.out.println(dq.pop());  
  13.         //打印访问栈顶的元素  
  14.         System.out.println(dq.peek());  
  15.     }  
  16. }  
Java代码   收藏代码
  1. //把Deque当成队列用:先进先出  
  2. public class Test2 {  
  3.     public static void main(String[] args) {  
  4.         //把Deque当成队列用:先进先出  
  5.         Deque<String> dq = new ArrayDeque<String>();  
  6.         //从队列尾部入队  
  7.         dq.offer("a");  
  8.         dq.offer("b");  
  9.         dq.offer("c");  
  10.         dq.offer("d");  
  11.         //从队列头部出队  
  12.         System.out.println(dq.poll());  
  13.         //打印访问队头元素  
  14.         System.out.println(dq.peek());  
  15.     }  
  16. }  

Collections集合工具类:

Java代码   收藏代码
  1. public class TestCollections {  
  2.     public static void main(String[] args) {  
  3.         List<String> list = new ArrayList<String>();  
  4.         list.add("a");  
  5.         list.add("b");  
  6.         list.add("c");  
  7.         list.add("d");  
  8.         System.out.println(list);  
  9.         //对集合进行反转  
  10.         Collections.reverse(list);  
  11.         System.out.println(list);  
  12.         //把b, c位置进行交换  
  13.         Collections.swap(list, 12);  
  14.         System.out.println(list);  
  15.         //将list集合元素进行随机排列  
  16.         Collections.shuffle(list);  
  17.         System.out.println(list);  
  18.           
  19.     }  
  20. }  

 

 

结束语

今天内容比较多,而且有些和数据结构相关,所以理解起来可能会有些困难。编程我觉得还是要多练,只要你肯多练,就不会那么难了。今天就讲到这,明天开始讲Map。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值