java集合

java集合

(1)、什么是集合?有什么用?
集合实际上是一个容器,比如数组。可以用来容纳其他类型的数据。

(2)、为什么说集合在开发中使用较多?
集合是一个容器,是一个载体,可以一次容纳多个对象。在实际开发中,假设连接数据库,数据库当中有10条记录,那么假设把这10条记录查询出来,在java中会将10条数据封装成10个java对象,然后将10个java对象放到某一个集合当中,将集合传到前端,然后遍历集合,将一个数据一个数据展现出来。

(3)、集合不能直接存储基本数据类型,另外集合也不能直接存储java对象,集合当中存储的都是java对象的内存地址。(或者说集合中存储的是引用)
list.add(100);//自动装箱Integer
注意:

  • 集合在java中本身是一个容器,是一个对象。

  • 集合中任何时候存储的都是“引用”。

(4)、在java中每一个不同的集合,底层会对应不同的数据结构。网不同的集合中存储元素,等于将数据放到了不同的数据结构中。什么是数据结构?数据存储的结构就是数据结构。不同的数据结构,数据存储方式不同。例如:
数组、二叉树、链表、哈希表…
new ArrayList();创建一个集合,底层是数组
new LinkList();创建一个集合对象,底层是链表
new TreeSet();创建一个集合对象,底层是二叉树

(5)、最好能将集合的继承结构图背会!
总结:

1)、ArrayList,底层是数组
2)、LinkList,底层是双向链表
3)、Vector,底层是数组,线程安全的,效率低,使用较少
4)、HashSet,底层是HashMap,放到HashSet集合中的元素等同于放到 HashMap集合key部分了
5)、TreeSet,底层是TreeMap,放到TreeSet集合中的元素等同于放到TreeMap集合key部分了
6)、HashMap,底层是哈希表
7)、Hashtable,底层是哈希表,只不过线程安全,效率较低,使用较少。
8)、Properties,是线程安全的, 并且key和value只能存储字符串String
9)、TreeMap,底层是二叉树,TreeMap集合的key可以自动按照大小顺序排序

在这里插入图片描述
在这里插入图片描述

(6)、在java中集合分为两大类:

  • 一类是单个方式存储元素:

     单个方式存储元素,这一类集合中超级父接口:java.util.Collection;
    
  • 一类是以键值对的方式存储元素:

     		以键值对的方式存储元素,这一类集合中超级父接口:
     		java.util.Map;
    

(7)、map.put(k,v)实现原理:

第一步:先将k,v封装到Node对象当中。
第二步:底层会调用K的hashCode()方法的出hash值,然后通过哈希函数/哈希算法,将hash值转换成数组的下标,下标位置上如果没有任何元素,就把Node添加到这个位置上了。如果说下标对应的位置上有链表,此时会拿着k和链表上每一个节点中的k进行equals,如果所有的equals方法返回的都是false,那么这个新节点将被添加到链表的末尾,如果其中有一个equals返回了true,那么这个节点的value将会被覆盖。

map.get(k)实现原理:

先调用k 的hashCode()方法得出哈希值,通过哈希算法转换成数组下标,通过数组下标快速定位到某个位置上,如果这个位置上什么也没有,返回null,如果这个位置上有单向链表,那么会拿着参数k和单向链表上的每个节点中的k进行equals,如果所有equals方法返回false,那么get方法返回null,只要有其中一个返回true,那么此时这个节点的value就是我们要找的value,get方法最终返回这个要找的value。

**以下分别介绍上面的几种集合类型
一、Collection
(1)关于java.util.Collection接口中常用的方法

package javaCoreTest;

import java.util.ArrayList;
import java.util.Collection;

/*
 * 关于java.util.Collection接口中常用的方法
 * 1、Collection中能存放什么元素?
 * 		没有使用“泛型”之前,Collection中可以存储Object的所有子类型
 * 		使用了“泛型”之后,Collection中只能存储某个具体的类型
 * 		【集合中不能直接存储基本数据类型,也不能存储java对象,只是存储java对象的内存地址】
 * 2、Collection中的常用方法
 * 		boolean add(Object e)	向集合中添加元素
 * 		int size()				获取集合中元素个数
 * 		void clear()			清空集合
 * 		boolean contains(Object o)判断当前集合中是否包含元素o,包含为true,不包含为false
 * 		boolean remove(Object o)删除集合中的某个元素
 * 		boolean isEmpty()		判断该集合中元素的个数是否为空
 * 		Object[] toArray()		把集合转换成数组
 * 
 */
public class CollectionTest01 {

