JAVA 基礎知識學習21

目錄

01項目訓練目標

* A: 項目訓練目標
    * a: 項目目標
        * 綜合運用前面所學習的知識點
        * 熟練View層、Service層、Dao層之間的方法相互調用操作、
        * 熟練dbutils操作數據庫表完成增刪改查
        * 瞭解公司項目開發的流程,充分的掌握項目需求分析、設計與功能的代碼實現。提高同學們獨立分析需求與功能實現的能力。           

02項目中的功能模塊

* A: 項目中的功能模塊   
    * a: 五大模塊
        * 查詢賬務
        * 多條件組合查詢賬務
        * 添加賬務
        * 編輯賬務
        * 刪除賬務

03技術的選擇和相關jar包

* A: 技術的選擇和相關jar包
    * a: apache的commons組件:
        * commons-dbutils-1.4.jar:封裝並簡化了JDBC;
        * commons-dbcp-1.4.jar:apache commons提供的數據庫連接池組件,命名爲DBCP;
    * b: commons.pool-1.3.jar:DBCP連接池依賴該jar包;
        * mysql-connector-java-5.1.28-bin.jar:MySQL的JDBC驅動包,用JDBC連接MySQL數據庫必須使用該JAR包。

04項目中的工具類

* A: 項目中的工具類
    * a: 工具類的介紹 
        * 每個項目中都會有很多個工具類,不要求每個工具類對能獨立寫出來,但是要會使用工具類
        * JDBCUtils:用來創建數據庫連接池對象

05數據表的設計

* A: 數據表的設計
    * a: 數據表的設計(詳見:day34_source/表關係.JPG)
        * 表與表之間是有關係的
        * 主表和從表的關係
        * 主表中的主鍵作爲從表中的外鍵

06創建數據庫數據表寫入測試數據

* A: 創建數據庫數據表寫入測試數據
    * a: 創建數據庫數據表
    /*
              創建管家婆的數據庫
              名字 gjp
            */
            CREATE DATABASE gjp;

            USE gjp;

            /*
              創建數據表,表名賬務
              字段,列
              主鍵
              分類名稱  可變字符
              金額  double
              賬戶  可變字符 (支付,收入方法)
              創建日期 date
              賬務描述 可變字符
            */

            CREATE TABLE gjp_zhangwu(
               -- 主鍵
               zwid INT PRIMARY KEY AUTO_INCREMENT,
               -- 分類名稱   
               flname VARCHAR(200),
               -- 金額
               money DOUBLE,
               -- 賬戶
               zhanghu VARCHAR(100),
               -- 創建日期
               createtime DATE,
               -- 賬務描述
               description  VARCHAR(1000)
            );
            SELECT * FROM gjp_zhangwu;
        * b: 寫入數據
            -- 寫入測試的數據
            INSERT  INTO gjp_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (1,'喫飯支出',247,'交通銀行','2016-03-02','家庭聚餐');
            INSERT  INTO gjp_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (2,'工資收入',12345,'現金','2016-03-15','開工資了');
            INSERT  INTO gjp_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (3,'服裝支出',1998,'現金','2016-04-02','買衣服');
            INSERT  INTO gjp_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (4,'喫飯支出',325,'現金','2016-06-18','朋友聚餐');
            INSERT  INTO gjp_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (5,'股票收入',8000,'工商銀行','2016-10-28','股票大漲');
            INSERT  INTO gjp_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (6,'股票收入',5000,'工商銀行','2016-10-28','股票又大漲');
            INSERT  INTO gjp_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (7,'工資收入',5000,'交通銀行','2016-10-28','又開工資了');
            INSERT  INTO gjp_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (8,'禮金支出',5000,'現金','2016-10-28','朋友結婚');
            INSERT  INTO gjp_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (9,'其他支出',1560,'現金','2016-10-29','丟錢了');
            INSERT  INTO gjp_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (10,'交通支出',2300,'交通銀行','2016-10-29','油價還在漲啊');
            INSERT  INTO gjp_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (11,'喫飯支出',1000,'工商銀行','2016-10-29','又喫飯');
            INSERT  INTO gjp_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (12,'工資收入',1000,'現金','2016-10-30','開資');
            INSERT  INTO gjp_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (13,'交通支出',2000,'現金','2016-10-30','機票好貴');
            INSERT  INTO gjp_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (14,'工資收入',5000,'現金','2016-10-30','又開資');

07項目中的分層設計

* A: 項目中的分層設計
    * a: 各層功能介紹
        * view層作用: 視圖層,即項目中的界面
        * controller層作用: 控制層, 獲取界面上的數據,爲界面設置數據; 將要實現的功能交給業務層處理
        * service層作用: 業務層, 功能的實現, 與controller控制層和數據訪問層DAO交互, 將對數據庫的操作交給DAO數據訪問層來處理
        * dao層作用: 數據訪問層, 用來操作數據庫表的數據
        * db數據庫: 這裏指MySQL
        * domain 實體包: 存放JavaBean
        * tools工具包:存放項目中使用到的工具類
        * test 測試包: 存放項目功能測試的代碼

08創建項目分層導入jar包

* A: 創建項目_分層_導入jar包
    * a: 創建工程包
        * cn.itcast.gjp.app: 存放main方法類;
        * cn.itcast.gjp.domain: 存放JavaBean;
        * cn.itcast.gjp.view: 存放界面,及表現層類;
        * cn.itcast.gjp.service: 存放業務層類;
        * cn.itcast.gjp.dao: 存放數據訪問層類;
        * cn.itcast.gjp.tools:存放工具類
    * b: 導入jar包
        * 在項目根路徑下建立文件夾lib
        * 導入以下jar包
            * mysql-connector-java-5.1.37-bin.jar:數據庫驅動
            * commons-dbutils-1.6.jar:提供QueryRunner類方便進行增刪改查操作
            * commons-dbcp-1.4.jar:
            * commons-pool-1.5.6.jar:提供高效的數據庫連接池技術              
        * 拷貝以上jar包,選定拷貝的jar包/右鍵/Build Path/Add to Build Path

09創建domain包中的類

* A: 創建domain包中的類
    * a: 案例代碼
    public class ZhangWu {
                 private int  zwid;

                 private String flname; 

                 private double  money; 

                 private String zhanghu;

                 private String createtime; 

                 private String description;
                 //注意生成空參構造、有參構造、set和get方法、toString方法等
            }

10創建JDBCUtils工具類

* A:創建JDBCUtils工具類
    * a: 案例代碼
    public class JDBCUtils{
                //創建BasicDataSource對象
                private static BasicDataSource datasource = new BasicDataSource();
                //靜態代碼塊,實現必要參數設置
                static{
                    datasource.setDriverClassName("com.mysql.jdbc.Driver");
                    datasource.setUrl("jdbc:mysql://localhost:3306/gjp");
                    datasource.setUsername("root");
                    datasource.setPassword("123");
                    datasource.setMaxActive(10);
                    datasource.setMaxIdle(5);
                    datasource.setMinIdle(2);
                    datasource.setInitialSize(10);
                }
                public static DataSource getDataSource(){
                    return datasource;
                }
            }

11創建其他包中的類

* A: 創建其他包中的類
    * a: cn.itcast.gjp.dao包中創建ZhangWuDao類
            /*
             *  實現對數據表 gjp_zhangwu 數據增刪改查操作
             *  dbuils工具類完成,類成員創建QueryRunner對象,指定數據源
             */
            public class ZhangWuDao {
                private QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
            }
        * b: cn.itcast.gjp.service包中創建ZhangWuService類
            /*
             *  業務層類
             *  接收上一層,控制層controller的數據
             *  經過計算,傳遞給dao層,操作數據庫
             *  調用dao層中的類,類成員位置,創建Dao類的對象
             */
            public class ZhangWuService {
                private ZhangWuDao dao = new ZhangWuDao();

            }
        * c: cn.itcast.gjp.controller包中建立ZhangWuController類
            /*
             *  控制器層
             *  接收視圖層的數據,數據傳遞給service層
             *  成員位置,創建service對象
             */
            public class ZhangWuController {
                private ZhangWuService service = new ZhangWuService();              
            }
        * d: cn.itcast.gjp.view包中建立MainView類
            /*
             *  試圖層,用戶看到和操作的界面
             *  數據傳遞給controller層實現
             *  成員位置,創建controller對象
             */
            public class MainView {
                private ZhangWuController controller = new ZhangWuController();

            }
        * e: cn.itcast.gjp.app包中建立MainApp類
            /*
             *  主程序類,作用,開啓軟件程序
             */
            public class MainApp {
                public static void main(String[] args) {
                    new MainView().run();
                }
            }

12實現用戶的界面菜單

* A: 實現用戶的界面菜單
    * a: 案例核心代碼
    * cn.itcast.gjp.view包中建立MainView類中添加run方法
            /*
             *  實現界面效果
             *  接收用戶的輸入
             *  根據數據,調用不同的功能方法
             */
            public void run(){
                //創建Scanner類對象,反覆鍵盤輸入
                Scanner sc = new Scanner(System.in);
                while(true){
                    System.out.println("---------------管家婆家庭記賬軟件---------------");
                    System.out.println("1.添加賬務 2.編輯賬務 3.刪除賬務 4.查詢賬務 5.退出系統");
                    System.out.println("請輸入要操作的功能序號[1-5]:");
                    //接收用戶的菜單選擇
                    int choose = sc.nextInt();
                    //對選擇的菜單判斷,調用不同的功能
                    switch(choose){
                    case 1:
                       // 選擇添加賬務,調用添加賬務的方法
                        break;
                    case 2:
                        // 選擇的編輯賬務,調用編輯賬務方法
                        break;
                    case 3:
                        // 選擇的刪除賬務,調用刪除賬務方法
                        break;
                    case 4:
                        // 選擇的是查詢賬務,調用查詢方法
                        //selectZhangWu();
                        break;
                    case 5:
                        System.exit(0);
                        break;
                    }
                }
            }

13實現查詢的界面菜單

* A: 實現查詢的界面菜單
        * a: 案例核心代碼
            *  cn.itcast.gjp.view包中建立MainView類中添加selectZhangWu方法、selectAll方法、select方法
                /*
                 * 定義方法 selectZhangWu()
                 * 顯示查詢的方式 1 所有查詢   2 條件查詢
                 * 接收用戶的選擇
                 */
                 public void selectZhangWu(){
                     System.out.println("1. 查詢所有    2. 條件查詢");
                     Scanner sc = new Scanner(System.in);
                     int selectChooser = sc.nextInt();
                     //判斷根據用戶的選擇,調用不同的功能
                     switch(selectChooser){
                     case 1:
                         //選擇的查詢所有,調用查詢所有的方法
                         selectAll();
                         break;
                     case 2:
                         //選的條件查詢,調用帶有查詢條件的方法
                         select();
                         break;
                     }
                 }
                 /*
                  * 定義方法,實現查詢所有的賬務數據
                  */
                 public void selectAll(){

                 }

                 /*
                  * 定義方法,實現條件查詢賬務數據
                  * 提供用戶的輸入日期,開始日期結束日期
                  * 就2個日期,傳遞到controller層
                  * 調用controller的方法,傳遞2個日期參數
                  * 獲取到controller查詢的結果集,打印出來
                  */
                 public void select(){

                 }

