javaSE(4)——集合框架

前言

泛型+反射+注释+XML = 框架

区别数组,但是长度可变;

在这里插入图片描述

在这里插入图片描述
ArrayList: 遍历,查找 快
LinkedList: 插入,删除 快
TreeMap: 有序的进,有序的出

接口类型数据内容顺序
List接口可重复有序
Set接口不可重复无序
Map接口键值对无序

Collection和Collections

java.util
在集合框架中,分为两种API :
1、装载数据的集合类
2、操作集合的工具类

集合Collection
集合( Collection )接口位于Set接口和List接口的最顶层,是Set接口和List接口的父接口。定义了Collection对象共有的一些基本方法,这些方法分为基本操作、批量操作和数组操作。Iterator接口是一 种用于遍历集合的接口。所谓遍历,是指从集合中取出每一个元素的过程。
E - 此集合中元素的类型

方法:

  • boolean add(E e) 确保此集合包含指定的元素(可选操作)。
  • boolean addAll(Collection<? extends E> c) 将指定集合中的所有元素添加到此集合(可选操作)。
  • void clear() 从此集合中删除所有元素(可选操作)。
  • boolean contains(Object o) 如果此集合包含指定的元素,则返回 true 。 ——containsAll(Collection<?> c)
  • boolean equals(Object o) 将指定的对象与此集合进行比较以获得相等性。
  • boolean isEmpty() 如果此集合不包含元素,则返回 true 。
  • Iterator iterator() 返回此集合中的元素的迭代器。
  • boolean remove(Object o) 从该集合中删除指定元素的单个实例(如果存在)(可选操作)。
  • boolean removeAll(Collection<?> c) 删除指定集合中包含的所有此集合的元素(可选操作)。
  • int size() 返回此集合中的元素数。
  • Object[] toArray() 返回一个包含此集合中所有元素的数组。

Collections 集合工具类(包含方法均为static)
(参考API)
方法:sort(), reverse(), shuffle()

public class TestTool {

	public static void main(String[] args) {
		List<Integer> list = new ArrayList();
		list = new LinkedList<>(list);
		list.add(11);
		list.add(1);
		list.add(111);
		list.add(2);
		//排序
		Collections.sort(list);
		for (Integer integer : list) {
			System.out.println(integer);
		}//1  2  11   111
		System.out.println("-----------------");
		Collections.reverse(list);
		for (Integer integer : list) {
			System.out.println(integer);
		}//111  11  2  1
		System.out.println("-----------------");
		Collections.shuffle(list);//乱序
		for (Integer integer : list) {
			System.out.println(integer);
		} //11  1  2  111
		System.out.println("-----------------");
		Object[] arry = list.toArray();
		//排序
		Arrays.sort(arry);
		for (Object integer : arry) {
			System.out.println(integer);
		}  // 1  2  11  111
	}
}

Arrays数组工具类
(参考API)
static void sort(byte[] a) :按照数字顺序排列指定的数组。

1 List

List接口实现类的选择:
●ArrayList : 使用最广泛,集合元素增加或删除操作不频繁时使用,最适合查询。
●LinkedList : 当需要在集合的中间位置,频繁增加或删除元素时使用。
●Vector : 与ArrayList类似,但Vector是线程安全的,所以性能要低于ArrayList。
●LinkedList > ArrayList > Vector

List接口是继承Collection接口,所以Collection集合中有的方法,List集合也继承过来;此接口的用户可以对列表中每个元素的插入位置进行精确地控制;列表通常有序(存储和取出的元素一致),允许重复的元素;
方法:

  1. void add(int index, E element):
    在指定位置插入元素,后面的元素都往后移一个元素;
  2. boolean addAll(int index, Collection<? extends E> c):
    当插入的集合c没有元素,那么就返回false,如果集合c有元素,插入成功,那么就返回true;
  3. E get(int index):返回list集合中指定索引位置的元素;
  4. int indexOf(Object o):
    返回list集合中第一次出现o对象的索引位置,如果list集合中没有o对象,那么就返回-1;
  5. ListIterator listIterator():
    返回此列表元素的列表迭代器(按适当顺序);
  6. ListIterator listIterator(int index):
    从指定位置开始,返回此列表元素的列表迭代器(按适当顺序);
  7. E remove(int index):
    删除指定索引的对象;
  8. E set(int index, E element):
    在索引为index位置的元素更改为element元素
  9. List subList(int fromIndex, int toIndex):
    返回从索引fromIndex到toIndex的元素集合,包左不包右。
