带妹学Java第十三天(至Map)

重点

1.TreeSet的Comparator排序方式

TreeSet的排序方式有2种
1.自然顺序(Comparable)
2.比较器顺序(Comparator)
public TreeSet(Comparator<? super E> comparator)
使用场景:如果元素的类型是final类型,不被重写,这个时候选择Comparator排序方式
3.如果希望有相同的元素存在,在compareTo或者compare方法,返回1就行了。

public class Demo01 {
	public static void main(String[] args) {
		Set\<Integer> set = new TreeSet\<Integer>(new MyComparator());
		set.add(123);
		set.add(12);
		set.add(55);
		set.add(16);
		
		for(Integer i : set){
			System.out.println(i);
		}
		
	}
}

class MyComparator implements Comparator\<Integer>{

	@Override
	public int compare(Integer o1, Integer o2) {
		// TODO Auto-generated method stub
		return o2-o1;
	}
}

2.TreeSet排序原理总结

TreeSet的特点:
–TreeSet是用来排序的, 可以指定一个顺序, 对象存入之后会按照指定的顺序排列
–TreeSet排序方式有两种自然顺序和比较器顺序

  • 自然顺序(Comparable)

    TreeSet类的add()方法中会把存入的对象提升为Comparable类型
    调用对象的compareTo()方法和集合中的对象比较
    根据compareTo()方法返回的结果进行存储

  • 比较器顺序(Comparator)

    创建TreeSet的时候可以制定 一个Comparator
    如果传入了Comparator的子类对象, 那么TreeSet就会按照比较器中的规则比较
    add()方法内部会自动调用Comparator接口中compare()方法排序
    调用的对象是compare方法的第一个参数,集合中的对象是compare方法的第二个参数

–两种比较方式的区别
1.TreeSet构造函数什么都不传, 默认按照类中Comparable的顺序(没有就报错ClassCastException)
2.TreeSet如果传入Comparator, 就优先按照Comparator

3.Map介绍

Map是属于java.util的一个接口Map<K,V>
类型参数:
K - 映射所维护的键的类型
V - 映射值的类型
Map是将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。

Map接口和Collection接口的不同
–Map是双列的,Collection是单列的
–Map的键唯一,Collection的Set是唯一的,List不是惟一的

Map:有几个常用的子类HashMap,LinkedHashMap,TreeMap,Hashtable,Properites

4.Map的功能

a>添加功能
V put(K key,V value):添加元素。
如果键是第一次存储,就直接存储元素,返回null
如果键不是第一次存在,就用值把以前的值替换掉,返回以前的值
b>删除功能
void clear():移除所有的键值对元素
V remove(Object key):根据键删除键值对元素,并把值返回
c>判断功能
boolean containsKey(Object key):判断集合是否包含指定的键
boolean containsValue(Object value):判断集合是否包含指定的值
boolean isEmpty():判断集合是否为空
d>获取功能
V get(Object key):根据键获取值
Set<K> keySet():获取集合中所有键的集合
Collection<V> values():获取集合中所有值的集合
e>长度功能
int size():返回集合中的键值对的个数

5.HashMap使用注意事项

  • 声明HashMap时的键值可以是任意对象
  • 如果有重复的键,会把以前的替换
  • 值能为空
  • 键能为空,但这样写没什么意义
  • put方法的返回值
  • 如果键是第一次存储,就直接存储元素,返回null
  • 如果键不是第一次存在,就用值把以前的值替换掉,返回以前的值

6.Map的遍历,有两种方式

a>Map集合的遍历一(键找值)
//1.创建Map对象
Map<String,String> map = new HashMap<String,String>();
map.put(“name”, “刘三姐”);
map.put(“age”, “48”);
map.put(“gender”, “女”);
map.put(“height”, “1.62”);

//3.遍历
//3.1获取map所有键
Set\<String> keys = map.keySet();
//3.2遍历键
for(String key : keys){
	//3.3 通过key获取值
	String value =  map.get(key);
	
	//打印key&value
	System.out.println(key + " : " + value);
}

b>Map集合的遍历二(键值对对象Entry找键和值)
public static void test1() {
//1.创建Map对象
Map<String,String> map = new HashMap<String,String>();
map.put(“name”, “刘三姐”);
map.put(“age”, “48”);
map.put(“gender”, “女”);
map.put(“height”, “1.62”);

//java.util.Map.Entry
/**
 * Entry:称为键值对 对象
 * */
Set\<Entry\<String, String>> entries = map.entrySet();
//遍历
for(Entry\<String, String> entry : entries){
	String key = entry.getKey();
	String value = entry.getValue();
	System.out.println(key + " : " + value);
}

}