14實現查詢所有賬務的控制,業務層的實現

* A: 實現查詢所有賬務的控制,業務層的實現
    * a: 案例核心代碼
            * a: cn.itcast.gjp.dao包中創建ZhangWuDao類
            /*
             *  實現對數據表 gjp_zhangwu 數據增刪改查操作
             *  dbuils工具類完成,類成員創建QueryRunner對象,指定數據源
             */
            public class ZhangWuDao {
                private QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
                /*
                 * 定義方法,查詢數據庫,獲取所有的賬務數據
                 * 方法,由業務層調用
                 * 結果集,將所有的賬務數據,存儲到Bean對象中,存儲到集合中
                 */
                public List<ZhangWu> selectAll(){                   
                    return null;
                }
            }
            * b: cn.itcast.gjp.service包中創建ZhangWuService類
                /*
                 *  業務層類
                 *  接收上一層,控制層controller的數據
                 *  經過計算,傳遞給dao層,操作數據庫
                 *  調用dao層中的類,類成員位置,創建Dao類的對象
                 */
                public class ZhangWuService {
                    private ZhangWuDao dao = new ZhangWuDao();
                    /*
                     *  定義方法,實現查詢所有的賬務數據
                     *  此方法,由控制層調用, 去調用dao層的方法
                     *  返回存儲ZhangWu對象的List集合
                     */
                    public List<ZhangWu> selectAll(){
                        return dao.selectAll();
                    }
                }
            * c: cn.itcast.gjp.controller包中建立ZhangWuController類
                /*
                 *  控制器層
                 *  接收視圖層的數據,數據傳遞給service層
                 *  成員位置,創建service對象
                 */
                public class ZhangWuController {
                    private ZhangWuService service = new ZhangWuService();      
                    /*
                     * 控制層類定義方法,實現查詢所有的賬務數據
                     * 方法由試圖層調用,方法調用service層
                     */
                    public List<ZhangWu> selectAll(){
                        return service.selectAll();
                    }                   
                }

###15實現查詢所有賬務的dao層的實現
    * A: 實現查詢所有賬務的dao層的實現
        * a: 案例核心代碼
            * a: cn.itcast.gjp.dao包中創建ZhangWuDao類selectAll方法
            /*
             *  實現對數據表 gjp_zhangwu 數據增刪改查操作
             *  dbuils工具類完成,類成員創建QueryRunner對象,指定數據源
             */
            public class ZhangWuDao {
                private QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
                /*
                 * 定義方法,查詢數據庫,獲取所有的賬務數據
                 * 方法,由業務層調用
                 * 結果集,將所有的賬務數據,存儲到Bean對象中,存儲到集合中
                 */
                public List<ZhangWu> selectAll(){
                    try{
                        //查詢賬務數據的SQL語句
                            String sql = "SELECT * FROM gjp_zhangwu";
                            //調用qr對象的方法,query方法,結果集BeanListHandler
                            List<ZhangWu> list = qr.query(sql, new BeanListHandler<>(ZhangWu.class));
                            return list;
                        }catch(SQLException ex){
                            System.out.println(ex);
                            throw new RuntimeException("查詢所有賬務失敗");
                        }
                }
            }

16實現查詢所有賬務的view層的實現

* A: 實現查詢所有賬務的view層的實現
    * a: 案例核心代碼
            * cn.itcast.gjp.view包中建立MainView類selectAll方法
            /*
              * 定義方法,實現查詢所有的賬務數據
              */
             public void selectAll(){
                 //調用控制層中的方法,查詢所有的賬務數據
                 List<ZhangWu> list = controller.selectAll();
                //輸出表頭
                 System.out.println("ID\t\t類別\t\t賬戶\t\t金額\t\t時間\t\t說明");
                 //遍歷集合,結果輸出控制檯
                 for(ZhangWu zw : list){
                     System.out.println(zw.getZwid()+"\t\t"+zw.getFlname()+"\t\t"+zw.getZhanghu()+"\t\t"+
                     zw.getMoney()+"\t\t"+zw.getCreatetime()+"\t"+zw.getDescription());
                 }
             }

###17實現條件查詢賬務的菜單實現
    * A: 實現條件查詢賬務的菜單實現
        * a: 案例核心代碼
            * cn.itcast.gjp.view包中建立MainView類select方法
              /*
              * 定義方法,實現條件查詢賬務數據
              * 提供用戶的輸入日期,開始日期結束日期
              * 就2個日期,傳遞到controller層
              * 調用controller的方法,傳遞2個日期參數
              * 獲取到controller查詢的結果集,打印出來
              */
             public void select(){
                 System.out.println("選擇條件查詢,輸入日期格式XXXX-XX-XX");
                 Scanner sc = new Scanner(System.in);
                 System.out.print("請輸入開始日期:");
                 String startDate = sc.nextLine();
                 System.out.print("請輸入結果日期:");
                 String endDate = sc.nextLine();
                 //調用controller層的方法,傳遞日期,獲取查詢結果集

             }

18實現條件查詢賬務的控制層,業務層實現

* A: 實現條件查詢賬務的控制層,業務層實現
        * a: 案例核心代碼
            * a: cn.itcast.gjp.dao包中創建ZhangWuDao類
                /*
                 *  實現對數據表 gjp_zhangwu 數據增刪改查操作
                 *  dbuils工具類完成,類成員創建QueryRunner對象,指定數據源
                 */
                public class ZhangWuDao {
                    private QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
                    /*
                     * 定義方法,查詢數據庫,帶有條件去查詢賬務表
                     * 由業務層調用,查詢結果集存儲到Bean對象,存儲到List集合
                     * 調用者傳遞2個日期字符串
                     */
                    public List<ZhangWu> select(String startDate,String endDate){
                        return null;
                    }
                }
            * b: cn.itcast.gjp.service包中創建ZhangWuService類
                /*
                 *  業務層類
                 *  接收上一層,控制層controller的數據
                 *  經過計算,傳遞給dao層,操作數據庫
                 *  調用dao層中的類,類成員位置,創建Dao類的對象
                 */
                public class ZhangWuService {
                    private ZhangWuDao dao = new ZhangWuDao();
                    /*
                     * 定義方法,實現條件查詢賬務
                     * 方法由控制層調用,傳遞2個日期字符串
                     * 調用dao層的方法,傳遞2個日期字符串
                     * 獲取到查詢結果集
                     */
                    public List<ZhangWu> select(String startDate,String endDate){
                        return dao.select(startDate, endDate);
                    }
                }
            * c: cn.itcast.gjp.controller包中建立ZhangWuController類
                /*
                 *  控制器層
                 *  接收視圖層的數據,數據傳遞給service層
                 *  成員位置,創建service對象
                 */
                public class ZhangWuController {
                    private ZhangWuService service = new ZhangWuService();      
                    /*
                     * 定義方法,實現條件查詢賬務
                     * 方法由試圖層調用,傳遞兩個日期的字符串
                     * 調用service層的方法,傳遞兩個日期字符串,獲取結果集
                     * 結果集返回給試圖
                     */
                    public List<ZhangWu> select(String startDate,String endDate){
                        return service.select(startDate, endDate);
                    }                   
                }

19實現條件查詢賬務的dao層實現

* A: 實現條件查詢賬務的dao層實現
        * a: 案例核心代碼
            * a: cn.itcast.gjp.dao包中創建ZhangWuDao類select方法
                /*
                 *  實現對數據表 gjp_zhangwu 數據增刪改查操作
                 *  dbuils工具類完成,類成員創建QueryRunner對象,指定數據源
                 */
                public class ZhangWuDao {
                    private QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
                    /*
                     * 定義方法,查詢數據庫,帶有條件去查詢賬務表
                     * 由業務層調用,查詢結果集存儲到Bean對象,存儲到List集合
                     * 調用者傳遞2個日期字符串
                     */
                    public List<ZhangWu> select(String startDate,String endDate){
                        try{
                            //拼寫條件查詢的SQL語句
                            String sql = "SELECT * FROM gjp_zhangwu WHERE createtime BETWEEN ? AND ?";
                            //定義對象數組,存儲?佔位符
                            Object[] params = {startDate,endDate};
                            //調用qr對象的方法query查詢數據表,獲取結果集
                            return qr.query(sql, new BeanListHandler<>(ZhangWu.class),params);
                        }catch(SQLException ex){
                            System.out.println(ex);
                            throw new RuntimeException("條件查詢失敗");
                        }
                    }
                }

20實現條件查詢賬務的view層實現

* A: 實現條件查詢賬務的view層實現
        * a: 案例核心代碼
            * cn.itcast.gjp.view包中建立MainView類selectAll方法優化、抽取print方法、select方法
            /*
              * 定義方法,實現查詢所有的賬務數據
              */
             public void selectAll(){
                 //調用控制層中的方法,查詢所有的賬務數據
                 List<ZhangWu> list = controller.selectAll();
                 if(list.size()!=0)
                     print(list);
                 else
                     System.out.println("沒有查詢到數據");
             }

             /*
              * 定義方法,實現條件查詢賬務數據
              * 提供用戶的輸入日期,開始日期結束日期
              * 就2個日期,傳遞到controller層
              * 調用controller的方法,傳遞2個日期參數
              * 獲取到controller查詢的結果集,打印出來
              */
             public void select(){
                 System.out.println("選擇條件查詢,輸入日期格式XXXX-XX-XX");
                 Scanner sc = new Scanner(System.in);
                 System.out.print("請輸入開始日期:");
                 String startDate = sc.nextLine();
                 System.out.print("請輸入結果日期:");
                 String endDate = sc.nextLine();
                 //調用controller層的方法,傳遞日期,獲取查詢結果集
                 List<ZhangWu> list = controller.select(startDate, endDate);
                 if(list.size()!=0)
                     print(list);
                 else
                     System.out.println("沒有查詢到數據");
             }

             //輸出賬務數據方法,接收List集合,遍歷集合,輸出表格
             private void print(List<ZhangWu> list) {
                    //輸出表頭
                     System.out.println("ID\t\t類別\t\t賬戶\t\t金額\t\t時間\t\t說明");
                     //遍歷集合,結果輸出控制檯
                     for(ZhangWu zw : list){
                         System.out.println(zw.getZwid()+"\t\t"+zw.getFlname()+"\t\t"+zw.getZhanghu()+"\t\t"+
                         zw.getMoney()+"\t\t"+zw.getCreatetime()+"\t"+zw.getDescription());
                     }
                }

21添加賬務功能分析