List list = new ArrayList();
list.add("demo1");
list.add("demo2");
list.add("demo3");
// 遍历:
Iterator i = list.iterator();
while(i.hasNext()) {
	String s = (String) i.next();
	System.out.println(s);
}

1.1 ArrayList

  • ArrayList实现了可变大小的数组。
  • 它允许所有元素,包括null。
  • 和LinkedList一样,ArrayList也是非同步的(unsynchronized)(异步)。线程不安全
  • size,isEmpty,get,set方法运行时间为常数。但是add方法开销为分摊的常数,添加n个元素需要O(n)的时间。其他的方法运行时间为线性。
  • 每个ArrayList实例都有一个容量(Capacity),即用于存储元素的数组的大小。这个容量可随着不断添加新元素而自动增加,但是增长算法并没有定义。当需要插入大量元素时,在插入前可以调用ensureCapacity方法来增加ArrayList的容量以提高插入效率。
  • 支持随机访问。当从 ArrayList 的中间位置插入或者删除元素时,需要对数组进行复制、移动、代价比较高。因此,它适合随机查找和遍历,不适合插入和删除。
1.1.1 构造函数

public ArrayList()
public ArrayList(int initialCapacity)
public ArrayList(Collection<? extends E> c):按照集合的迭代器返回的顺序构造一个包含指定集合元素的列表。如果集合长度为0则为{}

/**
* Constructs an empty list with an initial capacity of ten.
* 构造一个空的集合初始容量是10
*/
public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }


public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }
1.1.2 常用方法

add()
扩容grow()
public E remove(int index)
get (因为底层使用数组来实现,所以 底层直接通过[index]的方式获取和设置值)
set()
equals()
public ListIterator listIterator(int index)
E get(int index)
List subList(int fromIndex, int toIndex)

1.1.3 总结
  1. 底层数组
  2. 有序,可重复
  3. 速度快,增删慢(数组的移位)
  4. 线程不安全
  5. 容量不够时,扩容后的容量 = 当前容量*1.5+1;
import java.util.ArrayList;
import java.util.Iterator;
import day3.exciting.Person;
public class TestArrayList {

	public static void main(String[] args) {
		ArrayList list = new  ArrayList();
		System.out.println(list.size()); // 0
		list.add(2);
		list.add(false);
		list.add(1);
		list.add("abc");
		list.add(new Object());
		list.add(true);
		list.add(true);
		Integer j = 1;
		list.remove(j); // 基本数据类型的话,就是下标
		list.set(1, new Person());
		for(int i=0;i<list.size();i++){
			System.out.println(list.get(i));
		}
		/*
		 *  2
			day3.exciting.Person@15db9742
			abc
			java.lang.Object@6d06d69c
			true
			true
		 */
		System.out.println("--------------------------");
//		list.clear();
		System.out.println(list.get(2)); // abc
		//foreach
		for (Object object : list) {
			System.out.println(object);
		}
		System.out.println("--------------------------");
		//迭代   先获得迭代器
		Iterator it = list.iterator();
		while(it.hasNext()){//有没有下一个元素
			System.out.println(it.next());//下一个元素
		}
		System.out.println("------------不打印的原因  迭代结束--------------");
		while(it.hasNext()){//有没有下一个元素
			System.out.println(it.next());//下一个元素
		}
	}
}

1.2 LinkedList

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

