/**
* 一,集合框架的概述:
* 1,集合数组都是对多个数据进行存储,简称java容器
* 说明:此时的存储是作用与内存层面上的,不涉及持久化的存储(txt,jpg,avi,数据库,硬盘等等)
* 2.1,数组在存储多个数据的特点:
* >初始化时,数组长度需要确定
* >数组一旦定义好,其元素就确定了,我们只能操作已经确定了的元素数据
* 2.2,数组在存储多个数据的缺点:
* >一旦初始化后就确定了长度,不可修改
* >数组中提供的方法非常有限,对于添加,删除,插入数据等操作,非常的不便。并且效率不高
* >获取数组中实际元素的个数的需求,数组没有现成的属性或方法
* >数组存储数据的特点:有序,可重复,对于无序,不可重复的需求,不能满足
* 二,集合框架
* -- collection接口:单列集合,用来存储一个个的对象
* ---List接口:存储有序的,可重复的数据 ---》"动态"对象
* ----ArrayList,LinkedList,vector
* ---Set接口:存储无序的,不可重复的数据 ---》数学中的集合
* ----HashSet,LinkedHashSet,TreeSet
* -- Map接口:双列集合,用来存储一对(key---value)一对的数据
* ----HashTable,HashMap,TreeMap,LinkedHashMap,Properties
*
* @author rieson
* @create 2021-01-10-11:34
*/
public class CollectionTest {
@Test
public void test1() {
Collection con = new ArrayList<>();
//add(Object e):将元素e添加到集合con中
con.add(1);
con.add("asd");
con.add(new Date());
//size():获取添加的元素的个数
System.out.println(con.size());
//addAll():将con1中的元素全部添加到当前几何中
Collection con1 = new ArrayList<>();
con1.add(1);
con1.add(2);
con.addAll(con1);
System.out.println(con.size());
//clear():清空集合中的元素
//con.clear();
//isEmpty():判断当前集合是否为空
System.out.println(con.isEmpty());
//contains(Object o):判断当前集合中是否包含o
//我们在判断时,会调用o中对象所在类的equals()方法
//向Collection接口实现类的对象中添加o时,要求o所在的类要重写equals()方法
boolean asd = con.contains("asd");
System.out.println(asd);
System.out.println(con.contains(new Date()));
//containsAll:判断集合con1中当前集合中是否全部包含,全部包含返回true,反而为false
con.containsAll(con1);
}
@Test
public void test2() {
Collection con = new ArrayList<>();
//add(Object e):将元素e添加到集合con中
con.add(1);
con.add("asd");
con.add(new Date());
con.add(false);
//remove(Object o):删除集合中对应的元素
con.remove(1);
//removeAll(Collection con1):删除con与con1中的相同的数据
Collection con1 = new ArrayList<>();
con1.add(1);
con1.add(true);
con.removeAll(con1);
System.out.println(con1);
System.out.println(con);
}
@Test
public void test3() {
Collection con = new ArrayList<>();
con.add(1);
con.add("asd");
con.add(new Date());
con.add(false);
//retainAll(Collection con1):获取当前集合与con集合的交集,并返回给当前集合
// Collection con1 = Arrays.asList(1,1234);
// con.retainAll(con1);
// System.out.println(con);
Collection con1 = new ArrayList<>();
con1.add(1);
con1.add("asd");
con1.add(new Date());
con1.add(false);
//equals(Object o):比较两个集合里面的元素是否相等
System.out.println(con.equals(con1));
}
@Test
public void test4(){
Collection con = new ArrayList<>();
con.add(1);
con.add("asd");
con.add(new Date());
con.add(false);
//hashCode():返回当前对象的hash值
System.out.println(con.hashCode());
//toArray():集合转换成数组
Object[] objects = con.toArray();
for (int i = 0; i < objects.length; i++) {
System.out.println(objects[i]);
}
//数组转换成集合
List<String> strings = Arrays.asList(new String[]{"aa", "bb", "CC"});
System.out.println(strings);
//iterator():返回Iterator接口的实例,用于遍历集合元素,放在IteratorTest.java中测试
}
}
/**
* 一,集合框架
* -- collection接口:单列集合,用来存储一个个的对象
* ---List接口:存储有序的,可重复的数据 ---》"动态"对象
* ---ArrayList:作为List的主要实现类,线程是不安全的,效率高;底层使用的是Object[]存储
* ---LinkedList:对于频繁的插入,删除操作时,使用此效率要比Arraylist高;底层使用双向链表存储,
* ---vector:作为List的古老实现类,线程是安全的,效率相对低;底层使用的是Object[]存储
*
* 2,ArrayList的源码分析:
* 2.1 jdk1.7情况下
* ArrayList list = new ArrayList();底层创建了长度是10的object[]数组elementData
* list.add(123);elementData[0] = new Integer(123);
* ....
* list(123456);如果此次的添加导致底层elementData数组容量不足,则扩容。
* 默认情况下,扩容为原容量的1.5倍,同时需要将原数组中的数据复制到新的数组中。
* 结论:建议开发中使用带参数的构造器:ArrayList list = new ArrayList(int capacity)
* 2.2 jdk1.8中的变化:
* ArrayList list = new ArrayList();底层Object[] elementData初始化为{},并没有创建长度为10的数组
* list.add(123);第一次调用add()方法时,底层才创建了长度为10的数组,并将数据123,添加到elementData数组中
* 后续的添加跟扩容跟1.7无异
* 2.3 小结:jdk7中的ArrayList的对象的创建类似于单例模式的饿汉式,
* 而jdk8时使用的是饿汉式,延迟了创建数组,节省内存
*
* 3,LinkedList源码分析:
* LinkedList list = new LinkedList();内部声明了Node类型的first和last属性,默认值为null
* list.add(123);将123封装带Node中,创建了Node对象。
* 其中,Node定义为:体现了LinkedList 的双向链表说法
*
*
*
*
*
*
*
* @author rieson
* @create 2021-01-10-17:41
*/
public class ListTest {
// 4,List接口中的常用方法
@Test
public void test3(){
ArrayList list = new ArrayList();
list.add(123);
list.add(465);
list.add("asd");
Iterator iterator = list.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
for( Object o : list){
System.out.println(o);
}
}
@Test
public void test2() {
ArrayList list = new ArrayList();
list.add(123);
list.add(465);
list.add("asd");
list.add(new String("hello"));
list.add(123);
System.out.println(list);
//int indexOf(Object obj):返回obj首次出现的位置
System.out.println(list.indexOf(123));
//int lastIndexOf(Object obj):返回obj首次出现的位置
System.out.println(list.lastIndexOf(123));
// Object remove(int index):移除指定index位置的元素,并返回此元素
System.out.println(list.remove(2));
//Object set(int index,object obj ):修改指定index位置的元素为obj
System.out.println(list.set(1,"asd"));
//List subList(int fromIndex,int toIndex):返回fromIndex到toIndex位置的左臂右开区间的值
List list1 = list.subList(2, 4);
System.out.println(list1);
}
@Test
public void test1(){
ArrayList list = new ArrayList();
list.add(123);
list.add(465);
list.add("asd");
list.add(new String("hello"));
list.add(123);
System.out.println(list);
//void add(int index,Object ele):在index位置插入 ele元素
list.add(2,"qwe");
//boolean addAll(int index,Collection clo):从index位置开始给clo元素全部添加到list中
List<Integer> integers = Arrays.asList(1, 3, 2);
list.addAll(2,integers);
System.out.println(list);
System.out.println( list.get(3));
}
}
/**二,集合框架
* --- collection接口:单列集合,用来存储一个个的对象
* ---Set接口:存储无序的,不可重复的数据 ---》数学中的集合
* ----HashSet:存储无序的,不可重复的数据;线程不安全的;可以存储null值
* ----LinkedHashSet:是HashSet的子类;遍历数据时,可以按照添加的顺序去遍历
* ----TreeSet:可以按照添加的对象的指定的属性,进行排序
*
*
* 1,set接口中,没有额外定义方放,都是用Collection声明过的方法
* 要求:向Set中添加的数据,其所在类一定要重写hashCode()和equals()方法
* 要求:重写的hashCode()和equals()方法,尽可能要保证一致性:相等的对象必须要有相同的hash值
* 以HashSet为例
* 无序性:不是随机性,在底层不是根据索引顺序来存储的,而是根据数据的hash值来存储的
* 不可重复性:保证添加的元素
*
*
* 2,以hashset为例
* 我们向HashSet中添加元素,首先调用元素a所在类的hashcode()方法,计算a的hash值,
* 此hash值,接着通过某种算法计算出在HashSet底层数组中存放的位置,(索引位置),
* 判断索引位置上是否有相同的数据:
* 如果没有其他元素,直接添加---->情况1
* 如果有其他的元素,比较他们的hash值:
* 如果不同:就添加成功---->情况2
* 如果相同:就用新添加的元素的所在类的equals()方法与索引位置元素比较
* 返回的是false就添加成功---->情况3
* 是ture就添加失败
* 对于情况2与情况3而言,与已经存在索引位置上的元素以链表的方式存储
* jdk1.7时:新元素放到数组中,指向之前元素
* jdk1.8时:老元素在数组中指向新元素
* hashSet 底层是数组+链表的结构
* @author rieson
* @create 2021-01-11-9:33
*/
public class SetTest {
@Test
public void test1(){
Set<Object> set = new HashSet<>();
set.add(123);
set.add(456);
set.add("qwe");
set.add("asd");
set.add(null);
set.add(new Date());
set.add(new String("unb"));
System.out.println(set);
Iterator<Object> iterator = set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
@Test
public void test2(){
//LinkedHashSet 作为HashSet的子类,再添加数据时,每个数据还维护了,两个引用,
// 记录此数据前后数据和,
//优点:对于比较频繁的遍历操作,LinkedHashSet效率高于HashSet.
Set<Object> set = new LinkedHashSet<>();
set.add(123);
set.add(456);
set.add("qwe");
set.add("asd");
set.add(null);
set.add(new Date());
set.add(new String("unb"));
System.out.println(set);
Iterator<Object> iterator = set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
@Test
public void test3(){
//向TreeSet中添加数据,要求是相同类的对象
//两种排序方式:自然排序:Comparable,定制排序:Comparator
//自然排序中,比较两个对象是否相同的标准:compareTo()返回0,不是equals()
//定制排序略
Set<Object> set = new TreeSet<>();
set.add(123);
set.add(456);
System.out.println(set);
Iterator<Object> iterator = set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
/**
* 1, Map接口:双列集合,用来存储一对(key---value)一对的数据
* ------HashMap:作为Map的主要实现类;线程不安全,效率高;可以存储null的key value值
* ----- LinkedHashMap:保证在遍历map元素时,可以按照添加的顺序实现遍历
* 原因:在原有的HashMap底层结构基础上,添加了一对指针,指向前一个和后一个
* 元素,对于频繁的遍历操作,此类要效率要高与HashMap
* -----TreeMap:保证按照添加的key-value对进行排序,实现排序遍历,此时考虑key的自然排序,或定制排序
* 底层使用的是红黑树
* ----Hashtable:作为Map的古老实现类;线程安全,效率低;不能存储null的key value值
* ----- Properties:常用来处理配置文件。key和value都是String类型的。
*
* HashMap的底层:数组+链表(1.7)
* 数组+链表+红黑树(1.8)
*
* 面试题:
* 1,HashMap的底层实现原理
* 2,HashMap与Hashtable的异同
* 3,
* 2,Map结构的理解:
* Map 中的key:无序的,不可重复的,使用Set存储所有的Key ---》Key所在的类需要重写equals()方法和hashcode()方法
* value:无序的,可重复的,使用Collection存储所有的value---》value所在类需要重写equals()方法
* 一个键值对:key-value构成一个Entry对象
* Map中的Entry:无序的,不可重复的,使用Set来存储所有的Entry
*
* 3,HashMap的底层实现原理:
* (jdk7)
* HashMap map = new HashMap();
* 在实例化以后,底层创建了长度是16的一维数组Entry[] table.
* ....已经执行过很多次put...
* map.put(key1,value1):
* 首先调用的key1所在类的hashCode()计算key1的哈希值此哈希值经过某种算法计算以后,得到Entry数组中的存放位置
* 如果此位置上为空,此时的key1-value1添加成功,-----情况1
* 如果此位置上有一个,或多个元素(以链表的方式存储),比较key1和已经存在的一个或多个元素的key的哈希值
* 如果key1的哈希值与所有的元素的哈希值都不同时,则key1添加成功-----情况2
* 如果key1的哈希值与其中任何一个元素的哈希值一样时,继续比较,调用key1所在类的equals()方法
* 如果返回的是false,则key1添加成功。----情况3
* 如果返回的是true,此时已经存储的key,保持不变,value值被key1的value替换
* 补充:关于情况2,情况3:此时的key1-value1和原来的数据以链表的方式存储
*
* 再不断的添加过程中,会涉及到扩容问题,当超出临界值时,并且下一个添加的索引位置上不为空
* 默认的扩容方式:扩容为原来容量的2倍,将原有的数据复制过来
*
* (jdk8)相较于jdk7底层实现方面的不同:
*
* * 1,new HashMap();在实例化以后,底层没有创建了长度是16的一维数组Entry[] table.
* 2,jdk8底层的数组是:Node[],而非Entry[]
* 3,首次使用put()方法时,底层创建建了长度是16的数组
* 4,jdk7底层只有:数组+链表。jdk8中的底层结构:数组+链表+红黑树。
* 当数组的某一个索引位置上的元素以链表的方式存在的个数大于8 且当前数组的长度大于64时
* 此时索引位置上的所有数据改为使用红黑树存储
*
*
*
*
*
*
*
*
* @author rieson
* @create 2021-01-11-17:57
*/
public class MapTest {
@Test
public void test3(){
Map map = new HashMap<>();
map.put("aa",123);
map.put(123,456);
map.put("AA","bb");
//遍历所有的key集:KeySet
Set set = map.keySet();
Iterator iterator = set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
//遍历所有的value:values()
Collection values = map.values();
for (Object o : values ){
System.out.println(o);
}
//遍历所有的key-value
Set set1 = map.entrySet();
Object a=new Object();
System.out.println("------------------");
for (Object o:set1){
System.out.println(o);
}
System.out.println("****************");
//方式一
Iterator iterator1 = set1.iterator();
while (iterator1.hasNext()){
Object next = iterator1.next();
Map.Entry m = (Map.Entry) next;
System.out.println(m.getKey()+"------->"+m.getValue());
System.out.println("+++++++++++++++++++++++");
//System.out.println(iterator1.next());
}
//方式二
Set set2 = map.keySet();
Iterator iterator2 = set2.iterator();
while (iterator2.hasNext()){
Object key = iterator2.next();
Object o = map.get(key);
System.out.println(key+"======="+o);
}
}
@Test
public void test2(){
Map map = new HashMap<>();
//put(key,value):添加数据
map.put("aa",123);
map.put(123,456);
map.put("AA","bb");
System.out.println(map);
//putAll(Map m):将m集合的数据添加到map中
HashMap m = new HashMap<>();
m.put(000,111);
map.putAll(m);
System.out.println(map);
//remove(123):删除指定key值的key-value
Object remove = map.remove(123);
System.out.println(remove);
System.out.println(map);
//map.clear():清空集合中的元素
map.clear();
//map.get(111):获取指定key的value值
map.get(000);
// map.isEmpty():Map是否为空
map.isEmpty();
//map.containsKey(000);是否包含key值
map.containsKey(000);
//map.containsKey(000);是否包含制定的value
map.containsValue(111);
}
@Test
public void test1(){
Map map = new HashMap<>();
map.put(null,null);
}
}
2021-01-12 Java 集合的学习总结
最新推荐文章于 2022-02-10 16:55:46 发布