Java 集合看这一篇够了

主要集合概述

Java 主要有 3 种重要的集合类型:

  • List:是一个有序集合,可以放置重复的元素

  • Set:是一个无序集合,不允许放置重复的元素

  • Map:是一个无序集合,集合中包含一个对象,一个对象,键对象不允许重复,值对象可以重复

    • 就像身份证号和姓名 : <键 , 值>

集合中只能存储引用类型,不能存储基本数据类型

集合中 Collection 的继承结构图(重要·背下来)

集合中 Collection 的继承结构图

Collection 中的常用方法
	boolean	add(E e)
	boolean	addAll(Collection<? extends E> c)
	void	clear()
	boolean	contains(Object o)
	boolean	containsAll(Collection<?> c)
	int	hashCode()
	boolean	isEmpty()
	Iterator<E>	iterator()
	boolean	remove(Object o)
	boolean	removeAll(Collection<?> c)
	int	size()
	Object[] toArray()
  • 举例1

    import java.util.*;
    
    public class Test02 {
    	public static void main(String[] args) {
    		// 创建集合
    		Collection c = new ArrayList();
    		// 添加元素
    		c.add(1);// auto boxing
    		c.add(new Integer(1));
    		Object o = new Object();
    		c.add(o); // 集合中只能单个存储元素,并且只能存储引用类行
    		c.add(new Customer("张三", 23));
    		// 获取元素个数
    		System.out.println(c.size());// 4
    		
    		// 判断集合是否为空
    		System.out.println(c.isEmpty());// false
    		Object[] resO = c.toArray();
    		for (int i = 0; i < resO.length; i++) {
    			System.out.println(resO[i]);
    		}
    		// 移除某一个引用
    		c.remove(1);
    		System.out.println(c.size());//3
    		// 清空集合
    		c.clear();
    		System.out.println(c.size());//0
    		
    		// 判断集合是否为空
    		System.out.println(c.isEmpty());// true
    	}
    }
    
    class Customer{
    	String name;
    	int age;
        
    	public Customer(String name, int age) {
    		this.name = name;
    		this.age = age;
    	}
    	@Override
    	public String toString() {
    		return "Customer [name=" + name + ", age=" + age + "]";
    	}
    }
    
    
  • 举例2- Iterator 迭代器

    Iterator iterator(); 获取集合所依赖的迭代器对象, 通过迭代器中的方法完成集合的遍历/迭代
    注意: 这种方法是所有集合通用的遍历方式

    import java.util.*;
    /*
     Iterator iterator(); 获取集合所依赖的迭代器对象
     通过迭代器中的方法完成集合的遍历/迭代
     注意: 这种方法是所有集合通用的遍历方式
     */
    public class Test03 {
    	public static void main(String[] args) {
    		// 创建集合对象
    		Collection c = new LinkedList();
    		// 添加元素
    		c.add(122); // 自动装箱
    		c.add(false);// 自动装箱
    		c.add(399);// 自动装箱
    		
    		// 迭代遍历
    		// 获取迭代器对象
    		// 不需要关心底层集合的具体类型,所有集合依赖的迭代器都实现了 java.util.Iterator; 接口
    		Iterator iterator = c.iterator(); // 迭代器对象是面向接口编程
    		// iterator 是引用,保存了内存地址,指向堆中的“迭代器对象”
    		System.out.println(iterator); // java.util.LinkedList$ListItr@15db9742
    		
    		// 开始调用方法,完成遍历,迭代 
    		// 原则, 调用 iterator.next() 方法之前必须调用 iterator.hasNext()
    		// while循环
    		while(iterator.hasNext()) {
    			System.out.println(iterator.next());
    		}
    		// for 循环
    		for(Iterator it = c.iterator(); it.hasNext();) {
    			System.out.println(it.next());
    		}
    	}
    }
    
    
  • 举例3-contains()方法

    contains()底层是调用的equals()方法

    注意:自己创建的类一般都要重写 Object 类中的 equals() 方法,使之用于比较内容

    import java.util.*;
    //  boolean contains(Object o)
    public class Test04 {
    	public static void main(String[] args) {
    		// 创建集合
    		Collection c = new ArrayList();
    		// 创建 Integer 类型的对象
    		Integer i1 = new Integer(256);
    		// 添加元素
    		c.add(i1);
    		System.out.println(c.contains(256));// true
    		// 创建 Integer 类型的对象
    		Integer i2 = new Integer(256);
    		// 虽然i2没有添加进c集合里面,但是contains()底层是调用的equals()方法
    		// Integer重写了Object类中的equals方法
    		// 所以下面执行结果为true
    		System.out.println(c.contains(i2));// true
    		
    		Manger m1 = new Manger("张三", 12);
    		c.add(m1);
    		System.out.println(c.contains(m1));// true
    		Manger m2 = new Manger("张三", 12);
    		// Manger类重写equals方法后
    		System.out.println(c.contains(m2));// true
    	}
    }
    
    class Manger{
    	String name;
    	int id;
    	public Manger(String name, int id) {
    		this.name = name;
    		this.id = id;
    	}
    	@Override
    	public boolean equals(Object obj) {
    		if(this == obj) {
    			return true;
    		}
    		if(obj instanceof Manger) {
    			Manger m = (Manger)obj;
    			return this.name == m.name && this.id == m.id;
    		}
    		return false;
    	}
    	
    }
    
    • ArrayList 中的contains()方法的实现

      public boolean contains(Object o) {
          return indexOf(o) >= 0;
      }
      
      public int indexOf(Object o) {
          if (o == null) {
              for (int i = 0; i < size; i++)
                  if (elementData[i]==null)
                      return i;
          } else {
              for (int i = 0; i < size; i++)
                  if (o.equals(elementData[i]))
                      return i;
          }
          return -1;
      }
      
  • 举例4-集合中的remove()方法

    remove() 方法和contains()方法都需要集合中的对象重写 equals() 方法。 因为Object类中的equals方法是比较内存地址,而在现实的业务逻辑中不能比较内存地址,该比较内容。

    import java.util.*;
    
    public class Test05 {
    	public static void main(String[] args) {
    		// 创建集合
    		Collection c = new ArrayList();
    		// 添加元素
    		Integer i1 = new Integer(10);
    		c.add(i1);
    		Integer i2 = new Integer(10);
    		System.out.println(c.remove(i2));// true
    		System.out.println(c.size());// 0
    		
    		Manger m1 = new Manger("张三", 12);
    		c.add(m1);
    		Manger m2 = new Manger("张三", 12);
    		// Manger类重写equals方法后
    		System.out.println(c.remove(m2));// true	
    		System.out.println(c.size());//0
    	}
    }
    
    
  • 举例5-迭代器中的remove()方法

    在使用迭代器循环删除集合中的元素的时候,不能使用集合的remove()方法,只能使用迭代器的remove()方法

    import java.util.*;
    
    public class Test06 {
    	public static void main(String[] args) {
    		// 创建集合
    		Collection c = new ArrayList();
    		
    		c.add(1);
    		c.add(2);
    		c.add(3);
    		// 创建迭代器对象
    		Iterator it = c.iterator();
    		while(it.hasNext()) {
    			Object o = it.next();
    			it.remove();// 使用迭代器删除
    		}
    		System.out.println(c.size());// 0
    		// 如果在迭代的过程中不使用迭代器的 remove()方法 
    		// 使用 集合的 remove()方法可以吗
    			// 当然不可以,在第一次循环的时候没问题,但是第二次循环的时候 it对应的集合已经不是原来的集合了
    			// 报错ConcurrentModificationException
    		/*
    		 	c.add(1);
    			c.add(2);
    			c.add(3);
    			it = c.iterator();// 需要重新指定 it
    			while(it.hasNext()) {
    				Object o = it.next();
    				c.remove(o);// 使用结合中的方法删除 // 报错ConcurrentModificationException
    			}
    			System.out.println(c.size()); // 0
    		 */
    	}
    }
    
    List集合详解

    List 是一个接口, 里面有自己规定的(独特的)方法

    public interface List<E> extends Collection<E>

    • 举例1-List集合中存储的元素有序可以重复

      import java.util.*;
      
      public class Test07 {
      	public static void main(String[] args) {
      		List list = new ArrayList();
      		list.add(2);
      		list.add(4);
      		list.add(3);
      		list.add(34);
      		// 遍历
      		Iterator it = list.iterator();
      		while(it.hasNext()) {
      			System.out.println(it.next());
      		}
      		// E get(int index) 获取对应下标的元素
      		System.out.println(list.get(3));
      	}
      }
      
    • 举例2-深入List集合

      • ArrayList集合底层是数组,数组是有下标的,所以ArrayList有很多自己的特性(关于下标的特性)

      • ArrayList集合底层默认初始化数组大小为 10 ,扩大之后的容量是原容量的 1.5 倍

      • Vector 集合底层默认初始化数组大小为10,扩大之后的容量是原容量的 2 倍

        如何优化 ArrayLIst 和 Vector?

        ​ 尽量减少扩容操作,因为扩容需要数组拷贝。一般推荐在创建集合的时候指定初始化数组的大小

      • 方法

        void add(int index, E element);
        Object get(int index);
        Object remove(int index);
        Object set(int index, Object element);
        List subList(int fromIndex, int toIndex)
        
      import java.util.*;
      
      public class Test08 {
      	public static void main(String[] args) {
      		List l = new ArrayList();
      		l.add(23);
      		l.add(123);
      		l.add(321);
      		l.add(69);
      		// 在下标为 1 的地方添加 555
      		l.add(1, 555);
      		// 将下标2的地方的数据更改为 100
      		l.set(2, 100);
      		// 获取第1个元素
      		System.out.println(l.get(0));
      		System.out.println("=======");
      		// 遍历(List 集合中特有的遍历方式)
      		for(int i=0; i<l.size(); i++) {
      			Object o = l.get(i);
      			System.out.println(o);
      		}
      	}
      }
      
