集合框架
集合的概念
- 概念:对象的容器,定义了对多个对象进行操作的常用方法。可实现数组的功能
- 和数组区别:
- 数组长度固定,集合长度不固定
- 数组可以存储基本类型和引用类型,集合只能存储引用类型,不能存储基本类型
- 位置:java.util.*;
Collection接口与实现类
Collection体系
- Collection接口:该体系结构的根接口,代表一组对象,称为“集合”
- List接口特点:有序、有下标、元素可重复
- Set接口特点:无序、无下标、元素不可重复
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() //将此集合转换成数组
Collection接口使用
- 添加元素
- 删除元素
- 遍历元素
- 检查集合是否为空
存储字符串
package com.yushuo.collection.demo01;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Demo01 {
public static void main(String[] args) {
/**
* Collection接口使用
* 添加元素
* 删除元素
* 遍历元素
* 检查集合是否为空
*/
//创建接口
Collection collection = new ArrayList();
//添加元素
collection.add("苹果");
collection.add("西瓜");
collection.add("香蕉");
System.out.println("集合中元素个数:" + collection.size());
System.out.println(collection);//默认toString,强转String
/*
//删除元素
//删除特定元素
collection.remove("西瓜");
System.out.println("删除特定元素之后,集合中元素个数:" + collection.size());
System.out.println("删除特定元素之后,集合为:" + collection);//默认toString,强转String
//清空
collection.clear();
System.out.println("清空之后,集合中元素个数:" + collection.size());
System.out.println("清空元素之后,集合为:" + collection);//默认toString,强转String
*/
//遍历元素【重点】
//使用增强for
for (Object o : collection) {
System.out.println(o);//默认toString,强转String
}
//使用迭代器(迭代器,专门用来遍历集合的一种方法)
/**
* 使用迭代器(迭代器,专门用来遍历集合的一种方法)
* hasNext();有没有下一个元素
* next();获取下一个元素
* remove();删除当前元素
*
* 迭代过程中,不允许使用collection的方法
* 并发修改异常ConcurrentModificationException
*/
/*
Iterator iterator = collection.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());//默认toString,强转String
iterator.remove();
}
System.out.println("清空之后,集合中元素个数:" + collection.size());
System.out.println("清空元素之后,集合为:" + collection);//默认toString,强转String
*/
//检查集合是否为空
System.out.println(collection.contains("桃子"));
System.out.println(collection.contains("西瓜"));
}
}
存储类
package com.yushuo.collection.demo02;
//学生类
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student() {
}
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 +
'}';
}
}
package com.yushuo.collection.demo02;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Demo02 {
public static void main(String[] args) {
//collection使用,保存学生信息
//创建Collection对象
Collection collection = new ArrayList();
Student student1 = new Student("张三",20);
Student student2 = new Student("李四",21);
Student student3 = new Student("王五",22);
//添加学生数据,由于是ArrayList,可以重复添加
collection.add(student1);
collection.add(student2);
collection.add(student3);
System.out.println("集合的元素个数为:" + collection.size());
//由于Student类重写了toString,因此显示的信息更详细
System.out.println(collection);
/*
//删除学生数据
collection.remove(student1);
System.out.println("删除后集合的元素个数为:" + collection.size());
System.out.println("删除后集合为:" + collection);
collection.remove(new Student("李四",21));
//无法删除,因为新创建的类与之前的类仅是内容相同,不是相同的类
collection.clear();//清空,清空之后集合为空,但是Student对象还在
*/
//遍历学生数据
//增强for
for (Object o : collection) {
System.out.println(o);
}
//迭代器
Iterator iterator = collection.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
//判断
System.out.println(collection.contains(student1));//true
System.out.println(collection.contains(new Student("张三",20)));//false
}
}
List接口与实现类
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接口使用
存储字符串
package com.yushuo.list.demo01;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public class Demo01 {
public static void main(String[] args) {
//List接口:特点:有序、有下标、可以重复
//创建List对象
List list = new ArrayList();
//添加对象
list.add("苹果");
list.add("西瓜");
list.add(0,"香蕉");//在0位置添加对象
System.out.println("集合的元素个数为:" + list.size());
System.out.println("集合的元素为:" + list);
/*
//删除元素
//list.remove("苹果");//删除元素"苹果"
list.remove(1);//删除位置1的元素
System.out.println("删除后,集合的元素个数为:" + list.size());
System.out.println("删除后,集合的元素为:" + list);
*/
//遍历元素
//for
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
//增强for
for (Object o : list) {
System.out.println(o);
}
//迭代器
Iterator iterator = list.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
/**
* 列表迭代器ListIterator
* 与Iterator区别:
* 可以向前向后遍历
* 可以删除、修改元素
*/
ListIterator listIterator = list.listIterator();
//从前往后
while (listIterator.hasNext()){
System.out.println(listIterator.nextIndex() + ":" + listIterator.next());
}
//从后往前,执行完前面后,指针已经指向最末
while (listIterator.hasPrevious()){
System.out.println(listIterator.previousIndex() + ":" + listIterator.previous());
}
//判断
System.out.println(list.contains("苹果"));//true
System.out.println(list.isEmpty());//false
//获取位置
System.out.println(list.indexOf("苹果"));//1
System.out.println(list.indexOf("葡萄"));//没有,返回-1
}
}
存储数字数据
package com.yushuo.list.demo02;
import java.util.ArrayList;
import java.util.List;
public class Demo02 {
public static void main(String[] args) {
//List的使用,存储对象
//创建List对象
List list = new ArrayList();
/**
* 存储数字数据
* 默认包含自动装箱操作
* 集合无法存储基本类型,基本类型会自动装箱,为包装类
*/
list.add(20);
list.add(30);
list.add(40);
System.out.println("集合的元素个数为:" + list.size());
System.out.println("集合的元素为:" + list);
//删除元素
list.remove(0);//删除特定位置的元素
System.out.println("删除后的集合的元素个数为:" + list.size());
System.out.println("删除后的集合的元素为:" + list);
/*
list.remove(20);
输入的整数被认为是元素的位置,而不是元素本身
删除特定的元素20
list.remove((Object) 20);或者list.remove(new Integer(20));
这里new Integer(20)可以使用是因为Integer的equals比较的是内容,不是地址
*/
//返回子集合,范围fromIndex到toIndex-1
System.out.println(list.subList(0,1));
}
}
List实现类
ArrayList与LinkedList的区别:
- ArrayList存储结构为数组,为连续的内存空间,查询快、增删慢
- LinkedList存储结构为双向链表,为离散的内存空间,查询慢、增删快
ArrayList
ArrayList【重点】:
- 数组结构实现,查询快、增删慢
- JDK1.2版本,运行效率块、线程不安全
ArrayList的使用
package com.yushuo.list;
import java.util.Objects;
//学生类
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student() {
}
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 obj) {
//判断是否为同一个对象
if (this == obj){
return true;
}
//判断是否为空
if (obj == null){
return false;
}
//判断是否是Student相关类型
if (obj instanceof Student){
Student student = (Student) obj;
//比较属性
if (this.age == student.getAge() && this.name.equals(student.getName())){
return true;
}
}
//如果不满足属性相同
return false;
}
*/
//以下为快捷键生成的
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age && Objects.equals(name, student.name);
}
}
package com.yushuo.list;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;
public class Demo03 {
public static void main(String[] args) {
/**
* ArrayList的使用
* 存储结构:数组,查找遍历速度快、增删慢
*/
//创建集合
ArrayList arrayList = new ArrayList();
//添加元素,可重复
Student student1 = new Student("张三",20);
Student student2 = new Student("李四",21);
Student student3 = new Student("王五",22);
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("李四",21));不会删除
//因为二者内容相同但是地址不同,想要凭内容相同删除,需要重写equals
arrayList.remove(new Student("李四",21));//重写后删除成功
System.out.println("删除后的集合的元素个数为:" + arrayList.size());
System.out.println("删除后的集合的元素为:" + arrayList);
*/
//遍历元素【重点】
//使用迭代器
Iterator iterator = arrayList.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
//列表迭代器,顺序
ListIterator listIterator = arrayList.listIterator();
while (listIterator.hasNext()){
System.out.println(listIterator.next());
}
//列表迭代器,逆序
while (listIterator.hasPrevious()){
System.out.println(listIterator.previous());
}
//判断
System.out.println(arrayList.contains(student1));
//因为equals重写了,所有返回true,没重写则为false
System.out.println(arrayList.contains(new Student("张三",20)));
System.out.println(arrayList.isEmpty());//false
//查找
System.out.println(arrayList.indexOf(student1));
}
}
ArrayList源码分析
-
DEFAULT_CAPACITY = 10; 默认容量
注意:如果没有向集合中添加任何元素时,容量为0,添加一个元素之后,容量为10
初始容量为0,存放一个元素后扩容为10,之后每一次扩容,容量变为原本的1.5倍
-
elementData 存放元素的数组
-
size 实际元素个数
add()源码解析:
//初始size为0
public boolean add(E e) {
ensureCapacityInternal(size + 1);
// Increments modCount!!
//存放元素
elementData[size++] = e;
return true;
}
//确保数组有空间存储元素
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
//计算所需容量,参数为存储元素的数组elementData与存放元素所需最小容量minCapacity
private static int calculateCapacity(Object[] elementData, int minCapacity) {
//判断初始数组是否为空
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//数组为空时,比较所需最小容量与默认容量10,将较大值作为的计算结果
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
//数组非空时,计算得到的所需容量即为所需最小容量
return minCapacity;
}
//确保数组有足够的容量,参数minCapacity为所需容量
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
//如果所需容量超过现有数组大小,对数组进行扩充
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
//扩充数组,参数为数组所需最小容量minCapacity,存储10个元素以后,每次扩容,容量变为原先的1.5倍
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//oldCapacity >> 1右移一位即除2
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);
}
Vector
Vector:
- 数组结构实现,查询快、增删慢
- JDK1.0版本,运行效率慢、线程安全
Vector的使用
package com.yushuo.list;
import java.util.Enumeration;
import java.util.Vector;
public class Demo04 {
public static void main(String[] args) {
/**
* Vector集合的使用
* 存储结构:数组
*/
//创建集合
Vector vector = new Vector();
//添加元素
vector.add("苹果");
vector.add("西瓜");
vector.add("香蕉");
System.out.println("集合的元素个数为:" + vector.size());
System.out.println("集合的元素为:" + vector);
//删除,可以根据下标或根据元素删除,也可清空
//遍历
//使用枚举器
Enumeration enumeration = vector.elements();
while (enumeration.hasMoreElements()){
System.out.println(enumeration.nextElement());
}
//判断
System.out.println(vector.contains("苹果"));//true
//其他方法:firstElement()、lastElement()、elementAt(index)
}
}
LinkedList
LinkedList:
- 链表结构实现,增删快、查询慢
LinkedList的使用
package com.yushuo.list;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;
public class Demo05 {
public static void main(String[] args) {
/**
* LinkedList的使用
* 存储结构:双向链表
*/
//创建集合
LinkedList linkedList = new LinkedList();
//添加对象
Student student1 = new Student("张三",20);
Student student2 = new Student("李四",21);
Student student3 = new Student("王五",22);
linkedList.add(student1);
linkedList.add(student2);
linkedList.add(student3);
System.out.println("集合的元素个数为:" + linkedList.size());
System.out.println("集合的元素为:" + linkedList);
/*
//删除对象
linkedList.remove(student1);
System.out.println("集合的元素个数为:" + linkedList.size());
System.out.println("集合的元素为:" + linkedList);
linkedList.clear();//清空
*/
//遍历对象
//for
for (int i = 0; i < linkedList.size(); i++) {
System.out.println(linkedList.get(i));
}
//增强for
for (Object o : linkedList) {
System.out.println(o);
}
//迭代器
Iterator iterator = linkedList.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
//列表迭代器,顺序
ListIterator listIterator = linkedList.listIterator();
while (listIterator.hasNext()){
System.out.println(listIterator.next());
}
//逆序
while (listIterator.hasPrevious()){
System.out.println(listIterator.previous());
}
//判断
System.out.println(linkedList.contains(student1));
System.out.println(linkedList.isEmpty());
//获取
System.out.println(linkedList.indexOf(student2));
}
}
LinkedList源码分析
first 头指针,指向链表的头节点
last 尾指针,指向链表的尾节点
add()
//初始size为0
public boolean add(E e) {
ensureCapacityInternal(size + 1);
// Increments modCount!!
//存放元素
elementData[size++] = e;
return true;
}
//确保数组有空间存储元素
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
//计算所需容量,参数为存储元素的数组elementData与存放元素所需最小容量minCapacity
private static int calculateCapacity(Object[] elementData, int minCapacity) {
//判断初始数组是否为空
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//数组为空时,比较所需最小容量与默认容量10,将较大值作为的计算结果
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
//数组非空时,计算得到的所需容量即为所需最小容量
return minCapacity;
}
//确保数组有足够的容量,参数minCapacity为所需容量
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
//如果所需容量超过现有数组大小,对数组进行扩充
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
//扩充数组,参数为数组所需最小容量minCapacity,存储10个元素以后,每次扩容,容量变为原先的1.5倍
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//oldCapacity >> 1右移一位即除2
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);
}
泛型和工具类
泛型
泛型概念:
- JDK5中引入,提供了编译时类型安全检测机制,该机制允许在编译时检测到非法的类型
- 它的本质是参数化类型,也就是说所操作的参数类型被指定为一个参数
- 参数化类型:将类型由原来的具体的类型参数化,然后在使用/调用时传入具体的类型
- 这种参数类型可以在类、方法和接口中,分别称为泛型类、泛型方法、泛型接口
泛型定义格式:
- <类型>:指定一种类型的格式,这里的类型可以看成是形参
- <类型1,类型2, …>:指定多种类型的格式,多种类型之间用逗号隔开。这里的类型可以看成是形参
- 将来具体调用时给定的类型可以看成是实参,并且实参的类型只能是引用数据类型
泛型优点:
- 把运行时的问题提前到了编译器
- 避免了强制类型转换
package com.yushuo.generic;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Demo01 {
public static void main(String[] args) {
//泛型
//Collection集合存储字符串并遍历
//创建集合对象,可以存储任意类型
Collection collection = new ArrayList();
//添加元素
collection.add("hello");//类型是object
collection.add("world");
collection.add("java");
//100被自动装箱为Integer类型
collection.add(100);
//遍历集合
Iterator iterator = collection.iterator();
while (iterator.hasNext()){
/*
Object obj = iterator.next();//存储的是Object类型
System.out.println(obj);
*/
//可以强制转换为String类型
//报错ClassCastException,因为100是Integer类型的
String str = (String) iterator.next();
System.out.println(str);
}
}
}
package com.yushuo.generic.demo01;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Demo01_1 {
public static void main(String[] args) {
//泛型
//Collection集合存储字符串并遍历
//创建集合对象,限定单一类型String
Collection<String> collection = new ArrayList<String>();
//添加元素
collection.add("hello");//类型是object
collection.add("world");
collection.add("java");
//100被自动装箱为Integer类型
//报错,因为只能存储单一类型String
//把运行时会发生的问题提前在编译器就避免了
//collection.add(100);
//遍历集合
Iterator<String> iterator = collection.iterator();
while (iterator.hasNext()){
//不需要强制类型转换
String str = iterator.next();
System.out.println(str);
}
}
}
泛型类
定义格式:
-
格式:修饰符 class 类名<类型> {}
-
范例:publiuc class Generic< T > {}
此处T可以随便写为任意标示,常见的如T、E、K、V等形式的参数用于表示泛型
package com.yushuo.generic.demo02;
public class Student {
private String name;
public Student(String name) {
this.name = name;
}
public Student() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package com.yushuo.generic.demo02;
public class Teacher {
private Integer age;
public Teacher(Integer age) {
this.age = age;
}
public Teacher() {
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
package com.yushuo.generic.demo02;
//泛型类
public class Generic<T> {
private T t;
public Generic() {
}
public Generic(T t) {
this.t = t;
}
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
package com.yushuo.generic.demo02;
public class Demo02 {
public static void main(String[] args) {
Student student = new Student();
student.setName("张三");
Teacher teacher = new Teacher();
teacher.setAge(30);
//teacher.setAge("30");编译出错
System.out.println(student.getName());
System.out.println(teacher.getAge());
//上面两种类才能完成的事情,使用泛型类,一种类即可
//只有类指定为泛型的属性才会被设置为String,其余的保持原因
Generic<String> generic1 = new Generic<String>();
generic1.setT("张三");
Generic<Integer> generic2 = new Generic<Integer>();
generic2.setT(20);
System.out.println(generic1.getT());
System.out.println(generic2.getT());
}
}
泛型方法
定义格式:
- 格式:修饰符 <类型> 返回值类型 方法名(变量类型 变量名){}
- 范例:public < T > void show(T t){}
package com.yushuo.generic.demo03;
/*
public class Generic {
public void show(String s){
System.out.println(s);
}
public void show(Integer i){
System.out.println(i);
}
public void show(Boolean b){
System.out.println(b);
}
}
*/
/*
//泛型类改进
public class Generic<T> {
public void show(T t){
System.out.println(t);
}
}
*/
//泛型方法改进
public class Generic {
public <T> void show(T t){
System.out.println(t);
}
}
package com.yushuo.generic.demo03;
public class Demo03 {
public static void main(String[] args) {
/*
Generic generic = new Generic();
generic.show("张三");
generic.show(20);
generic.show(true);
//改进以前,generic.show(12.34);报错,因为没有提供对应类型参数的方法
*/
/*
//泛型类改进以后,每次创建对象都要明确类型
Generic<String> generic1 = new Generic<String>();
generic1.show("张三");
Generic<Integer> generic2 = new Generic<Integer>();
generic2.show(20);
Generic<Boolean> generic3 = new Generic<Boolean>();
generic3.show(true);
*/
//如何创建时不明确,调用方法才明确——泛型方法
//根据参数确定类型,传递什么类型参数,就是什么类型
Generic generic = new Generic();
generic.show("张三");
generic.show(20);
generic.show(true);
}
}
泛型接口
定义格式:
- 格式:修饰符 interface 接口名 <类型> {}
- 范例:public interface Generic < T > {}
package com.yushuo.generic.demo04;
public interface Generic<T> {
void show(T t);
}
package com.yushuo.generic.demo04;
//泛型接口实现类
public class GenericImpl<T> implements Generic<T>{
@Override
public void show(T t) {
System.out.println(t);
}
}
package com.yushuo.generic.demo04;
public class Demo04 {
public static void main(String[] args) {
GenericImpl<String> generic1 = new GenericImpl<String>();
generic1.show("张三");
GenericImpl<Integer> generic2 = new GenericImpl<Integer>();
generic2.show(20);
}
}
类型通配符
为了表示各种泛型List的父类,可以使用类型通配符
- 类型通配符:<?>
- List<?>:表示元素类型未知的List,它的元素可以匹配任何类型
- 这种带通配符的List仅表示它是各种泛型的父类,并不能把元素添加到其中
如果我们不希望List<?>是任何泛型List的父类,只希望它代表某一类泛型List的父类,可以使用类型通配符的上限
- 类型通配符上限:<? extends 类型>
- List<? extends Number>:它表示的类型是Number或者其子类型
除了可以指定类型通配符的上限,我们也可以指定类型通配符的下限
- 类型通配符下限:<? super 类型>
- List<? super Number>:它表示的类型是Number或者其父类型
package com.yushuo.generic.demo05;
import java.util.ArrayList;
import java.util.List;
public class Demo05 {
public static void main(String[] args) {
//类型通配符:<?>
List<?> list1 = new ArrayList<Object>();
List<?> list2 = new ArrayList<Number>();
List<?> list3 = new ArrayList<Integer>();
//类型通配符上限:<? extends 类型>
//List<? extends Number> list4 = new ArrayList<Object>();编译报错
//上限是Number,因此不能是Number的父类Object
List<? extends Number> list5 = new ArrayList<Number>();
List<? extends Number> list6 = new ArrayList<Integer>();
//类型通配符下限:<? super 类型>
List<? super Number> list7 = new ArrayList<Object>();
List<? super Number> list8 = new ArrayList<Number>();
//List<? super Number> list9 = new ArrayList<Integer>();编译报错
//下限是Number,因此不能是Number的子类Integer
}
}
可变参数
可变参数
可变参数又称参数个数可变,用作方法的形参出现:
- 格式:修饰符 返回值类型 方法名(数据类型… 变量名){}
- 范例:public static int sum(int… a){}
可变参数注意事项:
- 这里的变量其实是一个数组
- 如果一个方法有多个参数,包含可变参数,可变参数要放最后
package com.yushuo.generic.demo06;
public class Demo06 {
public static void main(String[] args) {
System.out.println(sum(10,20));
System.out.println(sum(10,20,30));
System.out.println(sum(10,20,30,40));
}
public static int sum(int... a){
//把多个参数放到数组a种
int sum = 0;
for (int i : a) {
sum += i;
}
return sum;
}
/*
可变参数需要放在最后
因为可变参数会把所有参数存放在数组中,其之后的形参就没东西存放了
public static int sum(int b,int... a){
}
*/
}
可变参数的使用
Arrays工具类中有一个静态方法:
- public static < T > List< T > asList(T… a):返回由指定数组支持的固定大小的列表
List接口中有一个静态方法:
- public static < E > List< E > of (E… elements):返回包含任意数量元素的不可变列表
Set接口中有一个静态方法:
- public static < E > Set< E > of(E… elements):返回一个包含任意数量元素的不可变集合
package com.yushuo.generic.demo07;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
public class Demo07 {
public static void main(String[] args) {
//public static <T> List<T> asList(T... a):返回由指定数组支持的固定大小的列表
//JDK8就有,元素可重复
List<String> list1 = Arrays.asList("hello","world","java");
//不能使用add和remove,因为二者会改变数组大小
//list1.add("generic");
//UnsupportedOperationException报错
//list1.remove("hello");
//UnsupportedOperationException报错
//set可以使用,因为它不改变数组大小
list1.set(1,"string");//[hello, string, java]
System.out.println(list1);
//public static <E> List<E> of (E... elements):返回包含任意数量元素的不可变列表
//JDK9以后才有,元素可重复
//List<String> list2 = List.of("hello","world","java");
//add、remove、set都不能用
//public static <E> Set<E> of(E... elements):返回一个包含任意数量元素的不可变集合
//JDK9以后才有,元素不可重复
//Set<String> set = Set.of("hello","world","java");
//add、remove不可用,且不可用同字符的set方法
}
}
Set接口与实现类
Set接口
- 特点:无序、无下标、元素不可重复
- 方法:全部继承自Collection中的方法
Set接口使用
基本和Collection相同
package com.yushuo.set;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class Demo01 {
public static void main(String[] args) {
/**
* Set接口使用
* 特点:无序、无下标,元素不可重复
*/
//创建集合
Set<String> set = new HashSet<String>();
//添加数据
set.add("苹果");
set.add("西瓜");
set.add("香蕉");
//即便添加多个重复元素,最后集合里面也只有1个元素
System.out.println("集合的元素个数为:" + set.size());
System.out.println("集合的元素为:" + set);
/*
//删除数据
set.remove("苹果");
System.out.println("删除后,集合的元素个数为:" + set.size());
System.out.println("删除后,集合的元素为:" + set);
*/
//遍历【重点】
//增强for
for (String s : set) {
System.out.println(s);
}
//迭代器
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
HashSet【重点】:
- 基于HashCode计算元素存放位置
- 当存入元素的哈希码相同时,会调用equals进行确认,如结果为true,则拒绝后者存入
HashSet的使用
存储过程:
- 根据hashcode计算保存的位置,如果此位置为空,则直接保存,如果不为空执行第二步
- 执行equals方法,如果equals方法为true,则认为是重复,否则,形成链表
HashSet存储字符串
package com.yushuo.set;
import java.util.HashSet;
import java.util.Iterator;
public class Demo02 {
public static void main(String[] args) {
/**
* HashSet的使用,不允许元素重复
* 存储结构:哈希表(数组 + 链表),jdk18之后还有红黑树
*/
//创建集合,后面的String在jdk1.8以后可以不写
HashSet<String> hashSet = new HashSet<String>();
//添加元素,不允许元素重复,多个重复只会存1个
hashSet.add("苹果");
hashSet.add("西瓜");
hashSet.add("香蕉");
System.out.println("集合的元素个数为:" + hashSet.size());
System.out.println("集合的元素为:" + hashSet);
/*
//删除元素
hashSet.remove("苹果");
System.out.println("删除后,集合的元素个数为:" + hashSet.size());
System.out.println("删除后,集合的元素为:" + hashSet);
*/
//遍历元素
//增强for
for (String s : hashSet) {
System.out.println(s);
}
//迭代器
Iterator<String> iterator = hashSet.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
//判断
System.out.println(hashSet.contains("苹果"));
System.out.println(hashSet.isEmpty());
}
}
HashSet存储集合对象
package com.yushuo.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 Person() {
}
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 == 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 com.yushuo.set;
import java.util.HashSet;
import java.util.Iterator;
public class Demo03 {
public static void main(String[] args) {
/**
* HashSet的使用,不允许元素重复
* 存储结构:哈希表(数组 + 链表),jdk18之后还有红黑树
*/
//创建集合,后面的String在jdk1.8以后可以不写
HashSet<Person> hashSet = new HashSet<Person>();
//添加元素,不允许元素重复,多个重复只会存1个
//对于new Person,不会认作同一元素
//可以重写hashcode与equals以使其被认作同一个
//重写hashcode保证相同的元素得到相同的哈希码,否则可能被存到不同数组里面,依然无法认为是同一个
Person person1 = new Person("张三",20);
Person person2 = new Person("李四",21);
Person person3 = new Person("王五",22);
hashSet.add(person1);
hashSet.add(person2);
hashSet.add(person3);
System.out.println("集合的元素个数为:" + hashSet.size());
System.out.println("集合的元素为:" + hashSet);
/*
//删除元素
//hashSet.remove(person1);
//不重写hashcode与equals,不会被认为是同一个,删除不成功
hashSet.remove(new Person("张三",20));
System.out.println("删除后,集合的元素个数为:" + hashSet.size());
System.out.println("删除后,集合的元素为:" + hashSet);
*/
//遍历元素【重点】
//增强for
for (Person person : hashSet) {
System.out.println(person);
}
//迭代器
Iterator<Person> iterator = hashSet.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
//判断
System.out.println(hashSet.contains(person1));
System.out.println(hashSet.isEmpty());
}
}
HashSet补充
hash码计算,使用31原因:
- 31是一个质数,可以减少散列冲突
- 使用31可以提高执行效率,31*i = (i<<5)-i,i乘31相当于左移5位再减i
public static int hashCode(Object a[]) {
if (a == null)
return 0;
int result = 1;
for (Object element : a)
result = 31 * result + (element == null ? 0 : element.hashCode());
return result;
}
TreeSet
TreeSet:
- 基于排列顺序实现元素不重复
- 实现了SortedSet接口,对集合元素自动排序
- 元素对象的类型必须实现Comparable接口,指定排序规则
- 通过CompareTo方法确定是否为重复元素
TreeSet的使用
TreeSet存储字符串
package com.yushuo.set;
import java.util.Iterator;
import java.util.TreeSet;
public class Demo04 {
public static void main(String[] args) {
/**
* TreeSet的使用
* 存储结构:红黑树
* 不允许重复元素,多个重复元素只存储一个
*/
//创建集合
TreeSet<String> treeSet = new TreeSet<>();
//添加元素。存储顺序以字符串的排列顺序,与添加顺序无关
treeSet.add("张三");
treeSet.add("李四");
treeSet.add("王五");
System.out.println("集合的元素个数为:" + treeSet.size());
System.out.println("集合的元素为:" + treeSet);
/*
//删除元素
treeSet.remove("张三");
System.out.println("删除后,集合的元素个数为:" + treeSet.size());
System.out.println("删除后,集合的元素为:" + treeSet);
*/
//遍历
//增强for
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("张三"));
System.out.println(treeSet.isEmpty());
}
}
TreeSet存储数据
package com.yushuo.set.demo05;
import java.util.Objects;
public class Person implements Comparable<Person>{
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person() {
}
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 == 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);
}
//先比较姓名,再比较年龄
@Override
public int compareTo(Person o) {
//比较姓名
int n1 = this.getName().compareTo(o.getName());
//比较年龄
int n2 = this.getAge() - o.getAge();
//若n1为0即姓名相同,比较年龄,因此返回n2,若n1不为0,则比较姓名,返回n1
return n1 == 0 ? n2 : n1;
}
}
package com.yushuo.set.demo05;
import java.util.Iterator;
import java.util.TreeSet;
public class Demo05 {
public static void main(String[] args) {
/**
* TreeSet存储数据
* 存储结构:红黑树
* 要求:元素必须要实现Comparable接口
* CompareTo()返回0,认为是同一元素
*/
//创建集合
TreeSet<Person> treeSet = new TreeSet<>();
//添加元素
Person person1 = new Person("张三",20);
Person person2 = new Person("李四",21);
Person person3 = new Person("王五",22);
treeSet.add(person1);
treeSet.add(person2);
treeSet.add(person3);
//未实现接口以前,报错
//ClassCastException: Person cannot be cast to java.lang.Comparable
//原因:红黑树即二叉树需要比较,没有定义怎么比较
System.out.println("集合的元素个数为:" + treeSet.size());
System.out.println("集合的元素为:" + treeSet);
/*
//删除元素
treeSet.remove(person1);
//new也可以删除,因为之前实现接口时重写的CompareTo()方法比较的是姓名和年龄
System.out.println("删除后,集合的元素个数为:" + treeSet.size());
System.out.println("删除后,集合的元素为:" + treeSet);
*/
//遍历元素
//增强for
for (Person person : treeSet) {
System.out.println(person);
}
//迭代器
Iterator<Person> iterator = treeSet.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
//判断
System.out.println(treeSet.contains(person1));
System.out.println(treeSet.isEmpty());
}
}
Comparator接口
package com.yushuo.set.demo06;
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 Person() {
}
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 == 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 com.yushuo.set.demo06;
import java.util.Comparator;
import java.util.TreeSet;
public class Demo06 {
public static void main(String[] args) {
/**
* TreeSet的使用
* Comparator接口:实现定制比较(比较器)
*/
//创建集合,并指定比较规则
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("张三",20);
Person person2 = new Person("李四",21);
Person person3 = new Person("王五",22);
treeSet.add(person1);
treeSet.add(person2);
treeSet.add(person3);
//未实现接口以前,报错
//ClassCastException: Person cannot be cast to java.lang.Comparable
//原因:红黑树即二叉树需要比较,没有定义怎么比较
System.out.println("集合的元素个数为:" + treeSet.size());
System.out.println("集合的元素为:" + treeSet);
}
}
TreeSet案例
package com.yushuo.set.demo07;
import java.util.Comparator;
import java.util.TreeSet;
public class Demo07 {
public static void main(String[] args) {
/**
* 要求:使用TreeSet集合实现字符串按照长度进行排序
* hello world list zhang as number collection
*/
//创建集合,并指定比较规则
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("world");
treeSet.add("list");
treeSet.add("zhang");
treeSet.add("as");
treeSet.add("number");
treeSet.add("collection");
System.out.println(treeSet);
}
}
Map接口与实现类
Map集合概述
map体系结构
Map接口特点:
- 用于存储任意键对应值(Key-Value)
- 键:无序、无下标、不允许重复(唯一)
- 值:无序、无下标、允许重复
Map接口的使用
-
特点:
存储一对数据(Key-Value),无序、无下标,键不可重复,值可重复
-
方法:
- V put(K Key,V Value) //将对象存入到集合中,关联键值。key重复则覆盖原值
- Object get(Object key) //根据键获取对应的值
- Set< K > //返回所有key
- Collection< V > values() //返回包含所有制的Collection集合
- Set<Map.Entry<K,V>> //键值匹配的Set集合
package com.yushuo.map.demo01;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class Demo01 {
public static void main(String[] args) {
/**
* Map接口的使用
* 特点:
* 存储键值对
* 键不能重复,值可以重复
* 无序
*/
//创建Map集合
Map<String, String> map = new HashMap<>();
//添加元素
map.put("cn","中国");
map.put("uk","英国");
map.put("usa","美国");
System.out.println("集合的元素个数为:" + map.size());
System.out.println("集合的元素为:" + map);
/*
//删除元素,根据键值Key删除
map.remove("usa");
System.out.println("删除后,集合的元素个数为:" + map.size());
System.out.println("删除后,集合的元素为:" + map);
*/
//遍历元素
//使用keySet,map.keySet()返回Key的Set集合
Set<String> keyset = map.keySet();
for (String s : keyset) {
//map.get()根据键值Key返回对应Value
System.out.println(s + "————" + map.get(s));
}
/*
或者
for (String s : map.keySet()) {
System.out.println(s + "————" + map.get(s));
}
*/
//使用entrySet,map.entrySet()返回键值对Key-Value的Map.Entry集合
Set<Map.Entry<String, String>> entries = map.entrySet();
for (Map.Entry<String, String> entry : entries) {
System.out.println(entry.getKey() + "————" + entry.getValue());
}
/*
或者
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println(entry.getKey() + "————" + entry.getValue());
}
*/
//判断
System.out.println(map.containsKey("cn"));
System.out.println(map.containsValue("中国"));
System.out.println(map.isEmpty());
}
}
Map集合的实现类
HashMap、HashTable(跳过)、Properties
HashMap
HashMap【重点】:
- JDK1.2版本,线程不安全,运行效率快,允许用null作为key或是value
HashMap的使用
存储数据
package com.yushuo.map.demo02;
import java.util.Objects;
public class Student {
private String name;
private int stuNo;
public Student() {
}
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 == 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);
}
}
package com.yushuo.map.demo02;
import com.yushuo.set.demo03.Person;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class Demo02 {
public static void main(String[] args) {
/**
* HashMap集合的使用
* 存储结构:哈希表(数组 + 链表 + 红黑树)
*/
//创建集合
HashMap<Student, String> hashMap = new HashMap<>();
//添加元素
Student student1 = new Student("张三",1);
Student student2 = new Student("李四",2);
Student student3 = new Student("王五",3);
//如果键值重复,后输入的value或覆盖旧的value
//对于new的对象,如果没有重写,不会重复,依旧可以添加
//重写hashCode和equals可以被认作重复
hashMap.put(student1,"北京");
hashMap.put(student2,"上海");
hashMap.put(student3,"福州");
//如果键值重复,后输入的value或覆盖旧的value
System.out.println("集合的元素个数为:" + hashMap.size());
System.out.println("集合的元素为:" + hashMap);
/*
//删除元素
hashMap.remove(student1);
System.out.println("删除后,集合的元素个数为:" + hashMap.size());
System.out.println("删除后,集合的元素为:" + hashMap);
*/
//遍历元素
//使用keySet
Set<Student> set = hashMap.keySet();
//增强for
for (Student student : set) {
System.out.println(student + "————" + hashMap.get(student));
}
//迭代器
Iterator<Student> iterator = set.iterator();
while (iterator.hasNext()){
Student student = iterator.next();
System.out.println(student + "————" + hashMap.get(student));
}
/*
或者
for (Student student : hashMap.keySet()) {
System.out.println(student + "————" + hashMap.get(student));
}
*/
//*******************************************************************
//使用entrySet,返回的是Map.Entry类型
Set<Map.Entry<Student, String>> entries = hashMap.entrySet();
//增强for
for (Map.Entry<Student, String> entry : entries) {
System.out.println(entry.getKey() + "————" + entry.getValue());
}
//迭代器
Iterator<Map.Entry<Student, String>> iterator1 = entries.iterator();
while (iterator1.hasNext()){
Map.Entry<Student, String> entry = iterator1.next();
System.out.println(entry.getKey() + "————" + entry.getValue());
}
/*
或者
for (Map.Entry<Student, String> entry : hashMap.entrySet()) {
System.out.println(entry.getKey() + "————" + entry.getValue());
}
*/
//判断
System.out.println(hashMap.containsKey(student1));
System.out.println(hashMap.containsValue("北京"));
System.out.println(hashMap.isEmpty());
}
}
HashMap源码分析
属性:
-
默认初始容量大小:DEFAULT_INITIAL_CAPACITY = 16
-
最大容量:MAXIMUM_CAPACITY = 2^30,2的30次方
-
默认加载因子:DEFAULT_LOAD_FACTOR = 0.75,即当存储数据超过容量的75%时会扩容
-
数组:table、容量:size
-
阈值:TREEIFY_THRESHOLD = 8,MIN_TREEIFY_CAPACITY = 64,JDK1.8以后才有,基于数组的链表,当数组大小 > 64,链表长度 > 8时,链表会转为红黑树
-
UNTREEIFY_THRESHOLD = 6,当链表长度 < 6时,红黑树会转为链表
//构造方法
public HashMap() {
//加载因子赋值
this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
public V put(K key, V value) {
//hash(key)计算key的哈希码
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;
//添加第一个元素之前,数组为空,元素数量为0
if ((tab = table) == null || (n = tab.length) == 0)
//创建一个数组,数组大小为16
n = (tab = resize()).length;
//如果数组中没有元素
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;
//当元素个数超过容量的0.75时,扩充为原容量2倍
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
总结:
- HashMap刚创建时,table是null,为了节省空间,当添加第一个元素时,table容量调整为16
- 当元素个数大于阈值(16*0.75=12)时,会进行扩容,扩容后大小为原来的2倍,目的时减少调整元素的个数
- jdk1.8当每个链表长度大于8,并和元素个数大于等于64时,会调整为红黑树,目的提高执行效率
- jdk1.8当链表长度小于6时,调整成链表
- jdk1.8以前,链表时头插入,jdk1.8以后是尾插入
HashSet就是用HashMap的Key保存数据
Hashtable(跳过)
- JDK1.0版本,线程安全,运行效率慢,不允许null作为key或是value
Properties
- Hashtable的子类,要求key和calue都是String。通常用于配置文件的读取
TreeMap
- 实现了SortedMap接口(是Map的子接口),可以对key自动排序
存储对象
package com.yushuo.map.demo03;
import java.util.Objects;
public class Student implements Comparable<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 stuNo) {
this.age = stuNo;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public int compareTo(Student o) {
int n1 = this.getName().compareTo(o.getName());
int n2 = this.getAge() - o.getAge();
return n1 == 0 ? n2 : n1;
}
}
package com.yushuo.map.demo03;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class Demo03 {
public static void main(String[] args) {
/**
* TreeMap的使用
* 存储结构:红黑树
*/
//创建集合,如果Student不想写接口,可以定制比较
TreeMap<Student, String> treeMap = new TreeMap<>();
//添加元素
Student student1 = new Student("张三",1);
Student student2 = new Student("李四",2);
Student student3 = new Student("王五",3);
treeMap.put(student1,"北京");
treeMap.put(student2,"上海");
treeMap.put(student3,"福州");
//ClassCastException: Student cannot be cast to java.lang.Comparable
//TreeMap结构是红黑树,需要比较
//Student需要实现Comparable接口
//new也可以,因为重写了CompareTo
System.out.println("集合的元素个数为:" + treeMap.size());
System.out.println("集合的元素为:" + treeMap);
/*
//删除
treeMap.remove(student1);
System.out.println("删除后,集合的元素个数为:" + treeMap.size());
System.out.println("删除后,集合的元素为:" + treeMap);
*/
//遍历
//使用keySet
Set<Student> set = treeMap.keySet();
//增强for
for (Student student : set) {
System.out.println(student + "————" + treeMap.get(student));
}
/*
或者
for (Student student : treeMap.keySet()) {
System.out.println(student + "————" + treeMap.get(student));
}
*/
//迭代器
Iterator<Student> iterator = set.iterator();
while (iterator.hasNext()){
Student student = iterator.next();
System.out.println(student + "————" + treeMap.get(student));
}
//*************************************************************
//使用entrySet
Set<Map.Entry<Student, String>> entries = treeMap.entrySet();
//增强for
for (Map.Entry<Student, String> entry : entries) {
System.out.println(entry.getKey() + "————" + entry.getValue());
}
/*
或者
for (Map.Entry<Student, String> entry : treeMap.entrySet()) {
System.out.println(entry + "————" + treeMap.get(entry));
}
*/
//迭代器
Iterator<Map.Entry<Student, String>> iterator1 = entries.iterator();
while (iterator1.hasNext()){
Map.Entry<Student, String> entry = iterator1.next();
System.out.println(entry.getKey() + "————" + entry.getValue());
}
//判断
System.out.println(treeMap.containsKey(student1));
System.out.println(treeMap.containsValue("北京"));
System.out.println(treeMap.isEmpty());
}
}
TreeSet就是用TreeMap的Key保存数据
Collections工具类
-
概念:集合工具类,定义了除了存取以外的集合常用方法
-
方法
-
public static void reverse(List<?> list) //反转及集合中元素的顺序
-
public static void shuffle(List<?> list) //随机重制集合元素的顺序
-
public static void sort(List<?> list) //升序排序(元素类型必须实现Comparable接口)
-
package com.yushuo.collectionsTools;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class Demo01 {
public static void main(String[] args) {
//Collection工具类的使用
//创建对象
List<Integer> list = new ArrayList<>();
list.add(20);
list.add(15);
list.add(8);
list.add(26);
list.add(3);
list.add(10);
System.out.println("排序之前:" + list);
//sort排序
Collections.sort(list);
System.out.println("排序之后:" + list);
//binarySearch二分查找,没找到返回-1
int binarySearch = Collections.binarySearch(list,20);
//copy复制
List<Integer> dest = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
dest.add(0);
}
Collections.copy(dest,list);
//IndexOutOfBoundsException: Source does not fit in dest
//copy要求两个集合大小要一样,需要先对dest装入相同数量的元素
System.out.println(dest);
//reverse反转
Collections.reverse(list);
System.out.println("反转之后:" + list);
//shuffle打乱
Collections.shuffle(list);
System.out.println("打乱之后:" + list);
//补充1:list转成数组,参数不一定是0,随便都可以
//如果参数未超过list大小,数组大小与list大小相同
//如果参数超过list大小,数组大小为参数大小
Integer[] arr = list.toArray(new Integer[0]);
System.out.println(Arrays.toString(arr));
//补充2:数组转成集合
String[] names = {"张三","李四","王五"};
//集合是一个受限集合,不能添加和删除
List<String> list1 = Arrays.asList(names);
System.out.println(list1);
//把基本类型数组转成集合时,需要修改为包装类
int[] nums = {100,200,300};
List<int[]> list2 = Arrays.asList(nums);
System.out.println(list2);//[[I@4554617c]
//这样集合中的元素就只有一个,即一个数组了
Integer[] num = {100,200,300};
List<Integer> list3 = Arrays.asList(num);
System.out.println(list3);//[100, 200, 300]
}
}