java基础第二阶段之day5
一、集合分类
- 集合类体系结构图:
二、Collection集合
1. Collection介绍
Collection集合,它是单列集合,创建Colection集合的对象要用多太的方式(ArrarList();)
多态的方式创建Collection对象:
//Collection<E>
Collection<String> c = new ArrayList<String>();
//用Collection的 boolean add<E e> 方法往集合添加元素
c.add("hello");
c.add("world");
c.add("java");
system.out.println(c);
//此处结果为:
[hello,world,java]
可以看出,ArrayList里是自动重写了父类的toString方法的,所以输出的是[元素1,元素2,...,元素n]的格式
而不是 对象名+@+哈希值 格式(这个格式是没有重写的)。
2. Collection的常用集合方法:
boolean add(E e) 底层代码返回的返回值定义的就是ture,所以使用add永远返回的都是ture。
boolean remove(object o )移除成功返回ture,失败返回false。
void clear() 是直接清空集合里的元素,需要谨慎使用。
boolean isEmpty() 是判断集合是否为空,ture是表示为空,false是表示不为空。
3. Collection的iterator()方法
Iterator iterator()是方法是返回此集合中元素的迭代器
所以可以通过iterator()方法创建一个该集合的一个迭代器。然后通过迭代器对象对该集合的数据进行操作。
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class CollectionDemo1 {
public static void main(String[] args) {
Collection<String> c = new ArrayList<String>();
c.add("hello");
c.add("world");
c.add("java");
// System.out.println(c.remove("java")); 移除某个元素的方法
// c.clear();清空
// System.out.println(c.contains("java")); 判断集合是否有指定元素 结果:返回ture;
// System.out.println(c.isEmpty()); 判断是否为空,结果:false
// System.out.println( c.size()); 集合的大小,结果:3
System.out.println(c);
//Iterator()方法
Iterator<String> it = c.iterator();//通过集合迭代器iterator遍历对象
while (it.hasNext()){ //不用for循环遍历是因为迭代器是一个个接收数据的
String s = it.next(); //没有办法知道共有多少个元素,所以没有it的大小,也就没办法通过index遍历了
System.out.println(s); //这里是通过hasNext判断是否仍有下一个判断it的结束点。
}
}
}
这里用到了迭代器两个常用方法:
1. E next();返回迭代中的下一个元素
2. boolean hasNext();如果迭代具有更多元素,则返回ture
总结Collection集合使用步骤:
三、List集合
1. List概述和特点
代码演示:
基本功能和Collection一致,此外List还有它特有的方法:
注意:
以上所有方法都会出现索引越界异常,使用的时候注意索引在有效范围内。
删除和修改方法返回的都是未更改前索引位置的元素。
因为List可以通过访问索引来获取元素,于是要遍历List集合除了可以使用迭代器外,还可以通过for循环完成遍历。
但是注意利用迭代器进行遍历的时候不能同时对集合长度进行修改,不然会出现并发修改异常:
ConcurrentModificationException
2. 实际应用例子(并发修改异常)
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ListDemo1 {
public static void main(String[] args) {
//创建LIist对象
List<String> l = new ArrayList<>();
//添加元素
l.add("hello");
l.add("java");
l.add("javaee");
//遍历集合,遍历要求:遍历的过程如果有java,则添加一个”world“
//1.迭代器遍历(无法实现)
Iterator<String> it = l.iterator();
while (it.hasNext()){
String s = it.next();
if (s.equals("java")){
l.add("world"); //ConcurrentModificationException
//并发修改异常
} //利用迭代器遍历的时候,不可以遍历的同时改变集合的长度
System.out.println(s);
}
//2.利用索引for循环遍历
for (int i = 0; i < l.size(); i++) {
String s = l.get(i);
if (s.equals("java")){
l.add("world");
}
System.out.println(s);
}
}
}
3. List特有迭代器
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class ListIteratorDemo1 {
public static void main(String[] args) {
List<String> l = new ArrayList<>();
l.add("java");
l.add("c++");
l.add("python");
ListIterator<String> lit = l.listIterator();
while (lit.hasNext()){
String s1 = lit.next();//顺序遍历
System.out.print(s1+"\t");
}
System.out.println();
System.out.println("-------------------------");
while (lit.hasPrevious()){
String s2 = lit.previous();//逆序遍历
System.out.print(s2+"\t");
}
System.out.println();
System.out.println("-------------------------");
//利用迭代器遍历,若出现java字符串则加上PHP。
while (lit.hasNext()){
String s = lit.next();
if(s.equals("java")){
lit.add("PHP"); //注意:这个add方法是迭代器的方法,不是集合的方法
}
System.out.print(s+"\t");//此时是添加了PHP元素到列表集合但是遍历依旧不会遍历这个中途加入的。
}
System.out.println();
System.out.println(l);//此时的列表集合已经有PHP元素。
}
}
4. for-each遍历集合原理
首先回顾for-each循环遍历的基本格式:
for(元素数据类型 变量名:数组或者Collection集合){
//此处使用变量进行操作,此处的变量就是各元素;
}
Collection<String> c = new ArrayList<String>();
c.add("hello");
c.add("world");
c.add("java");
for (String s1:c) { //foreach原理其实就是通过迭代器用next方法把各个元素取出,
// 赋值给foreach里定义的变量,然后通过循环把所有的元素遍历出来
System.out.println(s1);
}
可以通过在遍历的同时修改集合长度,若抛出并发修改异常,即可证明foreach是利用iterator迭代器。
for(String s2:c){
if(c.equals("java")){
c.add("c++") //此处抛出并发修改异常 ConcurrentModificationException
}
}
得出结论,Collection及其子类都应该具有两个或以上的遍历方法
1.迭代器遍历
2.增强for遍历
3.fori循环(List特有,利用索引)
5. 常用数据结构之栈,队列,数组,链表
1.栈
入栈过程:
入栈顺序 | 元素名 |
---|---|
03 | C |
02 | B |
01 | A |
栈的特点是先进后出,A是第一个进来的,但是A要出来的时候,A就是最后一个出来了
出栈过程
出栈顺序 | 元素名 |
---|---|
01 | C |
02 | B |
03 | A |
2.队列
入队顺序 | 元素名 |
---|---|
03 | C |
02 | B |
01 | A |
队列的特点是先进先出,就是A是先进来的,所以先出来的时候,A也是第一个出来的。
出队顺序 | 元素名 |
---|---|
03 | C |
02 | B |
01 | A |
3.数组(Array)
特点:查询的速度快(通过索引,搜索哪个的速度都是一样的)
增删的速度慢 (牵一发而动全身)
4.链表(Linked)
特点:增删速度相较于数组快(修改上一元素地址值和自身地址值即可完成增删)
查询速度相较于数组慢(每一次查询都必须从头部出发去查询)
6. 两种数据结构的List集合实现类
根据两种数据结构的不同,自然而然就产生了两种数据结构的实现类:
ArrayList(数组类型)和LinkedList(链表类型)
- ArrayList(数组类型)实现类:
使用方法就是
ArrayList list = new ArrayList();
前面的例子都是通过这个实现类进行演示的,
简单的说就是get,set,add,remove方法。
- LinkedList (链表类型)的实现类:
LinkedList list = new LinkedList();
他有他特有的对数据的处理方法:
import java.util.LinkedList;
public class LinkedListDemo1 {
public static void main(String[] args) {
LinkedList<String> l1 =new LinkedList<>();
l1.add("java");
l1.add("c++");
l1.add("python");
l1.addFirst("hello");//在最开始添加一个元素
l1.addLast("ok");//addLast() = add() 在列表最后添加元素
System.out.println(l1);
System.out.println( l1.getFirst());//获得开头的元素
System.out.println(l1.getLast());//获得最后的元素
System.out.println(l1.removeFirst());//删除列表开始的元素并把他返回
System.out.println(l1.removeLast());//删除列表开始的元素并把他返回
System.out.println(l1);
}
}
/*
结果:
[hello, java, c++, python, ok]
hello
ok
hello
ok
[java, c++, python]
*/
四、Set集合
1. Set集合概述
-
set是继承自Collection的所以有collection的所有特点
-
set独有的特点是,元素不能重复;
-
没有索引,无法使用fori循环遍历
2. HashSet
import com.lys.oop.extendsDemo.Students;
import com.sun.xml.internal.ws.encoding.HasEncoding;
import java.util.HashSet;
public class HashSetDemo1 {
public static void main(String[] args) {
HashSet<String> hs1 = new HashSet<>();
String s1 = "java";//96515
String s2 = "c++";//3254818
String s3 = "c";//99
String s4 = "c";
hs1.add(s1);
hs1.add(s2);
hs1.add(s3);
hs1.add(s4);//字符串相同,在堆里是同一个,所以是一致的,不重复添加
for (String s :hs1) {
System.out.println(s+"\t"+s.hashCode());
}
HashSet<Students> hs2 = new HashSet<>();
Students stu1 = new Students("java",18);
Students stu2 = new Students("c++",18);
Students stu3 = new Students("java",18);
//注意,这里的stu1=stu3,但是却两个都能输出,原因是因为在栈堆中,创建的对象不一样。
//解决方案,去对象的源码,重写hashcode和equlas方法
hs2.add(stu1);
hs2.add(stu2);
hs2.add(stu3);
System.out.println(hs2);
}
}
保证元素唯一性的源码分析:
为什么hashset的元素不重复?
HashSet<String> hs = new HashSet<>();
hs.add("java");//96515
hs.add("c++");//3254818
hs.add("c");//99
hs.add("c");//99 //是因为添加元素的时候,重复值被处理了,所以看add方法
根据API把所有相关源码展示:
public boolean add(E e) { //add方法用到了put方法,e表示我放进去的对象,这里用”java“表示
return map.put(e, PRESENT)==null;
}
public V put(K key, V value) { //key就是java。这里对我的”java“字符串进行了hashcode方法。java.hashcode()=96515
return putVal(hash(key), key, value, false, true); //把96515和”java“作为参数传到putVal()中;
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; //tab是一个数组,由”java“这样的对象+一个值构成,这个值是上面的PRESENT
Node<K,V> p; //p是一个对象,由”java“这样的对象+一个值构成,这个值是上面的PRESENT
int n, i;
存入的元素和以前的元素比较哈希值
如果哈希值不一样,继续执行,把元素添加到集合
如果是一样的,调用对象的equals方法比较
如果返回false,继续执行,添加到集合
如果返回ture,说明元素重复,不存储
if ((tab = table) == null || (n = tab.length) == 0) //如果这个表是等于初始表的,或者这个表长度为空的
n = (tab = resize()).length; //初始化这个哈希表
if ((p = tab[i = (n - 1) & hash]) == null) 根据这个hash值判断对应存储空间是否为空
tab[i] = newNode(hash, key, value, null); //把 p对象初始化并把它写进表的第i号位
else {
Node<K,V> e; K k;
if (p.hash == hash && //存入的hash值和原来的hash值比较
((k = p.key) == key || (key != null && key.equals(k)))) 对象是不是和原来的一样 || 再通过对象的equals方法再判断一次是否一样
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;
}
逻辑图法:
3. 常用数据结构之哈希表
哈希表是采用数组加链表的形式存储的,
1.把对象的hashcode算出来
2.把hashcode全部取余16
3.算出一个常数。该常数就是数组的索引位置
4.然后就把对象一个个放入数组
5.当常数一致时(就是说该位置已经有对象了,但是我后面还有是属于这个位置的对象进来),
比较两个对象的hashcode,不一致则在该对象后面以链表的数据类型存储,
若一致,再次比较两个对象的内容,两者内容一样,则说明元素一致,不存储。
若不一致,则在这对象后面用链表的形式存储。
4.LinkedHashSet集合的概述和特点
代码演示
import java.util.LinkedHashSet;
//LinkedHashSet特点:因为Linked存储数据,元素有序
//hash表存储,元素不重复
public class LinkedHashSetDemo1 {
public static void main(String[] args) {
LinkedHashSet<String> lhs=new LinkedHashSet<>();
String s1 = "java";
String s2 = "c";
String s3 = "c++";
String s4 = "java";
lhs.add(s1);
lhs.add(s2);
lhs.add(s3);
lhs.add(s4);
for (String s:lhs) {
System.out.println(s);
}
}
}
/*
结果:
java
c
c++
*/
5.TreeSet
特点:
-
public class TreeSet<E> extends AbstractSet<E> implements NavigableSet<E>, Cloneable, Serializable
NavigableSet
实现基于TreeMap
的元件使用其有序natural ordering ,或由Comparator
集合创建时提供,这取决于所使用的构造方法。
代码演示:
要求:1.用TreeSet集合存储学生对象并遍历,创建集合的无参构造
2.按照年龄大小顺序排序,若年龄相同,则按姓名的字母顺序排列
思路:1.创建student类,并在测试类引入对象
2.测试类引入集合,把学生对象添加到集合里,并遍历
3.由于用TreeSet集合,故集合的泛型对象必须实现Comparable<T>的接口
4.重写实现类的compareTo()方法,根据返回值的特性完成对元素的顺序排列
------------------------------------------
public class StudentPo implements Comparable<StudentPo> {
int age;
String name;
@Override
public String toString() {
return "[" +
"age=" + age +
", name='" + name + '\'' +
']';
}
public StudentPo() {
}
public StudentPo(int age, String name) {
this.age = age;
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int compareTo(StudentPo s) {
// return 0; //不进行比较
// return 1; //顺序比较
// return -1; //逆序排列
int num1 = 0;
if (this.age - s.age != 0) {
num1 = this.age - s.age;
} else {
num1 = this.name.compareTo(s.name) ;
}
return num1;
}
}
---------------------------------------------------------------------------------
import java.util.TreeSet;
/*TreeSet特点:
1.继承Set元素不重复
2.有一定规律的顺序,自然顺序
*/
public class TreeSetDemo1 {
public static void main(String[] args) {
//创建集合对象
TreeSet<StudentPo> ts1 = new TreeSet<>();
//创建学生对象
StudentPo stu1 =new StudentPo( 16,"sting" );
StudentPo stu2 =new StudentPo( 16,"char" );
StudentPo stu3 =new StudentPo( 30,"int" );
StudentPo stu4 =new StudentPo( 50,"varchar" );
StudentPo stu5 =new StudentPo( 16,"sting" );//相同的项,根据特性不输出相同的元素
ts1.add(stu1);
ts1.add(stu2);
ts1.add(stu3);
ts1.add(stu4);
ts1.add(stu5);
for (StudentPo i:ts1) {
System.out.println("[name:"+i.getName()+"\t"+"age:"+ i.getAge()+"]");
}
}
}
/*
结果:
[name:char age:16]
[name:sting age:16]
[name:int age:30]
[name:varchar age:50]
*/
------------------------------------------------------------
而利用有参构造完成这个问题则不需要让student对象实现comprable接口,然后重写它的compareTo方法
而是直接在new TreeSet集合对象的时候,通过匿名内部类的办法重写comparator的compare方法就完事了
核心代码如下:
TreeSet<StudentPo> ts2 = new TreeSet<>(new Comparator<StudentPo>() {
@Override
public int compare(StudentPo s1, StudentPo s2) {
int num1 = 0;
if (s1.getAge() - s2.getAge() != 0) {
num1 = s1.getAge() - s2.getAge();
} else {
num1 = s1.getName().compareTo(s2.getName()) ;
}
return num1;
}
});
结论:
实战例子:产生10个不重复的随机数
package com.lys.heima.javaSEjichu;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
//要求:写一个程序,获取1-20的10个随机整数,要求10个整数不重复,把其输出;
//思路:1.随机数用random对象,生成随机数
// 2.通过set集合存储数据,达到随机数不重复,利用循环添加随机数当集合Size=10则停下来
// 3.遍历集合
public class canshen10geshuijishu {
public static void main(String[] args) {
Set<Integer> s = new HashSet<>();//此处利用TreeSet作为多态方法的话还能把随机数进行排序
Random r = new Random();
while (s.size()<10){
Integer a =r.nextInt(20)+1;
s.add(a);
}
for (Integer x: s) {
System.out.println(x);
}
System.out.println("size="+s.size());
}
}
五、泛型
1.泛型介绍:
简单来说:泛型的引入就是减少重复性代码,把相同的行为的代码抽象出来,通过泛型的概念,把这个行为抽象成一类通用行为,只要是符合这个行为的动作,我都可以通过这个泛型定义的行为完成。
:常用来表示类型
:常用来表示元素
:常用来表示键
:常用来表示值
泛型类:
格式:修饰符 class 类名<类型>{ }
例子:public class fun<T>{ }
好处:类的成员变量可以在创建对象的时候再去指定;
泛型方法:
格式:修饰符 <类型> 返回值类型 方法名 (类型 变量名){ }
例子:public <T> class fun(T t){ }
好处:方法的参数可以是任意类型,不需写多次的不同参数类型的方法重写,但是相对的代码的安全性需要自己注意,因为无限制,所以报错提示也相对变弱了
泛型接口:
格式:修饰符 interface 接口名<类型>{ }
例子:public interface fun<T>{ }
好处: 创建的接口的参数是任意类型,其实现类的参数也是可以是任意类型
2.类型通配符
<? extends 类型> :既然是extends ,意味着这个通配符?
是后面类型的子类或者是它本身。
<? super 类型> :这个是super,意味着这个通配符?
表示的是这个类型的父类或者是这个类型本身。
3.可变参数的使用
可变参数,意思是在方法重写的时候,同一种类型的多个参数在方法中被传入,如果按写定的参数则无法实现这个,于是使用 (参数类型…参数名)的方式表示这个参数的长度是可变的。
public <T> void say(T... t){
System.out.println(t);
}
注意:这个T...t的底层原理是把t按存T[]这样一个集合存作为参数传到方法中的。所以要使用这种T...的格式的话,这个必须是最后的一个参数。
即(int x ,T... t)
public <T> void say(int x ,T... t){ //T...t不能在x前面。
System.out.println(t);
}
集合上的可变参数的使用:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
//注:List。of()和Set.of()方法在jdk9才能使用
public class ListofDemo1 {
public static void main(String[] args) {
List<String> l1 = Arrays.asList("java","c++","c");//可以在这添加元素
// l1.add("a");//UnsupportedOperationException
// l1.remove("a");//UnsupportedOperationException
l1.set(1,"a");//可行
List<String> l2 = List.of("java","c++","c");//可以在这里添加元素
l2.set(1,"c#");//可行
l2.add("c#");//UnsupportedOperationException
l2.remove("c#");//UnsupportedOperationException
Set<String> set= Set.of("java","c++","c","c");//IllegalArgumentException,元素不可重复
set.add("c#");//UnsupportedOperationException
set.remove("c#");//UnsupportedOperationException
}
}
六、Map
1.概述和特点:
基本功能:
代码展示:
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
public class MapDemo1 {
public static void main(String[] args) {
Map<String,String> m =new HashMap<>();//TreeMap<>();多种多态方式
//put方法添加元素
m.put("01","java");
m.put("02","c++");
m.put("03","c#");
m.put("04","c#");
//remove方法删除元素,返回值是K对应的V值;
System.out.println(m.remove("01"));
//clear,清空集合
m.clear();
//containsKey,和containsValue 对比键和值 ,返回值是boolean类型
System.out.println(m.containsKey("01"));
System.out.println(m.containsValue("c++"));
//size,返回值int型
System.out.println(m.size());
System.out.println(m);
}
}
以上方法可看出,map集合底层左边的键是以Set集中装的,右边的值是以Collection装的;
Map<String,String> m =new HashMap<>();
//put方法添加元素
m.put("01","java");
m.put("02","c++");
m.put("03","c#");
m.put("04","c#");
//V get(object Key):根据键获取对应的值
System.out.println(m.get("01"));
// System.out.println(m.get("05"));//没有则返回null
//Set<k> keySet();获取所有键的集合
Set<String> set = m.keySet();
for (String s:set){
System.out.print(s+" ");
}
System.out.println();
System.out.println("---------------------");
//Collection<v> values();获取所有值的集合
Collection<String> values = m.values();
for (String s:values){
System.out.print(s+" ");
}
2.Map集合的遍历:
方法1:
//通过键找值
Set<String> set = m.keySet();
for (String s : set){
String v = m.get(s);
System.out.println("key="+s+"\t"+"values="+ v);
方式2:
Set<Map.Entry<String, String>> entries = m.entrySet();
for ( Map.Entry<String, String> kvd:entries){ //Map.Entry<String, String>键值对对象的类型
System.out.println(kvd.getKey()+"\t"+kvd.getValue());
3.经典案例
1.在ArrayLIst集合里装HashMap<String,String>类型的数据;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;
//在ArrayList集合中存储HashMap类型元素
public class HashMapInstArrayListDemo1 {
public static void main(String[] args) {
ArrayList<HashMap<String,String>> arrayList = new ArrayList<>();
HashMap<String, String> hm1 = new HashMap<String,String>();
hm1.put("01","java");
hm1.put("02","c++");
HashMap<String,String> hm2 = new HashMap<>();
hm2.put("01","剑姬");
hm2.put("02","青钢影");
HashMap<String,String> hm3 = new HashMap<>();
hm3.put("01","剑魔");
hm3.put("02","潘森");
arrayList.add(hm1);
arrayList.add(hm2);
arrayList.add(hm3);
for (HashMap<String,String> hm :arrayList){
Set<String> keySet = hm.keySet();
for (String k:keySet){
String v = hm.get(k);
System.out.println("k="+k+"\t"+"v="+v);
}
}
}
}
/*
结果:
k=01 v=java
k=02 v=c++
k=01 v=剑姬
k=02 v=青钢影
k=01 v=剑魔
k=02 v=潘森
进程已结束,退出代码为 0
*/
反过来的在idea有案例HashMapInstArrayListDemo2
import java.util.HashMap;
import java.util.Scanner;
import java.util.Set;
//键盘录入一堆字符串,根据字符串出现次数,分处其出现次数
public class HashMapTestdemo1 {
public static void main(String[] args) {
//1.键盘录入:
Scanner sc = new Scanner(System.in);
String line= sc.nextLine();
//创建hashmap对象
HashMap<Character,Integer> hm = new HashMap<>();
//改进:用TreeMap作为集合来存储可以使结果输出的时候,按照字母的顺序进行排序。
//遍历字符串,化成char类型,然后装箱进集合
for (int i = 0; i <line.length() ; i++) {
char key = line.charAt(i);
//判断返回值,
//1.若返回值为null,说明集合中没有此字符,则把该字符放进去,并把其值赋为1、
//2.若返回值为ture,说明已经有此字符,则把其取值出,进行加一操作,再放回集合
Integer v = hm.get(key);
if (v==null){
hm.put(key,1);
}else {
v++;
hm.put(key, v);
}
}
//遍历hashmap集合
Set<Character> keySet = hm.keySet();
for(Character k:keySet){
Integer v = hm.get(k);
System.out.print(k+"("+v+")");
//可以通过StringBuilder进行封装,把结果封装起来,存到一个resule里面,方便调用;
/* StringBuilder sb =new StringBuilder();
sb.append(k).append("(").append(v).append(")");
String result = sb.toString();
System.out.print(result);
*/
}
}
}
七、Collections
1.概述
Collections的方法全是静态方法
使用方法:
Collections.sort(List) //升序排序
Collections.reverse(List)//反转元素顺序
Collections.shuffle(List)//随机排列,每传一次变一次
使用这个方法进行排序时,必须把传进来的来继承Comparable并重写其方法,或者是在传入数组的时候,同时传入一个Comparator的对象(采用匿名内部类的方法)
2.斗地主模拟案例
package com.lys.heima.javaSEjichu;
import java.util.*;
/*
要求:实现斗地主的洗牌,发牌和看牌
思路:
1.先存牌,用arraylist进行存牌
2.洗牌。用collections。shuffle()方法把牌打乱
3.发牌,用Treemap,存对应三个人的名字和牌
4.看牌,遍历对应的玩家的牌
*/
public class doudizhuDemo1 {
public static void main(String[] args) {
ArrayList<String> arrayList = new ArrayList<>();
//把花色和字符拼接,添加到集合中
String[] Color = {"♦", "♣", "♥", "♠"};
String[] Num = {"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"};
for (String color : Color) {
for (String num : Num) {
arrayList.add(color + num);
}
}
//添加大王小王
arrayList.add("🧛j");
arrayList.add("🧛J");
//System.out.println(arrayList+"\t"+arrayList.size());
//打乱顺序
Collections.shuffle(arrayList);
// System.out.println(arrayList);
//发牌,遍历,满17张就换下一个,通过三个数组装载
//自己想出来的发牌方法
/* String[] w1 = new String[17];
String[] w2 = new String[17];
String[] w3 = new String[17];
String[] dz = new String[3];
for (int i = 0; i <arrayList.size() ; i++) {
//玩家一
if (i < 17) {
w1[i] = arrayList.get(i);
}
//玩家二
else if (17 <= i && i < 34) {
w2[i - 17] = arrayList.get(i);
}
//玩家三
else if (34 <= i && i < 51) {
w3[i - 34] = arrayList.get(i);
}
//地主牌
else if (i >= 51 && i < 54) {
dz[i - 51] = arrayList.get(i);
}
}*/
//老师的方法:
ArrayList<String> player1 =new ArrayList<>();
ArrayList<String> player2 =new ArrayList<>();
ArrayList<String> player3 =new ArrayList<>();
ArrayList<String> dipai =new ArrayList<>();
for (int i = 0; i < arrayList.size(); i++) {
String pai = arrayList.get(i);
if (i>=arrayList.size()-3){
dipai.add(pai);
}
else if (i%3==0){
player1.add(pai);
}
else if (i%3==1){
player2.add(pai);
}
else if (i%3==2){
player3.add(pai);
}
}
StudentPo wj1 = new StudentPo("张三丰",15);
StudentPo wj2 = new StudentPo("关 羽",17);
StudentPo wj3 = new StudentPo("王 五",44);
StudentPo dz = new StudentPo("地主牌",03);
/* TreeMap<StudentPo,String[]> gx= new TreeMap<>();
gx.put(wj1.w1);
gx.put(wj2,w2);
gx.put(wj3,w3);
gx.put(cp,dz);
Set<StudentPo> keySet = gx.keySet();
for (StudentPo k:keySet){
String[] vsz = gx.get(k);
System.out.print(k.getName()+"("+k.getAge()+"):");
for (String v:vsz){
System.out.print("["+v+"]");
}
System.out.println();
}*/
lookpoker(wj1,player1);
lookpoker(wj2,player2);
lookpoker(wj3,player3);
lookpoker(dz,dipai);
}
public static void lookpoker(StudentPo s,ArrayList<String> a){
System.out.print(s.getName()+"("+s.getAge()+"):");
for(String poker:a) {
System.out.print(poker+" ");
}
System.out.println();
}
}
3.斗地主模拟升级
//呜呜呜,敲了两个小时才敲出来的
import java.util.*;
public class doudizhuDemo2 {
public static void main(String[] args) {
//1.存牌
HashMap<Integer, String> paihe = new HashMap<>();
ArrayList<String> pai = new ArrayList<>();
String[] Color = {"♦", "♣", "♥", "♠"};
String[] Num = {"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"};
for (String color : Color) {
for (String num : Num) {
pai.add( color + num);
}
}
pai.add("🧛R");
pai.add("🧛G");
for (int i = 0; i <54 ; i++) {
paihe.put(i,pai.get(i));
}
Set<Integer> keys = paihe.keySet();
for (Integer k:keys ){
String v = paihe.get(k);
System.out.println(k+":"+v);
}
//洗牌
ArrayList<Integer> xipai = new ArrayList<>();
for (int i = 0; i < 54; i++) {
xipai.add(i);
}
Collections.shuffle(xipai);
// System.out.println(xipai);
//发牌
TreeSet<Integer> kd1 = new TreeSet<>();
TreeSet<Integer> kd2 = new TreeSet<>();
TreeSet<Integer> kd3 = new TreeSet<>();
TreeSet<Integer> dipai = new TreeSet<>();
for (int i = 0; i < xipai.size(); i++) {
Integer ph = xipai.get(i);
if (i>=xipai.size()-3){
dipai.add(ph);
}
else if (i%3==0){
kd1.add(ph);
}
else if (i%3==1){
kd2.add(ph);
}
else if (i%3==2){
kd3.add(ph);
}
}
// System.out.println(kd3);
//看牌
StudentPo wj1 = new StudentPo("张三丰",15);
StudentPo wj2 = new StudentPo("关 羽",17);
StudentPo wj3 = new StudentPo("王 五",44);
StudentPo dz = new StudentPo("地主牌",3);
see(wj1,kd1,paihe);
see(wj2,kd2,paihe);
see(wj3,kd3,paihe);
see(dz,dipai,paihe);
}
public static void see(StudentPo s,TreeSet<Integer> t,HashMap<Integer, String> h){
System.out.print(s.getName()+"("+s.getAge()+"):");
for (Integer i:t) {
String v = h.get(i);
System.out.print(v+" ");
}
System.out.println();
}
}
/*
结果:
张三丰(15):♦A ♦7 ♦10 ♣3 ♣6 ♣10 ♣Q ♣K ♥A ♥3 ♥4 ♥6 ♥10 ♥Q ♠A 🧛R 🧛G
关 羽(17):♦2 ♦3 ♦5 ♦6 ♦8 ♦J ♦Q ♦K ♣2 ♣9 ♣J ♥2 ♥5 ♥8 ♥9 ♠6 ♠9
王 五(44):♦4 ♦9 ♣A ♣4 ♥7 ♥J ♥K ♠2 ♠3 ♠4 ♠5 ♠7 ♠8 ♠10 ♠J ♠Q ♠K
地主牌(3):♣5 ♣7 ♣8
进程已结束,退出代码为 0
*/
ze(); i++) {
Integer ph = xipai.get(i);
if (i>=xipai.size()-3){
dipai.add(ph);
}
else if (i%3==0){
kd1.add(ph);
}
else if (i%3==1){
kd2.add(ph);
}
else if (i%3==2){
kd3.add(ph);
}
}
// System.out.println(kd3);
//看牌
StudentPo wj1 = new StudentPo("张三丰",15);
StudentPo wj2 = new StudentPo("关 羽",17);
StudentPo wj3 = new StudentPo("王 五",44);
StudentPo dz = new StudentPo("地主牌",3);
see(wj1,kd1,paihe);
see(wj2,kd2,paihe);
see(wj3,kd3,paihe);
see(dz,dipai,paihe);
}
public static void see(StudentPo s,TreeSet<Integer> t,HashMap<Integer, String> h){
System.out.print(s.getName()+"("+s.getAge()+"):");
for (Integer i:t) {
String v = h.get(i);
System.out.print(v+" ");
}
System.out.println();
}
}
/*
结果:
张三丰(15):♦A ♦7 ♦10 ♣3 ♣6 ♣10 ♣Q ♣K ♥A ♥3 ♥4 ♥6 ♥10 ♥Q ♠A 🧛R 🧛G
关 羽(17):♦2 ♦3 ♦5 ♦6 ♦8 ♦J ♦Q ♦K ♣2 ♣9 ♣J ♥2 ♥5 ♥8 ♥9 ♠6 ♠9
王 五(44):♦4 ♦9 ♣A ♣4 ♥7 ♥J ♥K ♠2 ♠3 ♠4 ♠5 ♠7 ♠8 ♠10 ♠J ♠Q ♠K
地主牌(3):♣5 ♣7 ♣8
进程已结束,退出代码为 0
*/