Set对应的类及常用方法

Set 中存储的元素是无序不可重复的,存进去的顺序和取出来的顺序不一定一致。

HashSet 类实现了Set接口(HashSet 的底层时间上是一个 HashMap,见下图·java的HashSet源码)

HashMap底层是哈希表

SortedSet 接口继承了Set 接口,其存储的元素也是无需,不可重复的,但是存进去的元素可以按照元素的大小自动排序,TreeSet 类实现了 SortedSet 接口

hashSet的实现源码

  • 哈希表/散列表(较高的查找/删除/增加效率

    • 哈希表是数组和单向链表的结合

      hash表是数组和单向链表的结合

    • 哈希表的本质是一个数组,只不过这个数组中的每一个元素都是一个单向链表

      hash表是数组和单向链表的结合

    • 数组中每一个元素存储的是一个单向链表,单向链表中每一个节点存储的是:final int hash, Object key, Object value, Node<> next

      • hash 值是通过 key调用hashcode()方法得到的值,再通过hash算法得到的值

        如何通过key得到对应的hash值

      • 在数组中每一个单向链表中节点的hash值都是相同的,代表了数组的下标

      • hashMap中有一个方法用于查找对应的节点:Object get(Object key)

        public V get(Object key) {
                Node<K,V> e;
                return (e = getNode(hash(key), key)) == null ? null : e.value;
        }
        
      • hashMap中有一个添加元素的方法:void put(Object key, Object value)

        public V put(K key, V value) {
                return putVal(hash(key), key, value, false, true);
        }
        final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                           boolean evict) {
                Node<K,V>[] tab; Node<K,V> p; int n, i;
            	// tab = table
                if ((tab = table) == null || (n = tab.length) == 0)
                    n = (tab = resize()).length;
            	// hash 和 数组下标的对应关系:i = (n - 1) & hash
                if ((p = tab[i = (n - 1) & hash]) == null)
                    tab[i] = newNode(hash, key, value, null);// 新的单向链表
                else {// 已经存在的单向链表
                    Node<K,V> e; K k;
                    if (p.hash == hash &&
                        ((k = p.key) == key || (key != null && key.equals(k))))
                        e = p;
                    else if (p instanceof TreeNode)
                        e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
                    else {
                        for (int binCount = 0; ; ++binCount) {
                            if ((e = p.next) == null) {
                                p.next = newNode(hash, key, value, null);
                                if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                                    treeifyBin(tab, hash);
                                break;
                            }
                            if (e.hash == hash &&
                                ((k = e.key) == key || (key != null && key.equals(k))))
                                break;
                            p = e;
                        }
                    }
                    if (e != null) { // existing mapping for key
                        V oldValue = e.value;
                        if (!onlyIfAbsent || oldValue == null)
                            e.value = value;
                        afterNodeAccess(e);
                        return oldValue;
                    }
                }
                ++modCount;
                if (++size > threshold)
                    resize();
                afterNodeInsertion(evict);
                return null;
            }
        
        