* A: 添加賬務功能分析
    * a: 編寫MainView類中addZhangWu方法
        * 鍵盤輸入新添加的賬務信息
        * 調用ZhangWuService類中addZhangWu方法,用來指定賬務的添加
        * 添加完畢後,使用輸出語句,提示“添加賬務成功!”
    * b: 編寫ZhangWuService類中addZhangWu方法
        * 調用ZhangWuDao類中addZhangWu方法,用來指定賬務的添加
    * c: 編寫ZhangWuDao類中addZhangWu方法
        * 通過QueryRunner對象,調用update方法更新數據庫表gjp_zhangwu,完成指定賬務添加到數據庫表中

22添加賬務功能菜單和輸入功能實現

* A: 添加賬務功能菜單和輸入功能實現    
    * a: 案例核心代碼
    * cn.itcast.gjp.view包中建立MainView類addZhangWu方法
            /*
             * 定義方法addZhangWu
             * 添加賬務的方法,用戶在界面中選擇菜單1的時候調用、
             * 實現思想:
             *    接收鍵盤輸入,5項輸入,調用controller層方法
             */
            public void addZhangWu() {
                System.out.println("選擇的添加賬務功能,請輸入以下內容");
                Scanner sc = new Scanner(System.in);
                System.out.println("輸入分類名稱");
                String flname = sc.next();
                System.out.println("輸入金額");
                double money = sc.nextDouble();
                System.out.println("輸入賬戶");
                String zhanghu = sc.next();
                System.out.println("輸入日期:格式XXXX-XX-xx");
                String createtime = sc.next();
                System.out.println("輸入具體描述");
                String description = sc.next();
                //將接收到的數據,調用controller層的方法,傳遞參數,實現數據添加

            }

23添加賬務功能控制層,業務層實現

* A: 添加賬務功能控制層,業務層實現
    * a: 案例核心代碼
* cn.itcast.gjp.controller包中的ZhangWuController類addZhangWu方法
                /*
                 * 定義方法,實現賬務添加功能
                 * 由視圖層調用,傳遞參數(傳遞過來的參數不能是5個數據,傳遞的是一個ZhangWu類型的對象)
                 * 本方法調用service層的方法,傳遞ZhangWu對象,獲取到添加後的結果集(添加成功影響的行數,int)
                 * 
                 */
                public void addZhangWu(ZhangWu zw) {
                    service.addZhangWu(zw);
                }
            * cn.itcast.gjp.service包中的ZhangWuService類addZhangWu方法
                /*
                 * 定義方法,實現添加賬務
                 * 是由控制層調用,傳遞ZhangWu對象
                 */
                public void addZhangWu(ZhangWu zw) {
                    dao.addZhangWu(zw);
                }
            * cn.itcast.gjp.dao包中的ZhangWuDao類addZhangWu方法
                /*
                 * 定義方法,實現添加賬務功能
                 * 由業務層調用,傳遞ZhangWu對象
                 * 將ZhangWu對象中的數據,添加到數據庫
                 */
                public void addZhangWu(ZhangWu zw) {

                }

24添加賬務功能dao層實現

* A: 添加賬務功能dao層實現
    * a: 案例核心代碼 
    * cn.itcast.gjp.dao包中的ZhangWuDao類的addZhangWu方法
                public void addZhangWu(ZhangWu zw) {
                    try{
                         //拼接添加數據的sql
                        String sql = "INSERT INTO gjp_zhangwu (flname,money,zhanghu,createtime,description) VALUES(?,?,?,?,?)";
                        //創建對象數組,處處5個佔位符的實際參數
                        //實際參數來源是傳遞過來的對象ZhangWu
                        Object[] params = {zw.getFlname(),zw.getMoney(),zw.getZhanghu(),zw.getCreatetime(),zw.getDescription()};
                        //調用qr對象中的方法update執行添加
                        qr.update(sql, params);
                    }catch(SQLException ex) {
                        System.out.println(ex);
                        throw new RuntimeException("賬務添加失敗");
                    }
                }

25添加賬務功能view層實現

* A: 添加賬務功能view層實現
        * a: 案例核心代碼
            * cn.itcast.gjp.view包中建立MainView類addZhangWu方法
                public void addZhangWu() {
                    System.out.println("選擇的添加賬務功能,請輸入以下內容");
                    Scanner sc = new Scanner(System.in);
                    System.out.println("輸入分類名稱");
                    String flname = sc.next();
                    System.out.println("輸入金額");
                    double money = sc.nextDouble();
                    System.out.println("輸入賬戶");
                    String zhanghu = sc.next();
                    System.out.println("輸入日期:格式XXXX-XX-xx");
                    String createtime = sc.next();
                    System.out.println("輸入具體描述");
                    String description = sc.next();
                    //將接收到的數據,調用controller層的方法,傳遞參數,實現數據添加
                    //將用戶輸入的所有參數,封裝成ZhangWu對象
                    ZhangWu zw = new ZhangWu(0, flname, money, zhanghu, createtime, description);
                    controller.addZhangWu(zw);
                    System.out.println("恭喜添加賬務成功");
                }

26編輯賬務功能分析

* A: 編輯賬務功能分析
    * a: 編寫MainView類中editZhangWu方法
        * 鍵盤輸入要編輯的賬務信息ID號
        * 鍵盤輸入要修改的賬務信息內容
        * 調用ZhangWuService類中editZhangWu方法,用來將指定的賬務信息進行更新
        * 更新完畢後,使用輸出語句,提示 “編輯賬務成功!”
    * b: 編寫ZhangWuService類中editZhangWu方法
        * 調用ZhangWuDao類中editZhangWu方法,用來將指定的賬務信息進行更新
    * c: 編寫ZhangWuDao類中editZhangWu方法
        * 通過QueryRunner對象,調用update方法更新數據庫表gjp_zhangwu,完成數據庫表中指定賬務更新操作

27編輯賬務功能功能之前實現查詢所有

* A: 編輯賬務功能功能之前實現查詢所有
    * a: 案例核心代碼
        * cn.itcast.gjp.view包中建立MainView類editZhangWu方法
            public void editZhangWu() {
                //調用查詢所有賬務數據的功能,顯示出來
                //看到所有數據,從中選擇一項,進行修改
                selectAll();
                System.out.println("選擇的是編輯功能,請輸入數據");


            }

28編輯賬務功能菜單實現

* A: 編輯賬務功能菜單實現
    * a: 案例核心代碼
    * cn.itcast.gjp.view包中建立MainView類editZhangWu方法
                public void editZhangWu() {
                    //調用查詢所有賬務數據的功能,顯示出來
                    //看到所有數據,從中選擇一項,進行修改
                    selectAll();
                    System.out.println("選擇的是編輯功能,請輸入數據");
                    Scanner sc = new Scanner(System.in);
                    System.out.print("請輸入ID");
                    int zwid = sc.nextInt();
                    System.out.println("輸入分類名稱");
                    String flname = sc.next();
                    System.out.println("輸入金額");
                    double money = sc.nextDouble();
                    System.out.println("輸入賬戶");
                    String zhanghu = sc.next();
                    System.out.println("輸入日期:格式XXXX-XX-xx");
                    String createtime = sc.next();
                    System.out.println("輸入具體描述");
                    String description = sc.next();
                    //將用戶輸入的數據,封裝到ZhangWu對象中
                    //用戶輸入的ID,必須封裝到到對象中
                    ZhangWu zw = new ZhangWu(zwid, flname, money, zhanghu, createtime, description);
                    //調用controller層中的方法,實現編輯賬務
                }           

29編輯賬務功能控制層,業務層實現

* A: 編輯賬務功能控制層,業務層實現
    * a: 案例核心代碼
    * cn.itcast.gjp.controller包中的ZhangWuController類editZhangWu方法
                /*
                 * 定義方法,實現編輯賬務功能
                 * 由視圖層調用,傳遞參數,也是ZhangWu對象
                 * 調用service層的方法,也是ZhangWu對象
                 */
                public void editZhangWu(ZhangWu zw) {
                    service.editZhangWu(zw);
                }
            * cn.itcast.gjp.service包中的ZhangWuService類editZhangWu方法
                /*
                 * 定義方法,實現編輯賬務
                 * 由控制層調用,傳遞ZhangWu對象
                 * 調用dao層的方法,傳遞ZhangWu對象
                 */
                public void editZhangWu(ZhangWu zw) {
                    dao.editZhangWu(zw);
                }
            * cn.itcast.gjp.dao包中的ZhangWuDao類editZhangWu方法
                public void editZhangWu(ZhangWu zw) {
                    // TODO Auto-generated method stub

                }

30編輯賬務功能dao層實現

* A:編輯賬務功能dao層實現
    * a: 案例核心代碼
    * cn.itcast.gjp.dao包中的ZhangWuDao類editZhangWu方法
                /*
                 * 定義方法,實現編輯功能
                 * 由業務層調用,傳遞ZhangWu對象
                 * 將對象中的數據,更新到數據表
                 */
                public void editZhangWu(ZhangWu zw) {
                    try {
                        //更新數據的SQL
                        String sql = "UPDATE zhangwu SET flname=?,money=?,zhanghu=?,createtime=?,description=? WHERE zwid=?";
                        //定義對象數組,封裝所有數據
                        Object[] params = {zw.getFlname(),zw.getMoney(),zw.getZhanghu(),zw.getCreatetime(),zw.getDescription(),zw.getZwid()};
                        //調用qr對象方法update執行更新
                        qr.update(sql, params);
                    } catch (SQLException ex) {
                        System.out.println(ex);
                        throw new RuntimeException("編輯賬務失敗");
                    }

                }

31編輯賬務功能view層實現

* A: 編輯賬務功能view層實現
    * a: 案例核心代碼
        * cn.itcast.gjp.view包中建立MainView類editZhangWu方法
    /*
                 * 定義方法,實現對賬務的編輯功能
                 * 實現思想:
                 *  接收用戶的輸入的信息
                 *  封裝成ZhangWu對象
                 *  調用控制層的方法,傳遞ZhangWu對象,實現編輯
                 * 
                 */
                public void editZhangWu() {
                    //調用查詢所有賬務數據的功能,顯示出來
                    //看到所有數據,從中選擇一項,進行修改
                    selectAll();
                    System.out.println("選擇的是編輯功能,請輸入數據");
                    Scanner sc = new Scanner(System.in);
                    System.out.print("請輸入ID");
                    int zwid = sc.nextInt();
                    System.out.println("輸入分類名稱");
                    String flname = sc.next();
                    System.out.println("輸入金額");
                    double money = sc.nextDouble();
                    System.out.println("輸入賬戶");
                    String zhanghu = sc.next();
                    System.out.println("輸入日期:格式XXXX-XX-xx");
                    String createtime = sc.next();
                    System.out.println("輸入具體描述");
                    String description = sc.next();
                    //將用戶輸入的數據,封裝到ZhangWu對象中
                    //用戶輸入的ID,必須封裝到到對象中
                    ZhangWu zw = new ZhangWu(zwid, flname, money, zhanghu, createtime, description);
                    //調用controller層中的方法,實現編輯賬務
                    controller.editZhangWu(zw);
                    System.out.println("賬務編輯成功");
                }

