1c 集合.txt

UP 返回
1.Collection接口 (集合,定义的是所有单列集合中共性的方法,没有带索引的方法)
	集合只能存储对象

2.List接口(继承于Collection):
	1.有序的集合(存储和取出元素顺序相同)
	2.允许存储重复的元素
	3.有索引,可以使用普通的for循环遍历
    子类有Vector,ArrayList,LinkedList

   Set接口(继承于Collection):
	1.不允许存储重复元素
	2.没有索引,不能使用普通的for循环遍历
    子类有TreeSet,HashSet,两者是无序集合(HashSet有子类LinkedHashSet,是有序集合)

3.Collection常用功能
	public boolean add(E e);//添加对象
	public void clear();//清空集合
	public boolean remove(E e);//删除集合中该对象
	public boolean contains(E e);//判断集合中是否包含该对象
	public boolean isEmpty();//判断集合是否为空
	public int size();//集合元素个数
	public Object[] toArray();//把集合元素存入数组

4.Iterator接口(迭代器)
	boolean hasNext();//判断集合中有没有下一个元素
	E next();//取出集合中下一个元素
   获取Iterator实现类的方法:Collection中有一个方法Iterator<E> iterator(),返回此集合对应的迭代器
		Iterator<String> it=coll.iterator();
		while(it.hasNext){										//使用while循环
			String e=it.next();
			System.out.println(e);
		}
		
		for(Iterator<String> it=coll.iterator();it.hasNext()){		//使用for循环
			String e=it.next();
			System.out.println(e);
		}
    foreach语句(增强for)内部即是通过迭代器实现

5.泛型
  5.1 集合不使用泛型的话,默认的类型是Object 。使用泛型的好处是:1.避免了类型转换的麻烦(存储什么类型取出就是什么类型) 2.把运行期异常提升到了编译期;弊端是:泛型是什么类型,就只能存储什么类型   =============(未理解这句话的含义,待定)
   泛型类的创建和使用:
	public class GenericClass<E>{
		private E name;
	
		public E getName(){
			return name;
		}
	
		public void setName(E name){
			this.name=name;
		}
	}
	
	GenericClass<Integer> gc1=new GenericClass<>();
	gc1.setName(1);
	Integer name=gc1.getName();
	System.out.println(name);
	
	GenericClass<String> gc2=new GenericClass<>();
	gc2.setName("小明");
	String name1=gc3.getName();
	System.out.println(name);

   5.2 定义含有泛型的方法:
	public class GenericMethod{
		public <M> void method(M m){	//泛型写在函数的修饰符和返回类型之间,<M>不可删
			System.out.println(m);
		}
	}

   5.3 定义含有泛型的接口:
	public interface GenericInterface<I>{
		public abstract void method(I i);
	}

	public class GenericInterfaceImpl1 implements GenericInterface<String>{		//1.实现类指定泛型的类型
		@Override
		public void method(String s){	//对应的泛型方法自动变为设定的类型
		}
	}

	public class GenericInterfaceImpl2<I> implements GenericInterface<I>{		//2.实现类仍然使用泛型,创建对象的时候再指定类型
		@Override
		public void method(I s){	//对应的泛型方法自动变为设定的类型
		}
	}

   5.4 泛型通配符:不知道使用什么类型来接收的时候,可以使用?表示未知通配符,此时只能接收数据,而不能往该集合中存储数据 
	public static void printArray(ArrayList<?> list){		//通配符作为参数
		Iterator<?> it=list.iterator();
		whiel(it.hasNext()){
			Object o=if.next();		//此时返回的只能是Object
			System.out.println(o);
		}
	}
   定义的时候不可用,比如不可以写:ArrayList<?> list=new ArrayList<?>();,只能在参数传递的时候用

   5.5 受限泛型(只要在阅读java源码时能看懂即可)
	泛型的上限限定:? extends E		代表使用的泛型只能是E和E的子类		:public static void getElement1(Collection<? extends Number> coll){}	//此处的?只能是Number或者其子类
	泛型的下限限定:? super E		代表使用的泛型只能是E和E的父类		:public static void getElement2(Collection<? super Number> coll){}		//此处的?只能是Number或者其父类

6.红黑树(趋近于平衡树,查询叶子节点最大次数和最小次数不能超过2倍)
   二叉树;排序树/查找树;平衡树;红黑树
   红黑树:
	1 趋近于平衡树,查询叶子节点最大次数和最小次数不能超过2倍
	2 结点可以是红色的或者黑色的
	3 根节点是黑色的
	4 叶子节点(空节点)是黑色的
	5 每个红色结点的子节点都是黑色
	6 任何一个结点到其每一个叶子节点的所有路径上黑色节点数相同 

7.List集合
	List<String> list=new ArrayList<>();
   ArrayList是一个数组实现,查询快,增删慢,是多线程的(不同步)。增加元素时他的底层实际是重新创建一个新的数组,再将原数组复制过来(适用于查询较多的)
	public void add(int index ,E element);
	public E get(int index);
	public E remove(int index);
	public E set(int index ,E element);
   LinkedList是一个双向链表实现,查询慢(但是首尾元素的查询很快),增删快,也是多线程。里面包含了大量操作首尾元素的方法(此类不可使用多态定义变量,即只能写LinkedList<String> linked=new LinkedList<>();,不可用List<String> linked...)
	public void addFirst(E e);
	public void addLast(E e);
	public void push(E e);		//等价于addFirst(E e)
	public E getFirst();
	public E getLast();
	public E removeFirst();	//返回的是被移除的元素
	public E removeLast();
	public E pop();				//等价于removeFirst()
	public boolean isEmpty();
   Vector 对所有单列集合进行了包装,底层也是一个数组。是同步的(单线程,故速度慢,1.0版本出现,1.2版本之后就被替代了)