public static void main(String[] args) {
		// 表头和表位进行扩展  大的数据量排序  LinkedList  
		LinkedList list = new LinkedList();
		list.add("1");//  linkLast(e);
		list.addFirst("2");// linkFirst(e);
		list.addLast("3");//  linkLast(e);
		list.offerFirst("4") ;//addFirst
		list.offerLast("5");
		list.add(2, true);
		//void add(int index, E element) 
		//在此列表中的指定位置插入指定的元素
	}

1.3 Vector

可实现自动增长的对象数组。

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

1.3.1 构造方法
  • public vector() :构造一个空向量,使其内部数据数组的大小为 10 ,标准容量增量为零(自动对向量进行管理)
  • public vector(int initialcapacity):构造具有指定初始容量并且其容量增量等于零的空向量
  • public vector(int initialcapacity,int capacityIncrement) :构造具有指定的初始容量和容量增量的空向量
1.3.2 方法

(参考API)
常用:

  • boolean add(E e)
    将指定的元素追加到此Vector的末尾
  • void add(int index, E element)
    在此Vector中的指定位置插入指定的元素
  • void addElement(E obj)
    将指定的组件添加到此向量的末尾,将其大小增加1。
  • boolean addAll(int index, Collection<? extends E> c)
    将指定集合中的所有元素插入到此向量中的指定位置
  • int capacity()返回此向量的当前容量; int size()向量中的组件数
  • boolean contains(Object obj)
    向量包含指定元素返回true
  • E get(int index)
    返回此向量中指定位置的元素
  • int indexOf(Object o, int index)
    返回此向量中指定元素的第一次出现的索引,从 index向前 index ,如果未找到该元素,则返回-1
  • E remove(int index)
    删除此向量中指定位置的元素
  • public final int indexOf(Object obj)
    从向量头开始搜索obj,返回所遇到的第一个obj对应的下标,若不存在此obj,返回-1

1.4 ArrayList和LinkedList以及Vector的区别

注意点:

  1. 如果是jdk6的话,采用Array.of()方法来生成一个新的数组,如果是jdk5.0的话,使用的是 System.arraycopy方法(将数组拷贝)
  2. List list = new ArrayList();时,底层会生成一个长度为10的数组来存放对象,如果预先知道list 会存放多少个对象的话,最好通过new ArrayList(int length)的方式先确定数组的最小长度,如new ArrayList(50),这样能提高底层的效率。
  3. 对于ArrayList与Vector来说,底层都是采用数组方式来实现的(该数组是一个Object类型的数组)。此数组元素数大于实际存储的数据以便增加和插入元素,都允许直接序号索引元素,但是插入数据要设计到数组元素移动等内存操作,所以索引数据快插入数据慢,Vector由于使用了synchronized方法(线程安全)所以性能上比ArrayList要差。
  4. 对于ArrayList,所有方法都不是同步的,对于Vector,大部分是public的方法都是同步的。
  5. LinkedList底层是由双向循环链表实现的,按序号索引数据需要进行向前或向后遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。LinkedList查找速度非常慢,增加和删除操作非常快(本质上是由双向循环链表的特点来决定的)。
  6. 对于ArrayList,查找速度非常快,增加和删除操作非常慢。(本质上是由数组的特点来决定的)

1.存储结构
ArrayList和Vector是按照顺序将元素存储(从下标为0开始),删除元素时,删除操作完成后,需要使部分元素移位,默认的初始容量都是10.

ArrayList和Vector是基于数组实现的,LinkedList是基于双向链表实现的(含有头结点)。

2.线程安全性
ArrayList不具有有线程安全性,在单线程的环境中,LinkedList也是线程不安全的,如果在并发环境下使用它们,可以用Collections类中的静态方法synchronizedList()对ArrayList和LinkedList进行调用即可。

Vector实现线程安全的,即它大部分的方法都包含关键字synchronized,但是Vector的效率没有ArraykList和LinkedList高。

