Java~集合

Collection

    List
        ArrayList
        LinkedList
        Vector(已过时)
    Set
        HashSet
            LinkedHashSet
        TreeSet

Map

    HashMap
        LinkedHashMap
    TreeMap
    ConcurrentHashMap
    Hashtable(已过时)

Collection的常见方法:
(1)添加
    boolean add(E o);
    boolean add(Collection<? extends E> c);
(2)删除
    boolean remove(Object o);
    boolean removeAll(Collection<? extends E> c)
    void clear();
(3)判断  
    a.判断集合中是否有元素:boolean isEmpty();
    b.判断集合中是否包含某个元素:boolean contains(Object o);
    c.判断集合中是否包含某些元素:boolean contains(Collection<?> c);
    
 (4)获取
    a.获取集合中元素个数:int size();
    b.遍历集合中所有元素:Iterator<E> iterator();
    c.判断两个集合中是否存在相同的元素并保留两个集合中相同的元素删除不同的元素:boolean retainAll(Collection<?> c);
 (5)其他
    将集合中元素转为数组:a.    Ojbect[] toArray();
                  b.    <T>  T[] toArray();   泛型

List接口

List是有序的Collection。用户能够使用索引(元素在List中的位置,类似于数组下标)来访问List中的元素,这类似于Java的数组。除了具有Collection接口必备的iterator()方法外,List还提供一个listIterator()方法,返回一个 ListIterator接口,和标准Iterator接口相比,ListIterator多了一些add()之类的方法,允许添加,删除,设定元素, 还能向前或向后遍历。实现List接口的常用类有LinkedList,ArrayList,Vector和Stack。

LinkedList类

LinkedList实现了List接口,允许null元素。此外LinkedList提供额外的get,remove,insert方法在LinkedList的首部或尾部。这些操作使LinkedList可被用作堆栈(stack),队列(queue)或双向队列(deque)。注意LinkedList没有同步方法。如果多个线程同时访问一个List,则必须自己实现访问同步。一种解决方法是在创建List时构造一个同步的List:List list = Collections.synchronizedList(new LinkedList(...));

LinkedList 类中的常用方法 

//向链表末尾添加一个新节点,该节点中的数据是参数element指定的对象
public boolean add(Object element)

//向链表指定位置添加一个新节点,该节点中的数据是参数element指定的对象
public void add(int index,Object element)
 
//向链表表头添加一个新节点,该节点中的数据是参数element指定的对象
public void addFirist(Object element)
 
//向链表表尾添加一个新节点,该节点中的数据是参数element指定的对象
public void addLast(Object element)
 
//删除第一个节点并返回这个节点中的对象
public  Object removeFirst()

//删除最后一个节点并返回这个节点中的对象
public  Object removeLast()

//删除指定位置的节点
public Object remove(int index)

//得到指定位置的节点
public Object get(int index)

//得到链表第一个节点的对象
public Object getFirst()

//得到链表最后一个节点的对象
public Object getLast()

//返回节点对象element在链表中首次出现的位置,如果链表中无此节点的对象则返回-1
int indexOf(Object element) 

//返回节点对象element在链表中最后出现的位置,如果链表中无此节点的对象则返回-1
public int lastIndexOf(Object element)
 
//将当前链表index位置节点中的对象替换成参数element指定的对象,返回被替换对象
public Object set(int index,Object element)

//返回链表的长度即节点个数
public int size()

//判断链表节点对象中是否含有element
public boolean contains(Object element)

ArrayList类

和LinkedList一样,ArrayList也是非同步的(unsynchronized)。ArrayList实现了可变大小的数组。它允许所有元素,包括null。每个ArrayList实例都有一个容量(Capacity),即用于存储元素的数组的大小。这个容量可随着不断添加新元素而自动增加,但是增长算法 并没有定义。当需要插入大量元素时,在插入前可以调用ensureCapacity方法来增加ArrayList的容量以提高插入效率

ArrayList 的一些方法

//构造函数,创建一个空的列表, size为0
ArrayList()

//在list的末尾添加一个元素o
add(o: E): void

//在指定的index处插入元素o
add(index: int, o: E): void

//从list中删除所有元素
clear(): void

//如果list含有元素o,返回true
contains(o: Object): boolean

//返回指定index处的元素
get(index: int): E

//返回list中第一个匹配元素的index
indexOf(o: Object): int

//如果list不含元素,返回true
isEmpty(): boolean

//返回list中最后一个匹配元素的index
lastIndexOf(o: Object): int

