2 集合类图 

java 内聚 java集合内存图_java 内聚

 

   UML

一、 List集合

            特点:元素有序,且可重复
            遍历:下标,foreach,迭代器

package com.zking.listjh;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.junit.Before;
import org.junit.Test;



public class ListDemo {

	List<Integer> list = new ArrayList<>();
//遍历

	@Before
	public void setup() {
		System.out.println("------------before-------------");
		list.add(1);
		list.add(2);
		list.add(4);
		list.add(3);
	}
	
	@Test
	public void et01() {
		for (int i = 0; i < list.size(); i++) {
			System.out.println(list.get(i));
			
		}
	}
	
	@Test
	public void et02() {
	for (Integer e : list) {
		System.out.println(e);
	}
		}

    @Test
	public void et03() {
//迭代器
		Iterator<Integer> it = list.iterator();	
	while(it.hasNext()) {
		System.out.println(it.next());
	}
	
	}
	
}

          扩容
                初始容量10,负载因子0.5,扩容增量0.5倍
                新容量 = 原容量 + 原容量 * 0.5  , 如 ArrayList的容量为10,一次扩容后是容量为15

private List<Integer> list;

 //扩容
	@Test
	public void listKourong() throws Exception {
		List<Integer> list = new ArrayList<>();
		for (int i = 0; i< 100; i++) {
			list.add(i);
			System.out.println("i : "+i);
			System.out.println("len : " + getElenLen(list));
		}
	}
	
	private int getElenLen(Object list) throws Exception {
		Class<? extends Object> clazz = list.getClass();
		Field f = clazz.getDeclaredField("elementData");
		f.setAccessible(true);
		Object[] param= (Object[])f.get(list);
			
		return param.length;
	}

            实现
                ArrayList
                    简单数据结构,超出容量自动扩容,动态数组
                    内部实现是基于基础的对象数组的
                    随机访问快
                    不适合随机增加或删除
                    线程不安全
                LinkedList
                    LinkedList提供额外的get,remove,insert方法在LinkedList的首部或尾部
                    线程不安全
                    LinkedList可被用作堆栈(stack)【包括了push,pop方法】,队列(queue)或双向队列(deque)
                    以双向链表实现,链表无容量限制,允许元素为null,线程不安全
                    适合做随机的增加或删除
                Vector
                    线程安全
                    并行性能慢,不建议使用
                CopyOnWriteArrayList
                    写时复制
                    线程安全
                    适合于读多,写少的场景
                    写时复制出一个新的数组,完成插入、修改或者移除操作后将新数组赋值给array
                    比Vector性能高
                    最终一致性
                    实现了List接口,使用方式与ArrayList类似
            ArrayList remove 的注意点
1

数据准备:为方便演示,需要有紧挨在一起的两个或多个相同的元素
                      List<Integer> list=new ArrayList<Integer>();
  list.add(1);
  list.add(2);
  list.add(3);
  list.add(3);
  list.add(4);
                for(int i=0;i<list.size();i++){
   if(list.get(i)==3) list.remove(i);
}
                    错误,为啥?
                for(int i=0;i<list.size();i++){
   if(list.get(i)==3) list.remove(i--);
}
                    正确,为啥?
                for(int i=list.size()-1;i>=0;i--){
 if(list.get(i)==3){
  list.remove(i);
 }
}
                    正确,为啥?
                for(Integer i:list){
    if(i==3) list.remove(i);
}
                    错误,??
                Iterator<Integer> it=list.iterator();
 while(it.hasNext()){
  if(it.next()==3){
   it.remove();
  }
}
                    ??
                Iterator<Integer> it=list.iterator();
 while(it.hasNext()){
  Integer value=it.next();
   if(value==3){
   list.remove(value);
  }
}
                    ??
                list.remove(2);
                    输出结果是什么?
package com.zking.listjh;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.junit.Before;
import org.junit.Test;

public class ListRemove {

	private List<Integer> list;
	
	@Before
	public void setup() {
		list = new ArrayList<Integer>();
	    list.add(1);
	    list.add(2);
	    list.add(3);
	    list.add(5);    
	    list.add(3);
	    list.add(3);
	}
	

	/**
	 * 
	 *删除集合中所有的为3的元素
	 * 
	 * */
	
	//不能删除  (不出现重复元素就可以删除)
	@Test
	public void remove01() {
		for (int i = 0; i < list.size(); i++) {
			if (list.get(i)==3)
				list.remove(i);	
			}
		System.out.println(list);           输出结果 1235
		}
		
		
	//可以删除
	@Test
	public void remove02() {
		for (int i = 0; i < list.size(); i++) {
			if (list.get(i)==3)
				list.remove(i--);	
			}
		System.out.println(list);            输出结果 125
		}
		
		//可以删除
	@Test
	public void remove03() {
		for (int i =  list.size() - 1; i >= 0; i--) {
			if (list.get(i) == 3) {
				list.remove(i);
			}
		}
		System.out.println(list);            输出结果 125
	}
	