3.扩容机制
从内部实现机制来讲,ArrayList和Vector都是使用Object的数组形式来存储的,当向这两种类型中增加元素的时候,若容量不够,需要进行扩容。ArrayList扩容后的容量是之前的1.5倍,然后把之前的数据拷贝到新建的数组中去。而Vector默认情况下扩容后的容量是之前的2倍。

Vector可以设置容量增量,而ArrayList不可以。在Vector中,有capacityIncrement:当大小大于其容量时,容量自动增加的量。如果在创建Vector时,指定了capacityIncrement的大小,则Vector中动态数组容量需要增加时,如果容量的增量大于0,则增加的是大小是capacityIncrement,如果增量小于0,则增大为之前的2倍。

在这里需要说一下可变长度数组的原理:当元素个数超过数组的长度时,会产生一个新的数组,将原数组的数据复制到新数组,再将新的元素添加到新数组中。

4.增删改查的效率
ArrayList和Vector中,从指定的位置检索一个对象,或在集合的末尾插入、删除一个元素的时间是一样的,时间复杂度都是O(1)。但是如果在其他位置增加或者删除元素花费的时间是O(n),LinkedList中,在插入、删除任何位置的元素所花费的时间都是一样的,时间复杂度都为O(1),但是他在检索一个元素的时间复杂度为O(n).

所以如果只是查找特定位置的元素或只在集合的末端增加移动元素,那么使用ArrayList或Vector都是一样的。如果是在指定位置的插入、删除元素,最好选择LinkedList

区别的原文链接:https://blog.csdn.net/kuangsonghan/article/details/79861170

2 Set

Set接口继承了Collection接口。Set集合不包含重复的元素(元素加入set中,重复的元素会自动移除),每个元素必须是唯一,这是使用Set的主要原因。
有三种常见的Set实现——HashSet, TreeSet和LinkedHashSet。如果你需要一个访问快速的Set,你应该使用HashSet;当你需要一个排序的Set,你应该使用TreeSet;当你需要记录下插入时的顺序时,你应该使用LinedHashSet。

1.1 HashSet

HashSet实现了Set接口,不重复无序,可以有一个null元素;
将对象存储在HashSet之前,要确保重写hashCode()方法和equals()方法,这样才能比较对象的值是否相等,确保集合中没有储存相同的对象。如果不重写上述两个方法,那么将使用下面方法默认实现:
public boolean add(Object obj)方法用在Set添加元素时,如果元素值重复时返回 “false”,如果添加成功则返回"true"

boolean add() 判定标准:hashCode值相同 和equals时true :

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
public class TestSet {
	public static void main(String[] args) {
		HashSet set = new HashSet();
		//判断 对象是否相同  hashCode 和equals
		set.add(new  Student("韩梅梅"));
		set.add(new  Student("李磊"));
		set.add("b");
		set.add(1);
		set.add(2);
		set.add(2);
		set.add(new  Student("韩梅梅"));
		System.out.println(set.size()); // 6
		//两种
		for (Object object : set) {
			System.out.println(object);
		}
		/**
		 * Student [name=韩梅梅, className=null, score=0]
			1
			b
			2
			Student [name=韩梅梅, className=null, score=0]
			Student [name=李磊, className=null, score=0]
		 */
	   
	   Iterator iterator = set.iterator();  //迭代
	   List list = new ArrayList();
	   list.add(1);
	   list.add(true);
	   list.add("abc");
	 //  set.addAll(list);//把集合里面元素一个一个放置集合中 //8
	   set.add(list);//把集合作为一个元素放入集合中
	   System.out.println(set.size()); // 7
       while (iterator.hasNext()) {
    		System.out.print(iterator.next() + " ");
		} // 输出顺序不确定
	}
}

1.2 TreeSet