32刪除賬務功能分析

* A: 刪除賬務功能分析
    * a: 編寫MainView類中deleteZhangWu方法
        * 鍵盤輸入要刪除的賬務信息ID號
        * 調用ZhangWuService類中deleteZhangWu方法,用來將指定的賬務信息刪除
        * 刪除完畢後,使用輸出語句,提示 “刪除賬務成功!”
    * b: 編寫ZhangWuService類中deleteZhangWu方法
        * 調用ZhangWuDao類中deleteZhangWu方法,用來將指定的賬務信息刪除
    * c: 編寫ZhangWuDao類中deleteZhangWu方法
        * 通過QueryRunner對象,調用update方法更新數據庫表gjp_zhangwu,完成數據庫表中指定賬務刪除操作

33刪除賬務功能菜單實現

* A: 刪除賬務功能菜單實現
    * a: 案例核心代碼
* cn.itcast.gjp.view包中建立MainView類deleteZhangWu方法
                /*
                 * 定義方法,實現賬務刪除
                 * 實現思想:
                 *  接收用戶的輸入,輸入一個主鍵數據
                 *  調用控制層方法,傳遞一個主鍵
                 */
                public void deleteZhangWu() {
                    //調用查詢所有賬務數據的功能,顯示出來
                    //看到所有數據,從中選擇一項,進行修改
                    selectAll();
                    System.out.println("選擇的是刪除功能,請輸入序號即可");
                    int zwid = new Scanner(System.in).nextInt();
                    //調用控制層方法,傳遞主鍵id即可
                }

34刪除賬務功能控制層,業務層實現

* A: 刪除賬務功能控制層,業務層實現
    * a: 案例核心代碼
        * cn.itcast.gjp.controller包中的ZhangWuController類deleteZhangWu方法
                /*
                 * 定義方法,實現刪除功能
                 * 視圖層調用,傳遞int類型主鍵
                 * 調用service層方法,傳遞int主鍵
                 */
                public void deleteZhangWu(int zwid) {
                    service.deleteZhangWu(zwid);
                }
            * cn.itcast.gjp.service包中的ZhangWuService類deleteZhangWu方法
                /*
                 * 定義方法,實現刪除賬務功能
                 * 由控制層調用,傳遞主鍵id
                 * 調用dao層方法,傳遞主鍵id
                 */
                public void deleteZhangWu(int zwid) {
                    dao.deleteZhangWu(zwid);
                }
            * cn.itcast.gjp.dao包中的ZhangWuDao類deleteZhangWu方法
                public void deleteZhangWu(int zwid) {

                }

35刪除賬務功能dao實現

* A: 刪除賬務功能dao實現
    * a: 案例核心代碼
    * cn.itcast.gjp.dao包中的ZhangWuDao類deleteZhangWu方法
                /*
                 * 定義方法,實現刪除業務
                 * 業務層調用,傳遞主鍵id
                 */
                public void deleteZhangWu(int zwid) {
                    try {
                        //拼寫刪除數據SQL
                        String sql = "DELETE FROM gjp_zhangwu WHERE zwid=?";
                        qr.update(sql, zwid);
                    } catch (SQLException ex) {
                        System.out.println(ex);
                        throw new RuntimeException("刪除賬務失敗");
                    }
                }

36刪除賬務功能view層實現

