天天看點

什麼是分類分包,static關鍵字的使用-學生管理系統

作者:小謝吖

六 :環境搭建

建包
domain: 封裝學生資訊(存放标準類)
dao: 最直接的增删改查(和資料庫打交道)
serivce: 業務邏輯(複雜功能實作)
controller:排程(和前端打交道,接受使用者資料 并傳回響應資料)
entry: 展示(暫時代替使用者頁面)           

七 :菜單搭建

菜單搭建步驟
1 黑馬資訊管理系統菜單
2 學生管理系統菜單
3 switch 退出死循環的方法回顧
4 在學生管理中不能用結束jvm的方式,因為要傳回到 最初選擇學生或者老師管理的界面
//系統菜單
import com.itcast.manager1.controller.StuController;
import java.util.Scanner;
public class ManagerEntry {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (true){
System.out.println("歡迎使用管理系統");
System.out.println("請輸入您的選擇: 1 學生管理 2 老師管理 0 退出");
int choice = sc.nextInt();
switch(choice){
case 1:
StuController controller = new StuController();
controller.start();
break;
case 2:
System.out.println("歡迎使用老師管理系統");
break;
case 0:
System.out.println("歡迎再次使用!再見");
System.exit(0);
break;
default:
System.out.println("您輸入的有誤請從新輸入");
}
}
}
}
//學生菜單
package com.itcast.manager1.controller;
import java.util.Scanner;
public class StuController {

//學生管理系統開始使用
public void start() {
Scanner sc= new Scanner(System.in);
System.out.println("歡迎使用學生管理系統");
loop:while (true){
System.out.println("1 添加學生 2 删除學生 3 修改學生 4 檢視學生 0退出學生管理系統");
int choice = sc.nextInt();
switch (choice){
case 1:
break;
case 2:
break;
case 3:
break;
case 4:
break;
case 0:
System.out.println("退出學生管理系統");
break loop;
default:
System.out.println();
break;
}
}
}
}
           

八 :基本添加功能

步驟分析
Controller 層接受使用者添加的資料
service對資料進行業務處理
dao進行資料的儲存
儲存之後會有一個結果-->成功/失敗 把這個結果要告訴給他的上一層service
service在高速Controller 進而使用者得知添加結果是成功或者失敗           

九 :代碼實作

代碼實作過程
1 接受使用者資料: Controller
2 進行業務處理: Service 中進行 但是現在沒有什麼業務 就直接調用資料層存儲
3 存儲資料: 接受業務層傳遞的資料并儲存 資料層很單純,隻做資料的存入和取出
4 傳回結果
5 觀察參數的傳遞 和傳回值是如何回到controller
//Studentcontroller
//add
public void addStudent() {
Scanner sc= new Scanner(System.in);
//輸入資料
//判斷id是否存在(暫時先不做)
System.out.println("請輸入id");
String sid= sc.next();
System.out.println("請輸入name");
String sname = sc.next();
System.out.println("請輸入age");
String sage = sc.next();
System.out.println("請輸入birthday");
String sbirthday = sc.next();
//把錄入的資料封裝成學生對象
Student student = new Student(sid, sname, sage, sbirthday);
//把對象傳遞給業務層
StuService service = new StuService();
boolean flag = service.addStudent(student);
if(flag){
System.out.println("添加成功");
}else{
System.out.println("添加失敗");
}
}
--------------------------------------------------------------------------------
//Studentservice
public boolean addStudent(Student student) {
//建立dao
StuDao stuDao = new StuDao();
//向資料層傳遞學生對象
boolean flag = stuDao.addStudent(student);
//傳遞完畢之後,把添加是否成功的結果傳回
return flag;
}

//StudentDao
//添加
//建立存儲資料的容器
Student[] arr=new Student[10];
public boolean addStudent(Student student) {
/*
1 添加學生到數組
因為我不确定是第幾次添加,或者是否已經有别人添加過内容,是以數中的情況如下:
情況分析: 1 數組已經沒有位置了 傳回false表示添加失敗
2 數組中還有位置 找到該位置放入學生對象 傳回true 表示添加成功
是以我們首先要做的是判斷數組中是否還有位置能存儲學生對象
*/
//假設數組中沒有位置了
int index = -1;
//周遊數組取出每一個元素判斷是否有null
for (int i = 0; i < arr.length; i++) {
if(arr[i]==null){
//如果已經找到了為null的位置了 就把目前索引記錄下來 該位置就是你要新添加的對象的位置
//找到了之後就不用繼續往下找了 直接結束循環
index=i;
break;
}
}

/*
當循環結束之後 index 現在有兩種情況
1 循環結束 if條件成立了 找到了位置
2 循環結束 if條件沒有成立 沒有找到要存儲對象的位置
是以我們要進行判斷
*/
if(index==-1){
return false;
}
//存入對象到數組index索引上
arr[index]=student;
return true;
}           