底层的数据结构是红黑树(一种自平衡二叉查找树)
有序,无重复集合。不可以有Null元素,根据元素的自然顺序进行排序。
作用:提供有序Set集合,因此支持add(),remove(),get()
继承AbstractSet抽象类,可以被实例化;一种基于TreeMap的NavigableSet实现。
TreeSet中的元素支持2种排序方式:自然排序 或者 根据创建TreeSet 时提供的 Comparator 进行排序。这取决于使用的构造方法。
TreeSet的性能比HashSet差,但是在需要排序的时候可以用TreeSet,因为他是自然排序,也就是升序。
不支持快速随即遍历,只能通过迭代器进行遍历。

1.3 LinkedHashSet

底层数据结构由哈希表和链表组成。
LinkedHashSet介于HashSet和TreeSet之间。它也是一个hash表,但是同时维护了一个双链表来记录插入的顺序。

1.4 .HashSet和TreeSet以及LinkedHashSet区别

HashSet是采用hash表来实现的。
TreeSet是采用树结构实现(红黑树算法)。
LinkedHashSet介于HashSet和TreeSet之间。它也是一个hash表,但是同时维护了一个双链表来记录插入的顺序。

无排序要求可以选用HashSet;如果想取出元素的顺序和放入元素的顺序相同,那么可以选用LinkedHashSet。如果想插入、删除立即排序或者按照一定规则排序可以选用TreeSet。

HashSetTreeSetLinkedHashSet
不重复(可以有一个null元素),无序不重复(不可以有null元素),有序不重复(可以有一个null元素),无序
确保唯一性:hashCode(),equals()底层的数据结构是红黑树(一种自平衡二叉查找树)链表保证了元素的有序即存储和取出一致,哈希表保证了元素的唯一性
add()、remove()以及contains()等方法都是复杂度为O(1)的方法添加、删除操作时间复杂度O(log(n));还提供了一些方法来处理排序的set,如first(), last(), headSet(), tailSet()添加、删除操作时间复杂度O(1)
非线程安全非线程安全非线程安全

HashSet和TreeSet区别,参考一下别人的:
https://www.cnblogs.com/williamjie/p/9099038.html

3 Map

将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。

Map接口有两个基本的实现TreeMap和HashMap。

interface Map<K,V>
K - 此映射所维护的键的类型
V - 映射值的类型

1.map存储键值对,每个键(key)都有一个对应的值(value)。键不可以重复(唯一性),值可以重复。
2.Map和Collection在集合框架中属并列存在,Map存储元素使用put方法,Collection使用add方法;
3.Map一次存一对元素, Collection 一次存一个,也就是Collection是单列集合, Map 是双列集合;
4.Map集合没有直接取出元素的方法,而是先转成Set集合,在通过迭代获取元素

遍历Map方式:
第一种方式: 使用keySet:
将Map转成Set集合(keySet()),通过Set的迭代器取出Set集合中的每一个元素(Iterator)就是Map集合中的所有的键,再通过get方法获取键对应的值。
第二种方式: 通过values 获取所有值,不能获取到key对象(Collection coll = map.values(); )
第三种方式: Map.Entry
public static interface Map.Entry<K,V>
通过Map中的entrySet()方法获取存放Map.Entry<K,V>对象的Set集合。
Set<Map.Entry<K,V>> entrySet()
面向对象的思想将map集合中的键和值映射关系打包为一个对象,就是Map.Entry,将该对象存入Set集合,Map.Entry是一个对象,那么该对象具备的getKey,getValue获得键和值。

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class TestMap {
	public static void main(String[] args) {
		//创建集合对象
		Map<String,Integer> map = new HashMap();
		map.put("A", 1);
		map.put("B", 1);
		map.put("C", 11);
		map.put("A", 12); // 覆盖
		//循环出键值对
		for(Object obj : map.entrySet()){ //Set key = value
			System.out.println(obj);
		}
/*
A=12
B=1
C=11
*/
		//获得所有的键
		System.out.println("--------------------");
		Set<String> keys = map.keySet();
		for (String key : keys) {
			System.out.println(key + ":" + map.get(key));// 用键获得值
		}
		//返回所有 
		Collection coll = map.values();
		map.remove("A") ;//移除的是键值对
		System.out.println(coll); // 获取值 [1, 11]
		System.out.println(map);  // {B=1, C=11}
	}
}