7.键值对对象找键和值源码分析

  1. Map.Entry理解成"键值对对象"
  2. Map.Entry是一个接口,它的实现类是HashMap$Node
  3. Map.Entry是有个key和value属性,通过get方法可以取值
  4. 遍历Entry的两种方法,通过迭代器和for增强
//1.创建Map
Map\<String,Integer> map = new HashMap\<String,Integer>();
map.put("zhangsan", 100);
map.put("lisi", 89);
map.put("wangwu", 1000);

//2.遍历
Set\<Entry\<String, Integer>> entries = map.entrySet();

//2.1通过增强for循环来遍历Set
/*for(Entry\<String, Integer> entry : entries){
	//Map.Entry 的实现类HashMap$Node 
	System.out.println(entry.getClass());
	System.out.println(entry.getKey() + "---" + entry.getValue());
}*/

//2.2 通过迭代器来遍历Set
Iterator\<Entry\<String, Integer>>  iterator = entries.iterator();
while(iterator.hasNext()){
	Entry\<String, Integer> entry = iterator.next();
	System.out.println(entry.getKey() + "---" + entry.getValue());
}

8.LinkedHashMap

LinkedHashMap是存和取的顺序是一样
HashMap是存和取的顺序不是一样
LinkedHashMap它是继承HashMap

9.TreeMap

TreeMap会对键key进行排序
TreeMap的key,如果是自定义对象话,这个对象要实现Comparable接口,
或者说在new TreeMap的时候,传一个comparator参数

public class Demo01 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub

		//案例:TreeMap集合键是Student值是String
		/**
		 * TreeMap对key进行排序
		 */
		
		test3();
	}

	//使用Comparator进行TreeMap的key排序
	public static void test3() {
		Map\<Student,String> map = new TreeMap\<Student,String>(new Comparator\<Student>() {

			@Override
			public int compare(Student o1, Student o2) {
				// TODO Auto-generated method stub
				//按名字字母的倒序排序
				int num = o2.name.compareTo(o1.name);
				num = num == 0 ? 1 : num;//同名的可以存储
				return num;
			}
		});
		map.put(new Student("banana", 18), "gz");
		map.put(new Student("cc", 18), "sz");
		map.put(new Student("apple", 18), "xg");
		map.put(new Student("cc", 28), "sz");
		
		for(Entry\<Student,String> entry :map.entrySet()){
			System.out.println(entry.getKey() + " - " + entry.getValue());
		}
	}
	//使用Comparable进行TreeMap的key排序
	public static void test2() {
		Map\<Student,String> map = new TreeMap\<Student,String>();
		map.put(new Student("banana", 18), "gz");
		map.put(new Student("cc", 18), "sz");
		map.put(new Student("apple", 18), "xg");
		map.put(new Student("cc", 28), "sz");
		
		for(Entry\<Student,String> entry :map.entrySet()){
			System.out.println(entry.getKey() + " - " + entry.getValue());
		}
	}

	public static void test1() {
		Map\<String,String> map = new TreeMap\<String,String>();
		map.put("zhangsan", "广州");
		map.put("lisi", "广西");
		map.put("wangwu", "湖南");
		map.put("zhaoliu", "湖北");
		map.put("xiaoqi", "福建");
		
		//最方便遍历方式
		//Set\<Entry\<String, String>> entries = map.entrySet();
		for(Entry\<String, String> entry : map.entrySet()){
			System.out.println(entry.getKey() + "--" + entry.getValue());
		} 
	}
}

class Student implements Comparable\<Student>{
	String name;
	int age;
	public Student(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + "]";
	}
	@Override
	public int compareTo(Student o) {
		// TODO Auto-generated method stub
		//按名字字母排序
		int num = this.name.compareTo(o.name);
		
		//同名的可以存储
		num = num == 0 ? 1 : num;
		return num;
	}
	
}

10.Collections集合工具类

Collections成员方法
public static <T> void sort(List<T> list) 排序
public static <T> int binarySearch(List<?> list,T key) 二分查找
public static <T> T max(Collection<?> coll) 取大值
public static void reverse(List<?> list) 反转
public static void shuffle(List<?> list) 打乱顺序

public class Demo01 {