散列表的数据结构

HashSet集合详解
  • HashSet实际上是一个HashMap,HashMap底层采用了哈希表数据结构
    • HashMap的初始容量是 16,缩放因子是 0.75
  • 哈希表又叫散列表。哈希表的底层是一个数组,这个数组的每一个元素是一个单向链表,每一个单向链表都有一个独一无二的hash值,代表了数组的下标
    • 在一个单向链表中每一个节点的hash值是相同的。
      • hash值实际上是 key 调用 hashCode 方法,再通过 hash function 得到的值。
  • 向hash 表中添加元素的过程:
    • 先调用被存储的 keyhashCode方法,经过 hash function 得到 hash
      • 如果在这个hash表中不存在这个 hash 值,则直接加入元素。
      • 如果该 hash 值已经存在,继续调用key之间的 equals 方法
        • 如果equals方法返回 false,则将该元素田间
        • 如果equals方法返回 true,则放弃添加该元素(元素不可重复,所以就不添加了)
import java.util.*;

public class Test09 {
	public static void main(String[] args) {
		Set s = new HashSet();
		s.add(1);
		s.add(1);
		s.add(188);
		s.add(100);
		s.add(74);
		s.add(85);
		
		// 遍历
		// 创建迭代器
		Iterator it = s.iterator();
		while(it.hasNext()) {
			System.out.println(it.next());
		}
	}
}
// 输出
1
100
85
74
188
  • 关于往Set集合里面添加元素

    • 存储在hashSet或者HashMap集合中Key部分的的元素,需要同时重写 hashCode()equals()方法
    import java.util.*;
    public class Test10 {
    		
    	public static void main(String[] args) {
    		Set s = new HashSet();
    		Employee e1 = new Employee("1000", "jack");
    		Employee e2 = new Employee("1000", "jack");
    		Employee e3 = new Employee("2000", "cook");
    		Employee e4 = new Employee("2000", "book");
    		Employee e5 = new Employee("4003", "barabase");
    		// 添加元素的时候,会先调用Employee里面的hashCode方法得到hash值,hash不一样往数组里面添加
    		// hash 一样,调用equals方法,返回false,插入到对应hash单向链表中
    		// 返回 true,不添加,所以要重写对应类里面的hashCode()方法和
    		s.add(e1);
    		s.add(e2);
    		s.add(e3);
    		s.add(e4);
    		s.add(e5);
    		
    		System.out.println(s.size());
    	}
    }
    
    class Employee{
    	String no;
    	String name;
    	public Employee(String no, String name) {
    		this.no = no;
    		this.name = name;
    	}
    	// 重写 Object 中的 hashCode
    	@Override
    	public int hashCode() {
    		return this.no.hashCode();//直接使用 String 类里面的hashCode方法
    	}
    	// 重写 Object中的equals方法
    	@Override
    	public boolean equals(Object obj) {
    		if(this == obj) {
    			return true;
    		}
    		if(obj instanceof Employee) {
    			Employee e = (Employee)obj;
    			return (this.no == e.no && this.name == e.name);
    		}
    		return false;
    	}
    }
    