	//不出现重复元素 可以删除
	@Test
	public void remove04() {
		for (Integer i : list) {
			if (i==3) 
			list.remove(i);
			}
	System.out.println(list);	            输出结果 1235
	}
	
	
	//可以删除
	@Test
	public void remove05() {
		Iterator<Integer> it=list.iterator();
		while(it.hasNext()) {
			if (it.next()==3) {
				it.remove();
			}
		}
		System.out.println(list);           输出结果 125
	}
	
	
	//不出现重复元素 可以删除
	@Test
	public void remove06() {
		Iterator<Integer> it = list.iterator();
		while(it.hasNext()) {
			Integer value = it.next();
			if (value==3) {
				list.remove(value);
			}
		}
		System.out.println(list);          输出结果 1235
	}
	
	@Test
	public void remove07() {
//		list.add(1);
//		list.add(2);
//		list.add(3);
//		list.add(5);
//		list.add(3);
//		list.add(3);
		list.remove(2);
	System.out.println(list);         1235
	}

二、Set集合

        特点:无序,不重复
                思考:如果对List容器中的元素去重?

     遍历:foreach,迭代器
            扩容: 初始容量16,负载因子0.75,扩容增量1倍
            实现
                HashSet
                    它存储唯一元素并允许空值
                        依据对象的hashcode来确定该元素是否存在
                    由HashMap支持
                    不保持插入顺序
                    非线程安全
                    性能参数:初始容量,负载因子
                        默认值: 初始容量16,负载因子0.75
                        示例:new HashSet<>(20, 0.5f);

思考
    1. 如何给ArrayList集合去重

public class setDemo {

	
	private List<Integer> list = new ArrayList<Integer>();
	
	@Before
	public void setup() {
		list.add(1);
		list.add(1);
		list.add(2);
		list.add(2);
		list.add(3);
		list.add(3);
	}
	
	@Test
	public void text01() {
		//去重
		List<Integer> tmp = new ArrayList<>(new HashSet<Integer>(list));
		System.out.println(tmp);        //输出 123
	}
	

@Test
	public void test02() {
		//去重     
        //通过这种方法去重必须在实体类实现hashCode 和 equals方法
		Set<Student> stuSet = new HashSet<>();
		//添加元素
		stuSet.add(new Student(1, "hhhh", 23));
		stuSet.add(new Student(1, "hhhh", 23));
		stuSet.add(new Student(2, "yy", 18));
		stuSet.add(new Student(2, "yy", 18));
		stuSet.add(new Student(3, "wwwwww", 20));
		stuSet.add(new Student(3, "wwwwww", 20));

		for (Student s : stuSet) {
			System.out.println(s);
		}
	}





eg:
//Student类 实现hashCode 和 equals方法
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((sid == null) ? 0 : sid.hashCode());
		return result;
	}


	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Student other = (Student) obj;
		if (sid == null) {
			if (other.sid != null)
				return false;
		} else if (!sid.equals(other.sid))
			return false;
		return true;
	}

    2. set有ArrayList中存在的通过下标删除,或foreach循环删除时的问题吗? 为什么

答:set不存在通过下标删除, 只能通过foreach循环删除 或者迭代器删除  。因为set是一个无序集合,没有下标 不能通过下标获取。


    3. set是否存在List删除,传入整数需要区分是基本型还是对象型的问题,【例如:list.remove(2)】,为什么? 

答:set不存在 List删除中,传入整数需要区分是基本型还是对象型的问题。

因为set没有下标  删除时直接通过对象进行删除 【 例如:list.remove(Integer.valueOf(2)    】


    4. HashSet是如何实现的?
答:HashSet是通过Map实现的,只用到了键,没有用到值。因为Map是通过键值对的形式存在的 ,键不能重复而值可以重复。


  TreeSet
                    是一个包含有序的且没有重复元素的集合
                    作用是提供有序的Set集合,自然排序或者根据提供的Comparator进行排序
                    TreeSet是基于TreeMap实现的
  

实体类 Student

package com.zking.setjh;

public class Student implements Comparable<Student>{

	private Integer sid;
	private String sname;
	private int age;
	
	
	public Student(Integer sid, String sname, int age) {
		super();
		this.sid = sid;
		this.sname = sname;
		this.age = age;
	}
	
	
	public Integer getSid() {
		return sid;
	}
	public void setSid(Integer sid) {
		this.sid = sid;
	}
	public String getSname() {
		return sname;
	}
	public void setSname(String sname) {
		this.sname = sname;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}

	
//实现hashCode 和 equals方法
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((sid == null) ? 0 : sid.hashCode());
		return result;
	}


	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Student other = (Student) obj;
		if (sid == null) {
			if (other.sid != null)
				return false;
		} else if (!sid.equals(other.sid))
			return false;
		return true;
	}
	

	@Override
	public String toString() {
		return "Student [sid=" + sid + ", sname=" + sname + ", age=" + age + "]";
	}


	@Override
	public int compareTo(Student o) {
      if (this.getAge() == o.getAge()) {
		return this.getSid() - o.getSid();
	}
		
		return this.getAge() - o.getAge();
	}


	
}