十: 添加功能 -->學号判斷

代碼實作過程
1 接受使用者輸入的id 判斷該id是否在數組中存在(數組中的每個對象)
邏輯判斷-->業務
2 業務在service中寫 傳回一個布爾的結果

3 使用者輸入id判斷次數不限

4 擷取數組中的所有對象

5 周遊找每個對象的每個id

//StudentController
public void addStudent() {
StuService service = new StuService();
Scanner sc= new Scanner(System.in);
//輸入資料
//判斷id是否存在(暫時先不做)
//進行修改的地方++++++++++++++++++++++++++++++++++++++++++++++++++++
String sid;
while (true){
System.out.println("請輸入id");
sid= sc.next();
boolean result = service.exists(sid);
//如果傳回的是true表示該id已經存在不能使用
//如果傳回的是false表示該id沒有使用過,可以使用
if(!result){
break;
}
//如果if不成立表示id不能用
System.out.println("該id已經被使用請從新輸入!");
}
//進行修改的地方++++++++++++++++++++++++++++++++++++++++++++++++++++
System.out.println("請輸入name");
String sname = sc.next();
System.out.println("請輸入age");
String sage = sc.next();
System.out.println("請輸入birthday");
String sbirthday = sc.next();
//把錄入的資料封裝成學生對象
Student student = new Student(sid, sname, sage, sbirthday);
//把對象傳遞給業務層
boolean flag = service.addStudent(student);
if(flag){
System.out.println("添加成功");
}else{
System.out.println("添加失敗");
}
}
--------------------------------------------------------------------------------
//Studentserivce
//判斷id是否已經存在
public boolean exists(String sid) {
//修改的地方+++++++++++++++++++++++++++++++++++
StuDao stuDao = new StuDao(); //這句話提取到類的成員位置
//修改的地方+++++++++++++++++++++++++++++++++++
//擷取整個的數組
Student[] arr = stuDao.findAll();
for (int i = 0; i < arr.length; i++) {
Student s = arr[i];
//在判斷的時候數組定義的是10 但是不一定有十個資料 有也預設的null值
//如果不排除這種情況 那麼會報空指針異常
if (s != null && sid.equals(s.getId())) {
//如果在循環的過程中if成立了表明了在數組中這個sid 是已經存在了 直接傳回true
return true;
}
}
//如果循環結束能走到這裡表明上邊的if沒有成立也就說明sid沒有被占用 傳回false
return false;
}
-------------------------------------------------------------------------------------
//Studentdao
//傳回整個容器
public Student[] findAll() {
return arr;
}           

十一: 添加問題分析

大對象是由小對象組成的
每次建立大對象其組成的小對象也會跟着從新建立
在項目中根據功能盡可能的少建立對象,
對象的建立會浪費時間和性能
解決方案 1 把小對象提取到公共位置 變成大對象的一個成員屬性
不再每次在每個方法中都去new新的小對象
讓每個方法公用一個對象
2 使用static關鍵字 (新技術)           

十二: static 關鍵字

1.1 問題提問

1 static 關鍵字的意思

2 static 能修飾什麼

3 static 修飾的内容有什麼特點           

1.2 視訊時長

10分18秒           

1.3 問題答案

1 static 關鍵字的意思
靜态的意思 是一個狀态修飾符

2 static 能修飾什麼
成員方法 成員變量 代碼塊
被static修飾的成員變量叫 靜态變量(類變量)
被static修飾的成員方法叫 靜态方法
被static修飾的代碼塊叫 靜态代碼塊(後邊講)

3 static 修飾的内容有什麼特點
被static修飾的成員 會被該類的所有對象指派 (共享)
被static修飾的成員 會随着類的加載而加載--類加載
被static修飾的成員 可以通過類名.的形式調用
還是可以通過對象名.的方式去調用
(而且以後的用法也隻是通過類名.調同 不會去建立對象在調用)           

1.4 問題補充

