常用类,集合二

2.6 泛型

2.6.1 泛型简介

  • 什么是泛型
    泛型本质上是参数化类型,将类由原来的具体类型参数化,然后在使用/调用时传入具体的类型
    泛型JDK5引入这种参数类型可用在类,方法和接口中,成为泛型类,泛型方法,泛型接口

  • 泛型格式

    • <类型>:指定一种类型的格式,可看作形参
    • <类型1,类型2...>:指定多种类型的格式,用逗号隔开.
    • 具体调用的时候给定的类型可看作实参,且实参只能时引用类型
  • 使用泛型的好处

    • 把运行时期的问题提前到了编译期间
      集合里原来可以添加任意类型的引用对象,编译期间对赋值成具体类型如做了类型检查,限制了元素的类型,避免因为类型转换引起的异常
    • 避免了强制类型转换

2.6.2 泛型类

格式:修饰符 class 类名 <类型>{}
public class Generic {}, T为任意标识,可以换成E, K ,V
例,泛型相当于模板

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 void show(T t){}

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 可变参数

  1. 参数个数可变,用做方法的形参出现
  • 格式: 修饰符 返回值类型 方法名(数据类型... 变量名){}
    例: 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;
    }

  1. 可变参数的使用
  • Arrays 工具类静态方法asList:
    • public static List asList(T...a):返回由指定数组支持的固定大小的列表
    • 返回的集合不能做增删操作,可以做修改操作
  • Lists接口中
    • public static List of(E...elements):返回包含任意数量元素的不可变列表
    • 返回的集合不能做增删改操作
  • Set接口方法
    • public static Set of(E...elements):返回一个包含任意数量元素的不可变集合
    • 给的元素不能重复
    • 返回的集合不能做增删操作,没有修改的方法
        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 of 得到的集合增删改都不支持
Set of(E ...elements)元素不能重复
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集合中的操作
    1. 调用keySet()方法,获取所有键的集合
    2. 遍历键的集合(增强for),获取每个键
    3. 根据键找值,用get(Object)方法实现
      例:
Set<String> keySet = map.keySet();
for(String s:keySet){
    System.out.println(s+" "+map.get(s));
}
  • 方式二
  1. 获取所有键值对的对象的集合(类比做结婚证)
    Set<Map.Entry<K,V> entrySet():获取键值对对象的集合
  2. 遍历键值对对象的集合,得到每一个键值对对象
    用增强for实现,得到每一个MapEntry
  3. 根据键值对对象获取键和值
    用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),存储多个键值对元素,并遍历
要求保证键的唯一性:如果学生对象的成员变量值相同,我们就认为是同一个对象
思路:

  1. 定义学生类
  2. 创建HashMap对象
  3. 创建学生对象
  4. 把学生天骄到集合
  5. 遍历集合
  6. 在学生中重写两个方法(自动生成即可)
    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进行排序
要求:按年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
思路:

  1. 定义学生类
  2. 创建Arraylist集合
  3. 创建学生对象
  4. 将学生存储到ArrayList集合中
  5. 学生类继承comparable接口,重写compareto方法
  6. 使用Collection.sort方法对list进行排序
  7. 遍历集合
    法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();
	}

}

例 模拟斗地主升级版
通过程序实现斗地主过程中的洗牌,发牌和看牌,要求:对牌进行排序

思路:

  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. 调用看牌方法
 */
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黑马程序员笔记

posted @ 2021-04-13 11:11  晒网达人  阅读(60)  评论(0)    收藏  举报