SortedSet接口介绍
  • SortedSet是一个接口

    java.util.Set;
        java.util.SortedSet;//无需不可重复,但是可以按照元素大小自动排序 
        	java.util.TreeSet;
    
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.*;
    
    public class Test11 {
    	public static void main(String[] args) throws ParseException {
    		SortedSet ss = new TreeSet();
    		ss.add(10);
    		ss.add(22);
    		ss.add(12);
    		ss.add(34);
    		ss.add(28);
    		// 遍历
    		Iterator it = ss.iterator();
    		while(it.hasNext()) {
    			System.out.println(it.next());
    		}
    /* 输出
    10
    12
    22
    28
    34
    */
    		// 字符串
    		SortedSet strs = new TreeSet();
    		String s1 = "Jack";
    		String s2 = "Tom";
    		String s3 = "Jerry";
    		String s4 = "Pack";
    		strs.add(s1);
    		strs.add(s2);
    		strs.add(s3);
    		strs.add(s4);
    		it = strs.iterator();
    		while(it.hasNext()) {
    			System.out.println(it.next());
    		}
    /* 输出
    Jack
    Jerry
    Pack
    Tom
    */		
    		// 日期
    		String st1 = "2008-08-08";
    		String st2 = "2009-08-08";
    		String st3 = "2008-02-03";
    		String st4 = "2008-12-14";
    		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    		Date d1 = sdf.parse(st1);
    		Date d2 = sdf.parse(st2);
    		Date d3 = sdf.parse(st3);
    		Date d4 = sdf.parse(st4);
    		SortedSet times = new TreeSet();
    		times.add(d1);
    		times.add(d2);
    		times.add(d3);
    		times.add(d4);
    		// 遍历
    		it = times.iterator();
    		while(it.hasNext()) {
    			Object o = it.next();
    			if(o instanceof Date) {
    				Date t = (Date) o;
    				System.out.println(sdf.format(t));
    			}
    		}
    /* 输出
    2008-02-03
    2008-08-08
    2008-12-14
    2009-08-08
    */	
    	}
    }
    
    
    • Collection 里面只能存储引用类型

    • SortedSet里面存储的元素不重复,无需,但是会自动根据元素大小来排序

      • 为什么不同类型的数据(Integer, String, Date)都可以进行比较大小呢?

        因为他们都实现了 Compareable接口,实现了里面的 compareTo() 方法

  • SortedSet集合里面的元素是如何排序的?

    在上面的程序中,我们使用了Sun公司已经写好的Date类/String类型的数据存储到TreeSet集合中,发现可以直接排序,那么我们尝试以下往SortedSet中存储我们自己写的类会发生什么呢?

    import java.util.*;
    public class Test12 {
    	public static void main(String[] args) {
    		SortedSet ss = new TreeSet();
    		User u1 = new User(10);
    		User u2 = new User(13);
    		User u3 = new User(12);
    		User u4 = new User(15);
    		User u5 = new User(11);
    		ss.add(u1);
    		ss.add(u2);
    		ss.add(u3);
    		ss.add(u4);
    		ss.add(u5);
    		Iterator it = ss.iterator();
    		while(it.hasNext()) {
    			System.out.println(it.next());
    		}
    	}
    }
    class User{
    	int age;
    	public User(int age) {
    		this.age = age;
    	}
    	@Override
    	public String toString() {
    		return "User[age="+this.age+"]";
    	}
    	
    }
    
    
    // 编译成功,运行错误
    Exception in thread "main" java.lang.ClassCastException: com.test.collections.User cannot be cast to java.lang.Comparable
    	at java.util.TreeMap.compare(Unknown Source)
    	at java.util.TreeMap.put(Unknown Source)
    	at java.util.TreeSet.add(Unknown Source)
    	at com.test.collections.Test12.main(Test12.java:11)
    
    

    运行报 “类型转换错误” 的错误, 我们自己写的类不能转换成 java.lang.Comparable 类型,所以我们应该实现Comparable接口里面的方法

    所以说 凡是放在 SortedSet 里面的元素 必须 实现了Comparable接口里面的 compareTo() 方法

    import java.util.*;
    public class Test12 {
    	public static void main(String[] args) {
    		SortedSet ss = new TreeSet();
    		User u1 = new User(10);
    		User u2 = new User(13);
    		User u3 = new User(12);
    		User u4 = new User(15);
    		User u5 = new User(11);
    		ss.add(u1);
    		ss.add(u2);
    		ss.add(u3);
    		ss.add(u4);
    		ss.add(u5);
    		Iterator it = ss.iterator();
    		while(it.hasNext()) {
    			System.out.println(it.next());
    		}
    	}
    }
    class User implements Comparable{// 继承Comparable接口实现里面的方法
    	int age;
    	public User(int age) {
    		this.age = age;
    	}
    	@Override
    	public String toString() {
    		return "User[age="+this.age+"]";
    	}
    	// 实现Comparable 接口中的 compareTo方法
    	@Override
    	public int compareTo(Object o) {
    		
    		return this.age-((User)o).age;
    	}
    }
    

    这样就可以成功运行了,输出结构是按照年龄从小到大排序的

    User[age=10]
    User[age=11]
    User[age=12]
    User[age=13]
    User[age=15]
    
  • SortedSet集合做到排序还有另一种方式:java.util.Comparator

    • 单独编写一个比较器,传入到TreeSet对象中。
    • 比较推荐此类写法,因为不需要改变存入SortedSet内元素的类,具有更低的耦合性

    单独编写比较器,传入到TreeSet构造函数里面

    
    import java.util.*;
    
    public class Test13 {
    	public static void main(String[] args) {
    		@SuppressWarnings("unchecked")
    		SortedSet ss = new TreeSet(new ProductComparator());
    		Product p1 = new Product(32);
    		Product p2 = new Product(12);
    		Product p3 = new Product(24);
    		Product p4 = new Product(13);
    		ss.add(p1);
    		ss.add(p2);
    		ss.add(p3);
    		ss.add(p4);
    		// 遍历
    		Iterator it = ss.iterator();
    		while(it.hasNext()) {
    			System.out.println(it.next());
    		}
    	}
    }
    
    class Product{
    	double price;
    	public Product(double price) {
    		this.price = price;
    	}
    	@Override
    	public String toString() {
    		return "Product["+this.price+"]";
    	}
    	
    }
    class ProductComparator implements Comparator{
    
    	@Override
    	public int compare(Object o1, Object o2) {
    		if(o1 instanceof Product && o2 instanceof Product) {
    			double price1 = ((Product)o1).price;
    			double price2 = ((Product)o2).price;
    			if(price1 == price2) {
    				return 0;
    			}else if(price1 > price2) {
    				return 1;
    			}else {
    				return -1;
    			}
    		}
    		return 0;
    	}
    	
    }
    

    也可以使用匿名内部类

    import java.util.*;
    
    public class Test13 {
    	public static void main(String[] args) {
    		@SuppressWarnings("unchecked")
    		SortedSet ss = new TreeSet(new Comparator() {// 匿名内部类
    			@Override
    			public int compare(Object o1, Object o2) {
    				double price1 = ((Product)o1).price;
    				double price2 = ((Product)o2).price;
    				if(price1 == price2) {
    					return 0;
    				}else if(price1 > price2) {
    					return 1;
    				}else {
    					return -1;
    				}
    			}
    		});
    		Product p1 = new Product(32);
    		Product p2 = new Product(12);
    		Product p3 = new Product(24);
    		Product p4 = new Product(13);
    		ss.add(p1);
    		ss.add(p2);
    		ss.add(p3);
    		ss.add(p4);
    		// 遍历
    		Iterator it = ss.iterator();
    		while(it.hasNext()) {
    			System.out.println(it.next());
    		}
    	}
    }
    
    class Product{
    	double price;
    	public Product(double price) {
    		this.price = price;
    	}
    	@Override
    	public String toString() {
    		return "Product["+this.price+"]";
    	}
    	
    }
    

    输出结果:// 已经排序了

    Product[12.0]
    Product[13.0]
    Product[24.0]
    Product[32.0]
    