詳細講解:
1 修飾屬性
靜态變量也叫類變量-->全類公有 直接用類名通路 (類名.屬性名)
class MyClass{
int a=10;
static int b=20;
}
public static void main(String[] args) {
MyClass m1=new MyClass();
MyClass m2=new MyClass();
m1.a++;
m1.b++;
System.out.println(m2.a); //判斷 m1 m2 分别是不同的對象有各自的 a屬性 是以m2的a值現在還是10
System.out.println(m2.b); //結果是21 因為b是靜态的
/*
m1 m2分别是不同的對象 當m1的對象的a屬性+1的時候 m2對象的a屬性還是 原來的10
但是b是static修飾的就是一個靜态變量
官方說話就是類變量 -- 類變量不在屬于某一個對象是全類共有的
也就是說m1 m2 共有一個類變量
是以當m1對象對類變量b進行+1之後 m2對象去通路的時候已經是21了
*/
//是全類共有的 直接用類名.通路
System.out.println(MyClass.b);
//同樣也能通路到 我們應該想到靜态b屬性是什麼時候才有的,
//我們知道執行個體變量是在建立對象的時候才初始化指派(不建立對象執行個體變量是不存在的)
}
*********************************************************************
/*
很顯然肯定不是在建立對象的時候初始化的b屬性,那靜态變量b是什麼時候有的呢--->類加載

我們說資料存在的基礎是必須把虛拟機啟動起來,把資料存在虛拟機的記憶體中,虛拟機啟動以後在程式執行的過程中肯定會用到很多的類比如JVM開始執行代碼 遇到了代碼 new A(); 這是讓JVM建立一個A類的對象,虛拟機得琢磨什麼是A類啊,怎麼去建立對象,A的父類是誰它的無參構造方法需要幹什麼,有那些個屬性需要初始化。 虛拟機無法獲知類的資訊。當虛拟機第一次遇到一個類的時候,不知道這個類是個 什麼東西,無法使用這個類。類的資訊包括(它的父類,屬性 方法 構造方法 分别都幹了些什麼)。隻有當虛拟機全部掌握了這個消息之後才能更好的去建立這個類,這個類的資訊在 A.java這個類中都能找到。 但是虛拟機不認識A.java檔案,虛拟機認識的是A.class檔案,這個檔案中存着類的全部資訊,虛拟機隻要把這個檔案中的内容讀進記憶體就能知道類的資訊了,就能很好的建立A對象了但是第二次遇到new A();呢 需要在從新讀一遍嗎。虛拟機不會那麼笨,以前見過一次了,它就會把這個類的資訊讀入虛拟機記憶體中儲存起來以後不不用再去讀取了。是以這個.class的讀取一般來說隻會做一次。而且是在第一次用到這個類的時候。這個過程就是類的加載

什麼叫類加載 簡單說:當虛拟機第一次使用一個類的時候,需要找到這個類對應的.class檔案,
把這個檔案中包含的類的資訊讀取到虛拟機記憶體并儲存,一般來說一個類隻會被加載一次

"類變量就是在類加載的時候配置設定空間 并且初始化的。"

類加載的時機:
通俗講: 1 建立類的對象的時候 也就是new
2 通路類的靜态成員(靜态屬性,靜态方法)
3 加載子類必須先加載父類
4 如果僅僅聲明引用是不會發生類加載 Student s;

局部變量-|
|--屬性|--執行個體變量- | 變量
類| |--類變量 -|
|
|--方法
*/
總結:
按照是否使用static修飾分為: 靜态屬性 vs 非靜态屬性(執行個體變量)
執行個體變量:我們建立了類的多個對象,每個對象都獨立的擁有一套類中的非靜态屬性,
當修改其中一個對象的非靜态屬性的時候,不會對其他對象造成影響
靜态變量:我們建立了類的多個對象,多個對象共享同一靜态變量,當通過某一個對象修改靜态變量時會導緻其他對象調用此靜态變量時,得到的是修改之後的結果

修飾屬性其他說明
> 靜态變量随着類的加載而加載
> 靜态變量的加載要早于對象的建立
使用: 通過"類名.靜态變量名" 調用
> 由于類隻會加載一次, 則靜态變量在記憶體中也隻會加載一次,存在一份 存在方法區 的靜态域中
>
類變量 : 通過類名(推薦,以後也是這樣用) 或者對象名去調用
執行個體變量: 隻能通過對象名去調用:

列舉: System.out
Math中的靜态方法
Arrays.toString();

