1、集合的概念
2、Collection接口
3、List接口与实现类
4、泛型和工具类
5、Set接口与实现类
6、Map接口与实现类
集合的概念
- 对象的容器,定义了对多个对象进行操作的常用方法。可实现数组的功能。
- 和数组的区别:
- (1)数组长度固定,集合长度不固定。
- (2)数组可以存储基本类型和引用类型,集合只能存储引用类型。
- 位置:java.util.*;
Collection体系集合
- Interface:Collection,为该体系结构的根接口,代表一组对象,称为“集合”。
- Interface:List,有序、有下标、元素可重复;
- Class:ArrayList
- Class:LinkedList
- Class:Vector
- Interface:Set,无序、无下标、元素不能重复
- Class:HashSet
- Interface:SortedSet
- Class:TreeSet
- Interface:List,有序、有下标、元素可重复;
Collection父接口
-
特点:代表一组任意类型的对象,无序、无下标、不能重复
-
方法:
- boolean add(Object obj)//添加一个对象
- boolean addAll(Collection c)//将一个集合中的所有对象添加到此集合中
- void clear()//清空此集合中的所有对象
- boolean contains(Object o)//检查此集合中是否包含o对象
- boolean equals(Object o)//比较此集合是否与指定对象相等
- boolean isEmpty()//判断此集合是否为空
- boolean remove(Object o)//在此集合中移除o对象
- int size()//返回此集合中的元素个数
- Object[] toArray()//将此集合转换成数组
-
迭代器Iterator
- hasNext();有没有下一个元素
- Next();获取下一个元素
- remove();删除当前元素
-
Collection的使用1
-
package com.collection; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; /** * Collection接口使用说明 * (1)添加元素 * (2)删除元素 * (3)遍历元素 * (4)判断 * @author A_sh * */ public class Demo01 { public static void main(String args[]){ //创建集合 Collection collection = new ArrayList(); //(1)添加元素 collection.add("苹果"); collection.add("香蕉"); collection.add("西瓜"); collection.add("榴莲"); System.out.println("元素个数:"+collection.size()); System.out.println(collection); //(2)删除元素 /*collection.remove("西瓜");*/ /*collection.clear();*/ System.out.println("元素个数:"+collection.size()); //(3)遍历元素【重点】 /*3.1使用增强for循环*/ System.out.println("-------------3.1使用增强for循环-------------"); for (Object o: collection) { System.out.println(o); } /*3.2使用迭代器(迭代器专门用来遍历集合的一种方式)*/ //hasNext();有没有下一个元素 //next();获取下一个元素 //remove();删除当前元素 System.out.println("----------------3.2使用迭代器---------------"); Iterator it = collection.iterator(); while(it.hasNext()){ String s = (String)it.next(); System.out.println(s); //collection.remove(s);/*java.util.ConcurrentModificationException并发修改异常*/ /*it.remove();*///用Iterator中的remove();函数删除 } System.out.println("元素个数:"+collection.size()); //(4)判断 System.out.println("----------------判断---------------"); System.out.println(collection.contains("西瓜")); System.out.println(collection.contains("葡萄")); System.out.println(collection.isEmpty()); } }
-
-
Collection的使用2
-
package com.collection; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; public class Demo02 { public static void main(String[] args){ //新建Collection对象 Collection collection = new ArrayList(); Student s1 = new Student("曾阿牛",17); Student s2 = new Student("张无忌",18); Student s3 = new Student("张三丰",100); //1、添加数据 collection.add(s1); collection.add(s2); collection.add(s3); System.out.println("元素个数:"+collection.size()); System.out.println(collection.toString()); //2、删除 //collection.remove(s3); /*collection.remove(new Student("王重阳",99));*/ /*collection.clear();*///清除集合 System.out.println("删除之后:"+collection.size()); //3、遍历 //3.1、增强for System.out.println("-------------3.1使用增强for循环-------------"); for (Object o: collection) { Student s = (Student) o; System.out.println(o.toString()); } //3.2、迭代器hasNext();next();remove();迭代过程中不能使用collection的删除方法 System.out.println("----------------3.2使用迭代器---------------"); Iterator it = collection.iterator(); while(it.hasNext()){ Student s = (Student)it.next(); System.out.println(s.toString()); } //4、判断 System.out.println("----------------判断---------------"); System.out.println(collection.contains(s1)); 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之间的集合元素。
-
List接口使用1:
-
package com.collection; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.ListIterator; /** * List子接口的使用 * 特点:1、有序,有下标;2、可以重复 * @author A_sh * */ public class Demo03 { public static void main(String[] args){ //先创建集合对象 List list = new ArrayList(); //1、添加元素 list.add("Apple"); list.add("xiaomi"); list.add(0,"huawei"); System.out.println("元素个数:"+list.size()); System.out.println(list.toString()); //2、删除元素 //list.remove("Apple"); list.remove(0); System.out.println("删除之后:"+list.size()); System.out.println(list.toString()); //3、遍历 //3.1、使用for循环 System.out.println("-------------3.1使用for循环----------------"); for(int i=0;i<list.size();i++){ System.out.println(list.get(i)); } //3.2、使用增强for循环 System.out.println("-------------3.2使用增强for循环----------------"); for(Object o: list){ System.out.println(o); } //3.3、使用迭代器 System.out.println("-------------3.3使用迭代器----------------"); Iterator it = list.iterator(); while(it.hasNext()){ System.out.println(it.next()); } //3.4、使用列表迭代器 /* 和Iterator的区别: ListIterator可以向前或者向后遍历, 添加、删除、修改元素*/ System.out.println("-------------3.4使用列表迭代器----------------"); System.out.println("-------------从前往后遍历----------------"); ListIterator lis = list.listIterator(); while (lis.hasNext()){ System.out.println(lis.nextIndex()+":"+lis.next()); } System.out.println("-------------3.4使用列表迭代器----------------"); System.out.println("-------------从后往前遍历----------------"); while(lis.hasPrevious()){ System.out.println(lis.previousIndex()+":"+lis.previous()); } //4、判断 System.out.println(list.contains("xiaomi")); System.out.println(list.isEmpty()); //5、获取 System.out.println(list.indexOf("Apple")); } }
-
-
List接口使用2
-
package com.collection; import java.util.ArrayList; import java.util.List; public class Demo04 { public static void main(String[] args){ //创建集合 List list = new ArrayList(); //1添加数字数据(自动装箱) list.add(0); list.add(1); list.add(2); list.add(3); list.add(4); //隐藏有自动装箱,此时的数据已经是装箱后的数据 System.out.println("元素个数:"+list.size()); System.out.println(list.toString()); //2删除操作 /*list.remove(0);//传入脚标*/ /*list.remove((Object) 3);//删除元素:3*/ list.remove(new Integer(3));//删除元素3 System.out.println("删除元素:"+list.size()); System.out.println(list.toString()); //3补充方法subList,返回子集合,含头不含尾 List subList = list.subList(1,3); System.out.println(subList.toString()); } }
-
- List实现类
- ArrayList【重点】:
- 数组结构实现,查询快、增删慢
- JDK1.2版本,运行效率快,线程不安全
- Vector:
- 数组结构实现,查询快,增删慢
- JDK1.0版本,运行效率慢,线程安全
- LinkedList:
- 链表结构实现,增删快,查询慢
- ArrayList【重点】:
ArrayList的使用
package com.collection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;
public class Demo05 {
public static void main(String[] args) {
//创建集合
ArrayList arrayList = new ArrayList<>();
//1添加元素
Student s1 = new Student("刘德华",48);
Student s2 = new Student("郭富城",59);
Student s3 = new Student("梁朝伟",50);
Student s4 = new Student("周星驰",48);
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
arrayList.add(s4);
System.out.println("元素个数:"+arrayList.size());
System.out.println(arrayList.toString());
//2删除元素
arrayList.remove(new Student("刘德华",48));//此处Student类中重写equals方法(修改比较规则)后,可实现删除元素
System.out.println("删除之后:"+arrayList.size());
System.out.println(arrayList.toString());
//3遍历元素【重点】
//3.1使用迭代器
System.out.println("-------------3.1使用迭代器----------");
Iterator it = arrayList.iterator();
while(it.hasNext()){
Student s = (Student) it.next();
System.out.println(s.toString());
}
//3.2列表迭代器
System.out.println("-------------3.1列表迭代器----------");
ListIterator its = arrayList.listIterator();
while(its.hasNext()){
Student s = (Student)its.next();
System.out.println(s.toString());
}
//4判断
System.out.println(arrayList.contains(new Student("梁朝伟",50)));
System.out.println(arrayList.isEmpty());
//5查找
System.out.println(arrayList.indexOf(new Student("梁朝伟",50)));
}
}
**【重点】**重写Student类的equals方法:
package com.collection;
import java.util.Objects;
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
//1、判断是否同一对象
if (this == o) return true;
//2、判断是否Student类型
if (!(o instanceof Student)) return false;
//3、比较属性
Student student = (Student) o;
return age == student.age &&
name.equals(student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
*ArrayList源码分析
- DEFAULT_CAPACITY 默认容量,【注意】如果没有向集合中添加元素,默认容量为0
- elementData 存放元素的数组
- size 实际元素个数
- add() 添加元素
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_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);//扩容,此时minCapacity为10
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);//每次扩容是原来的1.5倍
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);//初次扩容为10
}
Arrays.copyOf()源码:
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
@SuppressWarnings("unchecked")
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
/**
这段代码定义了一个静态方法copyOf,用于创建一个新的数组,该数组是原始数组的副本,并具有指定的新长度和新类型。
方法的参数说明如下:
<T,U>:泛型类型参数,T表示返回数组中元素的类型,U表示原始数组中元素的类型。
original:要被复制的原始数组。
newLength:新数组的长度。
newType:新数组的类型。
方法的主要逻辑如下:
1、使用SuppressWarnings("unchecked")抑制未检查的类型转换警告。
2、判断newType是否为Object[]类,如果是,则创建一个新的Object数组并强制转换为T[]类型;否则,使用Array.newInstance方法根据newType的组件类型创建一个新的数组并强制转换为T[]类型。
3、使用System.arraycopy方法将原始数组中的元素复制到新数组中,复制的长度为原始数组长度和新长度中的较小值。
4、返回新创建的数组副本。
*/
Vector的使用
- 存储结构:数组
- 使用枚举器【】遍历
package com.collection;
import java.util.Enumeration;
import java.util.Vector;
/***
* 演示Vector集合的使用
* 存储结构:数组
* @author A_sh
*/
public class Demo06 {
public static void main(String[] args) {
Vector vector = new Vector<>();
//1添加元素
vector.add("草莓");
vector.add("西瓜");
vector.add("苹果");
System.out.println("元素个数:"+vector.size());
//2删除元素
/*vector.remove(0);
vector.remove("西瓜");
System.out.println("元素个数:"+vector.size());
vector.clear();
System.out.println("元素个数:"+vector.size());*/
//3遍历
//使用枚举器【】
Enumeration en = vector.elements();
while(en.hasMoreElements()){
String o = (String)en.nextElement();
System.out.println(o);
}
//4判断
System.out.println(vector.contains("西瓜"));
System.out.println(vector.isEmpty());
//5补充
System.out.println(vector.firstElement());
System.out.println(vector.lastElement());
System.out.println(vector.elementAt(0));
}
}
LinkedList的使用
package com.collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;
public class Demo07 {
public static void main(String args[]){
//创建集合
LinkedList linkedList = new LinkedList<>();
//1添加元素
Student s1 = new Student("成剑",25);
Student s2 = new Student("洛开样",25);
Student s3 = new Student("徐招招",29);
linkedList.add(s1);
linkedList.add(s2);
linkedList.add(s3);
System.out.println("元素个数:"+linkedList.size());
System.out.println(linkedList.toString());
//2删除元素
/*linkedList.remove(0);
linkedList.remove(new Student("罗开样",25));
System.out.println("元素个数:"+linkedList.size());*/
//3遍历
//3.1for循环
System.out.println("-------------for-------------");
for(int i=0; i<linkedList.size(); i++){
System.out.println(linkedList.get(i));
}
//3.2增强for循环
System.out.println("-----------增强for-----------");
for(Object o : linkedList){
Student s = (Student) o;
System.out.println(s);
}
//3.3迭代器
System.out.println("-----------迭代器-----------");
Iterator e = linkedList.iterator();
while(e.hasNext()){
Student student = (Student) e.next();
System.out.println(student.toString());
}
//3.4列表迭代器
System.out.println("---------列表迭代器---------");
ListIterator llt = linkedList.listIterator();
while(llt.hasNext()){
Student student = (Student) llt.next();
System.out.println(student.toString());
}
//4判断
System.out.println("---------判断---------");
System.out.println(linkedList.contains(new Student("徐招招",29)));
System.out.println(linkedList.isEmpty());
//5获取
System.out.println("---------获取---------");
System.out.println(linkedList.indexOf(s1));
}
}
*LinkedList源码分析
元素:
transient int size = 0;
transient Node first;
transient Node last;
方法:add()
节点:Node
//节点
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
//prev:前一个指向
//element:当前元素值
//next:后一个指向
this.item = element;
this.next = next;
this.prev = prev;
}
}
//add()
public boolean add(E e) {
linkLast(e);
return true;
}
//linkLast()
void linkLast(E e) {
final Node<E> l = last;//last的指向赋给l
final Node<E> newNode = new Node<>(l, e, null);//对newNode中三个元素传参
last = newNode;//last指向newNode
if (l == null)
first = newNode;//当newNode为链表中第一个被添加进来的节点时,first指向newNode
else
l.next = newNode;//当newNode不是链表中第一个被添加进来的节点时,l.next指向它
size++;
modCount++;
}
ArrayList和LinkList的区别:
泛型
- Java泛型是JDK1.5中引入的一个新特性,其本质是参数化类型,把类型作为参数传递。
- 常见形式有泛型类、泛型接口、泛型方法。
- 语法:
- <T,…>T称为类型占位符,表示一种引用类型。
- 好处:
- 提高代码重用性。
- 防止类型转换异常,提高代码的安全性。
泛型类&泛型接口&泛型方法
package com.collection;
/**
* 泛型类
* 语法:类名<T>
* T是类型占位符,表示一种引用类型,如果编写多个,使用逗号隔开
* @author A_sh
* */
public class MyGeneric<T> {
//使用泛型T
//1创建变量
T t;
//2泛型作为方法的参数
public void show(T t){
System.out.println(t);
}
//3泛型作为方法的返回值
public T getT(){
return t;
}
}
package com.collection;
/**
* 泛型接口
* 语法:接口名<T>
* 注意:不能创建泛型静态常量
* @param <T>
*/
public interface MyInterface<T> {
String name = "Zhangsan";
T server(T t);
}
//接口实现类1
public class MyInterfaceImpl1 implements MyInterface<String>{
@Override
public String server(String s) {
System.out.println(s);
return s;
}
}
//接口实现类2
public class MyInterfaceImpl2<T> implements MyInterface<T> {
@Override
public T server(T t) {
System.out.println(t);
return t;
}
}
package com.collection;
/**
* 泛型方法
* 语法:<T>返回值类型
*/
public class MyGenericMethod {
//泛型方法,静态与否均可
public <T> T show (T t){
System.out.println("泛型方法"+t);
return t;
}
}
main:
package com.collection;
public class TestGeneric {
public static void main(String[] args){
//使用泛型类创建对象
//【注意】1、泛型只能使用引用类型;2、不同的泛型类型对象之间不能相互赋值
MyGeneric<String> myGeneric1 = new MyGeneric<String>();
myGeneric1.t = "Hello";
myGeneric1.show("Hello,everyone");
String string = myGeneric1.getT();
System.out.println(string);
MyGeneric<Integer> myGeneric2 = new MyGeneric<Integer>();
myGeneric2.t = 100;
myGeneric2.show(200);
Integer integer = myGeneric2.getT();
System.out.println(integer);
//泛型接口实现类的使用
MyInterfaceImpl1 impl1 = new MyInterfaceImpl1();
impl1.server("chenjian");
MyInterfaceImpl2<Integer> impl2 = new MyInterfaceImpl2<Integer>();
impl2.server(100);
//泛型方法的使用
MyGenericMethod myGenericMethod = new MyGenericMethod();
myGenericMethod.show("中国加油");
myGenericMethod.show(100);
myGenericMethod.show(3.14);
}
}
泛型集合
- 概念:参数化类型、类型安全的集合,强制集合元素的类型必须一致。
- 特点:
- 编译时即可检查,而非运行时抛出异常。
- 访问时,不必类型转换(拆箱)。
- 不同泛型之间引用不能相互赋值,泛型不存在多态。
package com.collection;
/**
* 泛型集合
*/
import java.util.ArrayList;
import java.util.Iterator;
public class Demo08 {
public static void main(String[] args) {
ArrayList arrayList = new ArrayList();
arrayList.add("金言");
arrayList.add("康德");
arrayList.add("阿杉");
arrayList.add(100);
arrayList.add(200);
/*for(Object object:arrayList){
String string = (String)object;
System.out.println(string);
//java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
}*/
ArrayList<Student> arrayList1 = new ArrayList<>();
Student s1 = new Student("金言",20);
Student s2 = new Student("康德",20);
Student s3 = new Student("阿杉",20);
arrayList1.add(s1);
arrayList1.add(s2);
arrayList1.add(s3);
Iterator<Student> it = arrayList1.iterator();
while(it.hasNext()){
Student s = it.next();
System.out.println(s.toString());
}
}
}
Set子接口
- 特点:无序、无下标、元素不可重复。
- 方法:全部继承自Collection中的方法。
Set实现类
- HashSet【重点】:
- 基于HashCode实现元素不重复。
- 当存入元素的哈希码相同时,会调用equals进行确认,如结果为true,则拒绝后者存入。
- TreeSet:
- 基于排列顺序实现元素不重复。
- 实现SortedSet接口,对集合元素自动排序。
- 【重点】元素对象的类型必须实现Comparable接口,指定排序规则。
- 通过CompareTo方法来确定元素是否重复。
- 存储结构为:红黑树
package com.set;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* Set接口的使用
*特点:(1)无序、没有下标;(2)不能重复
* @author A_sh
*/
public class Demo01 {
public static void main(String[] args){
//创建集合
Set<String> set = new HashSet<>();
//1添加元素
//数据存放没有顺序
set.add("苹果");
set.add("华为");
set.add("小米");
set.add("华为");//不能重复
System.out.println("数据个数:"+set.size());
System.out.println(set.toString());//打印
//2删除数据
/*set.remove("苹果");
System.out.println(set.toString());*/
//3遍历【重点】
//3.1使用增强for
System.out.println("---------使用增强for------------");
for(String string : set ){
System.out.println(string);
}
//3.2使用迭代器
System.out.println("---------使用迭代器------------");
Iterator<String> it = set.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
//4判断
System.out.println(set.contains("华为"));
System.out.println(set.isEmpty());
}
}
【重点】HashSet存储结构
存储结构:哈希表(组+链表+红黑树)
* (1)根据hashCode来计算保存的位置,如果位置为空,则直接保存;
* (2)如果不为空,再执行equals()方法,如果equals()方法为true,则认为重复,否则,形成链表
Person类(重写equals()和hashCode()方法)
package com.set;
import java.util.Objects;
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Person)) return false;
Person person = (Person) o;
return age == person.age &&
name.equals(person.name);
}
@Override
public int hashCode() {
//(1)31是质数,减少散列冲突;(2)31提高执行效率 ——> 31*i=(i<<5)-i
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
package com.set;
import java.util.HashSet;
import java.util.Iterator;
/**
* Hashset的使用
* 存储结构:哈希表(数组+链表+红黑树)
* (1)根据hashCode来计算保存的位置,如果位置为空,则直接保存;
* (2)如果不为空,再执行equals()方法,如果equals()方法为true,则认为重复,否则,形成链表
*/
public class Demo03 {
public static void main(String[] args) {
//创建集合
HashSet<Person> persons = new HashSet<>();
//1添加数据
Person p1 = new Person("刘德华",20);
Person p2 = new Person("郭富城",22);
Person p3 = new Person("梁朝伟",23);
persons.add(p1);
persons.add(p2);
persons.add(p3);
//persons.add(p3);重复
persons.add(new Person("梁朝伟",23));//重写equals()和hashCode()方法前,可行
System.out.println("元素个数:"+persons.size());
System.out.println(persons.toString());
//2删除元素
persons.remove(new Person("梁朝伟",23));//可删
System.out.println("删除之后:"+persons.size());
//3遍历
//3.1增强for
System.out.println("-------------增强for---------------");
for (Person person:
persons) {
System.out.println(person);
}
//3.2使用迭代器
System.out.println("-------------使用迭代器-------------");
Iterator<Person> iterator = persons.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
//判断
System.out.println(persons.contains(p1));//true
System.out.println(persons.isEmpty());//false
}
}
TreeSet的使用1:
package com.set;
import java.util.Objects;
public class Person implements Comparable<Person>{
//实现Comparable接口
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Person)) return false;
Person person = (Person) o;
return age == person.age &&
name.equals(person.name);
}
@Override
public int hashCode() {
//(1)31是质数,减少散列冲突;(2)31提高执行效率 ——> 31*i=(i<<5)-i
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
//重写compareTo接口,先按姓名比再按年龄比
@Override
public int compareTo(Person o) {
int n1 = this.getName().compareTo(o.getName());
int n2 = this.age-o.getAge();
return n1==0? n2:n1;
}
}java
package com.set;
import java.util.Iterator;
import java.util.TreeSet;
/**
* 使用TreeSet保存数据
* 存储结构:红黑树
* 要求:元素必须要实现Comarable接口
*/
public class Demo05 {
public static void main(String[] args) {
//创建集合
TreeSet<Person> treeset = new TreeSet<>();
//1添加元素
Person p1 = new Person("xyz",20);
Person p2 = new Person("abc",23);
Person p3 = new Person("zs",24);
Person p4 = new Person("zs",25);
treeset.add(p1);
treeset.add(p2);
treeset.add(p3);
treeset.add(p4);
System.out.println("元素个数"+treeset.size());
System.out.println(treeset.toString());
//2删除
treeset.remove(p1);
System.out.println("元素个数"+treeset.size());
//3遍历
//3.1使用增强for
System.out.println("-------------------");
for (Person person:
treeset) {
System.out.println(person.toString());
}
//3.2使用迭代器
System.out.println("-------------------");
Iterator<Person> it = treeset.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
//4判断
System.out.println(treeset.contains(new Person("zs",24)));
}
}
TreeSet的使用2:
package com.set;
import java.util.Comparator;
import java.util.TreeSet;
/**
* TreeSet集合的使用
* Comparable:可比较的
* Comparator:实现定制比较(比较器)
*/
public class Demo06 {
public static void main(String[] args) {
//创建集合,并指定比较规则
TreeSet<Person> persons = 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 p1 = new Person("xzy",20);
Person p2 = new Person("abc",22);
Person p3 = new Person("wasd",25);
Person p4 = new Person("chenj",25);
persons.add(p1);
persons.add(p2);
persons.add(p3);
persons.add(p4);
System.out.println(persons.toString());
}
}
Map集合
Map(Interface)<——HashMap(Class)
Map(Interface)<——SortedMap(interface)<——TreeMap(class)
Map父接口
-
特点:存储一对数据(Key-Value),无序、无下标,键不可重复,值可重复。
-
方法:
- V put(K key,V value)//将对象存入集合中,关联键值。key重复则覆盖原值。
- Object get(Object key)//根据键获取对应的值。
- Set keySet()//返回所有key。
- Collection values()//返回包含所有值的Collection集合。
- Set<Map.Entry<K,V>> entrySet()//键值匹配的Set集合。
Map接口的使用,示例1:
package com.map.demo01;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Map接口的使用
* 特点:(1)存储键值对(2)键不能重复,值可以重复(3)无序
*/
public class Demo01 {
public static void main(String[] args) {
//创建Map集合
Map<String,String> map = new HashMap<>();
//1添加元素
map.put("us","美国");
map.put("uk","英国");
map.put("cn","中国");
map.put("cn","中华人民共和国");//覆盖
System.out.println("元素个数:"+map.size());
System.out.println(map.toString());
//2删除
map.remove("us");
System.out.println("删除之后"+map.size());
map.put("usa","美国");
//3遍历
//3.1使用keySet()
System.out.println("------使用keySet()---------");
Set<String> keyset = map.keySet();
for(String key : keyset){
System.out.println(key+"--------"+map.get(key));
}
//3.2使用entrySet()
Set<Map.Entry<String,String>> entries = map.entrySet();
for(Map.Entry<String,String> entry : entries){
System.out.println("key:"+entry.getKey()+" value:"+entry.getValue());
}
//4判断
System.out.println(map.containsKey("cn"));
System.out.println(map.containsValue("德国"));
}
}
HashMap的使用:
Student类重写方法:hashcode()和equals()
package com.map.demo01;
import java.util.Objects;
public class Student {
private String name;
private int stuNo;
public Student(String name, int stuNo) {
this.name = name;
this.stuNo = stuNo;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getStuNo() {
return stuNo;
}
public void setStuNo(int stuNo) {
this.stuNo = stuNo;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", stuNo=" + stuNo +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Student)) return false;
Student student = (Student) o;
return stuNo == student.stuNo &&
Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, stuNo);
}
}
package com.map.demo01;
import java.util.HashMap;
import java.util.Map;
/**
* HashMap集合的使用
* 存储结构:哈希表(数组+链表+红黑树)
*使用key,hashcode()和equals()作为重复
*/
public class Demo02 {
public static void main(String[] args){
HashMap<Student,String> students = new HashMap<Student,String>();
//1添加元素
Student s1 = new Student("孙悟空",500);
Student s2 = new Student("猪八戒",300);
Student s3 = new Student("沙和尚",200);
students.put(s1,"北京");
students.put(s2,"上海");
students.put(s3,"天津");
students.put(s3,"南京");
students.put(new Student("沙和尚",200),"杭州");//添加成功
System.out.println("元素个数:"+students.size());
System.out.println(students.toString());
//2删除元素
students.remove(s1);
System.out.println(students.size());
System.out.println(students.toString());
//3遍历
//3.1使用keySet()方法
for(Student key : students.keySet()){
System.out.println(key+"==========="+students.get(key));
}
//3.2entrySet()方法
for(Map.Entry<Student,String> entry : students.entrySet()){
System.out.println(entry.getKey()+"==========="+entry.getValue());
}
//4判断
System.out.println(students.containsKey(s2));
System.out.println(students.containsValue("上海"));
}
}
HashMap源码分析
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16,hashMap初始容量大小
static final int MAXIMUM_CAPACITY = 1 << 30;//hashMapd数组最大容量
static final float DEFAULT_LOAD_FACTOR = 0.75f;//默认加载因子
static final int TREEIFY_THRESHOLD = 8;//jdk1.8当链表长度大于8时,调整成红黑树
static final int UNTREEIFY_THRESHOLD = 6;//jdk1.8当链表长度小于6时,调整成链表
static final int MIN_TREEIFY_CAPACITY = 64;//jdk1.8当链表长度大于8时,并且集合元素个数大于等于64时,调整成红黑树
transient Node<K,V>[] table;//哈希表中的数组
size;//元素个数
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
【注意点】put()方法
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
总结:
(1)HashMap刚创建时,table是null,为了节省空间,当添加第一个元素时,table容量调整为16;
(2)当元素个数大于阈值(16*0.75=12)时,会进行扩容,扩容后大小为原来的两倍,目的时减少调整元素的个数;
(3)jdk1.8,当每个链表长度大于8并且数组元素个数大于等于64时, 会调整为红黑树,目的是提高执行效率;
(4)jdk1.8,当链表长度小于6时,调整成链表;
(5)jdk1.8以前,链表是头插入,1.8以后是尾插入;
Map集合的实现类
-
HashMap【重点】:
- jdk1.2版本,线程不安全,运行效率快;允许用null作为key或value
-
Hashtable
- jdk1.0版本,线程安全,运行效率慢;不允许null作为key或value
-
Properties:
- Hashtable的子类,要求key和value都是String。通常用于配置文件的读取。
TreeMap的使用
-
存储结构为红黑树
-
使用toString()方法时,需要重写CompareTo()方法
package com.map.demo01;
import java.util.Map;
import java.util.TreeMap;
/**
* TreeMap的使用
* 存储结构:红黑树
*/
public class Demo03 {
public static void main(String[] args){
//新建集合
TreeMap<Student,String> treeMap = new TreeMap<Student,String>();
//1添加元素
Student s1 = new Student("孙悟空",500);
Student s2 = new Student("猪八戒",300);
Student s3 = new Student("沙和尚",200);
treeMap.put(s1,"北京");
treeMap.put(s2,"上海");
treeMap.put(s3,"天津");
treeMap.put(s3,"南京");
System.out.println("元素个数:"+treeMap.size());
System.out.println(treeMap.toString());
//报错ClassCastException,
// 由于红黑树的数据结构和Student类型目前无法完成比较,需要重写CompareTo()方法
//2删除元素
treeMap.remove(s1);
System.out.println(treeMap.size());
System.out.println(treeMap.toString());
//3遍历
//3.1使用keySet()方法
for(Student key : treeMap.keySet()){
System.out.println(key+"==========="+treeMap.get(key));
}
//3.2entrySet()方法
for(Map.Entry<Student,String> entry : treeMap.entrySet()){
System.out.println(entry.getKey()+"==========="+entry.getValue());
}
//4判断
System.out.println(treeMap.containsKey(s2));
System.out.println(treeMap.containsValue("上海"));
}
}
Collections工具类
package com.map.demo01;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* Collections工具类的使用
*
*/
public class Demo04 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(20);
list.add(2);
list.add(5);
list.add(12);
list.add(30);
list.add(6);
//sort排序
System.out.println("排序之前:"+list.toString());
Collections.sort(list);//排序工具
System.out.println("排序之后:"+list.toString());
//binarySearch
int i = Collections.binarySearch(list,12);
System.out.println(i);
//copy复制
List<Integer> dest = new ArrayList<>();
for(int j = 0 ; j<list.size() ; j++){
dest.add(0);
}
Collections.copy(dest,list);//java.lang.IndexOutOfBoundsException: Source does not fit in dest
// dest需要提前设置链表长度和元素初始化
System.out.println(dest.toString());
//reverese反转
Collections.reverse(list);
System.out.println("反转之后:" +list.toString());
//shuffle打乱
Collections.shuffle(list);
System.out.println("打乱之后:" +list.toString());
//补充:list转成数组
System.out.println("--------list转成数组------------");
Integer[] arr = list.toArray(new Integer[0]);
System.out.println(arr.length);
System.out.println(Arrays.toString(arr));
//数组转成集合
String[] names = {"张三","李四","王五"};
List<String> list2 = Arrays.asList(names);
//此集合为受限集合,不能添加和删除元素
//把基本类型转为引用类型时,需要修改为包装类
System.out.println(list2);
Integer[] nums = {100,20,200,30,230};
List<Integer> list3 = Arrays.asList(nums);
System.out.println(list3);
}
}
总结
- 集合的概念:
- 对象的容器,和数组类似,定义了对多个对象进行操作的常用方法。
- List集合:
- 有序、有下标,元素可重复。(ArrayList、LinkedList、Vector)
- Set集合:
- 无序,无下标、元素不可重复。(HashSet、TreeSet)
- Map集合:
- 存储一对数据,无序、无下标、键不可重复,值可重复。(HashMap、HashTable、TreeMap)
- Collections:
- 集合工具类,定义了除了存取以外的集合常用方法。