特点:
1.存取无序
2.数据唯一
3.不能使用索引操作
位于java.util包下的,使用需要导包
Set集合中的方法和Collection集合中的方法一样,没有特有的方法
Set接口的子类:
代码演示:
package com.itheima.sh.hashset_01;
import java.util.HashSet;
/*
HashSet集合特点:
1.存取无序
2.数据唯一
3.不能使用索引操作
*/
public class HashSetDemo01 {
public static void main(String[] args) {
//创建HashSet集合类的对象
//HashSet() 构造一个新的空 set,其底层 HashMap 实例的默认初始容量是 16,加载因子是 0.75。
HashSet<String> hs = new HashSet<>();
//添加数据
hs.add("柳岩");
hs.add("杨幂");
hs.add("李小璐");
hs.add("马蓉");
hs.add("柳岩");
// System.out.println("hs = " + hs);
//使用增强for循环
for (String s : hs) {
System.out.println("s = " + s);
}
}
}
小结:
1.HashSet集合特点:
1.存取无序
2.数据唯一
3.不能使用索引操作
2.向HashSet集合中存储数据依赖于HashCode和equals方法
/*
HashCode方法演示
结论:
1.如果两个对象的哈希码值不一样,那么这两个对象肯定不同
2.如果两个对象的哈希码值一样,那么两个对象有可能不相同
3.对象调用hasCode方法计算出的值是一个比较大的整数值,我们称为哈希码值
*/
private static void method_2() {
int i = "柳岩".hashCode();//848662
int i1 = "杨幂".hashCode();//844762
int i2 = "杨幂".hashCode();//844762
System.out.println(i);
System.out.println(i1);
System.out.println(i2);
System.out.println("重地".hashCode());//1179395
System.out.println("通话".hashCode());//1179395
}
小结:
1.如果两个对象的哈希码值不一样,那么这两个对象肯定不同
2.如果两个对象的哈希码值一样,那么两个对象有可能不相同
1.在jdk8前哈希表由:数组+链表 数组是主体,链表解决哈希冲突(两个对象的HashCode方法的哈希码值一样)
2.jdk8后哈希表由:数组+链表+红黑树,数组是主体,链表+红黑树来解决哈希冲突,引入红黑树的目的是为了提高查询效率。比链表快。当链表的节点个数大于8并且数组长度大于等于64,才将链表变为红黑树
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ermVgmdP-1592806598812)(/image-20200517100439615.png)]
代码演示:
package com.itheima.sh.hashset_01;
import java.util.HashSet;
/*
哈希表的存储过程
*/
public class HashSetDemo02 {
public static void main(String[] args) {
//创建HashSet集合对象
HashSet<String> hs = new HashSet<>();
//添加数据
hs.add("柳岩");
hs.add("杨幂");
hs.add("璐璐");
hs.add("冰冰");
hs.add("蓉蓉");
hs.add("诗诗");
hs.add("柳岩");
System.out.println(hs);
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1rbk90MS-1592806598817)(/image-20200517103627431.png)]
代码演示:
package com.itheima.sh.hashset_01;
import java.util.Objects;
public class Student {
String name;
int age;
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 String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//重写equals和hashCode alt+insert
@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);
}
}
package com.itheima.sh.hashset_01;
import java.util.HashSet;
/*
需求:向HashSet集合中存储自定义类Student的对象
*/
public class HashSetDemo03 {
public static void main(String[] args) {
//创建HashSet集合
HashSet<Student> hs = new HashSet<Student>();
//添加数据
Student s1 = new Student("张三", 19);
Student s2 = new Student("李四", 20);
Student s3 = new Student("王五", 19);
Student s4 = new Student("张三", 19);
//添加数据
hs.add(s1);
hs.add(s2);
hs.add(s3);
hs.add(s4);
System.out.println(hs);
}
}
小结:
只要向哈希表中存储对象数据,那么所属类必须重写hashCode和equals方法。
public class HashMap{
//......
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
//......
static final int hash(Object key) {//根据参数,产生一个哈希值
int h;
/*
1)如果key等于null:
可以看到当key等于null的时候也是有哈希值的,返回的是0.
2)如果key不等于null:
首先计算出key的hashCode赋值给h,然后与h无符号右移16位后的二进制进行按位异或得到最后的 hash值
3)注意这里计算最后的hash值会结合下面的数组长度计算出存储数据的索引
*/
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
//......
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; //临时变量,存储"哈希表"——由此可见,哈希表是一个Node[]数组
Node<K,V> p;//临时变量,用于存储从"哈希表"中获取的Node
int n, i;//n存储哈希表长度;i存储哈希表索引
/*
1)transient Node[] table; 表示存储Map集合中元素的数组。
2)(tab = table) == null 表示将空的table赋值给tab,然后判断tab是否等于null,第一次肯定是 null
3)(n = tab.length) == 0 表示将数组的长度0赋值给n,然后判断n是否等于0,n等于0
由于if判断使用双或,满足一个即可,则执行代码 n = (tab = resize()).length; 进行数组初始化。
并将初始化好的数组长度赋值给n.
4)执行完n = (tab = resize()).length,数组tab每个空间都是null
*/
if ((tab = table) == null || (n = tab.length) == 0)//判断当前是否还没有生成哈希表
n = (tab = resize()).length;//resize()方法用于生成一个哈希表,默认长度:16,赋给n
/*
1)i = (n - 1) & hash 表示计算数组的索引赋值给i,即确定元素存放在哪个桶中
2)p = tab[i = (n - 1) & hash]表示获取计算出的位置的数据赋值给节点p
3) (p = tab[i = (n - 1) & hash]) == null 判断节点位置是否等于null,如果为null,则执行代 码:tab[i] = newNode(hash, key, value, null);根据键值对创建新的节点放入该位置的桶中
小结:如果当前桶没有哈希碰撞冲突,则直接把键值对插入空间位置
*/
if ((p = tab[i = (n - 1) & hash]) == null)//(n-1)&hash等效于hash % n,转换为数组索引
tab[i] = newNode(hash, key, value, null);//此位置没有元素,直接存储
else {//否则此位置已经有元素了
Node<K,V> e; K k;
/*
比较桶中第一个元素(数组中的结点)的hash值和key是否相等
1)p.hash == hash :p.hash表示原来存在数据的hash值 hash表示后添加数据的hash值 比较两个 hash值是否相等
说明:p表示tab[i],即 newNode(hash, key, value, null)方法返回的Node对象。
Node newNode(int hash, K key, V value, Node next)
{
return new Node<>(hash, key, value, next);
}
而在Node类中具有成员变量hash用来记录着之前数据的hash值的
2)(k = p.key) == key :p.key获取原来数据的key赋值给k key 表示后添加数据的key 比较两 个key的地址值是否相等
3)key != null && key.equals(k):能够执行到这里说明两个key的地址值不相等,那么先判断后 添加的key是否等于null,如果不等于null再调用equals方法判断两个key的内容是否相等
*/
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))//判断哈希值和equals
/*
说明:两个元素哈希值相等,并且key的值也相等
将旧的元素整体对象赋值给e,用e来记录
*/
e = p;//将哈希表中的元素存储为e
// hash值不相等或者key不相等;判断p是否为红黑树结点
else if (p instanceof TreeNode)//判断是否为"树"结构
// // 放入树中
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {//排除以上两种情况,将其存为新的Node节点
//说明是链表节点
/*
1)如果是链表的话需要遍历到最后节点然后插入
2)采用循环遍历的方式,判断链表中是否有重复的key
*/
for (int binCount = 0; ; ++binCount) {//遍历链表
/*
1)e = p.next 获取p的下一个元素赋值给e
2)(e = p.next) == null 判断p.next是否等于null,等于null,说明p没有下一个元 素,那么此时到达了链表的尾部,还没有找到重复的key,则说明HashMap没有包含该键
将该键值对插入链表中
*/
if ((e = p.next) == null) {//找到最后一个节点
/*
1)创建一个新的节点插入到尾部
p.next = newNode(hash, key, value, null);
Node newNode(int hash, K key, V value, Node next)
{
return new Node<>(hash, key, value, next);
}
注意第四个参数next是null,因为当前元素插入到链表末尾了,那么下一个节点肯定是 null
2)这种添加方式也满足链表数据结构的特点,每次向后添加新的元素
*/
p.next = newNode(hash, key, value, null);//产生一个新节点,赋值到链表
/*
1)节点添加完成之后判断此时节点个数是否大于TREEIFY_THRESHOLD临界值8,如果大于
则将链表转换为红黑树
2)int binCount = 0 :表示for循环的初始化值。从0开始计数。记录着遍历节点的个 数。值是0表示第一个节点,1表示第二个节点。。。。7表示第八个节点,加上数组中的的一 个元素,元素个数是9
TREEIFY_THRESHOLD - 1 --》8 - 1 ---》7
如果binCount的值是7(加上数组中的的一个元素,元素个数是9)
TREEIFY_THRESHOLD - 1也是7,此时转换红黑树
*/
if (binCount >= TREEIFY_THRESHOLD - 1) //判断链表长度是否大于了8
//转换为红黑树
treeifyBin(tab, hash);//树形化
//跳出循环
break;
}
/*
执行到这里说明e = p.next 不是null,不是最后一个元素。继续判断链表中结点的key值与插 入的元素的key值是否相等
*/
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))//跟当前变量的元素比较,如果hashCode相同,equals也相同
// 相等,跳出循环
/*
要添加的元素和链表中的存在的元素的key相等了,则跳出for循环。不用再继续比较了
直接执行下面的if语句去替换去 if (e != null)
*/
break;//结束循环
/*
说明新添加的元素和当前节点不相等,继续查找下一个节点。
用于遍历桶中的链表,与前面的e = p.next组合,可以遍历链表
*/
p = e;//将p设为当前遍历的Node节点
}
}
/*
表示在桶中找到key值、hash值与插入元素相等的结点
也就是说通过上面的操作找到了重复的键,所以这里就是把该键的值变为新的值,并返回旧值
这里完成了put方法的修改功能
*/
if (e != null) {
// 记录e的value
V oldValue = e.value;
// onlyIfAbsent为false或者旧值为null
if (!onlyIfAbsent || oldValue == null)
//用新值替换旧值
//e.value 表示旧值 value表示新值
e.value = value;
// 访问后回调
afterNodeAccess(e);
// 返回旧值
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
}
1.哈希碰撞:对象的hashCode方法计算的值相等产生哈希碰撞
2.如何解决哈希碰撞:使用链表(8之前),使用链表+红黑树(8之后)
3.为什么引入红黑树?
目的是为了提高查找效率
4.何时链表变为红黑树?
节点大于大于8并且数组长度大于等于64
8.为什么红黑树设置的节点是8?
* Because TreeNodes are about twice the size of regular nodes, we
* use them only when bins contain enough nodes to warrant use
* (see TREEIFY_THRESHOLD). And when they become too small (due to
* removal or resizing) they are converted back to plain bins. In
* usages with well-distributed user hashCodes, tree bins are
* rarely used. Ideally, under random hashCodes, the frequency of
* nodes in bins follows a Poisson distribution
* (http://en.wikipedia.org/wiki/Poisson_distribution) with a
* parameter of about 0.5 on average for the default resizing
* threshold of 0.75, although with a large variance because of
* resizing granularity. Ignoring variance, the expected
* occurrences of list size k are (exp(-0.5) * pow(0.5, k) /
* factorial(k)). The first values are:
*
* 0: 0.60653066
* 1: 0.30326533
* 2: 0.07581633
* 3: 0.01263606
* 4: 0.00157952
* 5: 0.00015795
* 6: 0.00001316
* 7: 0.00000094
* 8: 0.00000006
满足泊松分布,统计学。
9.什么是加载因子?
加载因子也称为负载因子,默认是0.75.他是根据数组长度计算出边界值,何时扩容的。
数组长度默认是16,边界值:16*0.75===》12
为什么加载因子设置为0.75呢?
因为0.75是最佳方案。
10.创建集合对象时,如果知道存储多少个数据,那么不建议使用空参的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VGL05qHI-1592806598819)(/image-20200517115252124.png)]
集合长度一定是2的n次方。
假设这里给参数是7
HashSet(int initialCapacity) 7--->变为8 10---》16
底层会根据你指定的值变为比你指定的值大的最小的2的n次幂
Set集合下面都是存取无序的,但是该集合是存取有序的。因为他底层有两个数据结构:
1.链表:保证存取有序
2.哈希表:保证数据唯一,真正存储数据
代码演示:
package com.itheima.sh.linkedhashset_02;
import java.util.LinkedHashSet;
public class LinkedHashSetDemo01 {
public static void main(String[] args) {
//创建集合对象
LinkedHashSet<String> list = new LinkedHashSet<>();
//添加数据
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.add("aaa");
System.out.println("list = " + list);//list = [aaa, bbb, ccc]
}
}
小结:
1.LinkedHashSet是Set集合下面的存取有序的集合
链表:保证存取有序
哈希表:保证数据唯一,真正存储数据
1.TreeSet集合底层是TreeMap,TreeMap底层是红黑树数据结构
2.向该集合中存储的数据特点:
1)数据唯一
2)可以对数据进行大小排序,具体如何排序看使用的构造方法
1)TreeSet() 构造一个新的空 set,默认排序方式,大小升序
2)TreeSet(Comparator<? super E> comparator) 构造一个新的空 TreeSet,它根据指定比较器进行排序。
Comparator表示自定义排序接口,该接口下有一个排序方法:
int compare(T o1, T o2)
升序:o1 - o2
降序:o2 - o1
代码演示:
package com.itheima.sh.treeset_02;
import java.util.Comparator;
import java.util.TreeSet;
public class TreeSetDemo01 {
public static void main(String[] args) {
//调用方法
method_3();
}
/*
2)TreeSet(Comparator super E> comparator) 构造一个新的空 TreeSet,它根据指定比较器进行排序。
Comparator表示自定义排序接口,该接口下有一个排序方法:
int compare(T o1, T o2)
升序:o1 - o2
降序:o2 - o1
*/
private static void method_3() {
/*
TreeSet存储自定义类型时,必须要给出排序方式。
需求:按照年龄从小到大排序,如果年龄相同,判断姓名是否相同,相同不存储,不同就存储
*/
//创建集合对象
TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
//判断年龄是否相同,如果不同大小升序
if(o1.age != o2.age){
//说明年龄不等
return o1.age - o2.age;
}
//如果执行到这里,说明年龄相同,判断姓名是否相同,相同就不存储,不同存储
if(o1.name.equals(o2.name)){
//说明姓名相同 不存储
return 0;//这里一定是0
}else{
//说明姓名不同 存储
return -1;//这里只要不返回0就可以,正数和负数都可以存储
}
}
});
//创建学生对象
Student s1 = new Student("柳岩", 19);
Student s2 = new Student("杨幂", 20);
Student s3 = new Student("冰冰", 19);
Student s4 = new Student("柳岩", 19);
//添加数据
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
//输出
System.out.println(ts);
}
/*
2)TreeSet(Comparator super E> comparator) 构造一个新的空 TreeSet,它根据指定比较器进行排序。
Comparator表示自定义排序接口,该接口下有一个排序方法:
int compare(T o1, T o2)
升序:o1 - o2
降序:o2 - o1
*/
private static void method_2() {
//比较器排序.要求:按照长度升序排序,长度相同的不存
//创建集合对象
TreeSet<String> ts = new TreeSet<>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
});
//添加数据
ts.add("ajaha");
ts.add("AJAH");
ts.add("abc");
ts.add("abcd");
ts.add("abc");
ts.add("哈哈哈");
//输出 ts = [abc, AJAH, ajaha]
System.out.println("ts = " + ts);
}
/*
1)数据唯一
2)可以对数据进行大小排序,
*/
private static void method_1() {
//自然排序 1)TreeSet() 构造一个新的空 set,默认排序方式,大小升序
TreeSet<String> ts = new TreeSet<>();
//添加数据
ts.add("ajaha");
ts.add("AJAH");
ts.add("abc");
ts.add("abcd");
ts.add("abc");
//输出 ts = [AJAH, abc, abcd, ajaha]
System.out.println("ts = " + ts);
}
}
小结:
1.TreeSet集合底层是红黑树数据结构,可以对其数据进行大小排序
2.TreeSet() 构造一个新的空 set,默认排序方式,大小升序
3.TreeSet(Comparator super E> comparator) 构造一个新的空 TreeSet,它根据指定比较器进行排序。
Comparator表示自定义排序接口,该接口下有一个排序方法:
int compare(T o1, T o2)
升序:o1 - o2
降序:o2 - o1
4.向TreeSet集合中存储自定义类的对象时只能使用带参数的构造方法:
TreeSet(Comparator<? super E> comparator) 传递比较器
父类Person:
package com.itheima.sh.domain;
/*
父类
*/
public abstract class Person {
//属性
private int id;//编号
private String name;//姓名
private String sex;//性别
private String birthday;//生日
private int age;//年龄
//构造方法
public Person() {
}
public Person(int id, String name, String sex, String birthday, int age) {
this.id = id;
this.name = name;
this.sex = sex;
this.birthday = birthday;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
this.birthday = birthday;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
", sex='" + sex + '\'' +
", birthday='" + birthday + '\'' +
", age=" + age +
'}';
}
//类型
public abstract String getType();
//职业
public abstract String getWork();
}
子类Student:
package com.itheima.sh.domain;
public class Student extends Person {
//构造方法
public Student() {
}
public Student(int id, String name, String sex, String birthday, int age) {
super(id, name, sex, birthday, age);
}
//重写方法
@Override
public String getType() {
return "学生";
}
@Override
public String getWork() {
return "学习Java";
}
}
直接将资料中的Utils工具类复制到包下即可.
package com.itheima.sh.utils;
import com.itheima.sh.domain.Person;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
public class Utils {
public static int stuId = 0;//学员ID的初始值 后期可以改为从文件/数据库读取初始值
public static int teaId = 0;//教师ID的初始值
//通过生日计算年龄
public static int birthdayToAge(String birthday) {//"1999-11-13"
Date birthDate = null;
//异常处理的代码,后边学
//这个东西以后讲(idea生成就可以了)
//创建日期格式化解析类对象指定时间格式,并使用parse方法将输入的字符串时间解析为Date
try {
birthDate =new SimpleDateFormat("yyyy-MM-dd").parse(birthday);
} catch (ParseException e) {
e.printStackTrace();
}
//获取当前系统时间
Calendar now = Calendar.getInstance();
//如果出生日期大于当前时间,则抛出异常
Calendar birth = Calendar.getInstance();//获取当前日期的Calendar
//将birthDate表示生日日期转换为Calendar void setTime(Date date) 根据参数date日期更改对象birth的日期
birth.setTime(birthDate);//将生日转换为Calendar(1999-11-13)
//2020 2030
// boolean before(Object when) 判断此 Calendar 表示的时间是否在指定 Object 表示的时间之 前,
//返回判断结果。
//这里就是判断now表示的时间是否在参数birth的时间之前,如果是返回true
//举例:当前时间:2020 出生日期填写2030 那么显然是非法的,那么before方法就会返回true
//now : 2020 birth:2030 非法
//now : 2020 birth:1990 合法
if (now.before(birth)) {//判断当前日期是否在生日日期之前(before()的参数必须是一个Calendar类型)
return -1;//表示计算失败
}
//取出系统当前时间的年、月、日部分
int yearNow = now.get(Calendar.YEAR);//2020
int monthNow = now.get(Calendar.MONTH);//5
int day = now.get(Calendar.DAY_OF_MONTH);//17
//取出出生日期的年、月、日部分
int yearBirth = birth.get(Calendar.YEAR);//1999
int monthBirth = birth.get(Calendar.MONTH);//11
int dayBirth = birth.get(Calendar.DAY_OF_MONTH);//13
//当前年份与出生年份相减,初步计算年龄
// 21 2020 1999
int age = yearNow - yearBirth;
//当前月份与出生日期的月份相比,如果月份小于出生月份,则年龄上减1,表示不满多少周岁
// 5 5
if (monthNow < monthBirth) {
age--;//20
}
//如果月份相等,在比较日期,如果当前日,小于出生日,也减1,表示不满多少周岁
// 1999-3-20 1999-3-30
//2020-5-17 1999-5-17
if (monthNow == monthBirth && day < dayBirth) {//如果:当前月 = 生日月
age--;
}
return age;
}
//打印ArrayList的方法// extends Person>是以后学的
public static void printPersonList(ArrayList<? extends Person> list) {
System.out.println("************************************************************************************");
System.out.println("编号\t\t姓名\t\t性别\t\t生日\t\t\t\t年龄\t\t描述");
//遍历集合
for (int i = 0; i < list.size(); i++) {
//获取集合的每个元素
Person p = list.get(i);
System.out.println(p.getId() + "\t\t" + p.getName() + "\t\t" + p.getSex() + "\t\t" + p.getBirthday() + "\t\t" + p.getAge() + "\t\t" + "我是一名"+ p.getType() +"我要" + p.getWork());
}
System.out.println("************************************************************************************");
}
}
package com.itheima.sh.run;
import com.itheima.sh.domain.Student;
import java.util.ArrayList;
import java.util.Scanner;
/*
一级菜单
*/
public class MainApp {
public static void main(String[] args) {
//1.创建集合对象存储学生
ArrayList<Student> list = new ArrayList<>();
//创建键盘录入的对象
Scanner sc = new Scanner(System.in);
// ArrayList list2 = new ArrayList<>();
//2.使用死循环控制一级菜单一直运行
while (true) {
System.out.println("***************************************");
System.out.println("1.学员信息管理 2.教师信息管理 3.退出");
System.out.println("***************************************");
System.out.println("请输入菜单编号:");
//获取输入菜单项
int choose = sc.nextInt();
//使用多分支结构
switch (choose) {
case 1:
//1.学员信息管理
StudentManager.manager(list);
break;
case 2:
//2.教师信息管理
// TeacherManager.manager(list2);
break;
case 3:
//3.退出 停止虚拟机
System.exit(0);
// return;//结束main方法
default:
System.out.println("【您输入有误】");
break;
}
}
}
}
public class StudentManager {
//二级菜单 学员信息管理
public static void manager(ArrayList<Student> list) {
//死循环
while (true) {
System.out.println("=====================================================");
System.out.println("【学员信息管理】");
System.out.println("");//换行
System.out.println("1.添加学员 2.修改学员 3.查询学员 4.删除学员 5.返回");
System.out.println("=====================================================");
//创建键盘录入的对象
Scanner sc = new Scanner(System.in);
System.out.println("请输入菜单编号:");
//获取编号
int choose = sc.nextInt();
//使用多分支根据录入的编号来操作学生管理系统
switch (choose) {
case 1:
//1.添加学员
break;
case 2:
//2.修改学员
break;
case 3:
//3.查询学员
break;
case 4:
//4.删除学员
break;
case 5:
//5.返回 到一级菜单,不是结束jvm虚拟机
//System.exit(0);一定不能使用这个代码
//结束方法manager
return;
default:
System.out.println("【亲,您输入有误】");
}
}
}
}
//添加学生
private static void addStudent(ArrayList<Student> list) {
//创建键盘录入的对象
Scanner sc = new Scanner(System.in);
System.out.println("请输入学员姓名:");
String name = sc.next();
System.out.println("请输入学员性别:");
String sex = sc.next();
System.out.println("请输入学员出生日期:(2000-01-01)");
String birthday = sc.next();
//给编号+1
Utils.stuId++;
//计算年龄:根据生日birthday
int age = Utils.birthdayToAge(birthday);
//创建学生对象 Utils.stuId 获取上述加1的编号给学生编号
Student s = new Student(Utils.stuId,name,sex,birthday,age);
//将学生存储到集合list
list.add(s);
System.out.println("【添加成功】");
}
//查询学生
private static void findAllStudents(ArrayList<Student> list) {
//对集合list进行判断是否有数据
if(list.size() == 0){
//说明集合没有数据
System.out.println("【亲,没查到你要查的学生】");
}else{
//集合有数据
//输出集合中的数据,使用工具类完成
Utils.printPersonList(list);
}
}