排序

	@Test
	public void text03() {
		//HashSet 自然排序 从小到大
		Set<Integer> set = new HashSet<>();
		set.add(5);
		set.add(2);
		set.add(4);
		set.add(3);
		set.add(1);

		System.out.println(set);
	}
	
	
	@Test
	public void text04() {
		//TreeSet默认是 自然排序 从小到大	
        // TreeSet通过构造函数传递 Comparator比较器 会有一个方法
		TreeSet<Integer> set = new TreeSet<>(new Comparator<Integer>() {

			@Override //方法   >正 <负  0=
			public int compare(Integer o1, Integer o2) {
				return o2 - o1; //用后面的减去前面的 结果顺序为倒序
			}
		});
		set.add(7);
		set.add(1);
		set.add(2);
		set.add(5);
		set.add(4);
		set.add(3);
		set.add(6);
		System.out.println(set); //输出 7654321
	}
	
	
//方法一
	@Test
	public void text05() {
    // TreeSet通过构造函数传递 Comparator比较器 会有一个方法
    //自定义对象Student     通过年龄进行排序 降序
		TreeSet<Student> set = new TreeSet<>(new Comparator<Student>() {

			@Override
			public int compare(Student o1, Student o2) {	
				if (o2.getAge() - o1.getAge() == 0) {// 相减等于0 说明它们相等
					return o2.getSid() - o1.getSid();//一旦发现年龄相等 就用学号来排序
				}
			 return o2.getAge() - o1.getAge();
			}
		});
        set.add(new Student(1, "zs", 5));
        set.add(new Student(2, "ls", 10));
        set.add(new Student(3, "ww", 15));
        set.add(new Student(4, "mz", 20));
        set.add(new Student(5, "ll", 5));

         for (Student s : set) {
			System.out.println(s);
		}
	}
	

	//如果两种方式的比较器同时存在  第一种(构造函数实现的Comparator)比第二种优先
	//(在实体里实现Comparator接口 进行判断)
	

//方法二	
//2通过比较器实现排序	 通过这种方法进行排序 必须实现比较器接口 并且实现方法进行判断
	@Test   //从小到大
	public void text06() {

		TreeSet<Student> set = new TreeSet<>();

        set.add(new Student(1, "zs", 5));
        set.add(new Student(2, "ls", 10));
        set.add(new Student(3, "ww", 15));
        set.add(new Student(4, "mz", 20));
        set.add(new Student(5, "ll", 5));

         for (Student s : set) {
			System.out.println(s);  
		}
	}
	

	}

  三、 Map集合

      特点:
                无序,键值对,键不能重复,值可以重复,
                键重复则覆盖,没有继承Collection接口
            扩容:初始容量16,负载因子0.75,扩容增量1倍
            遍历
                先获取所有键的Set集合,再遍历(通过键获取值)
                取出保存所有Entry的Set,再遍历此Set即可
            实现
                HashMap
                    线程不安全,最常用,速度快
                    内部采用数组来存放数据
                    基本原理
                        put执行过程
                            Table数组中的的Node
                                链表结构示意图
                                红黑树结构示意图
                            流程图中绿色标出的部分为JDK8新增的处理逻辑,目的是在Table[i]中的Node节点数量大于8时,通过红黑树提升查找速度。
                HashTable
                    线程安全,不太常用
                ConcurrentHashMap
                    线程安全,比HashTable性能高
                TreeMap
                    key值按一定的顺序排序
                    添加或获取元素时性能较HashMap慢
                        因为需求维护内部的红黑树,用于保证key值的顺序
                LinkedHashMap
                    继承HashMap
                    LinkedHashMap是有序的,且默认为插入顺序
                        当我们希望有顺序地去存储key-value时,就需要使用LinkedHashMap了
                     Map<String, String> linkedHashMap = new LinkedHashMap<>();
        linkedHashMap.put("name1", "josan1");
        linkedHashMap.put("name2", "josan2");
        linkedHashMap.put("name3", "josan3");
        Set<Entry<String, String>> set = linkedHashMap.entrySet();
        Iterator<Entry<String, String>> iterator = set.iterator();
        while(iterator.hasNext()) {
            Entry entry = iterator.next();
            String key = (String) entry.getKey();
            String value = (String) entry.getValue();
            System.out.println("key:" + key + ",value:" + value);
        }
        排序
            java.lang.Comparable
            java.util.Comparator
        工具类
            Collections
                提供一组静态方法操作集合
            Arrays
                提供一组静态方法操作数组

    jdk8:stream
        介绍
            jdk8添加的一个新的功能,称之为流,可以以声明的方式来处理数据,提供一种对 Java 集合运算的方便处理方式
            让程序员写出高效率、干净、简洁的代码
        特点
            可以方便的对集合进行并行操作,便于使用多核资源
            惰性求值
            不是数据结构,不保存数据
            不会修改原来的数据源,将操作后的数据保存到另一个对象中
        操作
            中间操作(Intermediate)
                map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 skip、 parallel、 sequential、 unordered
            最终操作(Terminal)
                forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、iterator
            特点:
                在一次聚合操作中,可以有多个Intermediate,但是有且只有一个Terminal
        使用示例
            filter
            sorted
            distinct
            min,max,count
            group