集合
Collection:集合层次的根接口,一些集合允许元素重复(List),一些集合不允许元素重复(Set)
一些集合有序(存储和取出一致)(List),一些集合无序(存储和取出不一致)(Set),
JDK不提供此接口的任何直接实现:它提供了更具体的子接口的实现,如Set和List
Collection
List
最具体的子实现类ArrayList,LinkedList,Vector
1.功能
基本功能
1)添加
boolean add(Object e):添加元素 E(Element)
2)删除:
void clear() 暴力删除(将集合的素有元素全部干掉)
boolean remove(Object o):从集合中删除指定的元素
3)获取集合的元素数 :
int size()
4)判断功能:
boolean isEmpty():判断集合是否为空,为空元素,则返回true
boolean contains(Object o):判断集合中是否包含指定元素,包含则返回true
//@SuppressWarnings("all") //jdk提供的内置注解:压制警告
public class CollectionDemo {
public static void main(String[] args) {
//创建Collection集合对象
//接口多态
Collection c = new ArrayList() ;
System.out.println(c);//ArrayList重写了Object的toString()方法
System.out.println("-----------------------------------------");
// boolean add(Object e):添加元素 E(Element)
// boolean flag = c.add("hello");
/**
* 添加的原码
* public boolean add(E e) {
* ensureCapacityInternal(size + 1); // Increments modCount!!
* elementData[size++] = e;
* return true; //永远返回true
* }
*/
//System.out.println(flag);
c.add("hello") ;
c.add(100) ;
c.add("javaee") ;
System.out.println(c);
// void clear()
// c.clear();
// boolean remove(Object o):从集合中删除指定的元素
// System.out.println(c.remove(100));
//int size()
System.out.println(c.size());
System.out.println("--------------------------");
System.out.println(c.contains("world"));
System.out.println(c.contains("javaee"));
System.out.println(c.isEmpty());
System.out.println(c);
}
}
高级功能
Collection的高级功能
1)boolean addAll(Collection c):添加一个集合中的所有元素
2)oolean containsAll(Collection c):包含一个集合中的所有元素
3)boolean removeAll(Collection c):删除集合中的所有元素, (删除一个算删除,还是删除所有)
4)boolean retainAll(Collection c):A集合对B集合求交集, boolean的返回值是什么意思,交集的元素是保存在A中还是B中
5)Collection最基本的遍历功能,不属于集合的专有遍历
Object[] toArray():将集合转换成了对象数组
public class CollectionDemo2 {
public static void main(String[] args) {
//创建两个Collection集合对象
Collection c1 = new ArrayList() ;
c1.add("abc1") ;
c1.add("abc2") ;
c1.add("abc3") ;
c1.add("abc4") ;
Collection c2 = new ArrayList() ;
c2.add("abc1") ;
c2.add("abc2") ;
c2.add("abc3") ;
c2.add("abc4") ;
c2.add("abc5") ;
c2.add("abc6") ;
c2.add("abc7") ;
System.out.println(c1);
System.out.println(c2);
System.out.println("---------------------------------");
//boolean addAll(Collection c):添加一个集合中的所有元素
// System.out.println(c1.addAll(c2));
//boolean containsAll(Collection c) :包含所有的元素算包含...
// System.out.println(c1.containsAll(c2));
//boolean removeAll(Collection c):删除集合中的所有元素, (删除一个算删除,还是删除所有):删除一个算删除(必须同时都被包含进去)
// System.out.println(c1.removeAll(c2));
// boolean retainAll(Collection c):A集合对B集合求交集, boolean的返回值是什么意思,交集的元素是保存在A中还是B中
/**
* A集合堆B集合求交集,交集的元素存储在A集合中,然后返回值的意思: 看A集合的元素是否有变化(之前的元素和现在交集的元素进行对比)
*/
System.out.println(c1.retainAll(c2)); //c1集合对c2集合取交集
System.out.println(c1);
System.out.println(c2);
System.out.println("-------------------------------------------");
//使用Colllection存储5个学生(姓名,年龄,性别),然后将Collection进行遍历,获取出来每一个学生的信息!
//创建一个Collection集合对象
Collection c = new ArrayList() ;
//创建5个学生
Student s1 = new Student("宋江",45,"男") ;
Student s2 = new Student("李逵",35,"男") ;
Student s3 = new Student("武大郎",35,"男") ;
Student s4 = new Student("西门庆",30,"男") ;
Student s5 = new Student("吴用",40,"男") ;
//存储集合中
c.add(s1) ;
c.add(s2) ;
c.add(s3) ;
c.add(s4) ;
c.add(s5) ;
// Object[] toArray():将集合转换成了对象数组
Object[] objs = c.toArray();//数组存储的每一个数据类型 Object obj = new Student() ; //向上转型
//遍历数组
for(int x = 0 ; x < objs.length ; x ++){
//System.out.println(objs[x]) ;
//getXXX()---->Student类的方法
Student student = (Student) objs[x]; //向下转型
System.out.println(student.getName()+"---"+student.getAge()+"---"+student.getGender());
}
}
}
1.List
1.List集合
List集合
ArrayList
底层数据结构是数组,查询快,增删慢
通过arr[索引值]:查询到某个元素
存储null元素---->
线程角度: 线程不安全的类,实现不同步的 ----->执行效率高
特点:扩容机制:1.5倍的方式扩容
Integer[] arr = {11,22,33,44,55} ;
添加和删除元素:需要判断
在33这个元素后面新的元素,需要新建数组,长度是以前数组长度+1
判断加入的元素是否33元素
33以前,按照以前的元素在新的数组进行存储
33,继续存储
33以后的,加入88元素(给33以后的元素后面插入新的元素)
public ArrayList():无参构造方法:默认容量是10
ArrayList扩容机制
public ArrayList(int initialCapacity):初始容量为空,指定初始容量大小
public ArrayList(int initialCapacity) {//10,20
if (initialCapacity > 0) {
10
this.elementData = new Object[initialCapacity];//创建数组对象elementData
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
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 void ensureExplicitCapacity(int minCapacity) {
modCount++; /protected transient int modCount = 0;:ArrayList父类中 默认0开始,统计变量
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity); //调用扩容方法
}
//扩容方法
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
//右移动1位 //将左边的数据除以2的移动次幂 1/2
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);
}
//计算最终容量大小
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
Vector集合:
底层数据结构是数组,查询快,增删慢
线程角度:线程安全的类----同步的方法---->执行效率低
单线程程序中.考虑集合默认都会使用 ArrayList,多线程环境集合---->Vector集合
LinkedList
底层数据结构是链表,查询慢,增删快
线程角度:线程不安全的类---->不同步---->执行效率高
特有功能:
addFirst()
removeFirst()
getFirst()
xxxLast()
应用场景:模拟栈结构特点:
先进后出
如果没有明确要求使用什么(List)集合的时候 ,默认都是用ArrayList
List接口继承Collection
1.List集合特点:
有序(存储元素和取出元素一致)
允许元素重复
2.具备Collection相关的功能
Object [] toArray()
Iterator iterator()
3.特有功能
void add(int index,Object element):在指定的索引处插 入元素
Object get(int index):获取指定位置处的元素 + int size():一种新的集合遍历方式
Object remove(int index):删除指定位置处的元素
Object set(int index,E element):修改指定位置处的元素(替换)
ListIterator<E> listIterator():列表迭代器
ListIterator接口:
void add(E e)有添加
remove():有删除
public class ListDemo {
public static void main(String[] args) {
//创建List集合对象
List<String> list = new ArrayList<String >();
//添加元素
list.add("hello") ;
list.add("hello") ;
list.add("world") ;
list.add("world") ;
list.add("world") ;
list.add("javaEE") ;
list.add("javaEE") ;
// void add(int index,Object element):在指定的索引处插 入元素
list.add(1,"高圆圆");
//Object get(int index):获取指定位置处的元素 :返回的被获取到的元素内容
System.out.println(list.get(1));
// Object remove(int index):删除指定位置处的元素,返回被删除的元素
System.out.println(list.remove(2));
System.out.println("---------------------------------------");
//Object set(int index,E element):修改指定位置处的元素(替换)
System.out.println(list.set(1,"赵又廷"));
System.out.println(list);
}
}
2.迭代器
Collection的迭代器:集合的专有遍历方式
Iterator iterator():返回值类型接口类型,需要返回的子实现类对象
Iterator接口:
1)boolean hasNext():判断迭代器中是否存在下一个元素
2)Object next(): 获取下一个可以遍历的元素
3)给Collection中存储String类型,遍历出来
public class CollectionTest {
public static void main(String[] args) {
//创建集合对象
Collection c = new ArrayList() ; //List接口的子实现类 (重复元素)
//添加元素
c.add("hello") ;
c.add("world") ;
c.add("javaee") ;
//获取Collection的迭代器Iterator iterator()
Iterator it = c.iterator();
//如果现在明确存储了3个元素,以后这些数据可能数据库获取的一个列表集合数据,一般while循环
while(it.hasNext()){//判断迭代器中有下一个元素
//才获取
Object obj = it.next();// Object obj = new String("hello") ...
String str = (String) obj;//向下转型
System.out.println(str+"----"+str.length());
}
}
}
3.泛型
jdk5以后新特性:泛型<E/T>
泛型的格式:
<引用数据类型>
模拟数组创建的时候,就已经明确了数据类型
举例:
// String[] array = {"hello","world","java",100}
创建集合对象的时候,明确了集合中存储的数据类型<>
格式:
集合类型<引用数据类型> 集合对象名 = new 子实现类<引用数据类型>() ;
泛型的好处:
1)将运行时期异常提前了编译时期
2)避免了强制类型转换
3)提高了程序安全性
public class GenericDemo {
public static void main(String[] args) {
//创建Collection集合对象
Collection<String> c = new ArrayList<String>() ; //new XXX<数据类型>: jdk7以后泛型推断
c.add("hello") ;
c.add("高圆圆") ;
c.add("你好吗") ;
// c.add(100) ;
//获取迭代器Iteratr<E>是集合中存储的泛型是一致的
Iterator<String> it = c.iterator();
while(it.hasNext()){
//获取String字符串的同时,还要获取长度
String str = it.next();
System.out.println(str+"---"+str.length());
}
}
}
4.List集合的遍历方式
List集合的遍历方式
1)Object[] toArray()
2)Iterator iterator()
3)Object get(int index):获取指定位置处的元素 + int size():一种新的集合遍历方式
4)ListIterator<E> listIterator():列表迭代器 :List集合专有遍历方式
ListIterator:特有功能:
boolean hasPrevious():是否有上一个元素可以迭代
Object previous():获取上一个元素
5)增强for
DK5以后 提供了增强for循环,替代集合中迭代器去遍历集合使用的(优先在集合中使用)
格式:
for(存储的引用数据类型 变量名: 集合/数组对象){ //集合使用居多,数组一般都是使用普通for
使用变量名即可
}
注意事项:
当前集合对象不能为空 null :foreach语句:增强for它本身就是获取迭代器了,就会出现空指针异常
public class ListTest {
public static void main(String[] args) {
//创建List集合对象
List<String> list = new ArrayList<>() ;
//添加元素
list.add("hello");
list.add("world");
list.add("java");
list.add("android");
//Object get(int index):获取指定位置处的元素 + int size():一种新的集合遍历方式
//size()+get(int index)集合
for(int x = 0 ; x < list.size() ; x ++){
String s = list.get(x);
System.out.println(s+"---"+s.length());
}
System.out.println("-----------------------------------------------");
//List集合存储Student对象并进行遍历(学生:姓名,年龄)
List<Student> stuList = new ArrayList<>() ;//JDK7以后 泛型推断:自动的和前面的泛型类型一致!
//创建3个学生
Student s1 = new Student("张佳宁",31) ;
Student s2 = new Student("迪丽热巴",29) ;
Student s3 = new Student("张俊杰",20) ;
//添加到列表中
stuList.add(s1) ;
stuList.add(s2) ;
stuList.add(s3) ;
//遍历
//方式1:Object[] toArray()
Object[] objs = stuList.toArray();
for(int x = 0 ; x < objs.length ; x ++){
Student s = (Student) objs[x];
System.out.println(s.getName()+"----"+s.getAge());
}
System.out.println("--------------------------------------");
//方式2:Collection的迭代器
Iterator<Student> it = stuList.iterator();
while(it.hasNext()){
Student s = it.next() ;
System.out.println(s.getName()+"---"+s.getAge());
// System.out.println((it.next().getName()+"---"+(it.next().getAge())));
// next()只能使用一次,不能多次使用 //错误的用法
}
System.out.println("-------------------------------------");
//方式3:size()+get(int index)
for(int x = 0 ; x < stuList.size() ; x ++){
Student s = stuList.get(x);
System.out.println(s.getName()+"----"+s.getAge());
}
System.out.println("-----------------------------------------");
//方式4:正向遍历:ListIterator<E> listIterator():列表迭代器 :List集合专有遍历方式
ListIterator<Student> lit = stuList.listIterator();
/**
* ListIterator extends Iterator{}
*
* class ArrayList{
* List具体ArrayList子实现类重写了Iterator listiterator(){
* return new ListItr(0) ;
* }
* private class ListItr extends Itr implements Iterator{
* //具备hasNext()
* //next()
* }
* }
*/
while(lit.hasNext()){
Student student = lit.next();
System.out.println(student.getName()+"---"+student.getAge());
}
System.out.println("-----------------------------------------");
//逆向遍历:前提:必须有正向遍历
//ListIterator<E> listIterator()
//ListIterator:特有功能:
//boolean hasPrevious():是否有上一个元素可以迭代
//Object previous():获取上一个元素
while(lit.hasPrevious()){
Student student = lit.previous();
System.out.println(student.getName()+"---"+student.getAge());
}
}
}
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;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public void setAge(int age) {
this.age = age;
}
}
public class ForeachDemo {
public static void main(String[] args) {
//创建List集合
List<String> list = new ArrayList<>() ;
list.add("hello") ;
list.add("world") ;
list.add("javaee") ;
/* for(String s:list){//替换迭代器使用
//如果存在world元素,添加一个android元素
//System.out.println(s);
if("world".equals(s)){
list.add("android") ;//出现并发修改异常
}
}
System.out.println(list);
*/
list = null ;
if(list!=null){
for(String s:list){//获取迭代器
System.out.println(s+"---"+s.length());
}
}else{
System.out.println("当前集合对象为null了");
}
}
}
1)并发修改异常
需求:
通过List集合ArrayList集合对象,如果当前集合中存在"world"元素,那么就给集合中添加一个"javaEE"元素,最后将
集合中的所有元素进行遍历!
举例:
List集合现在就存有三个元素
"hello"
"world"
"java"
java.util.ConcurrentModificationException:并发修改异常
集合在使用迭代器会经常出现的问题:并发修改异常,
当集合的元素正在被迭代器进行遍历,那么集合对象是不能够对元素进行增加或者删除 (一个线程正在遍历,一个线程在修改元素)
解决方案:
1)要么就是迭代器去遍历集合的元素,迭代器去添加元素 :列表迭代器才具备添加的动作
2)要么集合遍历,集合添加
public class ListTest2 {
public static void main(String[] args) {
//创建List集合对象
List<String> list = new ArrayList<>() ;
//给添加元素
list.add("hello") ;
list.add("world") ;
list.add("javaee") ;
//使用迭代器遍历
//Iterator iterator()
/* Iterator<String> it = list.iterator(); //"hello","world","javaee"
while(it.hasNext()){
String s = it.next() ;//"hello","world","javaee"
//判断
if("world".equals(s)){
list.add("javaEE") ;//集合对象添加的元素,迭代器不知道
}
}
System.out.println(list);*/
//解决方案1: 1)要么就是迭代器去遍历集合的元素,迭代器去添加元素 :列表迭代器才具备添加的动作
//ListIterator
//void add(E e)
/*ListIterator<String> lit = list.listIterator();
while(lit.hasNext()){
//获取
String s = lit.next();
//判断是否存在"world"元素
if("world".equals(s)){
//列表迭代器添加
lit.add("javaEE");
}
}*/
//方案2:要么集合遍历,集合添加
//size()+get(int index)
for(int x = 0 ; x < list.size(); x ++){
String s = list.get(x);
if("world".equals(s)){//将常量放前面,防止出现NullPointerException
list.add("javaEE");
}
}
System.out.println(list);
}
}
5.List去重
1)方式1:新建空集合思想
方式1:新建空集合思想
存储字符串类型并保证集合的元素唯一!
List<String>
集合中Collection/List--->contains(Object o)底层依赖于Object的equals方法
而List现在存储的是String类型,本身重写Object的equals,所以比较的是内容是否相同
public class ListTest2 {
public static void main(String[] args) {
//创建List集合
List<String> list = new ArrayList<>() ;
//现在给集合中添加重复的字符串数据
list.add("hello") ;
list.add("hello") ;
list.add("world") ;
list.add("javaEE") ;
list.add("world") ;
list.add("javaEE") ;
list.add("android") ;
list.add("android") ;
list.add("ios") ;
//新建一个空的集合List
List<String> newList = new ArrayList<>() ;
//遍历以前的集合
for(String s :list){
//使用新集合判断,不包含这个元素,说明该元素没有重复,就可以添加
if(!newList.contains(s)){
newList.add(s) ;
}
}
//遍历新的集合
for(String s:newList){
System.out.println(s);
}
}
}
2)方式2:利用选择排序的思想去完成
选择排序的思想:
使用0角标对应的元素依次和后面角标对应的元素进行比较,小的往前方法.依次这样比较,1角标,2角标...
List集合---集合列表角标从0开始
遍历当前集合
然后使用0角标对应的元素依次和后面对应的元素进行比较,如果后面的元素和前面的相同了,那么将后面的元素删除掉
角标--
public class ListTest3 {
public static void main(String[] args) {
//创建List集合
List<String> list = new ArrayList<>() ;
//现在给集合中添加重复的字符串数据
list.add("hello") ;
list.add("hello") ;
list.add("world") ;
list.add("world") ;
list.add("javaEE") ;
list.add("world") ;
list.add("javaEE") ;
list.add("android") ;
list.add("android") ;
list.add("ios") ;
//利用选择排序的思想完成
for(int x = 0 ; x < list.size()-1 ; x ++){
for(int y = x +1 ; y < list.size() ; y++){
//如果后面的元素和前面的元素相同
if(list.get(y).equals(list.get(x))){
//通过集合remove掉
list.remove(y) ; // public Object remove(int index)
//角标--
y -- ;
}
}
}
for(String s:list){
System.out.println(s);
}
}
}
3)List存储自定义对象
List<Student>存储自定义对象 怎么去重?
Student s1 = new Student("高圆圆",42) ;
Student· s2 = new Student("高圆圆",42) ;
成员信息如果一致,认为是同一个人,需要使用List集合去重!
1)方式1:
新建集合思想
contains(Object)方法依赖于Object的equals方法,所以集合存储的类型所在的类必须重写equals方法,否则默认使用
Object的equals方法比较的地址值是否相同!
2)方式2:使用选择排序思想 将List<Student>存储的重复的学生对象进行重写!
public class ListTest4 {
public static void main(String[] args) {
//创建一个List集合
List<Student> list = new ArrayList<>() ;
//创建一些学生对象:有重复的成员信息
Student s1 = new Student("高圆圆",42) ;
Student s2 = new Student("高圆圆",42) ;
Student s3 = new Student("刘诗诗",39) ;
Student s4 = new Student("刘诗诗",39) ;
Student s5 = new Student("张佳宁",30) ;
Student s6 = new Student("文章",36) ;
Student s7 = new Student("文章",36) ;
Student s8 = new Student("姚笛",32) ;
//添加到集合中
list.add(s1) ;
list.add(s2) ;
list.add(s3) ;
list.add(s4) ;
list.add(s5) ;
list.add(s6) ;
list.add(s7) ;
list.add(s8) ;
//方式1:创建新的一个新集合
List<Student> newList = new ArrayList<>() ;
//遍历以前的集合获取每一个学生对象
for(Student s:list){
//如果当前newList不包含这个学生添加到新集合中
if(!newList.contains(s)){
newList.add(s) ;
}
}
//遍历新集合
for(Student student:newList){
System.out.println(student.getName()+"----"+student.getAge());
}
}
}
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;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public void setAge(int age) {
this.age = age;
}
@Override //重写equals
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
if (age != student.age) return false;
return name.equals(student.name);
}
@Override
public int hashCode() {
int result = name.hashCode();
result = 31 * result + age;
return result;
}
}
2.Vector
Vector集合特有功能:
1)添加
public void addElement(Object obj):在vector对象的末尾添加元素 ------> 一直使用的add(Object e)
2)删除
public boolean removeElement(Object obj):删除元素
3)获取功能
public Object elementAt(int index):获取指定位置的元素---->类似于 public Object get(int index)
public Enumeration<E> elements() :Vector集合的专有遍历方式---->类似于 Iterator literator()
接口
boolean hasMoreElements():判断是否有更多的元素可以迭代
Object nextElement() 获取元素
public class VectorDemo {
public static void main(String[] args) {
//创建Vector集合对象
Vector<String> v = new Vector<>() ;
v.addElement("hello");
v.addElement("world");
v.addElement("SpringBoot");
v.addElement("SpringCloud") ;
//遍历:特有功能
Enumeration<String> en = v.elements(); //相当于Iterator
while(en.hasMoreElements()){
String s = en.nextElement();
System.out.println(s+"---"+s.length());
}
System.out.println("----------------------------------");
for(String s: v){
System.out.println(s+"----"+s.length());
}
}
}
3.LinkedList
LinkedList集合特点:线程不安全的类,执行效率高
链接列表结构,查询慢,增删快
特有功能:
1)public void addFirst(Object e):在列表开头插入元素
2)public void addLast(Object e):将元素追加到列表的末尾
3)public Object getFirst():获取列表的第一个元素
4)public Object getLast():获取列表的最后一个元素
5)public Object removeFirst(): 删除列表的第一个元素,并获取第一个元素
6)public Object removeLast():删除列表的最后一个元素,并获取最后一个元素
public class LinkedListDemo {
public static void main(String[] args) {
//创建一个LinkedList集合对象
LinkedList<String> link = new LinkedList<>() ;
//添加元素
// public void addFirst(Object e):在列表开头插入元素
link.addFirst("hello") ;
link.addFirst("world") ;
link.addFirst("JavaEE") ;
link.addFirst("Android") ;
link.addLast("Php") ;
//public Object getFirst():获取列表的第一个元素
System.out.println(link.getFirst());
System.out.println(link.getLast());
// public Object removeFirst(): 删除列表的第一个元素,并获取第一个元素
System.out.println(link.removeFirst());
System.out.println(link.removeLast());
System.out.println(link);
}
}
4.HashSet
Set集合:无序 (存储和取出不一致), 能够保证元素唯一
HashSet:底层数据结构是一个哈希表,元素为链表的数组。(桶结构)
线程不安全的类---->不同步---->执行效率高
JDK8以后;提供了juc(并发包:java.util.concurrent):
String类型:String类型本身已经重写了hashCode()和equals,如果hashCode和equals()都相同,那么认为同一个元素,存储以前的值
如果现在存储是自定义对象,如何保证元素唯一?
如果现在存储是自定义对象,如何保证元素唯一?HashSet<Student>
Student s1 = new Student("高圆圆",42) ;
Student s2 = new Student("高圆圆",42) ;
HashSet集合依赖于add方法---->HashMap的put方法
首先要比较元素的哈希码值相同----->hash()就相同
还要比较成员信息是否相同,对应存储自定的类必须要重写Object的equals方法
Student的这个类,必须手动给出hashCode()和equals
Hashset集合不能保证顺序迭代恒久不变!
应用场景:
在一些需求中,如果没有明确要求元素重复,那就可以使用hashSet,保证元素唯一!
类型:String,Integer,Long,....常用类都已经重写了hashCode和equals方法
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) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
if (age != student.age) return false;
return name.equals(student.name);
}
@Override
public int hashCode() {
int result = name.hashCode();
result = 31 * result + age;
return result;
}
}
public class HashSetDemo2 {
public static void main(String[] args) {
//创建HashSet集合对象
HashSet<Student> hs1 = new HashSet<>() ;
Student s1 = new Student("宋江",35) ;
Student s2 = new Student("宋江",35) ;
Student s3 = new Student("武松",30) ;
Student s4 = new Student("宋江",30) ;
Student s5 = new Student("武松",30) ;
Student s6 = new Student("卢俊义",28) ;
Student s7 = new Student("卢俊义",28) ;
System.out.println("-------------------------------");
//System.out.println(s1.hashCode());
//System.out.println(s2.hashCode());
//添加集合中
hs1.add(s1) ;
hs1.add(s2) ;
hs1.add(s3) ;
hs1.add(s4) ;
hs1.add(s5) ;
hs1.add(s6) ;
hs1.add(s7) ;
//遍历
for(Student s : hs1){
System.out.println(s.getName()+"---"+s.getAge());
}
}
}
HashSet的add方法源码
interface Collection{
boolean add(E e);
}
interface Set<E> extends Collection{
boolean add(E e);
}
//具体的子类
class HashSet implements Set<E>{
private transient HashMap<E,Object> map; map属性:类型HashMap类型
rivate static final Object PRESENT = new Object();
public HashSet() {
map = new HashMap<>();实际就是创建了HashMap
}
public boolean add(E e) {//
return map.put(e, PRESENT)==null; //e="hello",HashSet集合添加的内容,参数2对应用的Value值是一个常量
//调用的是HashMap的添加功能put方法S
//put(K key,V value)
}
//HashMap的添加功能
public V put(K key, V value) {//key="hello","hello" ,参数2:常量PRESENT (当前HashSet类一加载,在内存中就已经创建了Object集合对象,而且是常量)
return putVal(hash(key), key, value, false, true);
//参数1:计算以下传进来的内容的hash码值
}
//hash方法
static final int hash(Object key) {//"hello","hello"
int h; //h变量
return (key == null) ? 0: (h = key.hashCode()) ^ (h >>> 16);
//h= ("hello".hashCode()) ^ (h无符号右移16位号)
}
//HashSet集合的add方法依赖于HashMap的put方法,put方法底层依赖于:先计算每一个元素的hashCode值是否一样
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
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)))) //依赖于Object的equals方法
break;
p = e;
}
......
}
}
Set<String> set = new HashSet<>() ; 实际就是创建了HashMap<E,Object>实例
set.add("hello") ;
set.add("hello") ;
set.add("world") ;
set.add("world") ;
HashSet依赖于HashMap的put方法,put---->putVal()--->
方法依赖于hash()---->计算出每一个元素的哈希值hashCode() 完成无符号右移16位然后进行位异或
putVal()--->还依赖于equals方法 (Object的equals方法)
刚才存储都是String类型:String类型本身已经重写了hashCode()和equals,如果hashCode和equals()都相同,
那么认为同一个元素,存储以前的值
LinkedHashSet的特点
LinkedHashSet的特点
可以保证怎么存入的就怎么取出来。
底层是链表实现的,是set集合中唯一一个能保证怎么存就怎么取的集合对象
因为是HashSet的子类,所以也是保证元素唯一的,与HashSet的原理一样
5.TreeSet
TreeSet集合 :无序性,元素唯一
TreeSet是非同步的,线程不安全的
底层依赖于TreeMap集合, 红黑树结构(也称为 "自平衡的二叉树结构"),可以实现Map的自然排序以及比较器排序取决于使用的构造方法
构造方法:
public TreeSet():构造一个空的树,实现元素自然排序 (取决于存储的元素类型能否实现Comparable接口)
自然排序 ----->执行的TreeSet无参构造方法,而且前提条件当前存储类型必须实现Comparable接口
public class TreeSetDemo {
public static void main(String[] args) {
// public TreeSet()
//Integer类型
TreeSet<Integer> ts = new TreeSet<>() ;
//Intger元素 实现Comparable接口---就能够按照元素自然排序(默认升序排序)
//添加元素
ts.add(20) ;
ts.add(17) ;
ts.add(17) ;
ts.add(18) ;
ts.add(24) ;
ts.add(23) ;
ts.add(24) ;
ts.add(19) ;
//遍历集合TreeSet
for(Integer i:ts){
System.out.println(i);
}
}
}
1.TreeSet的排序
TreeSet针对排序条件来操作,并不是简单的存储,加入排序条件,否则针对TreeSet<自定义类型>,就报错!
排序:
自然排序 ----->执行的TreeSet无参构造方法,而且前提条件当前存储类型必须实现Comparable接口
比较强排序
1)自然排序
public TreeSet():构造一个空的树,实现元素自然排序 (取决于存储的元素类型能否实现Comparable接口)
自然排序----->执行的TreeSet无参构造方法,而且前提条件当前存储类型必须实现Comparable接口 并实现compareTo方法
/**
* 需求:
* 使用TreeSet集合存储学生类型
* 主要条件:按照学生姓名的长度:从小到大进行排序
*/
//实现自然排序 实现一个接口Comparable
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 age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//排序的代码
@Override
public int compareTo(Student s) { //后面需要和学生对象对比
//主要条件:按照学生姓名的长度:从小到大进行排序
int num = this.name.length() - s.name.length() ;
//如果长度相同,还比较内容是否一样 "hello" ,"hel"
int num2 = (num==0)?(this.name.compareTo(s.name)):num ;
//如果长度相同,内容一样
//按照学生的年龄从小到大比
int num3 = (num2==0)? (this.age - s.age) :num2 ;
return num3 ;
}
}
public class TreeSetDemo3 {
public static void main(String[] args) {
//无参构造方法创建TreeSet集合
TreeSet<Student> ts = new TreeSet<>() ;
//创建几个学生对象
Student s1 = new Student("wenzhang",34) ;
Student s2 = new Student("zhaosisi",36) ;
Student s3 = new Student("wuyifan",40) ;
Student s4 = new Student("wuyifan",32) ;
Student s5 = new Student("gaoyuanyuan",42) ;
Student s6 = new Student("gaoyuanyuan",42) ;
Student s7 = new Student("zhangjunjie",20) ;
Student s8 = new Student("liuqiangdong",50) ;
ts.add(s1) ;
ts.add(s2) ;
ts.add(s3) ;
ts.add(s4) ;
ts.add(s5) ;
ts.add(s6) ;
ts.add(s7) ;
ts.add(s8) ;
//遍历
for(Student s: ts){
System.out.println(s.getName()+"---"+s.getAge());
}
}
}
2)比较强排序
TreeSet能够实现两种排序:
自然排序/比较强排序,取决于构造方法
自然排序:TreeSet<E>(),E类型必须实现Comparable接口,实现自然排序(实现的compareTo(T t))
比较强排序:
public TreeSet(Comparator<? super E> comparator)
Comparator是一个接口类型
1)自定义一个类实现Comparator接口,重写compare方法
2)使用接口的匿名内部类(推荐)
使用TreeSet存储Student类型,遍历元素(使用比较强排序完成)
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) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
if (age != student.age) return false;
return name.equals(student.name);
}
@Override
public int hashCode() {
int result = name.hashCode();
result = 31 * result + age;
return result;
}
}
//方式1:创建一个类实现Comparator接口
public class MyComparator implements Comparator<Student> {
@Override
public int compare(Student s1, Student s2) {
//主要条件:按照学生的年龄从小到大排序
//s1---->就是刚才自然排序里面this
//s2---->就是刚才自然排序里面s
int num = s1.getAge() - s2.getAge() ;
//如果年龄相同,比较姓名是否一样
int num2 = (num==0)? (s1.getName().compareTo(s2.getName())): num ;
return num2;
}
}
public class TreeSetDemo {
public static void main(String[] args) {
//方式2:接口的匿名内部类
TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
//主要条件:按照学生的年龄从小到大排序
//s1---->就是刚才自然排序里面this
//s2---->就是刚才自然排序里面s
int num = s1.getAge() - s2.getAge() ;
//如果年龄相同,比较姓名是否一样
int num2 = (num==0)? (s1.getName().compareTo(s2.getName())): num ;
return num2;
}
}) ;
//创建几个学生对象
Student s1 = new Student("gaoyuanyuan",42) ;
Student s2 = new Student("gaoyuanyuan",42) ;
Student s3 = new Student("jacky",40) ;
Student s4 = new Student("rose",40) ;
Student s5 = new Student("tomcat",35) ;
Student s6 = new Student("jeffry",35) ;
Student s7 = new Student("liushishi",54) ;
Student s8 = new Student("liudehua",60) ;
ts.add(s1) ;
ts.add(s2) ;
ts.add(s3) ;
ts.add(s4) ;
ts.add(s5) ;
ts.add(s6) ;
ts.add(s7) ;
ts.add(s8) ;
for (Student s:ts) {
System.out.println(s.getName()+"---"+s.getAge());
}
}
}
2.泛型
泛型高级通配符(了解)
<?> : 任意Java类型,包括Object
<? super E> : 向上限定:E类型以及E父类
<? extends E>: 向下限定:E以及它的子类
public static void main(String[] args) {
//创建Collection
Collection<?> c1 = new ArrayList<Object>() ;
Collection<?> c2 = new ArrayList<Animal>() ;
Collection<?> c3 = new ArrayList<Cat>() ;
Collection<?> c4 = new ArrayList<Dog>() ;
System.out.println("------------------------------");
Collection<? super Cat> c5 = new ArrayList<Cat>() ;//最基本的一致
Collection<? super Cat> c6 = new ArrayList<Animal>() ;
Collection<? super Cat> c7 = new ArrayList<Object>() ;
System.out.println("------------------------------");
Collection<? extends Object> c8 = new ArrayList<Object>() ;
Collection<? extends Object> c9 = new ArrayList<Animal>() ;
Collection<? extends Object> c10 = new ArrayList<Cat>() ;
Collection<? extends Animal> c11 = new ArrayList<Animal>() ;
Collection<? extends Animal> c12 = new ArrayList<Cat>() ;
Collection<? extends Animal> c13 = new ArrayList<Dog>() ;*/
}
3.TreeSet的add方法的源码
class TreeSet<E> implement Set<E>{
private transient NavigableMap<E,Object> m; 成员变量:(不会被序列化)
private static final Object PRESENT = new Object();
public TreeSet() {
this(new TreeMap<E,Object>()); //调用的是本类的有参构造方法
}
//本类的有参构造方法 //NavigableMap m = new TreeMap();
TreeSet(NavigableMap<E,Object> m) { //NavigableMap---extendsMap //形式参数是一个接口Map接口
this.m = m;
}
//添加方法
public boolean add(E e) { //20,17,20,21...
return m.put(e, PRESENT)==null;
}
}
class TreeMap implements NavigableMap{
private transient Entry<K,V> root; 键值对对对象: 根节点
public V put(K key, V value) { // key = 20 ,17 ,... V:Object
Entry<K,V> t = root;
if (t == null) {
compare(key, key); // type (and possibly null) check
root = new Entry<>(key, value, null);
size = 1;
modCount++;
return null;
}
int cmp;
Entry<K,V> parent;
// split comparator and comparable paths
//TreeSet<E>(有参构造方法) :执行的比较强排序
//public TreeSet(Comparator<? super E> comparator)
Comparator<? super K> cpr = comparator;
if (cpr != null) {
do {
parent = t;
cmp = cpr.compare(key, t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
else {
//开启自然排序 :TreeSet<E>()无参构造方法: E类型必须实现Comparable接口
if (key == null)
throw new NullPointerException();
/
@SuppressWarnings("unchecked"):压制警告
Comparable<? super K> k = (Comparable<? super K>) key;
do {
parent = t;
cmp = k.compareTo(t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
Entry<K,V> e = new Entry<>(key, value, parent);
if (cmp < 0)
parent.left = e;
else
parent.right = e;
fixAfterInsertion(e);
size++;
modCount++;
return null;
}
}
6.Map
Map集合:键映射到值的对象,Map集合可以多个值,但键必须唯一!
特点:
每个元素成对存在,由键和值两部分组成,通过键可以找到对应的值
键(key值)不可重复,值(value)可以重复,一个value值可以和很多key值形成对应关系,每个建最多只能映射到一个值
两个 Map 接口的重要实现类:HashMap类、LinkedHashMap 类
Map子类
1.HashMap
使用 HashMap定义的Map集合是无序存放的
如果发现重复的 key会将新的数据替换掉已有的数据
使用 HashMap子类保存数据时,key或 value可以保存为null
HashMap是非线程安全的,只是用于单线程环境下,多线程环境下可以采用concurrent并发包下的concurrentHashMap
2.Hashtable
Hashtable和 HashMap很相似,不同之处是 Hashtable线程是安全的,key不允许设置为 null
3.TreeMap
可以排序的Map集合,按集合中的key排序,key不允许重复
最终保存在Map中的数据是经过排序的数据,按其key排序
4.LinkedHashMap
LinkedHashMap 是HashMap的一个子类,保存了记录的插入顺序,因此在遍历的时候会比HashMap效率要低。
不过也有例外情况,当HashMap容量很大,实际存储的数据较少时,遍历起来可能会比LinkedHashMap要慢,因为LinkedHashMap的遍历速度只和实际数据有关,和容量无关,而HashMap的遍历速度和他的容量有关
一般情况下,在Map中插入、删除和定位元素,HashMap 是最好的选择。如果需要元素输出的顺序和输入的相同,就需要选择LinkedHashMap了
1.Map集合的功能
Map集合的功能:
1)V put(K key,V value):添加键值对元素
注意事项:
如果key是第一次添加,那么返回的结果为null
如果key是否重复添加,第二次添加,返回的上一次添加的键对应的值
2)V remove(Object key):删除指定的键,返回被删除键对应的值
3)void clear()
4)boolean containsKey(Object key) :是否包含指定的键 (使用居多)
5)boolean containsValue(Object value):是否包含指定的值
HashTable与HashMap对比
共同点:底层数据结构是桶结构(基于哈希表实现)
不同点:
1)HashMap是线程不安全的类,多线程下会造成并发冲突,但单线程下运行效率较高
HashTable是线程安全的类,很多方法都是用synchronized修饰,但同时因为加锁导致并发效率低下,单线程环境效率也十分低
2)插入null:HashMap允许有一个键为null,允许多个值为null
HashTable不允许键或值为null
3)容量:HashMap底层数组长度必须为2的幂,这样做是为了hash准备,默认为16
HashTable底层数组长度可以为任意值,这就造成了hash算法散射不均匀,容易造成hash冲突,默认为11
4)Hash映射:HashMap的hash算法通过非常规设计,将底层table长度设计为2的幂,使用位与运算代替取模运算,减少运算消耗
而HashTable的hash算法首先使得hash值小于整型数最大值,再通过取模进行散射运算
2.Map和Collection集合的区别
Map和Collection集合的区别:
Collection:只能存储一种类型 Collection<E> 简单记"光棍"
Map集合:可以两种类型的,键的类型,值的类型 Map<K,V> 简单记"夫妻对"
遍历方式不同
Collection:就通过5种方式(List)
Map:两种方式:
方式1:获取所有的K的集合(键的集合)
通过键获取值
方式2: 获取所有的键值对对象Map.Entry<K,V> ("结婚证")
通过键值对对象获取所有的键("结婚证男方")
通过键值对对象获取所有的值("结婚证女方")
有内在联系:
TreeSet集合---->Collection---->间接的使用到了TreeMap集合的put方法
HashSet阶------>Collection---->间接使用到了HashMap的put方法
public class MapDemo {
public static void main(String[] args) {
//创建Map集合:接口
//默认用的是HashMap集合 TreeMap(根据元素排序)
Map<String,String> map = new HashMap<String,String>() ;
System.out.println(map);
//添加功能
// String result = map.put("文章", "马伊琍");
// System.out.println(result);
map.put("文章", "马伊琍");
map.put("王宝强","马蓉") ;
map.put("杨过","小龙女") ;
map.put("郭靖","黄蓉") ;
// String result2 = map.put("文章", "姚笛");
// System.out.println(result2);
map.put("文章", "姚笛");
System.out.println("---------------------------------");
// System.out.println(map.remove("杨过"));
// map.clear();
System.out.println(map.containsKey("周杰伦")) ;
System.out.println(map.containsKey("王宝强")) ;
System.out.println(map.containsValue("郭蓉")) ;
System.out.println(map.containsValue("小龙女")) ;
System.out.println(map);
}
}
3.遍历
高级功能:
Map遍历功能
方式1:
Set<K> keySet() :获取当前Map集合中的所有的键的集合 (将所有的丈夫集中起来,找对应的妻子)
+
V get(Object key):通过键获取值
方式2:
获取所有的结婚证 (键值对对象)
Set<Map.Entry<K,V>> entrySet()
通过键值对象 获取键 /获取值(通过结婚证找男方/女方)
K getKey()
V getValue()
public class MapDemo2 {
public static void main(String[] args) {
//创建Map集合对象
Map<String,String> map = new HashMap<>() ;
//添加元素
map.put("令狐冲","东方不败") ;
map.put("杨过","小龙女") ;
map.put("陈玄风","梅超风") ;
map.put("郭靖","黄蓉") ;
// Set<K> keySet() :获取当前Map集合中的所有的键的集合
Set<String> keySet = map.keySet(); //推荐第一种方式
//增强for遍历
for(String key: keySet){
//获取所有的键的元素
// V get(Object key):通过键获取值
String value = map.get(key);
System.out.println(key+"="+value);
}
System.out.println("--------------------------------------");
//方式2:
//Set<Map.Entry<K,V>> entrySet()
Set<Map.Entry<String, String>> entry = map.entrySet();
//增强for:遍历键值对对象获取到
for(Map.Entry<String, String> en: entry){
//获取键和值
//K getKey()
// V getValue()
String key = en.getKey();
String value = en.getValue();
System.out.println(key+"="+value);
}
}
}
4.HashMap
HashMap<Student,String>: HashMap<String,Student>
Key: Student类型(姓名和年龄):自定义类型
Value: String(爱好)
Map集合针对键有效:不能迭代顺序恒久不变
HashMap的put方法依赖于hashCode()和equals方法,键的类型必须重写Object类的hashCode和equals方法,保证键唯一!
public class HashMapDemo {
public static void main(String[] args) {
//创建Map集合对象
HashMap<Student,String> map = new HashMap<>() ;
//创建几个学生对象
Student s1 = new Student("文章",35) ;
Student s2 = new Student("文章",35) ;
Student s3 = new Student("文章",37) ;
Student s4 = new Student("潘玮柏",40) ;
Student s5 = new Student("赵又廷",39) ;
Student s6 = new Student("蔡徐坤",38) ;
Student s7 = new Student("蔡徐坤",38) ;
Student s8 = new Student("肖战",30) ;
map.put(s1,"足球") ;
map.put(s2,"篮球") ;
map.put(s3,"足球") ;
map.put(s4,"吸毒") ;
map.put(s5,"高圆圆") ;
map.put(s6,"乒乓球") ;
map.put(s7,"篮球") ;
map.put(s8,"演戏") ;
//遍历
Set<Student> students = map.keySet();
for(Student key :students){
//通过键获取值
String hobit = map.get(key);
System.out.println(key.getName()+"---"+key.getAge()+"---"+hobit);
}
}
}
//public class Student implements Comparable<Student>{
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) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
if (age != student.age) return false;
return name != null ? name.equals(student.name) : student.name == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
/*@Override
public int compareTo(Student s) {
//主要条件:学生的年龄从小到大排序
int num = this.age - s.age ;
//如果年龄相同,要比较姓名的内容是否相同
int num2 = (num==0)? (this.name.compareTo(s.name)):num ;
return num2;
}*/
}
5.TreeMap
TreeMap:红黑树结构---针对Map的键按照条件排序---键属于自定义的情况
TreeMap<Integer,String>
TreeMap<Student,String>
存储学生类型(姓名,年龄) ,value:描述"朝代"
键必须唯一而且排序的主要条件:按照学生的年龄从小到大排序
TreeMap的构造方法
public TreeMap():针对键进行自然排序
public TreeMap(Comparator<? super K> comparator):针对键按照比较器进行排序
public class TreeMapDemo {
public static void main(String[] args) {
//创建TreeMap集合对象
// TreeMap<Student,String> tm = new TreeMap<>() ; //无参构造方法:自然排序 :前提条件:键 的类型必须实现Comparable
//比较器排序:匿名内部类
TreeMap<Student,String> tm = new TreeMap<>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
//主要条件:学生的年龄从大到小排序
int num = s2.getAge() - s1.getAge() ;
//如果年龄相同,要比较姓名的内容是否相同
int num2 = (num==0)? (s1.getName().compareTo(s2.getName())):num ;
return num2;
}
}) ;
//创建学生对象
Student s1 = new Student("唐伯虎",38) ;
Student s2 = new Student("唐伯虎",38) ;
Student s3 = new Student("秋香",30) ;
Student s4 = new Student("祝枝山",40) ;
Student s5 = new Student("祝枝山",45) ;
Student s6 = new Student("文征明",39) ;
Student s7 = new Student("石榴姐",20) ;
Student s8 = new Student("东香",18) ;
Student s9 = new Student("徐香",18) ;
tm.put(s1,"明朝") ;
tm.put(s2,"宋代") ;
tm.put(s3,"清朝") ;
tm.put(s4,"明朝") ;
tm.put(s5,"现代") ;
tm.put(s6,"唐朝") ;
tm.put(s7,"宋代") ;
tm.put(s8,"明朝") ;
tm.put(s9,"现代") ;
Set<Student> students = tm.keySet();
for(Student key :students){
String value = tm.get(key);
System.out.println(key.getName()+"---"+key.getAge()+"---"+value);
}
}
}
7.Collections
1.针对集合操作工具类
1.Collections:针对集合操作工具类
提供静态功能:
1)public static <T extends Comparable<? super T>> void sort(List<T> list):按照自然升序排序(针对List集合排序)
2)public static <T> void sort(List<T> list,Comparator<? super T> c):按照比较器排序针对List集合
3)public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T>:获取当前自然顺序中List的最大值
4)public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T>:最小值
5)public static void reverse(List<?> list):对List集合顺序反转
6)public static void shuffle(List<?> list):随机置换
public class CollectionsDemo1 {
public static void main(String[] args) {
//创建List集合
List<Integer> list = new ArrayList<>() ;
//添加元素
list.add(10) ;
list.add(50) ;
list.add(15) ;
list.add(25) ;
list.add(5) ;
list.add(12) ;
System.out.println(list);
System.out.println("---------------------------------");
//public static <T extends Comparable<? super T>> void sort(List<T> list):
Collections.sort(list);
System.out.println(list);
System.out.println("----------------------------------");
//public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T>
Integer max = Collections.max(list);
System.out.println(max);
System.out.println("----------------------------------");
System.out.println(Collections.min(list));
System.out.println("-----------------------------------");
Collections.reverse(list);//反转
System.out.println(list);
System.out.println("------------------------------------");
// public static void shuffle(List<?> list):随机置换
Collections.shuffle(list);
System.out.println(list);
}
}
2.自定义类型元素
1)public static <T extends Comparable<? super T>> void sort(List<T> list):按照自然升序排序(针对List集合排序)
2)public static <T> void sort(List<T> list,Comparator<? super T> c):按照比较器排序针对List集合
List<Student>:针对List进行自然升序排序,
主要条件:按照学生的年龄从小到大排
次要条件:年龄相同,比较姓名内容是否相同!
public class CollectionsTest {
public static void main(String[] args) {
//创建List集合对象
List<Student> list = new ArrayList<>() ;
//创建几个学生对象
Student s1 = new Student("gaogaoyuan",42) ;
Student s2 = new Student("gaogaoyuan",40) ;
Student s3 = new Student("liushishi",42) ;
Student s4 = new Student("wanglihong",45) ;
Student s5 = new Student("wenzhang",38) ;
Student s6 = new Student("huazi",35) ;
Student s7 = new Student("huazi",32) ;
Student s8 = new Student("zhangjunjie",20) ;
//添加
list.add(s1) ;
list.add(s2) ;
list.add(s3) ;
list.add(s4) ;
list.add(s5) ;
list.add(s6) ;
list.add(s7) ;
list.add(s8) ;
//排序
//Collections.sort(list); //自然升序排序:针对集合当前存储的类型必须实现Comparable
//使用比较器排序:针对List集合
//public static <T> void sort(List<T> list,Comparator<? super T> c):按照比较器排序针对List集合
Collections.sort(list, new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
int num = s1.getAge() - s2.getAge() ;
int num2 = (num==0)?(s1.getName().compareTo(s2.getName())):num ;
return num2;
}
});
for(Student s:list){
System.out.println(s.getName()+"---"+s.getAge());
}
}
}
//public class Student implements Comparable<Student> {
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 int compareTo(Student s) {
//主要条件:按照学生的年龄从小到大排序
int num = this.age - s.age ;
//如果年龄相同,姓名比(字典顺序)
int num2 = (num==0)?(this.name.compareTo(s.name)):num ;
return num2;
}*/
}
3.斗地主
/*
模拟斗地主,保证牌有序
*/
public class PokerTest2 {
public static void main(String[] args) {
//1)牌盒
//创建一个牌盒Map:HashMap<Integer,String> key:编号 value:牌
HashMap<Integer,String> hm = new HashMap<>();
//创建一个ArrayList集合:存储编号
ArrayList<Integer> arrayList = new ArrayList<>() ;
//2)装牌
//创建点数数组
String[] numbers = {"3","4","5","6","7","8","9","10","J","Q","K","A","2"} ;
//创建花色数组
String[] colors = {"♥","♠","♣","♦"} ;
//拼接
//定义牌的编号:0开始
int index = 0 ;
for(String number:numbers){
for(String color:colors){
String porker = number.concat(color);
//将编号以及牌都添加HashMap集合
hm.put(index,porker) ;
//单独给ArrayList存储编号
arrayList.add(index) ;
index ++ ;
}
}
//给HashMap集合添加小王,大王,给ArrayList添加小王,大王的编号
hm.put(index,"小王") ;
arrayList.add(index) ;
index ++ ;
hm.put(index,"大王") ;
arrayList.add(index) ;
// System.out.println(arrayList);
//3)洗牌:随机置换 ArrayList<Integer> 洗的是编号
Collections.shuffle(arrayList);
// System.out.println(arrayList);
//4)发牌
/*
为了保证牌有序,发也是编号
* 三个人都分别是 TreeSet<Integer>集合
* 创建一个集合:diPai
* 判断:
* 如果角标>=牌盒整个size()-3 底牌
* 如果角标 %3 == 0 第一个人的
* 如果角标 %3 == 1 第二个人的
* %3 == 2 第三个人的
*/
TreeSet<Integer> player1 = new TreeSet<>() ;
TreeSet<Integer> player2 = new TreeSet<>() ;
TreeSet<Integer> player3 = new TreeSet<>() ;
//底牌
TreeSet<Integer> diPai = new TreeSet<>() ;
for(int x = 0 ;x < arrayList.size() ; x ++){
//0开始
if(x >= arrayList.size()-3){
diPai.add(arrayList.get(x)) ;
}else if(x % 3 == 0 ){
player1.add(arrayList.get(x)) ;
}else if(x % 3 == 1){
player2.add(arrayList.get(x)) ;
}else if(x % 3 ==2){
player3.add(arrayList.get(x)) ;
}
}
//看牌://看牌:每一个人都可以看牌,还可以看底牌,所以看牌封装一个功能
lookPoker("张俊杰",player1,hm);
lookPoker("高圆圆",player2,hm);
lookPoker("赵又廷",player3,hm);
lookPoker("底牌",diPai,hm);
}
public static void lookPoker(String name,TreeSet<Integer> ts,HashMap<Integer,String> hm){
//玩家1的牌是:xxx...
//玩家2的牌是:xxx....
System.out.print(name+"的牌是:");
//遍历TreeSet集合,获取每一个编号
for(Integer key: ts){
//获取到每一个编号---在HashMap集合中属于key(键) 编号
String poker = hm.get(key); //在大Map集合中通过键获取值
System.out.print(poker+" ");
}
System.out.println();
}
}