	public static void main(String [] args) {
		//创建一个集合对象
		//Collection c = new Collection ();//接口是抽象的,无法实例化、
		
		//多态
		Collection c = new ArrayList();
		
		//1.boolean add(Object e)	向集合中添加元素
		c.add(new Object());
		c.add(1200);//自动装箱,实际上是放进去了一个对象的内存地址。Integer i = new Integer(1200);
		c.add(3.14);//自动装箱
		c.add(new Student());
		c.add(true);//自动装箱
		
		//2.int size()	获取集合中元素个数
		System.out.println("集合中的元素个数:" + c.size());//5
		
		//3.void clear()	清空集合
		c.clear();
		System.out.println("集合中的元素个数:" + c.size());//0
		
		//再向集合中添加新的元素
		c.add("hello");
		c.add("java");
		c.add("钢铁侠");
		c.add("绿巨人");
		c.add("迪迦奥特曼");
		
		//4.boolean contains(Object o)判断当前集合中是否包含元素o
		boolean bo1 = c.contains("java");
		System.out.println(bo1);//true
		System.out.println( c.contains("c++"));//false
		
		System.out.println("集合中的元素个数:" + c.size());//5
		
		//5.boolean remove(Object o)删除集合中的某个元素
		c.remove("java");
		System.out.println("集合中的元素个数:" + c.size());//4
		
		//6.boolean isEmpty()  判断该集合中元素的个数是否为空
		System.out.println(c.isEmpty());//false
		c.clear();
		System.out.println(c.isEmpty());//true
		
		//再向集合中添加新的元素
		c.add("hello");
		c.add("java");
		c.add("钢铁侠");
		c.add("绿巨人");
		c.add("迪迦奥特曼");
				
		//7.(了解)Object[] toArray()	把集合转换成数组
		Object [] obj = c.toArray();
		for(int i = 0; i < obj.length; i++) {
			System.out.println(obj[i]);//hello java 钢铁侠 绿巨人 迪迦奥特曼
		}
	}
}

class Student{
	
}

(2)List接口

package javaCoreTest;

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

/*
 * 测试List接口中常用的方法:
 * 1.List集合存储元素特点:有序可重复
 * 
 * 2.List既然是Collection接口的子接口,那么肯定List接口有自己“特色”的方法:
 * 	以下列出List接口特有的常用的方法:
 * 		void add(int index, Object element)  在列表的指定位置插入指定元素(第一个 参数是下标)
 * 		Object get(int index)  根据下标获取元素
 * 		int indexOf(Object o)  获取指定对象第一次出现处的索引
 * 		int lastIndexOf(Object o) 获取指定对象最后一次出现处的索引
 * 		Object remove(int index) 删除指定位置的元素
 * 		Object set(int index, Object element) 修改指定位置的元素
 */
public class ListTest01 {

	public static void main(String [] args) {
		//创建List集合
		List list = new ArrayList();
		
		//添加元素
		list.add("A");
		list.add("B");
		list.add("C");
		list.add("D");
		list.add("E");
		
		//1.void add(int index, Object element)  在列表的指定位置插入指定元素(第一个 参数是下标)
		//这个方法使用不多,因为对于ArrayList集合来说效率比较低
		list.add(1, 100);
		
		//迭代
		Iterator it = list.iterator();
		while(it.hasNext()) {
			System.out.println(it.next());
		}
		
		//2.Object get(int index)  根据下标获取元素
		System.out.println(list.get(1));//100
		
		//自己比较特殊的遍历方式
		//通过下标遍历【List集合有而Set没有】
		for(int i = 0; i < list.size(); i++) {
			System.out.println(list.get(i));
		}

		//3.int indexOf(Object o)  获取指定对象第一次出现处的索引
		System.out.println(list.indexOf(100));//1
		
		//4.int lastIndexOf(Object o)  获取指定对象最后一次出现处的索引
		System.out.println(list.lastIndexOf(100));//1
		
		//5.Object remove(int index) 删除指定位置的元素
		list.remove(1);
		System.out.println(list.size());//5
		
		//6.Object set(int index, Object element) 修改指定位置的元素
		list.set(2, "money");
		for(int i = 0; i < list.size(); i++) {
			System.out.println(list.get(i));
		}
	}
	
}

(3)集合迭代/遍历

package javaCoreTest;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;

/**
 *集合迭代/遍历专题 
 */

/*
 * 关于集合元素的remove
 * 当集合的结构发生改变时,迭代器必须重新获取,如果还是用以前老的迭代器
 * 会出现异常:java.util.ConcurrentModificationException
 * 
 * 在迭代集合元素的过程中,不能调用集合对象的remove方法,删除元素:
 * c.remove();//不能这样
 *在迭代的过程中,一定要使用迭代器Iterator的remove方法,
 *删除元素,不要使用集合自带的remove方法
 */

public class CollectionTest02 {

	public static void main(String [] args) {
		//注意:以下讲解的遍历/迭代方式是所有Collection通用的一种方式
		//在Map集合中不能用。在所有的Collection以及子类中使用
		//创建集合对象
		Collection c = new ArrayList();
		
		//如果在此处获取迭代器,指向的是集合中没有元素状态下的迭代器
		//注意:集合结构只要发生改变,迭代器必须重新获取
		//Iterator it = c.iterator();
		
		
		//添加新元素
		c.add("abc");
		c.add("def");
		c.add(100);
		c.add(new Object());
		c.add(100);
		
		//对集合Collection进行遍历/迭代
		//第一步:获取集合对象的迭代器对象Iterator
		//迭代器最初并没有指向第一个元素
		Iterator it = c.iterator();
		
		//第二步:通过以上获取的迭代器对象开始迭代/遍历集合
		/*
		 * 以下两个方法是迭代器对象Iterator中的方法:
		 * boolean hasNext()如果仍有元素可以迭代,则返回true。
		 * Object next() 返回迭代的下一个元素
		 */
	
		while(it.hasNext()) {
			System.out.println(it.next());//输出有序可重复
			
			//删除元素之后集合的结构发生变化,应该重新获取迭代器
			//但是下一次循环的时候并没有重新获取迭代器,所有会出现异常
			//c.remove(it.next());
			//可以使用迭代器删除
			it.remove();//删除的一定是迭代器指向的当前元素
		}
		
		//HashSet集合
		Collection c1 = new HashSet();
		
		c1.add(100);
		c1.add(90);
		c1.add(100);
		c1.add(0);
		c1.add(20);
		c1.add(100);
		c1.add(5000);
		
		Iterator it1 = c1.iterator();
		
		while(it1.hasNext()) {
			System.out.println(it1.next());//无序不可重复
			/*0
			100
			20
			5000
			90*/

		}
	}
}