	public static void main(String[] args) {
		//Collections工具类的概述和常见方法
		/**
		 * 1.Collection 与 Collections 区别
		 *   Collection是一个接口
		 *   Collections是一个类
		 * 2.Collections的作用针对集合操作 的工具类
		 * 
		 * 3.Collections成员方法
				public static <T> void sort(List<T> list) 排序
				public static <T> int binarySearch(List<?> list,T key) 二分查找
				public static <T> T max(Collection<?> coll)
				public static void reverse(List<?> list)
				public static void shuffle(List<?> list)
		 */
		
		List<Integer> list1 = new ArrayList<Integer>();
		list1.add(23);
		list1.add(2);
		list1.add(3);
		list1.add(13);
		System.out.println("list1:" + list1);
		
		//1.给list集合进行排序
		//Collections.sort(list1);
		//System.out.println("list1:" + list1);
		
		//2.二分查找
		//int index = Collections.binarySearch(list1, 13);
		//System.out.println("13在list1中的位置:" + index);
		
		//3.取最大值
		/**
		 * Collection
		 *  -List
		 *  -Set
		 */
		int max = Collections.max(list1);
		System.out.println("最大值:" + max);
		
		//4.reverse 反转
		Collections.reverse(list1);
		System.out.println("反转后的list1" + list1);
		
		//5.shuffle 打乱顺序
		Collections.shuffle(list1);
		System.out.println("打乱后的list1" + list1);
		
	}
}

11.泛型固定下边界 【? super E】

/*泛型固定下边界 ? super E

1.回顾 【? extends E】-表示泛型固定上边界
? 表示子类,E表示父类
ArrayList.addAll(Collection<? extends Person> c)

2.【? super E】 -表示泛型固定下边界
? 表示父类,E表示的是子类
ArrayList.sort(Comparator<? super Student> c)

3.【? extends E 】针对存的操作
4.【? super E】 针对取的操作*/

练习题

1.在一个集合中存储了无序并且重复的字符串,让其有序(字母顺序),而且还不能去除重复

public static void main(String[] args) {	
		Set\<String> set = new TreeSet\<String>(new Comparator\<String>() {

			@Override
			public int compare(String o1, String o2) {
				// TODO Auto-generated method stub
				int num = o1.compareTo(o2);//由小到大
				num = num==0 ? 1 : num;//保存同名元素
				return num;
			}
		});
		set.add("baa");
		set.add("dbb");
		set.add("ccc");
		set.add("ccc");
		
		System.out.println(set);
		for(String str : set){
			System.out.println(str);
		}
	}
}

2.从键盘输入接收多个整数, 直到输入quit时结束输入. 把所有输入的整数倒序排列打印

  • 掌握:
  • 1.数字的倒序实现
  • 2.把str转成int
public class Demo01 {
	public static void main(String[] args) {
		//1.创建TreeSet集合
		Set\<Integer> set = new TreeSet\<Integer>(new Comparator\<Integer>() {

			@Override
			public int compare(Integer o1, Integer o2) {
				// TODO Auto-generated method stub
				return o2 - o1;
			}
		});
		//2.接收整数存在TreeSet中
		System.out.println("请多次输入整数,直到输入quit时结束输入");
		Scanner scanner = new Scanner(System.in);
		while (true) {
			String str = scanner.next();
			if ("quit".equals(str)) {
				break;
			}
			set.add(Integer.parseInt(str));
		}
		
		//3.打印集合
		for(Integer i : set){
			System.out.println(i);
		}
	}
}

3.键盘录入学生信息按照总分排序后输出在控制台

/**
* 1.创建学生类
* 添加3个学科(语文,数学,英语)成绩属性
* 添加名字属性
* 在有参构造方法中把总分算好
* 2.把n个学生添加到TreeSet中
* angle,89,98,68
* 3.TreeSet要进行总分排序

	 * 4.键盘输入学生信息格式:【名字,89,98,68】
	 * 5.当键盘输入quit,代表学生的成绩录入完毕
	 * 
	 * 技巧:字符串有个split(",")方法
	 *      这个方法把有固定格式的字符串[angle,89,98,68]解析成数组 [angle, 89, 98, 68]
	 */
public class Demo01 {