//删除list中的第一个元素o,如果元素被删除,返回true
remove(o: Object): boolean

//返回list中元素个数
size(): int

//删除指定index处的元素,如果元素被删除,返回true
remove(index: int): boolean

//设置指定index处的元素为o
set(index: int, o: E): E

Vector类

Vector非常类似ArrayList,但是Vector是同步的。由Vector创建的Iterator,虽然和ArrayList创建的Iterator是同一接口,但是,因为Vector是同步的,当一个Iterator被创建而且正在被使用,另一个线程改变了 Vector的状态(例如,添加或删除了一些元素), 这时调用Iterator的方法时将抛出 ConcurrentModificationException,因此必须捕获该异常。

Stack类

Stack继承自Vector,实现一个后进先出的堆栈。Stack提供5个额外的方法使得Vector得以被当作堆栈使用。基本的push和pop方法, 还有peek方法得到栈顶的元素,empty方法测试堆栈是否为空,search方法检测一个元素在堆栈中的位置。Stack刚创建后是空栈。

Set接口

Set是一种不包含重复的元素的Collection,即任意的两个元素e1和e2都有e1.equals(e2)=false,Set最多有一个null元素。很明显,Set的构造函数有一个约束条件,传入的Collection参数不能包含重复的元素。请注意:必须小心操作可变对象(MutableObject)。如果一个Set中的可变元素改变了自身状态导致Object.equals(Object)=true将导致一些问题。

Map接口

请注意,Map没有继承Collection接口,Map提供key到value的映射。一个Map中不能包含相同的key,每个key只能映射一个value。Map接口提供3种集合的视图,Map的内容可以被当作一组key集合,一组value集合,或者一组key-value映射。

Hashtable类

Hashtable继承Map接口,实现一个key-value映射的哈希表。任何非空(non-null)的对象都可作为key或者value。添加数据使用put(key, value),取出数据使用get(key),这两个基本操作的时间开销为常数。Hashtable通过initial capacity和load factor两个参数调整性能。通常缺省的load factor 0.75较好地实现了时间和空间的均衡。增大load factor可以节省空间但相应的查找时间将增大,这会影响像get和put这样的操作。使用Hashtable的简单示例如下,将1,2,3放到Hashtable中,他们的key分别是”one”,”two”,”three”。

     Hashtable numbers = new Hashtable();
     numbers.put(“one”, new Integer(1));
     numbers.put(“two”, new Integer(2));
     numbers.put(“three”, new Integer(3));
要取出一个数,比如2,用相应的key:
    Integer n = (Integer)numbers.get(“two”);
    System.out.println(“two = ” + n);
由于作为key的对象将通过计算其散列函数来确定与之对应的value的位置,因此任何作为key的对象都必须实现hashCode和equals方 法。hashCode和equals方法继承自根类Object,如果你用自定义的类当作key的话,要相当小心,按照散列函数的定义,如果两个对象相同,即obj1.equals(obj2)=true,则它们的hashCode必须相同,但如果两个对象不同,则它们的hashCode不一定不同,如果两个不同对象的hashCode相同,这种现象称为冲突,冲突会导致操作哈希表的时间开销增大,所以尽量定义好的hashCode()方法,能加快哈希 表的操作。如果相同的对象有不同的hashCode,对哈希表的操作会出现意想不到的结果(期待的get方法返回null),要避免这种问题,只需要牢记一条:要同时复写equals方法和hashCode方法,而不要只写其中一个Hashtable是同步的。

HashMap类

当我们往hashmap中put元素的时候,先根据key的hash值得到这个元素在数组中的位置(即下标),然后就可以把这个元素放到对应的位置中了。如果这个元素所在的位子上已经存放有其他元素了,那么在同一个位子上的元素将以链表的形式存放,新加入的放在链头,最后加入的放在链尾。从hashmap中get元素时,首先计算key的hashcode,找到数组中对应位置的某一元素,然后通过key的equals方法在对应位置的链表中找到需要的元素。
hash算法

我们可以看到在hashmap中要找到某个元素,需要根据key的hash值来求得对应数组中的位置。如何计算这个位置就是hash算法。hashmap的数据结构是数组和链表的结合,所以我们当然希望这个hashmap里面的元素位置尽量的分布均匀些,
尽量使得每个位置上的元素数量只有一个,那么当我们用hash算法求得这个位置的时候,马上就可以知道对应位置的元素就是我们要的,而不用再去遍历链表。 HashMap和Hashtable类似,不同之处在于HashMap是非同步的,并且允许null,即null value和null key。但是将HashMap视为Collection时(values()方法可返回Collection),其迭代子操作时间开销和HashMap 的容量成比例。
因此,如果迭代操作的性能相当重要的话,不要将HashMap的初始化容量设得过高,或者load factor过低。