(4)深入Collection集合的contains方法

package javaCoreTest;

import java.util.ArrayList;
import java.util.Collection;

/*
 *深入Collection集合的contains方法:
 *	boolean contains(Object o)
 *		判断集合中是否包含某个对象o
 *		如果包含返回true,如果不包含返回false
 *
 * contains方法的底层是怎么判断集合中是否包含某个元素的呢?
 * 		调用了equals方法进行比对
 */
public class CollectionTest03 {

	public static void main(String [] args) {
		//创建集合对象
		Collection c = new ArrayList();
		
		//向集合中存储元素
		String s1 = new String ("abc");
		c.add(s1);
		
		String s2 = new String ("def");
		c.add(s2);
		
		//新建String对象
		String x = new String ("abc");
		//c集合中是否包含x?
		System.out.println(c.contains(x));//true
	}
}

(5)测试contains、remove方法

package javaCoreTest;
import java.util.*;

//测试contains、remove方法

public class CollectionTest04 {

	public static void main(String [] args) {
		//创建集合对象
		Collection c = new ArrayList();
		User u1 = new User("jack");
		
		c.add(u1);
		
		User u2 = new User("jack");
		
		//没有重写equals之前,这个结果是false
		//因为比较的是内存地址
		//System.out.println(c.contains(u2));//false
		
		//重写equals方法之后,比较是内容
		System.out.println(c.contains(u2));//true
		
		c.remove(u2);
		//如果重写了equals方法,删除u2会使集合中的u1被清除掉,如果不写equals方法则不行
		System.out.println(c.size());//0
	}
}

class User{
	private String name;
	
	public User() {
		
	}
	
	public User(String name) {
		this.name = name;
	}
	
	public boolean equals(Object obj) {
		if(obj == null || !(obj instanceof User))return false;
		if(obj == this)return true;
		
		User u = (User)obj;
		
		return u.name.equals(this.name);
	}
}

(6)ArrayList

package javaCoreTest;

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

/*
 * ArrayList集合:
 * 		1、默认初始化容量是10
 * 		2、集合底层是一个Object[]数组
 * 		3、构造方法:
 * 			new ArrayList();
 * 			new ArrayList(20);
 * 		4、ArrayList集合的扩容:
 * 			原容量的1.5倍
 * 			ArrayList集合底层是数组,怎么优化?
 * 				尽可能的减少扩容,因为数组扩容效率较低,建议在
 * 				使用ArrayList集合的时候预估计元素的个数,
 * 				给定一个初始化容量。
 * 		5、数组优点:检索效率比较高(每个元素占用空间大小相同,内存地址是连续的,知道首元素内存地址,然后知道下标,通过数学表达式计算出元素的内存地址,所以检索效率最高)
 * 		6、数组缺点:随机增删元素效率比较低
 * 			注意:向数组末尾添加元素,效率很高,不受影响。
 * 		7、面试官经常会问:这么多集合,你用哪个集合最多?
 * 			ArrayList集合。因为往数组末尾添加元素,效率不受影响。
 * 			另外,我们检索/查找某个元素的操作比较多。
 */
public class ArrayListTest01 {

	public static void main(String [] args) {
		
		//默认初始化容量是10
		List list = new ArrayList();
		//集合的size()方法是获取当前集合中元素的个数,不是获取集合的容量
		System.out.println(list.size());//0
		
		//指定初始化容量
		List list1 = new ArrayList(20);
		//集合的size()方法是获取当前集合中元素的个数,不是获取集合的容量
		System.out.println(list1.size());//0
	}
}
package javaCoreTest;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;

/*
 * 集合ArrayList的构造方法
 */

public class ArrayListTest02 {

	public static void main(String [] args) {
		
		//默认初始化容量10
		List list1 = new ArrayList();
		
		//指定初始化容量为100
		List list2 = new ArrayList(100);
		
		//创建一个HashSet集合
		Collection c = new HashSet();
		c.add(100);
		c.add(200);
		c.add(900);
		c.add(50);
		
		//通过这个构造方法可以将HashSet集合转换成List集合
		List list3 = new ArrayList(c);
		for(int i = 0; i < list3.size(); i++) {
			System.out.println(list3.get(i));//
		}
		
	}
}

(7)Linkedlist

package javaCoreTest;

import java.util.LinkedList;
import java.util.List;

/*
 * *链表的优点:
 * 由于链表上的元素在空间存储上内存地址不连续,所以随机增删元素的时候不会有
 * 大量元素位移,因此随机增删效率较高。在以后的开发中,如果遇到随机增删集合中
 * 元素的业务比较多时,建议使用Linkedlist
 * 
 * *链表的缺点:
 * 不能通过数学表达式计算被查找元素的内存地址,每一次查找都是从头节点开始
 * 遍历,直到找到为止,所以LinkedList集合检索/查找的效率较低
 */

public class LinkedListTest01 {