集合中 Map 的继承结构图(重要)

  • MapCollection 没有关系

Map的继承结构图

  • Map是一个父接口,HashMap类和Hashtable类实现了Map接口,SortedMap接口继承Map接口,TreeMap类实现了SortedMap接口

  • HashMap中的 key 要重写 hashCode()equals()方法

  • SortedMap或者TreeMapkey要实现Comparable接口中的compareTo() 方法。或者单独写一个Comparator比较器

  • Properties 类继承自 Hashtable,是一个属性类,也是以key-value的方式存储元素,但是key-value只能是字符串

Map集合中常用的方法
  • 存储在Map集合中的 key 部分的元素需要同时重写 hashCode()equals()方法。
void clear();
boolean	isEmpty();
int	size();

V	get(Object key);
V	put(K key, V value);	// 注意:map中如果key重复了,value将会覆盖key对应的值

boolean	containsKey(Object key);
boolean	containsValue(Object value);

V	remove(Object key);

Set keySet();
Collection values();
Set entrySet()
import java.util.*;

public class Test14 {
	public static void main(String[] args) {
		// 1.创建集合
		Map persons = new HashMap();
		// 2. 存储键值对
		persons.put("10000", "Javk");
		persons.put("10001", "Cook");
		persons.put("10002", "Book");
		persons.put("10003", "Kook");
		persons.put("10004", "Pook");
		persons.put("10002", "BooJ");
		// 3. 判断键值对的个数
		// Map 中的key是无序的不可重复的
		System.out.println(persons.size());// 5
		// 4. 判断Map中是否包含某key
		System.out.println(persons.containsKey("10003"));// true
		// 5. 判断Map中是否包含某value
		System.out.println(persons.containsValue("Javk"));// true
		System.out.println(persons.containsValue("Book"));// false
		// 6. 通过 key 获取value
		String key = "10002";
		Object value = persons.get(key);
		System.out.println(value);// BooJ  // BooJ将Book覆盖掉了
		// 7. 通过key删除键值对
		persons.remove("10004");
		System.out.println(persons.size());// 4
		// 8. 获取所有的value
		Collection values = persons.values();
		Iterator it = values.iterator();
		while(it.hasNext()) {
			System.out.println(it.next());
		}
		// 9. 获取所有的 key
		Set keys = persons.keySet();
		it = keys.iterator();
		while(it.hasNext()) {
			Object id = it.next();
			Object name = persons.get(id);
			System.out.println(id+"-->"+name);
		}
		// 10. entrySet
		Set entrySet = persons.entrySet();
		it = entrySet.iterator();
		while(it.hasNext()) {
			System.out.println(it.next());
		}
	}
}

