21_Java集合的进阶
Java中的集合进阶
了解:
1、集合知识回顾:
集合类的特点:提供了一种存储空间可变的储存类型,存储的数据容量可以随时发生改变
2、集合类体系结构(其中Collection、Map、list、Set都是接口【注意list有同名类】):
一、Colletion(单列)
1、Collection集合概述:
是单列集合的顶层接口,它表示一组对象,这些对象也称为Collection的元素
JDK不提供此接口的任何直接实现,它提供共更具体的子接口(如Set和List)实现
2、创建Collection集合对象
多态的方式
具体实现类ArrayList
参考代码:
package com.itheima_01; //导包 import java.util.Collection; import java.util.ArrayList; public class CollectionDemo01 { public static void main(String[] args){ //创建Collection集合对象 Collection<String> c = new ArrayList<String>(); //添加元素:boolean add(E e) c.add("Hello"); c.add("World"); c.add("Java"); //输出集合对象 System.out.println(c); } }
3、Collection集合常用方法:
方法名 | 说明 |
---|---|
boolean add(E e) | 添加元素 |
boolean remove(Object o) | 从集合中移除指定的元素 |
void clear() | 清空集合中的元素 |
boolean contains(Object o) | 判断集合中是否在指定的元素 |
boolean isEmpty() | 判断集合是否为空 |
int size() | 集合长度,也就是集合中元素的个数 |
参考代码:
package com.itheima_01; /* 测试常用方法: boolean add(E e) 添加元素 boolean remove(Object o) 从集合中移除指定的元素 void clear() 清空集合中的元素 boolean contains(Object o) 判断集合中是否在指定的元素 boolean isEmpty() 判断集合是否为空 int size() 集合长度,也就是集合中元素的个数 Alt + 7 可以打开一个类结构窗口 */ //导包 import java.util.Collection; import java.util.ArrayList; public class CollectionDemo02 { public static void main(String[] args){ //创建集合对象 Collection<String> collection = new ArrayList<String>(); //1、boolean add(E e) 添加元素 // System.out.println(collection.add("张三")); //判断是否添加成功 // System.out.println(collection.add("李四")); // System.out.println(collection.add("张三")); //返回值都是true 所以直接这样写,且发现可以有重复元素存在 collection.add("张三"); collection.add("李四"); collection.add("张三"); // //2、boolean remove(Object o) 从集合中移除指定的元素 // System.out.println(collection.remove("王五")); // System.out.println(collection.remove("张三")); // //3、void clear() 清空集合中的元素 // collection.clear(); // //4、boolean contains(Object o) 判断集合中是否在指定的元素 // System.out.println(collection.contains("王五")); // System.out.println(collection.contains("张三")); // //5、boolean isEmpty() 判断集合是否为空 // System.out.println(collection.isEmpty()); // collection.clear(); // System.out.println(collection.isEmpty()); //6、int size() 集合长度,也就是集合中元素的个数 System.out.println(collection.size()); //输出集合对象 System.out.println(collection); } }
4、Collection集合的遍历:
Iterator:迭代器,集合的专用遍历方式
Iterator<E> iterator(); 返回此集合中元素的迭代器,通过集合的iterator()方法得到 //迭代器是通过集合的iterator()方法得到的,所以我们说它是依赖于集合而存在的
Iterator中的常用方法
E next(); 返回迭代器中的下一个元素
boolean hasNext(); 如果迭代器具有更多元素,则返回true
参考代码:
package com.itheima_02; /* Iterator:迭代器,集合的专用遍历方式 Iterator<E> iterator(); 返回此集合中元素的迭代器,通过集合的iterator()方法得到 //迭代器是通过集合的iterator()方法得到的,所以我们说它是依赖于集合而存在的 Iterator中的常用方法 E next(); 返回迭代器中的下一个元素 boolean hasNext(); 如果迭代器具有更多元素,则返回true */ //导包 import java.util.Collection; import java.util.ArrayList; import java.util.Iterator; public class IteratorDemo { public static void main(String[] args){ //创建集合对象 Collection<String> collection = new ArrayList<String>(); //添加元素 collection.add("hello"); collection.add("world"); collection.add("java"); //1、Iterator<E> iterator(); 返回此集合中元素的迭代器,通过集合的iterator()方法得到 Iterator<String> it = collection.iterator(); /* public Iterator<E> iterator() { return new Itr(); } private class Itr implements Iterator<E>{...} */ //2、E next(); 返回迭代器中的下一个元素 /*System.out.println(it.next()); System.out.println(it.next()); System.out.println(it.next()); System.out.println(it.next()); //NoSuchElementException被各种访问器方法抛出,表示被请求的元素不存在。 */ //4、boolean hasNext(); 如果迭代器具有更多元素,则返回true // if(it.hasNext()){ // System.out.println(it.next()); // } // if(it.hasNext()){ // System.out.println(it.next()); // } // if(it.hasNext()){ // System.out.println(it.next()); // } // if(it.hasNext()) { // System.out.println(it.next()); // } //使用循环实现 while(it.hasNext()){ // System.out.println(it.next()); String s = it.next(); System.out.println(s); } // for(; it.hasNext();){ // System.out.println(it.next()); // } } }
5、集合的使用步骤:
1、创建集合对象
2、添加元素
2.1、创建元素
2.2、添加元素到集合
合并:添加元素到集合
3、遍历集合
3.1、通过集合对象获取迭代器对象(对象.iterator())
3.2、通过迭代器对象的hasNext()方法判断是否还有元素
3.3、通过迭代器对象的next()方法获取下一个元素
6、案例:Collection集合存储学生对象并遍历
package com.itheima_03; /* 定义一个简单的学生类 */ public class Student { private String name; private int age; public Student(){} public Student(String name, int age){ this.name = name; this.age = age; } public void setName(String name){ this.name = name; } public String getName(){ return this.name; } public void setAge(int age){ this.age = age; } public int getAge(){ return this.age; } @Override public String toString(){ return "Student" + "{" + "name=" + "'" + this.name + '\'' + "age=" + "'" + this.age + '\'' + "}"; } @Override public boolean equals(Object o){ if(o.toString().equals(this.toString())){ return true; } else{ return false; } } }
package com.itheima_03; /* 使用Collection集合对象存储学生对象并遍历 注意指明集合 与 迭代器 <> 中的泛型类(需要一致) */ //导包 import java.util.Collection; import java.util.ArrayList; import java.util.Iterator; public class CollectionDemo { public static void main(String[] args){ //创建Collection对象 Collection<Student> collection = new ArrayList<Student>(); //创建学生对象 Student s1 = new Student("张三", 20); Student s2 = new Student("李四", 21); Student s3 = new Student("王五", 22); //添加学生对象 collection.add(s1); collection.add(s2); collection.add(s3); //获取迭代器对象 Iterator<Student> it = collection.iterator(); //遍历学生对象 while(it.hasNext()){ Student stu = it.next(); System.out.println(stu.getName() + "," + stu.getAge()); } } }
二、List集合概述和特点
1、List集合概述:
有序集合(也称为序列),用户可以精确控制列表中每一个元素的插入位置。用户可以通过整数索引访问元素,并搜索列表中的元素
与Set集合不同,列表通常允许重复元素
2、List集合特点:
有序:存储和取出的元素顺序一致
可重复:存储的元素可以重复
参考代码:
package com.itheima_01; /* List集合特点: 有序:存储和取出的元素顺序一致 可重复:存储的元素可以重复 */ //导包 import java.util.List; import java.util.ArrayList; import java.util.Iterator; public class ListDemo01 { public static void main(String[] args){ //创建集合对象 List<String> list = new ArrayList<String>(); //添加元素 list.add("元素1"); list.add("元素2"); list.add(1, "元素2"); //直接输出集合对象 从输出看Arraylist中重写toString()方法 // System.out.println(list); //采用迭代器方式进行遍历 Iterator<String> it = list.iterator(); while(it.hasNext()){ String s = it.next(); System.out.println(s); } } }
3、List集合特有方法(相较于其父接口类Collcetion)
方法名 | 说明 |
---|---|
void add(int index, E element) | 在此集合中指定位置插入指定元素 |
E remove(int index) | 删除指定索引处的元素,返回被删除的元素 |
E set(int index, E element) | 修改指定索引处的元素,返回被修改的元素 |
E get(int index) | 返回指定索引处的元素 |
参考代码:
package com.itheima_01; /* void add(int index, E element) 在此集合中指定位置插入指定元素 E remove(int index) 删除指定索引处的元素,返回被删除的元素 E set(int index, E element) 修改指定索引处的元素,返回被修改的元素 E get(int index) 返回指定索引处的元素 */ //导包 import java.util.List; import java.util.ArrayList; public class ListDemo02 { public static void main(String[] args){ //创建集合对象 List<String> list = new ArrayList<String>(); //添加元素 list.add("hello"); list.add("world"); list.add("java"); // //1、void add(int index, E element) 在此集合中指定位置插入指定元素 // list.add(2, "javase"); // list.add(4, "javaee"); // //2、E remove(int index) 删除指定索引处的元素,返回被删除的元素 // list.remove(2); // //3、 E set(int index, E element) 修改指定索引处的元素,返回被修改的元素 // System.out.println(list.set(2, "javase")); // //4、E get(int index) 返回指定索引处的元素 // System.out.println(list.get(1)); //for遍历集合 for(int i = 0; i < list.size(); i++){ String str = list.get(i); System.out.println(str); } // //输出集合 // System.out.println(list); } }
4、案例:List集合存储学生对象并遍历:
package com.itheima_02; /* 定义一个简单的学生类 */ public class Student { private String name; private int age; public Student(){} public Student(String name, int age){ this.name = name; this.age = age; } public void setName(String name){ this.name = name; } public String getName(){ return this.name; } public void setAge(int age){ this.age = age; } public int getAge(){ return this.age; } @Override public String toString(){ return "Student" + "{" + "name=" + "'" + this.name + '\'' + "age=" + "'" + this.age + '\'' + "}"; } @Override public boolean equals(Object o){ if(o.toString().equals(this.toString())){ return true; } else{ return false; } } }
package com.itheima_02; /* 使用List集合存储并遍历学生类 */ //导包 import java.util.List; import java.util.ArrayList; import java.util.Iterator; public class ListDemo { public static void main(String[] args){ //创建集合对象 List<Student> list = new ArrayList<Student>(); //创建学生对象 Student s1 = new Student("张三", 18); Student s2 = new Student("李四", 19); Student s3 = new Student("王五", 20); //添加集合对象 list.add(s1); list.add(1, s2); list.add(s3); // //使用迭代器遍历 // Iterator<Student> it = list.iterator(); // while(it.hasNext()){ // Student s = it.next(); // System.out.println(s.getName() + "," + s.getAge()); // } //使用for循环遍历 for(int i = 0; i < list.size(); i++){ Student stu = list.get(i); System.out.println(stu.getName() + "," + stu.getAge()); } } }
5、并发修改异常:
1、并发修改异常:
ConcurrentModificationException
2、产生原因:
迭代器遍历的过程中,通过集合对象修改了集合中元素的长度,造成了迭代器获取元素中判断预期修改值和实际修改值不一致,所以抛出了异常
3、解决方案:
用for循环遍历,然后用集合对象进行添加操作即可
应为使用 get(int index) 方法获取数组元素时不会对预期修改值和实际修改值进行判断
参考代码:
package com.itheima_03; /* 需求: 我有一个集合:List<String> list = new ArrayList<String>(); 里面有三个元素:list.add("hello"); list.add("world"); list.add("java"); 遍历集合:的到每一个元素,看有没有"world"这个元素,如果有,我就添加一个"javase"元素,请用代码实现 */ //导包 import java.util.List; import java.util.ArrayList; import java.util.Iterator; public class ListDemo { public static void main(String[] args) { //创建集合对象 List<String> list = new ArrayList<String>(); //添加三个元素 list.add("hello"); list.add("world"); list.add("java"); //遍历集合:的到每一个元素,看有没有"world"这个元素,如果有,我就添加一个"javase"元素,请用代码实现 // Iterator<String> it = list.iterator(); // while (it.hasNext()) { // String s = it.next(); // if(s.equals("world")){ // list.add("javase"); // } // } for(int i = 0; i < list.size(); i++){ String s = list.get(i); if(s == "world"){ list.add("javase"); } System.out.println(s); } System.out.println(list); } }
!!此为txt文件 public interface List<E>{ Iterator<E> iterator(); boolean add(E e); } public abstract class AbstractList<E>{//ArrayList的抽象父类 protected int modCount = 0; } public class ArrayList<E> extends AbstractList<E> implements List<E>{ public E get(int index) { Objects.checkIndex(index, size); return elementData(index); } //调用add方法后会使得 modCount的值加1 在下一次与expectdeModCount对比时就会抛出异常 public boolean add(E e) { modCount++; add(e, elementData, size); return true; } public Iterator<E> iterator() { return new Itr(); } private class Itr implements Iterator<E> { int expectedModCount = modCount; //一开始从抽象父类中继承都为0 /* modCount:实际修改的集合的次数 expectdeModCount:预期修改集合的次数 */ public E next() { checkForComodification(); int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i + 1; return (E) elementData[lastRet = i]; } //产生的原因:使用迭代器取出元素时 每一次都要进行此判断 final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } } }
6、ListIterator
1、ListIterator:列表迭代器:
通过List集合的 listIterator() 方法得到,所以说它是List集合特有的迭代器
用于允许程序员沿任一方向遍历列表的列表的迭代器,在迭代期间修改列表,并获取列表中迭代器的当前位置
2、ListIterator中常用的方法: E next():返回迭代器中的下一个元素
boolean hasNext():如果迭代器具有更多元素,则返回true
E previous() :返回列表中的上一个元素
boolean hasPrevious():如果此列表迭代器在相反方向遍历列表时具有更多元素,则返回true
void add(E e):将指定元素插入列表中
参考代码:
package com.itheima_04; /* E next():返回迭代器中的下一个元素 boolean hasNext():如果迭代器具有更多元素,则返回true E previous() :返回列表中的上一个元素 boolean hasPrevious():如果此列表迭代器在相反方向遍历列表时具有更多元素,则返回true void add(E e):将指定元素插入列表中 */ //导包 import java.util.List; import java.util.ArrayList; import java.util.ListIterator; public class Listiterator { public static void main(String[] args){ //创建集合对象 List<String> list = new ArrayList<String>(); //添加元素 list.add("hello"); list.add("world"); list.add("java"); // //创建列表迭代器对象 一般直接用Iterator // ListIterator<String> li = list.listIterator(); // // //正向遍历 // while(li.hasNext()){ // String s = li.next(); // System.out.println(s); // } // // System.out.println("----------------"); // // //逆向遍历 了解即可 // while(li.hasPrevious()){ // String s = li.previous(); // System.out.println(s); // } //获取列表迭代器 ListIterator<String> li = list.listIterator(); while(li.hasNext()){ String s = li.next(); if(s.equals("world")){ //此处使用的是列表迭代器对象中的add方法 而没有使用集合对象的add方法 li.add("javase"); } } System.out.println(list); } }
public interface List<E>{ Iterator<E> iterator(); ListIterator<E> listIterator(); boolean add(E e); } public abstract class AbstractList<E>{//ArrayList的抽象父类 protected int modCount = 0; } public class ArrayList<E> extends AbstractList<E> implements List<E>{ public Iterator<E> iterator(){ return new Itr(); } private class Itr implements Iterator<E> { ... } public ListIterator<E> listIterator() { return new ListItr(0); } private class ListItr extends Itr implements ListIterator<E> { public void add(E e) { checkForComodification(); try { int i = cursor; ArrayList.this.add(i, e); cursor = i + 1; lastRet = -1; //!!!实际修改值重新赋值给预期修改值 expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } } }
7、增强for循环
1、增强for循环:简化数组和Collection集合的遍历
实现iterator接口的类允许其对象成为增强for语句的目标
它是JDK5之后出现的,其内部原理是一个iterator迭代器
2、增强for格式:
for(元素数据类型 变量名: 数组或者Collection集合){ //在此处使用变量即可,该变量就是元素 } 示例 int[] arr = {1, 2, 3, 4, 5}; for(int i: arr){ System.out.println(i); }
8、List集合存储学生对象用三种方式遍历
package com.itheima_06; /* 使用三种方式存储并遍历 List集合中存储的学生对象 */ //导包 import java.util.List; import java.util.ArrayList; import java.util.Iterator; public class ListDemo { public static void main(String[] args){ //创建List集合对象 List<Student> list = new ArrayList<Student>(); //创建Student对象 Student s1 = new Student("张三", 18); Student s2 = new Student("李四", 19); Student s3 = new Student("王五", 20); //添加元素 list.add(s1); list.add(s2); list.add(s3); //使用迭代器进行遍历 Iterator<Student> it = list.iterator(); while(it.hasNext()){ Student stu = it.next(); System.out.println(stu.getName() + "," + stu.getAge()); } System.out.println("--------"); //使用常见for循环遍历 for(int i = 0; i < list.size(); i++){ Student stu = list.get(i); //list中有,Collection中没有 System.out.println(stu.getName() + "," + stu.getAge()); } System.out.println("---------"); //使用增强for循环遍历 for(Student stu : list){ System.out.println(stu.getName() + "," + stu.getAge()); } } }
9、数据结构:
数据结构是计算机存储、组织数据的方式。是指相互之间存在一种或多种特定关系的数据元素的集合
通常情况下,精心选择的数据结构可以带来更高的运行效率
1、常见数据结构之栈:操作受限的线性表,栈一端封闭(不可在此进行进栈和出栈的操作),另一端可操作,所以就意味着栈是先进后出的。
可操作端:栈顶
不可操作端:栈底
元素进入栈中:压栈/进栈
元素离开栈中:弹栈/出栈
2、常见数据结构之队列:操作受限的线性表,队列一端规定只能进,另一端规定只能出(类似于排队),所以说队列是先进先出的。
只能出的一端:队头
只能进的一端:队尾
元素进入队列中:入队
元素离开队列中:出队
3、常见的数据结构之数组(线性表之顺序表):操作不受限(针对于前两种)的线性表(查询快,增删慢)
优点:通过数据对应的索引进行访问,查询速度快
缺点:
删除数据时,要将原始数据删除,同时还需要每个数据前移,删除效率低
添加数据时,添加位置后的每一个数据后移,再添加元素,添加效率极低
4、常见的数据结构之链表(线性表之链表):操作不受限(针对于前两种)的线性表(增删快,查询慢)
结点:与顺序表不同之处在于,链表的内存空间不是连续的!是通过指针进行关系连接的,所以链表是以结点为单位。
结点(C语言中一般使用结构体实现,在结构体中一部分变量用于存放数据,另一部分指针变量用于存放地址)
数据域:用于存放元素,可以是基本数据类型,也可以是自定义数据类型
指针与:用于指向下一个元素结点的空间地址值
一般来说为了使得,首元结点(第一个结点)与后续元素结点处于相同地位,我们又引入了头结点的概念。
当头结点指针域为null则表示该链表为空。
在链表中添加数据:
先确定好位置,然后先保存前一个结点中的地址值(即后一个结点位置),再用添加结点的地址值覆盖此数值,最后将保存的地址值赋值给添加结点的指针域即可添加一个元素(效率高)
在链表中删除数据:
先确定好位置,保留一下数据,再将这个数据对应的指针域的值赋值给前一个元素的指针域,清理空间即可(效率高)
在链表中查找数据:
只能从头结点开始:顺藤摸瓜,依次查找比对(效率慢)
10、List集合子类特点:
List集合常用子类:ArrayList(顺序表)、LinkedList(链表)
ArrayList:底层数据结构是数组,查询快,增删慢
LinkList:底层数据结构是链表,查询慢,增删快
练习:
分别使用ArrayList和LinkList完成存储数据字符串并遍历
参考代码:
package com.itheima_07; /* List集合常用子类:ArrayList(顺序表)、LinkedList(链表) ArrayList:底层数据结构是数组,查询快,增删慢 LinkList:底层数据结构是链表,查询慢,增删快 练习: 分别使用ArrayList和LinkList完成存储数据字符串并遍历 */ //导包 import java.util.ArrayList; import java.util.LinkedList; import java.util.Iterator; public class ListDemo { public static void main(String[] args){ //创建对象 ArrayList<String> arraylist = new ArrayList<String>(); //添加元素 arraylist.add("hello"); arraylist.add("world"); arraylist.add("java"); //迭代器遍历 Iterator<String> it = arraylist.iterator(); while(it.hasNext()){ String s = it.next(); System.out.println(s); } System.out.println("------"); //加强for循环遍历 for(String s : arraylist){ System.out.println(s); } System.out.println("------"); //普通for循环遍历 for(int i = 0; i < arraylist.size(); i++){ String s = arraylist.get(i); System.out.println(s); } System.out.println("以上都是ArrayList集合的遍历"); //创建LinkedList对象 LinkedList<String> linkedlist = new LinkedList<String>(); //添加元素 linkedlist.add("java"); linkedlist.add("javase"); linkedlist.add("javaee"); //迭代器遍历 Iterator<String> it2 = linkedlist.iterator(); while(it2.hasNext()){ String s = it2.next(); System.out.println(s); } System.out.println("--------"); //加强for循环遍历 for(String s : linkedlist){ System.out.println(s); } System.out.println("--------"); //普通for循环遍历 for(int i = 0; i < linkedlist.size(); i++){ String s = linkedlist.get(i); System.out.println(s); } } }
11、ArrayList集合存储学生对象用三种方式遍历:
package com.itheima_08; public class Student { private String name; private int age; public Student(){ } public Student(String name, int age){ this.name = name; this.age = age; } public void setName(String name){ this.name = name; } public String getName(){ return this.name; } public void setAge(int age){ this.age = age; } public int getAge(){ return this.age; } @Override public String toString(){ return "Student" + "{" + "name=" + "'" + this.name + '\'' + "age=" + "'" + this.age + '\'' + "}"; } @Override public boolean equals(Object o){ if(o.toString().equals(this.toString())){ return true; } else{ return false; } } }
package com.itheima_08; /* 通过ArrayList来实现三种遍历 */ //导包 import java.util.ArrayList; import java.util.Iterator; public class ArrayListDemo { public static void main(String[] args){ //创建ArrayList对象 ArrayList<Student> arraylist = new ArrayList<Student>(); //创建Student对象 Student s1 = new Student("张三", 18); Student s2 = new Student("李四", 19); Student s3 = new Student("王五", 20); //添加元素 arraylist.add(s1); arraylist.add(s2); arraylist.add(s3); //创建迭代器对象 Iterator<Student> it = arraylist.iterator(); while(it.hasNext()){ Student stu = it.next(); System.out.println(stu.getName() + "," + stu.getAge()); } System.out.println("--------"); //加强for for(Student stu : arraylist){ System.out.println(stu.getName() + "," + stu.getAge()); } System.out.println("--------"); //普通for for(int i = 0; i < arraylist.size(); i++){ Student stu = arraylist.get(i); System.out.println(stu.getName() + "," + stu.getAge()); } } }
package com.itheima_08; //导包 import java.util.LinkedList; import java.util.Iterator; public class LinkedListDemo { public static void main(String[] args){ //创建LinkedList对象 LinkedList<Student> linkedlist = new LinkedList<Student>(); //创建Student对象 Student s1 = new Student("张三", 18); Student s2 = new Student("李四", 19); Student s3 = new Student("王五", 20); //添加元素 linkedlist.add(s1); linkedlist.add(s2); linkedlist.add(s3); //迭代器遍历 Iterator<Student> it = linkedlist.iterator(); while(it.hasNext()){ Student stu = it.next(); System.out.println(stu.getName() + "," + stu.getAge()); } System.out.println("--------"); //使用加强for循环 for(Student stu : linkedlist){ System.out.println(stu.getName() + "," + stu.getAge()); } System.out.println("--------"); //使用普通for循环 for(int i = 0; i < linkedlist.size(); i++){ Student stu = linkedlist.get(i); System.out.println(stu.getName() + "," + stu.getAge()); } } }
12、Linkedlist集合的特有功能:
方法名 | 说明 |
---|---|
public void addFirst(E e) | 在列表开头插入指定的元素 |
public void addLast(E e) | 将指定元素追加到此列表中的末尾 |
public E getFirst() | 返回此列表中的第一个元素 |
public E getLast() | 返回此列表中的最后一个元素 |
public E removeFirst() | 从此列表中删除并返回第一个元素 |
public E removeLast() | 从此列表中删除并返回最后一个元素 |
package com.itheima_09; /* public void addFirst(E e) 在列表开头插入指定的元素 public void addLast(E e) 将指定元素追加到此列表中的末尾 public E getFirst() 返回此列表中的第一个元素 public E getLast() 返回此列表中的最后一个元素 public E removeFirst() 从此列表中删除并返回第一个元素 public E removeLast() 从此列表中删除并返回最后一个元素 */ //导包 import java.util.LinkedList; public class LinkedListDemo { public static void main(String[] args){ //创建LinkList集合对象 LinkedList<String> linkedlist = new LinkedList<String>(); //添加元素 linkedlist.add("List"); linkedlist.add("ArrayList"); //1、public void addFirst(E e) 在列表开头插入指定的元素 linkedlist.addFirst("Collection"); //2、public void addLast(E e) 将指定元素追加到此列表中的末尾 linkedlist.addLast("LinkedList"); //3、public E getFirst() 返回此列表中的第一个元素 System.out.println("单列集合体系的根是:" + linkedlist.getFirst()); //4、public E getLast() 返回此列表中的最后一个元素 System.out.println("目前使用的是其子类体系中的:" + linkedlist.getLast()); //5、public E removeFirst() 从此列表中删除并返回第一个元素 System.out.println("删除了:" + linkedlist.removeFirst());; //6、public E removeLast() 从此列表中删除并返回最后一个元素 System.out.println("又删除了:" + linkedlist.removeLast()); //输出元素 System.out.println("目前还有的元素:" + linkedlist); } }
三、Set集合(数学集)概述和特点
1、Set集合特点:
不包含重复元素的集合
没有带索引的方法,所以不能使用普通for循环遍历
2、Set集合练习:
存储字符串并遍历
参考代码:
package com.itheima_01; /* 1、Set集合特点 不包含重复元素的集合 没有带索引的方法,所以不能使用普通for循环遍历 HashSet 对集合的迭代顺序不作任何保证 */ //导包 import java.util.Set; //Set是一个接口 不能直接实现对象 要通过多态来创建 import java.util.HashSet; public class SetDemo { public static void main(String[] args){ //创建Set集合对象 Set<String> set = new HashSet<String>(); //添加元素 set.add("hello"); set.add("world"); set.add("java"); set.add("hello"); //增强for遍历元素 for(String s : set){ //从输出来看 就是无序的,自然没有索引一说 //同时,里面不允许出现重复元素 System.out.println(s); } } }
3、哈希值:
哈希值:是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值
Object类中有一个方法可以获取对象的哈希值
public int hashCode(); 返回对象的哈希码值
对象的哈希值特点
同一个对象多次调用hashCode()方法返回的哈希值是相同的
默认情况下,不同对象的哈希值是不同的,而且重写hashCode()方法,可以实现不同对象的哈希值相同(但是此时哈希值相同并不代表元素的内容相同)
参考代码:
package com.itheima_02; /* 哈希值:是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值 Object类中有一个方法可以获取对象的哈希值 public int hashCode(); 返回对象的哈希码值 */ //导包 import java.util.Set; import java.util.HashSet; public class HashDemo { public static void main(String[] args){ //创建学生对象 Student stu = new Student("张三", 19); //使用Object超类中的 public int hashCode(); 返回对象的哈希码值 //同一个对象 多次调用hashCode()方法返回的哈希值是相同的 System.out.println(stu.hashCode()); //1435804085 System.out.println(stu.hashCode()); //1435804085 //默认情况下,不同对象的哈希值是不相同的 //通过方法重写可以使得 不同对象的哈希值相同 Student stu2 = new Student("李四", 20); System.out.println(stu2.hashCode()); //1784662007 System.out.println("hello".hashCode()); //99162322 System.out.println("world".hashCode()); //113318802 System.out.println("java".hashCode()); //3254818 System.out.println("world".hashCode()); //113318802 System.out.println("--------"); System.out.println("重地".hashCode()); //1179395 System.out.println("通话".hashCode()); //1179395 } }
4、HashSet集合概述和特点:
HashSet集合特点
底层数据结构是哈希表
对集合的迭代顺序不作任何保证,也就是说不保证存储和取出的元素顺序一致
没有带索引的方法,所以不能使用普通for循环遍历
由于是Set集合,所以是不包含重复元素的集合
HashSet集合练习
存储字符串并遍历
参考代码:
package com.itheima_03; /* HashSet集合特点 底层数据结构是哈希表 对集合的迭代顺序不作任何保证,也就是说不保证存储和取出的元素顺序一致 没有带索引的方法,所以不能使用普通for循环遍历 由于是Set集合,所以是不包含重复元素的集合 */ //导包 import java.util.Set; import java.util.HashSet; public class HashDemo { public static void main(String[] args){ //创建集合对象 HashSet<String> hashset = new HashSet<String>(); //添加元素 hashset.add("hello"); hashset.add("world"); hashset.add("java"); hashset.add("world"); //遍历 for(String s : hashset){ System.out.println(s); } } }
5、HastSet集合保证元素唯一性源码分析
//创建集合对象 HashSet<String> hashset = new HashSet<String>(); //添加元素 hashset.add("hello"); hashset.add("world"); hashset.add("java"); hashset.add("world"); -------------------------------------------- public boolean add(E e) { return map.put(e, PRESENT)==null; } static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } public V put(K key, V value) { return putVal(hash(key), key, value, false, true); } //hash值和元素的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判断直接短路,继续向下执行,把元素添加到集合 如果哈希值相同,会调用对象的equals()方法进行比较 如果返回false,继续向下执行,把元素添加到集合 如果返回true,说明元素重复,不存储 */ 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; if (++size > threshold) resize(); afterNodeInsertion(evict); return null; }
HashSet集合存储元素:
要保证元素的唯一性,需要重写 hashCode() 和 equals()
(重写hashCode()方法后,会出现元素内容不同,但是其哈希值相同的情况)
6、常见数据结构之哈希表
哈希表
JDK8之前,底层采用数组 + 链表实现,可以说是一个元素为链表的数组
JDK8后,在长度比较长的时候,底层实现了优化
元素的在数组中的存储位置根据其 哈希值 % 16 来确定,对于计算结果相同的数据先比较自身与前面存储元素的哈希值,如果不同直接存储(与前面存好的元素构成链表),如果相同就比较内容,内容相同即不存,内容不同即存。
7、案例:HashSet集合存储学生对象并遍历:
package com.itheima_04; /* 定义一个简单学生类 */ public class Student { private String name; private int age; public Student(){} public Student(String name, int age){ this.name = name; this.age = age; } public void setName(String name){ this.name = name; } public String getName(){ return this.name; } public void setAge(int age){ this.age = age; } public int getAge(){ return this.age; } //重写了equals() 和 hashCode() 方法才能够判断重复元素 @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; } }
package com.itheima_04; /* 定义一个HashSet集合存储学生对象并遍历 */ import java.util.HashSet; import java.util.Iterator; public class HashSetDemo { public static void main(String[] args){ //创建HashSet对象 HashSet<Student> hashSet = new HashSet<Student>(); //创建学生对象 Student s1 = new Student("张三", 18); Student s2 = new Student("李四", 19); Student s3 = new Student("王五", 20); Student s4 = new Student("王五", 20); //添加元素 hashSet.add(s1); hashSet.add(s2); hashSet.add(s3); hashSet.add(s4); //增强for循环遍历 for(Student stu : hashSet){ System.out.println(stu.getName() + "," + stu.getAge()); } } }
8、LinkedHashSet集合概述和特点:
LinkedHashSet集合特点:
哈希表和链表实现的Set接口,具有可预测的迭代次序
由链表保证元素有序也就是说元素的存储和取出顺序是一致的
有哈希表保证元素唯一,也就是说没有重复的元素
LinkedHashSet集合练习:
存储字符串并遍历
参考代码:
package com.itheima_05; /* LinkedHashSet集合特点: 哈希表和链表实现的Set接口,具有可预测的迭代次序 由链表保证元素有序也就是说元素的存储和取出顺序是一致的(!!注意区分这并不等于排好了序) 有哈希表保证元素唯一,也就是说没有重复的元素 */ //导包 import java.util.LinkedHashSet; public class LinkedHashSetDemo { public static void main(String[] args){ //创建对象 LinkedHashSet<String> linkedHashSet = new LinkedHashSet<String>(); //添加元素 linkedHashSet.add("Set"); linkedHashSet.add("HashSet"); linkedHashSet.add("LinkedHashSet"); linkedHashSet.add("HashSet"); //遍历元素 for(String s : linkedHashSet){ System.out.println(s); } } }
9、TreeSet集合概述和特点:
TreeSet排序元素规则:
使用无参构造方法:其添加元素需要实现 Comparable<>接口,并重写了其中 compareTo() 方法才可以使用
使用有参构造方法:传入的参数就相当于排序规则,以下采用匿名内部类的形式,这个匿名内部类实现的Comparator比较器接口并重写了其中的 compare() 方法
TreeSet集合特点:
元素有序,这里的顺序不是指存储和取出的顺序,而是按照一定规则进行排序,具体排序方式取决于构造方法
TreeSet(): 根据其元素的自然排序进行排序
TreeSet(Comparator comparator): 根据指定的比较器进行排序
间接实现了Set接口,没有带索引的方法,索引不能使用普通for循环遍历
由于是Set集合,所以不包含重复元素的集合
TreeSet集合练习:
存储整数并遍历
参考代码:
package com.itheima_06; /* TreeSet集合特点: 元素有序,这里的顺序不是指存储和取出的顺序,而是按照一定规则进行排序,具体排序方式取决于构造方法 TreeSet(): 根据其元素的自然排序进行排序 TreeSet(Comparator comparator): 根据指定的比较器进行排序 间接实现了Set接口,没有带索引的方法,索引不能使用普通for循环遍历 由于是Set集合,所以不包含重复元素的集合 */ //导包 import java.util.TreeSet; public class TreeSetDemo { public static void main(String[] args) { //创建集合对象 //<>中只能存储引用类型 所以要使用基本类型对应的封装类 TreeSet<Integer> treeSet = new TreeSet<Integer>(); //无序添加Integer元素 JDK5之后可以自动装箱 手动需要使用方法valueOf()方法来实现 treeSet.add(10); treeSet.add(40); treeSet.add(30); treeSet.add(50); treeSet.add(Integer.valueOf(20)); //手动装箱 treeSet.add(Integer.valueOf(30)); //不包含重复元素 //遍历集合 for(Integer i : treeSet){ //从输出可以看出 通过无参构造方法进行了自然排序 如:0, 1, 2... System.out.println(i); } } }
10、自然排序Comparable的使用:
自然排序:即使用TreeSet集合中的无参构造方法,对于需要添加到集合中的类元素需要实现Comparable接口(那么同时也需要重写compareTo()方法),然后就能够根据我们重写的规则进行排序
存储学生对象并遍历,创建TreeSet集合使用无参构造方法
要求:
按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
结论:
用TreeSet集合存储自定义对象,无参构造方法使用的时自然排序对于元素进行排序的
自然排序,就是让元素所属的类实现Comparable接口,重写compareTo(To)方法
重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写
参考代码:
package com.itheima_07; public class Student implements Comparable<Student>{ //此类实现了Comparable<>接口 private String name; private int age; public Student(){} public Student(String name, int age){ this.name = name; this.age = age; } public void setName(String name){ this.name = name; } public String getName(){ return this.name; } public void setAge(int age){ this.age = age; } public int getAge(){ return this.age; } @Override public int compareTo(Student s){ // return 0; //返回值为0 表示这些元素都是重复的(只有一个元素) // return 1; //返回值为1 表示后一个元素比前一个元素大(排序正序) // return -1; //返回值为-1 表示后一个元素比前一个元素小(排序逆序) //按照年龄从小到大进行排序 int num = this.age - s.age; // int num = s.age - this.age; //年龄相同,按照姓名的字母顺序排序(String类实现了comparable<>接口中 重写了 compareTo方法) int result = num == 0 ? this.name.compareTo(s.name) : num; return result; } }
package com.itheima_07; /* 存储学生对象并遍历,创建TreeSet集合使用无参构造方法 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序 */ //导包 import java.util.TreeSet; public class TreeSetDemo { public static void main(String[] args){ //创建集合对象 TreeSet<Student> treeSet = new TreeSet<Student>(); //创建学生对象 Student s1 = new Student("zhangsan", 19); Student s2 = new Student("lisi", 20); Student s3 = new Student("wangwu", 21); Student s4 = new Student("zhaoliu", 22); //测试年龄相同情况下 Student s5 = new Student("kuangtu", 22); //测试相同元素 Student s6 = new Student("kuangtu", 22); //添加元素 treeSet.add(s1); treeSet.add(s2); treeSet.add(s3); treeSet.add(s4); treeSet.add(s5); treeSet.add(s6); //遍历集合 for(Student stu : treeSet){ System.out.println(stu.getName() + "," + stu.getAge()); } } }
11、比较器排序Comparator的使用:
比较器排序:即使用TreeSet集合的有参构造方法,Comparator<>接口做参数,需要传入一个它的实现类,形式可以是匿名内部类,在其中重写compareTo()方法
储存学生对象并遍历,创建TreeSet集合使用带参构造方法
要求:
按照年龄从小到大进行排序,年龄相同,按照姓名的字母顺序排序
结论:
用TreeSet集合存储自定义对象,带参构造方法使用的时比较排序对元素进行排序的
比较器排序,就是让集合构造方法接收Comparator的实现类对象,重写compare(To1, To2)方法,在这个作用域this指向的是这个匿名内部类
重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写
参考代码:
package com.itheima_08; public class Student { private String name; private int age; public Student(){} public Student(String name, int age){ this.name = name; this.age = age; } public void setName(String name) { this.name = name; } public String getName() { return name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
package com.itheima_08; /* 储存学生对象并遍历,创建TreeSet集合使用<strong>带参构造方法</strong> 要求: 按照年龄从小到大进行排序,年龄相同,按照姓名的字母顺序排序 */ //导包 import java.util.Comparator; import java.util.TreeSet; public class TreeSetDemo { public static void main(String[] args) { //创建集合对象 此处相当于传递了一个 Comparator<>接口的实现类 TreeSet<Student> treeSet = new TreeSet<Student>(new Comparator<Student>(){ @Override public int compare(Student s1, Student s2){ //使用了匿名内部类 此处this指向这个内部类 //使用自然排序时 this.age - s.age 此处变为s1 s2 int num = s1.getAge() - s2.getAge(); int result = num == 0 ? s1.getName().compareTo(s2.getName()) : num; return result; } }); //创建学生对象 Student s1 = new Student("zhangsan", 19); Student s2 = new Student("lisi", 20); Student s3 = new Student("wangwu", 21); Student s4 = new Student("zhaoliu", 22); //测试年龄相同情况下 Student s5 = new Student("kuangtu", 22); //测试相同元素 Student s6 = new Student("kuangtu", 22); //添加元素 treeSet.add(s1); treeSet.add(s2); treeSet.add(s3); treeSet.add(s4); treeSet.add(s5); treeSet.add(s6); //遍历集合 for(Student stu : treeSet){ System.out.println(stu.getName() + "," + stu.getAge()); } } }
12、案例成绩排序(要求使用TreeSet有参构造方法来实现):
package com.itheima_09; /* 定义一个简单学生类 里面包含学生姓名、语文成绩、数学成绩 */ public class Student { private String name; private double chScore; private double mathScore; public Student(){} public Student(String name, double chScore, double mathScore){ this.name = name; this.chScore = chScore; this.mathScore = mathScore; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getChScore() { return chScore; } public void setChScore(double chScore) { this.chScore = chScore; } public double getMathScore() { return mathScore; } public void setMathScore(double mathScore) { this.mathScore = mathScore; } }
package com.itheima_09; /* 使用TreeSet的 有参构造 来进行学生成绩的排序 需求: 按照总分从高到低出现 */ //导包 import java.util.TreeSet; import java.util.Comparator; public class TreeSetDemo { public static void main(String[] args){ //创建集合对象 TreeSet<Student> treeSet = new TreeSet<Student>(new Comparator<Student>(){ @Override public int compare(Student s1, Student s2){ int sum = (int)((s2.getChScore() + s2.getMathScore()) - (s1.getChScore() + s1.getMathScore())); //在成绩相同的情况下判断 姓名字母的自然排序 int result = sum == 0 ? s1.getName().compareTo(s2.getName()) : sum; return result; } }); //创建学生对象 Student s1 = new Student("zhangsan", 78, 79); Student s2 = new Student("lisi", 91, 99); Student s3 = new Student("wangwu", 68, 77); Student s4 = new Student("zhaoliu", 88, 78); //测试重复数据 Student s5 = new Student("zhaoliu", 88, 78); //测试成绩相同时的数据 Student s6 = new Student("kuangtu", 91, 99); //添加学生对象 treeSet.add(s1); treeSet.add(s2); treeSet.add(s3); treeSet.add(s4); treeSet.add(s5); treeSet.add(s6); //遍历学生对象 for(Student stu : treeSet){ double sum = stu.getChScore() + stu.getMathScore(); System.out.println( "姓名:" + stu.getName() + " " + "语文成绩:" + stu.getChScore() + " " + "数学成绩:" + stu.getMathScore() + " " + "总分:" + sum ); } } }
13、案例:不重复随机数
需求:编写一个程序,获取10个1~20之间的随机数,要求随机数不能重复,并在控制台输出
package com.itheima_10; /* 思路: 1、创建Set集合对象 2、创建随机数对象 3、判断集合的长度是不是小于十 是,产生一个随机数,添加到元素 继续判断... 4、遍历集合 */ //导包 import java.util.Set; import java.util.HashSet; import java.util.Random; import java.util.LinkedHashSet; import java.util.TreeSet; public class SetDemo { public static void main(String[] args){ //创建Set集合对象 注意此处的元素对象是int的包装类 Integer // Set<Integer> set = new HashSet<Integer>(); //添加与输出顺序不一致 无序 // Set<Integer> set = new LinkedHashSet<Integer>(); //可以根据结果查看有效插入的顺序 //无参构造 会进行自然排序(我们需要知道 Integer能这样用 就实现了Comparable<> 并重写了compareTo()方法) Set<Integer> set = new TreeSet<Integer>(); //创建随机数对象 Random r = new Random(); //判断集合对象的长度是否小于十 while(set.size() < 10){ int number = r.nextInt(20) + 1; //1 ~ 20之间 闭区间 set.add(number); //自动装箱 } //遍历集合 for(Integer i : set){ System.out.println(i); } } }
四、泛型
1、泛型概述:
是JDK5中引入的特性,他提供了编译时类型安全检测机制,该机制允许在编译时检测到非法的类型,它的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数
一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型如何理解呢?
顾名思义,就是将类型由原来的具体的类型参数化,然后在使用/调用时传入具体的类型
简单来讲:就是将变量的数据类型 参数化 然后再根据 传入的数据类型 用来表示这个参数表示的数据类型(参考C++模板:函数模板和类模板)
这种参数类型可以用在类、方法和接口中,分别被称为 泛型类、泛型方法、泛型接口
2、泛型定义格式:
<类型>:指定一种类型的格式。这里可以看成时形参 <类型1, 类型2...>:指定多种类型的格式,多种类型之间用逗号隔开,这里的类型可以看成是形参
将来具体调用时侯给定的类型可以看成是实参,并且实参的类型只能是引用数据类型(Java)
3、泛型的好处:
把运行时异常 提前到了 编译时异常(即添加的元素类型不一致)
避免了强制类型转换(提前就确定好了元素类型)
package com.itheima_01; /* 需求:Collection集合存储字符串并遍历 得出泛型使用的好处: 把运行时异常 提前到了 编译时异常(即添加的元素类型不一致) 避免了强制类型转换(提前就确定好了元素类型) */ //导包 import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; public class GenericDemo { public static void main(String[] args){ //创建Collection集合对象 当我们没有传入类型时 默认为 Object类 类型 //超类 被所有类直接或者间接继承可以用于表示所有引用类型 // Collection c = new ArrayList(); Collection<String> c = new ArrayList<String>(); //添加元素 c.add("hello"); c.add("world"); c.add("java"); //在没有使用泛型时,添加类型都被视为Object类型 所以数据都能够存入 //但是如果我们又在 遍历时将Object进行了向下转型,那么程序就会隐含数据类型转换异常 // c.add(100); 添加了<>的使用后 就无法进行指明类型以外的添加 //遍历集合 // Iterator it = c.iterator(); Iterator<String> it = c.iterator(); while(it.hasNext()){ // Object o = it.next(); // System.out.println(o); //向下转型 将父类对象 转换为 子类引用 // String s = (String)it.next(); //ClassCastException String s = it.next(); System.out.println(s); } } }
4、泛型类:
泛型类的定义格式
格式:修饰符 class 类名<类型>{} 示例:public class Generic<T>{} //此处T可以是任意的合法标识符,常见的如T、E、K、V等形式的参数常用于表示泛型
参考代码:
package com.itheima_02; /* 测试类 */ public class GenericDemo { public static void main(String[] args) { Student s = new Student(); s.setName("张三"); System.out.println(s.getName()); Teacher t = new Teacher(); t.setAge(30); //只能够接收 规定好的类型 // t.setAge("30"); System.out.println(t.getAge()); System.out.println("--------"); //使用泛型类后 我们只用了一个类 就可以根据传入的类型来实现不同类型的传递 Generic<String> g = new Generic<String>(); g.setT("李四"); System.out.println(g.getT()); Generic<Integer> g2 = new Generic<Integer>(); g2.setT(10); System.out.println(g2.getT()); Generic<Boolean> g3 = new Generic<Boolean>(); g3.setT(true); System.out.println(g3.getT()); } }
5、泛型方法:
泛型方法定义格式:
格式:修饰符<类型> 返回值类型 方法名(类型 变量名){}
参考代码:
package com.itheima_03; /* 用于查看普通类、泛型类、泛型方法的区别 */ //普通类 /*public class Generic(){ public void show(String s){ System.out.println(s); } public void show(Integer i){ } public void show(Character c){ System.out.println(c); } 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.itheima_03; /* 测试类:用于测试泛型方法 */ public class GenericDemo { public static void main(String[] args){ //普通类问题:需要在类中重载多次方法 /*Generic g = new Generic(); g.show("张三"); g.show(66); g.show('A'); g.show(true);*/ //为了避免 运行时类型转换错误 使用泛型前先表明类型是个好习惯 //泛型类问题:需要每次实例化对象时都指明泛型类 /*Generic<String> g1 = new Generic<String>(); g1.show("李四"); Generic<Integer> g2 = new Generic<Integer>(); g2.show(66); Generic<Character> g3 = new Generic<Character>(); g3.show('A'); Generic<Double> g4 = new Generic<Double>(); g4.show(13.14); Generic<Boolean> g5 = new Generic<Boolean>(); g5.show(true);*/ Generic g = new Generic(); g.show("王五"); g.show('B'); g.show(88); g.show(true); g.show(13.14); g.show(13.148F); g.show(12222222222L); } }
6、泛型接口:
泛型接口的定义格式:
格式: 修饰符 interface 接口名 <类型>{} 范例: public interface Generic<T>{}
参考代码:
package com.itheima_04; /* 定义一个泛型类 */ public interface Generic <T>{ void show(T t); }
package com.itheima_04; /* 定义一个泛型类来实现泛型接口 */ public class GenericImpl<T> implements Generic<T>{ @Override public void show(T t){ System.out.println(t); } }
package com.itheima_04; /* 测试类 */ public class GenericDemo { public static void main(String[] args){ //使用多态的形式 实现泛型接口实例化对象 Generic<String> generic = new GenericImpl<String>(); generic.show("张三"); generic.show("李四"); generic.show("王五"); generic.show("赵六"); Generic<Integer> generic2 = new GenericImpl<Integer>(); generic2.show(10); generic2.show(20); generic2.show(30); Generic<Character> generic3 = new GenericImpl<Character>(); generic3.show('a'); generic3.show('b'); generic3.show('c'); } }
7、类型通配符:
为了表示各种泛型List的父类,可以使用类型通配符
类型通配符:<?>
List<?>:表示元素类型未知的list,它的元素可以匹配任何的类型
这种带通配符List仅表示它是各种泛型List的父类,并不能把元素添加到其中
如果说我们不希望List<?>是任何泛型List的父类,只希望它代表某一类泛型List的父类,可以使用类型通配符的上限
类型通配符上限:<? extends 类型>
List<? extends Number>:它表示的类型是Number或者其子类型
除了可以指定类型通配符的上限,我们也可以指定类型通配符的下限
类型通配符下限:<? super 类型>
List<? super Number>:它表示的类型是Number或者其父类型
参考代码:
package com.itheima_05; /* 为了表示各种泛型List的父类,可以使用类型通配符 类型通配符:<?> List<?>:表示元素类型未知的list,它的元素可以匹配任何的类型 这种带通配符List仅表示它是各种泛型List的父类,并不能把元素添加到其中 如果说我们不希望List<?>是任何泛型List的父类,只希望它代表某一类泛型List的父类,可以使用类型通配符的上限 类型通配符上限:<? extends 类型> List<? extends Number>:它表示的类型是Number或者其子类型 除了可以指定类型通配符的上限,我们也可以指定类型通配符的下限 类型通配符下限:<? super 类型> List<? super Number>:它表示的类型是Number或者其父类型 */ //导包 import java.util.List; import java.util.ArrayList; public class GenericDemo { public static void main(String[] args) { //类型通配符 可以匹配任何的数据类型 List<?> list = new ArrayList<Object>(); List<?> list2 = new ArrayList<Number>(); List<?> list3 = new ArrayList<Integer>(); System.out.println("--------"); //类型通配符上限:<? extends 类型> 此时限定了上限是Number // List<? extends Number> list4 = new ArrayList<Object>(); //Object是Number的父类 List<? extends Number> list5 = new ArrayList<Number>(); List<? extends Number> list6 = new ArrayList<Integer>(); // List<? extends Number> list7 = new ArrayList<Character>(); //Character不在Number的子类体系中 List<? extends Number> list8 = new ArrayList<Short>(); //类型通配符下限:<? super 类型> List<? super Number> list9 = new ArrayList<Object>(); List<? super Number> list10 = new ArrayList<Number>(); // List<? super Number> list11 = new ArrayList<Integer>(); //Integer是Number的子类 } }
8、可变参数:
可变参数又称为参数个数可变,用作方法的形参出现,那么方法参数个数就是可变的了
格式:修饰符 返回值类型 方法名(数据类型...变量名){}
范例:public static int sum(int...a){}
可变参数的注意事项
这里的变量其实是一个数组
如果一个方法有多个参数,包含可变参数可变参数要放在最后
参考代码:
package com.itheima_06; /* 测试类:测试可变参数 */ public class ArgsDemo01 { 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)); System.out.println(sum(10, 20, 30, 40, 50)); System.out.println(sum(10, 20, 30, 40, 50, 60)); } /* //注意: public static int sum(int b, int...a){ //使用可变参数需要其它参数时要写在前面 return 0; }*/ public static int sum(int...a){ //此处的a可以是任意的合法标识符 // System.out.println(a); //从输出上来看是数组 // return 0; int sum = 0; for(int i : a){ sum += i; } return sum; } // public static int sum(int a, int b){ // return a + b; // } // // public static int sum(int a, int b, int c){ // return a + b + c; // } // // public static int sum(int a, int b, int c, int d){ // return a + b + c + d; // } }
9、可变参数的使用:
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.itheima_07; /* 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) //返回一个包含任意数量元素的不可变集合 */ //导包 import java.util.Arrays; import java.util.List; import java.util.Set; public class ArgsDemo01 { public static void main(String[] args){ /* //一、public static <T> List<T> asList(T...a) //返回由指定数组支持的"固定大小"的列表 List<String> list = Arrays.asList("hello", "world", "java"); // list.add("javase"); //UnsupportedOperationException 抛出以表示不支持请求的异常 // list.remove("world"); //UnsupportedOperationException list.set(1, "javase"); //可以运行:因为修改元素不会改变列表的大小 System.out.println(list); */ /* //二、public static <E> List<E> of(E...elements) //返回包含任意数量元素的"不可变"列 List<String> list = List.of("hello", "world", "java", "world"); // list.add("javase"); //UnsupportedOperationException // list.remove("java"); //UnsupportedOperationException // list.set(1, "hello"); //UnsupportedOperationException System.out.println(list);*/ //public static <E> Set<E> of(E...elements) //返回一个包含任意数量元素的不可变集合 //IllegalArgumentException 抛出表示一种方法已经通过了非法或不正确的参数 // Set<String> set = Set.of("hello", "world", "java", "world"); //Set集合中不可以有重复元素 Set<String> set = Set.of("hello", "world", "java"); // set.add("javase"); //UnsupportedOperationException // set.remove("world"); //UnsupportedOperationException System.out.println(set); } }
五、Map
1、Map集合概述:
Interface Map<K, V> //K: 键的类型; V: 值得类型
将建映射到值得对象;不能包含重复的键;每一个键可以映射到最多一个值,例如学生的学号和姓名
键是唯一的,值不是;但是它们之间是一一对应的
2、创建Map集合的对象
多态的方式
具体的实现类HashMap
参考代码:
package com.itheima_01; /* 测试Map集合创建对象 */ //导包 import java.util.Map; import java.util.HashMap; public class MapDemo01 { public static void main(String[] args){ //创建Map集合对象 Map<String, String> map = new HashMap<String, String>(); //V put(K key, V value) 将指定的值与该映射中的指定键相关联 map.put("001", "张三"); map.put("002", "李四"); map.put("003", "王五"); map.put("003", "赵六"); //从输出结果来看,"003" 对应的原有映射被替换了 //可见put第一次传入键值是添加 第二次传入键值是修改 //输出集合对象 //HashMap中重写了 toString方法,用等号将键值与映射相连接 System.out.println(map); } }
3、Map集合的基本功能:
方法名 | 说明 |
---|---|
V put(K key, V value) | 添加元素 |
V remove(Object key) | 根据键删除 键值对 元素 |
void clear() | 移除所有的 键值对 元素 |
boolean containsKey(Object key) | 判断集合是否包含指定的键值 |
boolean containsValue(Object value) | 判断集合是否包含指定的值 |
boolean isEmpty() | 判断集合是否为空 |
int size() | 集合的长度,也就是集合中键值对的个数 |
参考代码:
package com.itheima_01; /* V put(K key, V value) 添加元素 V remove(Object key) 根据键删除 键值对 元素 void clear() 移除所有的 键值对 元素 boolean containsKey(Object key) 判断集合是否包含指定的键值 boolean containsValue(Object value) 判断集合是否包含指定的值 boolean isEmpty() 判断集合是否为空 int size() 集合的长度,也就是集合中键值对的个数 */ //导包 import java.util.Map; import java.util.HashMap; public class MapDemo02 { public static void main(String[] args){ //创建Map集合对象 Map<String, String> map = new HashMap<String, String>(); //一、V put(K key, V value) 添加元素 map.put("左", "右"); map.put("上", "下"); map.put("前", "后"); // //二、V remove(Object key) 根据键删除 键值对 元素 // String s = map.remove("前"); // System.out.println(s); //返回被删除键值对应的值 // System.out.println(map.remove("里")); //没有对应的键值返回null // //三、void clear() 移除所有的 键值对 元素 // map.clear(); 使用时要 提醒用户 // //四、boolean containsKey(Object key) 判断集合是否包含指定的键值 // System.out.println(map.containsKey("左")); // System.out.println(map.containsKey("里")); // //五、boolean containsValue(Object value) 判断集合是否包含指定的值 // System.out.println(map.containsValue("下")); // System.out.println(map.containsValue("外")); // //六、boolean isEmpty() 判断集合是否为空 // System.out.println(map.isEmpty()); // //清空后 调isEmpty()方法后返回值为true // map.clear(); // System.out.println(map.isEmpty()); //七、int size() 集合的长度,也就是集合中键值对的个数 System.out.println(map.size()); //输出集合对象 System.out.println(map); } }
4、Map集合的获取功能:
方法名 | 说明 |
---|---|
V get(Object key) | 根据键获取值 |
Set |
获取所有的键值 |
Collection |
获取所有值的集合 |
Set<Map.Entry<K, V>> entrySet() | 获取所有 键值对 对象 |
参考代码:
package com.itheima_01; /* V get(Object key) 根据键获取值 Set<K> keySet() 获取所有的键值 Collection<V> values() 获取所有值的集合 */ //导包 import java.util.Map; import java.util.HashMap; import java.util.Set; import java.util.Collection; public class MapDemo03 { public static void main(String[] args) { //创建对象 Map<String, String> map = new HashMap<String, String>(); //添加元素 map.put("左", "右"); map.put("上", "下"); map.put("前", "后"); // //一、V get(Object key) 根据键获取值 // System.out.println(map.get("左")); // System.out.println(map.get("里")); //键在集合中不存在(当键对应的值是null时也输出null) // //二、Set<K> keySet() 获取所有的键值(通过Set接口来储所有存唯一键值) // Set<String> keySet = map.keySet(); // System.out.println(keySet); // // //结合两个方法通过 加强for循环来遍历Map键值对应的值 // for(String s : keySet){ // System.out.println(map.get(s)); // } //三、Collection<V> values() 获取所有的集合 Collection<String> collection = map.values(); for(String s : collection){ System.out.println(s); } } }
5、Map集合的遍历(方式1):
获取所有键的集合,使用前面的:keySet()方法实现
遍历键的集合,获取到每一个键,使用增强for实现
每次根据键值去找值,使用get(Object key)方法实现
参考代码:
package com.itheima_02; /* 获取所有键的集合,使用前面的:keySet()方法实现 遍历键的集合,获取到每一个键,使用增强for实现 每次根据键值去找值,使用get(Object key)方法实现 */ //导包 import java.util.Map; import java.util.HashMap; import java.util.Set; public class MapDemo01 { public static void main(String[] args) { //创建集合对象 Map<String, String> map = new HashMap<String, String>(); //添加元素 map.put("上", "下"); map.put("左", "右"); map.put("前", "后"); map.put("里", "外"); //遍历Map集合 //获取所有键的集合 Set<String> keySet = map.keySet(); //遍历所有键 for(String key : keySet){ //根据键值获取每一个值 String value = map.get(key); System.out.println(value); } } }
5、Map集合的遍历(方式2):
获取所有 键值对 对象的集合:
使用Set<Map.Entry<K, V>> entrySet() 获取所有 键值对 对象的集合
遍历键值对对象的集合,得到每一个键值对对象:
使用增强for实现,得到每一个Map.Entry
根据键值对对象获取键值和值
用getKey()得到键
用getValue()的到值
参考代码:
package com.itheima_02; /* 获取所有 键值对 对象的集合: 使用Set<Map.Entry<K, V>> entrySet() 获取所有 键值对 对象的集合 遍历键值对对象的集合,得到每一个键值对对象: 使用增强for实现,得到每一个Map.Entry 根据键值对对象获取键值和值 用getKey()得到键 用getValue()的到值 */ //导包 import java.util.HashMap; import java.util.Map; import java.util.Set; public class MapDemo02 { public static void main(String[] args) { //创建集合对象 Map<String, String> map = new HashMap<String, String>(); //添加元素 map.put("上", "下"); map.put("左", "右"); map.put("前", "后"); map.put("里", "外"); //获取所有 键值对 对象的集合 Set<Map.Entry<String, String>> entrySet = map.entrySet(); //遍历键值对对象 集合中的每一个键值对对象 for(Map.Entry<String, String> me : entrySet){ String key = me.getKey(); String value = me.getValue(); System.out.println(key + "=" + value); } } }
6、案例:HashMap集合存储学生对象并遍历:
需求:键是学号(String),值是学生对象
package com.itheima_03; /* 创建一个学生对象 */ public class Student { private String name; private int age; public Student(){} public Student(String name, int age){ this.name = name; this.age = age; } public void setName(String name){ this.name = name; } public String getName(){ return this.name; } public void setAge(){ this.age = age; } public int getAge(){ return this.age; } public void show(){ System.out.println(this.getName() + "," + this.getAge()); } @Override public String toString(){ return "Student{" + "name=" + "'" + this.name + '\'' + "age=" + "'" + this.age + '\'' + "}"; } }
package com.itheima_03; /* 使用HashMap集合,键是学号(String), 值是学生对象(Student), 存储三个数据并遍历 */ //导包 import java.util.HashMap; import java.util.Set; import java.util.Map; public class HashMapDemo { public static void main(String[] args){ //创建集合对象 HashMap<String, Student> hashMap = new HashMap<String, Student>(); //创建学生对象 Student s1 = new Student("张三", 18); Student s2 = new Student("李四", 19); Student s3 = new Student("王五", 20); //添加集合元素 hashMap.put("001", s1); hashMap.put("002", s2); hashMap.put("003", s3); //遍历集合(方式一) //1、获取keySet(键值集合) Set<String> keySet = hashMap.keySet(); //2、使用加强for循环获取 每一个键值 for(String key : keySet){ Student value = hashMap.get(key); System.out.println("学号:" + key + " 姓名:" + value.getName() + " 年龄:" + value.getAge()); } System.out.println("--------"); //遍历集合(方式二) //1、获取键值对对象集合 Set<Map.Entry<String, Student>> entrySet = hashMap.entrySet(); //2、使用加强for循环获取 每一个键值对对象 for(Map.Entry<String, Student> entry : entrySet){ String key = entry.getKey(); Student value = entry.getValue(); System.out.println("学号:" + key + " 姓名:" + value.getName() + " 年龄:" + value.getAge()); } } }
7、案例:HashMap集合存储学生对象象并遍历
需求:键是学生对象(自定义类型,如何保证其唯一性),值是学生居住地址(String)
package com.itheima_04; /* 创建一个学生对象 */ public class Student { private String name; private int age; public Student(){ } public Student(String name, int age){ this.name = name; this.age = age; } public void setName(String name) { this.name = name; } public String getName() { return name; } public void setAge(int age) { this.age = age; } public int getAge() { return age; } //关键在于,使用自定义类型做key 在HashMap中为了确保其唯一性需要重写 equals() 和 hashCode() 两个方法 //底层是哈希表 @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; } }
package com.itheima_04; /* 定义一个测试类测试 */ //导包 import java.util.HashMap; import java.util.Map; import java.util.Set; public class HashMapDemo { public static void main(String[] args) { //创建集合对象 HashMap<Student, String> hashMap = new HashMap<Student,String>(); //创建学生对象 Student s1 = new Student("张三", 18); Student s2 = new Student("李四", 19); Student s3 = new Student("王五", 20); //添加集合元素 hashMap.put(s1, "重庆"); hashMap.put(s2, "北京"); hashMap.put(s3, "上海"); //遍历集合(方式一) //1、获取keySet(键值集合) Set<Student> keySet = hashMap.keySet(); //2、使用加强for循环获取 每一个键值 for(Student key : keySet){ String value = hashMap.get(key); System.out.println("姓名:" + key.getName() + " 年龄:" + key.getAge() + " 住址:" + value); } System.out.println("--------"); //遍历集合(方式二) //1、获取键值对对象集合 Set<Map.Entry<Student, String>> entrySet = hashMap.entrySet(); //2、使用加强for循环获取 每一个键值对对象 for(Map.Entry<Student, String> entry : entrySet){ Student key = entry.getKey(); String value = entry.getValue(); System.out.println("姓名:" + key.getName() + " 年龄:" + key.getAge() + " 住址:" + value); } } }
8、案例:ArrayList集合存储HashMap元素并遍历:
package com.itheima_05; /* 需求:创建一个ArrayList集合,存储三个元素,每一个元素都是HashMap,每一个HashMap的键和值都是String,并遍历 */ //导包 import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.Set; public class HashMapDemo { public static void main(String[] args){ //创建一个ArrayList集合对象 ArrayList<HashMap<String, String>> arrayList = new ArrayList<HashMap<String, String>>(); //创建HashMap对象 HashMap<String, String> hashMap1 = new HashMap<String, String>(); HashMap<String, String> hashMap2 = new HashMap<String, String>(); HashMap<String, String> hashMap3 = new HashMap<String, String>(); //添加hashMap1元素 hashMap1.put("a100", "张三"); hashMap1.put("a101", "李四"); hashMap1.put("a102", "王五"); //添加hashMap2元素 hashMap2.put("b100", "小明"); hashMap2.put("b101", "小红"); hashMap2.put("b102", "小白"); //添加hashMap3元素 hashMap3.put("c100", "天天"); hashMap3.put("c101", "友友"); hashMap3.put("c102", "蹦蹦"); //添加ArrayList对象 arrayList.add(hashMap1); arrayList.add(hashMap2); arrayList.add(hashMap3); //遍历ArrayList集合 for(int i = 0; i < arrayList.size(); i++){ //使用简单for循环进行遍历(ArrayList实现类List接口可以使用下标索引的方法) HashMap<String, String> temp = arrayList.get(i);//通过一个间接变量来接收Array集合中的值 // //遍历ArrayList中HashMap元素(方式一) // for(String key : temp.keySet()){ //通过HashMap对象中的keySet方法来获取其键值集合 // String value = temp.get(key); // if(i == 0){ // System.out.println("a校区 - " + "学号:" + key + " 姓名:" + value); // } // else if(i == 1){ // System.out.println("b校区 - " + "学号:" + key + " 姓名:" + value); // } // else if(i == 2){ // System.out.println("c校区 - " + "学号:" + key + " 姓名:" + value); // } // } //遍历ArrayList中HashMap元素(方式二) Set<Map.Entry<String, String>> set = temp.entrySet(); for(Map.Entry<String, String> entry : set){ String key = entry.getKey(); String value = entry.getValue(); if(i == 0){ System.out.println("a校区 - " + "学号:" + key + " 姓名:" + value); } else if(i == 1){ System.out.println("b校区 - " + "学号:" + key + " 姓名:" + value); } else if(i == 2){ System.out.println("c校区 - " + "学号:" + key + " 姓名:" + value); } } } } }
9、案例:HashMap集合存储ArrayList元素并遍历:
package com.itheima_06; /* 需求:创建一个HashMap集合,存储三个元素,每一个键值对元素的键是String, 值是ArrayList,每一个ArrayList的元素是String,并遍历 */ //导包 import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.Set; public class HashMapDemo { public static void main(String[] args){ //创建HashMap集合对象 HashMap<String, ArrayList<String>> hashMap = new HashMap<String, ArrayList<String>>(); //创建ArrayList集合对象 并添加元素 ArrayList<String> arrayList1 = new ArrayList<String>(); arrayList1.add("a"); arrayList1.add("b"); arrayList1.add("c"); //System.out.println(arrayList1); ArrayList<String> arrayList2 = new ArrayList<String>(); arrayList2.add("d"); arrayList2.add("e"); arrayList2.add("f"); ArrayList<String> arrayList3 = new ArrayList<String>(); arrayList3.add("g"); arrayList3.add("h"); arrayList3.add("i"); //添加HashMap集合对象 hashMap.put("前三个", arrayList1); hashMap.put("中三个", arrayList2); hashMap.put("后三个", arrayList3); // //遍历HashMap集合(方式一) // for(String key : hashMap.keySet()){ //依次从keySet集合中获取对应的键值 // ArrayList<String> value = hashMap.get(key); //更具键值获取对应 值 // // System.out.print(key + ":"); // for(int i = 0; i < value.size(); i++){ //遍历HashMap中的ArrayList值 // System.out.print(value.get(i)); // } // System.out.println(); // } //遍历HashMap集合(方式二) //获取键值对集合对象 Set<Map.Entry<String, ArrayList<String>>> entrySet = hashMap.entrySet(); //依次获取键值对对象 for(Map.Entry<String, ArrayList<String>> entry: entrySet){ //获取键值对的键值和值 String key = entry.getKey(); ArrayList<String> value = entry.getValue(); System.out.print(key + ":"); //遍历值 for(int i = 0; i < value.size(); i++){ System.out.print(value.get(i)); } System.out.println(); } } }
10、案例:统计字符串每个字符出现的次数:
可以尝试使用TreeMap的无参构造方法来实现可以进行键值自然排序
package com.itheima_07; /* 需求: 键盘录入一个字符串,要求统计字符串出现的次数 举例:键盘录入"aababcabcdabcde" 在控制台输出:"a(5)b(4)c(3)d(2)e(1)" 思路: 1、键盘录入一个字符串 2、创建HashMap集合,键是Character,值是Integer 3、遍历字符串,得到每一个字符 4、拿到的每一个字符作为键 到HashMap集合中去找对应的值,看其返回值 如果返回值是null,说明该字符在HashMap集合中不存在,就把该字符作为键,1作为值存储 如果返回值不是null,说明该字符在HashMap集合中存在,把该值加1,然后重新存储该字符和对应值 5、遍历HashMap集合,得到键和值,按要求进行拼接 6、输出结果 */ //导包 import java.util.Scanner; import java.util.HashMap; import java.util.Set; public class HashMapDemo { public static void main(String[] args){ //创建一个Scanner对象 Scanner sc = new Scanner(System.in); System.out.println("请输入一个字符串:"); String str = sc.nextLine(); //创建HashMap集合 HashMap<Character, Integer> hashMap = new HashMap<Character, Integer>(); //遍历字符串并获取对应字符 for(int i = 0; i < str.length(); i++){ Character c = str.charAt(i); //拿到对应的字符作为键值进行值的查询(自动装箱) if(hashMap.get(c) == null){ //如果结果为:null 说明集合对象中无字符为键值 value=1 hashMap.put(c, 1); } else if(hashMap.get(c) != null){ //结果不为:null 说明集合对象中存在当前字符 value++ Integer value = hashMap.get(c); value++; hashMap.put(c, value); //存在此元素 put()表示修改 } } //遍历HashMap集合 (按照题目要求输出) Set<Character> keySet = hashMap.keySet(); for(Character key : keySet){ Integer value = hashMap.get(key); System.out.print(key + "(" + value + ")"); //也可以使用StringBulider类来拼接 } System.out.println(); } }
六、Collections
1、Collections概述和使用:
Collections类的概述:
是针对集合操作的工具类
Collections类的常用方法
public static <T extends Comparable<? super T>> void sort(List<T> list); //将指定的列表按升序排序 public static void reverse(List<?> list); //反转指定列表中元素的顺序 public static void shuffle(List<?> list); //使用的默认的随机源随机排列指定的列表
参考代码:
package com.itheima_01; /* Collections类的概述: 是针对集合操作的工具类 Collections类的常用方法 public static <T extends Comparable<? super T>> void sort(List<T> list); //将指定的列表按升序排序 public static void reverse(List<?> list); //反转指定列表中元素的顺序 public static void shuffle(List<?> list); //使用的默认的随机源随机排列指定的列表 */ //导包 import java.util.ArrayList; import java.util.List; import java.util.Collections; public class CollectionsDemo { public static void main(String[] args){ //创建集合对象 List<Integer> list = new ArrayList<Integer>(); //添加元素 list.add(30); list.add(20); list.add(50); list.add(10); list.add(40); //public static <T extends Comparable<? super T>> void sort(List<T> list); //将指定的列表按升序排序 // Collections.sort(list); //public static void reverse(List<?> list); //反转指定列表中元素的顺序 // Collections.reverse(list); //public static void shuffle(List<?> list); //使用的默认的随机源随机排列指定的列表 Collections.shuffle(list); //常用于洗牌 System.out.println(list); } }
2、案例:ArrayList存储学生对象并遍历:
需求:ArrayList存储学生对象,使用Collections对ArrayList进行排序,要求按年龄从大到小排序,年龄相同时按照姓名的字母顺序进行排序
package com.itheima_02; /* 定义一个简单的学生类 */ 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 void setName(String name){ this.name = name; } public String getName(){ return this.name; } public void setAge(int age){ this.age = age; } public int getAge(){ return this.age; } // @Override // public int compareTo(Student student){ // int num = this.age - student.age; // int result = num == 0 ? this.name.compareTo(student.name) : num; // return result; // } }
package com.itheima_02; /* 需求:ArrayList存储学生对象,使用Collections对ArrayList进行排序, 要求按年龄从大到小排序,年龄相同时按照姓名的字母顺序进行排序 */ //导包 import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Comparator; public class ArrayListDemo { public static void main(String[] args){ //创建Arraylist集合对象 ArrayList<Student> arrayList = new ArrayList<Student>(); //创建学生对象 Student s1 = new Student("zhangsan", 18); Student s2 = new Student("lisi", 19); Student s3 = new Student("wangwu", 18); Student s4 = new Student("zhaoliu", 20); //添加学生对象到集合中 arrayList.add(s1); arrayList.add(s2); arrayList.add(s3); arrayList.add(s4); //使用Collections集合工具类对ArrayList集合进行排序 // Collections.sort(arrayList); //底层使用自然排序实现,自定义类型要重写方法 // for(int i = 0; i < arrayList.size(); i++){ // System.out.println(arrayList.get(i).getName() + "," + arrayList.get(i).getAge()); // } //使用新方法,参数含比较器 //sort(List<T> list, Comparator<? super T> c) Collections.sort(arrayList, new Comparator<Student>(){ @Override public int compare(Student s1, Student s2){ int num = s1.getAge() - s2.getAge(); int result = num == 0 ? s1.getName().compareTo(s2.getName()) : num; return result; } }); //遍历 for(int i = 0; i < arrayList.size(); i++){ System.out.println(arrayList.get(i).getName() + "," + arrayList.get(i).getAge()); } } }
3、案例:模拟斗地主:
需求:通过程序实现斗地主过程中的洗牌,发牌和看牌
思路:
创建一个牌盒,也就是定义一个集合对象,用ArrayList集合实现
往牌盒里面装牌
洗牌,也就是把牌打散,用Collections的shuffle()方法实现
发牌,也就是遍历集合,给三个玩家发牌
看牌,也就是三个玩家分别遍历自己的牌
package com.itheima_03; /* 创建一个牌盒,也就是定义一个集合对象,用ArrayList集合实现 往牌盒里面装牌 洗牌,也就是把牌打散,用Collections的shuffle()方法实现 发牌,也就是遍历集合,给三个玩家发牌 看牌,也就是三个玩家分别遍历自己的牌 */ //导包 import java.util.ArrayList; import java.util.Collections; public class PokerDemo { public static void main(String[] args) { //创建一个牌盒 ArrayList<String> array = new ArrayList<String>(); //创建花色数组 此处花色用中文表示 String[] colors = {"方块", "梅花", "红桃", "黑桃"}; String[] numbers = {"2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"}; //往牌盒里面装牌 for(String color : colors){ for(String number : numbers){ array.add(color + number); } } array.add("小王"); array.add("大王"); //洗牌,也就是把牌打散,用Collections的shuffle()方法实现 Collections.shuffle(array); System.out.println("查看牌序:" + array); //发牌 ArrayList<String> player1 = new ArrayList<String>(); ArrayList<String> player2 = new ArrayList<String>(); ArrayList<String> player3 = new ArrayList<String>(); ArrayList<String> bottom = new ArrayList<String>(); /*for(int i = 0; i < array.size() - 5; i+=3){//可见下标 % 3 == 0 player1.add(array.get(i)); } for(int i = 1; i < array.size() - 4; i+=3){//可见下标 % 3 == 1 player2.add(array.get(i)); } for(int i = 2; i < array.size() - 3; i+=3){// 可见下标 % 3 == 2 player3.add(array.get(i)); } for(int i = 0; i < 3; i++){ Collections.reverse(array); bottom.add(array.get(i)); }*/ //优化后 for(int i = 0; i < array.size(); i++){ String s = array.get(i); if(i >= array.size() - 3){ bottom.add(s); } else if(i % 3 == 0){ player1.add(s); } else if(i % 3 == 1){ player2.add(s); } else if(i % 3 == 2){ player3.add(s); } } //看牌 System.out.println("玩家一:" + player1); System.out.println("玩家二:" + player2); System.out.println("玩家三:" + player3); System.out.println("底牌:" + bottom); } }
4、案例:模拟斗地主升级版:
需求:通过程序实现斗地主过程中的洗牌,发牌和看牌。要求:对牌进行排序
package com.itheima_03; /* 需求:通过程序实现斗地主过程中的洗牌,发牌和看牌。要求:对牌进行排序 */ //导包 import java.util.HashMap; import java.util.ArrayList; import java.util.Set; import java.util.Collections; import java.util.TreeSet; public class PokerDemo02 { public static void main(String[] args){ //创建HashMap集合对象 HashMap<Integer, String> hashMap = new HashMap<Integer, String>(); ArrayList<Integer> keyList = new ArrayList<Integer>(); //将牌存入牌盒 String[] colors = {"方块", "梅花", "红桃", "黑桃"}; String[] numbers = {"2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"}; int index = 0; for(String number : numbers){ //使用点数去匹配花色,使得相同点数的下标索引相近 for(String color : colors){ hashMap.put(index, color + number); index++; } } hashMap.put(index++, "大王"); hashMap.put(index++, "小王"); //使用ArrayList集合存储键值进行洗牌 //获取键值集合 Set<Integer> keySet = hashMap.keySet(); for(Integer key : keySet){ keyList.add(key); } //洗牌 Collections.shuffle(keyList); //发牌并齐牌 TreeSet<Integer> player1 = new TreeSet<Integer>(); TreeSet<Integer> player2 = new TreeSet<Integer>(); TreeSet<Integer> player3 = new TreeSet<Integer>(); TreeSet<Integer> bottom = new TreeSet<Integer>(); for(int i = 0; i < keyList.size(); i++){ //遍历集合 if(i >= keyList.size()-3){ bottom.add(keyList.get(i)); } else if(i % 3 == 0){ player1.add(keyList.get(i)); } else if(i % 3 == 1){ player2.add(keyList.get(i)); } else if(i % 3 == 2){ player3.add(keyList.get(i)); } } //看牌 System.out.print("玩家一:"); lookPoker(player1, hashMap); System.out.print("玩家二:"); lookPoker(player2, hashMap); System.out.print("玩家三:"); lookPoker(player3, hashMap); System.out.print("底牌:"); lookPoker(bottom, hashMap); } //定义一个通过键值看牌的方法 public static void lookPoker(TreeSet<Integer> t, HashMap<Integer, String> hashMap){ int flag = 0; System.out.print("["); for(Integer i : t){ flag++; if(flag != t.size()){ System.out.print(hashMap.get(i) + ","); } else if (flag == t.size()){ System.out.print(hashMap.get(i)); } } System.out.println("]"); } }
本文作者:编程初学者求大佬指点
本文链接:https://www.cnblogs.com/fragmentary/p/16808129.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步