	public static void main(String[] args) {

		//1.创建集合
		Set\<Student> set = new TreeSet\<Student>();
		
		//2.添加元素
		//2.1创建Scanner
		Scanner scanner = new Scanner(System.in);
		
		//2.2录入多个学生成绩
		
		System.out.println("请录入学生成绩,录入的格式【名字,89,98,68】");
		System.out.println("如果录入完毕,请输入quit退出");
		while(true){
			
			//2.3 获取录入学生成绩信息
			//angle,89,98,68
			String info = scanner.nextLine();
			System.out.println("info:" + info);
			
			//2.4 判断是否录入完毕
			if(info.equals("quit")){
				break;
			}
			
			//2.5 解析数据 info = "angle,89,98,68",
			//把有固定格式的字符串解析成数组 [angle, 89, 98, 68]
			String[] infos = info.split(",");
			System.out.println(Arrays.toString(infos));
			String name = infos[0];
			String chineseStr = infos[1];
			String mathStr = infos[2];
			String englishStr = infos[3];
			
			//把内容封装成学生对象
			Student stu = new Student(name, 
					Integer.parseInt(chineseStr), 
					Integer.parseInt(mathStr), 
					Integer.parseInt(englishStr));
			//System.out.println(Arrays.toString(infos));
			
			//把学生放在Set中
			set.add(stu);
		}
		
//		set.add(new Student("banana", 89, 89, 91));
//		set.add(new Student("angle", 89, 89, 90));
//		set.add(new Student("apple", 89, 89, 91));
//		set.add(new Student("king", 89, 89, 89));
//		set.add(new Student("banana", 89, 89, 91));
		
		//3.遍历集合
		for(Student stu : set){
			System.out.println(stu);
		}
	}
}

public class Student implements Comparable\<Student>{
	//1.创建学生类,添加3个学科(语文,数学,英语)成绩属性
	private String name;
	private int chinese;
	private int math;
	private int english;
	
	private int totalScore;//总分
	
	public Student() {
		super();
		// TODO Auto-generated constructor stub
	}
	/**
	 * 
	 * @param name 学生名字
	 * @param chinese 语文成绩
	 * @param math 数学成绩
	 * @param english 英语成绩
	 */
	public Student(String name, int chinese, int math, int english) {
		super();
		this.name = name;
		this.chinese = chinese;
		this.math = math;
		this.english = english;
		
		//在构造方法中把总分先算好
		this.totalScore = chinese + math + english;
	}
	@Override
	public String toString() {
		return "Student [名字=" + name + ", 语文=" + chinese + ", 数学=" + math + ", 英语=" + english
				+ ", 总分=" + totalScore + "]";
	}
	
	@Override
	public int compareTo(Student o) {
		// TODO Auto-generated method stub
		//总分排序【由大到小】
		int num = o.totalScore - this.totalScore;
		
		//如果总分一样,就按照名字排序
		num = num == 0 ? this.name.compareTo(o.name) : num;
		
		//同名的学生可能有些没法排序
		num = num == 0 ? 1 : num;
		return num;
	}
	
}

4.HashMap集合键是Student,值是String

public class Demo01 {
	public static void main(String[] args) {
/*		案例 :HashMap集合键是Student,值是String
		键是学生对象,代表每一个学生 
		值是字符串对象,代表学生归属地
		
		注意事项:
		1.打印的key是student的toString方法返回的字符串
       	2.如果key相同,会把前面的值替换掉,但是必须是同一个对象
		3.HashMap是无序的
		4.new出来的都不是相同的key,因为地址不同。如果属性一样,想替换前面对应属性一样的valus时候,需要重写equals&hashcode方法

		*/
		
		Map\<Student,String> map = new HashMap\<Student,String>();
		
		map.put(new Student("小刘", 18), "湖北");
		map.put(new Student("小胡", 18), "湖南");
		
//		Student stu = new Student("小官", 18);
//		map.put(stu, "广东");
//		map.put(stu, "广西");
		map.put(new Student("小官", 18), "广东");
		map.put(new Student("小官", 18), "广西");
		
		//System.out.println("map:" + map);
		//遍历
		Set\<Entry\<Student, String>> entries = map.entrySet();
		for(Entry\<Student, String> entry : entries){
			System.out.println(entry.getKey() + " --- " + entry.getValue());
		}
		
		
	}
}

class Student{
	String name;
	int age;
	public Student(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + "]";
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Student other = (Student) obj;
		if (age != other.age)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}
	
	
	
}

5.统计字符串中每个字符出现的次数

public static void main(String[] args) {
		String str = "aaaabbbccccc";
		
		/**
		 * Map\<Character,Integer> map = new HashMap\<Character,Integer>();
		 * map.put('a',4);
		 * map.put('b',3);
		 * map.put('c',5);
		 */
		
		//1.创建存储字符次数的Map集合
		Map\<Character,Integer> map = new HashMap\<Character,Integer>();
		
		//2.遍历字符串的每一个字符
		for(int i=0;i\<str.length();i++){
			//3.往map里添加字符出现次数(累加)
			char ch = str.charAt(i);
			//map第一次出现这个字符
			if(!map.containsKey(ch)){
				map.put(ch, 1);
			}else{
				//map如果不是第一 次出现这个字符,累加+1
				map.put(ch, map.get(ch) + 1);
			}
		}
		
		System.out.println("map:" + map);
		
		
	}

