`

JAVA 集合类

 
阅读更多
Set,List,Map的区别
java集合的主要分为三种类型:
Set(集)
List(列表)
Map(映射)

Collection接口

Collection是最基本的集合接口,声明了适用于JAVA集合(只包括Set和List)的通用方法。Set和List都继承了Collection,Map

Collection接口的方法:
boolean add(Object o)      :向集合中加入一个对象的引用   
void clear():删除集合中所有的对象,即不再持有这些对象的引用   
boolean isEmpty()    :判断集合是否为空   
boolean contains(Object o) : 判断集合中是否持有特定对象的引用   
Iterartor iterator()  :返回一个Iterator对象,可以用来遍历集合中的元素   
boolean remove(Object o) :从集合中删除一个对象的引用   
int size()   :返回集合中元素的数目   
Object[] toArray()  : 返回一个数组,该数组中包括集合中的所有元素 </SPAN>  


Iterator接口声明了如下方法: 

hasNext():判断集合中元素是否遍历完毕,如果没有,就返回true
next() :返回下一个元素  
remove():从集合中删除上一个有next()方法返回的元素。
------------------------------------------------------------------------------------------------------------------------------------
List

List接口主要实现类包括:

ArrayList() : 代表长度可以改变得数组。ArrayList在Java内部实现也是进行封装的数组,当增加的元素后个数大于当前数组个数,ArrayList会重新创建新的数组。
因为数组是一段连续的内存,那么意味着可以对元素很快速的利用下标进行访问(ArrayList.get(index)),但如果向ArrayList()中间插入与删除元素的速度慢,因为它要将后面的元素向后移动。



LinkedList(): 在实现中采用链表数据结构,每个元素中不仅包括元素本身的值,还包含指向下个元素的内存地址的指针,各个元素之间通过指针进行串联起来。
由于这种结构设计,LinkedList插入和删除速度快,它可以直接改变指向下个元素的指针内存地址即可,但如果通过下标访问,则访问速度慢。(通过一个个指针查找)


对于List的随机访问来说,就是只随机来检索位于特定位置的元素。 List 的 get(int index) 方法放回集合中由参数index指定的索引位置的对象,
下标从“0” 开始。最基本的两种检索集合中的所有对象的方法: 


检索list的方法:

for (int i = 0; i < list.size(); i++) {
  System.out.println(list.get(i));  
}

使用 迭代器(Iterator): 

Iterator it = list.iterator();
while(it.hasNext()){
  System.out.println(it.next());
}


Map 是一种把键对象和值对象映射的集合,它的每一个元素都包含一对键对象和值对象。 Map没有继承于Collection接口 从Map集合中检索元素时,只要给出键对象,就会返回对应的值对象。 

Map 的常用方法: 

1 添加,删除操作: 


Object put(Object key, Object value): 向集合中加入元素 
Object remove(Object key): 删除与KEY相关的元素 
void putAll(Map t):  将来自特定映像的所有元素添加给该映像 
void clear():从映像中删除所有映射 

2 查询操作: 

Object get(Object key):获得与关键字key相关的值 。Map集合中的键对象不允许重复,也就说,任意两个键对象通过equals()方法比较的结果都是false.
但是可以将任意多个键独享映射到同一个值对象上。 

方法put(Object key, Object value)添加一个“值”(想要得东西)和与“值”相关联的“键”(key)(使用它来查找)。方法get(Object key)返回与给定“键”相关联的“值”。
可以用containsKey()和containsValue()测试Map中是否包含某个“键”或“值”。
 
--HashMap
Map<Integer,Student> stuMap = new HashMap<Integer,Student>();
stuMap.put(1234, new Student(1234,"yange"));
stuMap.put(1235, new Student(1235,"xiaowang"));
stuMap.put(1236, new Student(1236,"xiaoli"));
for(Map.Entry<Integer, Student> en:stuMap.entrySet()){//循环Map中的每个键值对, hashmap的内部实现为数组保存,保存的元素为entry
  System.out.println(en.getKey()+ " "+en.getValue());
}

HashMap不保证查询遍历顺序,无论不插入顺序或者Key值大小排序顺序。
无论HashMap保存的元素上W个或者百万级别,通过Key值访问的消耗是固定的,因为Key值通过Hash运算后得出的数组下标,通过下标可以直接访问到元素。



--LinkedHashMap

LinkedHashMap 是HashMap的一个子类,保证查询的顺序,可以按照插入顺序输出

--TreeMap
TreeMap,采用二叉树,保证插入的顺序是按照key插入的。查询也是按照key大小顺序输出。


------------------------------------------------------------------------------------------------------------------------------------
Set(集合)

Set是最简单的一种集合。集合中的对象不按特定的方式排序,并且没有重复对象。 Set接口主要实现了两个实现类:

HashSet: HashSet类按照哈希算法来存取集合中的对象,存取速度比较快 
TreeSet :TreeSet类实现了SortedSet接口,能够对集合中的对象进行排序。

Set 的用法:存放的是对象的引用,没有重复对象

Set set = new HashSet();
String s1 = new String("hello");
String s2 = s1;
String s3 = new String("world");
set.add(s1);
set.add(s2);
set.add(s3);
System.out.println(set.size());//打印集合中对象的数目 为 2。


Set 的 add()方法是如何判断对象是否已经存放在集合中? 

boolean isExists = false;
Iterator it = set.iterator();
while(it.hasNext()){
String oldstr = (String)it.next();
if(s2.equals(oldstr)){
  isExists = true;
}
}

Set : 存入Set的每个元素都必须是唯一的,因为Set不保存重复元素。加入Set的元素必须定义equals()方法以确保对象的唯一性。
Set与Collection有完全一样的接口。Set接口不保证维护元素的次序。 



HashSet:为快速查找设计的Set。
HashSet不能添加重复的元素,当调用add(Object)方法时候,
首先会调用Object的hashCode方法判hashCode是否已经存在,如不存在则直接插入元素;
hashCode是jdk根据对象的地址或者字符串或者数字算出来的int类型的数值
如果已存在则调用Object对象的equals方法判断是否返回true, 如果为true则说明元素已经存在,如为false则插入元素。



TreeSet: 保存次序的Set, 底层为树结构。使用它可以从Set中提取有序的序列。 
LinkedHashSet:具有HashSet的查询速度,且内部使用链表维护元素的顺序(插入的次序)。于是在使用迭代器遍历Set时,结果会按元素插入的次序显示。

遍历Set的方法

Set<String> set = new HashSet<String>();  
Iterator<String> it = set.iterator();  
while (it.hasNext()) {  
  String str = it.next();  
  System.out.println(str);  
}  
  
2.for循环遍历:  
for (String str : set) {  
     System.out.println(str);  
}
------------------------------------------------------------------------------------------------------------------------------------

Queue
保证先进先出,后进后出,不能插入到中间,或取中间的元素

REMOVE() 方法:取出并移走队列的头部,当队列为空时,返回一个异常。
POLL()方法: 取出并移走队列的头部,当队列为空时,返回NULL。
PEEK()方法:获取队列的头部元素,但并不移走。当队列为空时,返回NULL。

public static void main(String args[]){
  Queue<String> strSet = new LinkedList<String>();
  strSet.add("2");
  strSet.add("1");
  strSet.add("3");
  strSet.add("4");
  while(!strSet.isEmpty()){
    System.out.println(strSet.peek()); // 2 1 3 4
  }
}   
Deque
双端队列,可以选择从队列的头部或者尾部插入元素


FileIterator 类,利用队列一层层从外向里打印文件名称,先打印当前层次的所有文件后,再进入下一层

public List<String> listFiles(String dir){
    File fdir = new File(dir);
    List<String> subfiles = new ArrayList<String>();
    Queue<File> fileQueue = new ConcurrentLinkedQueue<File>();
    fileQueue.add(fdir);
    while(!fileQueue.isEmpty()){
      File file = fileQueue.poll();
      subfiles.add(file.getAbsolutePath());
      if(file.isFile()){
        continue;
      }
      File[] files = file.listFiles();
      for(File f:files){
        fileQueue.add(f);
      }
    }
    return subfiles;
  }



Stack 栈
最先进的元素,一定是在最后面,拿的话只能是拿最近进入的。
push()
增加一个元素压到栈中。
pop()
从栈中弹出一个元素

public static void main(String args[]){
   Stack<String> stackSet = new Stack<String>();
   stackSet.push("2");
   stackSet.push("1");
   stackSet.push("3");
   stackSet.push("4");
   while(!stackSet.isEmpty()){
     System.out.println(stackSet.pop());// 4 3 1 2
   }
 }


public List<String> listFiles(String dir){
    File fdir = new File(dir);
    List<String> subfiles = new ArrayList<String>();
    Stack<File> fileQueue = new Stack<File>();
    fileQueue.push(fdir);
    while(!fileQueue.isEmpty()){
      File file = fileQueue.pop();
      subfiles.add(file.getAbsolutePath());
      if(file.isFile()){
        continue;
      }
      File[] files = file.listFiles();
      for(File f:files){
        fileQueue.push(f);
      }
    }
    return subfiles;
  }
}
------------------------------------------------------------------------------
任何集合类都可以通过使用同步包装器变成线程安全的:

List<E> synchArrayList = Collections.synchronizedList(new ArrayList<E>());
Map<K,V> synchMap = Collections.synchronizedMap(new HasMap<K,V>());

其他常用的线程安全集合类

Vector
与ArrayList的线程安全类,但各个方法都有添加Synchronized关键字

Hashtable
是HashMap的线程安全类
它把所有方法都加上synchronized关键字来实现线程安全


注意:
如果使用for each 循环必须使用同步锁锁。

为什么线程安全的Vector也不能线程安全地遍历呢?其实道理也很简单,看Vector源码可以发现它的很多方法都加上了synchronized来进行线程同步,例如add()、remove()、set()、get(),
但是Vector内部的synchronized方法无法控制到遍历操作,所以即使是线程安全的Vector也无法做到线程安全地遍历。
如果想要线程安全地遍历Vector,需要我们去手动在遍历时给Vector加上synchronized锁,防止遍历的同时进行remove操作。

示例:
import java.util.Vector;

public class TestConcurrentModifyException implements Runnable {
	Vector<String> synchArrayList = new Vector<String>();
	public static void main(String args[]) throws InterruptedException{
		TestConcurrentModifyException test =  new TestConcurrentModifyException();
		test.synchArrayList.add("a");
		test.synchArrayList.add("b");
		test.synchArrayList.add("c");
		test.synchArrayList.add("d");
		test.synchArrayList.add("e");
		Thread tr = new Thread(test);
		tr.start();
		Thread.sleep(500);
		test.synchArrayList.add("f");
		Thread.sleep(500);
		test.synchArrayList.add("g");
		Thread.sleep(500);
		test.synchArrayList.add("h");
	}

	@Override
	public void run() {
		for(String str:synchArrayList){
			System.out.println("线程安全List Size:"+synchArrayList.size());
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(str);
		}		
	}
}

线程安全List Size:5
a
Exception in thread "Thread-0" java.util.ConcurrentModificationException
	at java.util.Vector$Itr.checkForComodification(Vector.java:1156)
	at java.util.Vector$Itr.next(Vector.java:1133)
	at TestConcurrentModifyException.run(TestConcurrentModifyException.java:26)
	at java.lang.Thread.run(Thread.java:745)

解决方案:

public void run() {
synchronized (synchArrayList) {
	for (String str : synchArrayList) {
		System.out.println("线程安全List Size:" + synchArrayList.size());
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(str);
	}
}
}

CopyOnWriteArrayList
CopyOnWrite的意思是在写时拷贝,也就是如果需要对CopyOnWriteArrayList的内容进行改变,首先会拷贝一份新的List并且在新的List上进行修改,最后将原List的引用指向新的List。
使用CopyOnWriteArrayList可以线程安全地遍历,因为如果另外一个线程在遍历的时候修改List的话,实际上会拷贝出一个新的List上修改,而不影响当前正在被遍历的List。

ConcurrentHashMap
ConcurrentHashMap的设计有点特别,表现在多个线程操作上。它不用做外的同步的情况下默认同时允许16个线程读和写这个Map容器。因为其内部的实现剥夺了锁,
使它有很好的扩展性。不像HashTable和Synchronized Map,ConcurrentHashMap不需要锁整个Map,相反它划分了多个段(segments),要操作哪一段才上锁那段数据。

悲观锁:
总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。
传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。再比如Java里面的同步原语synchronized关键字的实现也是悲观锁。

乐观锁:
顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,
可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁。
在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的

 

分享到:
评论

相关推荐

    java集合类详解(set list ArrayList等java集合类详述)

    Java 集合类详解 Java 集合类是 Java 语言中的一种基本数据结构,用于存储和操作大量数据。集合类可以分为三大类:Collection、List 和 Set。 Collection 是集合框架中的根接口,提供了基本的集合操作,如 add、...

    Java集合排序及java集合类详解.pdf

    ### Java集合排序及Java集合类详解 #### 一、集合框架概述 集合框架是Java编程语言的核心组件之一,用于组织和操作数据集。Java集合框架提供了多种数据结构,包括列表(List)、集(Set)和映射(Map),这些数据结构...

    第13讲 JAVA集合类.ppt

    Java集合类是Java编程语言中用于存储和管理对象的关键组件,它们构成了Java Collections Framework的核心。这个框架提供了一组高效、灵活的数据结构,使得开发者能够轻松地处理数据集合,而无需关心底层实现的复杂性...

    java集合类线程安全.doc

    所涉及的集合类不仅包括 Java SE 1.2 引入的集合类,还包括旧集合类(Java SE 1.2 前引入)和新集合类(Java SE 5 引入)。 Java 线程安全的等级定义根据 Bloch 的定义,将线程安全分为五个等级: 1. 非可变:如果...

    一张图让你看清Java集合类

    一张图让你看清Java集合类 所有精华 集于一图 一目了然 形象易懂 十分中肯 绝对干货!

    大公司最喜欢问的Java集合类面试题

    ### Java集合类重要知识点 #### 一、概述 在Java编程中,集合类是一个非常重要的概念,主要用于存储和管理对象的集合。Java集合框架主要包括两大类:`Collection`和`Map`。本篇文章将着重介绍`Collection`部分,并...

    Java集合类性能分析

    ### Java集合类性能分析 #### 一、Java集合框架概览 Java集合框架是一个非常重要的概念,它提供了处理数据集合的标准方法。集合框架的核心部分主要包括集合接口、抽象类以及具体的实现类。 - **集合接口**:Java...

    java集合类详解

    Java集合类是Java语言中用来存储数据的结构,它们是Java开发中非常重要的组件。在Java 2平台之前,集合框架的组成较为零散,自Java 2平台的JDK 1.2版本之后,引入了集合框架(Collections Framework),为集合类提供...

    java 集合类 容器类

    ### Java集合类与容器类详解 #### 一、引言 在Java编程中,集合类是一种非常重要的数据结构,用于存储一系列对象。相比于数组,集合类提供了更多的灵活性和功能,尤其是在处理未知数量的对象时更为方便。Java标准...

    java集合类面试题总结

    Java 集合类面试题总结 Java 集合类是 Java 语言中的一种重要组件,用于存储和操作数据。下面总结了 Java 集合类的一些常见问题和答案。 HashMap 和 Hashtable 的区别 HashMap 和 Hashtable 都是 Java 中的散列表...

    Java 集合排序及java 集合类详解

    Java 集合排序及java 集合类详解 Java 集合排序及java 集合类详解,Java里面最重要、最常用也就是集合那部分了,能够用好集合和理解好集合对于做Java程序的开发拥有无比的好处。本教程详细解释了关于Java中的集合是...

    Java集合类图片

    Java集合类,在图片上体现出来,为了更好的描述,本来是博客里的,不好往博客里插,所以单独弄出来了。

    Java集合类矩阵图

    Java集合类矩阵图是Java编程中非常重要的一个概念,它主要涵盖了Java集合框架中的各种接口、类以及它们之间的关系。这个矩阵图可以帮助开发者更清晰地理解Java集合框架的层次结构和实现方式。在这个矩阵图中,你可以...

    java集合类精华大全

    Java集合类是Java编程中非常重要的一个部分,它为开发者提供了灵活的数据结构,用来存储和管理数据。在Java中,集合类主要分为三大类:Set、List和Map,它们都位于`java.util`包中。 Set接口表示无序且不允许重复...

    Java 集合类 简单Demo

    本示例主要探讨的是Java集合类的简单使用,通过一个名为`CollectionsTest.java`的文件进行演示。这篇博客文章可能详细解释了如何创建、操作和理解Java集合类的基本概念。 首先,Java集合框架主要包括接口和实现这些...

    java集合分类总结.doc

    Arrays和Collections是Java集合中的两个工具类。Arrays类包含用来操作数组的各种方法,如排序和搜索等。Collections类主要提供了在collection上进行操作的方法,如排序、查找等。 学习Java集合需要掌握以下几个方面...

    java 集合类讲解

    Java集合类是Java编程语言中一个非常重要的概念,它提供了数据结构和算法的实现,使得开发者可以方便地存储、管理和操作对象。Java集合框架包括多种接口(如List、Set、Queue)和实现这些接口的类(如ArrayList、...

    java集合类演示源码

    集合类的框架为集合的实现者提供了大量的接口和抽象类,并对其中的某些机制给予了描述,例如,Iterator(迭代协议)。实现Comparable接口或Comparator接口,用户可以根据需要对集合中的元素进行排序。为了方便用户...

Global site tag (gtag.js) - Google Analytics