記憶體圖解析:
public class Demo1 {
public static void main(String[] args) {
Person.nation = "china";
Person p1 = new Person();
p1.name = "張三";
p1.age = 19;
System.out.println(p1.nation);
p1.nation="中國";
Person p2 = new Person();
p1.name = "李四";
p1.age = 19;
System.out.println(p2.nation);
}
}
class Person {
String name;
int age;
static String nation;
}
*********************************************************************
2 方法
靜态方法:直接用類名調用 類名.方法名()
class MyClass{
int a=10;
static int b=20;
public static void print(){
System.out.println("喝喝");
}
public void m1(){
System.out.println("i am m1");
}
}
public class Test {
public static void main(String[] args) {
//調用靜态方法
MyClass.print();
//調用非靜态方法
MyClass mc=new MyClass();
mc.m1();
mc.print(); //也可以調用 但是這不是找費事嗎
}
}
//看下面一個例子

class MyClass{
int a=10;
static int b=20;
public static void print(){
//System.out.println(a);
//不能直接通路 類加載之後靜态成員初始化,但是非靜态的成員還沒有初始化
System.out.println(b);
//但是我可以建立對象去通路
MyClass mc=new MyClass();
System.out.println(mc.a);
}
}

public class Test {
public static void main(String[] args) {
MyClass.print(); // 通路類的靜态成員(靜态屬性,靜态方法)發生了類加載
}
}
總結:随着類的加載而加載,可以通過"類名.靜态方法名"的方式調用
普通方法隻能通過對象名去調用,
靜态方法可以通過類名(推薦,也是以後的寫法),對象名去調用

靜态方法中,隻能直接調用靜态的方法或者屬性,
非靜态方法中,既可以調用靜态方法和屬性也可以調用非靜态的屬性和方法

注意:
在靜态方法中,不能使用this,super關鍵字 (聲明周期問題)           

1.5 總結

