常用类,集合二
2.6 泛型
2.6.1 泛型简介
-
什么是泛型
泛型本质上是参数化类型,将类由原来的具体类型参数化,然后在使用/调用时传入具体的类型
泛型JDK5引入这种参数类型可用在类,方法和接口中,成为泛型类,泛型方法,泛型接口 -
泛型格式
- <类型>:指定一种类型的格式,可看作形参
- <类型1,类型2...>:指定多种类型的格式,用逗号隔开.
- 具体调用的时候给定的类型可看作实参,且实参只能时引用类型
-
使用泛型的好处
- 把运行时期的问题提前到了编译期间
集合里原来可以添加任意类型的引用对象,编译期间对赋值成具体类型如做了类型检查,限制了元素的类型,避免因为类型转换引起的异常 - 避免了强制类型转换
- 把运行时期的问题提前到了编译期间
2.6.2 泛型类
格式:修饰符 class 类名 <类型>{}
public class Generic
例,泛型相当于模板
public class Generic <T>{
private T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
//////////////////////////////
public class GenericDemo {
public static void main(String[] args) {
Student s = new Student();
s.setName("xiaoming");
System.out.println(s.getName());
Teacher t = new Teacher();
t.setAge(30);
System.out.println(t.getAge());
System.out.println("-------------------");
Generic<String> g1 = new Generic<String>();
g1.setT("xiaoming");
System.out.println(g1.getT());
Generic<Integer> g2 = new Generic<Integer>();
g2.setT(30);
System.out.println(g2.getT());
}
}
2.6.3 泛型方法
格式: public
例
public class Generic{
public <T> void show(T t){
System.out.println(t);
}
}
//////////
public class GenericDemo {
public static void main(String[] args) {
//相比与泛型类,传入不同的参数,不用定义不同的对象
Generic g = new Generic();
g.show(100);
g.show(true);
g.show("zhangsan");
}
}
2.6.4 泛型接口
格式: 修饰符 interface 接口名<类型>{}
public interface GenericIfc <T>{
void show(T t);
}
////////
public class GenericImpl <T> implements GenericIfc<T>{
public void show(T t) {
System.out.println(t);
}
}
///////
public class GenericDemo {
public static void main(String[] args) {
GenericIfc<String> g1 = new GenericImpl<String>();
g1.show("xiaoming");
}
}
2.6.5 类型通配符
为了表示各种泛型List的父类,可以使用类型通配符
-
类型通配符<?>
- List<?>:表示元素类型未知的List,它的元素可以匹配任何类型
- 这种带通配符的List仅表示它是各种类型List的父类,并不能把元素添加到其中
- 设置类型通配符的上限,只能是该类型或者其子类 例 List
- 限制通配符的下限,必须是类型或者其父类 例 List
//<?>
List<?> list1 = new ArrayList<Object>();
List<?> list2 = new ArrayList<Integer>();
List<?> list3 = new ArrayList<String>();
//<?extends xxx>
//List<? extends Number> list4 = new ArrayList<Object>(); error
List<? extends Number> list5 = new ArrayList<Number>();
List<? extends Number> list6 = new ArrayList<Integer>();
//<? super xxx>
//List<? super Number> list7 = new ArrayList<Integer>(); errror
List<? super Number> list7 = new ArrayList<Number>();
List<? super Number> list8 = new ArrayList<Object>();
2.6.7 可变参数
- 参数个数可变,用做方法的形参出现
- 格式: 修饰符 返回值类型 方法名(数据类型... 变量名){}
例: public static int sum(int... a){} - 变量其实是一个数组
- 如果一个方法有多个参数,包含可变参数,可变参数要放到最后
例:
public class ArgsDemo01 {
public static void main(String[] args) {
System.out.println(sum(1,2,3,4));
System.out.println(sum(11,2,3,24,87,22));
}
public static int sum(int ...a){
int sum =0;
for (int i = 0; i < a.length; i++) {
sum+=a[i];
}
return sum;
}
- 可变参数的使用
- Arrays 工具类静态方法asList:
- public static
List asList(T...a):返回由指定数组支持的固定大小的列表 - 返回的集合不能做增删操作,可以做修改操作
- public static
- Lists接口中
- public static
List of(E...elements):返回包含任意数量元素的不可变列表 - 返回的集合不能做增删改操作
- public static
- Set接口方法
- public static
Set of(E...elements):返回一个包含任意数量元素的不可变集合 - 给的元素不能重复
- 返回的集合不能做增删操作,没有修改的方法
例
- public static
List<String> list = Arrays.asList("hello", "world", "java");
// list.add("javaee"); UnsupportedOperationException
//list.remove("world");UnsupportedOperationException
list.set(1,"java33");
System.out.println(list);
List
Set
Set.of("hello","world","java","world")报错IllegalArgumentException***
2.7 Map
2.7.1 map 简介
- Interface Map<K,V> K:键的类型,V:值的类型
- 将键映射到值的对象,键具有唯一性不能重复,每一个键可以映射到最多一个值,类似学号和姓名的关系
创建Map集合对象,采用多态的方式,使用HashMap
public class MapDemo1 {
public static void main(String[] args) {
Map<String, String> map = new HashMap<String,String>();
//put(K key, V value) 将指定的值与该映射中的指定键相关联(可选操作)
map.put("001","xiaoming");
map.put("002","xiaolan");
map.put("003","xiaofang");
//第二次put已有的key,会覆盖值
map.put("003","xiaohong");
System.out.println(map);
}
}
2.7.2 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() 集合中键值对的个数
- V get(Object key) 根据键获取值
- Set
keySet() 获取所有键的集合 - Collection
values() 获取所有值的集合(值可能重复,所以返回的是Collection集合而不是Set) - Set<Map.Entry<K,V> entrySet() 获取所有键值对象的集合
2.7.3 Map集合遍历
- 方式一 转换为Map集合中的操作
- 调用keySet()方法,获取所有键的集合
- 遍历键的集合(增强for),获取每个键
- 根据键找值,用get(Object)方法实现
例:
Set<String> keySet = map.keySet();
for(String s:keySet){
System.out.println(s+" "+map.get(s));
}
- 方式二
- 获取所有键值对的对象的集合(类比做结婚证)
Set<Map.Entry<K,V> entrySet():获取键值对对象的集合 - 遍历键值对对象的集合,得到每一个键值对对象
用增强for实现,得到每一个MapEntry - 根据键值对对象获取键和值
用getKey()得到键
用getValue()得到值
例
public static void main(String[] args) {
Map<String, String> map = new HashMap<String,String>();
map.put("001","xiaoming");
map.put("002","xiaolan");
map.put("003","xiaofang");
//获取键值对对象的集合
Set<Map.Entry<String, String>> entries = map.entrySet();
for(Map.Entry<String,String> entry:entries){
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key+" "+value);
}
}
例 HashMap集合存储学生对象并遍历
需求:创建一个HashMap集合,键是学生对象(Student),值是居住地(String),存储多个键值对元素,并遍历
要求保证键的唯一性:如果学生对象的成员变量值相同,我们就认为是同一个对象
思路:
- 定义学生类
- 创建HashMap对象
- 创建学生对象
- 把学生天骄到集合
- 遍历集合
- 在学生中重写两个方法(自动生成即可)
hashCode()
equals()
package collection;
import java.util.HashMap;
import java.util.Set;
public class HashMapDemo {
public static void main(String[] args) {
HashMap<Student, String> hm = new HashMap<>();
Student s1 = new Student("xiaoming",30);
Student s2 = new Student("xiaohong",25);
Student s3 = new Student("xiaolan",18);
Student s4 = new Student("xiaolan",18);
hm.put(s1,"江苏");
hm.put(s2,"深圳");
hm.put(s3,"北京");
hm.put(s4,"上海");
Set<Student> keySet = hm.keySet();
for(Student key:keySet){
String s = hm.get(key);
System.out.println(key.getName()+","+key.getAge()+","+s);
}
}
}
///////////
package collection;
import java.util.Objects;
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student() {
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Student)) return false;
Student student = (Student) o;
return getAge() == student.getAge() && Objects.equals(getName(), student.getName());
}
@Override
public int hashCode() {
return Objects.hash(getName(), getAge());
}
}
例 ArrayList集合存储HashMap元素, 遍历时按照集合嵌套遍历
for(HashMap<String,String> hm : array){
Set<String> keySet = hm.keySet();
for (String key: keySet){
System.out.println(key+" "+hm.get(key));
}
}
例 需求:键盘录入一个字符串,要求统计字符出现的次数
如输入"aababcabcdcabcde" 控制台输出"a(5)b(4)c(3)d(2)e(1)
分析 正是键值组合,用map来写
注意 键是字符类型为Character,值是出现的次数Integer
思路:
1.键盘录入一个字符串
2.创建HashMap集合,<Character,Integer>,发现最后输出的按字母顺序输出,所以采用TreeMap
3.遍历字符串,得到每个字符
4.拿到的字符作为键到TreehMap集合中找对应的值:
返回值是null,该字符在TreeMap中不存在,就把该字符作为键,1作为值存储
如果返回不是null,说明已存在,把值加1,然后重新存储字符和对应的值
5. 遍历TreeMap集合,得到键和值,按照要求进行拼接
6. 输出结果
public class HashMapDemo {
public static void main(String[] args) {
//1.键盘录入一个字符串
Scanner sc = new Scanner(System.in);
System.out.println("please input a string");
String input = sc.next();
TreeMap<Character,Integer> tm = new TreeMap<Character,Integer>();
for(int i=0; i<input.length();i++){
Character c = input.charAt(i);
Integer value = tm.get(c);
if(value == null){
tm.put(c,1);
}else{
tm.put(c, value+1);
}
}
StringBuilder sb = new StringBuilder();
Set<Character> keys = tm.keySet();
for(Character key : keys){
sb.append(key).append("(").append(tm.get(key)).append(")");
}
System.out.println(sb);
}
}
输出结果:
please input a string
aababcabcdabcde
a(5)b(4)c(3)d(2)e(1)
2.8 Collections
- 针对集合操作的工具类
- 注意Collections带s的是类,Collection不带s的是List单列集合的接口
常用方法
- public static <T extends Comparable<?super T>> void sort(List
list) 将指定列表按照自然排序(自然排序list元素) - public static
void | sort(List list, Comparator<? super T> c) 根据指定的比较器引起的顺序对指定的列表进行排序 - public static void reverse(List<?>list) 反转指定列表中的元素顺序
- public static void shuffle(List<?>list) 使用默认的随机源随机排列执行的列表
例:
public class CollectionsDemo01 {
public static void main(String[] argv){
List<Integer> list = new ArrayList<Integer>();
list.add(20);
list.add(10);
list.add(5);
list.add(40);
list.add(30);
list.add(12);
list.add(21);
list.add(17);
System.out.println(list);
Collections.sort(list);
System.out.println(list);
Collections.reverse(list);
System.out.println(list);
Collections.shuffle(list);
System.out.println(list);
}
}
输出结果:
[20, 10, 5, 40, 30, 12, 21, 17]
[5, 10, 12, 17, 20, 21, 30, 40]
[40, 30, 21, 20, 17, 12, 10, 5]
[5, 21, 20, 17, 40, 12, 30, 10]
例: 使用ArrayList存储学生对象,使用Collections对ArrayList进行排序
要求:按年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
思路:
- 定义学生类
- 创建Arraylist集合
- 创建学生对象
- 将学生存储到ArrayList集合中
- 学生类继承comparable接口,重写compareto方法
- 使用Collection.sort方法对list进行排序
- 遍历集合
法2使用比较器排序
public class CollectionsDemo02 {
public static void main(String[] args) {
ArrayList<Student> array = new ArrayList<Student>();
Student s1 = new Student("xiaoming",32);
Student s2 = new Student("xiaohong",30);
Student s3 = new Student("xiaolan",26);
Student s4 = new Student("zhangsan",31);
Student s5 = new Student("zhangsan",32);
Student s6 = new Student("xiaomingwang",32);
array.add(s1);
array.add(s2);
array.add(s3);
array.add(s4);
array.add(s5);
array.add(s6);
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());
}
}
}
输出:
xiaohong 30
zhangsan 31
xiaoming 32
xiaomingwang 32
zhangsan 32
例 模拟斗地主
通过程序实现斗地主过程中的洗牌,发牌和看牌
思路:
1.创建一个牌盒,定义一个集合对象,用ArrayList集合实现
2.在牌盒里装牌
3.洗牌,用Collection的shuffle()方法实现
4.发牌,遍历集合,给三个玩家发牌
5.看牌,三个玩家遍历自己的牌
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("dawang");
array.add("xiaowang");
//洗牌
Collections.shuffle(array);
ArrayList<String> aArray = new ArrayList<String>();
ArrayList<String> bArray = new ArrayList<String>();
ArrayList<String> cArray = new ArrayList<String>();
ArrayList<String> dpArray = new ArrayList<String>();
//发牌
for(int i =0; i<array.size();i++){
String poker = array.get(i);
if(i>=(array.size()-3)){
dpArray.add(poker);
}else{
int flag = i%3;
if(flag ==0){
aArray.add(poker);
}else if(flag == 1){
bArray.add(poker);
}else {
cArray.add(poker);
}
}
}
//看牌 写成方法
lookPoker("linqingxia",aArray);
lookPoker("wangzuxian",bArray);
lookPoker("zhaomin",cArray);
lookPoker("dipai",dpArray);
}
public static void lookPoker(String name,ArrayList<String> list){
System.out.print(name+" pokers are ");
for(String poker: list){
System.out.print(poker+ " ");
}
System.out.println();
}
}
例 模拟斗地主升级版
通过程序实现斗地主过程中的洗牌,发牌和看牌,要求:对牌进行排序