3.1 HashMap

底层是哈希表数据结构,所以无序,线程是不同步的,要保证键的唯一性,需要覆盖hashCode方法,和equals方法。
HashMap实现了Map接口,Map接口对键值对进行映射。Map中不允许出现重复的键(Key)。TreeMap保存了对象的排列次序,而HashMap不能。HashMap可以有空的键值对(Key(null)-Value(null))

HashMap是非线程安全的(非Synchronize),要想实现线程安全,那么需要调用collections类的静态方法synchronizeMap()实现。
常用方法:
public Object put(Object Key,Object value)方法用来将元素添加到map中。
contains(),get()

import java.util.HashMap;
import java.util.Map;

public class Test {
	public static Map<Integer, Integer> countArrNum(Object[] obj) {
		Map<Integer, Integer> map = new HashMap();
		// 循环元素
		for(Object key : obj) {
			// 判断这个元素在Map的key中是否存在
			if(!map.containsKey(key)) {
				map.put((Integer) key, 1); // 第一次出现
			} else {
				// 总次数 = 原来的次数+1   :  map.get(key) + 1
				map.put((Integer) key, map.get(key) + 1);
			}
		}
		return map;
	}
	public static void main(String[] args) {
		Integer[] arr = {1,2,3,4,1,2,4,3,4,5};
		Map<Integer, Integer> map = countArrNum(arr);
		System.out.println(map);
		for (Integer key : map.keySet()) {
			System.out.println(key + "出现次数:" + map.get(key));
		}
	}
}
/*
{1=2, 2=2, 3=2, 4=3, 5=1}
1出现次数:2
2出现次数:2
3出现次数:2
4出现次数:3
5出现次数:1
*/

3.2 HashMap,TreeMap,HashTable的区别

HashMapTreeMapHashTableLinkedHashMapConcurrentHashMap
底层是哈希表数据结构底层是二叉树数据结构底层是哈希表数据结构该子类基于哈希表又融入了链表
线程不同步,线程不安全线程不同步线程同步,线程安全线程安全(在多线程和并发环境中,通常作为Map的主要实现)
可以存入null键,null值不可以存入null键,null值
可以对map集合中的键进行排序效率较低,被HashMap 替代可以Map集合进行增删提高效率通过把整个Map分为N个Segment(类似HashTable),可以提供相同的线程安全,但是效率提升N倍,默认提升16倍
保证键的唯一性,需要覆盖hashCode方法,和equals方法使用Comparable或者Comparator 进行比较排序。return 0,来判断键的唯一性
初始size为16,扩容:newsize = oldsize*2,size一定为2的n次幂初始size为11,扩容:newsize = olesize*2+1

面试问答题,HashMap、Hashtable、ConcurrentHashMap的原理与区别,参考一下别人的:
https://www.cnblogs.com/heyonggang/p/9112731.html

常见方法:

  1. 添加:
  • V put(K key, V value) (可以相同的key值,但是添加的value值会覆
    盖前面的,返回值是前一个,如果没有就返回null)
  • putAll(Map<? extends K,? extends V> m) 从指定映射中将所有映射关
    系复制到此映射中(可选操作)。
  1. 删除
  • remove() 删除关联对象,指定key对象
  • clear() 清空集合对象
  1. 获取
  • value get(key); 可以用于判断键是否存在的情况。当指定的键不存在的时候,返回的是null。
  1. 判断:
  • boolean isEmpty() 长度为0返回true否则false
  • boolean containsKey(Object key) 判断集合中是否包含指定的key
  • boolean containsValue(Object value) 判断集合中是否包含指定的value
  1. 长度:int size()

4 其他

4.1 了解泛型