	/*
	 * LinkedList 集合底层也是有下标的。
	 * 注意:ArrayList之所以检索效率比较高,不是单纯因为下标的原因,是因为底层数组发挥作用
	 * LinkedList集合照样有下标,但是检索/查找某个元素的时候效率比较低,因为只能从头结点开始一个个地遍历
	 */
	public static void main(String [] args) {
		List list = new LinkedList();
		
		list.add("a");
		list.add("b");
		list.add("c");
		list.add("e");
		
		for(int i = 0; i < list.size(); i++) {
			System.out.println(list.get(i));
		}
	}
}

(8) HashSet

package javaCoreTest;

import java.util.HashSet;
import java.util.Set;

/*
 * HashSet:无序不可重复
 */

public class HashSetTest01 {

	public static void main(String [] args) {
		//创建集合
		Set<Integer> set = new HashSet<>();
		
		//添加元素
		set.add(1);
		set.add(2);
		set.add(3);
		set.add(4);
		set.add(5);
		set.add(6);
		set.add(3);
		
		//迭代
		for(Integer i : set) {
			System.out.println(i);
		}
		
	}
}

(9)TreeSet

package javaCoreTest;

import java.util.Set;
import java.util.TreeSet;

/*
 * TreeSet集合存储元素特点:
 * 		无序不可重复,但是存储的元素可以自动按照大小顺序排序!
 * 		称为:可排序集合
 * 
 * 这里的无序指:存进去的顺序和取出的顺序不同,并且没有下标
 */

public class TreeSetTest01 {

	public static void main(String [] args) {
		//创建集合对象
		Set<Integer> set = new TreeSet<>();
		
		//添加元素
		set.add(1);
		set.add(2);
		set.add(1);
		set.add(4);
		set.add(2);
		set.add(8);
		set.add(5);
		set.add(0);
		
		//迭代
		for(Integer i : set) {
			System.out.println(i);
		}
	}
}

(10) Vector

package javaCoreTest;

import java.util.*;

/*
 * Vector:
 * 1、底层是一个数组
 * 2、初始化容量:10
 * 3、扩容之后是原容量的2倍
 * 		10 --> 20 --> 40 --> 80
 * 4、ArrayList集合扩容特点:
 * 		是原容量的1.5倍
 * 5、Vector中所有的方法都是线程同步的,都带有synchronized关键字
 *    效率比较低,使用较少。
 * 6、怎么将一个线程不安全的ArrayList集合转换成线程安全的?
 * 		使用集合工具类:
 * 			java.util.Collections;
 * 			【java.util.Collection是集合接口】
 * 
 */

public class VectorTest01 {

	public static void main(String [] args) {
		//默认初始化容量为10
		List vec = new Vector();
		
		//添加元素
		vec.add(1);
		vec.add(2);
		vec.add(3);
		vec.add(4);
		vec.add(5);
		vec.add(6);
		vec.add(7);
		vec.add(8);
		vec.add(9);
		vec.add(10);
		//到此处,集合要进行扩容
		vec.add(11);
		
		
		for(int i = 0; i < vec.size(); i++) {
			System.out.println(vec.get(i));
		}
		
		List list = new ArrayList();//非线程安全的
		
		//变成线程安全的
		Collections.synchronizedList(list);
		
		list.add("hello");
		list.add("world");
		
		
	}
}

(11)Collections 集合工具类

package javaCoreTest;

import java.util.*;

/*
 * java.util.Collection 	集合接口
 * java.util.Collections	集合工具类,方便集合的操作
 */

public class CollectionsTest01 {

	public static void main(String [] args) {
		
		//ArrayList集合不是线程安全的
		List<String> list = new ArrayList<>();
		
		//变成线程安全的
		Collections.synchronizedList(list);
		
		//排序
		list.add("abz");
		list.add("abf");
		list.add("abt");
		list.add("abg");
		
		Collections.sort(list);
		for(String arr : list) {
			System.out.println(arr);
		}
		
		List<WuGui> list1 = new ArrayList<>();
		list1.add(new WuGui(1000));
		list1.add(new WuGui(2000));
		list1.add(new WuGui(500));
		
		//注意:对List集合中元素排序,需要保证List集合中的元素实现了:Comparable接口
		Collections.sort(list1);
		for(WuGui wg : list1) {
			System.out.println(wg);
		}
		
		//对Set集合怎么排序?
		Set<String> set = new HashSet<>();
		set.add("king5");
		set.add("king4");
		set.add("king2");
		set.add("king3");
		//将Set集合转换成List集合
		List<String> mylist = new ArrayList<>(set);
		Collections.sort(mylist);
		for(String s : mylist) {
			System.out.println(s);
		}
		
	}
}

class WuGui implements Comparable<WuGui>{
	int age;

	public WuGui(int age) {
		this.age = age;
	}

	@Override
	public int compareTo(WuGui o) {
		// TODO Auto-generated method stub
		return this.age - o.age;
	}

	@Override
	public String toString() {
		return "WuGui [age=" + age + "]";
	}
	
	
	
}

二、Map
(1).Map接口中常用的方法及遍历

