Java集合与泛型(黑马程序员)
1、Collection
1.1、集合知识回顾
集合类的特点:提供一种存储空间可变的存储模型,存储的数量容器会随时发生改变
1.2、集合类体系结构
1.3、Collection集合概述和使用
Collection集合概述
- 是单例集合的顶层接口,它表示一组对象,这些对象也称为Collection的元素
- JDK不提供此接口的任何直接实现,它提供更具体的子接口(如Set和List)实现
创建Collection集合的对象
- 多态的方式
- 具体的实现类ArraryList
import java.util.ArrayList;
import java.util.Collection;
public class CollectionDemo1 {
public static void main(String[] args) {
//创建collection集合的对象
Collection<String> c = new ArrayList<String>();
//添加元素,boolean add(E e)
c.add("hello");
c.add("my");
c.add("dp");
//输出集合对象
System.out.println(c);//结果为[hello, my, dp]
}
}
1.4、Collection 集合常用方法
/*
Collection集合常用方法:
boolean add(E e)添加元素
boolean remove(Object o) 从集合中移除指定的元素
void clear() 清空集合中的元素
boolean contains(Object o) 判断集合中是否存在指定的元素
boolean isEmpty() 判断集合是否为空
int size() 集合的长度,也就是集合中元素的个数
*/
import java.util.ArrayList;
import java.util.Collection;
public class CollectionDemo2 {
public static void main(String[] args) {
//创建集合对象
Collection<String> c = new ArrayList<String>();
//boolean add(E e)添加元素
c.add("hello");
c.add("my");
c.add("dp");
//输出集合对象
System.out.println(c);//[hello, my, dp]
//boolean remove(Object o) 从集合中移除指定的元素
// c.remove("my");
// System.out.println(c);//[hello, dp]
//void clear() 清空集合中的元素
// c.clear();
// System.out.println(c);//[]
//boolean contains(Object o) 判断集合中是否存在指定的元素
System.out.println(c.contains("dp"));//true
System.out.println(c.contains("1"));//false
//boolean isEmpty() 判断集合是否为空
System.out.println(c.isEmpty());//false
//int size() 集合的长度,也就是集合中元素的个数
System.out.println(c.size());//3
}
}
1.5、Collection 集合的遍历
Iterator:迭代器,集合的专用遍历方式
- Iterator iterator():返回此集合中元素的迭代器,通过集合的Iiterator() 方法得到
- 迭代器是通过集合的iterator() 方法得到的,所以我们说它依赖于集合存在
Iterator中常用方法
- E next():返回迭代中的下一个元素
- boolean hasNext():如果迭代具有更多元素,则返回true
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Iterator迭代器 {
public static void main(String[] args) {
//创建集合对象
Collection<String> c = new ArrayList<String>();
//添加元素
c.add("hello");
c.add("my");
c.add("dp");
//Iterator<E> iterator():返回此集合中元素的迭代器,通过集合的Iiterator() 方法得到
Iterator<String> it = c.iterator();
//遍历
while (it.hasNext()){
String s = it.next();
System.out.println(s);
}
}
}
1.6、集合的使用步骤
2、List
2.1、List集合概述和特点
List集合概述
- 有序集合(也称为序列),用户可以精确控制列表中每个元素的插入位置。用户可以通过整数索引访问元素,并且搜索列表中的元素
- 与set集合不同,列表通常允许重复的元素
List集合特点:
- 有序:存储和取出的元素顺序一致
- 可重复 :存储的元素可以重复
/*
list集合特点
* ==有序==:存储和取出的元素顺序一致
* ==可重复== :存储的元素可以重复
*/
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ListDemo1 {
public static void main(String[] args) {
//创建集合对象
List<String> list = new ArrayList<String>();
//添加元素
list.add("hello");
list.add("my");
list.add("dp");
list.add("my");
//输出集合对象
System.out.println(list);//[hello, my, dp, my]
System.out.println("-----------");
//迭代器的方式遍历
Iterator<String> it = list.iterator();
while (it.hasNext()){
String s = it.next();
System.out.println(s);
}
}
}
2.3、List 集合特有方法
import java.util.ArrayList;
import java.util.List;
/*
list 集合特有方法:
void add(int index,E element) 在此集合中的指定位置插入指定的元素
E remove(int index) 删除指定索引处的元素,返回被删除的元素
E set(int index,E element) 修改指定索引处的元素,返回被修改的元素
E get(int index) 返回指定索引处的元素
*/
public class ListDemo2 {
public static void main(String[] args) {
//创建集合对象
List<String> list = new ArrayList<String>();
//添加元素
list.add("hello");
list.add("my");
list.add("dp");
// void add(int index,E element) 在此集合中的指定位置插入指定的元素
list.add(1,"hh");
System.out.println(list);//[hello, hh, my, dp]
// E remove(int index) 删除指定索引处的元素,返回被删除的元素
list.remove("my");
System.out.println(list);//[hello, hh, dp]
// E set(int index,E element) 修改指定索引处的元素,返回被修改的元素
list.set(1,"java");
System.out.println(list);//[hello, java, dp]
//E get(int index) 返回指定索引处的元素
System.out.println(list.get(1));//java
//用for循环来遍历
for (int i = 0; i < list.size(); i++) {
String s = list.get(i);
System.out.println(s);
}
}
}
list 存储学生对象的集合
/*
需求:创建一个存储学生对象的集合,存储3个学生对象,使用程序实现在控制台遍历该集合
思路:
1.定义学生类
2.创建list集合对象
3.创建学生对象
4.把学生添加到集合
5.遍历集合(迭代器方式,for循环方式)
*/
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ListDemo {
public static void main(String[] args) {
//创建list集合对象
List<Student> list = new ArrayList<Student>();
//创建学生对象
Student s1 = new Student("大鹏",3);
Student s2 = new Student("小明",3);
Student s3 = new Student("小红",3);
//把学生添加到集合
list.add(s1);
list.add(s2);
list.add(s3);
//迭代器方式
Iterator<Student> it = list.iterator();
while (it.hasNext()){
Student s = it.next();
System.out.println(s.getName()+","+s.getAge());
}
System.out.println("---------");
//for循环
for (int i = 0; i <list.size() ; i++) {
Student s = list.get(i);
System.out.println(s.getName()+","+s.getAge());
}
}
}
2.4、并发修改异常
/*
需求:
我有一个集合,list<String> list = new ArrayList<String>()
里面有三个元素: list.add("hello");
list.add("my");
list.add("dp");
遍历集合,得到每一个元素,看有没有“dp”这个元素,如果有,我就添加一个“java world”元素,请写代码实现
ConcurrentModificationException:当不允许这样的修改时,可以通过检测到对象的并发修改的方法来抛出此异常
*/
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ListDemo {
public static void main(String[] args) {
//创建集合对象
List<String> list = new ArrayList<String>();
//添加元素
list.add("hello");
list.add("my");
list.add("dp");
//遍历集合,得到每一个元素,看有没有“dp”这个元素,如果有,我就添加一个“java world”元素,请写代码实现
// Iterator<String> it = list.iterator();
// while (it.hasNext()){
// String s = it.next();
// if (s.equals("dp")){
// list.add("java world");
// }
// }//这样做会报错,ConcurrentModificationException
for (int i = 0; i < list.size(); i++) {
String s = list.get(i);
if (s.equals("dp")){
list.add("java world");
System.out.println(list);
}
}
}
}
2.5、ListIterator
ListIterator:列表迭代器
- 通过List集合的ListIterator()方法得到,所以说它是list集合特有的迭代器
- 用于允许程序员沿任一方向遍历列表的列表迭代器,在迭代期间修改列表,并获取列表中迭代器的当前位置
ListIterator中的常用方法
- E next():返回迭代中的下一个元素
- boolean hasNext():如果迭代具有更多元素,则返回true
- E previous():返回列表中的上一个元素
- boolean hasPrevious():如果此列表迭代器在相反方向遍历列表时具有更多元素,则返回true
- void add(E e):将指定的元素插入列表
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class ListIteratorDemo {
public static void main(String[] args) {
//创建集合对象
List<String> list = new ArrayList<String>();
//添加元素
list.add("hello");
list.add("world");
list.add("java");
// //通过list集合的listIterator()方法得到
// ListIterator<String> lit = list.listIterator();
// while (lit.hasNext()){
// String s = lit.next();
// System.out.println(s);
// }
// System.out.println("------------");
//
// while (lit.hasPrevious()){
// String s = lit.previous();
// System.out.println(s);
// }
// System.out.println("------------");
//获取列表迭代器
ListIterator<String> lit = list.listIterator();
while (lit.hasNext()){
String s = lit.next();
if (s.equals("world")){
lit.add("javaee");
}
}
System.out.println(list);//[hello, world, javaee, java]
}
}
2.6、增强for循环
增强for:简化数组和collection集合的遍历
- 实现Iterable接口的类允许其对象成为增强for语句的目标
- 它是JDK5之后出现的,其内部原理是一个Iterator迭代器
增强for的格式
- 格式
for(元素数据类型 变量名:数组或者collection集合){
//在此处使用变量即可,该变量就是元素
}
import java.util.ArrayList;
import java.util.List;
public class ForDemo {
public static void main(String[] args) {
int[] arr = {1,2,3};
for (int i:arr){
System.out.println(i);
}
System.out.println("-----");
String[] strArray = {"hello","world","java"};
for (String s:strArray){
System.out.println(s);
}
System.out.println("-----");
//创建集合对象
List<String> list = new ArrayList<String>();
//添加元素
list.add("hello");
list.add("my");
list.add("dp");
for (String s:list){
System.out.println(s);
}
System.out.println("-----");
//内部原理是一个Iterator迭代器
// for (String s:list){
// if (s.equals("my")){
// list.add("java");//报错ConcurrentModificationException,证明是Iterator迭代器
// }
// }
}
}
2.7、List 集合子类特点
List 集合常用子类:ArrayList,LinkedList
- ArrayList:底层数据结构是数组,查询快,增删慢
- LinkedList:底层数据结构是链表,查询慢,增删快
import java.util.ArrayList;
import java.util.LinkedList;
public class ListDemo2 {
public static void main(String[] args) {
//创建集合对象
ArrayList<String> array = new ArrayList<>();
array.add("hello");
array.add("world");
array.add("java");
//遍历
for (String s:array){
System.out.println(s);
}
System.out.println("------------");
LinkedList<String> linkedList = new LinkedList<>();
linkedList.add("hello");
linkedList.add("world");
linkedList.add("java");
for (String s:linkedList){
System.out.println(s);
}
}
}
3、Set
3.1、Set 集合概述和特点
Set集合特点:
- 不包含重复元素的集合
- 没有带索引的方法,所有不能使用普通for循环遍历
/*
Set集合特点:
* ==不包含重复元素==的集合
* ==没有带索引的方法==,所有不能使用普通for循环遍历
HashSet:对集合的迭代顺序不作保证
*/
import java.util.HashSet;
import java.util.Set;
public class SetDemo {
public static void main(String[] args) {
//创建集合对象
Set<String> set = new HashSet<>();
//添加元素
set.add("hello");
set.add("world");
set.add("java");
//不包含重复元素的集合
set.add("world");
//遍历
for (String s:set){
System.out.println(s);
}
}
}
3.2、哈希值
是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值
Object类中有一种方法可以获取对象的哈希值
- public int hashCode():返回对象的哈希值
对象的哈希值特点
- 同一对象多次调用hashCode()方法返回的哈希值是相同的
- 默认情况下,不同对象的哈希值是不同的,而重写hashCode()方法,可以实现让不同对象的哈希值相同
3.3、HashSet集合概述和特点
HashSet集合特点
- 底层数据结构是哈希表
- 对集合的迭代顺序不作任何保证,也就是说不保证存储和取出的元素顺序一致
- 没有带索引的方法,所有不能使用普通for循环遍历
- 由于是Set集合,所有是不包含重复元素的集合
import java.util.HashSet;
/*
HashSet集合特点
* 底层数据结构是哈希表
* 对集合的迭代顺序不作任何保证,也就是说不保证存储和取出的元素顺序一致
* 没有带索引的方法,所有不能使用普通for循环遍历
* 由于是Set集合,所有是不包含重复元素的集合
*/
public class HashSet01 {
public static void main(String[] args) {
//创建集合对象
HashSet<String> hs = new HashSet<>();
//添加元素
hs.add("hello");
hs.add("world");
hs.add("java");
hs.add("world");
//遍历
for (String s:hs){
System.out.println(s);
}
}
}
3.4、LinkedHashSet集合概述和特点
LinkedHashSet集合概述
- 哈希表和链表实现的Set接口,具有可预测的迭代次序
- 由链表保证元素有序,也就是说元素的存储和取出顺序是一致的
- 由哈希表保证元素唯一,也就是说没有重复的元素
import java.util.LinkedHashSet;
/*
LinkedHashSet集合概述:
* 哈希表和链表实现的Set接口,具有==可预测的迭代次序==
* 由链表保证元素有序,也就是说==元素的存储和取出顺序是一致的==
* 由哈希表保证元素唯一,也就是说==没有重复的元素==
*/
public class LinkedHashDemo {
public static void main(String[] args) {
//创建集合对象
LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();
//添加元素
linkedHashSet.add("hello");
linkedHashSet.add("world");
linkedHashSet.add("java");
linkedHashSet.add("world");
//遍历
for (String s:linkedHashSet){
System.out.println(s);
}
}
}
3.5、TreeSet集合概述和特点
TreeSet集合特点
-
元素有序,这里的顺序不是指存储和取出的顺序,而是按照一定的规则进行排序,具体排序方式取决于构造方法
TreeSet():根据其元素的自然排序进行排序
TreeSet(Comparator comparator):根据指定的比较器进行排序
-
没有带索引的方法,所以不能使用普通for循环遍历
-
由于是Set集合,所以不包含重复元素的集合
/*
TreeSet集合特点
* 元素有序,这里的顺序不是指存储和取出的顺序,而是按照一定的规则进行排序,具体排序方式取决于构造方法
TreeSet():根据其元素的自然排序进行排序
TreeSet(Comparator comparator):根据指定的比较器进行排序
* 没有带索引的方法,所以不能使用普通for循环遍历
* 由于是Set集合,所以不包含重复元素的集合
*/
import java.util.TreeSet;
public class TreeSetDemo<I extends Number> {
public static void main(String[] args) {
TreeSet<Integer> ts = new TreeSet<Integer>();
ts.add(10);
ts.add(50);
ts.add(30);
ts.add(40);
ts.add(80);
ts.add(30);//不包含重复元素的集合
for (Integer i : ts){
System.out.println(i);
}
}
}
3.6、自然排序Comparable的使用
- 存储学生对象并遍历,创建TreeSet集合使用无参构造器
- 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
结论:
- 用TreeSet集合存储自定义对象,无参构造方法使用的是自然排序对元素进行排序的
- 自然排序,就是让元素所属的类实现Comparable接口,重写compareTo(To)方法
- 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写
注意:
当创建TreeSet集合使用无参构造器,Student类要实现Comparable接口
import java.util.TreeSet;
public class TreeSet案例 {
public static void main(String[] args) {
//创建集合对象
TreeSet<Student> ts = new TreeSet<Student>();
//创建学生对象
Student s1 = new Student("大鹏", 25);
Student s2 = new Student("b小明", 20);
Student s3 = new Student("小红", 35);
Student s4 = new Student("小慧", 15);
Student s5 = new Student("a小刚", 20);
Student s6 = new Student("a小刚", 20);//重复不输出
//把学生添加到集合
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);
ts.add(s6);
//遍历集合
for (Student s : ts){
System.out.println(s.getName()+":"+s.getAge());
}
}
}
import java.util.Objects;
public class Student implements Comparable<Student>{
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//重写hashCode()方法,可以实现让不同对象的哈希值相同
// @Override
// public int hashCode() {
// return 0;
// }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public int compareTo(Student s){
// return 0;//重复元素,不添加
// return 1;//升序
// return -1;//降序
//按照年龄从小到大排序
int num = this.age-s.age;//this指s2,s指s1 升序
// int num = s.age - this.age;//降序
//年龄相同时,按照姓名的字母顺序排序
int num2 = num==0?this.name.compareTo(s.name):num;
return num2;
}
}
3.7、比较器排序Comparator的使用
- 存储学生对象并遍历,创建TreeSet集合使用带参构造方法
- 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
import java.util.Comparator;
import java.util.TreeSet;
public class TreeSet案例 {
public static void main(String[] args) {
//创建集合对象
TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
//this.age - s.age
//s1,s2
int num = s1.getAge() - s2.getAge();//升序
// int num = s2.getAge() - s1.getAge();//降序
int num2 = num == 0? s1.getName().compareTo(s2.getName()):num;
return num2;
}
});
//创建学生对象
Student s1 = new Student("大鹏", 25);
Student s2 = new Student("b小明", 20);
Student s3 = new Student("小红", 35);
Student s4 = new Student("小慧", 15);
Student s5 = new Student("a小刚", 20);
Student s6 = new Student("a小刚", 20);//重复不输出
//把学生添加到集合
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);
ts.add(s6);
//遍历集合
for (Student s : ts){
System.out.println(s.getName()+":"+s.getAge());
}
}
}
public class Student{
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
3.8、案例:成绩排序
/*
需求:
用TreeSet集合存储多个学生信息(姓名,语文成绩,数学成绩),并遍历该集合
要求:按照总分从高到底出现
思路:
1.定义学生类
2.创建TreeSet集合对象,通过比较器排序进行排序
3.创建学生对象
4.把学生对象添加到集合
5.遍历集合
*/
import java.util.Comparator;
import java.util.TreeSet;
public class TreeSetDemo {
public static void main(String[] args) {
//创建TreeSet集合对象,通过比较器排序进行排序
TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
int num = s2.getSum() - s1.getSum();
int num2 = num ==0?s1.getChinese()-s2.getChinese():num;
int num3 = num2 ==0?s1.getName().compareTo(s2.getName()):num2;
return num3;
}
});
//创建学生对象
Student s1 = new Student("王杰", 90, 98);
Student s2 = new Student("林俊杰", 98, 96);
Student s3 = new Student("周杰伦", 96, 80);
Student s4 = new Student("鲲远", 100, 100);
Student s5 = new Student("旭凤", 95, 95);
Student s6 = new Student("锦觅", 96, 94);
Student s7 = new Student("润玉", 96, 94);
//把学生对象添加到集合
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);
ts.add(s6);
ts.add(s7);
//遍历集合
for (Student s:ts){
System.out.println(s.getName() +",语文成绩:"+s.getChinese()+",数学成绩:"+s.getMath()+",总分:"+s.getSum());
}
}
}
public class Student {
private String name;
private int chinese;
private int math;
public Student() {
}
public Student(String name, int chinese, int math) {
this.name = name;
this.chinese = chinese;
this.math = math;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getChinese() {
return chinese;
}
public void setChinese(int chinese) {
this.chinese = chinese;
}
public int getMath() {
return math;
}
public void setMath(int math) {
this.math = math;
}
public int getSum(){
return this.chinese+this.math;
}
}
4、泛型
4.1、泛型概述
本质:参数化类型 ----将类型由原来的具体的类型参数化,然后在使用/调用时传入具体的类型
泛型定义格式:
- <类型>:指定一种类型的格式。这里的类型可以看成是形参
- <类型1,类型2…>:指定多种类型的格式,多种类型之间用逗号隔开。这里的类型可以看成是形参
- 将来具体调用时候给定的类型可以看成是实参,并且实参的类型只能是引用数据类型
泛型的好处:
- 把运行期间的问题提前到编译期间,更加严谨
- 避免了强制类型转换
4.2、泛型类
定义格式:
- 格式:修饰符 class 类名 <类型> { }
- 范例:public class Generic{ }
- 此处 T 可以随便写为任意标识,常见的如T、E、K、v 等形式的参数常用于表示泛型
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);
System.out.println(t.getAge());
Generic<String> g1 = new Generic<String>();
g1.setT("林青霞");
System.out.println(g1.getT());
Generic<Integer> g2 = new Generic<>();
g2.setT(30);
System.out.println(g2.getT());
Generic<Boolean> g3 = new Generic<Boolean>();
g3.setT(true);
System.out.println(g3.getT());
}
}
public class Student {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Teacher {
private Integer age;
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
public class Generic<T> {
private T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
4.3、泛型方法
定义格式:
- 格式:修饰符 <类型> 返回型类型 方法名(类型 变量名){ }
- 范例:public void show(T t){ }
public class GenericDemo {
public static void main(String[] args) {
// Generic g = new Generic();
// g.show("林青霞");
// g.show(30);
// g.show(true);
//泛型类改进
// Generic<String> g1 = new Generic<String>();
// g1.show("张杰");
//
// Generic<Integer> g2 = new Generic<Integer>();
// g2.show(25);
//
// Generic<Boolean> g3 = new Generic<Boolean>();
// g3.show(true);
泛型方法改进
Generic g = new Generic();
g.show("张杰");
g.show(30);
g.show(false);
}
}
//public class Generic {
// public void show(String s){
// System.out.println(s);
// }
//
// public void show(Integer i){
// System.out.println(i);
// }
//
// public void show(Boolean b){
// System.out.println(b);
// }
//}
泛型类改进
//public class Generic<T>{
// public void show(T t){
// System.out.println(t);
// }
//}
//泛型方法改进
public class Generic{
public <T> void show(T t){
System.out.println(t);
}
}
4.4、泛型接口
定义格式:
- 格式:修饰符 interface 接口名<类型>{ }
- 范例:public interface Generic{ }
public class GenericDemo {
public static void main(String[] args) {
Generic<String> g1 = new GenericImpl<String>();
g1.show("林青霞");
Generic<Integer> g2 = new GenericImpl<Integer>();
g2.show(30);
}
}
public interface Generic <T>{
void show(T t);
}
public class GenericImpl <T> implements Generic<T>{
@Override
public void show(T t) {
System.out.println(t);
}
}
4.5、类型通配符
为了表示各种泛型List的父类,可以使用类型通配符
- 类型通配符:< ? >
- List<?>:表示元素类型未知的List,它的元素可以匹配任何类型
- 这种带通配符的List仅表示它是各种泛型list的父类,并不能把元素添加到其中
如果说我们不希望List<?> 是任何泛型list的父类,只希望它代表某一个类泛型List的父类
- 类型通配符上限:<? extends 类型>
- List<? extends Number>:它表示的类型是Number或者其子类型
除了可以指定类型通配符的上限,我们也可以指定类型通配符的下限
- 类型通配符下限:<? super 类型>
- List<? super Number>:它表示的类型是Number或者其父类型
import java.util.ArrayList;
import java.util.List;
public class GenericDemo {
public static void main(String[] args) {
//类型通配符:< ? >
List<?> list1 = new ArrayList<Object>();
List<?> list2 = new ArrayList<Number>();
List<?> list3 = new ArrayList<Integer>();
System.out.println("---------");
//类型通配符上限:<? extends 类型> 它表示的类型是<font color='red'>Number或者其子类型</font>
// List<? extends Number> list4 = new ArrayList<Object>();//报错
List<? extends Number> list5 = new ArrayList<Number>();
List<? extends Number> list6 = new ArrayList<Integer>();
System.out.println("---------");
//类型通配符下限:<? super 类型> 它表示的类型是<font color='red'>Number或者其父类型</font>
List<? super Number> list7 = new ArrayList<Object>();
List<? super Number> list8 = new ArrayList<Number>();
// List<? super Number> list9 = new ArrayList<Integer>();//报错
}
}
4.6、可变参数
可变参数又称参数个数可变,用作方法的形参出现,那么方法参数个数就是可变的了
- 格式:修饰符 返回值类型 方法名(数据类型… 变量名){ }
- 范例:public static int sum(int… a){ }
可变参数注意事项
- 这里的变量其实是一个数组
- 如果一个方法有多个参数,包含可变参数,可变参数要放到最后
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));
}
// public static int sum(int b,int... a){
// return 0;
// }
public static int sum(int... a){
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;
// }
}
4.7、可变参数的使用
Arrays工具类中有一个静态方法:
- public staticList asList(T… a):返回由指定数组支持的固定大小的列表
- 返回的集合不能做增删改操作,可以做修改操作
List接口中有一个静态方法:
- public static List of (E… elements):返回包含任意数量元素的不可变列表
- 返回的集合不能做增删改操作
- public static List of (E… elements)能用的前提是版本要是java 9[List (Java SE 9 & JDK 9 ) (oracle.com)]
Set接口中有一个静态方法:
- public static Set of(E… elements):返回一个包含任意数量元素的不可变集合
- 在给元素的时候,不能给重复的元素
- 返回的集合不能做增删改操作,没有修改方法
import java.util.Arrays;
import java.util.List;
import java.util.Set;
public class ArgsDemo02 {
public static void main(String[] args) {
//1.public static<T>List <T> asList(T... a):返回由指定数组支持的固定大小的列表
List<String> list = Arrays.asList("hello","world","java");
// list.add("javaee");//UnsupportedOperationException
// list.remove("world");//UnsupportedOperationException
list.set(1,"javaee");
System.out.println(list); //[hello, javaee, java]
//2.public static <E> List <E> of (E... elements):返回包含任意数量元素的不可变列表
//of 用不了,版本要是java 9 才能用
// List<String> list = List.of("hello", "world", "java", "world");
// list.add("javaee");//UnsupportedOperationException
// list.remove("world");//UnsupportedOperationException
// list.set(1,"javaee");
//
// System.out.println(list);
//3.public static <E> Set <E> of(E... elements):返回一个包含任意数量元素的不可变集合
// Set<String> set = Set.of("hello", "world", "java");
// set.add("javaee");//UnsupportedOperationException
// set.remove("world");//UnsupportedOperationException
//
// System.out.println(set);
}
}
5、Map
5.1、Map集合概述和使用
Map集合概述
-
Interface Map<K,V> k:键的类型 V:值的类型
-
将键映射到值的对象;不能包含重复的键;每个键可以映射到最多一个值
-
举例:学生的学号和姓名
it01 林青霞
it02 张曼玉
it03 王祖贤
创建Map集合的对象
- 多态的方式
- 具体的实现类HashMap
import java.util.HashMap;
import java.util.Map;
public class MapDemo01 {
public static void main(String[] args) {
//创建集合对象
Map<String,String> map = new HashMap<String,String>();
//V put(K key,V value) 将指定的值与该映射中的指定键相关联
map.put("it01","林青霞");
map.put("it02","张曼玉");
map.put("it03","王祖贤");//{it02=张曼玉, it01=林青霞, it03=王祖贤}
//输出集合对象
System.out.println(map);
}
}
5.2、Map集合的基本功能
import java.util.HashMap;
import java.util.Map;
public class MapDemo02 {
public static void main(String[] args) {
//创建集合对象
Map<String,String> map = new HashMap<String,String>();
//添加元素
map.put("张无忌","赵敏");
map.put("郭靖","黄蓉");
map.put("杨过","小龙女");
System.out.println(map);//{杨过=小龙女, 郭靖=黄蓉, 张无忌=赵敏}
//根据键删除键值对元素
// System.out.println(map.remove("郭靖"));//黄蓉
// System.out.println(map.remove("郭襄"));//null
//
// System.out.println(map);//{杨过=小龙女, 张无忌=赵敏}
//移除所有的键值对元素
// map.clear();
// System.out.println(map);//{}
//判断集合是否包含指定的键
System.out.println(map.containsKey("郭靖"));
System.out.println(map.containsValue("小龙女"));
//判断集合是否为空
System.out.println(map.isEmpty());
System.out.println(map.size());
}
}
5.3、Map集合的获取功能
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MapDemo03 {
public static void main(String[] args) {
//创建集合对象
Map<String,String> map = new HashMap<String,String>();
//添加元素
map.put("张无忌","赵敏");
map.put("郭靖","黄蓉");
map.put("杨过","小龙女");
//根据键获取值
System.out.println(map.get("张无忌"));//赵敏
System.out.println(map.get("张三丰"));//null
//Set< K > keyset():获取所有键的集合
Set<String> keyset = map.keySet();
for (String key:keyset){
System.out.println(key);
}
//Collection<V> values():获取所有值的集合
Collection<String> values = map.values();
for (String value:values){
System.out.println(value);
}
}
}
5.4、Map集合的遍历(方式1)
我们刚才存储的元素都是成对出现的,所以我们把Map看成是一个夫妻对的集合
遍历的思路
- 把所有的丈夫给集中起来
- 遍历丈夫的集合,获取到每一个丈夫
- 根据丈夫去找对应的妻子
转换为Map集合中的操作:
- 获取所有键的集合,用keySet()方法实现
- 遍历键的集合,获取到每一个键,用增强for实现
- 根据键去找值,用get(Object key)方法实现
import java.util.HashMap;
import java.util.Map;
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("杨过","小龙女");
//获取所有键的集合。用keySet()方法实现
Set<String> keyset = map.keySet();
//遍历键的集合,获取到每一个键。用增强for实现
for (String key:keyset){
//根据键去找值。用get(Object key)方法实现
String value = map.get(key);
System.out.println(key+","+value);
}
}
}
5.5、Map集合的遍历(方式2)
我们刚才存储的元素都是成对出现的,所以我们把Map看成是每一个夫妻对的集合
遍历思路:
- 获取所有结婚证的集合
- 遍历结婚证的集合,得到每一个结婚证
- 根据结婚证获取丈夫和妻子
转换为Map集合中的操作
-
获取所有键值对对象的集合
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("杨过","小龙女");
//获取所有键值对对象的集合
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);
}
}
}
5.6、案例:HashMap集合存储学生对象并遍历
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class HashMapDemo {
public static void main(String[] args) {
//创建HashMap集合对象
HashMap<String, Student> hm = new HashMap<String, Student>();
//创建学生对象
Student s1 = new Student("林青霞",30);
Student s2 = new Student("张曼玉",35);
Student s3 = new Student("王祖贤",33);
//把学生添加到集合
hm.put("IT01",s1);
hm.put("IT02",s2);
hm.put("IT03",s3);
//方式1:键找值
Set<String> keySet = hm.keySet();
for (String key:keySet){
Student value = hm.get(key);
System.out.println(key+","+value.getName()+","+value.getAge());
}
//方式2:键值对对象找键和值
Set<Map.Entry<String, Student>> entrySet = hm.entrySet();
for (Map.Entry<String, Student> me:entrySet){
String key = me.getKey();
Student value = me.getValue();
System.out.println(key+","+value.getName()+","+value.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;
}
public void setAge(int age) {
this.age = age;
}
}
import java.util.HashMap;
import java.util.Set;
public class HashMapDemo02 {
public static void main(String[] args) {
//创建HashMap集合对象
HashMap<Student, String> hm = new HashMap<>();
//创建学生对象
Student s1 = new Student("林青霞",30);
Student s2 = new Student("张曼玉",35);
Student s3 = new Student("王祖贤",33);
Student s4 = new Student("王祖贤",33);
//把学生添加到集合
hm.put(s1,"西安");
hm.put(s2,"武汉");
hm.put(s3,"郑州");
hm.put(s4,"北京");//王祖贤的地点从郑州变成北京,需要重写hashCode(),equals()这两个方法,不然会出现两个王祖贤
//遍历集合
Set<Student> keySet = hm.keySet();
for (Student key:keySet){
String value = hm.get(key);
System.out.println(key.getName()+","+key.getAge()+","+value);
}
}
}
import java.util.Objects;
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
5.7、ArrayList集合存储HashMap元素并遍历
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;
public class ArrayListIncludeHashMapDemo {
public static void main(String[] args) {
//创建ArrayList集合
ArrayList<HashMap<String, String>> array = new ArrayList<HashMap<String, String>>();
//创建HashMap集合,并添加键值对元素
HashMap<String, String> hm1 = new HashMap<>();
hm1.put("孙策","大乔");
hm1.put("周瑜","小乔");
//把HashMap作为元素添加到ArraryList集合
array.add(hm1);
HashMap<String, String> hm2 = new HashMap<>();
hm2.put("郭靖","黄蓉");
hm2.put("杨过","小龙女");
//把HashMap作为元素添加到ArraryList集合
array.add(hm2);
HashMap<String, String> hm3 = new HashMap<>();
hm3.put("令狐冲","任盈盈");
hm3.put("林平之","岳灵珊");
//把HashMap作为元素添加到ArraryList集合
array.add(hm3);
//遍历ArrayList集合
for (HashMap<String, String> hm:array){
Set<String> keySet = hm.keySet();
for (String key:keySet){
String value = hm.get(key);
System.out.println(key+","+value);
}
}
}
}
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;
public class HashMapIncludeArrayListDemo {
public static void main(String[] args) {
//创建HashMap集合
HashMap<String, ArrayList<String>> hm = new HashMap<>();
//创建ArrayList集合,并添加元素
ArrayList<String> sgyy = new ArrayList<>();
sgyy.add("诸葛亮");
sgyy.add("赵云");
//把ArrayList作为元素添加到HashMap集合
hm.put("三国演义",sgyy);
ArrayList<String> xyj = new ArrayList<>();
xyj.add("唐僧");
xyj.add("孙悟空");
//把ArrayList作为元素添加到HashMap集合
hm.put("西游记",xyj);
ArrayList<String> shz = new ArrayList<>();
shz.add("武松");
shz.add("鲁智深");
//把ArrayList作为元素添加到HashMap集合
hm.put("水浒传",shz);
//遍历HashMap集合
Set<String> keySet = hm.keySet();
for (String key:keySet){
System.out.println(key);
ArrayList<String> value = hm.get(key);
for (String s:value){
System.out.println(" "+s);
}
}
}
}
6、Collections
6.1、Collections概述和使用
Collections类的概述
- 是针对集合操作的工具类
Collections类的常用方法
- public static<T extends Comparable<? super T>> void sort (List list):将指定的列表按升序排序
- public static void reverse(List<?> list):反转指定列表中元素的顺序
- public static void shuffle(List <?> list):使用默许的随机源随机排列指定的列表
import java.util.ArrayList;
import java.util.Collections;
public class CollectionsDemo {
public static void main(String[] args) {
//创建集合对象
ArrayList<Integer> list = new ArrayList<Integer>();
//添加元素
list.add(30);
list.add(10);
list.add(50);
list.add(20);
list.add(40);
//public static<T extends Comparable<? super T>> void sort (List<T> list):将指定的列表按升序排序
// Collections.sort(list);
// System.out.println(list);//[10, 20, 30, 40, 50]
//public static void reverse(List<?> list):反转指定列表中元素的顺序
// Collections.reverse(list);
// System.out.println(list);//[40, 20, 50, 10, 30]
//public static void shuffle(List <?> list):使用默许的随机源随机排列指定的列表
Collections.shuffle(list);
System.out.println(list);//[20, 30, 10, 50, 40]
}
}
6.2、案例:ArrayList存储学生对象并排序
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class CollectionsDemo02 {
public static void main(String[] args) {
ArrayList<Student> array = new ArrayList<Student>();
//创建学生对象
Student s1 = new Student("林青霞",30);
Student s2 = new Student("张曼玉",35);
Student s3 = new Student("王祖贤",33);
//把学生添加到集合
array.add(s1);
array.add(s2);
array.add(s3);
//使用Collections对ArrayList集合排序
//sort (List<T> list,Comparator<? super T> c)
Collections.sort(array, 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:array){
System.out.println(s.getName()+","+s.getAge());
}
}
}
.util.ArrayList;
import java.util.Collections;
public class CollectionsDemo {
public static void main(String[] args) {
//创建集合对象
ArrayList list = new ArrayList();
//添加元素
list.add(30);
list.add(10);
list.add(50);
list.add(20);
list.add(40);
//public static<T extends Comparable<? super T>> void sort (List<T> list):将指定的列表按升序排序
// Collections.sort(list);
// System.out.println(list);//[10, 20, 30, 40, 50]
//public static void reverse(List<?> list):反转指定列表中元素的顺序
// Collections.reverse(list);
// System.out.println(list);//[40, 20, 50, 10, 30]
//public static void shuffle(List <?> list):使用默许的随机源随机排列指定的列表
Collections.shuffle(list);
System.out.println(list);//[20, 30, 10, 50, 40]
}
}
### 6.2、案例:ArrayList存储学生对象并排序
[外链图片转存中...(img-faxCj86k-1630291556995)]
```java
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class CollectionsDemo02 {
public static void main(String[] args) {
ArrayList<Student> array = new ArrayList<Student>();
//创建学生对象
Student s1 = new Student("林青霞",30);
Student s2 = new Student("张曼玉",35);
Student s3 = new Student("王祖贤",33);
//把学生添加到集合
array.add(s1);
array.add(s2);
array.add(s3);
//使用Collections对ArrayList集合排序
//sort (List<T> list,Comparator<? super T> c)
Collections.sort(array, 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:array){
System.out.println(s.getName()+","+s.getAge());
}
}
}