泛型:广泛的引用数据类型,出现于1.5
当不知道想采用的数据类型可以定义为泛型,泛型默认为Object
类<>
方法:传入数据的时候确定数据的类型
在集合中——定义泛型:定义集合的数据类型

public class TestAll<T,W> {//泛型 + 反射 + 注解 + XML + 设计模式 = 框架 JDBC
	T other;
	// 当不知道返回的类型 具体是什么的时候可以定义为泛型
	public<K> K update(K k){
		System.out.println("k--修改");
		if(k instanceof String){
			return	 (K) ((String) k).concat("abc");//final
		}
		if(k instanceof Student){
			((Student) k).setName("真好");
		}
		return  k;
	}
	public static void main(String[] args) {
		TestAll<String,Object>  ta=new TestAll<>();
		ta.other="abc";
		System.out.println(ta.update("你好"));
		System.out.println(ta.update(new Student("韩梅梅","201",99)));
		//TestAll<Student> ta2 = new TestAll<>();
		//ta2.other=new Student();
/*
k--修改
你好abc
k--修改
Student [name=真好, className=201, score=99]
*/
	}
}

4.2 List和Set区别

Collection是最基本的集合接口,声明了适用于JAVA集合的通用方法,list和set都继承自collection接口。Java中的集合包括三大类,它们是Set(集)、List(列表)和Map(映射),它们都处于java.util包中,Set、List和Map都是接口,它们有各自的实现类。Set的实现类主要有HashSet、LinkedHashSet和TreeSet,List的实现类主要有ArrayList、LinkedList和Vector。
区别:
1、List,Set都是继承自Collection接口
2、List特点:元素有放入顺序(输出顺序为插入顺序),元素可重复,可以插入多个null元素 ,
Set特点:元素无放入顺序,元素不可重复,重复元素会覆盖掉,只允许一个null元素
(元素虽然无放入顺序,但是元素在set中的位置是有该元素的HashCode决定的,其位置其实是固定的,加入Set 的Object必须定义equals()方法 ,另外list支持for循环,也就是通过下标来遍历,也可以用迭代器,但是set只能用迭代,因为他无序,无法用下标来取得想要的值。)
3、Set和List对比:
Set:检索元素效率低下,删除和插入效率高,插入和删除不会引起元素位置改变。
List:和数组类似,List可以动态增长,查找元素效率高,插入删除元素效率低,因为会引起其他元素位置改变。

4.3 HashSet和HashMap的区别

HashMapHashSet
实现了Map接口实现了Set接口
存储键值对仅存储对象
调用put() 向map中添加元素调用add()向set中添加元素
HashMap使用键(key)计算HashcodeHashSet使用成员对象来计算Hashcode值,对于两个对象来说hashcode可能相同,所以equals()方法用来判断对象的相等性,如果两个对象不同的话,那么返回false
HashMap相对于HashSet较快,因为它是使用唯一的键获取对象HashSet较HashMap来说比较慢

4.4 HashMap与ConcurrentHashMap的区别

上面所说他们之间的第一个重要的区别就是ConcurrentHashMap是线程安全的和在并发环境下不需要加额外的同步。虽然它不像Hashtable那样需要同样的同步等级(全表锁),但也有很多实际的用途。

  1. 可以使用Collections.synchronizedMap(HashMap)来包装HashMap作为同步容器,这时它的作用几乎与Hashtable一样,当每次对Map做修改操作的时候都会锁住这个Map对象,ConcurrentHashMap会基于并发的等级来划分整个Map来达到线程安全,它只会锁操作的那一段数据而不是整个Map都上锁。
  2. ConcurrentHashMap有很好的扩展性,在多线程环境下性能方面比做了同步的HashMap要好,但是在单线程环境下,HashMap会比ConcurrentHashMap好一点。
    以上两者的区别,在于线程安全、扩展性、同步之间的区别。如果是用于缓存的话,ConcurrentHashMap是一个更好的选择,在Java应用中会经常用到,并且在读操作线程数多于写操作线程数的情况下更胜一筹。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值