第七章集合

学习目标:

学会集合内容

学习内容:

1、 泛型 2、 Collection 3、 Map 4、 Collections

学习时间:

2021年6月7日 2021年6月25日

学习产出:

1、 技术笔记 1 遍 2、CSDN 技术博客 1 篇

泛型

为什么会有泛型?

​ 早期的Object可以存储任意的类型,但是在实际使用中存在数据转换的问题。也就存在隐患,java使用泛型解决这个安全问题

泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。

参数化类型,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在调用/使用时传入具体的类型(类型实参)

    public class Demo<T> { 
    private T p;
    public T getP() { 
        return p;
    }
    public void setP(T p) {
        this.p = p;
    }

泛型的类型参数只能是类类型(包括自定义类

泛型的类型参数可以有多个。

如果没有定义具体类型,默认为Object

集合的概念

当我们需要保存一组一样(类型相同的元素的时候,我们应该使用一个容器 来存储,数组就是这样一个容器。但是数组一旦定义,长度就不能发生变化

我们需要能够动态增长长度的容器来保存我们的数据。

而我们需要对数据的保存的逻辑可能多种多样,于是就有了各种各样的数据结构。java中对于各种数据结构的实现,就是我们的集合。

集合体系

Java的集合框架是由很多接口、抽象类、具体类组成的,都位于java.util包中

在这里插入图片描述

Collection接口

Collection接口定义了存取一组对象的方法,其子接口Set和List分别定义了存储方式。

​ Set中的数据对象没有顺序且不可以重复。

​ List中的数据对象有顺序且可以重复。

Collection接口中的方法:

    add(E e)//添加元素
    addAll(Collection<? extends E> c) //将制定集合添加到此集合
    clear() //清空集合
    contains(Object o) //如果刺激和包含指定元素,则返回true
    containsAll(Collection<?> c) //如果此集合包含指定 集合中的所有元素,则返回true。 
    isEmpty() //如果此集合不包含元素,则返回 true 。 
    remove(Object o) //从集合中删除某个元素
    removeAll(Collection<?> c) //删除指定集合中包含的所有此集合的元素(可选操作)。 
    size() //集合中的元素数
    retainAll(Collection<?> c) //;求交集,集合数据发生变化返回true, 不变返回false

List接口及实现类

List接口 继承 Collection
有序的(按照插入元素的顺序排列),存储重复元素,值插入后会有索引,可以通过索引访问元素。

ArrayList
底层是数组,查询快,从中间删除,添加慢
LinkedList
底层是双向链表,查询慢,从中间删除,添加快
Vector
底层是数组,查询快,从中间删除,添加慢,线程安全

ArrayList

构造方法:

​ ArrayList();默认不创建底层数组,当添加第一个元素时,创建一个长度10的数组
​ ArrayList(int length); 创建对象时,创建一个指定长度的数组
​ ArrayList(Collection collection); 把一个实现了Collection接口的子类,构造成一个ArrayList

ArrayList扩容:

          /*add(E e)向列表的末尾添加元素
		  add(int index,E e)向指定位置添加元素 
		  add方法底层数组扩容  当底层数组装满之后,会自动扩容为原来的1.5倍*/
		   public boolean add(E e) {
		        ensureCapacityInternal(size + 1);  // 检测是否还有位置
		        elementData[size++] = e;
		        return true;
		    }
		    
		     if (minCapacity - elementData.length > 0)//判断是否可以放得下
                grow(minCapacity);//扩容方法
		    
		    private void grow(int minCapacity) {
		        // overflow-conscious code
		        int oldCapacity = elementData.length;
		        int newCapacity = oldCapacity + (oldCapacity >> 1);//扩容1.5
		        if (newCapacity - minCapacity < 0)
		            newCapacity = minCapacity;
		        if (newCapacity - MAX_ARRAY_SIZE > 0) //判断数组索引是否大于Int的最大值
		            newCapacity = hugeCapacity(minCapacity);
		        // minCapacity is usually close to size, so this is a win:
		         //                            原数组              新长度
		        elementData = Arrays.copyOf(elementData, newCapacity);//进行数组赋值 
		                           //返回一个新数组
		    }

ArrayList一些方法:

        //System.out.println(list.get(3));//查询快,直接返回指定位置的值
        //System.out.println(list.remove(3));//删除并返回指定位置的值

        list.removeIf(new Predicate<String>() {//条件删除
            @Override
            public boolean test(String s) {
                return s.equals("e");//删除符合条件的元素
            }
        });

        list.set(0,"W");//替换指定位置的元素
        list.sort(new Comparator<String>() {//排序 指定排序的规则
            @Override
            public int compare(String o1, String o2) {
                return o1.compareTo(o2);
            }
        });
        List<String> li =  list.subList(0, 4);//从原集合中复制一段返回新集合,原集合不变
	
       public class ArrayListChild extends ArrayList{
	    public static void main(String[] args) {
		ArrayListChild a = new ArrayListChild();
		              a.add("a");//0
		              a.add("a");
		              a.add("a");
		              a.add("a");
		              a.add("b");//4
		              a.add("c");
		              a.add("d");
		              a.removeRange(0, 4);//在ArrayList的子类中使用
		              System.out.println(a);
     	}

  	}

ArrayList遍历方法

方式1:for循环 length (数组) length()(字符串) size()(集合)
循环时允许删除元素,但是我们需要注意索引与集合长度之间关系

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

方式2:增强for循环
循环时不允许从中删除元素

	   for (Integer item : list) {
		   if(item==1){
			   list.remove(item);
		   }
		  System.out.println(item);
	   } 

方式3:迭代器遍历

	   Iterator<Integer> it = list.iterator();
	     while(it.hasNext()){
	        	Integer item = it.next();
	        	if(item==1){
	        		it.remove();
	        	}
	     }
	     System.out.println(list);
        /*                 
	      listIterator() 只能用于List接口的集合
	   */
	   ListIterator<Integer> lit  =    list.listIterator();
	                  while(lit.hasNext()){
	                	   lit.next();
	                	   //lit.add(2);
	                	   //lit.remove();
	                  }
	                  System.out.println(list);
	   
	
		                               //从指定的位置开始,  list.size()从后向前遍历
		ListIterator<Integer> lit  =    list.listIterator(list.size());
		     while(lit.hasPrevious()){
		             System.out.println(lit.previous());	   
		    }

方式4:流遍历

         Stream<Integer> s =  list.stream();
                 s.forEach(new Consumer<Integer>() {
                	 @Override
                 	public void accept(Integer t) {
                		 System.out.println(t);
                	}
				});
		     
		    s.forEach(t->System.out.println(t));

LinkedList

LinkedList与ArrayList方法大致相同

LinkedList采用链表存储方式。插入、删除元素时效率比较高。查询效率比较慢

        /* 
		传入一个索引,如果索引小于集合一半,从头结点开始查找,直到找到这个位置的值    
		如果大于一半,从尾结点开始查找,直到找到这个位置的值    
         */
        LinkedList<String> list = new LinkedList<>();
        list.add("a");
        list.add("a");
        list.add("c");
        list.add("d");
        list.add("e");
        System.out.println(list.contains("a"));
        list.get(3);
        System.out.println(list.peek());//检索但不删除此列表的头(第一个元素)。
        System.out.println(list.pop());//从此列表表示的堆栈中弹出一个元素。
        list.push("d");//将元素推送到由此列表表示的堆栈上。
        list.remove();//检索并删除此列表的头(第一个元素)。
        list.remove(3);//删除该列表中指定位置的元素。
        list.set(1,"X");//用指定的元素替换此列表中指定位置的元素。
        System.out.println(list.size());//返回此列表中的元素数。

Vector

底层也是数组 查询快,中间增删慢,是线程安全的

           public synchronized(同步锁) boolean add(E e) {
			        modCount++;
			        ensureCapacityHelper(elementCount + 1);
			        elementData[elementCount++] = e;
			        return true;
			    } 

Set接口及实现类

Set中所存储的元素是不重复的,但是是无序的, Set中的元素是没有索引的

​ HashSet:无序 底层使用哈希表+链表+红黑树
​ TreeSet:有序(按照值(编码)的顺序排序) 底层是红黑树

HashSet

HashSet添加时如何判断值是否重复

添加时会调用hashCode(),equals()
添加时要比较内容是否相等,既要保证效率,又要保证安全
先调用hashCode()计算出一个哈希值,比较哈希值非常快,但是不安全
当哈希值相同时,再调用equals()方法比较

        HashSet<Student> set = new HashSet<>();
		 /*
		       我们的Student类中没有重写hashCode()和equals(),会调用Object中的方法
		  */

     "s".hashCode();//字符串.Integer....这些类重写了hashCode()都是根据对象中包含的内容来计算哈希值

HashSet遍历

​ listIterator()和iterator()区别

​ listIterator()只能遍历实现了List接口的类

​ iterator() 遍历list,set

	 /*
		  增强for
		  */
		   for(Integer it : set){
			   System.out.println(it);
		   }
	 
      //Iterator 遍历
	  Iterator<Integer> it =  set.iterator();
              while(it.hasNext()){
            	Integer n = it.next();
                   System.out.println(n);
            	   // it.remove();
              }
	  
	 /*
	   Stream
	  */
      Stream<Integer> stream =  set.stream();
      stream.forEach(new Consumer<Integer>(){
    	  @Override
        	public void accept(Integer t) {
                      System.out.println(t);	                		
        	}
      });

TreeSet

可以给Set集合中的元素进行指定方式的排序。存储的对象必须实现Comparable接口。

TreeSet底层数据结构是红黑树。

Map接口

三个实现类 : HashMap

​ TreeMap

​ Hashtable(线程安全)

方法:clear() 从该地图中删除所有的映射(可选操作)。

containsKey(Object key) 如果此映射包含指定键的映射,则返回 true 。

containsValue(Object value) 如果此地图将一个或多个键映射到指定的值,则返回 true 。

remove(Object key) 如果存在(从可选的操作),从该地图中删除一个键的映射。

get(Object key) 返回到指定键所映射的值,或 null如果此映射包含该键的映射。

put(K key, V value) 将指定的值与该映射中的指定键相关联(可选操作)。

putAll(Map<? extends K,? extends V> m) 将指定地图的所有映射复制到此映射(可选操作)。

size() 返回此地图中键值映射的数量。

isEmpty() 如果此地图不包含键值映射,则返回 true 。

replace(K key, V value) 只有当目标映射到某个值时,才能替换指定键的条目。

keySet() 返回此地图中包含的键的Set视图。

entrySet() 返回此地图中包含的映射的Set视图。

forEach(BiConsumer<? super K,? super V> action) 对此映射中的每个条目执行给定的操作,直到所有条目都被处理或操作引发异常。

HashMap

HashMap中元素的key值不能重复, 排列顺序是不固定的,可以存储一个为null的键。

HashMap的底层是哈希表+链表+红黑树

用key计算出哈希值,再用哈希值计算出元素在哈希表中的位置。当相同位置有元素加入进来后,才用链表存储(拉链法),当元素个数达到8时,采用红黑树存储。

哈希表的默认长度为8,负载因子为0.75,每次触发扩容机制,扩容为原来的1.5倍。

        HashMap<String,String> hashMap = new HashMap<>();
        hashMap.put("a","a");
        hashMap.put("a","b");
        hashMap.put("b","b");
        hashMap.put("j","i");
        hashMap.put("i","j");
        System.out.println(hashMap);
        //hashMap.clear();
        System.out.println(hashMap.containsKey("i"));//包含键
        System.out.println(hashMap.containsValue("i"));//包含值


        System.out.println(hashMap.get("o"));//根据键查找值,键不存在,返回null
        hashMap.remove("i");
        hashMap.replace("a","m");//替换已有的键,如果键不存在,不能替换
        hashMap.replace("s","s");

三种遍历方式:

        HashMap<String,String> hashMap = new HashMap<>();
        hashMap.put("a","a");
        hashMap.put("a","b");
        hashMap.put("b","b");
        hashMap.put("j","i");
        hashMap.put("i","j");

        //Map遍历方式1:keySet()
        Set<String> keySet = hashMap.keySet();
        for (String key:keySet){
            System.out.println(key+"::"+hashMap.get(key));
        }

        //Map遍历方式2:entrySet()将map中底层储存键值的entry对象,封装到一个Set集合中
        Set<Map.Entry<String,String>> entrySet = hashMap.entrySet();
        for (Map.Entry<String,String> entry : entrySet){
            System.out.println(entry.getKey()+"::"+entry.getValue());
        }

        //Map遍历方式3:
        hashMap.forEach(new BiConsumer<String, String>() {
            @Override
            public void accept(String key, String value) {
                System.out.println(key+"::"+value);
            }
        });

TreeMap

TreeMap中所有的元素都保持着某种固定的顺序,如果需要得到一个有序的Map就应该使用TreeMap,key值所在类必须实现Comparable接口。

HashtableDemo

底层也是哈希表+链表(红黑树)实现
是线程安全 synchronized Stringbuffer,Vector

和HashMap相似。

Collections类

方法:

        ArrayList<String>list = new ArrayList<>();
        list.add("c");
        Collections.addAll(list,"d","b","a");//将后面的元素添加进list集合
        Collections.sort(list);//排序
        int index = Collections.binarySearch(list,"a");//二分查找,返回一个int类型的索引
        Collections.swap(list,1,3);//将第一个位置的元素和第三个位置的元素交换
        ArrayList<String> list1 = new ArrayList<>();
        list1.add("a");
        list1.add("a");
        list1.add("a");
        list1.add("a");
        list1.add("a");
        Collections.copy(list1,list);//把后面的集合复制到前一个集合中去并覆盖。前面的集合元素必须必后面的集合元素多
            List<Object> list2 = Collections.emptyList();//返回为空的集合,不能添加数据
        System.out.println(list2.add("a"));
        Collections.fill(list,"b");//将list集合中的所有元素都用b替换掉
        Collections.replaceAll(list1,"b","c");//用c替换掉list1中的所有b

对类类型集合进行排序

        ArrayList<Student> students = new ArrayList<>();
        Student student1 = new Student("tim",10);
        Student student2 = new Student("tom",13);
        Student student3 = new Student("tony",19);
        Student student4 = new Student("jim",14);
        Student student5 = new Student("tim",10);
        students.add(student1);
        students.add(student2);
        students.add(student3);
        students.add(student4);
        students.add(student5);
        Collections.sort(students, new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return o1.getAge()-o2.getAge();
            }
        });
        System.out.println(students);

     /*
	  *   int...n 可变长度的参数,本质是一个数组,一个参数列表只能有一个, 必须放在参数列表的最后一个
	  *   [I@15db9742
	  */
	 public static void test(String name,int...n){
		  System.out.println(n);
	 }

Collection和Collections的区别

Collection是接口,是单列集合,其内包含Set接口和Link接口。提供了对集合进行基本操作的通用方法。

Collections是集合类的工具类,其内包含很多集合相关的静态的方法,不能被实例化

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值