Hashtable & Properties常用方法介绍
  • Hashtable 是线程安全的,但是效率低

    • 初始化容量是 11, 加载因子是 0.75
    • HashMap的初始化容量是 16, 加载因子是 0.75
  • Properties 是一个属性类,继承自 Hashtable类,存储的key-value 只能是字符串

    import java.util.*;
    
    public class Test15 {
    	public static void main(String[] args) {
    		// 1.创建属性类对象
    		Properties p = new Properties();
    		// 2. 存储元素
    		p.setProperty("driver", "oracle.jdbc.driver.OracleDriver");
    		p.setProperty("username", "tailor");
            // 注意 key 不能重复,如果重复则覆盖原来的value
            p.setProperty("username", "tailor95");
    		p.setProperty("password", "balabala");
    		p.setProperty("url", "jdbc:oracle:thin:@192.168.1.100:1512:balabala");
    		
    		// 3. 通过 key 获取 value
    		String v1 = p.getProperty("driver");
    		String v2 = p.getProperty("username");
    		String v3 = p.getProperty("password");
    		String v4 = p.getProperty("url");
    		
    		System.out.println(v1);
    		System.out.println(v2);
    		System.out.println(v3);
    		System.out.println(v4);
    	}
    }
    

    输出:

    oracle.jdbc.driver.OracleDriver
    tailor95
    balabala
    jdbc:oracle:thin:@192.168.1.100:1512:balabala
    
SortedMap & TreeMap
  • SortedMapkey 的特点:无序不重复,但是存进去的元素可以按照大小自动排序

    • 如果想自动排序,key部分的元素需要:或者实现 Comparable 接口, 或者单独实现一个比较器 Comparator
      • 下面代码是 实现了 Comparable接口
    import java.util.*;
    
    public class Test16 {
    	public static void main(String[] args) {
    		// Map 中的key 存储 product, value存储 重量
    		// 1. 创建 map集合
    		SortedMap sm = new TreeMap();
    		// 2. 准备 对象
    		ProductMap p1 = new ProductMap("西瓜", 0.5);
    		ProductMap p2 = new ProductMap("苹果", 3.0);
    		ProductMap p3 = new ProductMap("香蕉", 2.0);
    		ProductMap p4 = new ProductMap("橘子", 1.5);
    		// 3. 添加到map中
    		sm.put(p1, 8.0);
    		sm.put(p2, 5.0);
    		sm.put(p3, 2.0);
    		sm.put(p4, 3.0);
    		// 4. 遍历
    		Iterator it = sm.keySet().iterator();
    		while(it.hasNext()) {
    			Object p = it.next();
    			Object w = sm.get(p);
    			System.out.println(p+"===>"+w);
    		}
    	}
    }
    
    class ProductMap implements Comparable{// 实现 Comparable接口
    	String name;
    	double price;
    	public ProductMap(String name, double price) {
    		this.name = name;
    		this.price = price;
    	}
    	// 重写 toString
    	@Override
    	public String toString() {
    		return "[Product:"+this.name+"--->"+this.price+"]";
    	}
    	@Override
    	public int compareTo(Object o) {
    		double price1 = this.price;
    		double price2 = ((ProductMap)o).price;
    		if(price1 > price2) {
    			return 1;
    		}else if(price1 < price2) {
    			return -1;
    		}else return 0;
    	}
    	
    }
    
    • 下面代码是单独实现了一个比较器Comparator(使用了匿名内部类)

      package com.test.collections;
      
      import java.util.*;
      
      public class Test16 {
      	public static void main(String[] args) {
      		// Map 中的key 存储 product, value存储 重量
      		// 1. 创建 map集合
      //		SortedMap sm = new TreeMap();
      		SortedMap sm = new TreeMap(new Comparator() {// 单独实现了一个比较器
      
      			@Override
      			public int compare(Object o1, Object o2) {
      				double price1 = ((ProductMap)o1).price;
      				double price2 = ((ProductMap)o2).price;
      				if(price1 > price2) {
      					return 1;
      				}else if(price1 < price2) {
      					return -1;
      				}else return 0;
      			}
      			
      		});
      		// 2. 准备 对象
      		ProductMap p1 = new ProductMap("西瓜", 0.5);
      		ProductMap p2 = new ProductMap("苹果", 3.0);
      		ProductMap p3 = new ProductMap("香蕉", 2.0);
      		ProductMap p4 = new ProductMap("橘子", 1.5);
      		// 3. 添加到map中
      		sm.put(p1, 8.0);
      		sm.put(p2, 5.0);
      		sm.put(p3, 2.0);
      		sm.put(p4, 3.0);
      		// 4. 遍历
      		Iterator it = sm.keySet().iterator();
      		while(it.hasNext()) {
      			Object p = it.next();
      			Object w = sm.get(p);
      			System.out.println(p+"===>"+w);
      		}
      	}
      }
      
      class ProductMap{
      	String name;
      	double price;
      	public ProductMap(String name, double price) {
      		this.name = name;
      		this.price = price;
      	}
      	// 重写 toString
      	@Override
      	public String toString() {
      		return "[Product:"+this.name+"--->"+this.price+"]";
      	}
      
      }
      

      输出:可见key按照价格排了序

      [Product:西瓜--->0.5]===>8.0
      [Product:橘子--->1.5]===>3.0
      [Product:香蕉--->2.0]===>2.0
      [Product:苹果--->3.0]===>5.0
      