package javaCoreTest;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/*
 * java.util.Map接口中常用的方法及遍历
 * 
 * 1.Map和Collection没有继承关系
 * 2.Map集合以key和value的方式存储数据:键值对
 * 		key和value都是引用数据类型
 * 		key和value都是存储对象的内存地址
 * 		key起到主导的地位,value是key的一个附属品
 * 3.Map接口中常用的方法:
 * 		V put(K key, V value)	向Map集合中添加键值对
 * 		V get(Object key)	通过key获取value
 * 		void clear()		清空Map集合
 * 		boolean containsKey(Object key)判断Map中是否包含某个key
 * 		boolean containsValue(Object value)判断Map中是否包含某个value
 * 		boolean isEmpty()	判断Map集合中元素个数是否为0
 * 		Set<K> keySet()		获取Map集合中所有的key(所有的键是一个set集合)
 * 		V remove(Object key)	通过key删除键值对
 * 		int size()	获取Map集合中键值对的个数
 * 		Collection<V> values()	获取Map集合中所有value,返回一个Collection
 * 		
 * 		Set<Map.Entry<K,V>> entrySet()	
 * 		将Map集合转换成Set集合,如下所示:
 * 			map1集合对象
 * 		key				value
 * 		-------------------------------
 * 		1				zhangsan
 * 		2				lisi
 * 		3				wangwu
 * 		4				zhsoliu
 * 		Set set = map1.entrySet();
 * 		转换成Set对象
 * 		1=zhangsan【注意:Map集合通过entrySet()方法转换成Set集合,Set集合中元素的类型Map.<Entry<K,V>>】
 * 		2=lisi	   【Map.Entry和String一样,都是一种类型的名字,只不过:Map.Entry是静态内部类】
 * 		3=wangwu
 * 		4=zhaoliu 
 */

public class MapTest01 {

	public static void main(String [] args) {
		//创建Map集合对象
		Map<Integer, String> map = new HashMap<>();
		
		//1.V put(K key, V value)	向Map集合中添加键值对
		map.put(1, "zhangsan");
		map.put(2, "wangwu");
		map.put(3, "lisi");
		map.put(4, "zhaoliu");
		
		 //2.V get(Object key)	通过key获取value
		System.out.println(map.get(2));//wangwu
		
		//3.int size()	获取Map集合中键值对的个数
		System.out.println(map.size());//4
		
		//4.V remove(Object key)	通过key删除键值对
		map.remove(2);
		System.out.println(map.size());//3
		
		//5.boolean containsKey(Object key)判断Map中是否包含某个key
		System.out.println(map.containsKey(1));//true
		
		//6.boolean containsValue(Object value)判断Map中是否包含某个value
		//contains方法底层调用的是equals进行比对,所以自定义的类型都需要重写equals方法
		System.out.println(map.containsValue("zhaoliu"));//true
		
		//7.boolean isEmpty()	判断Map集合中元素个数是否为0
		System.out.println(map.isEmpty());//false
		
		//8.void clear()   清空Map集合
		map.clear();
		System.out.println(map.size());//0
		
		map.put(1, "zhangsan");
		map.put(2, "wangwu");
		map.put(3, "lisi");
		map.put(4, "zhaoliu");
		
		System.out.println("------------------------------");
		//Map集合的遍历
		//第一种方式:获取所有的key,通过遍历key,来遍历value
		//Set<K> keySet()获取Map集合中所有的key(所有的键是一个set集合)
		Set<Integer> keys = map.keySet();
		
		//通过迭代器,遍历key,通过key获取value
		Iterator<Integer> it = keys.iterator();
		while(it.hasNext()) {
			Integer key = it.next();
			String value = map.get(key);
			System.out.println(key + "=" + value);
		}
		
		//foreach
		for(Integer k : keys) {
			System.out.println(k + "=" + map.get(k));
		}
		
		//第二种方式:Set<Map.Entry<K,V>> entrySet()
		//以上这个方法把Map集合直接全部转换成Set集合、
		//Set集合中元素的类型是:Map.Entry
		Set<Map.Entry<Integer, String>> set = map.entrySet();
		
		//遍历Set集合,每次取出一个Node
		Iterator<Map.Entry<Integer, String>> it2 = set.iterator();
		while(it2.hasNext()) {
			Map.Entry<Integer, String> node = it2.next();
			System.out.println(node);
			Integer k = node.getKey();
			String v = node.getValue();
			System.out.println(k + "=" + v);
		}
		
		//foreach
		//这种方式效率比较高
		for(Map.Entry<Integer, String> i : set) {
			System.out.println(i.getKey() + " " + i.getValue());
		}
		
		
	}
}

(2)HashMap

