集合
对象的容器,定义了对多个对象进行操作的常用方法,可以实现数组的功能
和数组的区别:
-
数组长度固定,集合长度不固定
-
数组可以存储基本类型和引用类型,集合只能存储引用类型
Collection体系集合
Collection 该体系结构的根接口 代表一组对象 称为集合
List接口 有序 有下标 元素可以重复
set接口 无序 无下标 元素不能重复
Collection父接口
特点:代表一组任意类型的对象,无序,无下标,不能重复
方法:
-
boolean add(Object obj)//添加一个对象
-
boolean addAll(Collecttion 从)//将一个集合中的所有对象添加到此集合中
-
void clear()//清空此集合中的所有对象
-
boolean contains(Object o) //检查此集合中是否含有o对象
-
boolean equals(Object o) //班级此集合是否和指定对象相等
-
boolean isEmpty() //判断集合是否为空
-
boolean remove(Object o) //在此集合中移除o对象
-
int size() //返回此集合中元素的个数
-
Object[] toArray() //将此集合装换成数组
package CollectionFramework; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; public class TestCollection { public static void main(String[] args) { //创建集合 Collection collection = new ArrayList(); //添加元素 collection.add("苹果"); collection.add("香蕉"); collection.add("西瓜"); System.out.println("元素个数:"+collection.size());//3 System.out.println(collection);//[苹果, 香蕉, 西瓜] //删除元素 // collection.remove("西瓜"); // System.out.println(collection);//[苹果, 香蕉] // collection.clear(); // System.out.println(collection);//[] //遍历元素 //增强for for (Object o : collection) { System.out.println(o); } //迭代器 专门用来遍历集合的一种方式 //hasNext() 有没有下一个元素 //next() 获取下一个元素 //remove() 删除当前元素 Iterator iterator = collection.iterator(); while (iterator.hasNext()){ //在迭代过程中 不能使用collection的其他方法来改变元素 String s = (String) iterator.next(); System.out.println(s); // collection.remove(s);不能使用这个删除 // iterator.remove();//可以使用这个 } //判断 System.out.println(collection.contains("西瓜"));//有没有西瓜 System.out.println(collection.isEmpty());//是否为空 } }
package CollectionFramework; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; public class TestCollection02 { public static void main(String[] args) { //新建Collection对象 Collection collection = new ArrayList(); Student student1 = new Student("张三", 18); Student student2 = new Student("张四", 19); Student student3 = new Student("张五", 25); collection.add(student1); collection.add(student2); collection.add(student3); System.out.println(collection.size()); System.out.println(collection.toString()); //删除 // collection.remove(new Student("张三",18));//这样是无法删除的,因为new已经新建了一个对象,和以前的对象无关 // collection.remove(student2); // collection.clear();//只是把对象从集合中移除,对象本身还是存在 System.out.println(collection); //遍历 for (Object o : collection) { Student student = (Student)o; System.out.println(student); } Iterator iterator = collection.iterator(); while (iterator.hasNext()){ Student s = (Student) iterator.next(); System.out.println(s); } //判断 System.out.println(collection.contains(student1));//true System.out.println(collection.contains(new Student("张三",18)));//false System.out.println(collection.isEmpty()); } }
List集合
有序(添加的顺序和遍历顺序一样 有下标 元素可以重复
方法:
-
void add(int Index ,Object o) 在Index位置插入o对象
-
boolean addAll(int Index,Collection c) 将一个集合中的元素添加到该集合中的Index位置
-
Object get(int index) 返回集合中指定位置的元素
-
List subList(int fromIndex , int toIndex) 返回fromIndex 和 toindex之间的集合元素
package CollectionFramework; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.ListIterator; /* List集合 有序 有下标 可重复 */ public class TestList { public static void main(String[] args) { //先创建集合对象 List list = new ArrayList<>(); //添加 list.add("苹果"); list.add("小米"); list.add(0,"华为"); System.out.println(list.size()); System.out.println(list);//[华为, 苹果, 小米] //删除 // list.remove(0); // System.out.println(list);//[苹果, 小米] // list.remove("苹果"); // System.out.println(list);//[小米] //遍历 //1 for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); } //2 System.out.println("========="); for (Object o : list) { System.out.println(o); } //3迭代器 System.out.println("========="); Iterator iterator = list.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next()); } //4列表迭代器 /* 可以逆向迭代 可以向前或向后 可以删除,添加 修改 */ ListIterator listIterator = list.listIterator(); System.out.println("========="); //从前向后 while (listIterator.hasNext()){//这里下标从0开始 System.out.println(listIterator.nextIndex()+":"+listIterator.next()); } System.out.println("========="); //从后向前 while (listIterator.hasPrevious()){//这里下标以0结束 System.out.println(listIterator.previousIndex()+":"+listIterator.previous()); } //判断 System.out.println(list.contains("苹果")); System.out.println(list.isEmpty()); //获取位置 System.out.println(list.indexOf("华为")); } }
package CollectionFramework; import java.util.ArrayList; import java.util.List; public class TestList02 { public static void main(String[] args) { List list = new ArrayList(); //因为集合不能存储基本类型 下面隐含了自动装箱 list.add(20); list.add(30); list.add(40); list.add(50); list.add(60); System.out.println(list.size()); System.out.println(list);//[20, 30, 40, 50, 60] //删除 // list.remove("20");//无法删除20 两者类型不一样 // list.remove(20);//无法删除20 这里会当成下标去执行 // list.remove((Object) 20);//正确删除 转为Object类型 // list.remove(new Integer(30));//正确删除 转为Integer // list.remove((Integer)40);//正确删除 转为Integer 最好使用上面的new一个 // System.out.println(list); //补充subList 返回子集合 List list1 = list.subList(1, 3);//左闭右开 System.out.println(list1);//[30, 40] } }
List的实现类
ArrayList类 重点
-
数组结构实现 查询快 增删慢
-
JDK1.2版本加入的 运行效率快 线程不安全
-
源码分析:
-
默认容量大小为10,这个默认容量是添加了元素 如果没有添加任何元素 默认容量为0 每次扩容为原先的1.5倍
-
elementData数组 存放元素
-
size 实际的元素个数
-
add方法源码分析:
-
public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } private static int calculateCapacity(Object[] elementData, int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { return Math.max(DEFAULT_CAPACITY, minCapacity); } return minCapacity; } private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); } //扩容 默认容量为10 当添加第11个时 扩容 每次扩容为原先的1.5倍 private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); }
使用:
package CollectionFramework; import java.util.ArrayList; import java.util.Iterator; import java.util.ListIterator; /* ArrayList: 存储结构 :数组 查找快 增删慢 */ public class TestArrayList { public static void main(String[] args) { ArrayList arrayList = new ArrayList<>(); //添加 Student student1 = new Student("刘一",21); Student student2 = new Student("刘二",22); Student student3 = new Student("刘三",23); arrayList.add(student1); arrayList.add(student2); arrayList.add(student3); System.out.println(arrayList.size()); System.out.println(arrayList); //删除 // arrayList.remove(student1); // arrayList.remove(new Student("刘二",22));//这样无法删除 解决这个问题 重写equals方法 /* @Override public boolean equals(Object obj) { if (this==obj){ return true; } if (obj==null){ return false; } if (obj instanceof Student){ Student s = (Student) obj; //比较属性 if (this.name.equals(s.getName())&&this.age==s.age){ return true; } } return false; } */ System.out.println(arrayList); //遍历 //迭代器 Iterator iterator = arrayList.iterator(); while (iterator.hasNext()){ Student s = (Student) iterator.next(); System.out.println(s); } //列表迭代器 ListIterator listIterator = arrayList.listIterator(); System.out.println("==========前向后迭代"); while (listIterator.hasNext()){//这里的下标才1开始 Student s2 = (Student) listIterator.next(); System.out.println(s2); } System.out.println("==========后向前迭代"); while (listIterator.hasPrevious()){//这里的下标从-1开始 Student s3 = (Student) listIterator.previous(); System.out.println(s3); } //判断 //查找 } }
-
Vector类
-
数组结构 查询快 增删慢
-
JDK1.0版本的 运行效率慢 线程安全 现在已经基本不使用了
-
package CollectionFramework; import java.util.Enumeration; import java.util.Vector; /* 测试Vector类 */ public class TestVector { public static void main(String[] args) { Vector vector = new Vector<>(); vector.add("草莓"); vector.add("西瓜"); vector.add("葡萄"); System.out.println(vector.size()); System.out.println(vector); // vector.remove(0); // vector.remove("西瓜"); // System.out.println(vector); // vector.clear(); // System.out.println(vector); //遍历 //枚举器 Enumeration elements = vector.elements(); while (elements.hasMoreElements()){ String s = (String) elements.nextElement(); System.out.println(s); } //判断 System.out.println(vector.contains("西瓜")); System.out.println(vector.isEmpty()); //补充 System.out.println(vector.lastElement());//最后一个 System.out.println(vector.firstElement());//第一个 System.out.println(vector.elementAt(1));//下标为1的 } }
LinkedList类:
-
链表结构实现 增删快 查询慢 双向链表
-
package CollectionFramework; import java.util.Iterator; import java.util.LinkedList; import java.util.ListIterator; /** * 测试 LinkedList 双向链表结构 */ public class TestLinkedList { public static void main(String[] args) { LinkedList linkedList = new LinkedList<>(); Student student1 = new Student("宋一",21); Student student2 = new Student("宋二",22); Student student3 = new Student("宋三",23); linkedList.add(student1); linkedList.add(student2); linkedList.add(student3); System.out.println(linkedList.size()); System.out.println(linkedList); // linkedList.remove(student1); // linkedList.remove(new Student("宋二",22));//这里可以删除 因为重写了equals方法在Student类中 // System.out.println(linkedList); //遍历 System.out.println("==============遍历"); for (int i = 0; i < linkedList.size(); i++) { System.out.println(i); System.out.println(linkedList.get(i)); } System.out.println("==============遍历"); for (Object o : linkedList) { Student s = (Student) o; System.out.println(s); } System.out.println("==============迭代器"); Iterator iterator = linkedList.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next()); } System.out.println("==============迭代器2"); ListIterator listIterator = linkedList.listIterator(); System.out.println("==============前到后"); while (listIterator.hasNext()){ Student s2 = (Student)listIterator.next(); System.out.println(" "+s2+"下标"+listIterator.nextIndex()); } System.out.println("==============后到前"); while (listIterator.hasPrevious()){ System.out.println(listIterator.previous()+"下标"+listIterator.previousIndex()); } } }
泛型
JDK1.5 引入的新特性 其本质是参数化类型 把参数作为参数传递
常见形式:泛型类 泛型接口 泛型方法
语法: <T,.........> T为类型占位符 表示一种引用类型
好处:提高代码的重用性 防止类型转换异常 提高代码安全性
泛型类
package Generic; /* 测试泛型类 语法:在类名后面添加<T,Y,......> T数据类型占位符 引用类型 可以写多个 逗号隔开 */ public class MyGeneric<T> { //使用泛型T //1创建变量 T t; //2添加为方法参数 public void show(T t){ // T t1 = new T();T可以创建变量 但不能new对象 因为类型不知道无法保证构造方法可以使用 System.out.println(t); } //3泛型作为方法的返回值 public T getT(){ return t; } } //使用 package Generic; public class TestGeneric { public static void main(String[] args) { //使用泛型类创建对象 //注意:泛型只能是引用类型 不同的泛型对象不能相互赋值 MyGeneric<String> myGeneric = new MyGeneric<String>();//后面这个String在JDK1.7后面可以不写 myGeneric.t="hello"; myGeneric.show("大家好"); String string = myGeneric.getT(); MyGeneric<Integer> myGeneric1 = new MyGeneric<>(); myGeneric1.t=100; myGeneric1.show(200); Integer integer = myGeneric1.getT(); } }
泛型接口
使用方法:
-
先创建一个泛型接口
-
package Generic; /** * 泛型接口; * 语法: 接口名<T> * 不能创建泛型静态常量 */ public interface MyInterface<T> { String name = "张三"; T server(T t); }
-
-
创建泛型接口的实现类 有两种方法
-
实现类中已经确定泛型的类型
-
package Generic; //在实现接口时 就要把类型确定 public class MyInterfaceImpl implements MyInterface<String>{ @Override public String server(String s) { System.out.println(s); return null; } }
-
//在main方法中的使用 MyInterfaceImpl impl = new MyInterfaceImpl(); impl.server("xxxx");
-
-
实现类中没有确定泛型的类型 而是把实现类也写成泛型类 在创建对象的时候 确定类型
-
package Generic; //在实现泛型接口时 还没有确定类型 就把这个类也改成泛型类 创建对象的时候在确定 public class MyInterfaceImpl02<T> implements MyInterface<T>{ @Override public T server(T t) { System.out.println(t); return null; } }
-
MyInterfaceImpl02<Integer> impl02 = new MyInterfaceImpl02(); impl02.server(1000);
-
-
泛型方法
创建泛型方法
package Generic; /** * 泛型方法 * 语法:<T> 方法的返回值类型 */ public class MyGenericMethod { //泛型方法 T返回值 可以是void 这些 public <T> T show(T t){ System.out.println("泛型方法"+t); return t; } }
调用:
//泛型方法调用 MyGenericMethod method = new MyGenericMethod(); method.show("xxxxxxx");//根据你放进去的数据类型自动确定泛型的类型 method.show(200);
泛型集合
概念:参数化类型 类型安全的集合 强制集合元素的类型必须一致
特点:
-
编译时就可以检查 而非运行时抛出异常
-
访问时 不必类型装换(拆箱
-
不同的泛型之间引用不能相互赋值 泛型不存在多态
package Generic; import CollectionFramework.Student; import java.util.ArrayList; import java.util.Iterator; public class Demo { public static void main(String[] args) { //这里没有使用泛型 自动默认都是Object类型 ArrayList<String> arrayList = new ArrayList<>(); arrayList.add("xxx"); arrayList.add("yyy"); // arrayList.add(10); // arrayList.add(20); 这里确定了泛型为String 现在就是String类型的集合 此时集合只能保存String类型 // for (Object o : arrayList) { // /* // 因为没有使用泛型 确定集合中应该只存在该类型的 // 所以默认的是Object类型 // 如果我们需要对数据进行强制转换 很有可能两者无法强转 抛出异常 // java.lang.Integer cannot be cast to java.lang.String // */ String str = (String) o;//会有类型转换异常 如果没有确定泛型 System.out.println(str); // } for (String s : arrayList) { System.out.println(s); } ArrayList<Student> arrayList1 = new ArrayList<Student>(); Student student1 = new Student("x",21); Student student2 = new Student("x",21); Student student3 = new Student("x",21); arrayList1.add(student1);//此时只能添加Student类型的 arrayList1.add(student2); arrayList1.add(student3); Iterator<Student> iterator = arrayList1.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next());//这里next获取的就是Student类型 } } }
Set集合
特点:无效 无下标 不可重复元素
方法全部继承自Collection
set接口的使用
package Generic; import java.util.HashSet; import java.util.Iterator; import java.util.Set; /* 测试Set接口 无序 无下标 不可重复 */ public class TestSetInterface { public static void main(String[] args) { Set<String> set = new HashSet<>(); //添加属性 set.add("苹果"); set.add("华为"); set.add("华为"); set.add("小米"); System.out.println(set.size()); System.out.println(set); //删除 // set.remove("苹果"); // System.out.println(set); // set.clear(); //遍历 两种方式 //增强for System.out.println("================="); for (String s : set) { System.out.println(s); } System.out.println("================="); Iterator<String> iterator = set.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next()); } //判断 System.out.println(set.contains("华为")); System.out.println(set.isEmpty()); } }
Set的实现类:
HashSet(重点
-
基于HashCode实现元素不可重复
-
当存入元素的哈希码相同时,会调用equals进行确认 如果结果为true 则拒绝后者存入
-
//idea可以使用alt加insert快捷键重写 //自己重写: @Override public int hashCode() { int n1 = this.name.hashCode(); int n2 = this.age; return n1+n2; } @Override public boolean equals(Object obj) { if (this==obj){ return true; } if (obj==null){ return false; } if (obj instanceof Person){ Person p = (Person) obj; if (this.name.equals(p.getName())&&this.age==p.getAge()){ return true; } } return false; } //快捷键生成: @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return age == person.age && Objects.equals(name, person.name); } @Override public int hashCode() { return Objects.hash(name, age); }
-
package Generic; import java.util.HashSet; import java.util.Iterator; /** * HashSet 的使用 * 复杂一点的使用 */ public class TestHashSet02 { public static void main(String[] args) { HashSet<Person> hashSet = new HashSet<>(); Person person1 = new Person("刘一", 21); Person person2 = new Person("刘二", 22); Person person3 = new Person("刘三", 23); hashSet.add(person1); hashSet.add(person2); hashSet.add(person3); /* 这个添加是可以成功的 这个new是一个新的对象和person1不一样 原因:存储过程 1)根据hashcode计算保存的位置 如果位置为空 则直接保存 不为空执行第二步 2)再执行equals方法 如果equals方法为true 则认为是重复 否则形成链表 解决方法重写equals方法 和hashcode方法 @Override public int hashCode() { int n1 = this.name.hashCode(); int n2 = this.age; return n1+n2; } @Override public boolean equals(Object obj) { if (this==obj){ return true; } if (obj==null){ return false; } if (obj instanceof Person){ Person p = (Person) obj; if (this.name.equals(p.getName())&&this.age==p.getAge()){ return true; } } return false; } */ hashSet.add(new Person("刘一", 21));//这个添加是可以成功的 这个new是一个新的对象和person1不一样 解决方法重写equals方法和hashcode方法 System.out.println(hashSet.size()); System.out.println(hashSet); //删除 // hashSet.remove(person1); // hashSet.remove(new Person("刘二", 22));//在equals方法和hashcode方法重写前删不了 现在可以 // System.out.println(hashSet); //遍历 两种 for (Person person : hashSet) { System.out.println(person); } System.out.println("=====迭代器========"); Iterator<Person> iterator = hashSet.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next()); } //判断 System.out.println(hashSet.contains(new Person("刘一", 21)));//因为重写了equals方法和hashcode方法 所以可以这样判断 System.out.println(hashSet.isEmpty()); } }
-
package Generic; import java.util.HashSet; import java.util.Iterator; /* HashSet集合的使用 存储结构 哈希表(数组+链表+红黑树) */ public class TestHashSet { public static void main(String[] args) { //新建集合 HashSet<String> hashSet = new HashSet<>(); //添加 hashSet.add("刘一"); hashSet.add("刘二"); hashSet.add("刘三"); hashSet.add("刘四"); hashSet.add("刘四"); System.out.println(hashSet.size()); System.out.println(hashSet); //删除 hashSet.remove("刘四"); System.out.println(hashSet); //遍历 两种 for (String s : hashSet) { System.out.println(s); } System.out.println("============"); Iterator<String> iterator = hashSet.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next()); } //判断 System.out.println(hashSet.contains("刘一")); System.out.println(hashSet.isEmpty()); } }
TreeSet
-
基于排列顺序实现元素不重复 二叉树 红黑树(平衡二叉树)
-
实现SortedSet接口 对集合元素自动排序
-
元素对象的类型必须实现Comparable接口 指定排序顺序
-
Comparator接口的使用 定制比较(比较器)* 使用比较器后 集合了的元素可以不用实现Comparable接口
-
通过CompareTo方法确定是否是重复元素
-
简单使用:
-
package Generic; import java.util.Iterator; import java.util.TreeSet; /** * TreeSet集合的使用 * 存储结构:红黑树 */ public class TestTreeSet { public static void main(String[] args) { TreeSet<String> treeSet = new TreeSet<>(); treeSet.add("xyz"); treeSet.add("abc"); treeSet.add("hello"); System.out.println(treeSet.size()); System.out.println(treeSet);//[abc, hello, xyz] // treeSet.remove("xyz"); // System.out.println(treeSet); //遍历 for (String s : treeSet) { System.out.println(s); } Iterator<String> iterator = treeSet.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next()); } //判断 System.out.println(treeSet.contains("abc")); System.out.println(treeSet.isEmpty()); } }
-
-
package Generic; import java.util.Iterator; import java.util.TreeSet; /** * TreeSet集合 * 要求集合元素必须实现Comparable接口 */ public class TestTreeSet02 { public static void main(String[] args) { TreeSet<Person> treeSet = new TreeSet<>(); /* 异常:java.lang.ClassCastException Generic.Person cannot be cast to java.lang.Comparable 因为Person没有实现Comparable接口 CompareTo方法的返回值为0 认为是重复元素 重写比较规则 //比较规则 @Override public int compareTo(Person o) { int n1 = this.getName().compareTo(o.getName()); int n2 = this.age - o.getAge(); return n1==0?n2:n1; } */ Person person1 = new Person("刘一", 21); Person person2 = new Person("刘二", 22); Person person3 = new Person("刘三", 23); treeSet.add(person1); treeSet.add(person2); treeSet.add(person3); System.out.println(treeSet.size()); System.out.println(treeSet); // treeSet.remove(person1); // treeSet.remove(new Person("刘三", 23));//这样可以删除 因为实现CompareTo方法里面是通过比较名字和年龄 // System.out.println(treeSet); //遍历 for (Person person : treeSet) { System.out.println(person); } System.out.println("==========="); Iterator<Person> iterator = treeSet.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next()); } //判断 System.out.println(treeSet.contains(person1)); System.out.println(treeSet.contains(new Person("刘三", 23))); System.out.println(treeSet.isEmpty()); } }
补充Comparator接口:
-
package Generic; import java.util.Comparator; import java.util.TreeSet; /** * TreeSet集合 * Comparator接口的使用 定制比较(比较器) * 使用比较器后 集合了的元素可以不用实现Comparable接口 */ public class TestTreeSet03 { public static void main(String[] args) { //创建集合并指定比较规则 TreeSet<Person> treeSet = new TreeSet<>(new Comparator<Person>() { @Override public int compare(Person o1, Person o2) { int n1 = o1.getAge()-o2.getAge(); int n2 = o1.getName().compareTo(o2.getName()); return n1==0?n2:n1; } }); Person person1 = new Person("刘一", 21); Person person2 = new Person("刘二", 22); Person person3 = new Person("刘三", 23); Person person4 = new Person("刘三三", 23); treeSet.add(person1); treeSet.add(person2); treeSet.add(person3); treeSet.add(person4); System.out.println(treeSet); } }
-
TreeSet案例:
-
package Generic; import java.util.Comparator; import java.util.TreeSet; /** * 要求 使用TreeSet集合按照字符串长度进行排序 */ public class TestTreeSet04 { public static void main(String[] args) { TreeSet<String> treeSet = new TreeSet<>(new Comparator<String>() { @Override public int compare(String o1, String o2) { int n1=o1.length()-o2.length(); int n2=o1.compareTo(o2);//原来的比较规则 return n1==0?n2:n1; } }); treeSet.add("hello"); treeSet.add("hello world"); treeSet.add("apple"); treeSet.add("songhongming"); treeSet.add("jiang"); treeSet.add("cat"); System.out.println(treeSet); } }
-
Map体系集合
特点:
-
用于存储任意键值对
-
键 无序 无下标 不允许重复
-
值 无序 无下标 可以重复
方法:
-
put(K key,V value) 将对象存入到集合中 关联键值 key重复则覆盖原值
-
get(Object key) 获取key对应的值
-
Set<K> keySet() 返回所有的key
-
Collection<V> values() 返回所有值的Collection集合
-
Set<Map.Entry<K,V>> 键值匹配的Set集合
Map接口的使用:
基本使用:
package Generic; import java.util.HashMap; import java.util.Map; import java.util.Set; /** * Map接口的使用 * 存储键值对 键不能重复 值可以重复 无序 */ public class TestMap { public static void main(String[] args) { //创建Map集合 两个String设置键 值的 类型 因为Map是一个接口 所以需要new他的实现类 HashMap Map<String, String> map = new HashMap<>(); //添加元素 map.put("cn","中国"); map.put("uk","英国"); map.put("usa","美国"); System.out.println(map);//{usa=美国, uk=英国, cn=中国} System.out.println(map.size()); System.out.println(map.get("cn"));//中国 map.put("cn","古代中国");//因为有重复键 所以覆盖原先的值 中国 被覆盖为 古代中国 System.out.println(map);//{usa=美国, uk=英国, cn=古代中国} //删除 // map.remove("usa"); // System.out.println(map); //遍历 //1使用keySet(); System.out.println("====1使用keySet();====="); Set<String> keySet = map.keySet();//得到key的Set集合 for (String key : keySet) { System.out.println(key);//usa uk cn System.out.println(map.get(key));//美国 英国 古代中国 } //2.使用entrySet()方法 效率略高于上面 System.out.println("====2.使用entrySet()方法====="); Set<Map.Entry<String, String>> entrySet = map.entrySet();//entry 一个键值对 for (Map.Entry<String, String> entry : entrySet) { System.out.println(entry);//usa=美国 uk=英国 cn=古代中国 System.out.println(entry.getKey()); System.out.println(entry.getValue()); } //判断 System.out.println(map.containsKey("cn"));//true System.out.println(map.containsValue("泰国"));//false } }
Map集合的实现类
HashMap 重点
特点:
-
JDK1.2 线程不安全 运行效率快 允许用null作为key或者value
-
无参构造器构造一个具有默认容量(16)和默认加载因子(0.75)(超过容量的75%开始扩容)的空HashMap 每次扩容容量翻倍
package Generic; import java.util.HashMap; import java.util.Map; /** * HashMap的使用 * 存储结构 哈希表 */ public class TestHashMap { public static void main(String[] args) { //创建集合 HashMap<Student,String> hashMap = new HashMap<>(); //添加 Student student1 = new Student("孙悟空", 100); Student student2 = new Student("猪八戒", 110); Student student3 = new Student("沙和尚", 111); hashMap.put(student1,"北京"); hashMap.put(student2,"上海"); hashMap.put(student3,"杭州"); // hashMap.put(student3,"株州"); System.out.println(hashMap.size()); System.out.println(hashMap); System.out.println(hashMap.get(student1)); /* 下面添加会成功 因为new是一个新的对象 和student3 不一样 因为是使用key的hashcode的equal方法 来作为重复依据 比得是地址 解决:重写equals方法和hashcode在Student类中 @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Student student = (Student) o; return stuNo == student.stuNo && Objects.equals(name, student.name); } @Override public int hashCode() { return Objects.hash(name, stuNo); } */ hashMap.put(new Student("沙和尚", 111),"北京"); System.out.println(hashMap); //删除 // hashMap.remove(student3); // System.out.println(hashMap.size()); //遍历 //1使用keySet方法 System.out.println("======1使用keySet方法====="); for (Student student : hashMap.keySet()) { System.out.println(student);//Student{name='猪八戒', stuNo=110} System.out.println(hashMap.get(student));//上海 } //2使用entrySet集合 System.out.println("======2使用entrySet集合====="); for (Map.Entry<Student, String> entry : hashMap.entrySet()) { System.out.println(entry);//Student{name='猪八戒', stuNo=110}=上海 System.out.println(entry.getKey());//Student{name='猪八戒', stuNo=110} System.out.println(entry.getValue());//上海 } //判断 System.out.println(hashMap.containsKey(student1)); System.out.println(hashMap.containsKey(new Student("沙和尚", 111)));//重写方法前判断为false 现在为true System.out.println(hashMap.isEmpty()); } }
-
源码分析:
-
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 hashMap的初始容量大小16 static final int MAXIMUM_CAPACITY = 1 << 30;//hashMap数组最大容量 static final float DEFAULT_LOAD_FACTOR = 0.75f;//默认加载因子 static final int TREEIFY_THRESHOLD = 8;//当链表长度大于8,调整为红黑树 JDK1.8 static final int UNTREEIFY_THRESHOLD = 6;//当链表长度小于6 调整为链表 JDK1.8 static final int MIN_TREEIFY_CAPACITY = 64;//当链表长度大于8时 并且集合元素大于等于64 调整为红黑树JDK1.8 transient Node<K,V>[] table;//在hashMap刚刚创建没有添加元素时 为null transient int size;//为0
-
总结:
-
hashMap刚刚创建时 table是null 为了节省空间 当添加了第一个元素 table容量调整为16
-
当元素个数大于阈值(16*0.75=12)是 进行扩容 扩容为原来两倍 目的减少调整元素的个数
-
JDK1.8 当链表长度大于8时 并且集合元素大于等于64 调整为红黑树 目的提高执行效率
-
当链表长度小于6 调整为链表 JDK1.8
-
JDK1.8前 链表是头插入 JDK1.8后 链表是尾插入 头插入在多线程的情况下可能有死链
-
-
HashTable 了解就行
JDK1.0 线程安全 运行效率慢 不允许null作为key或者value
默认初始容量11 加载因子0.75
子类Properties使用比较多
要求key和value都是String 通常用于配置文件的读取 与流联系紧密
TreeMap:
存储结构 红黑树
实现SortedMap接口(Map的子接口),可以对key自动排序
package Generic; import java.util.Map; import java.util.Set; import java.util.TreeMap; /** * TreeMap的使用 */ public class TestTreeMap { public static void main(String[] args) { TreeMap<Student, String> treeMap = new TreeMap<>(); Student student1 = new Student("孙悟空", 1001); Student student2 = new Student("猪八戒", 1002); Student student3 = new Student("沙和尚", 1003); /* 报错: java.lang.ClassCastException: Generic.Student cannot be cast to java.lang.Comparable 因为Student没有实现Comparable接口 需要实现Comparable接口 重写CompareTo方法 怎么比较 @Override public int compareTo(Student o) { int n2 = this.stuNo-o.getStuNo(); //只比较学号 return n2; } 或者使用比较器 */ treeMap.put(student1,"北京"); treeMap.put(student2,"上海"); treeMap.put(student3,"南昌"); System.out.println(treeMap.size()); System.out.println(treeMap); //遍历 //1.使用keySet for (Student student : treeMap.keySet()) { System.out.println(student+""+treeMap.get(student)); } //使用entrySet Set<Map.Entry<Student, String>> entrySet = treeMap.entrySet(); for (Map.Entry<Student, String> entry : entrySet) { System.out.println(entry); System.out.println(entry.getValue()); System.out.println(entry.getKey()); } //判断 System.out.println(treeMap.containsKey(student1)); } }
Collection工具类
j集合工具类 定义了除了存取以外的集合常用方法
reverse 反转集合中元素顺序
shuffle 随机重置集合元素顺序
sort 升序排序
package CollectionFramework; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; /** * 演示Collections 工具类的使用 */ public class TestCollectionClass { public static void main(String[] args) { ArrayList<Integer> list = new ArrayList<>(); list.add(20); list.add(2); list.add(10); list.add(12); list.add(25); list.add(8); //sort升序排序 System.out.println("排序前"+list); Collections.sort(list); System.out.println("排序后"+list); //二分查找 binarySearch 必须先排序 int i = Collections.binarySearch(list, 12); System.out.println(i);//3 //copy复制 ArrayList<Integer> dest = new ArrayList<>(); /* Collections.copy(dest,list);报错 java.lang.IndexOutOfBoundsException: Source does not fit in dest 这个方法要求双方的大小一致 否则报错 */ for (int j = 0; j < list.size(); j++) { dest.add(0);//解决方法 } Collections.copy(dest,list); System.out.println(dest); // reverse 反转 Collections.reverse(list); System.out.println(list); //shuffle 打乱 Collections.shuffle(list); System.out.println(list); //补充 //List转成数组 Integer[] integers = list.toArray(new Integer[0]); System.out.println(integers.length); System.out.println(Arrays.toString(integers)); //数组变集合 String[] names = {"张三","李四","王五"}; //这个集合是受限集合 无法添加删除 List<String> list1 = Arrays.asList(names); System.out.println(list1); int[] nums = {100,200,300,400,500}; List<int[]> ints = Arrays.asList(nums);//基本数据类型转集合 《》里面只能写对应的基本类型 不能写包装类 } }
集合总结:
TreeSet TreeMap 两个集合添加的对象 必须实现 Comparable 接口重写CompareTo方法 或者实现比较器
比较器:
TreeSet<String> treeSet = new TreeSet<>(new Comparator<String>() { @Override public int compare(String o1, String o2) { //int n1=o1.length()-o2.length(); //int n2=o1.compareTo(o2);//原来的比较规则 //return n1==0?n2:n1; //里面写比较规则 } });
List集合 有序 有下标 元素可以重复
-
ArrayList 数组实现 查询快 增删慢 JDK1.2版本加入的 运行效率快 线程不安全
-
Vector 数组结构 查询快 增删慢JDK1.0版本的 运行效率慢 线程安全 现在已经基本不使用了
-
LinkedList 链表结构实现 增删快 查询慢 双向链表
Set集合 无序 无下标 元素不可重复
-
HashSet 基于HashCode实现元素不可重复当存入元素的哈希码相同时,会调用equals进行确认 如果结果为true 则拒绝后者存入
-
TreeSet
-
基于排列顺序实现元素不重复 二叉树 红黑树(平衡二叉树)
-
实现SortedSet接口 对集合元素自动排序
-
元素对象的类型必须实现Comparable接口 指定排序顺序
-
Comparator接口的使用 定制比较(比较器)* 使用比较器后 集合了的元素可以不用实现Comparable接口
-
通过CompareTo方法确定是否是重复元素
-
Map集合 存储一对数据 无序 无下标 键不可重复 值可以 重复 哈希表结构
-
HashMap JDK1.2 线程不安全 运行效率快 允许用null作为key或者value
-
HashTable JDK1.0 线程安全 运行效率慢 不允许null作为key或者value
-
TreeMap 存储结构 红黑树实现SortedMap接口(Map的子接口),可以对key自动排序