操作系统实验一:进程管理(含成功运行C语言源代码)
目录
(本文知识点较多,如时间较多可以详细看看第3章的知识点;如时间不多可直接点上方目录,直接看第4部分代码实现来理解)
操作系统实验一:进程管理
1.实验目的
1.理解进程的概念,明确进程和程序的区别
2.理解并发执行的实质
3.掌握进程的创建、睡眠、撤销等进程控制方法
2.实验内容
用C语言编写程序,模拟实现创建新的进程;查看运行进程;换出某个进程;杀死运行进程等功能。
3.实验准备
以下将分别介绍
①进程的概念,以及进程的各类状态(就绪状态、执行状态、阻塞状态);
②进程控制块PCB 的作用及内容信息
③进程的创建与撤销 (重点)
④进程的阻塞与唤醒(重点)
3.1.1进程的含义
进程是程序在一个数据集上的运行过程,是系统资源分配和调度的一个独立单位。一个程序在不同数据集上运行,乃至一个程序在同样数据集上的多次运行都是不同的进程。
3.1.2进程的状态
通常情况下,一个进程必须具有就绪、执行和阻塞三种基本状态。
(1)就绪状态
当进程已分配到除处理器(CPU)以外的所有必要资源后,只要再获得处理器就可以立即执行,此时进程的状态称为就绪状态。
在一个系统里,可以有多个进程同时处于就绪状态,通常把这些就绪进程排成一个或多个队列,称为就绪队列。
(2)执行状态
处于就绪状态的进程一旦获得了处理器(分配有处理器资源),就可以运行,进程状态也就处于执行状态。在单处理器系统中,只能有一个进程处于执行状态,在多处理器系统中,则可能有多个进程处于执行状态。
(3)阻塞状态
正在执行的进程因为发生某些事件(如请求输入输出、申请额外空间等)而暂停运行,这种受阻暂停的状态称为阻塞状态,也可以称为等待状态。通常将处于阻塞状态的进程排成一个队列,称为阻塞队列。在有些系统中,也会按阻塞原因的不同将处于阻塞状态的进程排成多个队列。
拓展
除了进程的3种基本状态外,在很多系统为了更好地描述进程的状态变化,又增加了两种状态。
I新状态
当一个新进程刚刚建立,还未将其放入就绪队列的状态,称为新状态。(例如一个,人刚开始接受教育,此时就可以称其处于新状态)
II终止状态
当一个进程已经正常结束或异常结束,操作系统已将其从系统队列中移出,但尚未撒消,这时称为终止状态。
3.1.3进程状态之间的转换
3.2 进程控制块PCB
3.2.1进程控制块的作用
进程控制块是构成进程实体的重要组成部分,是操作系统中最重要的记录型数据,在进程控制块PCB中记录了操作系统所需要的、用于描述进程情况及控制进程运行所需要的全部信息。通过PCB,能够使得原来不能独立运行的程序(数据),成为一个可以独立运行的基本单位,一个能够并发执行的进程。换句话说,在进程的整个生命周期中,操作系统都要通过进程的PCB来对并发执行的进程进行管理和控制,进程控制块是系统对进程控制采用的数据结构,系统是根据进程的PCB而感知进程是否存在。所以,进程控制块是进程存在的唯一标志。当系统创建一个新进程时,就要为它建立一个PCB;进程结束时,系统又回收其PCB,进程也随之消亡。
3.2.2进程控制块的内容
进程控制块主要包括以下四个方面的内容:
(1)进程标识信息
----进程标识符用于标识一个进程,通常又分外部标识符和内部标识符两种。
(2)说明信息
----说明信息是有关进程状态等一些与进程调度有关的信息,它包括:①进程状态 ②进程优先权 ③与进程调度所需的其他信息 ④阻塞事件
(3)现场信息(处理器状态信息)
----现场信息是用于保留进程存放在处理器中的各种信息。主要由处理器内的各个寄存器的内容组成。尤其是当执行中的进程暂停时,这些寄存器内的信息将被保存在PCB里,当该进程获得重新执行时,能从上次停止的地方继续执行。
(4)管理信息(进程控制信息)
进程控制信息主要分四方面:
程序和数据的地址 | 它是指该进程的程序和数据所在的主存和外存地址再次执行时,能够找到程序和数据 |
---|---|
进程同步和通信机制 | 它是指实现进程同步和进程通信时所采用的机制、指针、信号量等 |
资源清单 | 该清单中存放有除了CPU以外,进程所需的全部资源和已经分配到的资源 |
链接指针 | 它将指向该进程所在队列的下一个进程的PCB的首地址 |
3.2.3进程控制块(PCB)的组织形式
在一个系统中,通常拥有数十个、数百个乃至数千个PCB,为了能对它们进行有效的管理,就必须通过适当的方式将它们组织起来,日前常用的组织方式有链接方式和索引方式两种。.
(1)链接方式
把具有相同状态的PCB,用链接指针链接成队列,如就绪队列、阻塞队列和空闲队列等。就绪队列中的PCB将按照相应的进程调度算法进行排序。而阻塞队列也可以根据阻塞原因的不同,将处于阻塞状态的进程的PCB,排成等待I/O队列、等待主存队列等多个队列。此外,系统主存的PCB区中空闲的空间将排成空闲队列,以方便进行PCB的分配与回收。
(2)索引方式
系统根据各个进程的状态,建立不同索引表,例如就绪索引表、阻塞索引表等。并把各个索引表在主存的首地址记录在主存中的专用单元里,也可以称为表指针。在每个索引表的表目中,记录着具有相同状态的各个PCB在表中的地址。
3.2.4进程控制原语
原语是指具有特定功能的不可被中断的过程。它主要用于实现操作系统的一 些专门控制操作。用于进程控制的原语有:
原语 | 作用 |
---|---|
创建原语 | 用于为一个进程分配工作区和建立PCB,该进程为就绪状态 |
撤销原语 | 用于一个进程工作完后,收回它的工作区和PCB |
阻塞原语 | 用于进程在运行过程中发生等待事件时,把进程的状态改为等待态 |
唤醒原语 | 用于当进程等待的事件结束时,把进程的状态改为就绪态 |
3.3进程的创建与撤销 *重点
3.3.1进程的创建
一旦操作系统发现了要求创建进程的事件后,便调用进程创建原按下列步骤创建一个新进程。
①为新进程分配惟一的进程标识符, 并从PCB队列中申请一个空闲PCB。
②为新进程的程序和数据,以及用户栈分配相应的主存空间及其他必要分配资源。
③初始化PCB中的相应信息,如标识信息、处理器信息、进程控制信息等。
④如果就绪队列可以接纳新进程,便将新进程加入到就绪队列中。
3.3.2进程的撤销
一旦操作系统发现了要求终止进程的事件后,便调用进程终止原语按下列步骤终止指定的进程。
①根据被终止进程的标识符,从PCB集合中检索该进程的PCB,读出进程状态。
②若该进程处于执行状态,则立即终止该进程的执行。
③若该进程有子孙进程,还要将其子孙进程终止。
④将该进程所占用的资源回收,归还给其父进程或操作系统。
⑤将被终止进程的PCB从所在队列中移出,并撤销该进程的PCB。
3.4进程的阻塞与唤醒
3.4.1进程的阻塞
一旦操作系统发现了要求阻塞进程的事件后,便调用进程阻塞原语,按下列步骤阻塞指定的进程。
①立即停止执行该进程。
②修改进程控制块中的相关信息。把进程控制块中的运行状态由“执行”状态改为“阻塞”状态,并填入等待的原因,以及进程的各种状态信息。
③把进程控制块插入到阻塞队列。根据阻塞队列的组织方式插入阻塞队列中。
④待调度程序重新调度,运行就绪队列中的其他进程。
3.4.2进程的唤醒
一旦操作系统发现了要求唤醒进程的事件后,便调用进程唤醒原语,按下列步骤唤醒指定的进程。
①从阻塞队列中找到该进程。
②修改该进程控制块的相关内容。把阻塞状态改为就绪状态,删除等待原因等。
③把进程控制块插入到就绪队列中。
④按照就绪队列的组织方式,把被唤醒的进程的进程控制块插入到就绪队列中。
4.代码实现
可成功运行代码如下
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct jincheng_type{ //进程状态定义
int pid; //进程
int youxian; //进程优先级
int daxiao; //进程大小
int zhuangtai; //标志进程状态,0为不在内存,1为在内存,3为挂起
char info[10]; //进程内容
};
struct jincheng_type neicun[20];
int shumu=0,guaqi=0,pid,flag=0; //创建进程
void create(){
if(shumu>=20) printf("\n内存已满,请先换出或结束进程\n"); //内存容量大小设置为20
else{
int i;
printf("**当前默认一次性创建5个进程,内存容量20**");
for(i=0;i<5;i++) { //默认一次创建5个进程
//定位,找到可以还未创建的进程
if(neicun[i].zhuangtai==1) break; //如果找到的进程在内存则结束 ,初始设置都不在内存中(main函数中设置状态为0)
printf("\n请输入新进程pid\n");
scanf("%d",&(neicun[i].pid));
for(int j=0;j<i;j++)
if(neicun[i].pid==neicun[j].pid){
printf("\n该进程已存在\n");
return;
}
printf("请输入新进程优先级\n");
scanf("%d",&(neicun[i].youxian));
printf("请输入新进程大小\n");
scanf("%d",&(neicun[i].daxiao));
printf("请输入新进程内容\n");
scanf("%s",&(neicun[i].info));
//创建进程,使标记位为1
neicun[i].zhuangtai=1;
printf("进程已成功创建!");
shumu++;
}
}
} //进程运行状态检测
void run(){
printf("运行进程信息如下:");
for(int i=0;i<20;i++){
if(neicun[i].zhuangtai==1){
//如果进程正在运行,则输出此运行进程的各个属性值
printf("\n pid=%d ",neicun[i].pid);
printf(" youxian=%d ",neicun[i].youxian);
printf(" daxiao=%d ",neicun[i].daxiao);
printf(" zhuanbgtai=%d ",neicun[i].zhuangtai);
printf(" info=%s ",neicun[i].info);
flag=1;
}
}
if(!flag)
printf("\n当前没有运行进程!\n");
} //进程换出
void huanchu(){
if(!shumu){
printf("当前没有运行进程!\n");
return;
}
printf("\n请输入换出进程的ID值");
scanf("%d",&pid);
for(int i=0;i<20;i++){
//定位,找到要换出的进程,根据其状态进行相应处理
if(pid==neicun[i].pid) {
if(neicun[i].zhuangtai==1){
neicun[i].zhuangtai==2;
guaqi++;
printf("\n已经成功换出进程\n");
}
else if(neicun[i].zhuangtai==0) printf("\n要换出的进程不存在\n");
else printf("\n要换出的进程已被挂起\n");
flag=1;
break;
}
}
//找不到,则说明进程不存在
if(flag==0) printf("\n要换出的进程不存在\n");
} //结束(杀死)进程
void kill(){
if(!shumu){
printf("当前没有运行进程!\n");
return;
}
printf("\n输入杀死进程的ID值");
scanf("%d",&pid);
for(int i=0;i<20;i++){
//定位,找到所要杀死的进程,根据其状态做出相应处理
if(pid==neicun[i].pid){
neicun[i].zhuangtai = 0;
shumu--;
printf("\n已经成功杀死进程\n");
}
else if(neicun[i].zhuangtai==0) printf ("\n要杀死的进程不存在\n");
else printf("\n要杀死的进程已被挂起\n");
flag=1;
break;
}
//找不到,则说明进程不存在
if(!flag) printf("\n 要杀死的进程不存在\n"); } //唤醒进程
void huanxing(){
if (!shumu) {
printf("当前没有运行进程\n");
return;
}
if(!guaqi){
printf("\n当前没有挂起进程\n");
return;
}
printf("\n输入进程pid:\n");
scanf ("%d",&pid);
for (int i=0; i<20;i++) {
//定位,找到所要杀死的进程,根据其状态做相应处理
if (pid==neicun[i].pid) {
flag=false;
if(neicun[i].zhuangtai==2){
neicun[i].zhuangtai=1;
guaqi--;
printf ("\n已经成功唤醒进程\n");
}
else if(neicun[i].zhuangtai==0) printf("\n要唤醒的进程不存在\n");
else printf("\n要唤醒的进程已被挂起\n");
break;
}
}
//找不到,则说明进程不存在
if(flag) printf("\n要唤醒的进程不存在\n");
} //主函数
int main()
{
int n = 1;
int num;
//一开始所有进程都不在内存中
for(int i=0;i<20;i++)
neicun[i].zhuangtai = 0;
while(n){
printf("\n******************************************");
printf("\n* 进程演示系统 *");
printf("\n******************************************");
printf("\n*1.创建新的进程 2.查看运行进程 *");
printf("\n*3.换出某个进程 4.杀死运行进程 *");
printf("\n*5.唤醒某个进程 6.退出系统 *");
printf("\n******************************************");
printf("\n请选择(1~6)\n");
scanf("%d",&num);
switch(num){
case 1: create();break;
case 2: run();break;
case 3: huanchu(); break;
case 4: kill();break;
case 5: huanxing(); break;
case 6: printf("已退出系统");exit(0);
default: printf("请检查输入数值是否在系统功能中1~6");n=0;
}
flag = 0;//恢复标记
}
return 0;
}
4.1代码分解介绍
源程序中一共构造了5个函数方法来实现进程的创建、(运行进程的)显示、换出、结束(杀死)与唤醒。
4.1.1进程的创建
//创建进程
void create(){
if(shumu>=20) printf("\n内存已满,请先换出或结束进程\n"); //内存容量大小设置为20
else{
int i;
printf("**当前默认一次性创建5个进程,内存容量20**");
for(i=0;i<5;i++) { //默认一次创建5个进程
//定位,找到可以还未创建的进程
if(neicun[i].zhuangtai==1) break; //如果找到的进程在内存则结束 ,初始设置都不在内存中(main函数中设置状态为0)
printf("\n请输入新进程pid\n");
scanf("%d",&(neicun[i].pid));
for(int j=0;j<i;j++)
if(neicun[i].pid==neicun[j].pid){
printf("\n该进程已存在\n");
return;
}
printf("请输入新进程优先级\n");
scanf("%d",&(neicun[i].youxian));
printf("请输入新进程大小\n");
scanf("%d",&(neicun[i].daxiao));
printf("请输入新进程内容\n");
scanf("%s",&(neicun[i].info));
//创建进程,使标记位为1
neicun[i].zhuangtai=1;
printf("进程已成功创建!");
shumu++;
}
}
}
(默认设置内存容量大小为20,一次性创建5个进程;进程创建时首先检测进程状态,若为1则表明该进程此前已在内存中了,不可再创建)
4.1.2进程的显示(运行状态检测)
//进程运行状态检测
void run(){
printf("运行进程信息如下:");
for(int i=0;i<20;i++){
if(neicun[i].zhuangtai==1){
//如果进程正在运行,则输出此运行进程的各个属性值
printf("\n pid=%d ",neicun[i].pid);
printf(" youxian=%d ",neicun[i].youxian);
printf(" daxiao=%d ",neicun[i].daxiao);
printf(" zhuanbgtai=%d ",neicun[i].zhuangtai);
printf(" info=%s ",neicun[i].info);
flag=1;
}
}
if(!flag)
printf("\n当前没有运行进程!\n");
}
4.1.3进程的换出
//进程换出
void huanchu(){
if(!shumu){
printf("当前没有运行进程!\n");
return;
}
printf("\n请输入换出进程的ID值");
scanf("%d",&pid);
for(int i=0;i<20;i++){
//定位,找到要换出的进程,根据其状态进行相应处理
if(pid==neicun[i].pid) {
if(neicun[i].zhuangtai==1){
neicun[i].zhuangtai==2;
guaqi++;
printf("\n已经成功换出进程\n");
}
else if(neicun[i].zhuangtai==0) printf("\n要换出的进程不存在\n");
else printf("\n要换出的进程已被挂起\n");
flag=1;
break;
}
}
//找不到,则说明进程不存在
if(flag==0) printf("\n要换出的进程不存在\n");
}
4.1.4进程的结束(杀死)
1 //结束(杀死)进程
2 void kill(){
3 if(!shumu){
4 printf("当前没有运行进程!\n");
5 return;
6 }
7 printf("\n输入杀死进程的ID值");
8 scanf("%d",&pid);
9 for(int i=0;i<20;i++){
10 //定位,找到所要杀死的进程,根据其状态做出相应处理
11 if(pid==neicun[i].pid){
12 neicun[i].zhuangtai = 0;
13 shumu--;
14 printf("\n已经成功杀死进程\n");
15 }
16 else if(neicun[i].zhuangtai==0) printf ("\n要杀死的进程不存在\n");
17 else printf("\n要杀死的进程已被挂起\n");
18 flag=1;
19 break;
20 }
21 //找不到,则说明进程不存在
22 if(!flag) printf("\n 要杀死的进程不存在\n");
23
24 }
4.1.5进程的唤醒
1 //唤醒进程
2 void huanxing(){
3 if (!shumu) {
4 printf("当前没有运行进程\n");
5 return;
6 }
7 if(!guaqi){
8 printf("\n当前没有挂起进程\n");
9 return;
10 }
11 printf("\n输入进程pid:\n");
12 scanf ("%d",&pid);
13 for (int i=0; i<20;i++) {
14 //定位,找到所要杀死的进程,根据其状态做相应处理
15 if (pid==neicun[i].pid) {
16 flag=false;
17 if(neicun[i].zhuangtai==2){
18 neicun[i].zhuangtai=1;
19 guaqi--;
20 printf ("\n已经成功唤醒进程\n");
21 }
22 else if(neicun[i].zhuangtai==0) printf("\n要唤醒的进程不存在\n");
23 else printf("\n要唤醒的进程已被挂起\n");
24 break;
25 }
26 }
27 //找不到,则说明进程不存在
28 if(flag) printf("\n要唤醒的进程不存在\n");
29 }
4.1.6 mian()函数
1 //主函数
2 int main()
3 {
4 int n = 1;
5 int num;
6 //一开始所有进程都不在内存中
7 for(int i=0;i<20;i++)
8 neicun[i].zhuangtai = 0;
9 while(n){
10 printf("\n******************************************");
11 printf("\n* 进程演示系统 *");
12 printf("\n******************************************");
13 printf("\n*1.创建新的进程 2.查看运行进程 *");
14 printf("\n*3.换出某个进程 4.杀死运行进程 *");
15 printf("\n*5.唤醒某个进程 6.退出系统 *");
16 printf("\n******************************************");
17 printf("\n请选择(1~6)\n");
18 scanf("%d",&num);
19 switch(num){
20 case 1: create();break;
21 case 2: run();break;
22 case 3: huanchu(); break;
23 case 4: kill();break;
24 case 5: huanxing(); break;
25 case 6: printf("已退出系统");exit(0);
26 default: printf("请检查输入数值是否在系统功能中1~6");n=0;
27 }
28 flag = 0;//恢复标记
29 }
30 return 0;
31 }
5.运行结果截图
(图1--初始运行状态界面)
(图2--选择功能1 创建新进程)
源程序一次性创建5个进程,内存容量为20。
(图3--依次输入创建进程的pid、优先级、大小、内容)
(图4--选择功能2 显示当前运行的进程)
(图5--换出进程 输入要换出的进程pid,换出后提示进程已换出)
(图6--杀死进程 输入要结束的进程pid,之后执行操作杀死此进程,再次查看运行进程时可以看到进程1已不在运行进程列)
(图7--唤醒进程 输入要唤醒的进程pid,之后该进程将被挂起)
(图8--退出系统 输入6,选择退出系统功,系统结束运行)
本文为课程实验记录,参考学校实验教材书籍,重在学习交流。
码字不易,走过路过点个赞吧(❁´◡`❁)
操作系统实验一:进程管理(含成功运行C语言源代码)的更多相关文章
- 操作系统(2)_进程管理_李善平ppt
所有程序都有CPU和io这两部分,即使没有用户输入也有输出. CPU最好特别忙,io空闲无所谓. 程序/数据/状态 三个维度来看进程. 等待的资源可能是io资源或者通信资源(别的进程的答复). 一个进 ...
- Linux进程管理专题
Linux进程管理 (1)进程的诞生介绍了如何表示进程?进程的生命周期.进程的创建等等? Linux支持多种调度器(deadline/realtime/cfs/idle),其中CFS调度器最常见.Li ...
- BUPT复试专题—进程管理(2014网研)
题目描述 在操作系统中,进程管理是非常重要的工作.每个进程都有唯一的进程标识PID.每个进程都可以启动子进程,此时我们称该它本身是其子进程的父进程.除PID为0的进程之外,每个进程冇且只冇一个父进程. ...
- Linux快速入门教程-进程管理ipcs命令学习
使用Linux系统必备的技能之一就是Linux进程管理,系统运行的过程正是无数进程在运行的过程.这些进程的运行需要占用系统的内存等资源,做好系统进程的管理,对于我们合理分配.使用系统资源有非常大的意义 ...
- 操作系统--进程管理(Processing management)
一.进程的组成 进程通常由程序.数据和进程控制块(Process Control Block,PCB)组成. 二. 进程的状态以及状态切换 进程执行时的间断性决定了进程可能具有多种状态,最基本的三种状 ...
- 十天学会CS之操作系统——进程管理01
进程管理01 进程的概念 进程是计算机中一个非常重要的概念,在整个计算机发展历史中,操作系统中程序运行机制的演变按顺序大致可以分为: 单道程序:通常是指每一次将一个或者一批程序(一个作业)从磁盘加载进 ...
- 服务器端配置nodejs环境(使用pm2进程管理运行)
一.brew安装: 由于Mac没有装ubantu,所以不能用apt-get命令,在本地命令行下Mac安装homebrew替代: https://brew.sh 二.新开命令窗口,登录root用户,安 ...
- Linux 操作系统(四)用户组管理&进程管理&任务调度
以下实例均在Centos7下验证 Centos7 查看命令帮助 man xxx 用户组管理 useradd useradd user1 password user1 cat /etc/passwd # ...
- Linux操作系统(6):进程管理和服务管理
进程的基本介绍 1)在 LINUX 中,每个执行的程序(代码)都称为一个进程.每一个进程都分配一个 ID 号. 2)每一个进程,都会对应一个父进程,而这个父进程可以复制多个子进程.例如 www 服务器 ...
随机推荐
- leetcode 1541. 平衡括号字符串的最少插入次数
问题描述 给你一个括号字符串 s ,它只包含字符 '(' 和 ')' .一个括号字符串被称为平衡的当它满足: 任何左括号 '(' 必须对应两个连续的右括号 '))' . 左括号 '(' 必须在对应的连 ...
- 系统信号SIGHUP、SIGQUIT、SIGTERM、SIGINT的场景
SIGHUP:hong up 挂断.本信号在用户终端连接(正常或非正常)结束时发出, 通常是在终端的控制进程结束时, 通知同一session内的各个作业, 这时它们与控制终端不再关联.登录Linux时 ...
- 【机器学习】HMM
机器学习算法-HMM 目录 机器学习算法-HMM 1. 模型定义 2. 序列生成 3. 概率计算 3.1 前向计算 3.2 后向计算 4. 学习 4.1 求解 4.2 求解 4.3 求解 5. 预测 ...
- unity3d inputfield标签控制台打印object
inputfield标签控制台打印object 这说明没有字符串给入 这是因为 inputfield下的text不能人为写入值,只能在game界面输入. 所以这个标签里的text做个默认值不好搞.
- nacos集群开箱搭建
记录/朱季谦 nacos是一款易于构建云原生应用的动态服务发现.配置管理和服务管理平台,简单而言,它可以实现类似zookeeper做注册中心的功能,也就是可以在springcloud领域替代Eurek ...
- MySQL的MyISAM与InnoDB的索引方式
在MySQL中,索引属于存储引擎级别的概念,不同存储引擎对索引的实现方式是不同的,本文主要讨论MyISAM和InnoDB两个存储引擎的索引实现方式. MyISAM索引实现 MyISAM引擎使用B+Tr ...
- gin中的SecureJSON 防止 json 劫持
使用 SecureJSON 防止 json 劫持.如果给定的结构是数组值或map,则默认预置 "while(1)," 到响应体. package main import ( &qu ...
- Spring中的单例模式
Spring中的单例模式 单例模式的介绍 1.1 简介 保证整个应用中某个实例有且只有一个 1.2作用 保证一个类仅有一个实例,并且提供一个访问它的全局访问点. 单例模式的优点和缺点 单例模式的优 ...
- python利用正则表达式提取文本中特定内容
正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配. Python 自1.5版本起增加了re 模块,它提供 Perl 风格的正则表达式模式. re 模块使 Python ...
- lambda表达式的学习
Lambda表达式 为什么使用lambda表达式 Lambda表达式可以简化我们的代码,使我们只需要关注主要的代码就可以. //测试用的实体类 public class Employee { priv ...