package javaCoreTest;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/*
 * 1.HashMap集合底层是哈希表/散列表的数据结构
 * 
 * 2.哈希表是一个怎样的数据结构?
 * 		哈希表是一个数组和单向链表的结合体、
 * 		数组:在查询方面效率很高,随机增删效率较低
 * 		单向链表:在随机增删方面效率很高,在查询方面效率低
 * 		哈希表将以上两种数据结构融合在一起,充分发挥他们各自的优点。
 * 
 * 3.HashMap集合底层的源代码:
 * 		public class HashMap{
 * 			//HashMap底层实际上就是一个数组(一维数组)
 * 				Node<K,V>[] table;
 * 
 * 			//静态的内部类HashMap.Node
 * 			static class Node<K,V>{
 * 				final int hash;//哈希值
 * 				final K key;//存储到Map集合中的那个key
 * 				V value;//存储到Map集合中的那个value
 * 				Node<K,V> next;//下一个节点的内存地址
 * 			}
 * 		}
 * 
 * 4.最主要掌握的是:
 * 		map.put(k,v)
 * 		v = map.get(k)
 * 		以上这两个方法的实现原理,必须掌握
 * 
 * 5.HashMap集合的key部分特点:
 * 		无序,不可重复。
 * 		为什么无序?
 * 			因为不一定挂到哪个单向链表上。
 * 		怎么保证不可重复?
 * 			equals方法来保证HashMap集合的key不可重复。如果key重复了,value会覆盖。
 * 
 * 		放在HashMap集合key部分的元素其实是放在HashSet集合中了。
 * 		所以HashSet集合中的元素也需要同时重写hashCode()+ equals()方法。
 * 
 * 6.哈希表HashMap使用不当时无法发挥性能!
 * 		假设将所有的hashCode方法返回值固定为某个值,那么会导致底层哈希表变为纯单向链表。这种情况称为:散列分布不均匀。
 * 			什么是散列分布均匀?
 * 				假设有100个元素,10个单向链表,每个单向链表上有10个节点,这是散列分布均匀的。
 * 
 * 		假设将所有的hashCode方法返回值都设定为不一样的值,可以吗?、
 * 			不行,因为这样的话导致底层哈希表就成为一维数组了,没有链表的概念。也是散列分布不均匀。
 * 
 * 		散列分布均匀需要重写hashCode方法时有一定的技巧。
 * 
 * 7.重点:放在HashMap集合key部分的元素,以及放在HashMap集合中的元素,需要同时重写HashCode和equals方法。
 * 
 * 8.HashMap集合的默认初始化容量是16,默认加载因子是0.75
 * 		【这个默认加载因子是当HashMap集合底层数组的容量达到75%的时候,数组开始扩容】
 * 
 * 		重点记住:HashMap集合初始化容量必须是2的倍数【官方推荐】
 * 		这是因为达到散列均匀,为了提高HashMap集合的存取效率
 */

public class HashMapTest01 {

	public static void main(String [] args) {
		//测试HashMap集合key部分的元素特点
		//Integer是key,它的hashCode和equals都重写了
		Map<Integer, String> map = new HashMap<>();
		
		map.put(1111, "zhangsan");
		map.put(1222200, "wangtiechui");
		map.put(5555, "lisi");
		map.put(5555, "zhaoliu");//key重复的时候value会自动覆盖
		map.put(8888, "king");
		
		System.out.println(map.size());//4
		
		//遍历map集合
		Set<Map.Entry<Integer,String>> set = map.entrySet();
		for(Map.Entry<Integer,String> entry : set) {
			System.out.println(entry.getKey() + "=" + entry.getValue());
		}
	}
}
package javaCoreTest;

import java.util.HashSet;
import java.util.Set;

/*
 *1. 向Map集合中存,以及从Map集合中取,都是先调用key的hashCode方法,然后在调用equals方法
 * equals方法有可能调用,也有可能不调用。
 * 
 * 拿put(k,v)举例,什么时候equals不会调用?
 * k.hashCode()方法返回哈希值,哈希值经过哈希算法转换成数组下标。数组下标位置上
 * 如果null,equals不需要执行。
 * 
 * 拿get(k)举例,什么时候equals不会调用?
 * 如果单向链表上为null时,不需要调用equals方法。
 * 
 * 2.注意:如果一个类的equals方法重写,那么hashCode方法必须重写。
 * 并且equals方法返回的如果是true,hashCode方法返回的值必须一样。
 * 
 * equals方法返回true表示两个对象相同,在同一个单链表上比较。那么对于同一个单链表上的节点来说,
 * 他们的哈希值都是相同的,所以hashCode方法的返回值也应该相同。
 * 
 * 3.hashCode方法和equals方法可以直接用IDEA工具生成,但是这两个方法需要同时生成。
 * 
 * 4.终极结论:
 * 、		放在HashMap集合key部分的,以及放在HashSet集合中的元素,需要同时重写hashCode方法和equals方法
 * 
 * 5.扩容之后的容量是原容量的2倍
 */

public class HashMapTest02 {

	public static void main(String [] args) {
		University u1 = new University("zhangsan");
		University u2 = new University("zhangsan");

		//重写equals方法之前是false
		//System.out.println(u1.equals(u2));//false
		
		//重写equals方法之后是true
		System.out.println(u1.equals(u2));//true
		
		System.out.println("u1的hashCode=" + u1.hashCode());//366712642(重写hashCode方法后:-1432604525)
		System.out.println("u2的hashCode=" + u2.hashCode());//1829164700(重写hashCode方法后:-1432604525)
		
		//u1.equals(u2)结果已经是true了,表示u1和u2是一样的,相同的,那么往HashSet集合中放的话,按说只能放进去1个。
		//HashSet集合特点:无序不可重复
		Set<University> univer = new HashSet<>();
		univer.add(u1);
		univer.add(u2);
		System.out.println(univer.size());//1
		
	}
}

class University{
	
	private String name;
	
	public University() {
		
	}
	
	public University(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((name == null) ? 0 : name.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;
		University other = (University) obj;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}
	
	/*public boolean equals (Object obj) {
		if(obj == null || !(obj instanceof University))return false;
		if(obj == this) return true;
		University u = (University)obj;
		return this.name.equals(u.name);
		}*/
}
package javaCoreTest;

import java.util.HashMap;
import java.util.Map;

/*
 * HashMap集合key部分允许null吗?
 * 允许
 * 但是要注意:HashMap集合的key中null值只能有一个。
 */

public class HashMapTest03 {