HashMap用法

 public static void main(String[] args) {
        HashMap<String, String> map = new HashMap<>();
        map.put("zhang", "31");//存放键值对
        System.out.println(map.containsKey("zhang"));//键中是否包含这个数据
        System.out.println(map.containsKey("daniu"));	
        System.out.println("=========================");
		
        System.out.println(map.get("zhang"));//通过键拿值
        System.out.println(map.get("daniu"));
        System.out.println("=========================");

        System.out.println(map.isEmpty());//判空
        System.out.println(map.size());
        System.out.println("=========================");

        System.out.println(map.remove("zhang"));//从键值中删除
        System.out.println(map.containsKey("zhang"));
        System.out.println(map.get("zhang"));//获取值
        System.out.println(map.isEmpty());
        System.out.println(map.size());
        System.out.println("=========================");

        map.put("zhang", "31");
        System.out.println(map.get("zhang"));
        map.put("zhang", "32");
        System.out.println(map.get("zhang"));
        System.out.println("=========================");

        map.put("zhang", "31");
        map.put("cheng", "32");
        map.put("yun", "33");

        for (String key : map.keySet()) {
            System.out.println(key);
        }
        System.out.println("=========================");

        for (String values : map.values()) {
            System.out.println(values);
        }
        System.out.println("=========================");

        map.clear();
        map.put("A", "1");
        map.put("B", "2");
        map.put("C", "3");
        map.put("D", "1");
        map.put("E", "2");
        map.put("F", "3");
        for (Entry<String, String> entry : map.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            System.out.println(key + "," + value);
        }
        System.out.println("=========================");
        List<String> removeKeys = new ArrayList<String>();
        for (Entry<String, String> entry : map.entrySet()) {
            if (!entry.getValue().equals("1")) {
                removeKeys.add(entry.getKey());
            }
        }
        for (String removeKey : removeKeys) {
            map.remove(removeKey);
        }
        for (Entry<String, String> entry : map.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            System.out.println(key + "," + value);
        }
        System.out.println("=========================");
}

ArrayList和Vector的区别

Vector和ArrayList
1,vector是线程同步的,所以它也是线程安全的,而arraylist是线程异步的,是不安全的。如果不考虑到线程的安全因素,一般用arraylist效率比较高。
2,如果集合中的元素的数目大于目前集合数组的长度时,vector增长率为目前数组长度的100%,而arraylist增长率为目前数组长度的50%.如过在集合中使用数据量比较大的数据,用vector有一定的优势。
3,如果查找一个指定位置的数据,vector和arraylist使用的时间是相同的,都是0(1),这个时候使用vector和arraylist都可以。而
如果移动一个指定位置的数据花费的时间为0(n-i)n为总长度,这个时候就应该考虑到使用linklist,因为它移动一个指定位置的数据
所花费的时间为0(1),而查询一个指定位置的数据时花费的时间为0(i)。ArrayList 和Vector是采用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,都允许直接序号索引元素,但是插入数据要设计到数组元素移动 等内存操作,所以索引数据快插入数据慢,Vector由于使用了synchronized方法(线程安全)所以性能上比ArrayList要差,LinkedList使用双向链表实现存储,按序号索引数据需要进行向前或向后遍历,但是插入数据时只需要记录本项的前后项即可,所以插入数度较快!

ArrayList和LinkList

1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。这一点要看实际情况的。若只对单条数据插入或删除,ArrayList的速度反而优于LinkedList。但若是批量随机的插入删除数 据,LinkedList的速度大大优于ArrayList. 因为ArrayList每插入一条数据,要移动插入点及之后的所有数据。

HashMap和Hashtable的区别

从存储结构和实现来讲基本上都是相同的,都是实现Map接口
HashMap允许为null
Hashtable不允许为null
HashMap是非同步的
Hashtable是同步的

List和Map的区别

List是存储单列的集合
Map存储的是key-value键值对的集合
List允许元素重复
Map不允许key重复
List集合是有序的(存储有序)
Map集合是无序的(存储无序)

 

Enumeration和Iterator接口的区别

与Enumeration相比,Iterator更加安全,因为当一个集合正在被遍历的时候,它会阻止其它线程去修改集合。

猜你喜欢

转载自blog.csdn.net/weixin_42679286/article/details/86766621