关于集合工具类Collections的用法

  • java.util.Collections 是一个类,是集合的工具类,可以实现对集合的操作

    -java.util.Collection 是一个接口

  • Collections 里面的 sort方法,实现集合内的元素的排序

    static void	sort(List list)
    
    • 示例1

      import java.util.*;
      
      public class Test17 {
      	public static void main(String[] args) {
      		// 1. 创建List集合
      		List l = new ArrayList();
      		// 2. 添加元素
      		l.add(10);
      		l.add(20);
      		l.add(14);
      		l.add(23);
      		// 3. 遍历
      		for(int i=0; i<l.size(); i++) {
      			System.out.println(l.get(i));
      		}
      		// 调用 Collcetions类中的 sort方法排序
      		Collections.sort(l);
      		// 遍历
      		System.out.println("=========");
      		for(Iterator it = l.iterator();it.hasNext();) {
      			System.out.println(it.next());
      		}
      	}
      }
      
      

      输出:

      10
      20
      14
      23
      =========
      10
      14
      20
      23
      
    • Collcetions 类中的 sort() 方法怎么对集合中的元素进行排序?

      • Set集合转换为List类型

      Set类型转换为List类型-通过ArrayList构造方法

      import java.util.*;
      
      public class Test18 {
      	public static void main(String[] args) {
      		// 1. 创建set集合
      		Set s = new HashSet();
      		// 2. 添加元素
      		s.add(12);
      		s.add(10);
      		s.add(21);
      		s.add(32);
      		// 3. 创建List###########就是在这操作的###############
      		List list = new ArrayList(s);
      		// 4. 调用Collections工具类中的sort()方法进行排序
      		Collections.sort(list);
      		// 5. 遍历
      		Iterator it = list.iterator();
      		while(it.hasNext()) {
      			System.out.println(it.next());
      		}
      	}
      }
      
      
    • 是不是List中存储的所有类型的元素都可以调用Collections类中的sort方法?

      • 当然不是,元素要么实现Comparable接口,要么单独写一个比较器Comparator
        • 下面代码运行错误:java.lang.ClassCastException: Person cannot be cast to java.lang.Comparable
          • 需要实现 Comparable接口
      import java.util.*;
      
      public class Test19 {
      	public static void main(String[] args) {
      		// 创建集合
      		List list = new ArrayList();
      		// 准备数据
      		Person p1 = new Person(); 
      		Person p2 = new Person(); 
      		Person p3 = new Person(); 
      		Person p4 = new Person();
      		// 添加数据
      		list.add(p1);
      		list.add(p2);
      		list.add(p3);
      		list.add(p4);
      		// 调用Collections类中的sort方法
      		Collections.sort(list);
      		// 遍历输出
      		Iterator it = list.iterator();
      		while(it.hasNext()) {
      			System.out.println(it.next());
      		}
      	}
      }
      
      class Person{
          // 没有实现 Comparable
      }
      
      • 实现 Comparable接口

        package com.test.collections;
        import java.util.*;
        
        public class Test19 {
        	public static void main(String[] args) {
        		// 创建集合
        		List list = new ArrayList();
        		// 准备数据
        		Person p1 = new Person(); 
        		Person p2 = new Person(); 
        		Person p3 = new Person(); 
        		Person p4 = new Person();
        		// 添加数据
        		list.add(p1);
        		list.add(p2);
        		list.add(p3);
        		list.add(p4);
        		// 调用Collections类中的sort方法
        		Collections.sort(list);
        		// 遍历输出
        		Iterator it = list.iterator();
        		while(it.hasNext()) {
        			System.out.println(it.next());
        		}
        	}
        }
        
        class Person implements Comparable{
        
        	@Override
        	public int compareTo(Object o) {
        		return 0;
        	}
        	
        }
        
    • Collections 类中的 synchronizedList(List list)方法可以将线程不安全的 ArrayList转换成线程安全的

      import java.util.*;
      public class Test20 {
      	public static void main(String[] args) {
      		List list = new ArrayList();
      		Collections.synchronizedList(list);
      		// 这之后,list就是线程安全的了
      	}
      }
      
      