	public static void main(String [] args) {
		Map map = new HashMap();
		
		//HashMap集合允许key为null
		map.put(null, null);
		System.out.println(map.size());//1
		
		//key重复的话value被覆盖
		map.put(null, 100);
		System.out.println(map.size());//1
		
		//通过key获取value
		System.out.println(map.get(null));//100
	}
}
package javaCoreTest;

import java.util.Hashtable;
import java.util.Map;

/*
 * Hashtable的key可以为null吗?
 * Hashtable的key和value都是不能为null的。
 * HashMap集合的key和value都是可以为null的。
 * 
 * Hashtable方法都带有synchronized:线程安全的。
 * 
 * Hashtable 和HashMap一样,底层都是哈希表数据结构
 * Hashtable的初始化容量是11,默认加载因子是0.75
 * Hashtable的扩容是:原容量*2 + 1
 */

public class HashtableTest01 {

	public static void main(String [] args) {
		
		Map map = new Hashtable();
		
		//空指针异常
		//map.put(null, 123);//java.lang.NullPointerException
		
		//空指针异常
		map.put(1, null);//java.lang.NullPointerException
		
	}
}

(3)Properties

package javaCoreTest;

import java.util.Properties;

/*
 * 目前只需要掌握Properties属性类对象的相关方法即可
 * Properties是一个Map集合,继承Hashtable,Properties的key和value都是String类型
 * Properties被称为属性类对象
 * Properties是线程安全的。
 */

public class PropertiesTest01 {

	public static void main(String [] args) {
		//创建一个properties对象
		Properties pro = new Properties();
		
		//需要掌握Properties的两个方法,存和取
		//存
		pro.setProperty("user1", "jdbc:mysql://localhost:3306/bjpowernode");
		pro.setProperty("driver", "com.mysql.jdbc.Driver");
		pro.setProperty("username", "root");
		pro.setProperty("password", "123");
		
		//通过key获取value
		String user1 = pro.getProperty("user1");
		String driver = pro.getProperty("driver");
		String username = pro.getProperty("username");
		String password = pro.getProperty("password");
		
		System.out.println(user1);
		System.out.println(driver);
		System.out.println(username);
		System.out.println(password);
	}
}

三、泛型

package javaCoreTest;
import java.util.*;

/*
 * JDK5.0之后出现:泛型
 * 使用泛型List<类型>,表示List集合中只允许存储此种类型的数据
 * 用泛型来指定集合中存储的数据类型
 * 泛型这种语法机制,只在程序编译阶段起作用,只是给编译器参考(运行阶段泛型没用)
 */

/*
 * 1.使用泛型的优点:
 * 		集合中存储的元素类型统一
 * 		从集合中取出的元素类型是泛型指定的类型,不需要进行大量的“向下转型”
 * 
 * 2.使用泛型的缺点:
 * 		导致集合中存储的元素缺乏多样性
 * 	
 * 大多数业务中,集合中元素的类型还是统一的,所以这种泛型特性被大家所认可。
 */

public class GenericTest01 {

	public static void main(String [] args) {
		List<Animal01> list = new ArrayList();
		
		//编译报错,因为list集合指定为Animal类型
		//list.add("string");
		
		Cat01 c = new Cat01();
		Bird01 b = new Bird01();
		
		list.add(b);
		list.add(c);
		
		//获取迭代器
		//迭代器也可以使用泛型
		Iterator<Animal01> it = list.iterator();
		
		while(it.hasNext()) {
			//使用泛型之后,每一次迭代返回的数据都是Animal类型
			Animal01 a = it.next();
			//这里不需要进行强制类型转换,直接调用
			a.move();
		}
		
		//调用子类特有的方法还是需要向下转换的
		Iterator<Animal01> it1 = list.iterator();
		while(it1.hasNext()) {
			Animal01 a = it1.next();
			if(a instanceof Cat01) {
				Cat01 m = (Cat01)a;
				m.catMouse();
			}
			
			if(a instanceof Bird01) {
				Bird01 n = (Bird01)a;
				n.fly();
			}
		}
	}
}

class Animal01{
	public void move() {
		System.out.println("Runing!");
	}
}

class Cat01 extends Animal01{
	public void catMouse() {
		System.out.println("Cat and mouse");
	}
}

class Bird01 extends Animal01{
	public void fly() {
		System.out.println("Flying !");
	}
}
package javaCoreTest;

/*
 * 自定义泛型
 * <>尖括号中是一个标识符,随便写
 * java 源代码中经常出现的是:
 * 		<T>和<E>
 */

public class GenericTest02 {

	public static void main(String [] args) {
		MyIterator<String> mi = new MyIterator<>();
		String s1 = mi.get();
		
		MyIterator<Integer> mi1 = new MyIterator<>();
		Integer i = mi1.get();
	}
}

class MyIterator<T>{
	public T get() {
		return null;
	}
}

四、总结:必须要掌握的知识!!!:
(1)ArrayList、LinkedList

package javaCoreTest;

import java.util.*;

/*
 * ArrayList、LinkedList总结:
 * 每个集合对象的创建(new)
 * 向集合中添加元素
 * 从集合中取出某个元素
 * 遍历集合
 */

public class AllList {

	public static void main(String [] args) {
		//创建集合对象
		LinkedList<String> list = new LinkedList();
		//ArrayList<String> list = new ArrayList<>();
		
		//添加元素
		list.add("zhangsan");
		list.add("wangtiechui");
		list.add("wangdaniang");
		
		//从集合中取出某个元素
		//List集合有下标
		//取出某个元素
		System.out.println(list.get(0));//zhangsan
		
		//遍历
		for(int i = 0; i < list.size(); i++) {
			System.out.println(list.get(i));
		}
		
		for(String i : list) {
			System.out.println(i);
		}
		
		Iterator it = list.iterator();
		while(it.hasNext()) {
			System.out.println(it.next());
		}
	}
}

(2)HashSet

package javaCoreTest;

import java.util.*;

/*
 * HashSet(HashMap的key,存储在HashMap集合key的元素需要同时重写HashCode和equals方法)
 * 每个集合对象的创建(new)
 * 向集合中添加元素
 * 从集合中取出某个元素
 * 遍历集合
 * 测试HashSet集合的特点:无序不可重复
 */

public class AllHashSet {