6.集合的嵌套,Map嵌套Set

/**
 * 掌握: 1.HashMap嵌套HashSet,或者说Map里嵌套Set
 *       2.集合嵌套的遍历
 *
 */
public class Demo01 {

	public static void main(String[] args) {
		//集合嵌套之HashMap嵌套HashSet
	/*	需求
		一个学校有两个班
		一个班有多个学生
		通过HashMap与HashSet来实现数据存储*/
		
		//1.创建两个班(Set)
		Set\<Student> javaClass = new HashSet\<Student>();
		javaClass.add(new Student("小贾", 28));
		javaClass.add(new Student("小牛", 18));
		
		Set\<Student> h5Class = new HashSet\<Student>();
		h5Class.add(new Student("小丽", 28));
		h5Class.add(new Student("小红", 18));
		
		//2.创建一个学校(Map)
		//Key:班级名字,Value:这个班所有学生
		
		/***
		 * HashMap嵌套HashSet,或者说Map里嵌套Set
		 */
		Map\<String,Set\<Student>> school = new HashMap\<String,Set\<Student>>();
		school.put("Java班级", javaClass);
		school.put("H5班级", h5Class);
		
		//3.遍历
		//3.1遍历学校里的班级
		for(Entry\<String,Set\<Student>> entry : school.entrySet()){
			System.out.println("班级名称:" + entry.getKey());
			
			//3.2 遍历班级里学生
			//Set\<Student> myClass = entry.getValue();
			for(Student stu : entry.getValue()){
				System.out.println(stu);
			}
		}
		
	}
}
class Student{
	String name;
	int age;
	public Student(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + "]";
	}
	
	
}

7.斗地主

  • 功能:
    * 1.准备一幅牌(54张)
    * 2.洗牌(打乱牌序) shuffle方法
    * 3.发牌(三个人)
    * 4.留三张底牌
    * 5.每个人拿到牌后,对牌进行排序
    * 6.出牌…
    *
    * 一.发牌(每个人的牌先不排序)
    * 二.发牌(每个人的牌是排序)
    方法一:
public class Demo01 {

	public static void main(String[] args) {
		//一.发牌(每个人的牌先不排序)
//		 * 1.准备一幅牌(54张) 用List<String>
		List<String> poker = new ArrayList<String>();
		//花色
		String[] colors = {"黑桃","红心","梅花","方块"};
		//牌的数字
		String[] nums = {"2","3","4","5","6","7","8","9","10","j","Q","K","A"};
		
		//遍历
		for(String color : colors){
			for(String num : nums){
				String pai = color + num;//一张牌
				poker.add(pai);
			}
		}
		
		//少两个王
		poker.add("小王");
		poker.add("大王");
		System.out.println("poker" + poker);
		 
		
//		 * 2.洗牌(打乱牌序)
		Collections.shuffle(poker);
		System.out.println("poker" + poker);
		
//		 * 3.随机留三张底牌
		List<String> dipai = new ArrayList<String>();//底牌
		Random random = new Random();
		for(int i=0;i<3;i++){
			//0~53;
			//0~52
			//0~51
			int index = random.nextInt(poker.size());
			String pai = poker.remove(index);
			dipai.add(pai);
			//System.out.println("底牌:" + pai);
		}
		
		System.out.println("底牌:" + dipai);
		
		//抽了3张底牌,还有51张牌
//		 * 4.发牌(三个人) 把每个人的牌存在List集合
		 List<String> gaojin = new ArrayList<String>();//高进
		 List<String> longwu = new ArrayList<String>();//龙五
		 List<String> me = new ArrayList<String>();//我
		 for(int i=0;i<poker.size();i++){
			 //取牌
			 String pai = poker.get(i);
			 int mod = i % 3;
			 //前3张:索引0,1,2,3
			 if(mod == 0){
				 gaojin.add(pai);
			 }else if(mod == 1){
				 longwu.add(pai);
			 }else if(mod == 2){
				 me.add(pai);
			 }
		 }

//		 * 5.每个人拿到牌后
		 System.out.println("高进:" + gaojin);
		 System.out.println("龙五:" + longwu);
		 System.out.println("我:" + me);
	}

}