泛型初步

主要介绍jdk5.0的新特性: 泛型(属于编译期的概念)

为什么引入泛型
  • 可以统一集合中的数据类型
  • 可以减少强制类型转换
泛型语法如何实现
  • 泛型是编译阶段的语法,在编译阶段统一集合中的数据类型

    • List使用泛型
    import java.util.*;
    
    public class Test21 {
    	public static void main(String[] args) {
    		// 创建泛型集合// 创建String类型的集合
    		List<String> list = new ArrayList<String>();
    		// 添加元素
    		//list.add(1);// 编译错误 list中存储的是String类型,所以不能添加 Integer 类型的数据
    		list.add("Jack");
    		list.add("Tom");
    		list.add("Jerry");
    		list.add("Snobe");
    		// 遍历泛型集合
    		Iterator<String> it = list.iterator();
    		while(it.hasNext()) {
    			String s = it.next();
    			System.out.println(s);
    		}
    	}
    }
    
    • Map使用泛型

      import java.util.*;
      public class Test22 {
      	public static void main(String[] args) {
      		// 创建集合
      		Map<String, Integer> maps = new HashMap<String, Integer>();
      		// 添加元素
      		maps.put("苹果", 23);
      		maps.put("橘子", 18);
      		maps.put("香蕉", 3);
      		maps.put("西瓜", 64);
      		// 遍历
      		// 得到所有的key
      		Set<String> keys = maps.keySet();
      		Iterator<String> it = keys.iterator();
      		while(it.hasNext()) {
      			String key = it.next();
      			Integer i = maps.get(key);
      			System.out.println(key+"--->"+i);
      		}
      	}
      }
      
      
    • SortedSet 使用泛型

      • 注意实现 Comparable 接口
      import java.util.*;
      public class Test23 {
      	public static void main(String[] args) {
      		// 创建集合
      		SortedSet<Manager> ss = new TreeSet<Manager>();
      		// 准备数据
      		Manager m1 = new Manager(23.0);
      		Manager m2 = new Manager(22.0);
      		Manager m3 = new Manager(23.4);
      		Manager m4 = new Manager(12.0);
      		Manager m5 = new Manager(18.5);
      		ss.add(m1);
      		ss.add(m2);
      		ss.add(m3);
      		ss.add(m4);
      		ss.add(m5);
      		// 遍历数据
      		Iterator<Manager> it = ss.iterator();
      		while(it.hasNext()) {
      			it.next().work();
      		}
      	}
      }
      class Manager implements Comparable<Manager>{ // 实现 Comparable接口
      	double sal;
      	public Manager(double sal) {
      		this.sal = sal;
      	}
      	public void work() {
      		System.out.println("工作,一个月"+sal+"元");
      	}
      	@Override
      	public String toString() {
      		return sal+"";
      	}
      	@Override
      	public int compareTo(Manager o) {
      		if(this.sal > o.sal) {
      			return 1;
      		}else if(this.sal < o.sal) {
      			return -1;
      		}
      		return 0;
      	}
      
      	
      }
      
自定义泛型

public class Test24 {
	public static void main(String[] args) {
		MyClass<String> mc = new MyClass<String>();
//		mc.m1(100);// 编译错误
		mc.m1("Jack");;
	}
}
class MyClass<T>{
	void m1(T t) {
		System.out.println(t);
	}
}
泛型的优点和缺点
  • 优点:同一类型,减少强制转换
  • 缺点:只能存储一种类型
forEach

关于增强 for 循环(JDK5.0新特性)

语法:

for(类型 变量:数组名/集合名){}
  • 集合如果想使用 **增强for**循环这种语法,集合需要使用 泛型

    • 不使用泛型也可以,但是for里面的变量类型应该是 Object
    import java.util.*;
    
    public class Test25 {
    	public static void main(String[] args) {
    		int[] a= {1,2,3,4};
    		for(int e: a) {
    			System.out.println(e);
    		}
    		System.out.println("==========");
    		// 集合
    		Set<String> s = new HashSet<String>();
    		s.add("张三");
    		s.add("李四");
    		s.add("王五");
    		s.add("赵六");
    		// 遍历
    		for(String name:s) {
    			System.out.println(name);
    		}
    	}
    }
    
  • 增强for循环的缺点:

    • 没有下标

end

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tailor_long

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值