8.Set接口(不包含重复元素的collection,且最多包含一个null,接口中无索引)
   HashSet 哈希表结构,不保证set的迭代顺序,查询速度很快(使用迭代器或者增强for遍历)
	jdk1.8之前,哈希表=数组+链表;1.8以后,哈希表=数组+红黑树(提高查询速度。链表长度超过8位就转为红黑树)
	在向HashSet中添加元素时,add方法首先会计算hashCode(),如果没有则添加,如果有相等的,说明有冲突,再做equals比较两个元素是否相同,不同再存入。
		hash值:系统随机给出的一个十进制整数,是对象的逻辑地址值:
			public native int hashCode();		//获取hashcode,native代表该方法调用的是本地操作系统的方法。toString方法使用的也是这个hashcode
		String类重写了hashCode(),故相同的字符串返回的哈希值是一样的。特别的:"重地"和"通话"两个字符串的哈希值一样,巧合
   	在HashSet中存放自定义类型的元素时,需要重写hashCode和equals方法,建立自己的比较方式,才能保证HashSet集合中对象唯一(IDEA中Alt+Insert可以自动添加方法代码)
   LinkedHashSet 具有可预知迭代顺序的Set接口的哈希表和链表实现(内部有一个双重链表专门维护存入的元素顺序)
   
   可变参数:
	1.一个方法的参数列表,只能有一个可变参数
	2.如果方法有多个参数,可变参数必须在最后
		public static void method(String a,double b,int d,int...a){ }
	特殊写法:	public static void method(Object...obj){ }	//可以接受任意参数

9.Collections工具类
   public static <T> boolean addAll( Collection<T> c ,T... elements );//往集合中添加一些元素
   public static void shuffle( List<?> list );//打乱集合顺序
   public static <T> void sort( List<T> list );//元素按默认排序;排序自定义的类需要实现Comparable<自定义类名>,重写compareTo方法(返回this-参数表示升序),规定排序规则
   public static <T> void sort( List<T> list ,Comparator<? super T> );//元素按指定规则排序
	Comparator和Comparable的区别:
		Comparator:自己(this)和别人(参数)比较,自己需要实现Comparable接口,重写比较规则compareTo方法
		Comparable:相当于找一个第三方的裁判,比较两者
	Collections.sort(list01, new Comparator<Integer>(){
		@Override
		public int compare(Integer o1,Integer o2){		//如果是自定义的类型也需要重写该方法
			//return o1-o2;		//升序
			return o2-o1;		//降序
		}
	});

10.Map集合 java.util.HashMap<k,v> implements Map<k,v>
   HashMap 哈希表结构(参HashSet);无序集合;不同步(多线程,速度快)	【事实上HashMap在add时会自动对key值进行排序,所以有时可以通过此特性实现自动排序的功能,参视频  \2019年4月黑马程序员教程\01-黑马IDEA版本Java基础+就业课程\1.基础班\1-8 File类与IO流\第7节 缓冲流\08_练习_对文本的内容进行排序】
	HashSet的底层就是一个HashMap的实现,但是只使用了key,所以HashSet不允许相同元素同时存在
   LinkedHashMap 哈希表+链表;有序集合(链表可以保证)

   10.1 Map常用方法
	public V put(K key,V value);//存储键值对,key不存在时返回null,key不存在时新的value覆盖旧的值,同时返回旧的值
	public V remove(Object key);//删除指定的键值对;key存在返回被删除的值,不存在返回null
	public V get(Object key);//获取key的value
	boolean containsKey(Object key);//是否包含key
	keySet();//取出集合key的集合:Set<String> set=map.keySet(); Iterator<String> it=set.iterator();//再遍历循环(通过get(Object key)获得value)

   10.2 Map有一个内部嵌套接口Map.Entry<K,V>,映射项(键-值对)
	Map一旦创建,Entry对象即被创建,用来记录键值对:
		Set<Map.Entry<String,String>> set=map.entrySet();//entrySet()方法可以得到Entry集合
		Iterator it=set.iterator();//遍历
	当然上面的set集合也是可以直接用增强for来遍历的:
		for(Map.Entry<String,String> entry:set){
			String key=entry.getKey();
			tring value=entry.getValue();//Entry的两个get方法
		

   10.3 HashMap存储自定义类型的键值时,作为key的元素必须重写hashCode()和equals方法,以保证key唯一(不重写的话同样的对象基本会被当成不同的来添加进入map)

   10.4 Hashtable<K,V> 也是一个哈希表实现,区别就是该类只允许非null对象作为键值(开始于1.0,另外两个是1.2开始。之前所有的集合都可以存入null);是线程安全的(同步,单线程,速度慢)
	HashTable和Vector现在都不常用了(先进的HashMap,ArrayList所替代),但是HashTable的子类Properties依然在使用(properties是一个唯一和IO流相结合的集合)

11.JDK9对集合的更新
   11.1 jdk9添加了几种集合工厂方法,更方便创建少量元素的集合和map
	static <E> List<E> of (E... elements);//List,Set,Map接口里增加了一个静态的方法of,可以给集合一次性添加多个元素(集合元素已确定的情况下)。只适用于这三个接口,不包括实现类;返回的是一个不可改变的集合(无法再使用add put方法了,会抛出异常。同时set和map在调用of时不可有重复元素):
		List<String> list=List.of("a","b","a","d","e");
		list.add("w");//UnsupportedOperationException
		Set<String> set=Set.of("a","b","a","d","e");//IllegalArgumentException
		Set<String> set=Set.of("a","b","c","d","e");
		Map<String,Integer> map=Map.of("张三",18,"李四",19,"王五",20);
		map.put("赵四",30);//报错






















DOWN 返回