	public static void main(String [] args) {
		//创建集合对象
		HashSet<String> set = new HashSet<>();
		
		//添加元素
		set.add("abc");
		set.add("def");
		set.add("king");
		set.add("vde");
		
		//遍历集合
		Iterator it = set.iterator();
		while (it.hasNext()) {
			System.out.println(it.next());
		}
		
		//测试HashSet集合的特点:无序不可重复
		set.add("king");
		set.add("king");
		set.add("king");
		set.add("king");
		System.out.println(set.size());//4
		
		set.add("10");
		set.add("1");
		Iterator it1 = set.iterator();
		while (it1.hasNext()) {
			System.out.println(it1.next());
		}
		
	}
}

(3)HashMap

package javaCoreTest;

import java.util.*;

/*
 *每个集合对象的创建(new)
 * 向集合中添加元素
 * 从集合中取出某个元素
 * 遍历集合
 */

public class AllHashMap {

	public static void main(String [] args) {
		Map<Integer, String> map = new HashMap<>();
		
		//添加元素
		map.put(1, "zhangsan");
		map.put(9, "lisi");
		map.put(1, "wangtiechui");
		map.put(10, "kign");
		map.put(2, "Sima");//key重复value会覆盖
		
		//获取元素个数
		System.out.println(map.size());//4
		
		//取key是2的元素
		System.out.println(map.get(2));//Sima
		
		//遍历集合的几种方式
		//第一种方式:先获取所有的key,遍历key的时候,通过key获取value
		Set<Integer>keys = map.keySet();
		for(Integer key : keys) {
			System.out.println(key + "=" + map.get(key));
		}
		
		//第二种方式:将Map集合转换成Set集合,Set集合中每一个元素是Node
		Set<Map.Entry<Integer, String>> nodes = map.entrySet();
		for(Map.Entry<Integer, String> node : nodes) {
			System.out.println(node.getKey() + "=" +node.getValue());
		}
		
	}
}

(4)TreeSet

package javaCoreTest;

import java.util.*;

/*
 * 每个集合对象的创建(new)
 * 向集合中添加元素
 * 从集合中取出某个元素
 * 遍历集合
 * 测试TreeSet集合中的元素是可排序的
 * 测试TreeSet集合中存储的类型是自定义的
 */

public class AllTreeSet {

	public static void main(String [] args) {
		//集合的创建(可以测试以下TreeSet集合中存储String、Integer的。这些类型都是SUN公司提前写好的)
		//TreeSet<Integer> ts = new TreeSet();
		
		//编写比较器可以改变规则
		TreeSet<Integer> ts = new TreeSet<>(new Comparator<Integer>() {
			public int compare(Integer o1, Integer o2) {
				return o2 - o1;//自动拆箱
			}
		});
		
		//添加元素
		ts.add(1);
		ts.add(100);
		ts.add(20);
		ts.add(80);
		ts.add(12);
		ts.add(500);
		ts.add(14);
		
		//遍历(迭代方式)
		Iterator <Integer> it = ts.iterator();
		while(it.hasNext()) {
			System.out.println(it.next());
		}
		
		//TreeSet 集合中存储自定义类型
		TreeSet <A> atree = new TreeSet<>();
		
		atree.add(new A(100));
		atree.add(new A(2000));
		atree.add(new A(200));
		atree.add(new A(100));
		atree.add(new A(500));
		atree.add(new A(100));
		atree.add(new A(300));
		atree.add(new A(400));
		atree.add(new A(1000));
		
		//遍历
		for(A a : atree) {
			System.out.println(a);
		}
		
		TreeSet<B> btree = new TreeSet<>(new BComparator());
		
		btree.add(new B(500));
		btree.add(new B(200));
		btree.add(new B(100));
		btree.add(new B(5600));
		btree.add(new B(300));
		
		for(B b : btree) {
			System.out.println(b);
		}
		
	}
}

//实现Comparable接口
class A implements Comparable<A>{
	int i;

	public A(int i) {
		this.i = i;
	}

	@Override
	public int compareTo(A o) {
		// TODO Auto-generated method stub
		return this.i - o.i;
	}

	@Override
	public String toString() {
		return "A [i=" + i + "]";
	}
}

//第二种方式
class B{
	int i;

	public B(int i) {
		this.i = i;
	}

	@Override
	public String toString() {
		return "B [i=" + i + "]";
	}
}

class BComparator implements Comparator<B>{

	@Override
	public int compare(B o1, B o2) {
		// TODO Auto-generated method stub
		return o1.i - o2.i;
	}
	
}

(5)Properties

package javaCoreTest;

import java.util.Properties;

public class AllProperties {

	public static void main(String [] args) {
		//创建对象
		Properties pro = new Properties();
		
		//存
		pro.setProperty("username", "zhangsan");
		pro.setProperty("password", "123");
		
		//取
		String username = pro.getProperty("username");
		String password = pro.getProperty("password");
		
		System.out.println(username);
		System.out.println(password);
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值