方法二:(灵活的运用到了Map、Set、List的属性,发牌后有序)

public class Demo01 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//模拟斗地主
		/**
		 * 功能:
		 * 1.准备一幅牌(54张)
		 * 2.洗牌(打乱牌序)
		 * 3.发牌(三个人)
		 * 4.留三张底牌
		 * 5.每个人拿到牌后,对牌进行排序
		 * 6.出牌...
		 * 
		 * 二.发牌(每个人的牌是排序)
		 */
		
		//1.准备一幅牌(54张)
		Map<Integer,String> poker = new HashMap<Integer,String>();
		//1.1花色
		String[] colors = {"黑桃","红心","梅花","方块"};
		//1.2牌的数字
		String[] nums = {"2","3","4","5","6","7","8","9","10","J","Q","K","A"};
		
		//1.3遍历花色&数字
		int index = 0;
		//是进行花色排序
		/*for(String color : colors){
			for(String num : nums){
				String pai = color + num;
				//1.4 把索引和牌 添加到Map
				poker.put(index, pai);
				index ++;
				//System.out.println(pai);
			}
		}*/
		
		//进行数字排序
		for(String num : nums){
			for(String color : colors){
				String pai = color + num;
				//1.4 把索引和牌 添加到Map
				poker.put(index, pai);
				index ++;
				//System.out.println(pai);
			}
		}
		
		//1.5 添加大王小王
		poker.put(index, "小王");
		index++;
		poker.put(index, "大王");
		
		//1.6 遍历poker
		System.out.println("===========遍历poker=========");
		for(Entry<Integer,String> entry:poker.entrySet()){
			System.out.println(entry.getKey() + " -- " + entry.getValue());
		}
		
		//2.洗牌
		//2.1获取牌的索引
		//Set<Integer> pokerKeys =poker.keySet();
		
		//把set 转 list
		List<Integer> pokerIndexs = new ArrayList<Integer>();
		for(Integer i : poker.keySet()){
			pokerIndexs.add(i);
		}
		
		//2.2把索引打乱
		Collections.shuffle(pokerIndexs);
		System.out.println("==========打乱的牌索引==========");
		System.out.println("pokerIndexs:" + pokerIndexs);
		
		
		//3.留底牌【前三张】
		Set<Integer> dipaiIdxs = new TreeSet<Integer>();
		dipaiIdxs.add(pokerIndexs.remove(0));
		dipaiIdxs.add(pokerIndexs.remove(0));
		dipaiIdxs.add(pokerIndexs.remove(0));
		System.out.println("=========底牌索引===========");
		System.out.println("dipaiIdxs:" + dipaiIdxs);
		
		//4.发牌
		Set<Integer> gaoJinIdxs = new TreeSet<Integer>();
		Set<Integer> longWuIdxs = new TreeSet<Integer>();
		Set<Integer> meIdxs = new TreeSet<Integer>();
		for(int i = 0;i < pokerIndexs.size();i++){
			//取出扑克的索引
			int pokerIndex = pokerIndexs.get(i);
			int mod = i % 3;
			if(mod == 0){
				gaoJinIdxs.add(pokerIndex);
			}else if(mod == 1){
				longWuIdxs.add(pokerIndex);
			}else if(mod == 2){
				meIdxs.add(pokerIndex);
			}
		}
		
		//5.打印每个人扑克的索引
		System.out.println("高进:" + gaoJinIdxs);
		System.out.println("龙五:" + longWuIdxs);
		System.out.println("我:" + meIdxs);
		
		//6.看牌
		lookPoker("底牌", poker, dipaiIdxs);
		lookPoker("高进", poker, gaoJinIdxs);
		lookPoker("龙五", poker, longWuIdxs);
		lookPoker("我", poker, meIdxs);
	}
	
	//看牌
	/**
	 * 
	 * @param name 玩家的名字
	 * @param poker 完整的扑克牌
	 * @param playerPokerIndexs 玩家扑克牌的索引
	 */
	public static  void lookPoker(String name,Map<Integer,String> poker,Set<Integer> playerPokerIndexs){
		
		List<String> pokerValues = new ArrayList<String>();
		//遍历玩完的扑克牌索引
		for(Integer key :playerPokerIndexs){
			pokerValues.add(poker.get(key));
		}
		System.out.println(name + ":" + pokerValues);
	}

}

8.金融借款算法

本金
利息
利率:【1分=1%=0.01】【1厘=0.1%=0.001】

还款日期的计算【看代码】