思路:
- 创建HashMap,键是编号,值是牌
- 创建ArrayList,存储编号
- 创建花色数组和点数数组
- 从0开始往HashMap里面存编号,并存储对应的牌,同时往ArrayList例面存储编号
- 调用Collection的shuffle方法对ArrayList洗牌
- 发牌(发的也是编号),保证编号是排序的,创建TreeSet集合接收
- 定义方法看牌(遍历TreeSet集合,获取编号到HashMap里找对应的牌
- 调用看牌方法
package collections;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Set;
import java.util.TreeSet;
/*
思路:
1. 创建HashMap,键是编号,值是牌
2. 创建ArrayList,存储编号
3. 创建花色数组和点数数组
4. 从0开始往HashMap里面存编号,并存储对应的牌,同时往ArrayList例面存储编号
5. 调用Collection的shuffle方法对ArrayList洗牌
6. 发牌(发的也是编号),保证编号是排序的,创建TreeSet集合接收
7. 定义方法看牌(遍历TreeSet集合,获取编号到HashMap里找对应的牌
8. 调用看牌方法
*/
package collections;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Set;
import java.util.TreeSet;
/*
思路:
1. 创建HashMap,键是编号,值是牌
2. 创建ArrayList,存储编号
3. 创建花色数组和点数数组
4. 从0开始往HashMap里面存编号,并存储对应的牌,同时往ArrayList例面存储编号
5. 调用Collection的shuffle方法对ArrayList洗牌
6. 发牌(发的也是编号),保证编号是排序的,创建TreeSet集合接收
7. 定义方法看牌(遍历TreeSet集合,获取编号到HashMap里找对应的牌
8. 调用看牌方法
*/
```jav
public class PokerDemo1 {
public static void main(String[] args) {
HashMap<Integer, String> hm = new HashMap<Integer, String>();
ArrayList<Integer> list = new ArrayList<Integer>();
String[] colors = { "♥", "♠", "♦", "♣" };
String[] numbers = { "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q",
"K", "A", "2" };
int count = 0;
for (String number : numbers) {
for (String color : colors) {
list.add(count);
hm.put(count, color + number);
count++;
}
}
hm.put(count, "xiaowang");
list.add(count);
count++;
hm.put(count, "dawang");
list.add(count);
Collections.shuffle(list);
TreeSet<Integer> aTreeSet = new TreeSet<Integer>();
TreeSet<Integer> bTreeSet = new TreeSet<Integer>();
TreeSet<Integer> cTreeSet = new TreeSet<Integer>();
TreeSet<Integer> dpSet = new TreeSet<Integer>();
//发的是编号,用洗牌后的编号list集合发
//判断底牌用是索引,所以用普通for不是增强for
for (int i = 0; i < list.size(); i++) {
int x = list.get(i);
if (i >= list.size() - 3) {
dpSet.add(x);
} else if (i % 3 == 0) {
aTreeSet.add(x);
} else if (i % 3 == 1) {
bTreeSet.add(x);
} else {
cTreeSet.add(x);
}
}
lookPoker("xiaoming", aTreeSet, hm);
lookPoker("xiaolan", bTreeSet, hm);
lookPoker("xiaohong", cTreeSet, hm);
lookPoker("dipai", dpSet, hm);
}
public static void lookPoker(String name, TreeSet<Integer> ts,
HashMap<Integer, String> hm) {
System.out.print(name + " is looking pokers ");
for (Integer i : ts) {
System.out.print(hm.get(i) + " ");
}
System.out.println();
}
}
输出
xiaoming is looking pokers ♥3 ♠3 ♦3 ♣3 ♥4 ♦4 ♣4 ♦7 ♣8 ♥9 ♣9 ♣10 ♣J ♦K ♠A ♥2 ♣2
xiaolan is looking pokers ♥5 ♣5 ♦6 ♣6 ♥7 ♣7 ♥8 ♦8 ♦9 ♥10 ♠10 ♥K ♦A ♣A ♠2 ♦2 dawang
xiaohong is looking pokers ♠5 ♦5 ♥6 ♠6 ♠7 ♠8 ♠9 ♦10 ♥J ♦J ♥Q ♠Q ♦Q ♣Q ♠K ♥A xiaowang
dipai is looking pokers ♠4 ♠J ♣K
注: 内容是bilibili黑马程序员笔记

浙公网安备 33010602011771号