# JavaTraining2023AHUT **Repository Path**: webturing/JavaTraining2023AHUT ## Basic Information - **Project Name**: JavaTraining2023AHUT - **Description**: 汉云智数2023安徽工业大学《Java开发实训(Web方向)》Java项目实训 - **Primary Language**: Java - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 2 - **Forks**: 1 - **Created**: 2023-06-29 - **Last Updated**: 2025-02-17 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # JavaTraining-ahut2023 by ZHAO Jing zj@webturing.com ## Day01:Java编程概述 ### 准备 #### 环境搭建 - java开发环境:jdk 1.8 or 1.9 - 开发环境: intelliJ社区版+ADT =Swing Studio #### 文档链接 - runoob [菜鸟教程](https://www.runoob.com) - git - java [java基础教程](https://www.runoob.com/java/java-tutorial.html) - Java组件 how2j.cn ### 工具 - git/github/gitee - Linus : Linux/GIT - github - IntelliJ/SwingStudio - 文档工具 markdown ### 课程结构 - CoreJava 复习 5days - jdk核心API - 基本数据结构和算法 - 设计模式 - 项目准备 3days - 文件/git - Swing - 数据库 - Swing项目 2days ### 参考网址 - 菜鸟网 - how2j.cn ### Java基础 #### JVM基础数据类型 - 8种基础数据类型Primary DataType及其包装器类型Wrapper - boolean 布尔类型/Boolean - 1 byte 字节/Byte - 2 char 双字节 Unicode vs ASCII /Character - 4 short 短整数 /Short - 4 int 整数/ Integer - 8 long 长整数 /Long - 4 float 单精度浮点数/ Float - 8 double 双精度浮点数/Double #### 基础IO格式化输入输出: - Scanner - System.out/err.printf/print/println #### 静态方法(子函数) - 参数传递 - 基本数据类型:值传递 - 引用数据类型:引用传递 - 数组 int[] arr; - 定义,浅拷贝/深拷贝/克隆 :引用类型 x==y 意味着hashCode相同或者同为null - 索引访问,遍历:Arrays.toString(arr); - 排序 :Arrays.sort对基本数据类型仅支持按照非降序排列 - 查找:Arrays.binarySearch对基本数据类型仅支持已经按照非降序排列的二分查找 ## Day02 java 基础:字符和字符串基础 ### 字符char - Unicode vs ASCII - 字符的表示'c' \u0045 #### 包装器Character类 - 分类 isDigit/isUpper/isLower/isSpace - 大小写转化toUpperCase/toLowerCase #### 字符数组 - 长度length 不可变 - 排序 ### 字符串类 #### 不可变的字符串类String - 因为不可以改变,所以不适合大量的拼接(每次拼接都会产生一个副本) - API:length/charAt/indexOf/startsWith/endsWith/contain/split - 类型转化: parsXXX - 查找/匹配: 多次查找匹配 #### 可变字符串类StringBuilder/StringBuffer - 字符的可以扩展的列表 - 适合频繁修改的场景 ### 正则表达式 - 模式匹配 - 常用模式(闭包) - 数字 \d - 字母 [a-zA-Z] - 非 ^ - 正闭包+ - 星闭包* ## DAY03 java OOP和自定义类 ### 1. 类基础:(构造函数,this,可见性描述符) #### 静态(方法)变量 static method/field #### 构造方法(constructor)与this this() ####成员(方法)变量 member method/field #### 可见性描述符visibility : - private: 仅该类自己可见, - default:同一个包类可见 - protected:子类可见 - public:所有类都可见 #### 静态字段static与成员字段 - 静态字段在类加载时初始化,属于整个类(所有成员都共享),用类名引用 - 成员字段在构造函数调用时初始化,属于对象本身(每一个对象一份),用对象引用 #### 静态方法与成员方法: - 静态方法只要导入了类,都可以调用(静态方法内部只能调用静态方法) - 成员方法必须在对象产生后(通常是new)后才可以使用,既可以调用成员方法也可以调用静态方法 ### 2 继承和多态 #### 类继承inheritance ##### 子类拥有所有父类声明为public/protected的字段,可以调用描述符为public/protected的方法 ##### 子类构造函数调用时默认在第一行添加一个super()来调用父类默认构造函数(且只调用一次) #### A a=new B();意义为创建一个B类的对象并把引用赋值给a ##### 前提是B必须是A的子类,或者B实现了A的接口 ##### 如果引用a.x则只会访问A类中的数据 ##### 如果是a.f() 需要满足: - 类A中必须拥有方法f()的声明,可以是抽象方法 - 调用子类f还是父类f则会根据最后一次绑定的对象类型而定(多态) #### abstract/final ##### abstract描述的方法没有方法体{},该类必须是抽象类 ##### 抽象类的子类如果要实例化(生成实例,调用该类构造函数)则必须实现抽象方法,否则子类也必须声明为抽象类 - final 定义的变量为常量:Et .final int a=3;后a++则编译错误 - 如果为引用类型,表示引用关系不会改变(对象本身可以数值变化) - final描述的方法不可以被子类重载 - final 描述的类,不可以有子类(称为最终类) - final/abstract永远不会同时修饰一个元素 ### 3接口和包 #### 接口interface: - 全部方法都是public abstract的方法, - 全部数据都是public static final数据 - 接口刻画了类的部分特征,比父类更灵活,更抽象,可以当成父类使用 #### 包package: - 按层次构建类,并解决类重名的问题,都是小写字母如com.qq.view - 默认描述符描述的字段/方法,只在同一个包内可以访问 #### 匿名类和内部类 - 定义在类A内部的类B称为内部类,其名称为A$B.class,为了提高封装性 - 匿名类:隐式继承/实现一个类(接口)A(一般都重载该类方法),为了提高程序的效率,如比较器Comparator和窗体鼠标消息等 ### 4 OO建模://封装,继承,组合 #### 基本数据建模:分数,点,日期等 #### 数据结构建模: - 列表:顺序表(栈,队列,单链表,双向链表) - 二叉树 - 图: ## Day04:Java集合框架 ### 集合框架概述java.util.* #### 集合框架意义 #### 集合框架的核心技术: - 泛型编程 class XXX{} - 算法和数据结构的实现 - OOP的典范 #### 算法库: - 静态算法(用类调用):Math/Arrays/Collections - 对象算法:Random BigInteger BigDecimal - 包装器:Integer Long Character ### 顺序表:Vector/ArrayList/Stack/LinkedList/Queue ### 数组表:动态容量实现 - Vector - ArrayList #### 数组表的应用Stack - 括号匹配检测 - 后缀式的计算 #### 链表 LinkedList 双向链表 i. 集合迭代器访问方法 ii. Foreach iii. Get(index)//链表O(n),数组表为O(1) #### 链表的应用 队列Queue - 队列模拟 - 宽度优先搜索 ## Day05:Java集合框架(2): ### Set: #### Set://不再支持随机访问(索引访问) i. 基于排序树TreeSet: 1. 排序 去重 2. 所有操作原子操作都是lg(N) ii. 基于哈希表HashSet 1. 去重 2. 所有原子操作 O(1) ### Map i. 基于排序树TreeMap要求键有序 ii. 基于哈系表HashMap 不保证键有序 iii. 迭代键的集合keySet(),valueSet(), EntrySet() \3. Queue: ### PriorityQueue :(**k**th查询比较高效) - 保证所有操作都是log(n) - 默认是小顶堆 - 大顶堆的定义 new PriorityQueue<>(Collections.reverseOrder()); ### .案例建模: i. 字符串统计,键值互转 ii. 利用Map实现电话本操作 iii. 利用Map实现数据库的模拟(登录验证) iv. 二叉树建模:BinaryTree v. 图建模:TreeMap> graph; ### 总结: - 深入理解Java泛型思想 - 掌握集合排序、各种数据结构操作 - 利用集合框架提升建模和编程能力 ## Day06 JavaIO和CoreJava综合 ### JavaIO体系 ### Java File ### 多线程程序 - 继承Thread类 - 实现Runnable接口 ## Day07 Swing开发基础-Swing组件I ### 基础组件 - JButton - JTextView - JEditText ### ListView控件 ### 布局 ### 任务: - 掌握Log类调试输出 - 掌握Activity生命周期 - 熟练掌握Intent的使用 - 掌握基础控件,编写简单的应用程序 - 学习FlowLayout布局 - ListView实现 - 动态布局实现 - 计算器综合案例(复杂布局) ### 开发任务 - 重复Intent的实验 - 开发一个登录界面,可以把登录成功后的用户名放到另个一页面上 - 开发一个简单的计算器 - 把这个项目用推送到github/gitee上 ## Day08: Swing存储体系 ### 文件 IO - 文件IO - 本地读写 ### MySQL数据库 ### MyBatis - 数据库 - **SQLiteOpenHelper**:抽象类,我们通过继承该类,然后重写数据库创建以及更新的方法, 我们还可以通过该类的对象获得数据库实例,或者关闭数据库! - **SQLiteDatabase**:数据库访问类:我们可以通过该类的对象来对数据库做一些增删改查的操作 - **Cursor**:游标,有点类似于JDBC里的resultset,结果集!可以简单理解为指向数据库中某 一个记录的指针! - 数据库操作: - DDL : - DML - C - R - U - ### 开发任务 - 实现SharedPreference读写 - 实现JDBC数据库增删改查 - 实现Mybatis - 实现一个基础的用户管理系统:登录,注册,修改个人信息 ## Day09 Swing项目开发I ### 项目准备: #### git命令: - 初始化一个git仓库 - 和远程库同步 Git 全局设置: ```bash git config --global user.name "webturing" git config --global user.email "zj@webturing.com" ``` 创建 git 仓库: ```bash mkdir Point24 cd Point24 git init touch README.md git add README.md git commit -m "first commit" git remote add origin https://gitee.com/webturing/Point24.git git push -u origin master ``` 已有仓库? ```bash cd existing_git_repo git remote add origin https://gitee.com/webturing/Point24.git git push -u origin master ``` #### gitee/github管理 ### 需求分析 - 难点: - 中缀式(带括号)种类 a op b op c op d 枚举 - 运算符种类 4X4X4=64种 - 运算数的顺序 4!种=24 - 方案: - **任何带括号的中缀式总有一个不需要括号的后缀式与其对应** (1+2)* (3+4) => 1 2 + 3 4 + * 枚举a,b,c,d组成的所有的后缀式 - 运算符种类 4X4X4=64种 - 运算数的顺序 7!种=5040 //Collections.shuffle 或者DFS来搜 - 后缀式合法性的判断计算(栈) - 后缀式 ==> 中缀式 ### 系统设计: #### 后缀表达式模块 - 后缀式合法性的判断计算(栈) - ```java //如果是一个后缀表达式不合法返回-1=ERROR private static double eval(String[] exp) { Stack S = new Stack(); for (String tok : exp) { if (isNumber(tok)) { S.push(Double.parseDouble(tok)); } else { if(S.size()<2)return ERROR; double b = S.peek(); S.pop(); double a = S.peek(); S.pop(); double c=0; switch (tok) { case "+": c = a + b; break; case "*": c = a * b; break; default: break; } S.push(c); } } return S.size()!=1?ERROR:S.peek(); } ``` - 判断一个符号是否是数值//异常处理技术 ```java static boolean isNumber(String tok) { try { Double.parseDouble(tok); return true; } catch (NumberFormatException e) { return false; } } ``` - 方法的委托 delegate - static double eval(String[] exp) {}//委托实现 - static double eval(List exp) {.....} #### 随机搜索器的实现 ```java /** * 随机搜索器的实现v1.0 * 枚举运算符的种类,构造出后缀表达式 * @param arr * @return */ public static List search(int[] arr) { for (int x = 0; x < 4; x++) for (int y = 0; y < 4; y++) for (int z = 0; z < 4; z++) { List exp = new Vector<>(); exp.add(OPERATORS[x]); exp.add(OPERATORS[y]); exp.add(OPERATORS[z]); for (int i : arr) exp.add(Integer.toString(i)); for (int i = 0; i < MAX_COUNT; i++) { Collections.shuffle(exp); double val = PostExpression.eval(exp); if (val == 24.0) { return exp; } } } return null; } ``` ## Day13:从后缀表达式到中缀表达式 ### Swing UI界面 ### 表达式二叉树类 ```java /** * 根据后缀表达式生成运算二叉树 * @param exp * @return */ static BinaryTree createBinaryTree(List exp) { Stack S = new Stack<>(); for (String tok : exp) { if (PostExpression.isNumber(tok)) { BinaryTree tree = new BinaryTree(tok); S.push(tree); } else { BinaryTree right = S.peek(); S.pop(); BinaryTree left = S.peek(); S.pop(); BinaryTree tree = new BinaryTree(tok, left, right); S.push(tree); } } return S.peek(); } ``` ### 二叉树的遍历 ```java void midVisit() {//中序左子树,中序右子树 根节点 System.out.print("("); if (left != null) { left.midVisit(); } System.out.print(root); if (right != null) { right.midVisit(); } System.out.print(")"); } ``` #### 可移植性问题 - 原模块**耦合了System.out**会导致在Swing不可调用 - 返回字符串,利用可变字符串StringBuffer来解决递归的性能 ```java void midVisit(StringBuffer buffer) { buffer.append("("); if(left!=null){ left.midVisit(buffer); } buffer.append(root); if(right!=null){ right.midVisit(buffer); } buffer.append(")"); } ``` #### 括号问题: - 简单方案:每一个非叶子结点都打括号 - 扩展完善BinaryTree实现完美括号 ## Day10 全排列和确定性搜索器的实现 ### 常见解空间的形式 - 多项式空间 用多重循环嵌套 O(n^k)//P问题 - 子集空间 O(2^n)//NP问题 - 全排列空间//NP问题 ### 深度优先搜索DFS - DFS搜索子集 ```java public class SubSetDFS {//递归程序 static int n = 5; static int[] book = new int[n]; static void dfs(int k) { if (k >= n) { System.out.println(Arrays.toString(book)); return; } book[k] = 0; dfs(k + 1); book[k] = 1; dfs(k + 1); } public static void main(String[] args) { dfs(0); } } ``` - DFS搜索全排列 ```java public class Permutation2DFS { //递归程序 static int n = 4; static int[] book = new int[n]; static int[] arr = new int[n]; static void dfs(int k) { if (k >= n) { System.out.println(Arrays.toString(arr)); return; } for (int i = 0; i < n; i++) { if (book[i] == 1) continue; arr[k] = i; book[i] = 1; dfs(k + 1); book[i] = 0; } } public static void main(String[] args) { dfs(0); } } ``` ### 利用康拓展开(逆展开)全排列的生成 [0,n!-1) ```java static final int FAC[] = { 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880 }; public static int[] codel(int x, int m) { int[] label = new int[m]; int[] n = new int[m]; int cnt; for (int i = 0; i < m; i++) label[i] = 1; for (int i = 0; i < m; i++) { cnt = x / FAC[m - 1 - i]; x = x % FAC[m - 1 - i]; for (int j = 0; j < m; j++) { if (label[j] == 0) continue; if (cnt == 0) { label[j] = 0; n[i] = j; break; } cnt--; } } return n; } ``` ## 改进的后缀式枚举: ### (4个运算数 abcd三个算符XYZ组成的二叉树只有5种) - { a, b, X, c, Y, d, Z }, - { a, b, c, X, Y, d, Z }, - { a, b, X, c, d, Y, Z }, - { a, b, c, X, d, Y, Z }, - { a, b, c, d, X, Y, Z } ```java public List search(int[] arr) { //4!*4^3*5=24*64*5=7680 <<7!*64=32w+ for (int cc = 0; cc < FAC[4]; cc++) { int[] idx = codel(cc, 4); String a = String.valueOf(arr[idx[0]]); String b = String.valueOf(arr[idx[1]]); String c = String.valueOf(arr[idx[2]]); String d = String.valueOf(arr[idx[3]]); for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) for (int k = 0; k < 4; k++) { String X = OPERATORS[i]; String Y = OPERATORS[j]; String Z = OPERATORS[k]; for (String[] ee : new String[][]{ {a, b, X, c, Y, d, Z}, {a, b, c, X, Y, d, Z}, {a, b, X, c, d, Y, Z}, {a, b, c, X, d, Y, Z}, {a, b, c, d, X, Y, Z},}) { if (Math.abs(PostExpression.eval(ee) - TARGET) < EPS) { return Arrays.asList(ee); } } } } return null; } ``` #### 存储所有结果 ```java public Set> searchAll(int[] arr) { Set> lists = new HashSet>(); for (int cc = 0; cc < FAC[4]; cc++) { int[] idx = codel(cc, 4); String a = String.valueOf(arr[idx[0]]); String b = String.valueOf(arr[idx[1]]); String c = String.valueOf(arr[idx[2]]); String d = String.valueOf(arr[idx[3]]); for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) for (int k = 0; k < 4; k++) { String X = OPERATORS[i]; String Y = OPERATORS[j]; String Z = OPERATORS[k]; for (String[] ee : new String[][]{ {a, b, X, c, Y, d, Z}, {a, b, c, X, Y, d, Z}, {a, b, X, c, d, Y, Z}, {a, b, c, X, d, Y, Z}, {a, b, c, d, X, Y, Z},}) { if (Math.abs(PostExpression.eval(ee) - TARGET) < EPS) { lists.add(new Vector(Arrays.asList(ee))); } } } } return lists; } ``` ## Day16 动态规划(缓存技术):XML数据存储/Sqlite数据库: ### 历史数据的保存和读取:SharedPreference #### 保留上一次的计算结果:```onStop``` ```java @Override protected void onStop() { super.onStop(); //缓存计算结果 shared-preference Log.i("point24", "saving preference!!!"); SharedPreferences share = MainActivityProject.this.getSharedPreferences(FILENAME, Activity.MODE_PRIVATE); SharedPreferences.Editor edit = share.edit(); edit.putString("a", editTextA.getText().toString()); edit.putString("b", editTextB.getText().toString()); edit.putString("c", editTextC.getText().toString()); edit.putString("d", editTextD.getText().toString()); edit.putString("sol", textViewSolution.getText().toString()); edit.commit();// 提交更新 } ``` #### 读取SharedPreference```onCreate`` ```java //读取shared-preference Log.i("point24", "reading preference!!!"); SharedPreferences share = super.getSharedPreferences(FILENAME, Activity.MODE_PRIVATE); editTextA.setText(share.getString("a", "0")); editTextB.setText(share.getString("b", "0")); editTextC.setText(share.getString("c", "0")); editTextD.setText(share.getString("d", "0")); textViewSolution.setText(share.getString("sol", "计算Ing,请等待")); ``` ### 动态规划DynamicProgramming - 递归 ```java static int factorial(int n) {//每次都重复计算 if (n <= 1) return 1; return factorial(n - 1) * n; } ``` - 静态规划:打表 ```java static int[] F; static void fill() { F = new int[13]; F[0] = 1; for (int i = 1; i < F.length; i++) { F[i] = F[i - 1] * i; } } ``` - 记忆化搜索(学习模式) ```java static int[] F = new int[13]; static int factorial(int n) {//DynamicProgramming if(F[n]!=0){//查表 O(1) return F[n]; } if (n <1) return F[n]=1;//及时存储计算结果 return F[n]=factorial(n - 1) * n;//及时存储计算结果 } ``` ### sqlite 技术 #### 创建数据库CREATE ```java public class DatabaseHelper extends SQLiteOpenHelper{ //带全部参数的构造函数,此构造函数必不可少 public DatabaseHelper(Context context, String name, CursorFactory factory, int version) { super(context, name, factory, version); } @Override public void onCreate(SQLiteDatabase db) { //创建数据库sql语句并执行 String sql = "create table tb2(numbers varchar(20),solution varchar(50))"; Log.i("DB","数据表创建成功"); db.execSQL(sql); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } } ``` ### MainActivity加载 ```java DatabaseHelper dbHelper = new DatabaseHelper(MainActivity.this, "test_db", null, 1); Log.i("DB", "数据库创建成功"); final SQLiteDatabase db = dbHelper.getWritableDatabase(); ``` #### 数据库的增删改查 ```java int[] arr = new int[] { a, b, c, d }; Arrays.sort(arr); String keys = Arrays.toString(arr); // 先查询数据库的结果 如果存在直接读取结果 Log.i("DB", "start querying1!"); Cursor cursor = db.query("tb2", new String[] { "numbers","solution" }, null, null, null, null, null); boolean find = false; Log.i("DB", "start querying2!"); while (cursor.moveToNext()) { String numbers = cursor.getString(cursor.getColumnIndex("numbers")); if (numbers.equals(keys)) { String solution = cursor.getString(cursor.getColumnIndex("solution")); textViewResult.setText(solution); Toast.makeText(MainActivity.this,"读取本地数据库记录",Toast.LENGTH_SHORT).show(); Log.i("DB", "query succesfully!"); find = true; break; } } // 否则计算后存入数据库 if (!find) { String answer = Point24.solve(arr); textViewResult.setText(answer); ContentValues values = new ContentValues(); Log.i("DB", "start inserting!"); values.put("numbers", keys); values.put("solution", answer); // 数据库执行插入命令 db.insert("tb2", null, values); Log.i("DB", "insert succesfully!"); Toast.makeText(MainActivity.this,"插入数据库成功",Toast.LENGTH_SHORT).show(); } ```