Java集合详解

  • (1)集合是什么?

  • java集合类存放于java.util包中,是一个用来存放对象的容器。 注意:

  • ①集合只能存放对象。比如你存一个int类型数据1放入集合中,其实它是自动转换成Integer类后存入的,java中每一种基本类型都有对应的引用类型。

  • ② 、集合存放的是多个对象的引用,对象本身还是放在堆内存中。

  • ③ 、集合可以存放不同类型,不限数量的数据类型。

  • (2)Iterator:迭代器,它是java集合的顶层接口(不包括map系列的集合,

  • Map接口是map系列集合的顶层接口)

  • Obiect next():返回迭代器刚越过的元素的引用,返回值是Obiect,需要强制转换成自己需要的类型。 boolean
    hasNext():判断容器内是否还有可提供访问的元素。 void remove:删除迭代器刚越过的元素。
    所以除了map系列集合,我们都可以通过迭代器来对集合中的元素进行遍历。
    connection(实现)Iterable(封装)Iterator(核心方法next()、hasnext()、remove())

  • (3)Collection:List接口和Set接口的父接口
    最基本的集合接口,一个Collection代表一组Object的集合,这些Object被称作Collection的元素。Collection是一个接口,用以提供规范定义,不能被实例化使用。

@Test
           public void TestIterator(){
           		List<String> list = new ArrayList<>();
           		list.add("Tom");
           		list.add("Bob");
           		list.add("Marry");
           		Iterator it = list.iterator();
           		while(it.hasNext()){
           			Object obj = it.next();
           			System.out.println(obj);
           		}
           		list.remove("Tom");
           		System.out.println("-----------------");
           		Iterator it1 = list.iterator();
           		
           		while(it1.hasN
       
       ext()){
               			Object obj = it1.next();
               			System.out.println(obj);
               			
               		}
               	}
               	@Test
               	public void
   
    testCollection(){
           		//将ArrayList集合作为Collection的实现类
           		Collection<String> collection = new ArrayList<String>();
           		//添加元素
           		collection.add("a");
           		collection.add("b");
           		//删除指定元素
           		collection.remove("a");
           		//删除所有元素
           		Collection<String> c = new ArrayList<>();
           		c.add("c");
           		c.add("1");
           		c.add("1");
           		c.add("1");
           		c.add("1");
           		c.add("1");
           		
           		collection.removeAll(c);
           		
           		//检测是否存在某个元素
           		collection.isEmpty();
           		
           		//判断是否为空
           		collection.isEmpty();
           		
           		//利用增强for循环遍历集合
           		for (String string : c) {
           			System.out.println(string);
           		}
           		//利用迭代器Iterator
           		Iterator iterator = collection.iterator();
           		while(iterator.hasNext()){
           			Object obj = iterator.next();
           			System.out.println(obj);
           		}
           	}
  • ① 、List:有序,可重复的集合。 由于List接口是继承Collection接口,所以基本的方法如上所示。
    A)List接口的三个典型实现: a)List list1 = new ArrayList();
    底层数据结构是数组,查询块,增删慢;线程不安全,效率不高。它封装了动态的增长的、允许在分配的object[]数组。 b)List
    list2 = new Vector(); 底层数据结构是数组,查询快,增删慢;线程安全,效率低,几乎已经淘汰这个集合。
    c)List list3 = new LinkedList();
    底层数据结构是链表,查询慢,增删块;线程不安全,效率高。同时它还实现了Deque接口,即能将LinkedList当做双端队列。
    补充—Queue Queue用于模拟“队列”这种结构(先进先出
    FIFO)。队列的头部存放着队列中存放时间最长的元素,队列的尾部存放着时间最短的元素。新插入的(offer)到队列的尾部。
    访问元素(poll)操作会返回队列的头部元素,队列不允许随机访问队列中的元素。 (1)PriorityQueue
    PriorityQueue并不是一个比较标准的队列实现,PriorityQueue保存队列元素的顺序并不是按照加入队列的顺序。而是按照对列元素的大小重新排列,这点从它的类名可以看出来。
    (2)Deque
    Deque接口代表一个“双端队列”,双端队列可以同时从两端添加或者删除元素,因此Deque的实现可以当成队列来使用,也可以当成栈来使用。
    补充–线程安全与线程不安全:
    线程安全就是多线程访问时采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该程序读取完,其它线程猜可以使用。不会出现数据不一致或者数据污染。
    线程不安全就是不能提供数据访问保护,又可能出现多个线程先后更改数据造成所得到的数据是脏数据。 有哪些可以解决多线程并发访问资源的安全问题呢
    分别是 同步代码块、同步方法和锁机制(Lock)

  • (1)同步代码块:

synchronized(同步锁)
       { //方法体
       }
  • (2)同步方法: 给多线程访问的成员方法加上synchronized修饰符

public synchronized  void test(){
            //方法体
       }
  • 以上两种方法都用到了java语言的关键字synchronized修饰符,当它用来修饰一个方法或者一个代码块的时候,能保证在同一时刻最多只有一个线程执行该段代码。

  • (3)锁机制(Lock)

  • Java提供的同步代码块的另一种机制,比synchronized关键字更强大也更加灵活。
    这种机制基于Lock接口及其实现类(例如:ReentrantLock)它比synchronized关键字好的地方:

  • 1、提供了更多的功能。tryLock()方法的实现,这个方法试图获取锁,如果锁已经被其他线程占用,它将返回false并继续往下执行代码。
    2、Lock接口允许分离读和写操作,允许多个线程读和只有一个写线程。
    3、具有更好的性能

public class PrintQueue {
         private final Lock A=new ReentrantLock();
         //...  }
  • List相关方法:

//产生一个 List 集合,典型实现为 ArrayList
           List list = new ArrayList();
           //添加三个元素
           list.add("Tom");
           list.add("Bob");
           list.add("Marry");
           //构造 List 的迭代器
           Iterator it = list.iterator();
           //通过迭代器遍历元素
           while(it.hasNext()){
               Object obj = it.next();
               //System.out.println(obj);
           }
           //在指定地方添加元素
           list.add(2, 0);
           //在指定地方替换元素
           list.set(2, 1);
           //获得指定对象的索引
           int i=list.indexOf(1);
           System.out.println("索引为:"+i);
           //遍历:普通for循环
           for(int j=0;j<list.size();j++){
                System.out.println(list.get(j));
           }
  • ② 、set:Set集合类似于一个罐子,“丢进”set集合里的多个对象之间没有明显顺序。set继承collection接口,不能包含有重复元素(这是整个set类层次的共有属性)。
    Set判断两个对象相同不是使用“==”运算符,而是equals方法。也就是说,我们再加入一个新元素的时候,如果这个新元素对象和set中已有对象进行逐一equals比较都返回false。则set就会接受新元素对象,否则拒绝。
    A)Set hashSet = new HashSet();
    a)HashSet:不能保证元素的顺序;不可重复;不是线程安全的;集合元素可以为NULL;
    b)其实其底层是一个数组,存在的意义是加快查询速度。我们知道在一班得数组中,元素在数组中的索引位置是随机的,元素的存取和元素的位置之间不存在确定的关系,因此,在数组中查询特定的值时,需要把查询值和一系列的元素进行比较,此时的查询效率依赖于查询过程中比较的次数。而HashSet集合底层数组索引和值有一个确定的关系:index=hash(value),那么只需要调用这个公式,就能快速的找到元素或者索引。
    B)Set linkedhashSet = new LinkedHashSet(); a)不可重复、有序
    因为底层采用链表和哈希的算法。链表保证元素的添加顺序,哈希表保证元素的唯一性。 C)Set treeSet = new
    TreeSet(); TreeSet有序;不可重复、底层使用红黑树算法,擅长于范围查询。 以上三个Set接口的实现类比较:
    共同点:都不允许元素重复。都不是线程安全的类,解决办法:Set set =
    Collections.synchorizedSet(set对象)。 不同点;
    HashSet:不能保证元素的添加顺序、底层采用哈希表算法,查询效率高。判断两个元素是否相等,equals()方法返回true,hashCode()值相等。即要求存入HashSet中的元素覆盖equals()方法和hashCode()方法。
    LinkedHashSet():HashSet的子类,底层采用了哈希算法以及链表算法,既保证了元素的添加顺序,也保证了查询效率。但整体性能要低于HashSet。
    TreeSet:不能保证元素的添加顺序,但会对集合的元素进行排列。底层采用红-黑数算算法(树结构比较适合范围查询)。 (4)Map
    Map用于保存具有“映射关系”的数据,因此Map集合里保存着两组值,一组值用于保存Map里的key,另外一组值用于保存Map里的value。key和value都可以是任何引用类型的数据。Map的key不允许重复,即同一个Map里的任何两个key通过eques方法比较结果总是返回false。关于Map,我们要从代码复用的角度去理解,Java是先实现了Map,然后通过包装了一个所有value都为null的Map就实现了Set集合。
    Map的这些实现类和子接口中key集的存储形式和Set集合完全相同(即key不重复)
    Map的这些实现类和子接口中value集的存储形式和List非常相似(即vlaue可以重复、根据索引查找)。
    因为Map集合即没有实现于Collection接口,也没有实现Itersble接口,所以不能对Map集合进行for-each遍历。 ①
    、HashMap
    和HashSet集合不能保证元素顺序的一样,HashMap也不能保证key-value对的顺序。并且类似于HashSet判断两个key是否相等的标准也是:两个key通过equals()方法比较按返回true、同时两个key的hashCode的值也必须相等。
    A)ListedHashMap也是使用双向链表来维护key-value对的次序,该链表负责维护Map的迭代顺序。与key-value对插入的顺序一致。
    ② 、Hashtable是一个古老的Map实现类。
    A)Properties对象在处理属性文件是特别方便(windows平台的.ins文件),properties类可以把Map对象和属性文件联系起来,从而可以把Map对象中的key-value对写到属性文件中,也可以把属性文件中的“属性名-属性值”加载到Map对象中。
    B)SortMap TreeMap
    TreeMap就是一个红黑树数据结构,每个key-value对即作为红黑树的一个节点。TreeMap存储key-value对(节点)时,需要根据key对节点进行排序。TreeMap可以保证所有的key-value对处于有序状态。同样,TreeMap也有两种排序方式:
    自然排序、定制排序。 C) WeakHashMap
    WeakHashMap与HashMap的用法基本相似。区别在于,HashMap的key保留了对实际对象的"强引用",这意味着只要该HashMap对象不被销毁,该HashMap所引用的对象就不会被垃圾回收。但WeakHashMap的key只保留了对实际对象的弱引用,这意味着如果WeakHashMap对象的key所引用的对象没有被其他强引用变量所引用,则这些key所引用的对象可能被垃圾回收,当垃圾回收了该key所对应的实际对象之后,WeakHashMap也可能自动删除这些key所对应的key-value对。
    补充-红黑树:
    红黑树是一种自平衡二叉树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组。红黑树是在进行插入和删除操作时通过特定的操作保持二叉树的平衡,从而获得较高的查找性能。它虽然是复杂的,但它的最坏情况运行时间也是非常良好的,并且在实践中是最高效的。

    红黑树是每个节点都带有颜色属性的二叉查找树,颜色为红色或黑色。在二叉树强制一般要求以为,对于任何有效的红黑树我们增加了如下的额外要求:
    性质一:节点为红色或者黑色 性质二:根节点是黑色 性质三:每个叶节点(NIL节点,空节点)是黑色的。
    性质四:每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径不能有两个连续的红色节点)
    性质五:从任一节点到其每个叶子的所有路径都包含相同的黑色节点。 ListHashMap:
    ListHashMap:key和value都允许空;key重复会覆盖、value允许重复;数据有序;非线程安全。
    ListHashMap实现有序key值的关键就是根据插入顺序另外维护了一个按照插入顺序作为标记的双向循环列表,这样在获取所有数据进行循环时获取到的数据就是有序数据。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值