public class FinanceUtil {
	/**
	 * 返回 还款日期列表
	 * @param date 借款日期
	 * @param borrowMonth 贷款期数
	 * @return 
	 */
	public static List<String> replyDateList(Date date,int borrowMonth ) {
		//还款日期计算
				List<String> list = new ArrayList<String>();
				//1.借款日期
				Date borrowDate = new Date();
				//2.借款期数(借几个月)
				//3.计算未来12月的还款日期
				//3.1 把借款日期的年月日算出来 yyyy-MM-dd
				SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
				String str = sdf.format(borrowDate);
				String[] s = str.split("-");//按规律截取字符串
				int y = Integer.parseInt(s[0]);
				int m = Integer.parseInt(s[1]);
				int d = Integer.parseInt(s[2]);
				/*System.out.println("年:" + y);
				System.out.println("月:" + m);
				System.out.println("日:" + d);*/
				//3.2 计算未来还款日期
				//i = 0,1,2,3,4,5,6,7,8,9,10,11
				for (int i = 0; i < borrowMonth; i++) {
					//算2月份的最大天数
					//用Calendar计算
					Calendar calendar = Calendar.getInstance();
					calendar.set(y, m+i+1, 1);
					//天数-1
					calendar.add(Calendar.DAY_OF_MONTH, -1);//错误的使用了set方法,导致天数没有31天的
					//取出日期中年月日
					int hy = calendar.get(Calendar.YEAR);
					int hm = calendar.get(Calendar.MONTH)+1;
					int hd = calendar.get(Calendar.DAY_OF_MONTH);//当月的最大天数
					//还款日默认情况下就是借款日
					int huanMoney = d;
					//借款日大于当月的最大天数
					if (d > hd) {
						huanMoney = hd;
					}
					String str2 = hy+ "-" + hm + "-" + huanMoney; 
					list.add(str2);
				}
			return list;
	}
}

  • 等额本息:每个月还的本金一样,利息递减
public class Repayment {
	
	//当月本金
	private double principal;
	//还款期数
	private int index;
	//当月利息
	private double interest;
	//还款日期
	private String date;
	public Repayment() {
		super();
		// TODO Auto-generated constructor stub
	}
	public Repayment(double principal, int index, double interest, String date) {
		super();
		this.principal = principal;
		this.index = index;
		this.interest = interest;
		this.date = date;
	}
	public double getPrincipal() {
		return principal;
	}
	public void setPrincipal(double principal) {
		this.principal = principal;
	}
	public int getIndex() {
		return index;
	}
	public void setIndex(int index) {
		this.index = index;
	}
	public double getInterest() {
		return interest;
	}
	public void setInterest(double interest) {
		this.interest = interest;
	}
	public String getDate() {
		return date;
	}
	public void setDate(String date) {
		this.date = date;
	}
	@Override
	public String toString() {
		return "Repayment [当月本金=" + principal + ", 还款期数=" + index + ", 当月利息=" + interest + ", 还款日期=" + date
				+ "]";
	}
	
}

public class Demo01 {
	public static void main(String[] args) {
		//等额本息计算(按月还款-按月算)
		/*等额本息(每月等额)还款计算:
		   1.等额本息每个月的还的本金一样,利息递减
		   2.公式:本金/12 + 剩余本金 * 月利息(1%)*/
		System.out.println("还款方式:等额本息");
		List<Repayment> list = new ArrayList<Repayment>();
		//1.借款金额
		double borrowMoney = 10000;
		System.out.println("借了:"+borrowMoney);
		//2.还款的期数
		int index = 21;
		System.out.println("借款期数:"+index);
		//3.计算每个月还款的本金
		double principal = borrowMoney / index;
		//System.out.println(principal);//小数点太多了
		principal = Double.parseDouble(String.format("%.2f", principal));//设置保留两位小数点
		//借款日期
		Date date = new Date();
		SimpleDateFormat  sdf = new SimpleDateFormat("yyyy-MM-dd");
		String s= sdf.format(date);
		//借款月利率(1分2)
		double rate = 0.012;
		System.out.println("月利率:"+rate);
		System.out.println("借款日期:"+ s);
		//小数点保留2位
		//4.计算未来12个月还款数据
		for (int i = 0; i < index; i++) {
			//4.1计算好还款日期
			//调用了我封装的方法
			List<String> list2 = FinanceUtil.replyDateList(date, index);
			String hdate = list2.get(i);//还款日期
			//4.2设置还款期数
			int hqishu = i+1;
			//4.3设置当月的本金
			double dbenjin;
			if (i < index - 1) {
				dbenjin = principal;//0-11期的应还本金
			}else {
				//最后一期本金
				dbenjin = borrowMoney - (index - 1)*principal;
				dbenjin = Double.parseDouble(String.format("%.2f", dbenjin));
			}
			//4.4设置利息
			/**
			 * 公式:利息:剩余本金 * 月利息(0.012)
			 */
			double lixi = (borrowMoney - dbenjin*i)*rate;
			lixi = Double.parseDouble(String.format("%.2f", lixi));
			//把属性封装到对象
			Repayment repayment = new Repayment(dbenjin,hqishu, lixi, hdate);
			//把对象存到集合
			list.add(repayment);
			
		}
		//5.遍历
		for(Repayment re : list){
			System.out.println(re);
		}
	}
}