開發中如何确定屬性和方法要加static
屬性:
不會随着對象的不同而不同, 可以被多個同一個類的對象所共享的
類中的常量也經常會聲明為static Math.PI
方法:
操作靜态屬性的方法通常會設定為靜态的
工具類中的方法習慣上聲明為static 比如 Math Arrays(構造方法都是私有的 強制使 用靜态           

十三: static 關鍵字的注意事項 學号問題解決

什麼是分類分包,static關鍵字的使用-學生管理系統

十四: 檢視所有學生:

思路分析
拿到所有學生資訊
Controller-->service-->dao-->傳回給service(業務邏輯判斷空)-->傳回給Controller展示
可以直接調用dao已經寫好的方法findAll()

//StudentController
public void queryAll() {
StuService service = new StuService();
Student[] arr = service.queryAll();
//判斷傳回數組是否是一個真正的數組還是一個null
if(arr==null){
System.out.println("暫無資料");
//如果是一個不存在的數組就直接結束方法 沒有必要再往下執行
return;
}
//周遊數組,
System.out.println("學号\t\t姓名\t年齡\t\t生日");
for (int i = 0; i < arr.length; i++) {
Student s = arr[i];
//數組定義的長度為10 但是不一定都裝滿了對象 可能還空着一部分,是以要加以判斷
if(s!=null){
//展示資料
System.out.println(s.getId()+"\t\t"+s.getName()+"\t"+
s.getAge()+"\t\t"+s.getBirthday());
}
}
}
---------------------------------------------------------------------------------------
//Studentservice
public Student[] queryAll() {
Student[] all = stuDao.findAll();
//判斷這個數組中是否有資料存在 不能用 if(all.length==0)
for (int i = 0; i < all.length; i++) {
Student s = all[i];
if(s!=null){
//隻要數組中存在一個資料 就傳回整個數組
return all;
}
}
//當循環結束表示數組中沒有資料直接傳回一個空
return null;
}           

十五: 删除功能的實作

思路分析
Controller接受要删除的學生的id 判斷是否存在 不存在則繼續錄入 (死循環)
Service 判斷學号是否存在 已經寫好 如果查到在寫一個删除方法
dao擷取所有資料推送給service 如果查到寫一個删除方法 删除數組中的對象 (根據索引删除 )

//StudentController删除學生的方法
public void deleteById() {
//使用者輸入的資料可能是錯的或者不存在的 是以不确定使用者輸入幾次能輸入正确
//還有如果使用者 在沒有添加資料的情況下就删除也是會有問題
//1 首先判斷數組中是否有學生
Student[] students = service.queryAll();
if(students==null){
System.out.println("暫時沒有學生資訊 請添加後重試");
return;
}
//2 如果數組中已經有學生了 開始輸入學生id 但是輸入幾次能正确不确定
//提升sid 的作用域範圍
String sid;
while (true) {
System.out.println("請輸入要删除的學生id");
sid = sc.next();
//判斷sid所在的對象在數組中是否存在
boolean exists = service.exists(sid);
//傳回true 表示存在 傳回false 表示不存在
if(exists){
break; //表示存在的就結束循環
}else{
System.out.println("要删除的學生不存在 請從新輸入");
}
}
//當循環結束表示已經輸入了一個存在的學生的id
service.delete(sid);
System.out.println("删除成功");
}
-----------------------------------------------------------------------------------
//Studentservice 根據id進行删除
public void delete(String sid) {
stuDao.delete(sid);
}
-----------------------------------------------------------------------------------
//Studentdao delete
public void delete(String sid) {
//找到該sid對象所在數組的索引位置
int index = getIndex(sid);
//把該位置的對象置為null
arr[index]=null;
//如果想數組中的資料是連貫的可以嘗試如下代碼 把置空的位置的後邊存在的資料前移
/*
for (int i = index+1; i < arr.length; i++) {
Student s=arr[i];
if(s!=null){
//把對象向前挪動直接就覆寫了前一個位置的值
arr[index]=s;
//清空目前索引 位置的對象
arr[i]=null;
index++;
}
}
*/
}

private int getIndex(String sid) {
//其實在這直接可以定義
//int index; 因為走到這的時候已經能确定sid這個id對象是存在的, 隻需要找到在數組中的索引位置即可
int index=-1;
for (int i = 0; i < arr.length; i++) {
Student s = arr[i];
//如果數組中沒有滿會存在null預設值
if(s!=null && s.getId().equals(sid)){
index=i;
}
}
return index;
}           

十六: 修改功能

思路分析
1 Controller接受要修改的id 不存在從新輸入
存在 把要修改的資訊從新封裝為學生對象
2 service中 填寫修7改方法
3 dao中 修改數組
//Studentcontroller
public void updateById() {
//首先判斷數組是否有資料
Student[] students = service.queryAll();
if(students==null){
System.out.println("暫時沒有學生資訊 請添加後重試");
return;
}
//如果存在資料 就輸入要修改的學生的id
String sid;
while (true){
System.out.println("請輸入要修改的學生的id");
sid = sc.next();
//判斷該sid是否在集合中存在對象
boolean exists = service.exists(sid);
//傳回true 表示存在 傳回false表示不存在
if(exists){
break;
}else{
System.out.println("您要修改的學生不存在 請從新輸入");
}
}
//開始修改對象
//錄入新的資訊
System.out.println("請輸入name");
String name = sc.next();
System.out.println("請輸入age");
String age = sc.next();
System.out.println("請輸入bir");
String bir = sc.next();
//建立新的對象 id 還是原來的id
Student s = new Student(sid, name, age, bir);
//用s對象替換sid對象所在索引位置的老對象
//其實也可以直接傳遞對象 s 的sid 和查找的老對象的sid是一樣的
service.update(s,sid);
System.out.println("修改成功");
}
--------------------------------------------------------------------------------
//Studentservice
public void update(Student s, String sid) {
stuDao.update(s,sid);
}
--------------------------------------------------------------------------------
//Studentdao
public void update(Student s, String sid) {
//1 找到sid對象所在的索引
//int index = getIndex(s.getId());
int index = getIndex(sid);
arr[index]=s;
}           

十七: 管理系統代碼優化

1減少備援代碼:如果是功能邏輯相同的代碼有兩段或者以上的時候應該抽取成一個方法 供使用的地方調用

2選中重複的代碼 使用 ctrl+alt+m 抽取代碼 一般一個類中重複代碼抽取的方法隻是供本類使用 是以方法是私有的
//該方法傳回正确的要删除或者修改的學生的id
public String inputStu() {
String sid;
while (true) {
System.out.println("請輸入要删除的學生id");
sid = sc.next();
//判斷sid所在的對象在數組中是否存在
boolean exists = service.exists(sid);
//傳回true 表示存在 傳回false 表示不存在
if(exists){
break; //表示存在的就結束循環
}else{
System.out.println("要删除的學生不存在 請從新輸入");
}
}
return sid;
}

//該方法傳回一個學生對象
public Student inputStudentInfo(String sid) {
System.out.println("請輸入name");
String name = sc.next();
System.out.println("請輸入age");
String age = sc.next();
System.out.println("請輸入bir");
String bir = sc.next();
//建立新的對象 id 還是原來的id
return new Student(sid, name, age, bir);
}           

十八: 老師管理系統

獨立完成           

繼續閱讀