* A: 刪除賬務功能view層實現
    * a: 案例核心代碼
    * cn.itcast.gjp.view包中建立MainView類editZhangWu方法
                /*
                 * 定義方法,實現賬務刪除
                 * 實現思想:
                 *  接收用戶的輸入,輸入一個主鍵數據
                 *  調用控制層方法,傳遞一個主鍵
                 */
                public void deleteZhangWu() {
                    //調用查詢所有賬務數據的功能,顯示出來
                    //看到所有數據,從中選擇一項,進行修改
                    selectAll();
                    System.out.println("選擇的是刪除功能,請輸入序號即可");
                    int zwid = new Scanner(System.in).nextInt();
                    //調用控制層方法,傳遞主鍵id即可
                    controller.deleteZhangWu(zwid);
                    System.out.println("刪除賬務成功");

01網絡模型

*A:網絡模型
TCP/IP協議中的四層分別是應用層、傳輸層、網絡層和鏈路層,每層分別負責不同的通信功能,接下來針對這四層進行詳細地講解。
鏈路層:鏈路層是用於定義物理傳輸通道,通常是對某些網絡連接設備的驅動協議,例如針對光纖、網線提供的驅動。
網絡層:網絡層是整個TCP/IP協議的核心,它主要用於將傳輸的數據進行分組,將分組數據發送到目標計算機或者網絡。
傳輸層:主要使網絡程序進行通信,在進行網絡通信時,可以採用TCP協議,也可以採用UDP協議。
應用層:主要負責應用程序的協議,例如HTTP協議、FTP協議等。

02IP地址

*A:IP地址
在TCP/IP協議中,這個標識號就是IP地址,它可以唯一標識一臺計算機,
目前,IP地址廣泛使用的版本是IPv4,它是由4個字節大小的二進制數來表示,如:00001010000000000000000000000001。
由於二進制形式表示的IP地址非常不便記憶和處理,因此通常會將IP地址寫成十進制的形式,
每個字節用一個十進制數字(0-255)表示,數字間用符號“.”分開,如 “192.168.1.100”
127.0.0.1 爲本地主機地址(本地迴環地址)

03端口號

*A:端口號
通過IP地址可以連接到指定計算機,但如果想訪問目標計算機中的某個應用程序,還需要指定端口號。
在計算機中,不同的應用程序是通過端口號區分的。
端口號是用兩個字節(16位的二進制數)表示的,它的取值範圍是0~65535,
其中,0~1023之間的端口號用於一些知名的網絡服務和應用,用戶的普通應用程序需要使用1024以上的端口號,從而避免端口號被另外一個應用或服務所佔用

04InetAddress類

  *A:InetAddress類
     /*
      *  表示互聯網中的IP地址
      *    java.net.InetAddress
      *  靜態方法
      *    static InetAddress  getLocalHost()   LocalHost本地主機
      *    返回本地主機,返回值InetAddress對象
      *    
      *    static InetAddress getByName(String hostName)傳遞主機名,獲取IP地址對象
      *    
      *  非靜態方法
      *     String getHoustAddress()獲取主機IP地址
      *     String getHoustName()獲取主機名
      *    
      */
     public class InetAddressDemo {
      public static void main(String[] args)throws UnknownHostException {
        function_1();
      }
      /*
       * static InetAddress getByName(String hostName)傳遞主機名,獲取IP地址對象
       */
      public static void function_1()throws UnknownHostException {
        InetAddress inet = InetAddress.getByName("www.baidu.com");
        System.out.println(inet);
      }

      /*
       *  static InetAddress  getLocalHost()   LocalHost本地主機
       */
      public static void function() throws UnknownHostException{
        InetAddress inet = InetAddress.getLocalHost();
        //輸出結果就是主機名,和 IP地址
        System.out.println(inet.toString());

        String ip = inet.getHostAddress();
        String name = inet.getHostName();
        System.out.println(ip+"   "+name);

        /*String host = inet.toString();
        String[] str = host.split("/");
        for(String s : str){
          System.out.println(s);
        }*/
      }
     }

05UDP協議

A:UDP協議
a:UDP協議概述:
UDP是無連接通信協議,即在數據傳輸時,數據的發送端和接收端不建立邏輯連接。
簡單來說,當一臺計算機向另外一臺計算機發送數據時,發送端不會確認接收端是否存在,就會發出數據,同樣接收端在收到數據時,也不會向發送端反饋是否收到數據。
b:UDP協議特點:
由於使用UDP協議消耗資源小,通信效率高,所以通常都會用於音頻、視頻和普通數據的傳輸例如視頻會議都使用UDP協議,
因爲這種情況即使偶爾丟失一兩個數據包,也不會對接收結果產生太大影響。

06TCP協議

*A:TCP協議
TCP協議是面向連接的通信協議,即在傳輸數據前先在發送端和接收端建立邏輯連接,然後再傳輸數據,它提供了兩臺計算機之間可靠無差錯的數據傳輸。
在TCP連接中必須要明確客戶端與服務器端,
由客戶端向服務端發出連接請求,每次連接的創建都需要經過“三次握手”。
第一次握手,客戶端向服務器端發出連接請求,等待服務器確認
第二次握手,服務器端向客戶端回送一個響應,通知客戶端收到了連接請求
第三次握手,客戶端再次向服務器端發送確認信息,確認連接

========================================第二節課=========================================

07數據包和發送對象介紹

*A:數據包和發送對象介紹:
DatagramPacket數據包的作用就如同是“集裝箱”,
可以將發送端或者接收端的數據封裝起來。然而運輸貨物只有“集裝箱”是不夠的,還需要有碼頭。
在程序中需要實現通信只有DatagramPacket數據包也同樣不行,爲此JDK中提供的一個DatagramSocket類。
DatagramSocket類的作用就類似於碼頭,使用這個類的實例對象就可以發送和接收DatagramPacket數據包
DatagramPacket:封裝數據
DatagramSocket:發送DatagramPacket

08UDP發送端

*A:UDP發送端

     /*
        *  實現UDP協議的發送端:
        *    實現封裝數據的類 java.net.DatagramPacket  將你的數據包裝
        *    實現數據傳輸的類 java.net.DatagramSocket  將數據包發出去
        *    
        *  實現步驟:
        *    1. 創建DatagramPacket對象,封裝數據, 接收的地址和端口
        *    2. 創建DatagramSocket
        *    3. 調用DatagramSocket類方法send,發送數據包
        *    4. 關閉資源
        *    
        *    DatagramPacket構造方法:
        *      DatagramPacket(byte[] buf, int length, InetAddress address, int port) 
        *      
        *    DatagramSocket構造方法:
        *      DatagramSocket()空參數
        *      方法: send(DatagramPacket d)
        *      
        */
       public class UDPSend {
        public static void main(String[] args) throws IOException{
          //創建數據包對象,封裝要發送的數據,接收端IP,端口
          byte[] date = "你好UDP".getBytes();
          //創建InetAddress對象,封裝自己的IP地址
          InetAddress inet = InetAddress.getByName("127.0.0.1");
          DatagramPacket dp = new DatagramPacket(date, date.length, inet,6000);
          //創建DatagramSocket對象,數據包的發送和接收對象
          DatagramSocket ds = new DatagramSocket();
          //調用ds對象的方法send,發送數據包
          ds.send(dp);
          //關閉資源
          ds.close();
        }
       }

09UDP接收端

*A:UDP接收端

       /*
        *  實現UDP接收端
        *    實現封裝數據包 java.net.DatagramPacket 將數據接收
        *    實現輸出傳輸     java.net.DatagramSocket 接收數據包
        *    
        *  實現步驟:
        *     1. 創建DatagramSocket對象,綁定端口號
        *         要和發送端端口號一致
        *     2. 創建字節數組,接收發來的數據
        *     3. 創建數據包對象DatagramPacket
        *     4. 調用DatagramSocket對象方法
        *        receive(DatagramPacket dp)接收數據,數據放在數據包中
        *     5. 拆包
        *          發送的IP地址
        *            數據包對象DatagramPacket方法getAddress()獲取的是發送端的IP地址對象
        *            返回值是InetAddress對象
        *          接收到的字節個數
        *            數據包對象DatagramPacket方法 getLength()
        *          發送方的端口號
        *            數據包對象DatagramPacket方法 getPort()發送端口
        *     6. 關閉資源
        */
       public class UDPReceive {
        public static void main(String[] args)throws IOException {
          //創建數據包傳輸對象DatagramSocket 綁定端口號
          DatagramSocket ds = new DatagramSocket(6000);
          //創建字節數組
          byte[] data = new byte[1024];
          //創建數據包對象,傳遞字節數組
          DatagramPacket dp = new DatagramPacket(data, data.length);
          //調用ds對象的方法receive傳遞數據包
          ds.receive(dp);


        }
       }

10UDP接收端的拆包

*A:UDP接收端的拆包

      /*
       *  實現UDP接收端
       *    實現封裝數據包 java.net.DatagramPacket 將數據接收
       *    實現輸出傳輸     java.net.DatagramSocket 接收數據包
       *    
       *  實現步驟:
       *     1. 創建DatagramSocket對象,綁定端口號
       *         要和發送端端口號一致
       *     2. 創建字節數組,接收發來的數據
       *     3. 創建數據包對象DatagramPacket
       *     4. 調用DatagramSocket對象方法
       *        receive(DatagramPacket dp)接收數據,數據放在數據包中
       *     5. 拆包
       *          發送的IP地址
       *            數據包對象DatagramPacket方法getAddress()獲取的是發送端的IP地址對象
       *            返回值是InetAddress對象
       *          接收到的字節個數
       *            數據包對象DatagramPacket方法 getLength()
       *          發送方的端口號
       *            數據包對象DatagramPacket方法 getPort()發送端口
       *     6. 關閉資源
       */
      public class UDPReceive {
        public static void main(String[] args)throws IOException {
          //創建數據包傳輸對象DatagramSocket 綁定端口號
          DatagramSocket ds = new DatagramSocket(6000);
          //創建字節數組
          byte[] data = new byte[1024];
          //創建數據包對象,傳遞字節數組
          DatagramPacket dp = new DatagramPacket(data, data.length);
          //調用ds對象的方法receive傳遞數據包
          ds.receive(dp);

          //獲取發送端的IP地址對象
          String ip=dp.getAddress().getHostAddress();

          //獲取發送的端口號
          int port = dp.getPort();

          //獲取接收到的字節個數
          int length = dp.getLength();
          System.out.println(new String(data,0,length)+"..."+ip+":"+port);
          ds.close();
        }
      }

11鍵盤輸入的聊天

*A:鍵盤輸入的聊天
*a:發送端:

      /*
       * 實現UDP發送,鍵盤輸入的形式
       * 輸入完畢,發送給接收端      
       */
      public class UDPSend {
        public static void main(String[] args) throws IOException{
          Scanner sc = new Scanner(System.in);
          DatagramSocket ds = new DatagramSocket();
          InetAddress inet = InetAddress.getByName("127.0.0.1");
          while(true){
          String message = sc.nextLine();
          /*if("886".equals(message)){
            break;
          }*/
          byte[] date = message.getBytes();
          DatagramPacket dp = new DatagramPacket(date, date.length, inet,6000);
          ds.send(dp);
          }
        //  ds.close();
        }
      }



       /*
        *  實現UDP接收端
        *  永不停歇的接收端
        */
       public class UDPReceive {
        public static void main(String[] args)throws IOException {
          //創建數據包傳輸對象DatagramSocket 綁定端口號
          DatagramSocket ds = new DatagramSocket(6000);
          //創建字節數組
          byte[] data = new byte[1024];
          //創建數據包對象,傳遞字節數組
          while(true){
          DatagramPacket dp = new DatagramPacket(data, data.length);
          //調用ds對象的方法receive傳遞數據包
          ds.receive(dp);

          //獲取發送端的IP地址對象
          String ip=dp.getAddress().getHostAddress();

          //獲取發送的端口號
          int port = dp.getPort();

          //獲取接收到的字節個數
          int length = dp.getLength();
          System.out.println(new String(data,0,length)+"..."+ip+":"+port);
          }
          //ds.close();
        }
       }

=======================第三節課======================================

12TCP的客戶端和服務器

*A:TCP的客戶端和服務器
TCP通信同UDP通信一樣,都能實現兩臺計算機之間的通信,通信的兩端都需要創建socket對象。
區別在於,UDP中只有發送端和接收端,不區分客戶端與服務器端,計算機之間可以任意地發送數據。
而TCP通信是嚴格區分客戶端與服務器端的,在通信時,必須先由客戶端去連接服務器端才能實現通信,
服務器端不可以主動連接客戶端,並且服務器端程序需要事先啓動,等待客戶端的連接。
在JDK中提供了兩個類用於實現TCP程序,一個是ServerSocket類,用於表示服務器端,一個是Socket類,用於表示客戶端。
通信時,首先創建代表服務器端的ServerSocket對象,該對象相當於開啓一個服務,並等待客戶端的連接,然後創建代表客戶端的Socket對象向服務器端發出連接請求,服務器端響應請求,兩者建立連接開始通信。

13TCP的客戶端程序

*A:TCP的客戶端程序

   /*
    *  實現TCP客戶端,連接到服務器
    *  和服務器實現數據交換
    *  實現TCP客戶端程序的類 java.net.Socket
    *  
    *  構造方法:
    *      Socket(String host, int port)  傳遞服務器IP和端口號
    *      注意:構造方法只要運行,就會和服務器進行連接,連接失敗,拋出異常
    *      
    *    OutputStream  getOutputStream() 返回套接字的輸出流
    *      作用: 將數據輸出,輸出到服務器
    *      
    *    InputStream getInputStream() 返回套接字的輸入流
    *      作用: 從服務器端讀取數據
    *      
    *    客戶端服務器數據交換,必須使用套接字對象Socket中的獲取的IO流,自己new流,不行
    */
   public class TCPClient {
    public static void main(String[] args)throws IOException {
      //創建Socket對象,連接服務器
      Socket socket = new Socket("127.0.0.1", 8888);
      //通過客戶端的套接字對象Socket方法,獲取字節輸出流,將數據寫向服務器
      OutputStream out = socket.getOutputStream();
      out.write("服務器OK".getBytes());



      socket.close();
    }
   }

14TCP的服務器程序accept方法

A:TCP的服務器程序accept方法

  /*
      *  實現TCP服務器程序
      *  表示服務器程序的類 java.net.ServerSocket
      *  構造方法:
      *    ServerSocket(int port) 傳遞端口號
      *  
      *  很重要的事情: 必須要獲得客戶端的套接字對象Socket
      *    Socket  accept()
      */
     public class TCPServer {
      public static void main(String[] args) throws IOException{
        ServerSocket server = new ServerSocket(8888);
        //調用服務器套接字對象中的方法accept() 獲取客戶端套接字對象
        Socket socket = server.accept();
        //通過客戶端套接字對象,socket獲取字節輸入流,讀取的是客戶端發送來的數據
        InputStream in = socket.getInputStream();
        byte[] data = new byte[1024];
        int len = in.read(data);
        System.out.println(new String(data,0,len));


        socket.close();
        server.close();
      }
     }

15TCP的服務器程序讀取客戶端數據

A:TCP的服務器程序讀取客戶端數據


      /*
       *  實現TCP客戶端,連接到服務器
       *  和服務器實現數據交換
       *  實現TCP客戶端程序的類 java.net.Socket
       *  
       *  構造方法:
       *      Socket(String host, int port)  傳遞服務器IP和端口號
       *      注意:構造方法只要運行,就會和服務器進行連接,連接失敗,拋出異常
       *      
       *    OutputStream  getOutputStream() 返回套接字的輸出流
       *      作用: 將數據輸出,輸出到服務器
       *      
       *    InputStream getInputStream() 返回套接字的輸入流
       *      作用: 從服務器端讀取數據
       *      
       *    客戶端服務器數據交換,必須使用套接字對象Socket中的獲取的IO流,自己new流,不行
       */
      public class TCPClient {
        public static void main(String[] args)throws IOException {
          //創建Socket對象,連接服務器
          Socket socket = new Socket("127.0.0.1", 8888);
          //通過客戶端的套接字對象Socket方法,獲取字節輸出流,將數據寫向服務器
          OutputStream out = socket.getOutputStream();
          out.write("服務器OK".getBytes());
          socket.close();
        }
      }
      /*
       *  實現TCP服務器程序
       *  表示服務器程序的類 java.net.ServerSocket
       *  構造方法:
       *    ServerSocket(int port) 傳遞端口號
       *  
       *  很重要的事情: 必須要獲得客戶端的套接字對象Socket
       *    Socket  accept()
       */
      public class TCPServer {
        public static void main(String[] args) throws IOException{
          ServerSocket server = new ServerSocket(8888);
          //調用服務器套接字對象中的方法accept() 獲取客戶端套接字對象
          Socket socket = server.accept();
          //通過客戶端套接字對象,socket獲取字節輸入流,讀取的是客戶端發送來的數據
          InputStream in = socket.getInputStream();
          byte[] data = new byte[1024];
          int len = in.read(data);
          System.out.println(new String(data,0,len));

        }
      }

16TCP的服務器和客戶端的數據交換

A:TCP的服務器和客戶端的數據交換

      /*
       *  實現TCP客戶端,連接到服務器
       *  和服務器實現數據交換
       *  實現TCP客戶端程序的類 java.net.Socket
       *  
       *  構造方法:
       *      Socket(String host, int port)  傳遞服務器IP和端口號
       *      注意:構造方法只要運行,就會和服務器進行連接,連接失敗,拋出異常
       *      
       *    OutputStream  getOutputStream() 返回套接字的輸出流
       *      作用: 將數據輸出,輸出到服務器
       *      
       *    InputStream getInputStream() 返回套接字的輸入流
       *      作用: 從服務器端讀取數據
       *      
       *    客戶端服務器數據交換,必須使用套接字對象Socket中的獲取的IO流,自己new流,不行
       */
      public class TCPClient {
        public static void main(String[] args)throws IOException {
          //創建Socket對象,連接服務器
          Socket socket = new Socket("127.0.0.1", 8888);
          //通過客戶端的套接字對象Socket方法,獲取字節輸出流,將數據寫向服務器
          OutputStream out = socket.getOutputStream();
          out.write("服務器OK".getBytes());

          //讀取服務器發回的數據,使用socket套接字對象中的字節輸入流
          InputStream in = socket.getInputStream();
          byte[] data = new byte[1024];
          int len = in.read(data);
          System.out.println(new String(data,0,len));

          socket.close();
        }
      }
      /*
       *  實現TCP服務器程序
       *  表示服務器程序的類 java.net.ServerSocket
       *  構造方法:
       *    ServerSocket(int port) 傳遞端口號
       *  
       *  很重要的事情: 必須要獲得客戶端的套接字對象Socket
       *    Socket  accept()
       */
      public class TCPServer {
        public static void main(String[] args) throws IOException{
          ServerSocket server = new ServerSocket(8888);
          //調用服務器套接字對象中的方法accept() 獲取客戶端套接字對象
          Socket socket = server.accept();
          //通過客戶端套接字對象,socket獲取字節輸入流,讀取的是客戶端發送來的數據
          InputStream in = socket.getInputStream();
          byte[] data = new byte[1024];
          int len = in.read(data);
          System.out.println(new String(data,0,len));

          //服務器向客戶端回數據,字節輸出流,通過客戶端套接字對象獲取字節輸出流
          OutputStream out = socket.getOutputStream();
          out.write("收到,謝謝".getBytes());

          socket.close();
          server.close();
        }
      }

17TCP的中的流對象

*A:TCP的中的流對象
    參見圖解TCP中的流對象.jpg  

======================================第四節課=================================================

18TCP圖片上傳案例分析

*A:圖片上傳案例分析
     參見圖解TCP上傳圖片案例.jpg  

19TCP上傳客戶端

*A TCP上傳客戶端

   /*
    *  實現TCP圖片上傳客戶端
    *  實現步驟:
    *    1. Socket套接字連接服務器
    *    2. 通過Socket獲取字節輸出流,寫圖片
    *    3. 使用自己的流對象,讀取圖片數據源
    *         FileInputStream
    *    4. 讀取圖片,使用字節輸出流,將圖片寫到服務器
    *       採用字節數組進行緩衝
    *    5. 通過Socket套接字獲取字節輸入流
    *       讀取服務器發回來的上傳成功
    *    6. 關閉資源
    */
   public class TCPClient {
    public static void main(String[] args) throws IOException{
      Socket socket = new Socket("127.0.0.1", 8000);
      //獲取字節輸出流,圖片寫到服務器
      OutputStream out = socket.getOutputStream();
      //創建字節輸入流,讀取本機上的數據源圖片
      FileInputStream fis = new FileInputStream("c:\\t.jpg");
      //開始讀寫字節數組
      int len = 0 ;
      byte[] bytes = new byte[1024];
      while((len = fis.read(bytes))!=-1){
        out.write(bytes, 0, len);
      }
      //給服務器寫終止序列
      //socket.shutdownOutput();

      //獲取字節輸入流,讀取服務器的上傳成功
      InputStream in = socket.getInputStream();

      len = in.read(bytes);
      System.out.println(new String(bytes,0,len));

      fis.close();
      socket.close();
    }
   }

20TCP上傳服務器

A:TCP上傳服務器

  /*
    *  TCP圖片上傳服務器
    *   1. ServerSocket套接字對象,監聽端口8000
    *   2. 方法accept()獲取客戶端的連接對象
    *   3. 客戶端連接對象獲取字節輸入流,讀取客戶端發送圖片
    *   4. 創建File對象,綁定上傳文件夾
    *       判斷文件夾存在, 不存,在創建文件夾
    *   5. 創建字節輸出流,數據目的File對象所在文件夾
    *   6. 字節流讀取圖片,字節流將圖片寫入到目的文件夾中
    *   7. 將上傳成功會寫客戶端
    *   8. 關閉資源
    *       
    */
   public class TCPServer {
    public static void main(String[] args) throws IOException{
      ServerSocket server = new ServerSocket(8000);
      Socket socket = server.accept();
      //通過客戶端連接對象,獲取字節輸入流,讀取客戶端圖片
      InputStream in = socket.getInputStream();
      //將目的文件夾封裝到File對象
      File upload = new File("d:\\upload");
      if(!upload.exists())
        upload.mkdirs();

      //創建字節輸出流,將圖片寫入到目的文件夾中                         
      FileOutputStream fos = new FileOutputStream(upload+"t.jpg");
      //讀寫字節數組
      byte[] bytes = new byte[1024];
      int len = 0 ;
      while((len = in.read(bytes))!=-1){
        fos.write(bytes, 0, len);
      }
      //通過客戶端連接對象獲取字節輸出流
      //上傳成功寫回客戶端
      socket.getOutputStream().write("上傳成功".getBytes());

      fos.close();
      socket.close();
      server.close();
    }
   }

21TCP圖片上傳問題解決

/*
 *  實現TCP圖片上傳客戶端
 *  實現步驟:
 *    1. Socket套接字連接服務器
 *    2. 通過Socket獲取字節輸出流,寫圖片
 *    3. 使用自己的流對象,讀取圖片數據源
 *         FileInputStream
 *    4. 讀取圖片,使用字節輸出流,將圖片寫到服務器
 *       採用字節數組進行緩衝
 *    5. 通過Socket套接字獲取字節輸入流
 *       讀取服務器發回來的上傳成功
 *    6. 關閉資源
 */
public class TCPClient {
  public static void main(String[] args) throws IOException{
    Socket socket = new Socket("127.0.0.1", 8000);
    //獲取字節輸出流,圖片寫到服務器
    OutputStream out = socket.getOutputStream();
    //創建字節輸入流,讀取本機上的數據源圖片
    FileInputStream fis = new FileInputStream("c:\\t.jpg");
    //開始讀寫字節數組
    int len = 0 ;
    byte[] bytes = new byte[1024];
    while((len = fis.read(bytes))!=-1){
      out.write(bytes, 0, len);
    }
    //給服務器寫終止序列
    socket.shutdownOutput();//想服務端寫入一個結束標誌

    //獲取字節輸入流,讀取服務器的上傳成功
    InputStream in = socket.getInputStream();

    len = in.read(bytes);
    System.out.println(new String(bytes,0,len));

    fis.close();
    socket.close();
  }
}

TCP上傳文件名

*A:TCP上傳文件名

/*
    *  TCP圖片上傳服務器
    *   1. ServerSocket套接字對象,監聽端口8000
    *   2. 方法accept()獲取客戶端的連接對象
    *   3. 客戶端連接對象獲取字節輸入流,讀取客戶端發送圖片
    *   4. 創建File對象,綁定上傳文件夾
    *       判斷文件夾存在, 不存,在創建文件夾
    *   5. 創建字節輸出流,數據目的File對象所在文件夾
    *   6. 字節流讀取圖片,字節流將圖片寫入到目的文件夾中
    *   7. 將上傳成功會寫客戶端
    *   8. 關閉資源
    *       
    */
   public class TCPServer {
    public static void main(String[] args) throws IOException{
      ServerSocket server = new ServerSocket(8000);
      Socket socket = server.accept();
      //通過客戶端連接對象,獲取字節輸入流,讀取客戶端圖片
      InputStream in = socket.getInputStream();
      //將目的文件夾封裝到File對象
      File upload = new File("d:\\upload");
      if(!upload.exists())
        upload.mkdirs();

      //防止文件同名被覆蓋,從新定義文件名字
      //規則:  域名+毫秒值+6位隨機數
      String filename="itcast"+System.currentTimeMillis()+new Random().nextInt(999999)+".jpg";
      //創建字節輸出流,將圖片寫入到目的文件夾中                         
      FileOutputStream fos = new FileOutputStream(upload+File.separator+filename);
      //讀寫字節數組
      byte[] bytes = new byte[1024];
      int len = 0 ;
      while((len = in.read(bytes))!=-1){
        fos.write(bytes, 0, len);
      }
      //通過客戶端連接對象獲取字節輸出流
      //上傳成功寫回客戶端
      socket.getOutputStream().write("上傳成功".getBytes());

      fos.close();
      socket.close();
      server.close();
    }
   }

多線程上傳案例

*A:多線程上傳案例

  public class TCPThreadServer {
    public static void main(String[] args) throws IOException {
      ServerSocket server = new ServerSocket(8000);
      while (true) {
        // 獲取到一個客戶端,必須開啓新線程,爲這個客戶端服務
        Socket socket = server.accept(); 
        new Thread(new Upload(socket)).start();
      }
    }
  }

  public class Upload implements Runnable {

    private Socket socket;

    public Upload(Socket socket) {
      this.socket = socket;
    }

    public void run() {
      try {
        // 通過客戶端連接對象,獲取字節輸入流,讀取客戶端圖片
        InputStream in = socket.getInputStream();
        // 將目的文件夾封裝到File對象
        File upload = new File("d:\\upload");
        if (!upload.exists())
          upload.mkdirs();

        // 防止文件同名被覆蓋,從新定義文件名字
        // 規則: 域名+毫秒值+6位隨機數
        String filename = "itcast" + System.currentTimeMillis() + new Random().nextInt(999999) + ".jpg";
        // 創建字節輸出流,將圖片寫入到目的文件夾中
        FileOutputStream fos = new FileOutputStream(upload + File.separator + filename);
        // 讀寫字節數組
        byte[] bytes = new byte[1024];
        int len = 0;
        while ((len = in.read(bytes)) != -1) {
          fos.write(bytes, 0, len);
        }
        // 通過客戶端連接對象獲取字節輸出流
        // 上傳成功寫回客戶端
        socket.getOutputStream().write("上傳成功".getBytes());

        fos.close();
        socket.close();
      } catch (Exception ex) {

      }
    }

  }

01類加載器

* A.類的加載
    當程序要使用某個類時,如果該類還未被加載到內存中,則系統會通過加載,連接,初始化三步來實現對這個類進行初始化。
   * a 加載 
        * 就是指將class文件讀入內存,併爲之創建一個Class對象。
        * 任何類被使用時系統都會建立一個Class對象
   * b 連接
        * 驗證 是否有正確的內部結構,並和其他類協調一致
        * 準備 負責爲類的靜態成員分配內存,並設置默認初始化值
        * 解析 將類的二進制數據中的符號引用替換爲直接引用
   * c 初始化 
        * 就是我們以前講過的初始化步驟(new 對象)
    * 注:簡單的說就是:把.class文件加載到內存裏,並把這個.class文件封裝成一個Class類型的對象。
* B.類的加載時機
    以下的情況,會加載這個類。
    * a. 創建類的實例
    * b. 類的靜態變量,或者爲靜態變量賦值
    * c. 類的靜態方法
    * d. 使用反射方式來強制創建某個類或接口對應的java.lang.Class對象
    * e. 初始化某個類的子類
    * f. 直接使用java.exe命令來運行某個主類

* C: 類加載器(瞭解)
    負責將.class文件加載到內在中,併爲之生成對應的Class對象。
    * a. Bootstrap ClassLoader 根類加載器
        * 也被稱爲引導類加載器,負責Java核心類的加載
        * 比如System,String等。在JDK中JRE的lib目錄下rt.jar文件中

 * b. Extension ClassLoader 擴展類加載器
* 負責JRE的擴展目錄中jar包的加載。
* 在JDK中JRE的lib目錄下ext目錄
 * c. System ClassLoader 系統類加載器
* 負責在JVM啓動時加載來自java命令的class文件,以及classpath環境變量所指定的jar包和類路徑。
* 我們用的是System ClassLoader 系統類加載器

02反射

* A. 反射定義
    * a. JAVA反射機制是在運行狀態中,
            對於任意一個類,都能夠知道這個類的所有屬性和方法;
            對於任意一個對象,都能夠調用它的任意一個方法和屬性;
        這種動態獲取的信息以及動態調用對象的方法的功能稱爲java語言的反射機制。

    * b.反射技術
        條件:運行狀態
        已知:一個類或一個對象(根本是已知.class文件)
        結果:得到這個類或對象的所有方法和屬性

    * 注: 要想解剖一個類,必須先要獲取到該類的字節碼文件對象。而解剖使用的就是Class類中的方法.所以先要獲取到每一個字節碼文件對應的Class類型的對象。
* B. Class類
    * a. Class類及Class對象的瞭解
        要想解剖一個類,必須先了解Class對象。
        閱讀API的Class類得知,Class 沒有公共構造方法。Class 對象是在加載類時由 Java 虛擬機以及通過調用類加載器中的 defineClass 方法自動構造的。
    * b. 得到Class對象
        * 1. 有三個方法
            方式一: 通過Object類中的getClass()方法
                Person person = new Person();
                Class clazz = person.getClass();
            方式二: 通過 類名.class 獲取到字節碼文件對象(任意數據類型都具備一個class靜態屬性,看上去要比第一種方式簡單)。
                Class clazz = Person.class;
            方式三: 通過Class類中的方法(將類名作爲字符串傳遞給Class類中的靜態方法forName即可)。
                Class c3 = Class.forName("Person");
            注:第三種和前兩種的區別是:
                    前兩種你必須明確Person類型.
                    後面是指定這種類型的字符串就行.這種擴展更強.我不需要知道你的類.我只提供字符串,按照配置文件加載就可以了

        * 2. 得到Class對象的三個方法代碼演示:
           代碼演示
    /*
                 * 獲取.class字節碼文件對象的方式
                 *      1:通過Object類中的getObject()方法
                 *      2: 通過 類名.class 獲取到字節碼文件對象
                 *      3: 反射中的方法,
                 *          public static Class<?> forName(String className) throws ClassNotFoundException
                 *          返回與帶有給定字符串名的類或接口相關聯的 Class 對象 
                 */
                public class ReflectDemo {
                    public static void main(String[] args) throws ClassNotFoundException {
                        // 1: 通過Object類中的getObject()方法
                        // Person p1 = new Person();
                        // Class c1 = p1.getClass();
                        // System.out.println("c1 = "+ c1);

                        // 2: 通過 類名.class 獲取到字節碼文件對象
                        // Class c2 = Person.class;
                        // System.out.println("c2 = "+ c2);

                        // 3: 反射中的方法
                        Class c3 = Class.forName("cn.itcast_01_Reflect.Person");// 包名.類名
                        System.out.println("c3 = " + c3);
                    }
                }
               Person類
                package cn.itcast_01_Reflect;
                public class Person {
                    //成員變量
                    public String name;
                    public int age;
                    private String address;

                    //構造方法
                    public Person() {
                        System.out.println("空參數構造方法");
                    }

                    public Person(String name) {
                        this.name = name;
                        System.out.println("帶有String的構造方法");
                    }
                    //私有的構造方法
                    private Person(String name, int age){
                        this.name = name;
                        this.age = age;
                        System.out.println("帶有String,int的構造方法");
                    }

                    public Person(String name, int age, String address){
                        this.name = name;
                        this.age = age;
                        this.address = address;
                        System.out.println("帶有String, int, String的構造方法");
                    }

                    //成員方法
                    //沒有返回值沒有參數的方法
                    public void method1(){
                        System.out.println("沒有返回值沒有參數的方法");
                    }
                    //沒有返回值,有參數的方法
                    public void method2(String name){
                        System.out.println("沒有返回值,有參數的方法 name= "+ name);
                    }
                    //有返回值,沒有參數
                    public int method3(){
                        System.out.println("有返回值,沒有參數的方法");
                        return 123;
                    }
                    //有返回值,有參數的方法
                    public String method4(String name){
                        System.out.println("有返回值,有參數的方法");
                        return "哈哈" + name;
                    }
                    //私有方法
                    private void method5(){
                        System.out.println("私有方法");
                    }

                    @Override
                    public String toString() {
                        return "Person [name=" + name + ", age=" + age + ", address=" + address+ "]";
                    }
                }
            * 注: Class類型的唯一性
                因爲一個.class文件在內存裏只生成一個Class對象,所以無論那一種方法得到Class對象,得到的都是同一個對象。
    * C.通過反射獲取無參構造方法並使用
        * a. 得到無參構造方法
            public Constructor<?>[] getConstructors() 
                獲取所有的public 修飾的構造方法。
                選擇無參構造方法,不建議使用。
            public Constructor<T> getConstructor(Class<?>... parameterTypes) 
                獲取public修飾, 指定參數類型所對應的構造方法。
                不傳參數得到無參構造方法。
        * b. 運行無參構造方法
            public T newInstance(Object... initargs) 
                使用此 Constructor 對象表示的構造方法來創建該構造方法的聲明類的新實例,並用指定的初始化參數初始化該實例。 
                因爲是無參構造,所以不傳參數。
        * c. 通過反射獲取無參構造方法並使用的代碼演示:
                package cn.itcast.demo1;

                import java.lang.reflect.Constructor;

                /*
                 *  通過反射獲取class文件中的構造方法,運行構造方法
                 *  運行構造方法,創建對象
                 *    獲取class文件對象
                 *    從class文件對象中,獲取需要的成員
                 *    
                 *  Constructor 描述構造方法對象類
                 */
                public class ReflectDemo1 {
                    public static void main(String[] args) throws Exception {

                        Class c = Class.forName("cn.itcast.demo1.Person");
                        //使用class文件對象,獲取類中的構造方法
                        //  Constructor[]  getConstructors() 獲取class文件對象中的所有公共的構造方法
                        /*Constructor[] cons = c.getConstructors();
                        for(Constructor con : cons){
                            System.out.println(con);
                        }*/
                        //獲取指定的構造方法,空參數的構造方法
                        Constructor con =  c.getConstructor();
                        //運行空參數構造方法,Constructor類方法 newInstance()運行獲取到的構造方法
                        Object obj = con.newInstance();
                        System.out.println(obj.toString());
                    }
                }
    * D. 通過反射獲取有參構造方法並使用
        * a. 得到有參的構造方法
            public Constructor<T> getConstructor(Class<?>... parameterTypes) 
                獲取public修飾, 指定參數類型所對應的構造方法。
                傳相應的參數類型得到有參構造方法。
        * b. 運行無參構造方法
            public T newInstance(Object... initargs) 
                使用此 Constructor 對象表示的構造方法來創建該構造方法的聲明類的新實例,並用指定的初始化參數初始化該實例。 
                因爲是有參構造,所以傳相應的參數值。
        * c. 通過反射獲取有參構造方法並使用的代碼演示:
            package cn.itcast.demo1;

            import java.lang.reflect.Constructor;

            /*
             *  通過反射,獲取有參數的構造方法並運行
             *  方法getConstructor,傳遞可以構造方法相對應的參數列表即可
             */
            public class ReflectDemo2 {
                public static void main(String[] args)throws Exception {
                    Class c = Class.forName("cn.itcast.demo1.Person");
                    //獲取帶有,String和int參數的構造方法
                    //Constructor<T> getConstructor(Class<?>... parameterTypes)  
                    //Class<?>... parameterTypes 傳遞要獲取的構造方法的參數列表
                    Constructor con = c.getConstructor(String.class,int.class);
                    //運行構造方法
                    // T newInstance(Object... initargs)  
                    //Object... initargs 運行構造方法後,傳遞的實際參數
                    Object obj = con.newInstance("張三",20);
                    System.out.println(obj);
                }
            }
    * E. 通過反射獲取有參構造方法並使用快捷方式
        * a. 使用的前提
            類有空參的公共構造方法。(如果是同包,默認權限也可以)
        * b. 使用的基礎
            Class類的 public T newInstance() 方法
                 創建此 Class 對象所表示的類的一個新實例。
        * c. 通過反射獲取有參構造方法並使用快捷方式的代碼演示:
            package cn.itcast.demo1;
            /*
             * 反射獲取構造方法並運行,有快捷點的方式
             * 有前提:
             *   被反射的類,必須具有空參數構造方法
             *   構造方法權限必須public
             */
            public class ReflectDemo3 {
                public static void main(String[] args) throws Exception {
                    Class c = Class.forName("cn.itcast.demo1.Person");
                    // Class類中定義方法, T newInstance() 直接創建被反射類的對象實例
                    Object obj = c.newInstance();
                    System.out.println(obj);
                }
            }
    * F. 通過反射獲取私有構造方法並使用
        * a. 得到私有的構造方法
            public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 
                獲取指定參數類型所對應的構造方法(包含私有的)。
            public Constructor<?>[] getDeclaredConstructors() 
                獲取所有的構造方法(包含私有的)。
        * b. 運行私有構造方法
            public void setAccessible(boolean flag)
                將此對象的 accessible 標誌設置爲指示的布爾值。
                設置爲true,這個方法保證我們得到的私有構造方法的運行。(取消運行時期的權限檢查。)
            public T newInstance(Object... initargs) 
                使用此 Constructor 對象表示的構造方法來創建該構造方法的聲明類的新實例,並用指定的初始化參數初始化該實例。 
        * c. 通過反射獲取私有構造方法並使用的代碼演示:
            package cn.itcast.demo1;

            import java.lang.reflect.Constructor;

            /*
             *  反射獲取私有的構造方法運行
             *  不推薦,破壞了程序的封裝性,安全性
             *  暴力反射
             */
            public class ReflectDemo4 {
                public static void main(String[] args) throws Exception{
                    Class c = Class.forName("cn.itcast.demo1.Person");
                    //Constructor[] getDeclaredConstructors()獲取所有的構造方法,包括私有的
                    /*Constructor[] cons = c.getDeclaredConstructors();
                    for(Constructor con : cons){
                        System.out.println(con);
                    }*/
                    //Constructor getDeclaredConstructor(Class...c)獲取到指定參數列表的構造方法
                    Constructor con = c.getDeclaredConstructor(int.class,String.class);

                    //Constructor類,父類AccessibleObject,定義方法setAccessible(boolean b)
                    con.setAccessible(true);

                    Object obj = con.newInstance(18,"lisi");
                    System.out.println(obj);
                }
            }
        * 注:不推薦,破壞了程序的封裝性,安全性。
    * G. 反射獲取成員變量並改值
        * a. 獲取成員變量
            * 得到公共的成員變量
                public Field getField(String name) 
                    返回一個 Field 對象,它反映此 Class 對象所表示的類或接口的指定公共成員字段。 
                public Field[] getFields() 
                    返回一個包含某些 Field 對象的數組,這些對象反映此 Class 對象所表示的類或接口的所有可訪問公共字段。 
            * 得到所有的成員變量(包括私有的,如果要進行修改私有成員變量,要先進行public void setAccessible(boolean flag) 設置。)
                public Field getDeclaredField(String name) 
                    返回一個 Field 對象,該對象反映此 Class 對象所表示的類或接口的指定已聲明字段。 
                public Field[] getDeclaredFields() 
                    返回 Field 對象的一個數組,這些對象反映此 Class 對象所表示的類或接口所聲明的所有字段。 
        * b. 修改成員變量(Field)的值
            * 修改公共的成員變量
                public void set(Object obj, Object value) 
                    將指定對象變量上此 Field 對象表示的字段設置爲指定的新值。 
                    obj指的是修改的是那個對象的這個成員變量值。
        * c. 反射獲取成員變量並改值的代碼演示
            package cn.itcast.demo1;
            import java.lang.reflect.Field;
            /*
             *  反射獲取成員變量,並修改值
             *  Person類中的成員String name
             */
            public class ReflectDemo5 {
                public static void main(String[] args) throws Exception{
                    Class c = Class.forName("cn.itcast.demo1.Person");
                    Object obj = c.newInstance();
                    //獲取成員變量 Class類的方法 getFields() class文件中的所有公共的成員變量
                    //返回值是Field[]    Field類描述成員變量對象的類
                    /*Field[] fields = c.getFields();
                    for(Field f : fields){
                        System.out.println(f);
                    }*/

                    //獲取指定的成員變量 String name
                    //Class類的方法  Field getField(傳遞字符串類型的變量名) 獲取指定的成員變量
                    Field field = c.getField("name");

                    //Field類的方法 void set(Object obj, Object value) ,修改成員變量的值
                    //Object obj 必須有對象的支持,  Object value 修改後的值
                    field.set(obj,"王五");
                    System.out.println(obj);

                }
            }
    * H. 反射獲取空參數成員方法並運行
        * a. 獲取空參數成員方法
            * 得到公共的成員方法
                public Method getMethod(String name, Class<?>... parameterTypes) 
                    返回一個 Method 對象,它反映此 Class 對象所表示的類或接口的指定公共成員方法。 
                public Method[] getMethods()
                    返回一個包含某些 Method 對象的數組,這些對象反映此 Class對象所表示的類或接口(包括那些由該類或接口聲明的以及從超類和超接口繼承的那些的類或接口)的公共 member 方法。
            * 得到全部的成員方法(包括私有的,如果要使用私有成員方法,要先進行public void setAccessible(boolean flag) 設置。)
                public Method getDeclaredMethod(String name, Class<?>... parameterTypes) 
                    返回一個 Method 對象,該對象反映此 Class 對象所表示的類或接口的指定已聲明方法。 
                public Method[] getDeclaredMethods() 
                    返回 Method 對象的一個數組,這些對象反映此 Class 對象表示的類或接口聲明的所有方法,包括公共、保護、默認(包)訪問和私有方法,但不包括繼承的方法。 
        * b. 使用Method方法對象
            public Object invoke(Object obj, Object... args) 
                對帶有指定參數的指定對象調用由此 Method 對象表示的底層方法。 
                obj 指的是調這個方法的對象。
                args 指的是調用這個方法所要用到的參數列表。
                返回值Object就是方法的返回對象。如果方法沒有返回值 ,返回的是null.
        * c. 反射獲取空參數成員方法並運行代碼演示
            package cn.itcast.demo1;

            import java.lang.reflect.Method;

            /*
             *  反射獲取成員方法並運行
             *  public void eat(){}
             */
            public class ReflectDemo6 {
                public static void main(String[] args) throws Exception{
                    Class c = Class.forName("cn.itcast.demo1.Person");
                    Object obj = c.newInstance();
                    //獲取class對象中的成員方法
                    // Method[] getMethods()獲取的是class文件中的所有公共成員方法,包括繼承的
                    // Method類是描述成員方法的對象
                    /*Method[] methods = c.getMethods();
                    for(Method m : methods){
                        System.out.println(m);
                    }*/

                    //獲取指定的方法eat運行
                    // Method getMethod(String methodName,Class...c)
                    // methodName獲取的方法名  c 方法的參數列表
                    Method method = c.getMethod("eat");
                    //使用Method類中的方法,運行獲取到的方法eat
                    //Object invoke(Object obj, Object...o)
                    method.invoke(obj);
                }
            }

    * I. 反射獲取有參數成員方法並運行
        * a. 獲取有參數成員方法
            * 得到公共的成員方法
                public Method getMethod(String name, Class<?>... parameterTypes) 
                    返回一個 Method 對象,它反映此 Class 對象所表示的類或接口的指定公共成員方法。 
                public Method[] getMethods()
                    返回一個包含某些 Method 對象的數組,這些對象反映此 Class對象所表示的類或接口(包括那些由該類或接口聲明的以及從超類和超接口繼承的那些的類或接口)的公共 member 方法。
            * 得到全部的成員方法(包括私有的,如果要使用私有成員方法,要先進行public void setAccessible(boolean flag) 設置。)
                public Method getDeclaredMethod(String name, Class<?>... parameterTypes) 
                    返回一個 Method 對象,該對象反映此 Class 對象所表示的類或接口的指定已聲明方法。 
                public Method[] getDeclaredMethods() 
                    返回 Method 對象的一個數組,這些對象反映此 Class 對象表示的類或接口聲明的所有方法,包括公共、保護、默認(包)訪問和私有方法,但不包括繼承的方法。 
        * b. 使用Method方法對象
            public Object invoke(Object obj, Object... args) 
                對帶有指定參數的指定對象調用由此 Method 對象表示的底層方法。 
                obj 指的是調這個方法的對象。
                args 指的是調用這個方法所要用到的參數列表。
                返回值Object就是方法的返回對象。如果方法沒有返回值 ,返回的是null.
        * c. 反射獲取有參數成員方法並運行代碼演示
            package cn.itcast.demo1;
            import java.lang.reflect.Method;

            /*
             *  反射獲取有參數的成員方法並執行
             *  public void sleep(String,int,double){}
             */
            public class ReflectDemo7 {
                public static void main(String[] args) throws Exception{
                    Class c = Class.forName("cn.itcast.demo1.Person");
                    Object obj = c.newInstance();
                    //調用Class類的方法getMethod獲取指定的方法sleep
                    Method method = c.getMethod("sleep", String.class,int.class,double.class);
                    //調用Method類的方法invoke運行sleep方法
                    method.invoke(obj, "休眠",100,888.99);
                }
            }
    * J. 反射泛型擦除
        * a. 使用情況
            例如:在泛型爲String的集合裏,添加Integer的數據
            ArrayList<String> list = new ArrayList<String>();
            list.add(100);
        * b. 能用泛型擦除的理論
            僞泛型:在編譯後的.class文件裏面是沒有泛型的。類型爲Object。
            用反射的方法繞過編譯,得到Class文件對象,直接調用add方法。
        * c. 反射泛型擦除的代碼演示
            package cn.itcast.demo2;
            import java.lang.reflect.Method;
            import java.util.ArrayList;

            /*
             *   定義集合類,泛型String
             *   要求向集合中添加Integer類型
             *   
             *   反射方式,獲取出集合ArrayList類的class文件對象
             *   通過class文件對象,調用add方法
             *   
             *   對反射調用方法是否理解
             */
            public class ReflectTest {
                public static void main(String[] args)throws Exception {
                    ArrayList<String> array  = new ArrayList<String>();
                    array.add("a");
                    //反射方式,獲取出集合ArrayList類的class文件對象
                    Class c = array.getClass();
                    //獲取ArrayList.class文件中的方法add
                    Method method = c.getMethod("add",Object.class);
                    //使用invoke運行ArrayList方法add
                    method.invoke(array, 150);
                    method.invoke(array, 1500);
                    method.invoke(array, 15000);
                    System.out.println(array);


                }
            }
    * K. 反射通過配置文件來決定運行的步驟
        * a. 操作依據
                通過配置文件得到類名和要運行的方法名,用反射的操作類名得到對象和調用方法
        * b. 實現步驟:
             *    1. 準備配置文件,鍵值對
             *    2. IO流讀取配置文件  Reader
             *    3. 文件中的鍵值對存儲到集合中 Properties
             *        集合保存的鍵值對,就是類名和方法名
             *    4. 反射獲取指定類的class文件對象
             *    5. class文件對象,獲取指定的方法
             *    6. 運行方法
        * c. 代碼演示
            代碼:
            package cn.itcast.demo3;

            import java.io.FileReader;
            import java.lang.reflect.Method;
            import java.util.Properties;

            /*
             *  調用Person方法,調用Student方法,調用Worker方法
             *  類不清楚,方法也不清楚
             *  通過配置文件實現此功能
             *    運行的類名和方法名字,以鍵值對的形式,寫在文本中
             *    運行哪個類,讀取配置文件即可
             *  實現步驟:
             *    1. 準備配置文件,鍵值對
             *    2. IO流讀取配置文件  Reader
             *    3. 文件中的鍵值對存儲到集合中 Properties
             *        集合保存的鍵值對,就是類名和方法名
             *    4. 反射獲取指定類的class文件對象
             *    5. class文件對象,獲取指定的方法
             *    6. 運行方法
             */
            public class Test {
                public static void main(String[] args) throws Exception{
                    //IO流讀取配置文件
                    FileReader r = new FileReader("config.properties");
                    //創建集合對象
                    Properties pro = new Properties();
                    //調用集合方法load,傳遞流對象
                    pro.load(r);
                    r.close();
                    //通過鍵獲取值
                    String className = pro.getProperty("className");
                    String methodName = pro.getProperty("methodName");
                    //反射獲取指定類的class文件對象
                    Class c = Class.forName(className);
                    Object obj = c.newInstance();
                    //獲取指定的方法名
                    Method method = c.getMethod(methodName);
                    method.invoke(obj);
                }
            }
            配置文件:
            #className=cn.itcast.demo3.Student
            #methodName=study
            className=cn.itcast.demo3.Person
            methodName=eat
            #className=cn.itcast.demo3.Worker
            #methodName=job
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章