等额本息

  • 先息后本:前面n个的只还利息,最后一个,利息+所有本金
public class Demo02 {
	public static void main(String[] args) {
		/*先息后本款计算:
		前11个月  本金*月利息(1%)
		最后一个月  本金 + 本金*月利息(1%)
*/
		System.out.println("还款方式:先息后本");
		List<Repayment> list = new ArrayList<Repayment>();
		//1.借款金额
		double borrowMoney = 10000;
		System.out.println("借了:"+borrowMoney);
		//2.还款的期数
		int index = 12;
		System.out.println("借款期数:"+index);
		//3.计算每个月还款的本金
		double principal = 0;
		principal = Double.parseDouble(String.format("%.2f", principal));//设置保留两位小数点
		//借款日期
		Date date = new Date();
		SimpleDateFormat  sdf = new SimpleDateFormat("yyyy-MM-dd");
		String s= sdf.format(date);
		
		//借款月利率(1分2)
		double rate = 0.012;
		System.out.println("月利率:"+rate);
		System.out.println("借款日期:"+ s);
		//小数点保留2位
		//4.计算未来12个月还款数据
		for (int i = 0; i < 12; i++) {
			//4.1计算好还款日期
			//调用了我封装的方法
			List<String> list2 = FinanceUtil.replyDateList(date, index);
			String hdate = list2.get(i);//还款日期
			//4.2设置还款期数
			int hqishu = i+1;
			//4.3设置当月的本金
			double dbenjin;
			if (i < index - 1) {
				dbenjin = principal;//0-11期的应还本金
			}else {
				//最后一期本金
				dbenjin = borrowMoney;
				dbenjin = Double.parseDouble(String.format("%.2f", dbenjin));
			}
			//4.4设置利息
			/**
			 * 公式:利息:剩余本金 * 月利息(0.012)
			 */
			double lixi = borrowMoney*rate;
			lixi = Double.parseDouble(String.format("%.2f", lixi));
			//把属性封装到对象
			Repayment repayment = new Repayment(dbenjin,hqishu, lixi, hdate);
			//把对象存到集合
			list.add(repayment);
			
		}
		//5.遍历
		for(Repayment re : list){
			System.out.println(re);
		}
	}
}

先息后本

面试题

1.HashMap和Hashtable区别

  1. Hashtable是JDK1.0版本出现的,是线程安全的,效率低,有加锁(看原码)[很少用]
  2. HashMap是JDK1.2版本出现的,是线程不安全的,效率高
  3. Hashtable不可以存储null键和null值
  4. HashMap可以存储null键和null值
public static void main(String[] args) {
		
		//hashMap对象
		HashMap<String,String> map = new HashMap<String,String>();
		map.put("name", "gyf");
		map.put(null, null);
		System.out.println(map);
		
		//Hashtable对象
		Hashtable<String,String> table = new Hashtable<String,String>();
		table.put("name", "gyf");
		table.put(null, null);//Hashtable不可以存储null键和null值
		System.out.println(table);
		

	}

总结

通过对Set、Map的学习,对集合有了更深入的认识,对排序有了更深的印象,在斗地主案例里面,灵活的运用了Map的键值对特性,存扑克牌,然后用TreeSet集合存序号,这样得到的手牌就会自动排序,得到序号后再用ArrayList集合存序号所对应的牌,然后对比数组中的Arrays工具类,集合也有自己的工具类Collectiongs.练习了金融利息算法(包括等额本息、先息后本两种还款方式),遇到了保留小数点的问题,查阅,可以用String的format("%.2f",需要保留小数点的数)转化。自己封装了这两个方法,作为工具类。以后算利息,一行代码就可以搞定!

发布了24 篇原创文章 · 获赞 4 · 访问量 613

猜你喜欢

转载自blog.csdn.net/qq_43488797/article/details/103833940