java 平台
1、J2SE java 开发平台标准版
2、J2EE java 开发平台企业版
java 程序需要在虚拟机上才可以运行,换言之只要有虚拟机的系统都可以运行 java 程序。
不同系统上要安装对应的虚拟机才可以运行 java 程序
开发步骤
1、编写源文件 (.java)
2、编译源文件为类文件 (.class) 可用 J2SE 或 J2EE编译
3、在虚拟机上运行
注释
// 单行注释
/* */ 多行注释
java 内容介绍
java 编程可以分成三个方向:
1、java se (j2se) 桌面开发 java 中的基础中的基础 2、java ee (j2ee)web 开发 3、java me (j2me) 手机开发 java se 课程介绍 java 面向对象编程 (基础 ) java 图开界面开发 java 数据库编程 java 文件 io 流编程 java 网络编程 java 多线程编程 java ee 基础 1 java 面向对象编程 -- 数据库编程 -->java se java 基础 2 html--css--javascript-->div+css java ee 中级部分 Servlet--Jsp-->mvc 模式 java ee 高级部分 Struts--Ejb--Hibernate--Spring--Ajax(ext,dw2)-->ssh 框架 java 之父 gosling 1990 sun 启动 绿色计划 1992 创建 oak 语言 -->java 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 2 | 436 1994 gosling 参加硅谷大会演示 java 功能,震惊世界 1995 sun 正式发布 java 第一个版本,目前最新是 jdk7.0 java 开发工具 记事本、 (jcreator 、jbuilder 退出舞台了 ) 、 netbean 、eclipse 如何选择开发工具 先选择记事本,对 java 有一定了解后再使用 eclipse 高级开发工具 为什么呢? 1、更深刻的理解 java 技术,培养代码感 2、有利于公司面试 java 语言的特点 1、java 语言是简单的 2、java 语言是面向对象的 3、java 语言是跨平台 ( 操作系统 ) 的[ 即一次编译,到处运行 ] 4、java 是高性能的 java 第一个程序 hello.java 运行 java 程序要安装和配置 jdk jdk 是什么? 1、jdk 全称 java dvevlopment kit 中文 java 开发工具包 2、jdk 是 sun 公司开发的 3、jdk 包括 jre(java runtime envirnment)java 运行环境、一堆 java 工具和 java 基础的 类库 ( 类共 3600 左右,常用类在 150 个左右 ) 4、可以在 www.sun.com 下载 ** 开发安装 jdk, 用户执行需要安装 jre 配置 JDK 添加环境变量即可 windows 下配置 jdk 在计算机属性 -- 高级设置 -- 环境变量 -- 添加 PATH将 JDK所在路径指定即可。多个环境变量 设置时需要用 ; 号进行隔开 1、编写第一个 hello.java // 注释 ( 解释 ) 作者: // 功能:在控制台显示 "hello" // 日期: 2013.11.28 //public :表示这个类是公共的,一个 java 文件中只能有一个 public 类 //class :表示这是一个类 //hello :类名 ( 公共类的类名必须和文件名一致 ) public class hello{ // 一个主函数,相当于是程序的入口 public static void main(String args[]){ 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 3 | 436 // 执行语句 //System :是一个包 //out.println 是输入函数 System.out.println("hello!"); } } 2、编译 hello.java 使用 javac hello.java 3、执行 hello.java 使用 java hello java 程序运行关系 1、java 源文件 (.java 文件 ) 2、java 编译器即 javac.exe 3、java 字节码文件 (.class 文件 ) 4、由解释执行器即 (java.exe) 将字节码文件加载到 java 虚拟器 (jvm) 5、字节码文件 (.class) 就会在 java 虚拟机中执行 对 hello.java 程序进行改过使之变为一个简单的加法运算程序 // 注释 ( 解释 ) 作者: // 功能:在控制台显示 "hello" // 日期: 2013.11.28 //public :表示这个类是公共的,一个 java 文件中只能有一个 public 类 //class :表示这是一个类 //jiafa :类名 ( 公共类的类名必须和文件名一致 ) public class jiafa{ // 一个主函数,相当于是程序的入口 public static void main(String args[]){ // 执行语句 //System :是一个包 //out.println 是输入函数 // System.out.println("hello!"); int a=10; // 定义一个变量,变量名 a,它的值 10 int b=20; // 定义一个变量,变量名 b,它的值 20 int result=a+b; // 定义一个叫 result 变量将变量 ab 相加的值赋值给 result // 输出结果 System.out.println(" 结果是 "+result); } } ---------------------------------------------------------------- 为什么有变量 不论是使用哪种高级程序语言编写程序,变量都是其程序的基本组成单位。 java 中的基本 数据类型的定义与 c/c++ 中大体一致。 public class Test{ public static void main(String []args){ int a=1; // 定义一个整形变量,取名 a,并赋初值 1 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 4 | 436 int b=3; // 定义一个整形变量,取名 b,并赋初值 3 b=89; // 给变量 b 赋 89 System.out.println(a); // 输出语句,把变量 a 的值输出 System.out.println(b); // 把变量 b 的值输出 } } ---------------------------------------------------------------- java 基本语法 --- 基本数据类型 java 基本数据类型 四大类型 整数类型、小数 ( 浮点 ) 类型、布尔类型、字符类型 整数类型 可以表示一个整数, 常用的整数类型有: byte,short,int,long 主要区别是 数据大小范围,请大家看一个小案例。 byte 占用内存 一个字节 范围: -128 至 127 short 占用内存 两个字节 范围: -32768 至 32767 int 占用内存 四个字节 范围: -2147483648 至 2147483647 long 占用内存 八个字节 范围: -? 至? 小数 ( 浮点 ) 类型 可以表示一个小数,常用的 小数 ( 浮点 ) 类型有: float( 单精度 ),double( 双精度 ) float 占用内存 四个字节 范围: 3.4E-38 至 3.4E+38 只能提供 7 位有效数字 double 占用内存 八个字节 范围: 1.7E-308 至 1.7E+308 可提供 16 位有效数字 布尔类型 可以表示 "真 " 或者 "假" ,类型是 boolean 比如: boolean spBool=true; // 给变量 spBool 定义为 boolean 型并赋值为真 字符类型 可以表示 单个字符,字符类型是 char 。 char 是两个字节 ( 可以存放汉字 ) 多个字符我们称为字符串,在 java 中 String 这种数据类型表示,但是 String 不是基本数 据类型,而是类,类是复合数据类型。 结论:在 java 中,对 char 进行运算的时候,直接当做 ascii 码对应的整数对待。 思考: int test1='a'+'b'; 输出值 195 char test2='a'+'b'; 输出值 ? char test3=' 中'; 输出值 195 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 5 | 436 java 基本语法 -- 定义变量,初始化,赋值 定义变量 1、什么是定义变量? int a; 这就是定义了一个变量,变量名是 a float haha; 这也定义了一个变量,表示一个 float 类型的小数,变量名是 haha 初始化变量 在定义变量的时候,就给值 int a=45; 这就是初始化变量 a 给变量赋值 比如你先定义了变量: int tt; 然后再给值 tt=780; -> 这就是给变量赋值 ---------------------------------------------------------------- java 基本语法 -- 基本数据类型转换 自动转换 int a=1.2; double b=3; 结论:数据类型可以自动的从低精度 --> 高精度。高精度不能转为低精度。 byte 小于 大于; 3、=大于等于; 5、 <=小于等于; 6、!= 不等于 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 7 | 436 int a=90;int b=90; if(a==b){System.out.println("ok1");} b--; if(a>b){System.out.println("ok2");} if(a>=b){System.out.println("ok3");} 请编写一个程序, 该程序可以接收两个数 ( 可以是整数, 也可是小数 ) 并判断两个数是大于? 小于?还是等于? 程序代码: import java.io.*; // 载入 IO 流包 public class Demo5{ public static void main(String []args){ try{ // 输入流,从键盘接收数 InputStreamReader isr=new InputStreamReader(System.in); BufferedReader br=new BufferedReader(isr); // 给出提示 System.out.println(" 请输入第一个数 "); // 从控制台读取一行数据 String a1=br.readLine(); System.out.println(" 请输入第二个数 "); String a2=br.readLine(); // 把 String 转为 float float num1=Float.parseFloat(a1); float num2=Float.parseFloat(a2); if(num1>num2){System.out.println(" 第一个大 ");} if(num1==num2){System.out.println(" 相等 ");} if(num1第二个数 "); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 53 | 436 }else{ e=0; System.out.println(" 小于 "+b+" 输出判断值 "+e); } // 第一个数减去上式的值 int f=a-e; System.out.println(" 第一个数减去上式的值 "+f); // 第二个数乘上式的值 int g=b*f; System.out.println(" 第二个数累乘上式的值 "+g); // 第一个数累加并赋给第一个数 a+=g; System.out.println(" 第一个数累加第二个数赋给第一个数的值 "+a); } } ******************************************************************************* 第九题 渔夫出海打鱼,收获若干 1、渔夫卖掉一半的鱼,然后送给海伦 3 条; 2、渔夫又卖掉剩下的鱼的 2/3 ,自己吃掉 1 条; 3、海伦来看渔夫,问他那天打了多少鱼,渔夫数了数,还剩 4 条鱼,渔夫对海伦怎么说? // 打鱼 -- 共有多少鱼 [Work09.java] public class Work09{ public static void main(String []args){ int total=0; int rest=4; // 剩余的鱼 total=((rest+1)*3+3)*2; // 逆推 System.out.println(" 鱼一共有: "+total); } } ******************************************************************************* 第十题 有一只猴子摘了一堆桃子,当即吃了一半,可是桃子太好吃了,它又多吃了一个, 第二天它 把第一天剩下的桃子吃了一半,又多吃了一个,就这样到第十天早上它只剩下一个桃子了, 问它共摘了多少桃子 [Work10.java] import java.util.*; // 加载包 public class Work10{ public static void main(String []args){ Monkey mo=new Monkey(); mo.scan(); } } class Monkey{ //day 哪天的桃子数, sday 吃了多少天剩下一个 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 54 | 436 public static int peach(int day,int sday){ // 建一个 peach 方法 if(day==sday){ return 1; }else{ return (peach(day+1,sday)+1)*2; // 算法返回值 } } public static void scan(){ // 建立输入的方法 int a=1; System.out.println(" 请输入要吃几天: "); Scanner sr=new Scanner(System.in); int b=sr.nextInt(); if(a<=25;a--){ if(i<=25;k++){ if(k==i){ System.out.printf("@"); }else{ System.out.printf("."); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 61 | 436 } } } } ******************************************************************************* 代码分析: 1、运行一下代码,将得到什么打印结果: int i=3; int j=0; double k=3.2; if(j0;i++,j--){} // 错 c) int i,k; for(i=0,k=9;(i<10&&k>0);i++,j--){} // 错 d) int i,j 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 62 | 436 for(i=0;j=10;i3) break two; } } // 无法编译, break two; 无法返回到 two 标签 ------------------------------------------------------------------------------- 8、以下代码能否编译通过?假如能编译通过,运行时将得到什么打印结果? public class Hope{ 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 64 | 436 public static void main(String args[]){ Hope h=new Hope(); } protected Hope(){ int i=1; do{ System.out.println(i); }while(++i<=ps;i++){ System.out.println(" 游戏已开始,请出拳 !"); Scanner m=new Scanner(System.in); int a=m.nextInt(); // 玩家出拳 //Random n=new Random(2);// 随机函数 int b=(int)(0+Math.random()*(3-1+1)); // 随机产生 0-2 的 int 数,电脑出 拳 if(a==b){ a1++; System.out.println(" 打平 !"); }else if((a-b)==-1||(a-b)==2){ b1++; System.out.println("YOU Win!"); }else{ c1++; System.out.println("YOU LOSE"); } } System.out.println(" 平 :"+ a1 +"\n 赢 :" + b1 +"\n 输 :"+c1+"\n 一共玩了 "+(a1+b1+c1)+" 局 "); Kais.jingcyx(); } } ******************************************************************************* 第十五题 请编写一个类 koradji( 巫师的意思 ) 为类编写如下功能: 1、根据用户的输入某人的生日,可以计算出该人的星座; 2、根据用户的输入年月日可以计算是星期几; 3、可以显示该巫师给多少人算过星相。 1 月 20 日- 2 月 18 日水瓶 2 月 19 日- 3 月 20 日双鱼 3 月 21 日- 4 月 19 日白羊 4 月 20 日- 5 月 20 日金牛 5 月 21 日- 6 月 20 日双子 6 月 21 日- 7 月 22 日巨蟹 7 月 23 日- 8 月 22 日狮子 8 月 23 日- 9 月 22 日处女 9 月 23 日-10 月 22 日天秤 10 月 23 日-11 月 21 日天蝎 11 月 22 日-12 月 21 日射手 12 月 22 日- 1 月 19 日摩羯 // 通过输入生日显示出生在周几。巫师看星座 [Wrok15.java] import java.util.*; public class Work15{ 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 66 | 436 public static void main(String []args){ // 程序入口 Start ks=new Start(); // 调用程序开始类 Start ,并启用 st 方法 ks.st(); } } class Start{ // 程序开始类 public void st(){ System.out.println(" 年月日格式: 19XX XX XX\n 请输入出生年月日: "); Scanner sr=new Scanner(System.in); int year=sr.nextInt(); // 输入年 int month=sr.nextInt(); // 输入月 int date=sr.nextInt(); // 输入日 Rq r=new Rq(); // 调用周几类 r.rq(year,month,date); // 将年月日数据传给周几类的 rq 方法中 Xinz xz=new Xinz(); // 调用星座类 xz.xinz(month,date); // 将月日的数据传给星座类中的 xinz 方法中 System.out.println("\n 是否继续让巫师看星座? \n1 、继续 \t2 、退出 "); Scanner sr1=new Scanner(System.in); int o=sr1.nextInt(); if(o==1){ Start qd=new Start(); // 输入 1 调用程序开始类 qd.st(); }else if(o!=1){ // 不等于 1 退出 Xinz tc=new Xinz(); System.out.println(" 巫师为 "+tc.getI()+" 人看过星座 "); System.out.println(" 退出星座查询, Goodbay!"); } } } class Rq{ // 周几类 public void rq(int year,int month,int date){ Calendar c = Calendar.getInstance(); // 调用日期 Calendar 抽象类 c.set(Calendar.YEAR,year); c.set(Calendar.MONTH,month-1); c.set(Calendar.DATE,date); int week = c.get(Calendar.DAY_OF_WEEK); switch (week){ // 判断输入的日期是周几 case 1: System.out.println(" 星期日 "); break; case 2: System.out.println(" 星期一 "); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 67 | 436 break; case 3: System.out.println(" 星期二 "); break; case 4: System.out.println(" 星期三 "); break; case 5: System.out.println(" 星期四 "); break; case 6: System.out.println(" 星期五 "); break; case 7: System.out.println(" 星期六 "); break; } } } class Xinz{ // 星座类 public static int i=0; // 定义静态变量 i ,i 为统计调用人数计数器 public void xinz(int month,int date){ // 判断星座的方法 i++; // 调用此方法计数累器 switch(month){ case 1:{ if(date>=20){ System.out.println(" 水瓶座 "); }else{ System.out.println(" 摩羯座 "); } break; } case 2:{ if(date>=19){ System.out.println(" 双鱼座 "); }else{ System.out.println(" 水瓶座 "); } break; } case 3:{ if(date>=21){ System.out.println(" 白羊座 "); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 68 | 436 }else{ System.out.println(" 双鱼座 "); } break; } case 4:{ if(date>=20){ System.out.println(" 金牛座 "); }else{ System.out.println(" 白羊座 "); } break; } case 5:{ if(date>=21){ System.out.println(" 双子座 "); }else{ System.out.println(" 金牛座 "); } break; } case 6:{ if(date>=21){ System.out.println(" 巨蟹座 "); }else{ System.out.println(" 金牛座 "); } break; } case 7:{ if(date>=23){ System.out.println(" 狮子座 "); }else{ System.out.println(" 巨蟹座 "); } break; } case 8:{ if(date>=20){ System.out.println(" 处女座 "); }else{ System.out.println(" 巨蟹座 "); } break; 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 69 | 436 } case 9:{ if(date>=23){ System.out.println(" 天平座 "); }else{ System.out.println(" 处女座 "); } break; } case 10:{ if(date>=23){ System.out.println(" 天蝎座 "); }else{ System.out.println(" 天平座 "); } break; } case 11:{ if(date>=22){ System.out.println(" 射手座 "); }else{ System.out.println(" 天蝎座 "); } break; } case 12:{ if(date>=22){ System.out.println(" 摩羯座 "); }else{ System.out.println(" 射手座 "); } break; } } } public int getI(){ // 返回统计调用次数 return i; } } ******************************************************************************* 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 70 | 436 第十六题 10 个人投票选班长,有三个侯选人 ( 张三,李四,王五 ) ,通过编号投票,要求最后显示班 长姓名。 [Work16.java] import java.util.*; public class Work16 { public static void main(String[] args) { // 设定投票人数 System.out.print(" 设定投票人数: "); Scanner sr=new Scanner(System.in); int a=sr.nextInt(); System.out.print(" 请输入第 1 位侯选人的名字: \n"); Scanner sr1=new Scanner(System.in); String i1=sr1.nextLine(); // 键盘接收字符串 System.out.print(" 请输入第 2 位侯选人的名字: \n"); Scanner sr2=new Scanner(System.in); String i2=sr2.nextLine(); System.out.print(" 请输入第 3 位侯选人的名字: \n"); Scanner sr3=new Scanner(System.in); String i3=sr3.nextLine(); System.out.println(" 本次选举将有 "+ a +" 人参与 !"); System.out.println("1 号:"+i1+"\t2 号 :"+i2+"\t3 号:"+i3); Xuanju tp=new Xuanju(); tp.tp(a,i1,i2,i3); } } class Xuanju{ public void tp(int a,String i1,String i2,String i3){ int j1=0,j2=0,j3=0,qq=0; // 计票器 for (int i=1;i<=a;i++){ // 统计投票 System.out.println(" 请投票,投票请按 1,2,3 :"); Scanner tp=new Scanner(System.in); int b=tp.nextInt(); System.out.println(" 已有 "+ i +" 人投票 "); switch (b){ case 1: j1++; break; case 2: j2++; break; case 3: j3++; 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 71 | 436 break; default: qq++; break; } } if(j1>j2&&j1>j3){ System.out.println(i1 +" 得"+ j1 +" 票\n"+ i2 +" 得"+ j2 +" 票\n"+ i3 +" 得"+ j3 +" 票\n"+" 弃权票数 "+qq); System.out.println(" 恭喜 " + i1 + " 当选班长 !"); }else if(j1<j2&&j2>j3){ System.out.println(i1 +" 得"+ j1 +" 票\n"+ i2 +" 得"+ j2 +" 票\n"+ i3 +" 得"+ j3 +" 票\n"+" 弃权票数 "+qq); System.out.println(" 恭喜 " + i2 + " 当选班长 !"); }else if(j3>j1&&j2 电脑内存中 2、数组的引用 ( 使用 ) 数组名 [ 下标 ] 比如:你要使用 a 数组的第三个数 a[2] 二、关于数组的用法,有几种方式: 2、没事找事用法 第一步: 先声明数组 语法:数据类型 数组名 []; 也可以 数据类型 [] 数组名 ; 例: int a[]; 或者 int[] a; 第二步: 创建数组 语法:数组名 =new 数据类型 [ 数组大小 ]; 例: a=new int[10]; 第三步: 数组的引用 ( 使用 ) 语法:数组名 [ 下标 ] 例:引用 a 数组的第 8 个元素 a[7] 要想知道数组的大小可以使用数组的 length 方法 语法:数组名 .length 三、关于数组的用法,有几种方式: 3、古板用法 ( 当已知元素值的时候可以使用此法 ) 1、初始化数组 语法:数据类型 数组名 []={ 元素值 , 元素值 ...}; 例: int a[]={2,5,6,7,8,89,90,34,56} 上面的用法相当于: int a[]=new int[9] int a[0]=2;int a[1]=5;int a[2]=6;...a[8]=56; 2、数组的引用 ( 使用 ) 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 73 | 436 语法:数组名 [ 下标 ] 例: a 数组的第 8 个元素 a[7] 一个问题? 一个养鸡场有 6 只鸡,它们的体重分别是 3kg、5kg、1kg,3.4kg 、2kg、50kg。请问这六只 鸡的总体重是多少?平均体重是多少?请你编写一个程序。 // 数组的必要性 [Demo129.java] public class Demo129 { public static void main(String[] args) { // 定义一个可以存放六个 float 类型的数组 float arr[]=new float[6]; // 使用 for 循环赋值 // 给数组的各个元素赋值 arr[0]=3; arr[1]=5; arr[2]=1; arr[3]=3.4f; arr[4]=2; arr[5]=50; // 计算总体重 [ 遍历数组 ] float all=0; for(int i=0;idogs[j].getWeight()){ // 如何比较的狗体重小于第一只狗的体重则进行修改 minWeight=dogs[j].getWeight(); minIndex=j; } } System.out.println(" 体 重 大 的 狗 是 第 "+(maxIndex+1)+" 狗 , 名 字 叫 : "+dogs[maxIndex].getName()+"\t 体重是 "+maxWeight); System.out.println(" 体 重 小 的 狗 是 第 "+(minIndex+1)+" 狗 , 名 字 叫 : "+dogs[minIndex].getName()+"\t 体重是 "+minWeight); // 输入狗的名字查狗的体重 System.out.println(" 请输入你要找的狗的名字: "); String cname=sr.nextLine(); int cIndex=0; for(int k=0;karr[j+1]){ 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 78 | 436 // 换位 temp=arr[j]; arr[j]=arr[j+1]; arr[j+1]=temp; } } } // 输出最后结果 for(int i=0;iarr[k]){ // 修改最小值 min=arr[k]; minIndex=k; } } // 当退出 for 循环时就找到这次的最小值 temp=arr[j]; arr[j]=arr[minIndex]; arr[minIndex]=temp; } // 输出最后结果 for(int i=0;i=0&&insertValpivot) r--; if(l>=r) break; temp=arr[l]; arr[l]=arr[r]; arr[r]=temp; 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 82 | 436 if(arr[l]==pivot) --r; if(arr[r]==pivot) ++l; } if(l==r){ l++; r--; } if(leftl) sort(l,right,arr); } } ------------------------------------------------------------------------------- 其它排序法 -- 选堆排序法 ( 主考高级程序员,工作中基本上用不到,不再详解 ) 将排序码 k1,k2,k3,...,kn 表示成一棵完全二叉树,然后从第 n/2 个排序码开妈筛选, 使由该结点组成的子二叉树符合堆的定义, 然后从第 n/2-1 个排序码重复刚才操作, 直到第 一个排序码止,这时候,该二叉树符合堆的定义,初始堆已经建立。 接着,可以按如下方法进行堆排序: 将堆中第一个结点 ( 二叉树根结点 ) 和最后一个结点 的数据进行交换 (k1 与 kn) ,再将 k1--kn-1 重新建堆, 然后 k1 和 kn-1 交换,再将 k1--kn-2 重新建堆,然后 k1 和 kn-2 交换,如此重复下去,每次重新建堆的元素个数不断减 1,直到 重新建堆的元素个数仅剩一个为止。这时堆排序已经完成,则排序码 k1,k2,k3,...kn 已排 成一个有序序列。 若排序是从小到大排列, 则可以建立大根堆实现堆排序, 若排序是从大到小排列, 则可 以用建立小根堆实现堆排序。 其它排序法 -- 希尔排序法 ( 知道有这个排序法即可 ) 希尔排序 (Shell Sorting) 又称为"缩小增量排序" 。是 1959 年由 D.L.Shell 提出来的。 该方法的基本思想是:先将整个待排元素序列分割成若干个子序列 ( 由相隔某个"增量"的 元素组成的 ) 分别进行直接插入排序,待整个序列中的元素基本有序 ( 增量足够小 ) 时,再对 全体元素进行一次直接插入排序。 因为直接插入排序在元素基本有序的情况下 ( 接近最好情况 ) ,效率是很高的, 因此希尔 排序在时间效率上比前两种方法有较大提高。 其它排序法 -- 二叉树排序法 二分插入排序 (Binary Insert Sorting) 的基本思想是:在有序表中采用二分查找的方 法查找待排元素的插入位置。 其处理过程: 先将第一个元素作为有序序列, 进行 n-1 次插入, 用二分查找的方法查找 待排元素的插入位置,将待排元素插入。 ------------------------------------------------------------------------------- 外部排序法 其它排序法 -- 合并排序法 ( 最为常用的排序方法 ) 合并排序法 (Merge Sorting) 是外部排序最常使用的排序方法。若数据量太大无法一次 完全加载内存,可使用外部辅助内存来处理排序数据,主要应用在文件排序。 排序方法: 将欲排序的数据分别存在数个文件大小可加载内存的文件中,再针对各个文件分别使用 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 83 | 436 "内部排序法" 将文件中的数据排序好写回文件。 再对所有已排序好的文件两两合并, 直到 所有文件合并成一个文件后,则数据排序完成。 1、将已排序好的 A、B 合并成 E,C、D合并成 F,E、F 的内部数据分别均已排好序 2、将已排序好的 E、F 合并成 G,G的内部数据已排好序 3、四个文件 A、 B、C、D数据排序完成 // 合并排序法 [Demo137.java] public class Demo137{ public static void main(String[] args) { Merge m=new Merge(); int a[]={5,4,10,8,7,9}; m.merge_sort(a,0,a.length-1); } } class Merge{ // 递归分成小部分 public void merge_sort(int[] arrays,int start,int end){ if(start<=m &&j<=end){ if(arrays[i]<=m){ temp[c]=arrays[i]; i++; } while(j<=end){ temp[c]=arrays[j]; j++; } c=0; for(int t=start;t<=end;t++,c++){ arrays[t]=temp[c]; } snp(arrays); } // 打印数组 public void snp(int[] arrays){ for(int i=0;i=leftIndex){ // 如果要找的数比 midVal 大 if(midVal>val){ // 在 arr 数组左边数列中找 find(leftIndex,midIndex-1,val,arr); }else if(midVal>2; int b=-1>>2; int c=1<<>>2; //a,b,c,d,e 结果是多少 System.out.println("a="+a); //a=0 System.out.println("b="+b); //b=-1 System.out.println("c="+c); //c=4 System.out.println("d="+d); //d=-4 System.out.println("e="+e); //e=0 } 注: ">>" 代表算术右移, "<<" 代表算术左移, ">>>" 代表逻辑右移 2、请回答在 java 中,下面的表达式运算的结果是: ~2=? //-3 2&3=? //2 2|3=? //3 ~-5=? //4 13&7=? //5 5|4=? //5 -3^3=? //-2 注: "~" 代表位取反, "&" 代表位与, "|" 代表位或, "^" 代表位异或 二进制 -- 基本概念 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 88 | 436 二进制是逢 2 进位的进位制, 0、1 是基本算符。 现代的电子计算机技术全部采用的是二进制,因为它只使用 0、1 两个数字符号,非常 简单方便, 易于用电子方式实现。计算机内部处理的信息,都是采用二进制数来表示的。二 进制 (Binary) 数用 0 和 1 两个数字及其组合来表示任何数。 进位规则是 "逢 2 进 1",数字 1 在不同的位上代表不同的值,按从右至左的次序,这个值以二倍递增。 注: 1 个字节 =8 位 bit, bit 最高位是符号位如:■□□□□□□□黑色方框为符号位。 符号位 0 代表正数, 1 代表负数 二进制 -- 原码、反码、补码 对于有符号的而言: 1、二进制的最高位是符号位: 0 表示正数, 1 表示负数 2、正数的原码、反码、补码都一样 3、负数的反码 =它的原码符号位不变,其它位取反 4、负数的补码 =它的反码 +1 5、0 的反码,补码都是 0 6、java 没有无符号数,换言之, java 中的数都是有符号的 7、在计算机运算的时候,都是以补码的方式来运算的。 位运算符和移位运算 java 中有 4 个位运算,分别是 "按位与 &、按位或 | 、按位异或 ^,按位取反 ~",它们的运算 规则是: 按位与 &:两位全为 1,结果为 1 按位或 | :两位有一个为 1,结果为 1 按位异或 ^:两位一个为 0,一个为 1,结果为 1 按位取反: 0->1 , 1->0 java 中有 3 个移位运算符: >>、 <>>逻辑右移,运算规则是: 低们溢出,高位补 0 ------------------------------------------------------------------------------- 集合框架 一个问题? 前面我们学习了数组, 充分体会到数组的优越性, 就是可以存储同一类型的数据, 但是 我们假设有这样的需求,大家看看如何解决? [Demo140.java] 请做一个公司职员薪水管理系统,要求完成如下功能: 1、当有新员工时,将该员工加入到管理系统 2、可以根据员工号,显示该员工的信息 3、可以显示所有员工信息 4、可以修改员工的薪水 5、当员工离职时,将该员工从管理系统中删除 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 89 | 436 6、可以按照薪水从低到高顺序排序 [ 思考题 ] 7、可以统计员工的平均工资和最低和最高工资 //ArrayList 集合类的使用 // 公司职员薪水管理系统 import java.util.*; public class Demo140 { public static void main(String[] args) { // 创建 EmpManage对象 EmpManage em=new EmpManage(); Scanner sr=new Scanner(System.in); // 作出一个菜单 while(true){ System.out.println(" 公司职员薪水管理系统 "); System.out.println("1 、录入新员工 "); System.out.println("2 、根据工号查询信息 "); System.out.println("3 、查询所有员工信息 "); System.out.println("4 、通过工号修改员工薪水 "); System.out.println("5 、删除员工信息 "); System.out.println("6 、按薪水高低排序 "); System.out.println("7 、计算平均工资及最高 ( 低) 工资 "); System.out.println("0 、退出系统 "); System.out.print(" 请输入对应的数字进行操作: "); int sel=sr.nextInt(); if(sel==1){ System.out.println(" 请录入新员工的信息 "); System.out.print(" 工号 :"); String empNo=sr.next(); System.out.print(" 姓名 :"); String name=sr.next(); System.out.print(" 工资 :"); float sal=sr.nextFloat(); // 构建 emp对象 Emp emp=new Emp(empNo,name,sal); // 将 empNo,name,sal 的值传给构造函数 Emp em.addEmp(emp); System.out.println(" 创建新员工 "+name+"成功 !"); }else if(sel==2){ System.out.println(" 请录入员工工号: "); String empNo=sr.next(); em.showInfo(empNo); } else if(sel==3){ System.out.println(" 公司所有员工信息如下: "); em.AllInfo(); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 90 | 436 } else if(sel==4){ System.out.println(" 请输入工号: "); String empNo=sr.next(); System.out.println(" 将工资修改为: "); float newSal=sr.nextFloat(); em.updateSal(empNo, newSal); } else if(sel==5){ System.out.println(" 请输入要删除人员的工号: "); String empNo=sr.next(); em.delEmp(empNo); } else if(sel==6){ System.out.println(" 已按薪资高低进行排序如下: "); em.SortSal(); } else if(sel==7){ System.out.println(" 显示平均工资及最高、 最低工资人员信息如下: "); em.Average(); } else if(sel==0){ System.out.println(" 已正常退出 !"); System.exit(0); }else{ System.out.println(" 输入错误,请重新输入 !"); } } } } // 创建员工管理类 class EmpManage{ private ArrayList al=null; // 创建构造函数,初始化成员变量 public EmpManage(){ al=new ArrayList(); } // 加入员工 public void addEmp(Emp emp){ // 传入员工信息 al.add(emp); } 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 91 | 436 // 根据员工工号显示员工的相关信息 public void showInfo(String empNo){ // 将工号传入 showInfo 方法中 // 遍历整个 ArrayList for(int i=0;i0){ al.set(j,emp1); // 交换值并重写入 al 中 al.set(j-1,emp2); // 交换值并重写入 al 中 } } } for(Emp emp:al){ System.out.println(" 工 号 : "+emp.getEmpNo()+"\t 姓 名 : "+emp.getName()+"\t 工资: "+emp.getSal()); } } // 修改员工的薪水 public void updateSal(String empNo,float newSal){ // 遍历整个 ArrayList for(int i=0;i值 Emp emp=(Emp)hm.get("s002"); System.out.println(" 名字 "+emp.getName()); }else{ System.out.println(" 没该员工 "); } // 遍历 HashMap中所有的 key 和 value 值 //Iterator 迭代 Iterator it=hm.keySet().iterator(); //hasNext 返回一个 boolean 值 while(it.hasNext()){ // 如果有下一个取出 key 值 String key=it.next().toString(); // 通过 key 取出 value Emp emp=(Emp)hm.get(key); System.out.println(" 名字: "+emp.getName()); System.out.println(" 工资: "+emp.getSal()); } } } // 创建员工类 class Emp{ // 定义成员变量工号、姓名、薪水 private String empNo; private String name; private float sal; // 创建构造函数,初始化成员变量 public Emp(String empNo,String name,float sal){ this.empNo=empNo; this.name=name; this.sal=sal; } 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 102 | 436 // 使用 set 、get 方法进行数据传递 public String getEmpNo() { return empNo; } public void setEmpNo(String empNo) { this.empNo = empNo; } public String getName() { return name; } public void setName(String name) { this.name = name; } public float getSal() { return sal; } public void setSal(float sal) { this.sal = sal; } } ------------------------------------------------------------------------------- Hashtable 集合类的使用 ( Hashtable 具有同步性,线程安全 ) import java.util.*; public class Demo144{ public static void main(String []args){ Hashtable ht=new Hashtable(); //Hashtable 与 HsahMap在用法上一致 Emp emp4=new Emp("s101","a1",2.2f); Emp emp5=new Emp("s102","a2",1.2f); Emp emp6=new Emp("s103","a3",4.2f); ht.put("s101", emp4); ht.put("s102", emp5); ht.put("s103", emp6); // 遍历 for( Iterator it=ht.keySet().iterator();it.hasNext(); ){ String key=it.next().toString(); Emp emp=(Emp)ht.get(key); System.out.println(" 名字: "+emp.getName()+"\t 工资: "+emp.getSal()); } } } // 创建员工类 class Emp{ // 定义成员变量工号、姓名、薪水 private String empNo; 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 103 | 436 private String name; private float sal; // 创建构造函数,初始化成员变量 public Emp(String empNo,String name,float sal){ this.empNo=empNo; this.name=name; this.sal=sal; } // 使用 set 、get 方法进行数据传递 public String getEmpNo() { return empNo; } public void setEmpNo(String empNo) { this.empNo = empNo; } public String getName() { return name; } public void setName(String name) { this.name = name; } public float getSal() { return sal; } public void setSal(float sal) { this.sal = sal; } } ------------------------------------------------------------------------------- HashMap和 Hashtable 集合类的区别 HashMap 与 Hashtable 都是 java 的集合类,都可以用来存放 java 对象,这是他们的相 同点,但是他们也有区别。 1、历史原因 Hashtable 是基于陈旧的 Dictionary 类的, HashMap是 java 1.2 引进的 Map接口的一 个实现。 2、同步性 Hashtable 是线程同步的 。这个类中的一些方法 保证了 Hashtable 中的对象是线程安全 的。而 HashMap则是线程异步的 ,因此 HashMap中的对象并不是线程安全的 。因为 同步的要 求会影响执行的效率 ,所以如果你 不需要线程安全的集合那么使用 HashMap是一个很好的选 择,这样可以避免由于同步带来的不必要的性能开销,从而提高效率。 3、值 HashMap可以让你将空值作为一个表的条目的 key 或 value 但是 Hashtable 是不能放入 空值的 (null) 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 104 | 436 集合框架 -- 深入讨论 进一步理解集合框架 java 的设计者给我们提供了这些集合类,在后面编程中是相当有用的,具体什么时候 用什么集合,要根据我们刚才分析的集合异同来选取。 如何选用集合类? 1、要求线程安全,使用 Vector 、Hashtable 2、不要求线程安全,使用 ArrayList,LinkedList,HashMap 3、要求 key 和 value 键值,则使用 HashMap,Hashtable 4、数据量很大,又要线程安全,则使用 Vector =============================================================================== Set 结构的集合类 HashSet 类, TreeSet 类 HashSet 是基于 HashMap实现的, HashSet 底层采用 HashMap来保存所有元素。 hashCode 和 equal() 是 HashMap用的,因为无需排序所以只需要关注定位和唯一性即可 hashCode 是用来计算 hash 值的, hash 值是用来确定 hash 表索引的 hash 表中的一个索引存放的是一张链表,所以还要通过 equal 方法循环比较链上的每一个 对象才可以真正定位到键值对应的 Entry put 时,如果 hash 表中没定定位到, 就在链表前加一个 Entry ,如果定位到了, 则更换 Entry 中的 value( 值) 并返回旧 value( 值 ) 覆写 key 的 hashCode() 和 equal() 时一定要注意, 不要把它们和可变属性关联上, 否则属性 变了之后 hashCode 会变,equal 也会为 false ,这样在 Map中就找不到它了而且这样的对象 因为找不到它所以得不到释放,这样就变成了一个无效引用 ( 相当于内存泄漏 ) //HashSet 的使用方法 [Demo145.java] import java.util.*; public class Demo145{ public static void main(String []args){ HashSet hs=new HashSet(); Emp emp1=new Emp("s001","aa",1.2f); Emp emp2=new Emp("s002","bb",1.6f); Emp emp3=new Emp("s003","cc",1.8f); Emp emp4=new Emp("s001","aa",1.2f); hs.add(emp1); hs.add(emp2); hs.add(emp3); hs.add(emp4); hs.add(emp1); // 重复的 emp1,HashSet 会自动去除 System.out.println("HashSet_size="+hs.size()); System.out.println(); ArrayList al=new ArrayList(); Emp emp5=new Emp("s004","dd",1.0f); Emp emp6=new Emp("s005","ee",2.5f); al.add(emp5); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 105 | 436 al.add(emp6); //al.add(emp1); hs.addAll(al); // 将 al 中的值加到 hs 中,并去除重复的 emp1 System.out.println("HashSet_ArrayList_size="+hs.size()); System.out.println(); // 转换数组 o[] ,遍历并输出 HashSet 中的无素 Object o[]=hs.toArray(); for(int i=0;ist.num?1:(num==st.num?0:-1); // 判断学号是否相同并返回 result 的值 // 如果学号相等,就按姓名排列 /* if(result==0){ return name.compareTo(st.name); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 107 | 436 }*/ return result; } // 实现 Comparator 接口并实现它的抽象方法 public int compare(Object o1,Object o2){ Student st1 =(Student)o1; Student st2 =(Student)o2; return st1.name.compareTo(st2.name); // 比较姓名是否相同 } // 重写 toString() 方法,因为如果不重写,打印出来的是 16 进制代码 public String toString(){ return "num="+num+"; name="+name; } public static class StudentComparator implements Comparator{ // 定义一个静态 StudentComparator 类并实现 Comparator 接口 public int compare(Object o1,Object o2){ Student st1 =(Student)o1; Student st2 =(Student)o2; int result; result=st1.num>st2.num?1:(st1.num==st2.num?0:-1); // 判断学号是否相同 进行排序 if(result==0){ // 如果学号相等 就进行名字排序 result=st1.name.compareTo(st2.name); } return result; } } } ------------------------------------------------------------------------------- HashSet 与 TreeSet 集合类的区别: HashSet 是基于 hash 算法实现的,性能优于 TreeSet 。通常使用 HashSet,在我们需要对其 中元素排序的时候才使用 TreeSet 。 =============================================================================== Queue结构的集合 Queue接口 Queue 接口与 List 、Set 同一级别,都是继承了 Collection 接口。 LinkedList 实现了 Queue接口。 Queue接口窄化了对 LinkedList 的方法的访问权限 (即在方法中的参数类型如 果是 Queue时,就完全只能访问 Queue接口所定义的方法了,而不能直接访问 LinkedList 的非 Queue的方法),以使得只有恰当的方法才可以使用。 BlockingQueue 继承了 Queue 接 口。 队列是一种数据结构。 它有两个基本操作: 在队列尾部加人一个元素, 和从队列头部移 除一个元素。 就是说, 队列以一种先进先出的方式管理数据, 如果你试图向一个已经满了的 阻塞队列中添加一个元素或者是从一个空的阻塞队列中移除一个元索,将导致线程阻塞。 在多线程进行合作时, 阻塞队列是很有用的工具。 工作者线程可以定期地把中间结果存 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 108 | 436 到阻塞队列中而其他工作者线线程把中间结果取出并在将来修改它们。队列会自动平衡负 载。如果第一个线程集运行得比第二个慢, 则第二个线程集在等待结果时就会阻塞。 如果第 一个线程集运行得快,那么它将等待第二个线程集赶上来。 add 增加一个元索 如果队列已满, 则抛出一个 IIIegaISlabEepeplian 异 常 remove 移除并返回队列头部的元 素 如果队列为空,则抛出一个 NoSuchElementException 异常 element 返回队列头部的元素 如果队列为空,则抛出一个 NoSuchElementException 异常 offer 添加一个元素并返回 true 如果队列已满,则返回 false poll 移除并返问队列头部的元 素 如果队列为空,则返回 null peek 返回队列头部的元素 如果队列为空,则返回 null put 添加一个元素 如果队列满,则阻塞 take 移除并返回队列头部的元 素 如果队列为空,则阻塞 remove、element 、 offer 、poll 、 peek 其实是属于 Queue接口。 阻塞队列的操作可以根据它们的响应方式分为以下三类: add、remove 和 element 操作 在你试图为一个已满的队列增加元素或从空队列取得元素时 抛出异常。当然,在多线程程 序中,队列在任何时间都可能变成满的或空的, 所以你可能想使用 offer 、poll 、peek 方法。 这些方法在无法完成任务时 只是给出一个出错示而不会抛出异常。 注意: poll 和 peek 方法出错进返回 null 。因此,向队列中插入 null 值是不合法的。 offer ,add 区别: 一些队列有大小限制,因此如果想在一个满的队列中加入一个新项,多出的项就会被拒绝。 这时新的 offer 方法就可以起作用了。它不是对调用 add() 方法抛出一个 unchecked 异 常,而只是得到由 offer() 返回的 false 。 poll ,remove 区别: remove() 和 poll() 方 法 都 是 从 队 列 中 删 除 第 一 个 元 素 ( head )。 remove() 的 行 为 与 Collection 接口的版本相似, 但是新的 poll() 方法在用空集合调用时不是抛出异常, 只是 返回 null 。因此新的方法更适合容易出现异常条件的情况。 peek,element 区别: element() 和 peek() 用于在队列的头部查询元素。与 remove() 方法类似,在队列为空时, element() 抛出一个异常,而 peek() 返回 null 。 五个队列所提供的各有不同: * ArrayBlockingQueue : 一个由数组支持的有界队列。基于数组的阻塞循环队列,先进先出原则对元素进行排序。 * LinkedBlockingQueue : 一个由链接节点支持的可选有界队列。基于链表的队列,先进先出排序元素。 * PriorityBlockingQueue : 一个由优先级堆支持的无界优先级队列。 PriorityBlockingQueue 是对 PriorityQueue 的再 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 109 | 436 次包装,是基于堆数据结构的,而 PriorityQueue 是没有容量限制的,与 ArrayList 一样, 所以在优先阻塞队列上 put 时是不会受阻的。 但是由于资源被耗尽, 所以试图执行添加操作 可能会导致 OutOfMemoryError ),但是如果队列为空,那么取元素的操作 take 就会阻塞, 所以它的检索操作 take 是受阻的。另外,往入该队列中的元素要具有比较能力。 * DelayQueue : 一个由优先级堆支持的、基于时间的调度队列。 (基于 PriorityQueue 来实现的)是一个存 放 Delayed 元素的无界阻塞队列,只有在延迟期满时才能从中提取元素。该队列的头部是 延迟期满后保存时间最长的 Delayed 元素。如果延迟都还没有期满,则队列没有头部,并 且 poll 将返回 null 。当一个元素的 getDelay(TimeUnit.NANOSECONDS) 方法返回一个小于 或等于零的值时,则出现期满, poll 就以移除这个元素了。此队列不允许使用 null 元素。 * SynchronousQueue : 一个利用 BlockingQueue 接口的简单聚集( rendezvous )机制。 SynchronousQueue 类是最简单的。它没有内部容量。它就像线程之间的手递手机制。在队 列中加入一个元素的生产者会等待另一个线程的消费者。 当这个消费者出现时, 这个元素就 直接在消费者和生产者之间传递,永远不会加入到阻塞队列中。 注意: Queue队列是不能直接实例化的。 原先在 java 编程中, Queue的实现都是用 LinkedList 如: Queue qe=new LinkedList(); 注意: 此实现不是同步的。 如果多个线程同时访问一个链接列表, 而其中至少一个线程结构 上修改了该列表,则它必须保质外部同步。 ( 结构修改指添加或删除一个或多个元素的任何 操作;仅设置元素的值不是结构修改。 ) 这一般通过对自然封装该列表的对象进行同步操作 来完成。 JDK1.6 中: 接口 Queue 类型参数: E - collection 中所保存元素的类型。 所有超级接口: Collection, Iterable 所有已知子接口: BlockingDeque, BlockingQueue, Deque 所有已知实现类: AbstractQueue, ArrayBlockingQueue, ArrayDeque, ConcurrentLinkedQueue, DelayQueue, LinkedBlockingDeque, LinkedBlockingQueue, LinkedList, PriorityBlockingQueue, PriorityQueue, SynchronousQueue JDK1.7 中: 接口 Queue 类型参数: E - collection 中所保存元素的类型。 所有超级接口: Collection, Iterable 所有已知子接口: BlockingDeque, BlockingQueue, Deque, TransferQueue 所有已知实现类: AbstractQueue, ArrayBlockingQueue, ArrayDeque, ConcurrentLinkedQueue, ConcurrentLinkedQueue, DelayQueue, LinkedBlockingDeque, LinkedBlockingQueue, LinkedList, LinkedTransferQueue, PriorityBlockingQueue, PriorityQueue, SynchronousQueue =============================================================================== Java 中的 List/Set 和 Map的区别 List 按对象进入的顺序保存对象,不做排序和编辑操作。 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 110 | 436 Set 对每个对象只接受一次,并使用自己内部的排序方法 ( 通常,你只关心某个元素是 否属于 Set 而不关心它的顺序 -- 否则使用 List) 。 Map 同样对每个元素保存一份, 但这是基于 " 键 "(key) 的,Map也有内置的排序, 因而不 关心元素添加的顺序。 如果添加元素的顺序对程序设计很重要, 应该使用 LinkedHashSet 或者 LinkedHashMap。 List 的功能方法 实际上有两种 List :一种是基本的 ArrayList 其优点在于随机访问元素,另一种是更 强大的 LinkedList 它并不是为快速随机访问设计的,而是具有一套更通用的方法。 List :次序是 List 最重要的特点:它保证维护元素特定的顺序。 List 为 Collection 添加了许多方法,使得能够向 List 中间插入与移除元素 ( 这只推荐 LinkedList 使用 )一个 List 可以生成 Listlterator ,使用它可以从两个方向遍历 List ,也可以从 List 中间插入 和移除元素。 ArrayList :由数组实现的 List 。允许对元素进行快速随机访问,但是向 List 中间插 入与移除元素的速率很慢。 Listlterator 只应该用来由后向前遍历 ArrayList 。而不是用来 插入和移除元素。因为那比 LinkedList 开销要大很多。 LinkedList :对顺序访问进行了优化,向 List 中间插入与删除的开销并不大。随机访 问则相对较慢。 ( 使用 ArrayList 代替 ) 还具有下列方法: addFirst() , addLast() , getFirst() ,getLast() ,removeFirst() 和 removeLast() 这些方法 ( 没有在任何接口或基类 中定义过 )使得 LinkedList 可以当作堆栈、队列和双向队列使用。 Set 的功能方法 Set 具有与 Collection 完全一样的接口,因此没有任何额外的功能,不象前面有两个 不同的 List 。实际上 Set 就是 Collection ,只是行为不同。 ( 这是继承与多态思想的典型应 用:表现不同的行为。 )Set 不保存重复的元素 (至于如何判断元素相同则较为负责 ) Set :存入 Set 的每个元素都必须是唯一的,因为 Set 不保存重复元素。加入 Set 的元 素必需定义 equals() 方法以确保对象的唯一性。 Set 与 Collection 有完全一样的接口。 Set 接口不保证维护元素的次序。 HashSet :为快速查找设计的 Set 。存入 HashSet 的对象必须定义 hashCode() 。 TreeSet :保存次序的 Set,底层为树结构。使用它可以从 Set 中提取有序的序列。 LinkedHashSet :具有 HashSet 的查询速度, 且内部使用链表维护元素的顺序 ( 插入的次 序) 。于是在使用迭代器遍历 Set 时,结果会按元素插入的次序显示。 Map的功能方法 方法 put(Object key,Object value) 添加一个 " 值"( 想要得东西 ) 和与 " 值" 相关的 " 键 "(key)( 使用它来查找 ) 。方法 get(Object key) 返回与给定 " 键 " 相关联的 " 值" 。可以用 containsKey() 和 containsValue() 测试 Map中是否包含某个 " 键" 或" 值 " 。标准的 java 类库 中 包 含 了 几 种 不 同 的 Map: HashMap, TreeMap , LinkedHashMap , WeakHashMap, ldentityHashMap 。它们都有同样的基本接口 Map,但是行为、效率、排序策略、保存对象 的生命周期和判定 "键" 等价的策略等各不相同。 执行效率是 Map的一个大问题。看看 get() 要做哪些事,就会明白为什么在 ArrayList 中搜索 " 键" 是相当慢的。这正是 HashMap提高速度的地方。 HashMap使用了特殊的值,称为 " 散列码 "(hash code) ,来取代对键的缓慢搜索。 " 散列码 " 是" 相对唯一 " 用以代表对象的 int 值,它是通过将该对象的某些信息进行转换而生成的。所有 java 对象都能产生散列码,因 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 111 | 436 为 hashCode() 是定义在基类 Object 中的方法。 HashMap 就是使用对象的 hashCode() 进行快速查询的。此方法能够显著提高性能。 Map :维护 " 键值对 " 的关联性,使你可通过 "键 " 查找 " 值" HashMap :Map 基于散列表的实现。插入和查询 " 键值对 " 的开销是固定的。可以通过构 造器设置容量 capacity 和负载因子 load factor ,以调整容器的性能。 LinkedHashMap :类似于 HashMap,但是迭代遍历它时,取得 " 键值对 " 的顺序是其插入 次序,或者是最近最少使 (LRU)的次序。只能 HashMap慢一点。而在迭代访问时发而更快, 因为它使用键表维护内部次序。 TreeMap :基于红黑树数据结果的实现。 查看 "键" 或" 键值对 " 时,它们会被排序 (次序由 Comparabel 或 Comparator 决定 ) 。TreeMap的特点在于, 你得到的结果是经过排序的。 TreeMap 是唯一的带有 subMap() 方法的 Map,它可以返回一个子树。 WeakHashMap: 旨键 (weak key)Map ,Map 中使用的对象也被允许释放:这是为解决特殊 问题设计的。如果没有 map之外的引用指向某个 " 键" ,则此 " 键" 可以被垃圾收集器回收。 ldentifyHashMap :使用 ==代替 equals() 对" 键"作比较的 hash map。专为解决特殊问题 而设计。 ------------------------------------------------------------------------------- Java 中的 Iterator( 迭代器 ) 的用法 java.util 包中包含了一系列重要的集合类,集合类的根接口 Collection 。 Collection 接口是所有集合类的根类型。它的一个主要的接口方法是: boolean add(Object c) 添加数据 add() 方法将添加一个新元素。注意这个方法会返回一个 boolean ,但是返回值不是表 示添加成功与否。 Collection 规定:如果一个集合拒绝添加这个元素,无论任何原因,都 必须抛出异常。这个返回值表示的意义是 add() 方法执行后,集合的内容是否改变了 ( 就是 元素有无数量,位置等变化 ) ,这是由具体类实现的。即:如果方法出错,总会抛出异常; 返回值仅仅表示该方法执行后这个 Collection 的内容有无变化。 类似还有: boolean addall(Collection c); 添加所有数据 boolean remove(Object o); 删除数据 boolean removeall(Collection c); 删除所有数据 boolean remainall(Collection c); 保持所有数据 Object[]toArray() 方法很简单, 把集合转换成数组返回。 Object[]toArray(Object[] a) 方法就有点复杂了,首先,返回的 Object[] 仍然是把集合的所有元素变成数组,但是类型 和参数 a 的类型是相同的。 如: String[] o=(String)c.toArray(new String[0]); 得到的 o 实际类型是 String[] 数组。 其次, 如果参数 a 的大小装不下集合的所有元素, 返回的将是一个新的数组。 如果参数 a 的大小能装下集合的所有元素,则返回的还是 a,但 a 的内容用集合的元素来填充。尤其 要注意的是,如果 a 的大小比集合元素的个数还多, a 后面的部分全部被置为 null( 空) 。 最后一个最重要的方法是 Iterator() ,返回一个 Iterator( 迭代子 ) ,用于遍历集合的 所有元素。 用 Iterator 模式实现遍历集合 Iterator 模式 是用于遍历集合类的标准访问方法。 它可以把访问逻辑从不同类型的集合类 中抽象出来,从而避免向客户端暴露集合的内部结构。 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 112 | 436 例如,如果没有使用 Iterator ,遍历一个数组的方法是使用索引: for(int i=0;i al=new ArrayList(); // 即泛型的指定参数,提高安全 性 ArrayList bl=new ArrayList(); // 创建一只狗 Dog dog1=new Dog(); // 放入到集合中 al.add(dog1); // 取出 Dog temp=al.get(0); // 引用泛型后即可不用强转, Dog temp=(Dog)al.get(0); Cat temp1=(Cat)bl.get(0); } } class Cat{ private String color; private int age; public String getColor() { return color; } 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 114 | 436 public void setColor(String color) { this.color = color; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } class Dog{ private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } ------------------------------------------------------------------------------- Java--> 反射机制 [Demo147.java] // 泛型的必要性 import java.util.*; import java.lang.reflect.Method; // 引入 Java 反射方法类 public class Demo147 { public static void main(String[] args) { Gen gen1=new Gen("aa"); //<> 可以放任意类型 Gen gen2=new Gen(new Bird()); //<> 也可以放入定义好的类 gen1.showTypeName(); gen2.showTypeName(); } } // 定义一个 Bird class Bird{ public void test1(){ 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 115 | 436 System.out.println("aa"); } public void count(int a,int b){ System.out.println(a+b); } } // 定义一个类 class Gen { //T 传入什么类型, Gen类就是什么什么类型 private T o; // 构造函数 public Gen(T a){ o=a; } // 得到 T 的类型名称 public void showTypeName(){ System.out.println(" 类型是: "+o.getClass().getName()); // 通过反射机制,我们可以得到 T 这个类型的很多信息 // 得到成员函数名 Method [] m=o.getClass().getDeclaredMethods(); // 打印 for(int i=0;i al=null; / / 构造函数,初始化成员变量 public Referee(){ al=new ArrayList(); } // 加入裁判 public void addDive(Dive dive){ al.add(dive); } // 查看选手得分 public void View(){ float allnum=0f,pjnum=0f; // 遍历 for(int i=0;ifens[i]){ // 当 minFen 大于 fens[i] 修改最低分 minFen minFen=fens[i]; minIndex=i; } } return minIndex; } //2 、去掉最高分 ( 目地就是找到最高分的下标 ) public int getMaxFenIndex(){ // 选择法 // 认为第一个是最低分 float maxFen=fens[0]; int maxIndex=0; for(int i=1;i al=null; // 构造函数 public Result(){ al=new ArrayList(); } // 加入成绩 public void addResult(Student student){ al.add(student); } // 输入入学号,打印学生成绩 public void Id(){ System.out.println(" 请输入查询学号进行查询: "); int id=sr.nextInt(); for(int i=0;i=90f){ a++; }else if(al.get(i).getScore()<90f&&al.get(i).getScore()>=80f){ b++; }else if(al.get(i).getScore()<80f&&al.get(i).getScore()>=70f){ c++; }else if(al.get(i).getScore()<70f&&al.get(i).getScore()>=60f){ d++; }else if(al.get(i).getScore()<60f&&al.get(i).getScore()>0){ e++; }else if(al.get(i).getScore()==0){ f++; } } System.out.println(" 成绩优有: "+a+" 人"); System.out.println(" 成绩良有: "+b+" 人"); System.out.println(" 成绩中有: "+c+" 人"); System.out.println(" 成绩差有: "+d+" 人"); System.out.println(" 不及格有: "+e+" 人"); System.out.println(" 无成绩有: "+f+" 人"); } // 通过学号删除成绩 public void Del(){ System.out.println(" 请输入要删除成绩的学号: "); int id=sr.nextInt(); id=id-1; for(int i=0;i=90f){ a++; 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 130 | 436 }else if(arr[i]<90f&&arr[i]>=80f){ b++; }else if(arr[i]<80f&&arr[i]>=70f){ c++; }else if(arr[i]<70f&&arr[i]>=60f){ d++; }else if(arr[i]<60f&&arr[i]>0){ e++; }else if(arr[i]==0){ f++; } } System.out.println(" 成绩优有: "+a+" 人"); System.out.println(" 成绩良有: "+b+" 人"); System.out.println(" 成绩中有: "+c+" 人"); System.out.println(" 成绩差有: "+d+" 人"); System.out.println(" 不及格有: "+e+" 人"); System.out.println(" 无成绩有: "+f+" 人"); } // 删除学生成绩 public void Del(){ System.out.println(" 请输入要删除成绩的学号: "); int No=sr.nextInt(); System.out.println(" 学号为 "+No+" 的学生原成绩为: "+arr[No]); System.out.println(" 学号为 "+No+" 的学生成绩已清 "+(arr[No]=0)); } } ------------------------------------------------------------------------------- 3、三个同学考试,共考三门课:语文、数学、英语。使用二维整数数组存放三个同学的学 号和所有考试成绩。 学号 语文 数学 英语 1002 78 92 76 1003 67 88 80 1007 90 95 80 // 程序示例 [Demo152.java] public class Demo152 { public static void main(String[] args) { // 定义一个二维整数数组并初始化赋值 int stus[][]={{1002,78,92,76},{1003,67,88,80},{1007,90,95,80}}; // 也可以下面的方法 ( 不建议使用,效率太慢 ) int stus2[][]=new int[3][4]; stus2[0][0]=1002; 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 131 | 436 stus2[1][0]=1003; stus2[2][0]=1007; stus2[0][1]=78; stus2[1][1]=67; stus2[2][1]=90; stus2[0][2]=92; stus2[1][2]=88; stus2[2][2]=95; stus2[0][3]=76; stus2[1][3]=80; stus2[2][3]=80; for(int i=0;itempHao){ bestIndex=i; hao=tempHao; } } return bestIndex; } // 得到最后评分 public float lastFen(){ //3 、得到最后分数 float allFen=0; int minIndex=this.getminFenIndex(); int maxIndex=this.getMaxFenIndex(); // 遍历 for(int i=0;ifens[i]){ // 当 minFen 大于 fens[i] 修改最低分 minFen minFen=fens[i]; minIndex=i; } } 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 134 | 436 return minIndex; } //2 、去掉最高分 ( 目地就是找到最高分的下标 ) public int getMaxFenIndex(){ // 选择法 // 认为第一个是最低分 float maxFen=fens[0]; int maxIndex=0; for(int i=1;i 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 143 | 436 } - 注释 - boolean 变量只能以 true 或 false 作为值。 boolean 不能与数字类型相互转换。 包含 boolean 操作数的表达式只能包含 boolean 操作数。 Boolean 类是 boolean 原始类型的包装对象类。 3.break 用于提前退出 for 、while 或 do 循环,或者在 switch 语句中用来结束 case 块。 - 示例 - for (i=0; i){ break; } } int type = ; switch (type){ case 1: break; case 2: break; default: } - 注释 - break 总是退出最深层的 while 、 for 、do 或 switch 语句。 4.byte byte 是 Java 原始类型。 byte 可存储在 [-128, 127] 范围以内的整数值。 - 示例 - byte b = 124; - 注释 - Byte 类是 byte 原始类型的包装对象类。它定义代表此类型的值的范围的 MIN_VALUE 和 MAX_VALUE 常量。 Java 中的所有整数值都是 32 位的 int 值,除非值后面有 l 或 L (如 235L ),这表示该 值应解释为 long 。 5.case 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 144 | 436 用来标记 switch 语句中的每个分支。 - 示例 - int arg = ; switch (arg){ case 1: break; case 2: break; default: break; } - 注释 - case 块没有隐式结束点。 break 语句通常在每个 case 块末尾使用,用于退出 switch 语 句。 如果没有 break 语句,执行流将进入所有后面的 case 和/ 或 default 块。 6.catch catch 关键字用来在 try-catch 或 try-catch-finally 语句中定义异常处理块。 - 示例 - try{ }catch ( e){ } try{ }catch (FooException e){ }catch (BarException e){ } try{ }catch ( e){ }finally{ } 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 145 | 436 - 注释 - 开始和结束标记 { 和 } 是 catch 子句语法的一部分,即使该子句只包含一个语句,也不 能省略这两个标记。 每个 try 块都必须至少有一个 catch 或 finally 子句。 如果某个特定异常类未被任何 catch 子句处理,该异常将沿着调用栈递归地传播到下一个 封闭 try 块。如果任何封闭 try 块都未捕获到异常, Java 解释器将退出,并显示错误消 息和堆栈跟踪信息。 7.char char 是 Java 原始类型。 char 变量可以存储一个 Unicode 字符。 - 示例 - char delimiter = ';'; - 注释 - 可以使用下列 char 常量: \b - 空格 \f - 换页 \n - 换行 \r - 回车 \t - 水平制表符 \' - 单引号 \" - 双引号 \" - 反斜杠 \xxx - 采用 xxx 编码的 Latin-1 字符。 \x 和 \xx 均为合法形式,但可能引起混淆。 \uxxxx - 采用十六进制编码 xxxx 的 Unicode 字符。 Character 类包含一些可用来处理 char 变量的 static 方法,这些方法包括 isDigit() 、 isLetter() 、isWhitespace() 和 toUpperCase() 。 char 值没有符号。 8.class class 关键字用来声明新的 Java 类,该类是相关变量和 / 或方法的集合。 类是面向对象的程序设计方法的基本构造单位。 类通常代表某种实际实体, 如几何形状或人。 类是对象的模板。每个对象都是类的一个实例。 要使用类,通常使用 new 操作符将类的对象实例化,然后调用类的方法来访问类的功能。 - 示例 - public class Rectangle{ float width; float height; public Rectangle(float w, float h){ width = w; height = h; } 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 146 | 436 public float getWidth(){ return width; } public float getHeight(){ return height; } } 9.continue continue 关键字用来跳转到 for 、while 或 do 循环的下一个迭代。 - 示例 - for (i=0; i if (){ continue; } } - 注释 - continue 总是跳到最深层 while 、for 或 do 语句的下一个迭代。 10.default default 关键字用来标记 switch 语句中的默认分支。 - 示例 - int arg = ; switch (arg){ case 1: break; case 2: break; default: break; } - 注释 - default 块没有隐式结束点。 break 语句通常在每个 case 或 default 块的末尾使用,以 便在完成块时退出 switch 语句。 如果没有 default 语句,其参数与任何 case 块都不匹配的 switch 语句将不执行任何操 作。 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 147 | 436 11.do do 关键字用于指定一个在每次迭代结束时检查其条件的循环。 - 示例 - do{ } while (!found); - 注释 - do 循环体至少执行一次。 条件表达式后面必须有分号。 12.double double 是 Java 原始类型。 double 变量可以存储双精度浮点值。 - 示例 - double ratio = .01; double diameter = 6.15; double height = 1.35E03; // 1.35 * 103 或 1350.0 double height = 1e-2; // 1.0 * 10-2 或 0.01 - 注释 - 由于浮点数据类型是实际数值的近似值,因此,一般不要对浮点数值进行是否相等的比较。 Java 浮 点 数 值 可 代 表 无穷 大 和 NaN( 非 数 值 )。 Double 包 装 对 象 类 用来 定 义 常 量 MIN_VALUE、 MAX_VALUE、NEGATIVE_INFINITY、POSITIVE_INFINITY 和 NaN。 13.else else 关键字总是在 if-else 语句中与 if 关键字结合使用。 else 子句是可选的, 如果 if 条件为 false ,则执行该子句。 - 示例 - if (condition){ }else{ } 14.extends extends 关键字用在 class 或 interface 声明中,用于指示所声明的类或接口是其名称后 跟有 extends 关键字的类或接口的子类。 - 示例 - public class Rectangle extends Polygon{ } 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 148 | 436 - 注释 - 在上例中, Rectangle 类继承 Polygon 类的所有 public 和 protected 变量和方法。 Rectangle 类可以重写 Polygon 类的任何非 final 方法。 一个类只能扩展一个其他类。 15.false false 关键字代表 boolean 变量的两个合法值之一。 - 示例 - boolean isComplete = false; 16.final final 关键字可以应用于类,以指示不能扩展该类(不能有子类) 。 final 关键字可以应用于方法,以指示不能重写任何子类中的方法。 - 示例 - public final class MyFinalClass{ } public class MyClass{ public final String myFinalMethod(){ } } - 注释 - 一个类不能同时是 abstract 又是 final 。abstract 意味着必须扩展类, final 意味着不 能扩展类。 一个方法不能同时是 abstract 又是 final 。abstract 意味着必须重写方法, final 意味 着不能重写方法。 17.finally finally 关键字用来定义始终在 try-catch-finally 语句中执行的块。 finally 块通常包含清理代码,用在部分执行 try 块后恢复正常运行。 - 示例 - try{ }catch ( e){ }finally{ } - 注释 - 开始和结束标记 { 和 } 是 finally 子句语法的一部分,即使该子句只包含一个语句,也 不能省略这两个标记。 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 149 | 436 每个 try 块都必须至少有一个 catch 或 finally 子句。 如果执行 try 块的任何部分,不论是否出现异常,也不论 try 或 catch 块是否包含 return 、continue 或 break 语句,都一定会执行 finally 块中的代码。 如果不出现异常,控件将跳过 try 块,进入 finally 块。 如果在执行 try 块期间出现异常, 并且相应的 catch 块包含 break 、continue 或 return 语句,控件将首先穿过 finally 块,之后再执行 break 、continue 或 return 。 18.float float 是 Java 原始类型。 float 变量可以存储单精度浮点值。 - 示例 - float ratio = .01; float diameter = 6.15; float height = 1.35E03; // 1.35 * 103 或 1350.0 float height = 1e-2; // 1.0 * 10-2 或 0.01 - 注释 - 使用此关键字时应遵循下列规则: Java 中的浮点文字始终默认为双精度。 要指定单精度文字值, 应在数值后加上 f 或 F ,如 0.01f 。 由于浮点数据类型是实际数值的近似值,因此,一般不要对浮点数值进行是否相等的比较。 Java 浮点数值可代表无穷大和 NaN(非数值)。Float 包装对象类用来定义常量 MIN_VALUE、 MAX_VALUE、 NEGATIVE_INFINITY、 POSITIVE_INFINITY 和 NaN。 19.for for 关键字用于指定一个在每次迭代结束前检查其条件的循环。 - 示例 - int i; for (i=0; i } - 注释 - for 语句的形式为 for(initialize; condition; increment) 控件流进入 for 语句时,将执行一次 initialize 语句。 每次执行循环体之前将计算 condition 的结果。 如果 condition 为 true ,则执行循环体。 每次执行循环体之后,在计算下一个迭代的 condition 之前,将执行 increment 语句。 20.if if 关键字指示有条件地执行代码块。条件的计算结果必须是布尔值。 - 示例 - if (condition){ 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 150 | 436 } if (condition){ }else{ } - 注释 - if 语句可以有可选的 else 子句,该子句包含条件为 false 时将执行的代码。 包含 boolean 操作数的表达式只能包含 boolean 操作数。 21.implements implements 关键字在 class 声明中使用, 以指示所声明的类提供了在 implements 关键字 后面的名称所指定的接口中所声明的所有方法的实现。 - 示例 - public class Truck implements IVehicle{ } - 注释 - 在上例中, Truck 类必须提供在 IVehicle 接口中所声明的所有方法的实现。 否则, Truck 类将是独立的;它可以声明其他方法和变量,并扩展另一个类。 一个类可以实现多个接口。 22.import import 关键字使一个包中的一个或所有类在当前 Java 源文件中可见。可以不使用完全限 定的类名来引用导入的类。 - 示例 - import java.io.File; import java.net.*; - 注释 - 当多个包包含同名的类时,许多 Java 程序员只使用特定的 import 语句(没有" * ")来避 免不确定性。 23.instanceof instanceof 关键字用来确定对象所属的类。 - 示例 - if (node instanceof TreeNode){ } - 注释 - 在上例中,如果 node 是 TreeNode 类的实例,或者是 TreeNode 的子类的实例,则 instanceof 表达式的值将为 true 。 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 151 | 436 24.int int 是 Java 原始类型。 int 变量可以存储 32 位的整数值。 - 示例 - int number = 5; int octalNumber = 0377; int hexNumber = 0xff; - 注释 - Integer 类是 int 原始类型的包装对象类。 它定义代表此类型的值的范围的 MIN_VALUE 和 MAX_VALUE 常量。 Java 中的所有整数值都是 32 位的 int 值,除非值后面有 l 或 L (如 235L ),这表示该 值应解释为 long 。 25.interface interface 关键字用来声明新的 Java 接口,接口是方法的集合。 接口是 Java 语言的一项强大功能。 任何类都可声明它实现一个或多个接口, 这意味着它实 现了在这些接口中所定义的所有方法。 - 示例 - public interface IPolygon{ public float getArea(); public int getNumberOfSides(); public int getCircumference(); } - 注释 - 实现了接口的任何类都必须提供在该接口中的所有方法的实现。 一个类可以实现多个接口。 26.long long 是 Java 原始类型。 long 变量可以存储 64 位的带符号整数。 - 示例 - long number = 5; long anotherNumber = 34590L; long octalNumber = 0377; long hexNumber = 0xffl; - 注释 - Long 类是 long 原始类型的包装对象类。它定义代表此类型的值的范围的 MIN_VALUE 和 MAX_VALUE 常量。 Java 中的所有整数值都是 32 位的 int 值,除非值后面有 l 或 L (如 235L ),这表示该 值应解释为 long 。 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 152 | 436 27.native native 关键字可以应用于方法,以指示该方法是用 Java 以外的语言实现的。 - 示例 - native String getProcessorType(); - 注释 - Native 方法不在此文档的讨论范围内。 28.new new 关键字用于创建类的新实例。 - 示例 - String sName = new String(); Float fVal = new Float(0.15); - 注释 - new 关键字后面的参数必须是类名,并且类名的后面必须是一组构造方法参数(必须带括 号)。 参数集合必须与类的构造方法的签名匹配。 = 左侧的变量的类型必须与要实例化的类或接口具有赋值兼容关系。 29.null null 是 Java 的保留字,表示无值。 - 示例 - Integer i; i = null; String s; if (s != null){ } - 注释 - 将 null 赋给非原始变量相当于释放该变量先前所引用的对象。 不能将 null 赋给原始类型( byte 、short 、int 、long 、char 、float 、double 、boolean ) 变量。 30.package package 关键字指定在 Java 源文件中声明的类所驻留的 Java 包。 - 示例 - package com.mycompany; public class MyClass{ } - 注释 - 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 153 | 436 package 语句(如果出现)必须是 Java 源文件中的第一个非 - 注释 - 性文本。 在上面的 -示例 - 中, MyClass 类的完全限定类名是 com.mycompany.MyClass 。 如果 Java 源文件不包含 package 语句,在该文件中定义的类将位于"默认包"中。请注 意,不能从非默认包中的类引用默认包中的类。 31.private private 关键字是访问控制修饰符,可以应用于类、方法或字段(在类中声明的变量) 。 - 示例 - public class MyPublicClass{ private class MyPrivateClass{ } private int i; private String myMethod(){ } } - 注释 - 只能在声明 private (内部)类、方法或字段的类中引用这些类、方法或字段。在类的外部 或者对于子类而言,它们是不可见的。 所有类成员的默认访问范围都是 package 访问,也就是说,除非存在特定的访问控制修饰 符,否则,可以从同一个包中的任何类访问类成员。 32.protected protected 关键字是可以应用于类、方法或字段(在类中声明的变量)的访问控制修饰符。 - 示例 - public class MyPublicClass{ protected class MyPrivateClass{ } protected int i; protected String myMethod(){ } } - 注释 - 可以在声明 protected 类、方法或字段的类、同一个包中的其他任何类以及任何子类(无 论子类是在哪个包中声明的)中引用这些类、方法或字段。 所有类成员的默认访问范围都是 package 访问,也就是说,除非存在特定的访问控制修饰 符,否则,可以从同一个包中的任何类访问类成员。 33.public public 关键字是可以应用于类、方法或字段(在类中声明的变量)的访问控制修饰符。 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 154 | 436 - 示例 - public class MyPublicClass{ public class MyPrivateClass{ } public int i; public String myMethod(){ } } - 注释 - 可能只会在其他任何类或包中引用 public 类、方法或字段。 所有类成员的默认访问范围都是 package 访问,也就是说,除非存在特定的访问控制修饰 符,否则,可以从同一个包中的任何类访问类成员。 34.return return 关键字会导致方法返回到调用它的方法, 从而传递与返回方法的返回类型匹配的值。 - 示例 - public void myVoidMethod(){ return; } public String myStringMethod(){ String s = "my response"; return s; } public int myIntMethod(){ int i = 5; return(i); } - 注释 - 如果方法具有非 void 的返回类型, return 语句必须具有相同或兼容类型的参数。 返回值两侧的括号是可选的。 35.short short 是 Java 原始类型。 short 变量可以存储 16 位带符号的整数。 - 示例 - short number = 5; short octalNumber = 0077; short hexNumber = 0xff; - 注释 - Short 类是 short 原始类型的包装对象类。 它定义代表此类型的值的范围的 MIN_VALUE 和 MAX_VALUE 常量。 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 155 | 436 Java 中的所有整数值都是 32 位的 int 值,除非值后面有 l 或 L (如 235L ),这表示该 值应解释为 long 。 36.static static 关键字可以应用于内部类 (在另一个类中定义的类) 、方法或字段 (类的成员变量) 。 - 示例 - public class MyPublicClass{ public final static int MAX_OBJECTS = 100; static int _numObjects = 0; static class MyStaticClass{ } static int getNumObjects(){ } } - 注释 - 通常, static 关键字意味着应用它的实体在声明该实体的类的任何特定实例外部可用。 static (内部)类可以被其他类实例化和引用(即使它是顶级类) 。在上面的 - 示例 - 中,另 一个类中的代码可以实例化 MyStaticClass 类,方法是用包含它的类名来限定其名称,如 MyClass.MyStaticClass 。 static 字段(类的成员变量)在类的所有实例中只存在一次。 可以从类的外部调用 static 方法,而不用首先实例化该类。 这样的引用始终包括类名作为 方法调用的限定符。 在上面的示例中, MyClass 类外部的代码以 MyClass.getNumObjects() 的形式调用 getNumObjects() static 方法。 模式: public final static varName = ; 通常用于声明可以在类的外部使用的类常量。在引用这样的类常量时需要用类名加以限定。 在上面的 - 示例 - 中,另一个类可以用 MyClass.MAX_OBJECTS 形式来引用 MAX_OBJECTS 常 量。 37.super super 关键字用于引用使用该关键字的类的超类。 - 示例 - public class MyClass{ public MyClass(String arg){ super(arg); } public String myStringMethod(){ return super.otherStringMethod(); } } 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 156 | 436 - 注释 - 作为独立语句出现的 super 表示调用超类的构造方法。 super.() 表示调用超类的方法。只有在如下情况中才需要采用这种用法:要 调用在该类中被重写的方法,以便指定应当调用在超类中的该方法。 38.switch switch 语句用于基于某个表达式选择执行多个代码块中的某一个。 - 示例 - int arg = ; switch (arg){ case 1: break; case 2: break; default: break; } char arg = ; switch (arg){ case 'y': case 'Y': break; case 'n': case 'N': break; default: break; } - 注释 - switch 条件的计算结果必须等于 byte 、char 、short 或 int 。 case 块没有隐式结束点。 break 语句通常在每个 case 块末尾使用,用于退出 switch 语 句。 如果没有 break 语句,执行流将进入所有后面的 case 和/ 或 default 块。 39.synchronized synchronized 关键字可以应用于方法或语句块,并为一次只应由一个线程执行的关键代码 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 157 | 436 段提供保护。 - 示例 - public class MyClass{ public synchronized static String mySyncStaticMethod(){ } public synchronized String mySyncMethod(){ } } public class MyOtherClass{ Object someObj; public String myMethod(){ synchronized (someObj){ } } } - 注释 - synchronized 关键字可防止代码的关键代码段一次被多个线程执行。 如果应用于静态方法 (如上例中的 MySyncStaticMethod ),那么,当该方法一次由一个线程 执行时,整个类将被锁定。 如果应用于实例方法 (如上例中的 MySyncMethod),那么,当该方法一次由一个线程访问时, 该实例将被锁定。 如果应用于对象或数组,当关联的代码块一次由一个线程执行时,对象或数组将被锁定。 40.this this 关键字用于引用当前实例。 - 示例 - public class MyClass{ int number; public MyClass(int number){ this.number = number; } } - 注释 - 当引用可能不明确时,可以使用 this 关键字来引用当前的实例。 在上面的 - 示例 - 中,构造方法参数 number 与类的成员变量同名。 this.number 明确表示 MyClass 的该实例的 number 成员变量。 41.throw throw 关键字用于引发异常。 - 示例 - 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 158 | 436 import java.io.IOException; public class MyClass{ public method readFile(String filename) throws IOException{ if (error){ throw new IOException("error reading file"); } } } - 注释 - throw 语句将 java.lang.Throwable 作为参数。 Throwable 在调用栈中向上传播,直到被 适当的 catch 块捕获。 引发非 RuntimeException 异常的任何方法还必须在方法声明中使用 throws 修饰符来声 明它引发的异常。 42.throws throws 关键字可以应用于方法,以便指出方法引发了特定类型的异常。 - 示例 - import java.io.IOException; public class MyClass{ public method readFile(String filename) throws IOException{ if (error){ throw new IOException("error reading file"); } } } - 注释 - throws 关键字将逗号分隔的 java.lang.Throwables 列表作为参数。 引发非 RuntimeException 异常的任何方法还必须在方法声明中使用 throws 修饰符来声 明它引发的异常。 要在 try-catch 块中包含带 throws 子句的方法的调用,必须提供该方法的调用者。 43.transient transient 关键字可以应用于类的成员变量, 以便指出该成员变量不应在包含它的类实例已 序列化时被序列化。 - 示例 - public class MyClass{ private transient String password; } 44.try 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 159 | 436 try 关键字用于包含可能引发异常的语句块。 - 示例 - try{ }catch ( e){ } try{ }catch (FooException e){ }catch (BarException e){ } try{ }catch ( e){ }finally{ } - 注释 - 每个 try 块都必须至少有一个 catch 或 finally 子句。 如果某个特定异常类未被任何 catch 子句处理,该异常将沿着调用栈递归地传播到下一个 封闭 try 块。如果任何封闭 try 块都未捕获到异常, Java 解释器将退出,并显示错误消 息和堆栈跟踪信息。 45.true true 关键字表示 boolean 变量的两个合法值中的一个。 - 示例 - boolean isComplete = true; 46.void void 关键字表示 null 类型。 - 示例 - public class MyClass{ public void doSomething(){ return; } } - 注释 - 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 160 | 436 void 可以用作方法的返回类型,以指示该方法不返回值。 47.volatile volatile 关键字用于表示可以被多个线程异步修改的成员变量。 注意: volatile 关键字在许多 Java 虚拟机中都没有实现。 - 示例 - public class MyClass{ volatile int sharedValue; } - 注释 - volatile 的目标用途是为了确保所有线程所看到的指定变量的值都是相同的。 48.while while 关键字用于指定一个只要条件为真就会重复的循环。 - 示例 - while (!found){ } 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 161 | 436 图形开发 1、图形用户界面 (gui) 介绍 图形用户界面 (Graphics User Interface,GUI) 是用户与程序交互的窗口,比命令行的界面 更加直观并且更好操作。 awt,swing,swt,Jface 是什么? Sun 已经提供了一个跨平台 GUI 开发工具包 AWT 抽象窗口工具箱 (Abstract Window Toolkit). ↓ Sun又创建了一个新的 GUI 框架 swing. 解决了 AWT存在的 Icd 问题 . ↓ IBM认为 swing 比较消耗内存,创建了一个新的 GUI库,这就是 SWT ↓ IBM为了方便开发 SWT程序,在 SWT基础上又创建了一个更易用, 功能强大的图开包 "JFace" 2、eclipse 开发工具介绍 eclipse 是什么东西,我们用三句话来说明: 1、eclipse 最早是 IBM附属公司 oti 开发的,一共投入了 4000 万美金,后来捐献给开源社 区 2、eclipse 是一个开源的、可扩展的集成开发环境,已经成为目前最流行的 java 开发工具 3、eclipse 安装后就可以开发 java se 的项目了,但不能开发 java ee 项目,需要安装 web 开发插件 (lomboz 或是 myeclipse..) ide( 集成开发环境,比如 jcreator 、vs、myeclipse 这些开发工具都是 ide) 3、swing 组件介绍 1、JFrame 是 Frame 的子类 2、属于容器类组件,顶层容器 3、JFrame 有一些常用的方法,通过示例与 java 的帮助文档即可了解。 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 162 | 436 按钮组件为什么有? 在图形用户界面编程中, 我们在窗体中会经常使用到按钮, 我们在进行选择的时候, 常常需 要确认,所以按钮很重要。 按钮组件怎么用? 只需要在窗体中添加按钮组件 (JButton) 即可完成。 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 163 | 436 按钮组件 -- 深入讨论 1、JButton 是 AbstractButton 的子类 2、属于窗口类组件,可以加入别的组件 3、 Swing 包的按 钮组件不只 有 JButton , 还有单选 按钮 (JRadioButton) 、箭 头按钮 (BasicArrowButton) 、触发器按钮 (JToggleButton) .. 这些按钮我们在后面讲解。 // 功能: GUI界面开发演示 [Window001.java] import java.awt.*; // 开发图形要引入 java.awt.* 包 import javax.swing.*; // 开发图形要引入 javax.swing.* 包 public class Window001 extends JFrame { // 继承 JFrame 顶层容器类 ( 可以添加其它 swing 组件的类 ) // 把需要的 swing 组件,定义到这里 JButton jb1=null; public static void main(String[] args) { Window001 win=new Window001(); } // 构造函数 public Window001(){ // 创建一个 button 按钮 jb1=new JButton(" 按钮 "); // 添加 JButton 组件 this.add(jb1); // 给窗体设置标题 this.setTitle("Hello World!"); // 设置窗体大小 , 按像素设置大小 this.setSize(500, 500); // 设置窗体初始位置 this.setLocation(500, 150); // 设置当关闭窗口时,保证 JVM也退出 this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 显示窗体 this.setVisible(true); //true 显示, false 不显示 } } 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 164 | 436 4、三大常用布局管理器 布局管理器 -- 介绍 1、概念 组件在容器 ( 比如 JFrame) 中的位置和大小是由布局管理器来决定的。所有的容器都会 使用一个布局管理器,通过它来自动进行组件的布局管理。 2、种类 java 共提供了 五种布局管理器 : 流式布局管理器 (FlowLayout) 、 边界布局管理器 (BorderLayout) 、网格布局管理器 (GridLayout) 、卡片布局管理器 (CardLayout) 、网格包布 局管理器 (GridBagLayout) 。其中前三种是最常见的布局管理器。 边界布局 BorderLayout-- 介绍 边界布局 (BorderLayout) 将容器简单的划分为东南西北 5 个区域,中间区域最大。 JFrame 窗体, JDialog 对话框组件默认布局方法 边界布局 BorderLayout-- 使用 [Window002.java] /** * 边界布局 BorderLayout 使用演示 * 1 、继承 JFrame * 2 、定义你需要的各个组件 * 3 、创建组件 ( 在构造函数中组件 ) * 4 、添加组件 * 5 、对窗体设置 * 6 、显示窗体 */ import java.awt.*; import javax.swing.*; public class Window002 extends JFrame{ // 定义组件 JButton jb1,jb2,jb3,jb4,jb5; public static void main(String[] args) { Window002 win=new Window002(); } public Window002(){ // 创建组件 jb1=new JButton(" 中部 "); jb2=new JButton(" 北部 "); jb3=new JButton(" 东部 "); jb4=new JButton(" 南部 "); jb5=new JButton(" 西部 "); // 添加各个组件 this.add(jb1, BorderLayout.CENTER); //BorderLayout.CENTER 添加到中部 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 165 | 436 this.add(jb2, BorderLayout.NORTH); //BorderLayout.NORTH 添加到北部 this.add(jb3, BorderLayout.EAST); //BorderLayout.EAST 添加到东部 this.add(jb4, BorderLayout.SOUTH); //BorderLayout.SOUTH 添加到南部 this.add(jb5, BorderLayout.WEST); //BorderLayout.WEST 添加到西部 // 设置窗体属性 this.setTitle(" 边界布局演示 "); // 窗体标题名称 this.setSize(300, 200); // 窗体尺寸 this.setLocation(200, 200); // 窗体在屏幕打开时的初始位置 this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 退 出 窗 体 后 将 JFrame 同时关闭 // 显示窗体 this.setVisible(true); } } ------------------------------------------------------------------------------ 边界布局 BorderLayout-- 注意事项 1、不是五个部分都必需添加; 2、中部组件会自动调节大小; 3、JFrame, Jdialog 默认布局管理器就是 BorderLayout 三大常用布局管理器 -- 流式布局 流式布局 FlowLayout-- 介绍 FlowLayout 布局,按照组件的添加次序将按钮组件 ( 当然也可以是别的组件 ) 从左到右放置 在容器中。当到达容器的边界时,组件将放置到下一行中。 FlowLayout 可以以左对齐、居 中对齐、以右对齐的方式排列组件。 流式布局 FlowLayout-- 使用 [Window003.java] /** * 流式布局 FlowLayout 使用演示 * 1 、继承 JFrame * 2 、定义你需要的各个组件 * 3 、创建组件 ( 在构造函数中组件 ) * 4 、添加组件 * 5 、对窗体设置 * 6 、显示窗体 */ import java.awt.*; import javax.swing.*; public class Window003 extends JFrame{ // 定义组件 JButton jb1,jb2,jb3,jb4,jb5,jb6; 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 166 | 436 public static void main(String[] args) { Window003 win=new Window003(); } public Window003(){ // 创建组件 jb1=new JButton(" 关羽 "); jb2=new JButton(" 张飞 "); jb3=new JButton(" 赵云 "); jb4=new JButton(" 马超 "); jb5=new JButton(" 黄忠 "); jb6=new JButton(" 魏延 "); // 添加各个组件 this.add(jb1); this.add(jb2); this.add(jb3); this.add(jb4); this.add(jb5); this.add(jb6); // 设置布局管理器 , 流式布局默认为居中对齐 this.setLayout(new FlowLayout(FlowLayout.LEFT)); //new FlowLayout(FlowLayout.LEFT) 流式布局, (FlowLayout.??)?? 可以设置为不同方式对 齐。 // 设置窗体属性 this.setTitle(" 流式布局演示 "); // 窗体标题名称 this.setSize(300, 200); // 窗体尺寸 this.setLocation(200, 200); // 窗体在屏幕打开时的初始位置 this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 退 出 窗 体 后 将 JFrame 同时关闭 // 禁止用户改变窗体大小 this.setResizable(false); // 显示窗体 this.setVisible(true); } } ------------------------------------------------------------------------------ 流式布局 FlowLayout-- 注意事项 1、不限制他所管理的组件大小,允许他们有最佳大小 2、当容器衩缩放时,组件的位置可能变化,但组件的大小不变。 3、默认组件是居中对齐,可以通过 FlowLayout(intalign) 函数来指定对齐方式。 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 167 | 436 三大常用布局管理器 -- 网格 网格布局 GridLayout-- 介绍 GridLayout 布局, 听其名而知其意,它将容器分割成多行多列,组件被填充到每个网格中, 添加到容器中的组件首先放置在左上角的网格中 ,然后从左到右放置其它的组件, 当占满该 行的所有网格后,接着继续在下一行从左到右放置组件。 网格布局 GridLayout-- 使用 [Window004.java] /** * 网格布局 GridLayout 使用演示 * 1 、继承 JFrame * 2 、定义你需要的各个组件 * 3 、创建组件 ( 在构造函数中组件 ) * 4 、添加组件 * 5 、对窗体设置 * 6 、显示窗体 */ import java.awt.*; import javax.swing.*; public class Window004 extends JFrame{ // 定义组件 int size=9; JButton jbs[]=new JButton[size]; public static void main(String[] args) { Window004 win=new Window004(); } public Window004(){ // 创建组件 for(int i=0;i 这就是我们常说的多线程编程 5、线程有几种状态: a 、新建状态 (new) b 、就绪状态 (Runnable) c 、运行状态 (Running) d 、阻塞状态 (Blocked) e 、死亡状态 (Dead) 线程有什么用处 java 程序中流传一句话,不会使用线程就别跟别人说自己学过 java 。目前绝大部分应用程 序都会涉及到多并发的问题。只要应用程序涉及到并发,就离不开多线程编程。 线程 -- 如何使用 在 java 中一个类要当作线程来使用有两种方法 。 1、继承 Thread 类,并重写 run 函数 2、实现 Runnable 接口,并重写 run 函数 因为 java 是单继承的, 在某些情况下一个类可能已经继承了某个父类, 这时在用继承 Thread 类方法来创建线程显然不可能 java 设计者们提供了另外一个方式创建线程,就是通过实现 Runnable 接口来创建线程。 通过继承 Thread 类来实现建立线程实例 [Thread01.java] /** * 演示如何通过继承 Thread 来开发线程 */ public class Thread01 { public static void main(String[] args) { // 创建一个 Cat 对象 Cat cat=new Cat(); // 启动线程 cat.start(); //.start() 会导致 run 函数运行 } } class Cat extends Thread{ int times=0; // 重写 run 函数 public void run(){ while(true){ // 休眠一秒 //1000 表示 1000 毫秒 try { Thread.sleep(1000); //sleep 就会让该线程进入到 Blocked 阻塞状态 , 并 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 201 | 436 释放资源。 } catch (Exception e) { e.printStackTrace(); } times++; System.out.println("hello,world!"+times); if(times==10){ // 退出线程 break; } } } } ------------------------------------------------------------------------------- 通过 Runnable 接口来实现建立线程实例 [Thread02.java] /** * 演示如何通过 Runnable 接口来开发线程 */ public class Thread02{ public static void main(String []args){ Dog dog=new Dog(); // 创建线程 Thread t=new Thread(dog); // 启动线程 t.start(); } } class Dog implements Runnable{ // 创建 Runnable 接口 public void run(){ // 重写 run 函数 int times=0; while(true){ try{ Thread.sleep(1000); }catch (Exception e) { e.printStackTrace(); } times++; System.out.println("hello,wrold!"+times); if(times==10){ break; } } } } 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 202 | 436 ------------------------------------------------------------------------------- 多线程实例演示 [Thread03.java] /** * 多线程 Thread 使用 *1 、一个线程通过接收 n 来执行 1+..+n 得到和 *2 、另一线程每隔 1 秒输出一次 hello world! */ public class Thread03 { public static void main(String[] args) { Pig pig=new Pig(10); Bird bird=new Bird(10); // 建立线程 Thread t1=new Thread(pig); Thread t2=new Thread(bird); // 启动线程 t1.start(); t2.start(); } } // 打印 hello world! class Pig implements Runnable{ int n=0; int times=0; public Pig(int n){ this.n=n; } public void run(){ while(true){ try { Thread.sleep(1000); } catch (Exception e) { e.printStackTrace(); } times++; System.out.println(" 我 是 一 个 线 程 , 正 在 输 出 第 "+times+" 个 hello world!"); if(times==n){ break; } } } } 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 203 | 436 // 算数学题 class Bird implements Runnable{ // 多线程时应使用 implements 接口来实现,不要使用 extends 继承 int n=0; int res=0; int times=0; public Bird(int n){ this.n=n; } public void run() { while(true){ try { Thread.sleep(1000); } catch (Exception e) { e.printStackTrace(); } res+=(++times); System.out.println(" 当前结果是: "+res); if(times==n){ System.out.println(" 最后的结果是: "+res); break; } } } } ------------------------------------------------------------------------------- 线程 -- 区别 线程 -- 继承 Thread VS 实现 Runnable 的区别 从 java 的设计来看,通过继承 Thread 或者实现 Runnable 接口来创建线程本质上没有 区别,从 jdk 帮助文档我们可以看到 Thread 类本身就实现了 Runnable 接口 ,如果一定要 说它们有什么 区别,总结几点 : 1、尽可能使用实现 Runnable 接口的方式来创建线程 2、在使用 Thread 的时候只需要 new一个实例出来, 调用 start() 方法即可以启动一个线程, 如: Thread test=new Thread(); test.start(); 3、在使用 Runnable 的时候需要先 new一个实现 Runnable 的实例,之后用 Thread 调用,如: Test implements Runnable Test t=new Test(); Thread test=new Thread(t); tset.start(); 线程 -- 深入理解 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 204 | 436 线程对象只能启动一个线程,见 [Thread04.java] /** * 功能 : 使用线程的注意事项 * 不论继承 Thread 或实现 Rnunable 接口都不能使用 start 启同一个线程 2 次 */ public class Thread04 { public static void main(String[] args) { Cat cat1=new Cat(); cat1.start(); //cat1.start(); 同一个线程,不能启动 2 次 Dog dog1=new Dog(); Thread t=new Thread(dog1); t.start(); //t.start(); 同一个线程,不能启动 2 次 } } // 猫类 class Cat extends Thread{ public void run(){ System.out.println("11"); } } // 狗类 class Dog implements Runnable{ public void run(){ System.out.println("2"); } } ------------------------------------------------------------------------------- 结论: 不管是通过继承 Thread,还是通过实现 Runnable 接口创建线程,它们的一个对象只 能启动 ( 即: start()) 一次。否则就会有异常抛出。 两种创建线程的方法的区别 创建线程有两种方法: 1、继承 Thread;2、实现 Runnable 接口; 这两种方法有什么区别? 用实现 Runnable 接口的特点 1、用实现 Runnable 接口的方法创建对象可以避免 java 单继承机制带来的局限; 2、用实现 Runnable 接口的方法,可以实现多个线程共享同一段代码 (数据 ) ; 因此建议大家如果你的程序有同步逻辑需求,则使用 Runnable 的方法来创建线程。 java 线程的同步 -- 提出问题 多线程的并发, 给我们编程带来很多好处, 完成更多更有效率的程序。 但是也给我们带来线 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 205 | 436 程安全问题。 java 线程的同步 -- 解决问题 解决问题的关键就是要保证容易出问题的代码的 原子性 ,所谓原子性就是指:当 a 线程在 执行某段代码的时候,别的线程必须等到 a 线程执行完后,它才能执行这段代码。 也就是 排队一个一个解决。 java 处理线程两步的方法非常简单,只需要在需要同步的代码段,用 : synchronized(Object){ 你要同步的代码 } 即可。 售票案例演示 [Thread05.java] /** * 功能 : 使用线程的注意事项 * 线程并发同步锁 synchronized(Object){} 的使用 */ public class Thread05 { public static void main(String[] args) { // 定义一个售票窗口 TicketWindow tw1=new TicketWindow(); // 使用三个线程同时启动 Thread t1=new Thread(tw1); Thread t2=new Thread(tw1); Thread t3=new Thread(tw1); t1.start(); t2.start(); t3.start(); } } // 售票窗口类 class TicketWindow implements Runnable { // 共有 2000 张票 private int nums=2000; private Dog myDog=new Dog(); public void run() { while(true){ // 出票速度是 1 秒出一张 try { Thread.sleep(1000); } catch (Exception e) { e.printStackTrace(); } 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 206 | 436 // 认为 if else 要保证其原子性 // 先判断是否还有票 synchronized(myDog){ //synchronized(this){} 为同步代码块 if(nums>0){ // 显示售票信息 //Thread.currentThread().getName() 得到当前线程的名字 System.out.println(Thread.currentThread().getName()+" 正在售 出第 "+nums+"张票 "); nums--; }else{ // 售票结束 break; } } } } } class Dog{ } ------------------------------------------------------------------------------- java 线程的同步 -- 解决问题 对同步机制的解释: java 任意类型的对象都有一个标志位, 该标志位具有 0、1 两种状态, 其开始状态为 1, 当某个线程执行了 synchronized(Object) 语句后, object 对象的标志位变为 0 的状态,直 到执行完整个 synchronized 语句中的代码块后,该对象的标志位又回到 1 状态。 当一个线程执行到 synchronized(Object) 语句的时候,先检查 Object 对象的标志位, 如果为 0 状态,表明已经有另外的线程正在执行 synchronized 包括的代码,那么这个线程 将暂时阻塞,让出 CPU资源,直到另外的线程执行完相关的同步代码,并将 Object 对象的 标志位变为状态,这个线程的阻塞就被取消,线程能继续运行,该线程又将 Object 的标志 位变为 0 状态,防止其它的线程再进入相关的同步代码块中。 如果有多个线程因等待同一个对象的标志位面而处于阻塞状态时, 当该对象的标志位恢 复到 1 状态时,只会有一个线程能够进入同步代码执行,其它的线程仍处于阻塞的状态。 特别说明: 1、上面所说的标志位用术语讲就是对象锁 , 文件锁。数据库会有行锁、表锁等 2、synchronized(object)//object( 就是对象锁 ) 可以是任意类型对象 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 207 | 436 文件 -- 什么是文件 文件,对我们并不陌生, 文件是数据源 ( 保存数据的地方 ) 的一种, 比如大家经常使用的 word 文档、 txt 文件、 excel 文件 ... 都是文件。 文件最主要的作用就是保存数据, 它既可以保存 一张图片,也可以保存视频、声音 ... 等 文件流 -- 基本概念 文件在程序中是以流的形式来操作的。 流:数据在数据源 (文件 ) 和程序 ( 内存 ) 之间经历的路径 输入流:数据从数据源 ( 文件 ) 到程序 (内存 ) 的路径 输出流:数据从程序 ( 内存 ) 到数据源 (文件 ) 的路径 如何判断是输入流、输出流? 以内存为参照,如果数据流向内存流动,则是输入流;反之,则是输出流。 文件流 -- 分类 java 流分为两种流 1、字节流:可以用于读写二进制文件及任何类型文件 byte 2、字符流:可以用于读写文本文件,不能操作二进制文件 字节流 字符流 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 208 | 436 输入 InputStream Reader 输出 OutputStream Writer 常用 io 流-- 文件对象 目的:文件数据源 File 类介绍 ( 文件流对象中最为重要的 File 类,对 File 了解后对子类理 解会更加容易 ) File 类-- 使用 [Io01.java] /** * File 类的基本用法 */ import java.io.*; // 必需加载 IO 包 public class Io01 { public static void main(String[] args) { // 创建一个文件对象 File f1=new File("e:\\aa.txt"); // 得到文件的路径 System.out.println(" 文件路径 "+f1.getAbsolutePath()); // 得到文件的大小 , 字节数 System.out.println(" 文件的大小 "+f1.length()); // 创建文件夹 File f3=new File("e:\\ff"); // 判断文件夹是否存在 if(f3. isDirectory() ){ System.out.println(" 文件夹存在,不能创建 !"); }else{ // 创建文件夹 f3 .mkdir(); } // 创建文件和创建文件夹 File f2=new File("e:\\ff\\hsp.txt"); // 判断文件是否存在 if(!f2. exists() ){ // 可以创建 try { f2.createNewFile(); // 创建一个新文件 } catch (Exception e) { e.printStackTrace(); } }else{ System.out.println(" 文件存在,不能创建 !"); } 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 209 | 436 // 列出一个文件夹下面的所有文件 File f4=new File("e:\\ff"); // 判断文件夹是事存在 if(f4.isDirectory()){ // 将文件夹的文件,传给 lists 数组 File lists[]=f4.listFiles(); // 遍历数组 for(int i=0;imonkeys[j+1].height){ // 身高交换 tempHeight=monkeys[j].height; monkeys[j].height=monkeys[j+1].height; monkeys[j+1].height=tempHeight; // 编号交换 tempId=monkeys[j].monkeyId; monkeys[j].monkeyId=monkeys[j+1].monkeyId; monkeys[j+1].monkeyId=tempId; } } } } // 显示队列 public void show(Monkey []monkeys){ for(int i=0;imonkeys[j].height){ // 修正最低值 minHeight=monkeys[j].height; minIndex=j; } if(minIndex!=i){ // 交换 tempHeight=monkeys[minIndex].height; monkeys[minIndex].height=monkeys[i].height; monkeys[i].height=tempHeight; tempId=monkeys[minIndex].monkeyId; monkeys[minIndex].monkeyId=monkeys[i].monkeyId; monkeys[i].monkeyId=tempId; } } } } // 显示队列 public void show(Monkey []monkeys){ for(int i=0;i=0&&monkeys[insertIndex].height>insertHeight){ monkeys[insertIndex+1].height=monkeys[insertIndex].height; monkeys[insertIndex+1].monkeyId=monkeys[insertIndex].monkeyId; insertIndex--; } // 插入 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 222 | 436 monkeys[insertIndex+1].height=insertHeight; monkeys[insertIndex+1].monkeyId=insertId; } } // 显示队列 public void show(Monkey []monkeys){ for(int i=0;i<=note;i++){ num=num*i; } System.out.println(note+" 的阶乘结果是: "+num); num=1; }else{ System.out.println(note+" 不是合数 "); } if(note==-1){ System.out.println(" 退出 "); break; } } catch (Exception e) { e.printStackTrace(); } } } } ------------------------------------------------------------------------------ 答题: ( 递归方法 ) import java.io.*; public class Test { public static void main(String[] args) { InputStreamReader isr=new InputStreamReader(System.in); BufferedReader br=new BufferedReader(isr); while(true){ System.out.println(" 请输入一个整数 :"); try { int note=Integer.parseInt(br.readLine()); if((note%1==0&¬e%2==0)||(note%1==0&¬e%3==0)||(note%1==0&¬e%5==0)|| (note%1==0&¬e%7==0)){ System.out.println(" 你输入整数 "+note+" 是合数 !"); } Test t = new Test(); int n = t.calc(note); System.out.println(note+" 阶乘结果是: "+n); if(note==0){ System.out.println(" 输入 0 退出 "); break; 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 229 | 436 } } catch (Exception e) { e.printStackTrace(); } } } public int calc(int n) { if(n==0){ return 1; } return n*calc(n-1); } } 4、编写一个程序,在控制台接收数据,程序会让用户输入名字,并检查用户的输入:不允 许输入空名字: 一旦用户完成输入, 程序会向该用户发出问题: "Hello ,你输入的名字" 。( 提 示 : 如 果 希 望 在 控 制 台 中 与 用 户 交 互 , 一 种 可 能 的 做 法 就 是 将 System.in 包 装 成)BufferedReader 要做到这一点,必须使用 InputStreamReader 类将 System.in 这个 InputStream 对象转换成一个 Reader 即 BufferedReader in=new BufferedReader(new InputStreamReader(System.in)); 答题: import java.io.BufferedReader; import java.io.InputStreamReader; public class Test { public static void main(String[] args) { InputStreamReader isr=new InputStreamReader(System.in); BufferedReader br=new BufferedReader(isr); while(true){ System.out.println(" 请输入名字 :"); try { String name=br.readLine(); if(name.equals("")){ System.out.println(" 你输入的名字是空,退出 !"); System.exit(0); }else{ System.out.println("Hello,"+name+"!"); } } catch (Exception e) { e.printStackTrace(); } } } } 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 230 | 436 ------------------------------------------------------------------------------- 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 231 | 436 坦克大战案例源代码 [MyTank07.java] 源代码 /** * 功能:坦克游戏的 2.01 * 1 、画出我的坦克 * 2 、让我的坦克动起来 * 3 、让我的坦克按下空格 (space) 键发射子弹 * 4 、让我的坦克可以连发子弹 ( 最多连发 5 颗子弹 ) * 5 、打到敌人坦克,敌人坦克就消失 * 6 、加入坦克被击中爆炸的效果 * 7 、让敌人的坦克可以自由随机移动 * 8 、控制坦克在指定的 MyPanel 面板中移动,不可越界 * 9 、让敌人的坦克发射子弹 * 10 、当我的坦克被敌人子弹击中,我的坦克爆炸 * 11 、防止敌人坦克重叠运动 * 12 、可以分关 -- 做一个开始的 Panel ,它是空的主要是提示关卡 * 13 、游戏可以暂停、继续 -- 暂停时将子弹、坦克速度设为 0,坦克方向不变 * 14 、可以记录玩家的成绩 * 15 、java 如何操作声音文件 */ package com.haiding.tank_7; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.io.File; import javax.imageio.ImageIO; import javax.swing.*; import java.util.*; import javax.sound.sampled.*; public class MyTank07 extends JFrame implements ActionListener{ // 定义组件 MyPanel mp=null; // 定义一个开始面板 MyStartPanel msp=null; // 做出菜单 JMenuBar jmb=null; // 开始游戏 JMenu jm1=null; JMenuItem jmi1=null; // 退出游戏 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 232 | 436 JMenuItem jmi2=null; // 存盘退出 JMenuItem jmi3=null; // 接上局 JMenuItem jmi4=null; public static void main(String[] args) { MyTank07 mt=new MyTank07(); } // 构造函数 public MyTank07(){ // 创建菜单及菜单选项 jmb=new JMenuBar(); jm1=new JMenu(" 游戏 (G)"); // 设置快捷方式 jm1.setMnemonic('G'); jmi1=new JMenuItem(" 开始新游戏 (N)"); jmi1.setMnemonic('N'); // 对 jmi1 相应 jmi1.addActionListener(this); jmi1.setActionCommand("newgame"); jmi2=new JMenuItem(" 退出游戏 (E)"); jmi2.setMnemonic('E'); jmi2.addActionListener(this); jmi2.setActionCommand("exit"); jmi3=new JMenuItem(" 存盘退出 (S)"); jmi3.setMnemonic('S'); jmi3.addActionListener(this); jmi3.setActionCommand("save"); jmi4=new JMenuItem(" 继续游戏 (C)"); jmi4.setMnemonic('C'); jmi4.addActionListener(this); jmi4.setActionCommand("congame"); jm1.add(jmi1); jm1.add(jmi2); jm1.add(jmi3); jm1.add(jmi4); jmb.add(jm1); this.setJMenuBar(jmb); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 233 | 436 // 构建组件 msp=new MyStartPanel(); Thread t=new Thread(msp); t.start(); this.add(msp); // 设置 JFrame 窗体 this.setTitle(" 坦克大战 "); //JFrame 标题 this.setSize(600, 500); //JFrame 窗体大小 this.setLocationRelativeTo(null); // 在屏幕中心显示 this.setVisible(true); // 显示 this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 退出并关闭 JFrame } public void actionPerformed(ActionEvent e) { // 对用户不同的点击,做出不同的处理 if(e.getActionCommand().equals("newgame")){ // 创建战场面板 mp=new MyPanel("newgame"); // 启动 mp线程 Thread ta=new Thread(mp); ta.start(); // 先删除旧的开始面板 this.remove(msp); // 加入组件 this.add(mp); // 监听 this.addKeyListener(mp); // 显示,刷新 JFrame this.setVisible(true); }else if(e.getActionCommand().equals("exit")){ // 用户点击了退出菜单 // 保存用户游戏记录数据 Recorder.keepRecording(); System.exit(0); }else if(e.getActionCommand().equals("save")){ // 用户点击保存菜单 // 保存击毁敌人的数量和敌人的坐标 Recorder.setEts(mp.ets); Recorder.keepRecAndEnemyTank(); System.exit(0); }else if(e.getActionCommand().equals("congame")){ // 继续上次游戏 // 创建战场面板 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 234 | 436 mp=new MyPanel("congame"); // 启动 mp线程 Thread ta=new Thread(mp); ta.start(); // 先删除旧的开始面板 this.remove(msp); // 加入组件 this.add(mp); // 监听 this.addKeyListener(mp); // 显示,刷新 JFrame this.setVisible(true); } } } // 开始面板 -- 起提示作用 class MyStartPanel extends JPanel implements Runnable{ int times=0; public void paint(Graphics g){ super.paint(g); g.setColor(Color.black); g.fillRect(0, 0, 400, 300); // 提示信息 if(times%2==0){ g.setColor(Color.yellow); // 开关信息的字体 Font myFont=new Font(" 华文新魏 ", Font.BOLD, 30); g.setFont(myFont); g.drawString("Stage: 1", 150, 150); } } public void run() { while(true){ // 休眠 try { Thread.sleep(500); } catch (Exception e) { e.printStackTrace(); } times++; // 重画 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 235 | 436 this.repaint(); } } } // 我的面板 Panel class MyPanel extends JPanel implements KeyListener,Runnable{ //MyPanel 继承 Jpanel 面板,创建 KeyListener 键盘接口和 Runnable 线程接口 // 定义一个我的坦克 Hero hero=null; // 定义声音播放 AePlayWave apw=null; // 定义敌人的坦克组 Vector ets=new Vector(); Vector nodes=new Vector(); // 定义炸弹集合 Vector bombs=new Vector(); int enSize=3; // 初始敌人坦克数量 // 定义爆炸图片 Image image1=null; Image image2=null; Image image3=null; // 构造函数 public MyPanel(String flag){ hero=new Hero(200, 270); // 我的坦克初始位置 // 恢复游戏记录 Recorder.getRecoring(); if(flag.equals("newgame")){ // 播放开战声音 apw=new AePlayWave("e:\\tankgame\\tankmusic.wav"); apw.start(); // 初始化敌人的坦克 for(int i=0;i6){ g.drawImage(image1, b.x, b.y, 30, 30, this); }else if(b.life>3){ g.drawImage(image2, b.x, b.y, 30, 30, this); }else { g.drawImage(image3, b.x, b.y, 30, 30, this); } // 让 b 的生命值减少 b.lifeDown(); // 如果炸弹生命值为 0,就把该炸弹从 bombs向量中去掉 if(b.life==0){ bombs.remove(b); } } 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 239 | 436 // 画出敌人的坦克 for(int i=0;iet.x&&s.x<et.x+20&&s.y>et.y&&s.yet.x&&s.x<et.x+29&&s.y>et.y&&s.y<=4){ // 按下空格后开火 this.hero.shotEnemy(); } } // 调用 repaint() 函数,来重绘界面 this.repaint(); } public void keyReleased(KeyEvent e) { // 弹起键事件 } public void keyTyped(KeyEvent e) { // 按键输出值 } // 重写 run 函数 public void run() { while(true){ try { Thread.sleep(100); // 休息 100 毫秒后重绘 MyPanel 面板 } catch (Exception e) { e.printStackTrace(); } 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 244 | 436 this.hitEnemyTank(); // 判断敌人的子弹是否击中我的坦克 this.hitMe(); // 重绘 MyPanel 面板 this.repaint(); } } } ******************************************************************************* ******* [Members.java] 成员类 package com.haiding.tank_7; import java.util.Vector; import java.io.*; import javax.sound.sampled.*; // 播放声音的类 class AePlayWave extends Thread { private String filename; public AePlayWave(String wavfile) { filename = wavfile; } public void run() { File soundFile = new File(filename); AudioInputStream audioInputStream = null; try { audioInputStream = AudioSystem.getAudioInputStream(soundFile); } catch (Exception e1) { e1.printStackTrace(); return; } AudioFormat format = audioInputStream.getFormat(); SourceDataLine auline = null; DataLine.Info info = new DataLine.Info(SourceDataLine.class, format); try { auline = (SourceDataLine) AudioSystem.getLine(info); auline.open(format); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 245 | 436 } catch (Exception e) { e.printStackTrace(); return; } auline.start(); int nBytesRead = 0; // 这是缓冲 byte[] abData = new byte[2048]; try { while (nBytesRead != -1) { nBytesRead = audioInputStream.read(abData, 0, abData.length); if (nBytesRead >= 0) auline.write(abData, 0, nBytesRead); } } catch (IOException e) { e.printStackTrace(); return; } finally { auline.drain(); auline.close(); } } } // 记录恢复点 class Node{ int x,y,direct; public Node(int x,int y,int direct){ this.x=x; this.y=y; this.direct=direct; } } // 记录类,同时也可以保存玩家的设置 class Recorder{ // 记录每关有多少敌人 private static int enNum=20; // 设置我有多少可用的人 private static int myLife=3; // 记录总共消灭了多少敌人的坦克 private static int allEnNum=0; 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 246 | 436 // 从文件中恢复记录点 private static Vector nodes=new Vector(); private static FileWriter fw=null; private static BufferedWriter bw=null; private static FileReader fr=null; private static BufferedReader br=null; private static Vector ets=new Vector(); // 完成读取任务点任务 public static Vector getNodesAndEnNums(){ try { fr=new FileReader("e:\\tankgame\\tanksave.txt"); br=new BufferedReader(fr); String n=""; // 先读一行 n=br.readLine(); allEnNum=Integer.parseInt(n); while((n=br.readLine())!=null){ String []Recovery=n.split(" "); //split 方法可以按一行字符中有多 少个空间来返回数组 Node node=new Node(Integer.parseInt(Recovery[0]),Integer.parseInt(Recovery[1]),Integer.parseI nt(Recovery[2])); nodes.add(node); } } catch (Exception e) { e.printStackTrace(); }finally{ try { br.close(); fr.close(); } catch (Exception e2) { e2.printStackTrace(); } } return nodes; } // 保存击毁敌人的数量和敌人坦克坐标、方向 public static void keepRecAndEnemyTank(){ try { // 创建 fw=new FileWriter("e:\\tankgame\\tanksave.txt"); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 247 | 436 bw=new BufferedWriter(fw); bw.write(allEnNum+"\r\n"); // 保存当前还活着的敌人坦克坐标、方向 for(int i=0;i getEts() { return ets; 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 249 | 436 } public static void setEts(Vector ets) { Recorder.ets = ets; } // 敌人坦克死亡就减少坦克数 public static void reduceEnNum(){ enNum--; } // 当消灭敌人的时候 public static void addEnNumRec(){ allEnNum++; } } // 炸弹类 class Bomb{ // 定义炸弹的坐标 int x,y; int life=9; // 炸弹的生命 boolean isLive=true; public Bomb(int x,int y){ this.x=x; this.y=y; } // 减少炸弹生命值 public void lifeDown(){ if(life>0){ life--; }else{ this.isLive=false; } } } // 子弹类 class Shot implements Runnable{ int x,y,direct,speed=3; // 初始子弹 x,y 坐标 ,direct 子弹方向 ,speed 子弹速度 // 子弹是否还活着 boolean isLive=true; // 默认为活着 public Shot(int x,int y,int direct){ 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 250 | 436 this.x=x; this.y=y; this.direct=direct; } public void run(){ while(true){ try { Thread.sleep(50); // 让子弹休息 50 毫秒,防止快速消费内存 } catch (Exception e) { e.printStackTrace(); } switch(direct){ case 0: // 向上 y-=speed; break; case 1: // 向下 y+=speed; break; case 2: // 向 左 x-=speed; break; case 3: // 向右 x+=speed; break; } // 子弹何时死亡 // 判断该子弹是否碰到 MyPanel 面板的边缘 if(x400||y300){ this.isLive=false; break; } } } } // 定义坦克类 class Tank{ // 表示坦克的 X横坐标 Y纵坐标 int x=0,y=0; //direct 坦克方向 ,0 向上、 1 向下、 2 向左、 3 向右 int direct=0; // 坦克的速度 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 251 | 436 int speed=1; // 坦克颜色 int color; boolean isLive=true; public Tank(int x,int y){ this.x=x; this.y=y; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } public int getDirect() { return direct; } public void setDirect(int direct) { this.direct = direct; } public int getSpeed() { return speed; } public void setSpeed(int speed) { this.speed = speed; } public int getColor() { return color; } public void setColor(int color) { this.color = color; } } // 敌人坦克 , 把敌人坦克做成线程类 class EnemyTank extends Tank implements Runnable{ 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 252 | 436 int move=30; // 敌人坦克移动步长 (区域 ) int times=0; // 定义一个向量,可以访问到 MyPanel 上所有敌人坦克 Vector ets=new Vector(); // 定义一个向量,可以存放敌人的子弹 Vector ss=new Vector(); // 敌人添加子弹,应在创建坦克和敌人的坦克子弹死亡后 public EnemyTank(int x,int y){ super(x,y); } // 得到 MyPanel 的敌人坦克向量 public void setEts(Vector tank){ this.ets=tank; } // 判断敌人坦克是否重叠 public boolean isTouchOtherEnemy(){ boolean b=false; switch(this.direct){ case 0: // 敌人当前坦克向上 // 取出所有敌人坦克 for(int i=0;i=et.x&&this.x<=et.x+20&&this.y>=et.y&&this.y<=et.y+30){ return true; } if(this.x+20>=et.x&&this.x+20<=et.x+20&&this.y>=et.y&&this.y<=et.y+30){ return true; } } // 如果敌人同伴的坦克向左或向右 if(et.direct==2||et.direct==3){ // 判断敌人当前坦克右轮与同伴坦克 ( 向左或向右 )的位置比较 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 253 | 436 if(this.x>=et.x&&this.x<=et.x+30&&this.y>=et.y&&this.y<=et.y+20){ return true; } if(this.x+20>=et.x&&this.x+20<=et.x+30&&this.y>=et.y&&this.y<=et.y+20){ return true; } } } } break; case 1: // 敌人当前坦克向下 for(int i=0;i=et.x&&this.x<=et.x+20&&this.y+30>=et.y&&this.y+30<=et.y+30){ return true; } if(this.x+20>=et.x&&this.x+20<=et.x+20&&this.y+30>=et.y&&this.y+30<=et.y+30 ){ return true; } } if(et.direct==2||et.direct==3){ if(this.x>=et.x&&this.x<=et.x+30&&this.y+30>=et.y&&this.y+30<=et.y+20){ return true; } if(this.x+20>=et.x&&this.x+20<=et.x+30&&this.y+30>=et.y&&this.y+30<=et.y+20 ){ return true; } } } } break; case 2: // 敌人当前坦克向左 for(int i=0;i=et.x&&this.x<=et.x+20&&this.y>=et.y&&this.y<=et.y+30){ return true; } if(this.x>=et.x&&this.x<=et.x+20&&this.y+20>=et.y&&this.y+20<=et.y+30){ return true; } } if(et.direct==2||et.direct==3){ if(this.x>=et.x&&this.x<=et.x+30&&this.y>=et.y&&this.y<=et.y+20){ return true; } if(this.x>=et.x&&this.x<=et.x+30&&this.y+20>=et.y&&this.y+20<=et.y+20){ return true; } } } } break; case 3: // 敌人当前坦克向右 for(int i=0;i=et.x&&this.x+30<=et.x+20&&this.y>=et.y&&this.y<=et.y+30){ return true; } if(this.x+30>=et.x&&this.x+30<=et.x+20&&this.y+20>=et.y&&this.y+20<=et.y+30 ){ return true; } } if(et.direct==2||et.direct==3){ if(this.x+30>=et.x&&this.x+30<=et.x+30&&this.y>=et.y&&this.y<=et.y+20){ return true; } 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 255 | 436 if(this.x+30>=et.x&&this.x+30<=et.x+30&&this.y+20>=et.y&&this.y+20<=et.y+20 ){ return true; } } } } break; } return b; } // 重写 run() 函数 public void run() { while(true){ switch(this.direct){ case 0: // 坦克正在向上移动 for(int i=0;i0&&!this.isTouchOtherEnemy()){ // 判断敌人坦克向上走不会 越界 y-=speed; } try { Thread.sleep(50); } catch (Exception e) { e.printStackTrace(); } } break; case 1: // 向下移动 for(int i=0;i<400&&!this.isTouchOtherEnemy()){ // 判断敌人坦克向下走不 会越界 y+=speed; } try { Thread.sleep(50); } catch (Exception e) { e.printStackTrace(); } } break; case 2: // 向左移动 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 256 | 436 for(int i=0;i0&&!this.isTouchOtherEnemy()){ // 判断敌人坦克向左走不会 越界 x-=speed; } try { Thread.sleep(50); } catch (Exception e) { e.printStackTrace(); } } break; case 3: // 向右移动 for(int i=0;i<300&&!this.isTouchOtherEnemy()){ // 判断敌人坦克向右走不 会越界 x+=speed; } try { Thread.sleep(50); } catch (Exception e) { e.printStackTrace(); } } break; } this.times++; if(times%2==0){ if(isLive){ if(ss.size() ss=new Vector(); //Vector 线程安全的集合类 Shot s=null; public Hero(int x,int y){ super(x,y); } // 坦克开火 public void shotEnemy(){ switch(this.direct){ // 判断坦克方向来对应子弹运行方向 case 0: // 向上 // 创建一颗子弹 s=new Shot(x+10, y, 0); // 将子弹加入到向量集中 ss.add(s); break; 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 258 | 436 case 1: // 向下 s=new Shot(x+10, y+29, 1); ss.add(s); break; case 2: // 向左 s=new Shot(x, y+10, 2); ss.add(s); break; case 3: // 向右 s=new Shot(x+29, y+10, 3); ss.add(s); break; } // 启动子弹线程 Thread t=new Thread(s); t.start(); } // 坦克向上移动 public void moveUp(){ y-=speed; } // 坦克向右移动 public void moveRight(){ x+=speed; } // 坦克向下移动 public void moveDown(){ y+=speed; } // 坦克向左移动 public void moveLeft(){ x-=speed; } } 数据库学习 sql server 数据库基本概念 使用文件保存数据存在几个缺点: 1、文件的安全性问题; 2、文件不利于查询和对数据的管理; 3、文件不利于存放海量数据 4、文件在程序中控制不方便。 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 259 | 436 数据库的定义 (1) 严格地说,数据库是 "按照数据结构来组织、存储和管理数据的仓库" 。在经济管理的 日常工作中,常常需要把某些相关的数据放进这样的"仓库" ,并根据管理的需要进行相应 的处理。例如,企业或事业单位的人事部门常常要把单位职工的基本情况 ( 职工号、姓名、 年龄、性别、籍贯、工资、简历等 ) 存放在表中,这张表就可以看成一个数据库。有了这个 "数据仓库" 我们就可以根据需要随时查询某职工的基本情况, 也可以查询工资在某个范围 内的职工人数等等。 这些工作如果都能在计算机上自动进行, 那我们的人事管理就可以达到 极高的水平。此外,在财务管理、仓库管理、生产管理中也需要建立众多的这种"数据库" , 使其可以利用计算机实现财务、仓库、生产的自动化管理。 数据库的定义 (2) J.Martin 组数据库下了一个比较完整的定义: 数据库是存储在一起的相关数据的集合,这 些数据是结构化的, 无有害的或不必要的冗余, 并为多种应用服务; 数据的存储独立于使用 它的程序; 对数据库插入新数据, 修改和检索原有的数据均能按一种公用的和可控制的方式 进行。 当某个系统中存在结构上完全分开的若干个数据库时, 则该系统包含一个 "数据库集 合"。 数据库的基本结构 数据库的基本结构分三个层次,反映了观察数据库的三种不同角度。 1、物理数据层 它是数据库的最内层, 是物理存贮设备上实际存储的数据的集合。 这些数据的原始数据, 是用户加工的对象,由内部模式描述的指令操作处理的位串、字符和字组成。 2、概念数据层 它是数据库的中间一层, 是数据库的整体逻辑表示。 指出了每个数据的逻辑定义及数据 间的逻辑联系, 是存贮记录的集合。 它所涉及的是数据库所有对象的逻辑关系, 而不是它们 的物理情况,是数据库管理员概念下的数据库。 3、逻辑数据层 它是用户所看到和使用的数据库, 表示了一个或一些特定用户使用的数据集合, 即逻辑 记录的集合。 数据库不同层次之间的联系是通过映射进行转换的。 数据库的基本特点 1、实现数据共享 数据共享包含所有用户可同时存取数据库中的数据, 也包括用户可以用各种方式通过接 口使用数据库,并提供数据共享。 2、减少数据的冗余度 同文件系统比, 数据库实现了数据共享, 从而避免了用户各自建立应用文件。 减少了大 量重复数据,减少了数据冗余,维护了数据的一致性 3、数据实现集中控制 文件管理方式中, 数据处于一种分散的状态, 不同的用户或同一用户在不同处理中其文 件之间毫无关系。 利用数据库可对数据进行集中控制和管理, 并通过数据模型表示各种数据 的组织以及数据间的联系。 4、数据一致性和可维护性,以确保数据的安全性和可靠性。 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 260 | 436 5、故障恢复 目前主流数据库 微软: Sql Server 和 Access 瑞典 MySQL: AB公司 MySql IBM公司: DB2 美国 Sybase 公司: Sybase IBM公司: Informix 美国 Oracle 公司: Oracle 数据库选择: 1、成本; 2、功能; 3、并发性要求; 4、安全性; 为什么学习 Sql Server ? 简单易学 一般来讲,学习数据库很多人都是从微软的 sql server 数据库开始的,我们知道微软的产 品以简单易用见长,事实也是如此,从 sql server 开始学习数据库是正确的选择,后面我 们还要带领大学学习 oracle 数据库,如果一上手就学习 oracle 这种大型数据库, 会很吃力。 sql server 介绍 (1) SQL是英文 Structured Query Language 的缩写,意思为结构化查询语言。 SQL语言的主要 功能就是同各种数据库建立联系,进行沟通。按照 ANSI( 美国国家标准协会 ) 的规定, SQL 被作为关系型数据库管理系统的标准语言。 SQL语句可以用来执行各种各样的操作,例如更 新数据库中的数据, 从数据库中提取数据等。 目前,绝大多数流行的关系型数据库管理系统, 如 Oracle 、Sybase、Microsoft SQL Server 、 Access 等都采用了 SQL语言标准。 sql server 介绍 (2) SQL Server 是一个关系数据库管理系统。它最初是由 Microsoft Sybase 和 Ashton-Tate 三 家公司共同开发的,于 1988 年推出了第一个 OS/2 版本。在 Windows NT推出后, Microsoft 与 Sybase 在 SQL Server 的开发上就分道扬镳了, Microsoft 将 SQL Server 移植到 Windows NT系统上, 专注于开发推广 SQL Server 的 Windows NT版本。Sybase 则较专注于 SQL Server 在 UNIX操作系统上的应用。 SQL Server2000 是 Microsoft 公司推出的 SQL Server 数据库管理系统,该版本继承了 SQL Server7.0 版本的优点,同时又比它增加了许多更先进的功能。 sql server 开发工具 sql server2000 为我们提供了两种开发工具 1、企业管理器 企业管理器是微软提供的图形界面方式操作 sql server2000 的工具 2、查询分析器 查询分析器是微软提供的用命令行 (sql 语句 ) 操作 sql server2000 的工具 企业管理器的使用 (1) 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 261 | 436 数据库用户和管理员的概念 1、管理员 sa 的介绍 2、如何修改 sa 的密码 企业管理器的使用 (2) 为了让大家能迅速掌握企业管理器的使用,我们使用管理器。 以一个梁山好汉管理为例 1、建库 2、建表 英雄表 hero [ 这里涉及到对表的几个重要概念: a、字段; b、字段类型 ( 简单介绍 ) ;c、表行; d、表列; e、记录 ] 3、对表进行增加、删除、修改、查询的操作 这里可以针对真实班级的学生来做, 并增加一定的互动, 比如用点名机来抽学生操作, 或是 用点名机看看那个学生被删除或是添加、修改 ... 这样可能学生更有兴趣。 查询分析器的使用 (1) 企业管理器给用户提供了一个很方便的图形界面管理工具,大家用起来感觉直观方便, 可是它也有缺点, 当一个表的记录非常大的时候, 对表的各种操作, 都显得不方便了, 比如: 1、要求从 1000 行记录中查询是否存在名为"孙小明"的人 2、要求把 1000 行记录中工资低于 100 的人,工资增加 10% 3、要求把年龄大于 30 的人从数据表中删除 这时,你会发现使用企业管理器是很不方便的 所以微软为我们提供另外一个操作数据库的工具, 查询分析器。 查询分析器可以非常方便的 完成上述任务。 查询分析器的使用 (2)--sql 语句 使用查询分析器,我们就必需要了解 sql 语句。 什么是 sql 语句呢? 人与人交流是使用语言进行交流。 我们与 sql 数据库交流就要使用对应的计算机语言进行交 流,所以访问 sql 数据库要使用 sql 语句进行指令的发送。 查询分析器的使用 (3)--sql 语句 SQL全称是"结构化查询语言 (Structured Query Language) " SQL(Structured Query Language) 是一种数据库查询和程序设计语言,用于存取数据以及查 询、更新和管理关系数据库系统。构化查询语言 (Structured Query Language) 最早是 IBM 的圣约瑟研究实验室为其关系数据库管理系统 SYSTEM R开发的一种查询语言,它的前身是 SQUARE语言。 SQL语言结构简洁,功能强大,简单易学,所以自从 IBM 公司 1981 年推出以 来, SQL 语言得到了广泛的应用。如今无论是像 Oracle 、 Sybase、Informix 、SQL Server 这些大型的数据库管理系统,还是像 Visual Foxpro 、 PowerBuilder 这些 PC上常用的数据 库开发系统,都支持 SQL语言作为查询语言。 查询分析器的使用 (4)--sql 语句 SQL语言包含 4 个部分: 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 262 | 436 数据定义语言 (DDL),例如: CREATE、DROP、ALTER等语句。 数据操作语言 (DML),例如: INSERT、UPDATE、DELETE语句。 数据查询语言 (DQL),例如: SELECT语句。 数据控制语言 (DCL),例如: GRANT、REVOKE、COMMIT、ROLLBACK等语句。 查询分析器的使用 (5) 使用查询分析器再次完成梁山好汉管理数据库 1、建库 2、建表 英雄表 hero [ 这里涉及到对表的几个重要概念: a、字段; b、字段类型 ( 简单介绍 ) ;c、表行; d、表列; e、记录 ] 3、 对表进行增加、删除、修改、查询的操作 查询分析器中创建数据库 -- 创建数据库 create database LiangshanHero2 -- 创建表 use LiangshanHero2 -- 使用指定数据库 go-- 执行 create table hero -- 表名 (heroId int , -- 英雄排名 heroName varchar(50), -- 名字 heroNickName varchar(50), -- 绰号 sex char(2), -- 性别 sal int ) -- 删除一张表 ( 把表的结构和表的数据删除 ) drop table hero -- 使用 sql 语句来添加数据 insert into hero values(1,' 宋江 ',' 及时雨 ',' 男',20000) insert into hero values(2,' 卢俊义 ',' 玉麒麟 ',' 男',15000) insert into hero values(3,' 吴用 ',' 智多星 ',' 男',30) insert into hero values(4,' 公孙胜 ',' 入云龙 ',' 男',80) -- 使用 sql 语句查询数据 , 最基础的查询语句 select * from hero --1 、查询工资低于 100 的同志 select * from hero where sal3000 -- 如何查找 1982-1-1 后入职的员工 select ename" 员 工 姓 名 ",hiredate"1982-1-1 后 入 职 日 期 " from emp where hiredate>'1982-1-1' -- 如何显示工资在 2000 到 2500 的员工情况 select * from emp where sal>=2000 and sal<=2500 select * from emp where sal between 2000 and 2500 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 268 | 436 -- 如何使用 like 操作符 ( 模糊查询 ) --%:表示 0 到多个字符 _: 表示单个字符 -- 如何显示首字符为 S 的员工姓名和工资 select ename,sal from emp where ename like 's%' -- 如何显示第三个字符为 o 的所有员工的姓名和工资 select ename,sal from emp where ename like '__O%' -- 在 where 条件中使用 in -- 如何显示 empno为 123,345,800... 的雇员情况 select * from emp where empno in(123,345,800) -- 使用 is null 的操作符 -- 如何显示没有上级的雇员的情况 select * from emp where mgr is null -- 使用逻辑操作符号 -- 查询工资高于 500 或是岗位为 manager 的雇员,同时还要满足他们的姓名首写字母为大写 的 J select * from emp where (sal>500 or job='manager') and ename like 'J%' -- 使用 order by 字句 (asc 默认是升序排列 ,desc 为降序排列 ) -- 如何按照工资的从低到高的顺序显示雇员的信息 select sal from emp order by sal asc -- 按照部门号升序而雇员的工资降序排列 --order by 可以根据不同的字段排序 select deptno,sal from emp order by deptno,sal desc -- 使用列的别名排序 ( 别名需要使用 "" 号圈中 ) select ename,sal*12" 年薪 " from emp order by " 年薪 " 表的复杂查询 说明: 在实际应用中经常需要执行复杂的数据统计, 经常需要显示多张表的数据, 现在我们给 大家介绍较为复杂的 select 语句 数据分组 -max( 最大 ),min( 最小 ),avg( 平均 ),sum( 和),count( 统计 ) 见下例: -- 如何显示所有员工中最高工资和最低工资 select min(sal)" 最低工资 ",max(sal)" 最高工资 " from emp -- 显示最低工资并显示出雇员名字 select ename" 姓名 ",sal" 工资 " from emp where sal=(select min(sal) from emp) 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 269 | 436 -- 显示所有员工的平均工资和工资总和 select avg(sal)" 平均工资 ",sum(sal)" 工资总和 " from emp -- 把高于平均工资的雇员的名字和他的工资显示出来 select ename,sal from emp where sal>(select avg(sal) from emp) order by sal -- 计算共有多少员工 select count(*)" 雇员数 " from emp -- 扩展要求 -- 请显示工资最高的员工的名字、工作岗位 select ename,job from emp where sal=(select max(sal) from emp) -- 请显示工资高于平均工资的员工信息 , 并显示平均工资 ( 效率不高 ) select ename" 姓名 ",job" 岗位 ",sal" 工资 ",(select avg(sal) from emp)" 平均工资 " from emp where sal>(select avg(sal) from emp) order by sal 表的复杂查询 group by 和 having 子句 group by 用于对查询的结果分组统计 having 子句用于限制分组显示结果 例: --group by 和 having 子句使用 (having 与 group by 结合使用,可以对分组后的查询结果进 行筛选 ) -- 如何显示每个部门的平均工资和最高工资 select deptno" 部门号 ",avg(sal)" 平均工资 ",max(sal)" 最高工资 ",min(sal)" 最低工资 " from emp group by deptno -- 如何显示每个部门的平均工资和最高工资并显示部门名称 ( 多表查询 ) select emp.deptno" 部门号 ",avg(sal)" 平均工资 ",max(sal)" 最高工资 ",min(sal)" 最低工 资 ",dept.dname" 部 门名称 " from emp,dept where emp.deptno=dept.deptno group by emp.deptno,dept.dname -- 显示每个部门的每种岗位的平均工资和最低工资 select deptno" 部门号 ",job" 岗位 ",avg(sal)" 平均工资 ",min(sal)" 最低工资 " from emp group by deptno,job order by deptno -- 显示平均工资低于 2000 的部门号和它的平均工资 select deptno" 部 门 号 ",avg(sal)" 平 均 工 资 " from emp group by deptno having avg(sal)2000 order by " 平均工资 " 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 270 | 436 表的复杂查询 对数据分组的总结 1、分组函数只能出现在选择列表, having 、order by 子句中 2、如果在 select 语句中同时包含有 group by,having ,ovrder by 那么他们的顺序是 group by, having ,order by 3、在选择列中如果有列、 表达式、和分组函数, 那么这些列和表达式必需有一个出现在 group by 子句中,否则就会出错 如: select deptno,avg(sal),max(sal) from emp group by deptno having avg(sal)temp.myavg 在 from 子句中使用子查询 这里需要说明的当在 from 子句中使用子查询时,该子查询会被作为一个临时表来对待,当 在 from 子句中使用子查询时,必需给子查询指定别名 分面查询 按雇员的 id 号升序取出 -- 请显示第 5 个到第 10 个入职的雇员信息 ( 按照入职的时间先后顺序查找 ) -- 分析: 1、显示第 1 个到第 4 个入职的雇员 select top 4 * from emp order by hiredate --top 后的数表示要取出几条记录 select top 6 * from emp where empno not in(select top 4 empno from emp order by hiredate) order by hiredate -- 请显示第 11 个到 13 个入职的雇员信息 select top 3 * from emp where empno not in(select top 10 empno from emp order by 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 272 | 436 hiredate) order by hiredate -- 请显示第 5 个到 9 个入职的雇员信息 (按薪水高低排序 ) select top 5 * from emp where empno not in(select top 4 empno from emp order by sal desc) order by sal desc 用查询结果创建新表 这个命令是一种快捷的建表方法 select *( 这里可以选择字段 ) into 另一个表名 from 表 -- 如何删除掉一张表重复记录 create table cat( catId int, catName varchar(40) ) insert into cat values(1,'aa') select * from cat --1 、把 cat 表的记录 distinct 后的结果,放到临时表中 select distinct * into #temp from cat --2 、把 cat 表的记录清空 delete from cat --3 、把临时表中的数据信息加入到 cat 表中 insert into cat select * from #temp --4 、删除临时表 drop table #temp -- 左外连接和右外连接 -- 思考题:显示公司每个员工和他的上级领导的名字 -- 内连接的处理方式 ( 内连接只显示匹配的信息 ) select worker.ename" 员工名字 ",boss.ename" 领导名字 " from emp worker,emp boss where worker.mgr=boss.empno -- 思考题:显示公司每个员工和他的上级领导的名字,没有上级领导的也要显示出来 -- 左外连接:指如果左边的表记录全部显示,如果没有匹配的记录,就用 null 填写 select worker.ename" 员工名字 ",boss.ename" 领导名字 " from emp worker left join emp boss on worker.mgr=boss.empno -- 右外连接:指如果右边的表记录全部显示,如果没有匹配的记录,就用 null 填写 select worker.ename" 员工名字 ",boss.ename" 领导名字 " from emp worker right join emp boss on worker.mgr=boss.empno 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 273 | 436 维护数据的完整性 -- 约束 约束用于确保数据库数据满足特定的商业规则。 在 sql server 和 oracle 中,约束包括: not null 、unique ,primary key ,foreign key 和 check 五种 维护数据的完整性 -- 使用 not null( 非空 ) 如果在列上定义了 not null ,那么当插入数据时,必需为列提供数据。 -- 约束机制 --not null( 非空 ) -- 创建一张表 create table test1 (test1Id int primary key identity(1,1), testname varchar(30) not null, --not null 不能为空 testpass varchar(30) not null, testage int -- 不写代表可以为空 ) create table test1 (test1Id int primary key identity(1,1) , --identity(1,1) 自增长 1 条记录 testname varchar(30), testpass varchar(30), testage int -- 不写代表可以为空 ) -- 删除表 drop table test1 -- 向表插入数据 insert into test1 (testage) values (3) insert into test1 (testname,testpass,testage) values ('','',5) --'' 空与 null 空是 不一样的 -- 查询表内容 select * from test1 unique( 唯一 )( 一张表中可以有多个 ) 当定义了唯一约束后,该列值是不能重复的,但是可以为 null, 并只能有一个空值 -- 约束机制 --unique( 唯一 ) -- 建表 create table test2 (test1Id int primary key identity(1,1), --identity(1,1) 自增长 1 条记录 testname varchar(30) unique, --unique 唯一的,数据不允许重复 , 但可以为空 testpass varchar(30), testage int -- 不写代表可以为空 ) insert into test2 (testname,testpass,testage) values ('aa','123',45) insert into test2 (testpass,testage) values ('123',45) 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 274 | 436 select * from test2 primary key( 主键 )( 一张表中只可以有一个主键 ) 用于唯一的标示表行的数据,当定义主键约束后,该列不但不能重复而且不能为 null 需要说明的是:一张表最多只能有一个主键,但是可以有多个 unqiue 约束。 表可以有复合主键,有多个列构成一个主键 -- 复合主键 create table test3 (testId int, testname varchar(30), testpass varchar(30), testage int, primary key (testId,testname) -- 复合主键,需单独声明 ) -- 行级定义和表级定义 create table test4 (testId int, -- 在字段中定义主键为行级定义 . 例: testId int primary key testname varchar(30), testpass varchar(30), testage int, primary key (testId,testname)-- 复合主键,需单独声明为表级定义 ) foreign key( 外键 )( 外键在从表上,要配合主表,但主表要有主键或 unique 约束 ) 用于定义主表和从表之间的关系。 外键约束要定义在从表上, 主表则必需具有主键约束或是 unique 约束,当定义外键约束后,要求外键列数据必需在主表的主键列存在或是 null check( 强制条件 ) 用于强制行数据必需满足的条件,假定在 sal 列上定义了 check 约束,并要求 sal 列值在 1000-2000 之间如果不再 1000-2000 之间就会提示出错。 --check( 强制条件 ) create table test5 (testId int, testname varchar(30), testpass varchar(30), sal int check(sal>=1000 and sal<=2000), -- 规定 sal 的值在 1000-2000 之间 ) insert into test5 values (4,'aa','aa', 1200)-- 可以加入 sal 值在范围之内 insert into test5 values (5,'bb','bb', 2200)-- 不可加入 sal 值在范围之外 select * from test5 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 275 | 436 default 使用 ( 默认值 ) --default 使用 create table mes (mesId int primary key identity(1,1), mesccn varchar(2000) not null, mesDate datetime default getdate() -- 在不指定值是 default 可以直接取默认值,也可以 由用户指定值 ) insert into mes(mesccn) values('abc') insert into mes(mesccn,mesDate) values('cba','1976-1-6') select * from mes 商店售货系统表设计案例 现有一个商店的数据库,记录客户及其购物情况,由下面三个表组成: 商品 goods( 商品号 goodsId ,商品名 goodsName,单价 unitprice ,商品类别 category ,供 应商 provider) ; 客户 customer( 客户号 customerId ,姓名 name,住址 address ,电邮 email ,性别 sex,身 份证 cardId) ; 购买 purchase( 客户号 customerId ,商品号 goodsId ,购买数量 nums); 请使用 sql 语言完成下列功能: 1、建表,在定义中要求声明: 1、每个表的主外键; 2、客户的姓名不能为空值; 3、单价必需大于 0,购买数量大于 0; 4、电邮不能够重复; 5、客户的性别必需是男或者女,默认为男 6、商品类别是 ' 食物 ' ,' 日用品 ' -- 商店售货系统表设计案例 create table goods -- 商品表 (goodsId nvarchar(50) primary key, -- 商品 Id 为主键 goodsName nvarchar(80) not null, -- 商品名不为空 unitprice numeric(10,2) check (unitprice>0), -- 商品单价限制大于 0 category nvarchar(3) check(category in(' 食物 ',' 日用品 ')), -- 商品类别需在指定的范 围内 provide nvarchar(50) -- 供应商 ) create table customer -- 客户表 (custcmerId nvarchar(50) primary key, -- 客户 Id 为主键 cusname nvarchar(50) not null, -- 客户名不能为空 address nvarchar(100), -- 地址 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 276 | 436 email nvarchar(100) unique, -- 邮件不为重复 sex nchar(1) check(sex in(' 男',' 女')) default ' 男', -- 性别只能为男或女,默认为男 cardId nvarchar(18) -- 身份证 ) create table purchase -- 购买表 (custcmerId nvarchar(50) foreign key references customer(custcmerId), -- 客户 Id 为外键,并指向 customer 表的 custcmerId 主键 goodsId nvarchar(50) foreign key references goods(goodsId), -- 商品 Id 为外键,并指 向 goods 表的 goodsId 主键 nums int check(nums>0) -- 购买数量限定大于 0 ) 表的管理 -- 修改表 添加一个字段 ALTER TABLE distributors ADD COLUMN address varchar(30); 修改字段的类型 / 或是名字 ( 不能有数据 ) ALTER TABLE distributors ALTER COLUMN address TYPE varchar(80), ALTER COLUMN name TYPE varchar(100); ALTER TABLE distributors RENAME COLUMN address TO city; 删除一个字段 ALTER TABLE distributors DROP COLUMN address RESTRICT; 修改表的名字 ALTER TABLE distributors RENAME TO suppliers; 删除表 drop table 表名 ; 数据库的备份和恢复 使用企业管理器完成备份和恢复 使用企业管理器有两种方式完成备份和恢复 1、分离 / 附加 分离完后,请到 sql server 安装的目录下去找两个文件数据库名 .mdf 和数据库名 .ldf , 这两个文件就是分离后的文件,数据库分离后,该数据库就不能再使用了。 附加是指,当用户需要重新使用某个分离的数据库时进行的操作,就是让 sql server 数据库重新关联该数据库。 2、备份 / 恢复 备份数据库是指,把某个数据库文件从 sql server 中备份出来,这样用户可以根据需 要再使用 (用于恢复、复用 ..) ,备份数据库不会影响到源数据库的使用 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 277 | 436 恢复数据库是指, 当源数据库因为某种原因 ( 比如源数据库毁坏、 数据丢失、 系统崩溃 ) 需要恢复时进行的操作 使用查询分析器完成备份和恢复 用企业管理器完成对数据库的备份和恢复简单直观, 同样我们也可以在查询分析器中完 成类似的任务。 -- 使用查询分析器对数据库进行备份和恢复 -- 数据库备份 -- 语法: backup database 数据库名 to disk=' 存储路径 ' backup database LiangshanHero2 to disk='f:/liangshan.bak' -- 数据库恢复 -- 语法: restore database 数据库名 from disk=' 读取路径 ' restore database LiangshanHero2 from disk='f:/liangshan.bak' -- 新建数据库 -- 语法: create datebase 数据库名 create database LiangshanHero2 -- 删除数据库 -- 语法: drop database 数据库名 drop database LiangshanHero2 ******************************************************************************* 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 278 | 436 java 程序操作 sql server crud 介绍 ( 增、删、改、查操作 ) CRUD是指在做计算处理时的增加 (Create) 、查询 (Retrieve)( 重新得到数据 ) 、更新 (Update) 和删除 (Delete) 几个单记事的首字母简写。 主要被用在描述软件系统中数据库或者持久层的 基本操作功能。 Incomputing,CRUD is an acronym for create,retrieve,update,and delete.It is used to refer to the basic functions of a database or persistence layer in a software system. Create new records Rctricvc cxisting rccords Update existing records Delete existing records. crud 介绍 要对数据表进行增、删、改、查,我们首先要清楚 jdbc 基本的概念: 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 279 | 436 JDBC 有两种,一种原 sun 公司提供的数据库连接 api 但不是直接连接 sql server 而是 先连接 ODBC再通过 ODBC对 sql server 进行操作;一种是由微软提供的 JDBC数据库连接 api 可直接对 sql server 数据库进行操作。 JDBC (Java Data Base Connectivity,java 数据库连接)是一种用于执行 SQL语句的 Java API ,可以为多种关系数据库提供统一访问,它由一组用 Java 语言编写的类和接口组 成。 JDBC 提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编 写数据库应用程序,同时, JDBC也是个商标名。 有了 JDBC,向各种关系数据发送 SQL语句就是一件很容易的事。 换言之,有了 JDBC API, 就不必为访问 Sybase 数据库专门写一个程序, 为访问 Oracle 数据库又专门写一个程序, 或 为访问 Informix 数据库又编写另一个程序等等, 程序员只需用 JDBC API 写一个程序就够了, 它可向相应数据库发送 SQL调用。同时,将 Java 语言和 JDBC结合起来使程序员不必为不同 的平台编写不同的应用程序,只须写一遍程序就可以让它在任何平台上运行,这也是 Java 语言"编写一次,处处运行"的优势。 注: JDBC访问不同的数据库使用的 JDBC API 都有所不同,虽然统称为 JDBC。如:访问 sql server 数据库的 JDBC,是不能访问 oracle 数据库的,同理也是也不访问 mysql 、db2、 Informix 数据库等。只是访问方式不同,对数据库的操作依然是使用 sql 语句操作 Java 具有坚固、安全、易于使用、易于理解和可从网络上自动下载等特性,是编写数 据库应用程序的杰出语言。 所需要的只是 Java 应用程序与各种不同数据库之间进行对话的 方法。而 JDBC 正是作为此种用途的机制。 java 程序操作 sql server jdbc 的驱动的分类 目前比较常见的 JDBC驱动程序可分为以下四个种类 1、jdbc-odbc 桥连接 2、本地协议纯 java 驱动程序 3、网络协议纯 java 驱动程序 4、本地 api jdbc 不足 尽管 JDBC在 JAVA语言层面实现了统一, 但不同数据库仍旧有许多差异。 为了更好地实现跨 数据库操作,于是诞生了 Hibernate 项目, Hibernate 是对 JDBC的再封装,实现了对数据 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 280 | 436 库操作更宽泛的统一和更好的可移植性。 java 操作 sql server 数据库 (表 ) 1、我们先使用 jdbc-odbc 桥连的方式来操作 sql server 数据库 (表) 完成对 emp表的 crud 操作 [Sql_test1.java] 2、再用 jdbc 驱动程序直接操作 sql server 数据库 ( 表) 完成对 emp表的 crud 操作。 /** * 演示使用 jdbc-odbc 桥连方式 操作 sql server 数据库 * 具体操作 test 数据库的 emp表和 dept 表 * 1、配置数据源 --windows 下在控制面板 --> 管理工具 -->ODBC数据源 --> 用户 DSN--添加 * sql server * 2 、在程序中去连接数据源 * 3 、使用 Statement( 不安全 ) 连接数据库 */ package com.sqlserver; import java.sql.*; public class Sql_test1 { public static void main(String[] args) { Connection ct=null; Statement sm=null; ResultSet rs=null; try { //1 、加载驱动 (把需要的驱动程序加入内存 ) Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); //2 、得到连接 (指定连接到哪个数据源、数据库的用户名和密码 ) // 如果配置数据源的时候选择的是 windows NT 验证方式,则不需要数据库的 用户名和密码 //Connection ct=DriverManager.getConnection("jdbc:odbc:mytest"); ct=DriverManager.getConnection("jdbc:odbc:mytest","sa","sa"); //3 、创建 Statement 或者 PreparedStatement( 区别 ) //Statement 用处:主要用于发送 SQL语句到数据库 sm=ct.createStatement(); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 281 | 436 //4 、执行 (CRUD,创建数据库、备份数据库、删除数据库 ) // 演示 1:添加一条数据到 dept 表中 //executeUpdate 可以执行 CUD操作 ( 添加、删除、修改 ) int i=sm.executeUpdate("insert into dept values('60',' 保安部 ',' 西永 ')"); if(i==1){ System.out.println(" 数据添加成功 "); }else{ System.out.println(" 添加失败 "); } // 演示 2:从 dept 表中删除一条记录 int j=sm.executeUpdate("delete from dept where deptno='50'"); if(j==1){ System.out.println(" 数据删除成功 "); }else{ System.out.println(" 删除失败 "); } // 演示 3:从 dept 表中修改 deptno=40 loc 改为 beijing int k=sm.executeUpdate("update dept set loc='beijing' where deptno='40'"); if(k==1){ System.out.println(" 数据修改成功 "); }else{ System.out.println(" 修改失败 "); } // 演示 4:查询 , 显示所有的部门信息 //ResultSet 结果集 , 大家可以把 ResultSet 理解成返回一张表行的结果集 rs=sm.executeQuery("select * from dept"); // 循环取出 while( rs.next() ){ int a=rs.getInt(1); String b=rs.getString(2); String c=rs.getString(3); System.out.println(a+"\t"+b+"\t"+c); } } catch (Exception e) { e.printStackTrace(); }finally{ // 关闭资源,关闭顺序先创建后关闭,后创建先关闭 try { // 为了程序健壮 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 282 | 436 if(rs!=null){ rs.close(); } if(sm!=null){ sm.close(); } if(ct!=null){ ct.close(); } } catch (SQLException e) { e.printStackTrace(); } } } } ------------------------------------------------------------------------------- java 程序操作 sql server Statement 和 PreparedStatement 的区别 (1) Statemen 和 PreparedStatement 都可以用于把 sql 语句从 java 程序中发送到指定数据 库,并执行 sql 语句,但是他们也存在 区别: 1、直接使用 Statement ,驱动程序一般不会对 sql 语句作处理而直接交给数据库;使用 PreparedStamen ,形成预编译的过程,并且会对语句作字符集的转换 ( 至少在 sql server) 中如此。 如此,有两个好处: 对于多次重复执行的语句, 使用 PreparedStament 效率会更高一点, 并且在这种情况下也比较适合使用 batch ;另外,可以比较好地解决系统的本地化问题。 2、PreparedStatement 还能有效的防止危险字符的注入,也就是 sql 注入的问题。 PreparedStatement 的使用 [Sql_test2.java] /** * PreparedStatement 使用 CRUD * 1、PreparedStatement 可以提高执行效率 ( 因为它有预编译的功能 ) * 2、PreparedStatement 可以防止 SQL注入,但是要求用 ?赋值的方式才可以 */ package com.sqlserver; import java.sql.*; public class Sql_test2 { public static void main(String[] args) { Connection ct=null; PreparedStatement ps=null; ResultSet rs=null; try { //1 、加载驱动 (把需要的驱动程序加入内存 ) Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); //2 、得到连接 (指定连接到哪个数据源、数据库的用户名和密码 ) 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 283 | 436 ct=DriverManager.getConnection("jdbc:odbc:mytest","sa","sa"); //3 、创建 PreparedStatement //PreparedStatement 用处:主要用于发送 SQL语句到数据库 // ps=ct.prepareStatement("select * from dept where deptno=? and loc=?"); // // 给 ?赋值 ( 可防止 SQL注入漏洞问题 ) ,不要直接使用拼接的方式 // ps.setInt(1, 20); // ps.setString(2, "dallas"); // // 演示:查询 , 显示所有的部门信息 // //ResultSet 结果集 , 大家可以把 ResultSet 理解成返回一张表行的结果集 // rs=ps.executeQuery(); // // 循环取出 // while(rs.next()){ // int a=rs.getInt(1); // String b=rs.getString(2); // String c=rs.getString(3); // System.out.println(a+"\t"+b+"\t"+c); // } // 使用 PreparedStetement 添加一条记录 // ps=ct.prepareStatement("insert into dept values(?,?,?)"); // ps.setInt(1, 60); // ps.setString(2, " 安全部 "); // ps.setString(3, " 上海 "); // // 执行 // int i=ps.executeUpdate(); // if(i==1){ // System.out.println(" 添加成功 "); // }else{ // System.out.println(" 添加失败 "); // } // 使用 PreparedStetement 修改一条记录从 dept 表中修改 loc= 上海 deptno 改为 50 // ps=ct.prepareStatement("update dept set deptno=? where loc=' 上海 '"); // ps.setInt(1, 50); // // 执行 // int i=ps.executeUpdate(); // if(i==1){ // System.out.println(" 修改成功 "); // }else{ // System.out.println(" 修改失败 "); // } // 使用 PreparedStetement 删除一条记录 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 284 | 436 ps=ct.prepareStatement("delete from dept where deptno=?"); ps.setInt(1, 50); int i=ps.executeUpdate(); if(i==1){ System.out.println(" 删除成功 "); }else{ System.out.println(" 删除失败 "); } } catch (Exception e) { e.printStackTrace(); }finally{ // 关闭资源,关闭顺序先创建后关闭,后创建先关闭 try { if(rs!=null){ rs.close(); } if(ps!=null){ ps.close(); } if(ct!=null){ ct.close(); } } catch (SQLException e) { e.printStackTrace(); } } } } ------------------------------------------------------------------------------- JDBC-ODBC桥连操作 sql server 与 JDBC驱动直连操作 sql server 的区别: 1、JDBC-ODBC桥连 sql server 无需引入外部驱动 2、JDBC直连需要引入微软提供的 JDBC驱动 JDBC直连 sqlserver 示例 [Sql_test3.java] /** * JDBC 方式去操作数据库 ( 单表操作 ) * 1、引入 sql 包 * 2、sqlserver2000 需要引入三个 jar 包, 分别是 msbase.jar 和 mssqlserver.jar 和 msutil.jar * 3、sqlserver2005/2008/2012 版本中可以引入 sqljdbc.jar 或 sqljdbc4.jar 两个微软 提供的 JDBC包,官方目前推出 2.0/3.0/4.0 版本 * 4 、 使 用 sqljdbc4.jar 后 可 以 不 使 用 加 载 驱 动 Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); 而直接连接数据库 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 285 | 436 * 5 、使用 sqljdbc.jar 则需要加载驱动 * 6、特别说明,如果取值是按编号取,则需一一对应;如果按字段列名取值,则可以灵活 取值 */ package com.sqlserver; import java.sql.*; public class Sql_test3 { public static void main(String[] args) { // 定义需要的对象 PreparedStatement ps=null; Connection ct=null; ResultSet rs=null; try { // 初始化我们的对象 //1 、加载驱动 Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); //2 、得到连接 ct=DriverManager.getConnection("jdbc:sqlserver://127.0.0.1:1433;databaseNam e=test;user=sa;password=sa;"); if(!ct.isClosed()){ System.out.println(" 数据库连接成功 "); }else{ System.out.println(" 数据库连接失败 "); } //3 、创建 PreparedStatement // ps=ct.prepareStatement("select * from emp"); ps=ct.prepareStatement("select ename,sal,deptno from emp"); //4 、执行 ( 查询就用 executeQuery() ,增加、删除、修改就用 executeUpdate() ) rs=ps.executeQuery(); // 循环取出 , 雇员的名字、雇员的薪水,部门编号 while(rs.next()){ // String ename=rs.getString(2); // float sal=rs.getFloat(6); // int deptno=rs.getInt(8); // String ename=rs.getString(1); // 对应的列号可以取出数据 // float sal=rs.getFloat(2); // int deptno=rs.getInt(3); String ename=rs.getString("ename"); // 使用字段名也可以取出数据 float sal=rs.getFloat("sal"); int deptno=rs.getInt("deptno"); System.out.println(ename+"\t"+sal+"\t"+deptno); } } catch (Exception e) { 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 286 | 436 e.printStackTrace(); }finally{ try { if(rs!=null){ rs.close(); } if(ps!=null){ ps.close(); } if(ct!=null){ ct.close(); } } catch (SQLException e) { e.printStackTrace(); } } } } ------------------------------------------------------------------------------- 多表操作,示例 [Sql_test4.java] /** * JDBC 方式去操作数据库 ( 多表操作 ) * 1 、引入 sql 包 * 2 、sqlserver2000 需要引入三个 jar 包, 分别是 msbase.jar 和 mssqlserver.jar 和 msutil.jar * 3 、sqlserver2005/2008/2012 版本中可以引入 sqljdbc.jar 或 sqljdbc4.jar 两个微软 提供的 JDBC包,官方目前推出 2.0/3.0/4.0 版本 * 4 、 使 用 sqljdbc4.jar 后 可 以 不 使 用 加 载 驱 动 Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); 而直接连接数据库 * 5 、使用 sqljdbc.jar 则需要加载驱动 * 6、特别说明,如果取值是按编号取,则需一一对应;如果按字段列名取值,则可以灵活 取值 */ package com.sqlserver; import java.sql.*; public class Sql_test4 { public static void main(String[] args) { // 定义需要的对象 PreparedStatement ps=null; Connection ct=null; ResultSet rs=null; try { // 初始化我们的对象 //1 、加载驱动 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 287 | 436 Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); //2 、得到连接 ct=DriverManager.getConnection("jdbc:sqlserver://127.0.0.1:1433;databaseNam e=test;user=sa;password=sa;"); if(!ct.isClosed()){ System.out.println(" 数据库连接成功 "); }else{ System.out.println(" 数据库连接失败 "); } // //3 、创建 PreparedStatement // ps=ct.prepareStatement("select ename,sal,dname from emp,dept where emp.deptno=dept.deptno"); // //4 、执行 ( 查询就用 executeQuery() ,增加、删除、修改就用 executeUpdate()) // rs=ps.executeQuery(); // // 循环取出 , 雇员的名字、雇员的薪水,部门名称 // while(rs.next()){ // String ename=rs.getString("ename"); // 使用字段名也可以取出数据 // float sal=rs.getFloat("sal"); // String dname=rs.getString("dname"); // System.out.println(ename+"\t"+sal+"\t"+dname); // } // //5 、创建 PreparedStatement // ps=ct.prepareStatement("insert into dept values(?,?,?)"); // //6 、给 ?赋值 // ps.setInt(1, 60); // ps.setString(2, "Finance"); // ps.setString(3, "Alaska"); // //7 、执行 ( 查询就用 executeQuery() ,增加、删除、修改就用 executeUpdate()) // int i=ps.executeUpdate(); // if(i==1){ // System.out.println(" 添加数据成功 "); // }else{ // System.out.println(" 添加数据失败 "); // } // //8 、创建 PreparedStatement // ps=ct.prepareStatement("delete from dept where deptno=?"); // //9 、给 ?赋值 // ps.setInt(1, 50); // //10 、 执 行 ( 查 询 就 用 executeQuery() , 增 加 、 删 除 、 修 改 就 用 executeUpdate()) // int i=ps.executeUpdate(); // if(i==1){ // System.out.println(" 删除数据成功 "); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 288 | 436 // }else{ // System.out.println(" 删除数据失败 "); // } //11 、创建 PreparedStatement ps=ct.prepareStatement("update dept set deptno=? where loc=?"); //12 、给 ?赋值 ps.setInt(1, 50); ps.setString(2, "Alaska"); //13 、 执 行 ( 查 询 就 用 executeQuery() , 增 加 、 删 除 、 修 改 就 用 executeUpdate()) int i=ps.executeUpdate(); if(i==1){ System.out.println(" 修改数据成功 "); }else{ System.out.println(" 修改数据失败 "); } } catch (Exception e) { e.printStackTrace(); }finally{ try { if(rs!=null){ rs.close(); } if(ps!=null){ ps.close(); } if(ct!=null){ ct.close(); } } catch (SQLException e) { e.printStackTrace(); } } } } ------------------------------------------------------------------------------- java 程序操作 sql server Statement 和 PreparedStatement 的区别 (2) 看下面两段程序片断: Code Fragment 1: String updateString="UPDATE COFFEES SET SALES=75"+"WHERE COF_NAME LIKE 'Colombian'"; stmt.executeUpdate(updateString); Code Fragment 2: 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 289 | 436 PreparedStatement updateSales=con.prepareStatement("UPDATE COFFEES SET SALES=? WHERE COF_NAME LIKE ?"); updateSales.setInt(1,75); updateSales.setString(2,"Colombian"); updateSales.executeUpdate(); 后者使用了 PreparedStatement ,而前者是 Statement ,PreparedStatement 不仅包含 了 SQL语句,而且大多数情况下这个语句已被预编译过,当其执行时,只需 DBMS运行 SQL 语句,而不必先编译。当你需要执行 Statement 对象多次的时候, PreparedStatement 对象 将会降低运行时间,加快了访问数据库的速度。 好处是,不必重复 SQL语句的句法, 而只需要改其中变量的值, 便可重新执行 SQL语句。 选择 PreparedStatement 对象与否, 在于相同句法的 SQL语句是否执行了多次, 而且两次之 间的差别仅是变量的不同。 如仅执行一次的话, 它和普通的对象无差异, 体现不出预编译的 优越性。 java 操作 sql server 数据库 (表 )[Sql_test5.java] 在软件公司实际开发过程中,也许需要你在 java 程序中来控制对数据库 ( 表 ) 的创建、 删除、备份、恢复工作 ,这是我们又该怎样完成呢? /** * 在 java 中如何使用 ddl 语句 (credate( 创建 ),drop( 删除 ),backup( 备份 ),restore( 恢复 )) 数据库 */ package com.sqlserver; import java.sql.*; public class Sql_test5 { public static void main(String[] args) { // 定义需要的对象 PreparedStatement ps=null; Connection ct=null; ResultSet rs=null; try { //1 、加载驱动 Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); //2 、得到连接 ct=DriverManager.getConnection("jdbc:sqlserver://127.0.0.1:1433;databaseNam e=test;user=sa;password=sa;"); if(!ct.isClosed()){ System.out.println(" 数据库连接成功 "); }else{ System.out.println(" 数据库连接失败 "); } // //3 、创建 ps,创建数据库 // ps=ct.prepareStatement("create database vvv"); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 290 | 436 // // 如果执行的是 ddl 语句 // if(!ps.execute()){ // System.out.println(" 创建数据库成功 "); // }else{ // System.out.println(" 创建数据库失败 "); // } //4 、创建 ps,创建表 // ps=ct.prepareStatement("create table xxx(aa int)"); // // 如果执行的是 ddl 语句 // if(!ps.execute()){ // System.out.println(" 创建表成功 "); // }else{ // System.out.println(" 创建表失败 "); // } //5 、备份数据库 // ps=ct.prepareStatement("backup database vvv to disk='e:/vvv.bak'"); // if(!ps.execute()){ // System.out.println(" 备份数据库成功 "); // }else{ // System.out.println(" 备份数据库失败 "); // } //6 、恢复数据库 ps=ct.prepareStatement("restore database vvv from disk='e:/vvv.bak'"); if(!ps.execute()){ System.out.println(" 恢复数据库成功 "); }else{ System.out.println(" 恢复数据库失败 "); } } catch (Exception e) { e.printStackTrace(); }finally{ try { if(rs!=null){ rs.close(); } if(ps!=null){ ps.close(); } if(ct!=null){ ct.close(); } } catch (SQLException e) { 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 291 | 436 e.printStackTrace(); } } } } ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- sql server 作业点评: 使用 scott/tiger 用户下的 emp表完成下列练习,表的结构说明如下 emp员工表 (empno 员工号 /ename 员工姓名 /job 工作 /mgr 上级编号 /hiredate 受雇日期 /sal 薪金 /comm佣金 /deptno 部门编号 ) // 把课堂上创建的 emp,dept 表自己创建一下 ( 参考图 ) // 根据 emp表和 dept 表,完成下面的练习 --1 、选择部门 30 中的所有员工 select * from emp where deptno=30 --2 、列出所有办事员 (CLERK)的姓名,编号和部门编号 select ename,empno,deptno from emp where job='clerk' --3 、找出佣金高于薪金的员工 ( 佣金是奖金 ) select * from emp where isnull(comm,0)>sal --4 、找出佣金高于薪金的 60%的员工 select * from emp where comm>sal*0.6 --5 、找出部门 10 中所有经理 (MANAGER)和部门 20 中所有办事员 (CLERK)的详细资料 select * from emp where (deptno=10 and job='manager')or(deptno=20 and job='clerk') --6 、找出部门 10 中所有经理 (MANAGER)部门 20 中所有办事员 (CLERK)既不是经理又不是办 事员但其薪金大于或等于 2000 的所有员工的详细资料。 select * from emp where (deptno=10 and job='manager') or (deptno=20 and job='clerk') or (job<>'manager' and job<>'clerk' and sal>=2000) --7 、找出收取佣金的员工的不同工作 select distinct job from emp where comm>0 --8 、找出不收取佣金或收取的佣金低于 100 的员工 select * from emp where comm12 --11 、以首字母大写的方式显示所有员工的姓名 select upper(substring(ename,1,1))+lower(substring(ename,2,len(ename))) from emp --12 、显示正好为 5 个字符的员工的姓名 select * from emp where ename like'_____' select * from emp where len(ename)=5 --13 、显示不带有 R的员工的姓名 select ename from emp where ename not like'%R%' --14 、显示所有员工姓名的前三个字符 select substring(ename,1,3) from emp --15 、显示所有员工的姓名,用 a 替换所有 A select replace(ename,'A','a') from emp --16 、显示满 10 年服务年限的员工的姓名和受雇日期 select ename,hiredate from emp where datediff(year,hiredate,getdate())>10 --17 、显示员工的详细资料,按姓名排序 select * from emp order by ename --18 、显示员工的姓名和受雇日期,根据其服务年限,将最老的员工排在最前面 select ename,hiredate from emp order by hiredate --19 、显示所有员工的姓名、工作和薪金,按工作的降序排序,若工作相同则按薪金排序 select ename,job,sal from emp order by job desc,sal --20 、显示所有员工的姓名、加入公司的年份和月份,按受雇日期所在月排序 , 若月份相同 则将最早年份的员工排在最前面 select ename,datepart(year,hiredate) y,datepart(month,hiredate) m from emp order by m,y --21 、列出至少有一个员工的所有部门 select count(*),deptno from emp group by deptno having count(*)>1 --22 、列出薪金比" SMITH"多的所有员工 select * from emp where sal>(select sal from emp where ename='smith') 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 293 | 436 --23 、列出所有员工的姓名及其直接上级的姓名 select e1.ename,e2.ename from emp e1,emp e2 where e1.mgr=e2.empno --24 、列出受雇日期晚于其直接上级的所有员工 select e1.ename,e1.hiredate,e2.ename,e2.hiredate from emp e1,emp e2 where e1.mgr=e2.empno and e1.hiredate>e2.hiredate --25 、列出部门名称和这些部门的员工信息,同时列出那些没有员工的部门。 select d.dname,e.ename,e.job from emp e right join dept d on e.deptno=d.deptno --26 、列出所有" clerk " ( 办事员 ) 的姓名及其部门名称 select e.ename,d.dname from emp e,dept d where e.deptno=d.deptno and job='clerk' --27 、列出最低薪金大于 1500 的各种工作。 select min(sal),job from emp group by job having min(sal)>1500 --28 、列出在部门" SALES"( 销售部 )工作的员工的姓名,假定不知道销售部的部门编号。 select ename,'sales' from emp where deptno=(select deptno from dept where dname='sales') --29 、列出薪金高于公司平均薪金的所有员工。 select * from emp where sal>(select avg(sal) from emp) --30 、列出与" SCOTT"从事相同工作的所有员工。 select * from emp where job=(select job from emp where ename='scott') --31 、列出薪金等于部门 30 中员工的薪金的所有员工的姓名和薪金 select ename,sal from emp where sal in(select sal from emp where deptno=30) --32 、列出薪金高于在部门 30 工作的所有员工的薪金的员工姓名和薪金 select ename,sal from emp where sal>(select max(sal) from emp where deptno=30) --33 、列出在每个部门工作的员工数量、平均工资和平均服务期限 select count(*)" 员 工 人 数 ",avg(sal)" 部 门 平 均 工 资 ",avg(datediff(year,hiredate,getdate()))" 部门平均服务期限 ",deptno from emp group by deptno --34 、列出所有员工的姓名、部门名称和工资 select e.ename,d.dname,e.sal from emp e,dept d where e.deptno=d.deptno --35 、列出从事同一种工作但属于不同部门的员工的一种组合。 select w1.ename,w1.job,w1.deptno,w2.ename,w2.job,w2.deptno from emp w1,emp w2 where w1.job=w2.job and w1.deptno<>w2.deptno 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 294 | 436 --36 、列出所有部门的详细信息和部门人数。 select d2.dname,d2.loc,isnull(d.c,0) from dept d2 left join (select count(*) c,deptno de from emp group by deptno) d on d2.deptno=d.de --37 、列出各种工作的最低工资 select min(sal),job from emp group by job --38 、列出 MANAGER( 经理 ) 的最低薪金 select min(sal) from emp where job='manager' --39 、列出所有员工的年工资,按年薪从低到高排序 select ename,(sal+isnull(comm,0))*12" 年工资 " from emp order by " 年工资 " ******************************************************************************* 项目开发 -- 流程 1、项目需求分析 -- 充分理解客户对项目的要求是什么;形成分析文档 2、设计阶段 -- 决定用什么技术、框架;操作系统;数据库;形成设计文档,开发队伍 3、编码阶段 -- 程序员编码 4、测试阶段 5、实施阶段 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 295 | 436 ******************************************************************************* 学生管理系统需求文档 1、功能说明 ( 使用 use case 图来说明 uml( 统一建模语言 )) uml( 统一建模语言 )有两款较好的开发工具来做建模 uml-->IBM-rational rose 2003 或 7.0 uml-->jude uml 可以做出这样几种图 1、use case 图-- 用例图 ( 可以清晰的描述该系统有什么角色和功能 ) 2、时序图 3、类图 2、设计界面 ( 原型开发 [ 先搞定界面,在写代码 ]) 3、设计数据库 学生表 (stus) 字段名 类型 备注 是否为空字段 字段默认值 stuId varchar(30) 学生 ID not null stuName nvarchar(50) 学生名字 not null stuSex nchar(1) 性别 not null default' 男' 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 296 | 436 stuAge int 年龄 not null default>1 stuJg nvarchar(20) 籍贯 not null stuDept nvarchar(30) 所在系 not null JTable 讲解 [JTable_test1.java] /** * JTable 的使用 */ import javax.swing.*; import java.util.*; import java.sql.*; import java.awt.*; import java.awt.event.*; public class JTable_Test1 extends JFrame{ // 定义组件 //rowData 用来存放行数据、 columnNames存放列名 Vector rowData,columnNames; JTable jt=null; JScrollPane jsp=null; public static void main(String[] args) { JTable_Test1 sms=new JTable_Test1(); } // 构造函数 public JTable_Test1(){ columnNames=new Vector<>(); // 设置列名 columnNames.add(" 学号 "); columnNames.add(" 名字 "); columnNames.add(" 性别 "); columnNames.add(" 年龄 "); columnNames.add(" 籍贯 "); columnNames.add(" 系别 "); rowData=new Vector<>(); //rowData 可以存放多行 Vector hang=new Vector<>(); hang.add("sp001"); hang.add(" 孙悟空 "); hang.add(" 男"); hang.add("500"); hang.add(" 花果山 "); hang.add(" 少林派 "); // 加入 rowData 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 297 | 436 rowData.add(hang); // 初始化 JTable jt=new JTable(rowData,columnNames); // 初始化 jsp JScrollPane jsp=new JScrollPane(jt); // 把 jsp 放入到 jframe this.add(jsp); this.setSize(400, 300); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setVisible(true); } } ------------------------------------------------------------------------------- JTable 与数据库的使用 [JTable_test2.java] /** * JTable 的使用,从 sql server 数据库中取数据 */ import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Vector; import javax.swing.JFrame; import javax.swing.JScrollPane; import javax.swing.JTable; public class JTable_Test2 extends JFrame{ // 定义组件 //rowData 用来存放行数据、 columnNames存放列名 Vector rowData,columnNames; JTable jt=null; JScrollPane jsp=null; // 定义操作数据库需要的组件 PreparedStatement ps=null; Connection ct=null; ResultSet rs=null; public static void main(String[] args) { new JTable_Test2(); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 298 | 436 } public JTable_Test2(){ columnNames=new Vector<>(); // 设置列名 columnNames.add(" 学号 "); columnNames.add(" 名字 "); columnNames.add(" 性别 "); columnNames.add(" 年龄 "); columnNames.add(" 籍贯 "); columnNames.add(" 系别 "); rowData=new Vector<>(); //rowData 可以存放多行 try { //1 、加载驱动 Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); //2 、得到连接 ct=DriverManager.getConnection("jdbc:sqlserver://127.0.0.1:1433;databaseNam e=stussystem;user=sa;password=sa;"); if(!ct.isClosed()){ System.out.println(" 数据库连接成功 "); }else{ System.out.println(" 数据库连接失败 "); } ps=ct.prepareStatement("select * from stu"); rs=ps.executeQuery(); while(rs.next()){ Vector hang=new Vector(); hang.add(rs.getString(1)); hang.add(rs.getString(2)); hang.add(rs.getString(3)); hang.add(rs.getInt(4)); hang.add(rs.getString(5)); hang.add(rs.getString(6)); // 加入 rowData rowData.add(hang); } } catch (Exception e) { e.printStackTrace(); }finally{ 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 299 | 436 try { if(rs!=null){ rs.close(); } if(ps!=null){ ps.close(); } if(ct!=null){ ct.close(); } } catch (SQLException e) { e.printStackTrace(); } } // 初始化 JTable jt=new JTable(rowData,columnNames); // 初始化 jsp JScrollPane jsp=new JScrollPane(jt); // 把 jsp 放入到 jframe this.add(jsp); this.setSize(400, 300); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setVisible(true); } } 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 300 | 436 Mini 学生管理系统 [JTable_Test3.java] 源码 /** * 完成一个 mini 版本的学生管理系统 (MODEL1模式 ) * 1 、查询任务 * 2 、添加功能 * 3 、使用的是 sql server2012 ,数据库驱动与连接与视频教程中的 sql server2000 连接 * 有所不同 */ package com.student1; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Vector; import javax.swing.*; import javax.swing.table.AbstractTableModel; 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 301 | 436 public class JTable_Test3 extends JFrame implements ActionListener{ // 定义组件 JPanel jp1,jp2; JLabel jl1; JButton jb1,jb2,jb3,jb4; JTable jt; JScrollPane jsp; JTextField jtf; StuModel sm; // 定义操作数据库需要的组件 PreparedStatement ps=null; Connection ct=null; ResultSet rs=null; public static void main(String[] args) { try { // 将当前窗体外观设置为所在操作系统的外观 UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (UnsupportedLookAndFeelException e) { e.printStackTrace(); } new JTable_Test3(); } // 构造函数 public JTable_Test3(){ jp1=new JPanel(); jtf=new JTextField(10); jb1=new JButton(" 查询 "); jb1.addActionListener(this); jl1=new JLabel(" 请输入名字 "); // 把各个空间加入列 jp1.add(jl1); jp1.add(jtf); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 302 | 436 jp1.add(jb1); jp2=new JPanel(); jb2=new JButton(" 添加 "); jb2.addActionListener(this); jb3=new JButton(" 修改 "); jb3.addActionListener(this); jb4=new JButton(" 删除 "); jb4.addActionListener(this); // 把各个按钮加入到 jp2 中 jp2.add(jb2); jp2.add(jb3); jp2.add(jb4); // 创建一个数据模型对象 sm=new StuModel(); // 初始化 JTable jt=new JTable(sm); // 初始化 jsp JScrollPane jsp=new JScrollPane(jt); // 把 jsp 放入到 jframe this.add(jsp); this.add(jp1,"North"); this.add(jp2,"South"); this.setSize(400, 300); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setVisible(true); } @Override public void actionPerformed(ActionEvent e) { if(e.getSource()==jb1){ // 因为把对表的数据封装到 StuModel 中,我们就可以比较简单的完成查询 String name=this.jtf.getText(); // 写一个 SQL语句 String sql="select * from stu where stuName='"+name+"'"; // 构建新的数据模型类,并更新 sm=new StuModel(sql); // 更新 JTable 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 303 | 436 jt.setModel(sm); } // 用户点击添加时 else if(e.getSource()==jb2){ StuAddDialog sa=new StuAddDialog(this, " 添加学生 ", true); // 重新再获得新的数据模型 // 构建新的数据模型类,并更新 sm=new StuModel(); // 更新 JTable jt.setModel(sm); } // 用户修改数据 else if(e.getSource()==jb3){ int rowNum=this.jt.getSelectedRow(); if(rowNum==-1){ // 提示 JOptionPane.showMessageDialog(this, " 请 选 择 一 行 ", " 提 示 ", JOptionPane.INFORMATION_MESSAGE); return; } // 显示修改对话框 new StuUpdDialog(this," 修改学生信息 ",true,sm,rowNum); // 更新数据模型 sm=new StuModel(); // 更新 JTable jt.setModel(sm); } // 用户点击删除时,删除一条选中的数据 else if(e.getSource()==jb4){ //1 、得到学生的 ID 号 //getSelectedRow 会返回用户点中的行 // 如果该用户一行都没有选择,就会返回 -1 int rowNum=this.jt.getSelectedRow(); if(rowNum==-1){ // 提示 JOptionPane.showMessageDialog(this, " 请 选 择 一 行 ", " 提 示 ", JOptionPane.INFORMATION_MESSAGE); return; } // 得到学生编号 String stuId=(String)sm.getValueAt(rowNum, 0); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 304 | 436 // 连接数据库,完成删除任务 try { //1 、加载驱动 Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); //2 、得到连接 ct=DriverManager.getConnection("jdbc:sqlserver://127.0.0.1:1433;databaseNam e=stussystem;user=sa;password=sa;"); ps=ct.prepareStatement("delete from stu where stuid=?"); ps.setString(1, stuId); ps.executeUpdate(); } catch (Exception e2) { e2.printStackTrace(); }finally{ try { if(rs!=null){ rs.close(); } if(ps!=null){ ps.close(); } if(ct!=null){ ct.close(); } } catch (SQLException e1) { e1.printStackTrace(); } } // 更新数据模型 sm=new StuModel(); // 更新 JTable jt.setModel(sm); } } } ******************************************************************************* [StuModel.java] 源码 /** * 这是一个 stu 表的模型 * 可以把对 student 表的各种操作封装到该模型中 */ package com.student1; 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 305 | 436 import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Vector; import javax.swing.table.AbstractTableModel; public class StuModel extends AbstractTableModel{ //rowData 用来存放行数据、 columnNames存放列名 Vector rowData,columnNames; // 定义操作数据库需要的组件 PreparedStatement ps=null; Connection ct=null; ResultSet rs=null; public void init(String sql){ if(sql==""||sql.equals(null)){ sql="select * from stu"; } // 中间 columnNames=new Vector<>(); // 设置列名 columnNames.add(" 学号 "); columnNames.add(" 名字 "); columnNames.add(" 性别 "); columnNames.add(" 年龄 "); columnNames.add(" 籍贯 "); columnNames.add(" 系别 "); rowData=new Vector<>(); //rowData 可以存放多行 try { //1 、加载驱动 Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); //2 、得到连接 ct=DriverManager.getConnection("jdbc:sqlserver://127.0.0.1:1433;databaseNam e=stussystem;user=sa;password=sa;"); ps=ct.prepareStatement(sql); rs=ps.executeQuery(); while(rs.next()){ 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 306 | 436 Vector hang=new Vector(); hang.add(rs.getString(1)); hang.add(rs.getString(2)); hang.add(rs.getString(3)); hang.add(rs.getInt(4)); hang.add(rs.getString(5)); hang.add(rs.getString(6)); // 加入 rowData rowData.add(hang); } } catch (Exception e) { e.printStackTrace(); }finally{ try { if(rs!=null){ rs.close(); } if(ps!=null){ ps.close(); } if(ct!=null){ ct.close(); } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } // 构造函数 , 用于初始我们的数据模型 public StuModel(String sql){ this.init(sql); } // 构造函数 public StuModel(){ this.init(""); } // 得到共有多少列 public int getColumnCount() { return this.columnNames.size(); } 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 307 | 436 public String getColumnName(int column) { return (String)this.columnNames.get(column); } // 得到共有多少行 public int getRowCount() { return this.rowData.size(); } // 得到某行某列的数据 public Object getValueAt(int rowIndex, int columnIndex) { return ((Vector)this.rowData.get(rowIndex)).get(columnIndex); } } ******************************************************************************* [StuAddDialog.java] 源码 /** * 添加数据 */ package com.student1; import java.awt.BorderLayout; import java.awt.Frame; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTextField; public class StuAddDialog extends JDialog implements ActionListener{ // 定义我需要的 swing 组件 JLabel jl1,jl2,jl3,jl4,jl5,jl6; 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 308 | 436 JButton jb1,jb2; JTextField jtf1,jtf2,jtf3,jtf4,jtf5,jtf6; JPanel jp1,jp2,jp3; //owner 它的父窗口 ;title 窗口名 ;model 指定是模态窗口,还是非模态 public StuAddDialog(Frame owner,String title,boolean modal){ super(owner,title,modal); // 调用父类构造方法,达到模式对话框效果 jl1=new JLabel(" 学号 "); jl2=new JLabel(" 名字 "); jl3=new JLabel(" 性别 "); jl4=new JLabel(" 年龄 "); jl5=new JLabel(" 籍贯 "); jl6=new JLabel(" 系别 "); jtf1=new JTextField(); jtf2=new JTextField(); jtf3=new JTextField(); jtf4=new JTextField(); jtf5=new JTextField(); jtf6=new JTextField(); jb1=new JButton(" 添加 "); jb2=new JButton(" 取消 "); jp1=new JPanel(); jp2=new JPanel(); jp3=new JPanel(); // 设置布局 jp1.setLayout(new GridLayout(6,1)); jp2.setLayout(new GridLayout(6,1)); // 添加组件 jp1.add(jl1); jp1.add(jl2); jp1.add(jl3); jp1.add(jl4); jp1.add(jl5); jp1.add(jl6); jp2.add(jtf1); jp2.add(jtf2); jp2.add(jtf3); jp2.add(jtf4); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 309 | 436 jp2.add(jtf5); jp2.add(jtf6); jp3.add(jb1); jp3.add(jb2); this.add(jp1,BorderLayout.WEST); this.add(jp2,BorderLayout.CENTER); this.add(jp3,BorderLayout.SOUTH); jb1.addActionListener(this); jb2.addActionListener(this); // 展现 this.setSize(300, 250); this.setVisible(true); } @Override public void actionPerformed(ActionEvent e) { // 用户点击添加按钮后的响应动作 if(e.getSource()==jb1){ // 连接数据库 Connection ct=null; Statement stmt=null; ResultSet rs=null; PreparedStatement ps=null; // 连接数据库 try { //1 、加载驱动 Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); //2 、得到连接 ct=DriverManager.getConnection("jdbc:sqlserver://127.0.0.1:1433;databaseNam e=stussystem;user=sa;password=sa;"); String strsql="insert into stu values(?,?,?,?,?,?)"; ps=ct.prepareStatement(strsql); ps.setString(1,jtf1.getText()); ps.setString(2,jtf2.getText()); ps.setString(3,jtf3.getText()); ps.setInt(4,Integer.parseInt(jtf4.getText())); ps.setString(5,jtf5.getText()); ps.setString(6,jtf6.getText()); ps.executeUpdate(); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 310 | 436 this.dispose(); } catch (Exception e2) { e2.printStackTrace(); }finally{ try { if(ps!=null){ ps.close(); } if(ct!=null){ ct.close(); } } catch (SQLException e1) { e1.printStackTrace(); } } } else if(e.getSource()==jb2){ this.dispose(); } } } ******************************************************************************* [StuUpdDialog.java] 源码 /** * 修改学生信息 */ package com.student1; import java.awt.BorderLayout; import java.awt.Frame; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JPanel; 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 311 | 436 import javax.swing.JTextField; public class StuUpdDialog extends JDialog implements ActionListener{ // 定义我需要的 swing 组件 JLabel jl1,jl2,jl3,jl4,jl5,jl6; JButton jb1,jb2; JTextField jtf1,jtf2,jtf3,jtf4,jtf5,jtf6; JPanel jp1,jp2,jp3; //owner 它的父窗口 ;title 窗口名 ;model 指定是模态窗口,还是非模态 public StuUpdDialog(Frame owner,String title,boolean modal,StuModel sm,int rowNum){ super(owner,title,modal); // 调用父类构造方法,达到模式对话框效果 jl1=new JLabel(" 学号 "); jl2=new JLabel(" 名字 "); jl3=new JLabel(" 性别 "); jl4=new JLabel(" 年龄 "); jl5=new JLabel(" 籍贯 "); jl6=new JLabel(" 系别 "); jtf1=new JTextField(); // 初始化数据 jtf1.setText((String)sm.getValueAt(rowNum, 0)); // 让 jtf1 不能修改 jtf1.setEditable(false); jtf2=new JTextField(); jtf2.setText((String)sm.getValueAt(rowNum, 1)); jtf3=new JTextField(); jtf3.setText((String)sm.getValueAt(rowNum, 2)); jtf4=new JTextField(); jtf4.setText(sm.getValueAt(rowNum, 3).toString()); jtf5=new JTextField(); jtf5.setText((String)sm.getValueAt(rowNum, 4)); jtf6=new JTextField(); jtf6.setText((String)sm.getValueAt(rowNum, 5)); jb1=new JButton(" 修改 "); jb2=new JButton(" 取消 "); jp1=new JPanel(); jp2=new JPanel(); jp3=new JPanel(); // 设置布局 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 312 | 436 jp1.setLayout(new GridLayout(6,1)); jp2.setLayout(new GridLayout(6,1)); // 添加组件 jp1.add(jl1); jp1.add(jl2); jp1.add(jl3); jp1.add(jl4); jp1.add(jl5); jp1.add(jl6); jp2.add(jtf1); jp2.add(jtf2); jp2.add(jtf3); jp2.add(jtf4); jp2.add(jtf5); jp2.add(jtf6); jp3.add(jb1); jp3.add(jb2); this.add(jp1,BorderLayout.WEST); this.add(jp2,BorderLayout.CENTER); this.add(jp3,BorderLayout.SOUTH); jb1.addActionListener(this); jb2.addActionListener(this); // 展现 this.setSize(300, 250); this.setVisible(true); } public void actionPerformed(ActionEvent e) { // 用户点击添加按钮后的响应动作 if(e.getSource()==jb1){ // 连接数据库 Connection ct=null; Statement stmt=null; ResultSet rs=null; PreparedStatement ps=null; // 连接数据库 try { //1 、加载驱动 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 313 | 436 Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); //2 、得到连接 ct=DriverManager.getConnection("jdbc:sqlserver://127.0.0.1:1433;databaseNam e=stussystem;user=sa;password=sa;"); String strsql="update stu set stuName=?,stuSex=?,stuAge=?,stuJg=?,stuDept=? where stuId=?"; ps=ct.prepareStatement(strsql); ps.setString(1,jtf2.getText()); ps.setString(2,jtf3.getText()); ps.setInt(3,Integer.parseInt(jtf4.getText())); ps.setString(4,jtf5.getText()); ps.setString(5,jtf6.getText()); ps.setString(6, jtf1.getText()); ps.executeUpdate(); this.dispose(); } catch (Exception e2) { e2.printStackTrace(); }finally{ try { if(ps!=null){ ps.close(); } if(ct!=null){ ct.close(); } } catch (SQLException e1) { e1.printStackTrace(); } } } else if(e.getSource()==jb2){ this.dispose(); } } } 2、Mini 学生管理系统 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 314 | 436 [JTable_Test3.java] 源码 /** * 完成一个 mini 版本的学生管理系统 (MODEL2模式 ) * 1 、查询任务 * 2 、添加功能 */ package com.student2; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Vector; import javax.swing.*; import javax.swing.table.AbstractTableModel; public class JTable_Test3 extends JFrame implements ActionListener{ // 定义组件 JPanel jp1,jp2; JLabel jl1; 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 315 | 436 JButton jb1,jb2,jb3,jb4; JTable jt; JScrollPane jsp; JTextField jtf; StuModel sm; public static void main(String[] args) { try { // 将当前窗体外观设置为所在操作系统的外观 UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (UnsupportedLookAndFeelException e) { e.printStackTrace(); } new JTable_Test3(); } // 构造函数 public JTable_Test3(){ jp1=new JPanel(); jtf=new JTextField(10); jb1=new JButton(" 查询 "); jb1.addActionListener(this); jl1=new JLabel(" 请输入名字 "); // 把各个空间加入列 jp1.add(jl1); jp1.add(jtf); jp1.add(jb1); jp2=new JPanel(); jb2=new JButton(" 添加 "); jb2.addActionListener(this); jb3=new JButton(" 修改 "); jb3.addActionListener(this); jb4=new JButton(" 删除 "); jb4.addActionListener(this); // 把各个按钮加入到 jp2 中 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 316 | 436 jp2.add(jb2); jp2.add(jb3); jp2.add(jb4); // 创建一个数据模型对象 sm=new StuModel(); // 初始化 JTable jt=new JTable(sm); // 初始化 jsp JScrollPane jsp=new JScrollPane(jt); // 把 jsp 放入到 jframe this.add(jsp); this.add(jp1,"North"); this.add(jp2,"South"); this.setSize(400, 300); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setVisible(true); } public void actionPerformed(ActionEvent e) { if(e.getSource()==jb1){ // 因为把对表的数据封装到 StuModel 中,我们就可以比较简单的完成查询 String name=this.jtf.getText(); // 写一个 SQL语句 String sql="select * from stu where stuName='"+name+"'"; // 构建新的数据模型类,并更新 sm=new StuModel(sql); // 更新 JTable jt.setModel(sm); } // 用户点击添加时 else if(e.getSource()==jb2){ StuAddDialog sa=new StuAddDialog(this, " 添加学生 ", true); // 重新再获得新的数据模型 // 构建新的数据模型类,并更新 sm=new StuModel(); // 更新 JTable jt.setModel(sm); } // 用户修改数据 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 317 | 436 else if(e.getSource()==jb3){ int rowNum=this.jt.getSelectedRow(); if(rowNum==-1){ // 提示 JOptionPane.showMessageDialog(this, " 请 选 择 一 行 ", " 提 示 ", JOptionPane.INFORMATION_MESSAGE); return; } // 显示修改对话框 new StuUpdDialog(this," 修改学生信息 ",true,sm,rowNum); // 更新数据模型 sm=new StuModel(); // 更新 JTable jt.setModel(sm); } // 用户点击删除时,删除一条选中的数据 else if(e.getSource()==jb4){ //1 、得到学生的 ID 号 //getSelectedRow 会返回用户点中的行 // 如果该用户一行都没有选择,就会返回 -1 int rowNum=this.jt.getSelectedRow(); if(rowNum==-1){ // 提示 JOptionPane.showMessageDialog(this, " 请 选 择 一 行 ", " 提 示 ", JOptionPane.INFORMATION_MESSAGE); return; } // 得到学生编号 String stuId=(String)sm.getValueAt(rowNum, 0); // 创建一个 sql 语句 String sql="delete from stu where stuid=?"; String []paras={stuId}; StuModel temp=new StuModel(); if(temp.updStu(sql, paras)){ JOptionPane.showMessageDialog(this," 删除数据成功 "," 删除数据提示 ",JOptionPane.INFORMATION_MESSAGE); }else{ JOptionPane.showMessageDialog(this," 删除数据失败 "," 删除数据提示 ",JOptionPane.ERROR_MESSAGE); } 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 318 | 436 // 更新数据模型 sm=new StuModel(); // 更新 JTable jt.setModel(sm); } } } ******************************************************************************* [StuModel.java] 源码 /** * 这是一个 stu 表的模型 * 可以把对 student 表的各种操作封装到该模型中 */ package com.student2; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Vector; import javax.swing.JOptionPane; import javax.swing.table.AbstractTableModel; public class StuModel extends AbstractTableModel{ //rowData 用来存放行数据、 columnNames存放列名 Vector rowData,columnNames; // 定义操作数据库需要的组件 PreparedStatement ps=null; Connection ct=null; ResultSet rs=null; String sqlDriver="com.microsoft.sqlserver.jdbc.SQLServerDriver"; String url="jdbc:sqlserver://127.0.0.1:1433;databaseName=stussystem;user=sa;password=s a;"; // 添加学生 ( 增、删、改 ) public boolean updStu(String sql,String []paras){ boolean b=true; try { //1 、加载驱动 Class.forName(sqlDriver); //2 、得到连接 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 319 | 436 ct=DriverManager.getConnection(url); //3 、创建 ps ps=ct.prepareStatement(sql); // 给 ps 的问号赋值 for(int i=0;i<>(); // 设置列名 columnNames.add(" 学号 "); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 320 | 436 columnNames.add(" 名字 "); columnNames.add(" 性别 "); columnNames.add(" 年龄 "); columnNames.add(" 籍贯 "); columnNames.add(" 系别 "); rowData=new Vector<>(); //rowData 可以存放多行 try { //1 、加载驱动 Class.forName(sqlDriver); //2 、得到连接 ct=DriverManager.getConnection(url); ps=ct.prepareStatement(sql); rs=ps.executeQuery(); while(rs.next()){ Vector hang=new Vector(); hang.add(rs.getString(1)); hang.add(rs.getString(2)); hang.add(rs.getString(3)); hang.add(rs.getInt(4)); hang.add(rs.getString(5)); hang.add(rs.getString(6)); // 加入 rowData rowData.add(hang); } } catch (Exception e) { e.printStackTrace(); }finally{ try { if(rs!=null){ rs.close(); } if(ps!=null){ ps.close(); } if(ct!=null){ ct.close(); } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 321 | 436 } } } // 构造函数 , 用于初始我们的数据模型 public StuModel(String sql){ this.init(sql); } // 构造函数 public StuModel(){ this.init(""); } // 得到共有多少列 public int getColumnCount() { return this.columnNames.size(); } public String getColumnName(int column) { return (String)this.columnNames.get(column); } // 得到共有多少行 public int getRowCount() { return this.rowData.size(); } // 得到某行某列的数据 public Object getValueAt(int rowIndex, int columnIndex) { return ((Vector)this.rowData.get(rowIndex)).get(columnIndex); } } ******************************************************************************* [StuAddDialog.java] 源码 /** * 添加数据 */ package com.student2; import java.awt.BorderLayout; import java.awt.Frame; import java.awt.GridLayout; 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 322 | 436 import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTextField; public class StuAddDialog extends JDialog implements ActionListener{ // 定义我需要的 swing 组件 JLabel jl1,jl2,jl3,jl4,jl5,jl6; JButton jb1,jb2; JTextField jtf1,jtf2,jtf3,jtf4,jtf5,jtf6; JPanel jp1,jp2,jp3; //owner 它的父窗口 ;title 窗口名 ;model 指定是模态窗口,还是非模态 public StuAddDialog(Frame owner,String title,boolean modal){ super(owner,title,modal); // 调用父类构造方法,达到模式对话框效果 jl1=new JLabel(" 学号 "); jl2=new JLabel(" 名字 "); jl3=new JLabel(" 性别 "); jl4=new JLabel(" 年龄 "); jl5=new JLabel(" 籍贯 "); jl6=new JLabel(" 系别 "); jtf1=new JTextField(); jtf2=new JTextField(); jtf3=new JTextField(); jtf4=new JTextField(); jtf5=new JTextField(); jtf6=new JTextField(); jb1=new JButton(" 添加 "); jb2=new JButton(" 取消 "); jp1=new JPanel(); jp2=new JPanel(); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 323 | 436 jp3=new JPanel(); // 设置布局 jp1.setLayout(new GridLayout(6,1)); jp2.setLayout(new GridLayout(6,1)); // 添加组件 jp1.add(jl1); jp1.add(jl2); jp1.add(jl3); jp1.add(jl4); jp1.add(jl5); jp1.add(jl6); jp2.add(jtf1); jp2.add(jtf2); jp2.add(jtf3); jp2.add(jtf4); jp2.add(jtf5); jp2.add(jtf6); jp3.add(jb1); jp3.add(jb2); this.add(jp1,BorderLayout.WEST); this.add(jp2,BorderLayout.CENTER); this.add(jp3,BorderLayout.SOUTH); jb1.addActionListener(this); jb2.addActionListener(this); // 展现 this.setSize(300, 250); this.setVisible(true); } public void actionPerformed(ActionEvent e) { // 用户点击添加按钮后的响应动作 if(e.getSource()==jb1){ StuModel temp=new StuModel(); String sql="insert into stu values(?,?,?,?,?,?)"; String []paras={jtf1.getText(),jtf2.getText(),jtf3.getText(),jtf4.getText(),jtf5.getTe xt(),jtf6.getText()}; if(!temp.updStu(sql, paras)){ 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 324 | 436 JOptionPane.showMessageDialog(this, " 添加数据失败 ", " 添加数据提 示", JOptionPane.ERROR_MESSAGE); }else{ JOptionPane.showMessageDialog(this," 添加数据成功 "," 添加数据提示 ",JOptionPane.INFORMATION_MESSAGE); } // 关闭对话框 this.dispose(); } else if(e.getSource()==jb2){ this.dispose(); } } } ******************************************************************************* [StuUpdDialog.java] 源码 /** * 修改学生信息 */ package com.student2; import java.awt.BorderLayout; import java.awt.Frame; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTextField; public class StuUpdDialog extends JDialog implements ActionListener{ // 定义我需要的 swing 组件 JLabel jl1,jl2,jl3,jl4,jl5,jl6; JButton jb1,jb2; 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 325 | 436 JTextField jtf1,jtf2,jtf3,jtf4,jtf5,jtf6; JPanel jp1,jp2,jp3; //owner 它的父窗口 ;title 窗口名 ;model 指定是模态窗口,还是非模态 public StuUpdDialog(Frame owner,String title,boolean modal,StuModel sm,int rowNum){ super(owner,title,modal); // 调用父类构造方法,达到模式对话框效果 jl1=new JLabel(" 学号 "); jl2=new JLabel(" 名字 "); jl3=new JLabel(" 性别 "); jl4=new JLabel(" 年龄 "); jl5=new JLabel(" 籍贯 "); jl6=new JLabel(" 系别 "); jtf1=new JTextField(); // 初始化数据 jtf1.setText((String)sm.getValueAt(rowNum, 0)); // 让 jtf1 不能修改 jtf1.setEditable(false); jtf2=new JTextField(); jtf2.setText((String)sm.getValueAt(rowNum, 1)); jtf3=new JTextField(); jtf3.setText((String)sm.getValueAt(rowNum, 2)); jtf4=new JTextField(); jtf4.setText(sm.getValueAt(rowNum, 3).toString()); jtf5=new JTextField(); jtf5.setText((String)sm.getValueAt(rowNum, 4)); jtf6=new JTextField(); jtf6.setText((String)sm.getValueAt(rowNum, 5)); jb1=new JButton(" 修改 "); jb2=new JButton(" 取消 "); jp1=new JPanel(); jp2=new JPanel(); jp3=new JPanel(); // 设置布局 jp1.setLayout(new GridLayout(6,1)); jp2.setLayout(new GridLayout(6,1)); // 添加组件 jp1.add(jl1); jp1.add(jl2); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 326 | 436 jp1.add(jl3); jp1.add(jl4); jp1.add(jl5); jp1.add(jl6); jp2.add(jtf1); jp2.add(jtf2); jp2.add(jtf3); jp2.add(jtf4); jp2.add(jtf5); jp2.add(jtf6); jp3.add(jb1); jp3.add(jb2); this.add(jp1,BorderLayout.WEST); this.add(jp2,BorderLayout.CENTER); this.add(jp3,BorderLayout.SOUTH); jb1.addActionListener(this); jb2.addActionListener(this); // 展现 this.setSize(300, 250); this.setVisible(true); } @Override public void actionPerformed(ActionEvent e) { // 用户点击添加按钮后的响应动作 if(e.getSource()==jb1){ // 做一个 sql 语句 String sql="update stu set stuName=?,stuSex=?,stuAge=?,stuJg=?,stuDept=? where stuId=?"; String []paras={jtf2.getText(),jtf3.getText(),jtf4.getText(),jtf5.getText(),jtf6.getTe xt(),jtf1.getText()}; StuModel temp=new StuModel(); if(temp.updStu(sql, paras)){ JOptionPane.showMessageDialog(this," 修改数据成功 "," 修改数据提示 ",JOptionPane.INFORMATION_MESSAGE); }else{ JOptionPane.showMessageDialog(this," 修改数据失败 "," 修改数据提示 ",JOptionPane.ERROR_MESSAGE); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 327 | 436 } this.dispose(); } else if(e.getSource()==jb2){ this.dispose(); } } } ******************************************************************************* 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 328 | 436 3、Mini 学生管理系统 [JTable_Test3.java] 源码 /** * 完成一个 mini 版本的学生管理系统 (MODEL2-2模式 ) * 1 、查询任务 * 2 、添加功能 */ package com.student3; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Vector; import javax.swing.*; import javax.swing.table.AbstractTableModel; 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 329 | 436 public class JTable_Test3 extends JFrame implements ActionListener{ // 定义组件 JPanel jp1,jp2; JLabel jl1; JButton jb1,jb2,jb3,jb4; JTable jt; JScrollPane jsp; JTextField jtf; StuModel sm; public static void main(String[] args) { try { // 将当前窗体外观设置为所在操作系统的外观 UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (UnsupportedLookAndFeelException e) { e.printStackTrace(); } new JTable_Test3(); } // 构造函数 public JTable_Test3(){ jp1=new JPanel(); jtf=new JTextField(10); jb1=new JButton(" 查询 "); jb1.addActionListener(this); jl1=new JLabel(" 请输入名字 "); // 把各个空间加入列 jp1.add(jl1); jp1.add(jtf); jp1.add(jb1); jp2=new JPanel(); jb2=new JButton(" 添加 "); jb2.addActionListener(this); jb3=new JButton(" 修改 "); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 330 | 436 jb3.addActionListener(this); jb4=new JButton(" 删除 "); jb4.addActionListener(this); // 把各个按钮加入到 jp2 中 jp2.add(jb2); jp2.add(jb3); jp2.add(jb4); // 创建一个数据模型对象 sm=new StuModel(); String []paras={"1"}; sm.queryStu("select * from stu where 1=?", paras); // 初始化 JTable jt=new JTable(sm); // 初始化 jsp JScrollPane jsp=new JScrollPane(jt); // 把 jsp 放入到 jframe this.add(jsp); this.add(jp1,"North"); this.add(jp2,"South"); this.setSize(400, 300); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setVisible(true); } @Override public void actionPerformed(ActionEvent e) { if(e.getSource()==jb1){ // 因为把对表的数据封装到 StuModel 中,我们就可以比较简单的完成查询 String name=this.jtf.getText(); // 写一个 SQL语句 String sql="select * from stu where stuName=?"; String []paras={name}; // 构建新的数据模型类,并更新 sm=new StuModel(); sm.queryStu(sql, paras); // 更新 JTable jt.setModel(sm); } // 用户点击添加时 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 331 | 436 else if(e.getSource()==jb2){ StuAddDialog sa=new StuAddDialog(this, " 添加学生 ", true); // 重新再获得新的数据模型 // 构建新的数据模型类,并更新 sm=new StuModel(); String []paras2={"1"}; sm.queryStu("select * from stu where 1=?", paras2); // 更新 JTable jt.setModel(sm); } // 用户修改数据 else if(e.getSource()==jb3){ int rowNum=this.jt.getSelectedRow(); if(rowNum==-1){ // 提示 JOptionPane.showMessageDialog(this, " 请 选 择 一 行 ", " 提 示 ", JOptionPane.INFORMATION_MESSAGE); return; } // 显示修改对话框 new StuUpdDialog(this," 修改学生信息 ",true,sm,rowNum); // 更新数据模型 sm=new StuModel(); String []paras2={"1"}; sm.queryStu("select * from stu where 1=?", paras2); // 更新 JTable jt.setModel(sm); } // 用户点击删除时,删除一条选中的数据 else if(e.getSource()==jb4){ //1 、得到学生的 ID 号 //getSelectedRow 会返回用户点中的行 // 如果该用户一行都没有选择,就会返回 -1 int rowNum=this.jt.getSelectedRow(); if(rowNum==-1){ // 提示 JOptionPane.showMessageDialog(this, " 请 选 择 一 行 ", " 提 示 ", JOptionPane.INFORMATION_MESSAGE); return; } // 得到学生编号 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 332 | 436 String stuId=(String)sm.getValueAt(rowNum, 0); // 创建一个 sql 语句 String sql="delete from stu where stuid=?"; String []paras={stuId}; StuModel temp=new StuModel(); if(temp.updStu(sql, paras)){ JOptionPane.showMessageDialog(this," 删除数据成功 "," 删除数据提示 ",JOptionPane.INFORMATION_MESSAGE); }else{ JOptionPane.showMessageDialog(this," 删除数据失败 "," 删除数据提示 ",JOptionPane.ERROR_MESSAGE); } // 更新数据模型 sm=new StuModel(); String []paras2={"1"}; sm.queryStu("select * from stu where 1=?", paras2); // 更新 JTable jt.setModel(sm); } } } ******************************************************************************* [StuModel.java] 源码 /** * 这是一个 stu 表的模型 * 可以把对 student 表的各种操作封装到该模型中 */ package com.student3; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Vector; import javax.swing.JOptionPane; import javax.swing.table.AbstractTableModel; public class StuModel extends AbstractTableModel{ //rowData 用来存放行数据、 columnNames存放列名 Vector rowData,columnNames; 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 333 | 436 // 添加学生 ( 增、删、改 ) public boolean updStu(String sql,String []paras){ // 创建 SqlHelper( 如果程序并发性不考虑 , 可以把 SqlHelper 做成 static) SqlHelper sqlHelper=new SqlHelper(); return sqlHelper.updExecute(sql, paras); } // 查询的本质就是用来初始化 public void queryStu(String sql,String []paras){ SqlHelper sqlHelper=null; // 中间 columnNames=new Vector<>(); // 设置列名 columnNames.add(" 学号 "); columnNames.add(" 名字 "); columnNames.add(" 性别 "); columnNames.add(" 年龄 "); columnNames.add(" 籍贯 "); columnNames.add(" 系别 "); rowData=new Vector<>(); //rowData 可以存放多行 try { sqlHelper=new SqlHelper(); ResultSet rs=sqlHelper.queryExectue(sql, paras); while(rs.next()){ Vector hang=new Vector(); hang.add(rs.getString(1)); hang.add(rs.getString(2)); hang.add(rs.getString(3)); hang.add(rs.getInt(4)); hang.add(rs.getString(5)); hang.add(rs.getString(6)); // 加入 rowData rowData.add(hang); } } catch (Exception e) { e.printStackTrace(); }finally{ sqlHelper.close(); } } 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 334 | 436 // 得到共有多少列 public int getColumnCount() { return this.columnNames.size(); } @Override public String getColumnName(int column) { return (String)this.columnNames.get(column); } // 得到共有多少行 public int getRowCount() { return this.rowData.size(); } // 得到某行某列的数据 public Object getValueAt(int rowIndex, int columnIndex) { return ((Vector)this.rowData.get(rowIndex)).get(columnIndex); } } ******************************************************************************* [SqlHelper.java] 源码 /** * 这是一个对数据库进行操作的类 (SqlHelper) */ package com.student3; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import javax.swing.JOptionPane; public class SqlHelper { // 定义操作数据库需要的组件 PreparedStatement ps=null; Connection ct=null; ResultSet rs=null; String sqlDriver="com.microsoft.sqlserver.jdbc.SQLServerDriver"; String url="jdbc:sqlserver://127.0.0.1:1433;databaseName=stussystem;user=sa;password=s a;"; 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 335 | 436 public SqlHelper(){ try { //1 、加载驱动 Class.forName(sqlDriver); //2 、得到连接 ct=DriverManager.getConnection(url); } catch (Exception e) { e.printStackTrace(); } } // 关闭数据库资源 public void close(){ try { if(rs!=null){ rs.close(); } if(ps!=null){ ps.close(); } if(ct!=null){ ct.close(); } } catch (SQLException e1) { e1.printStackTrace(); } } // 写一个不需要注入的方法 ( 由于数据量少,所以写了一个这个方法。一般都带有条件 的注入 ) public ResultSet queryExectue(String sql){ try { //3 、创建 ps ps=ct.prepareStatement(sql); rs=ps.executeQuery(); } catch (Exception e) { e.printStackTrace(); }finally{ // 关闭资源??? } return rs; } 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 336 | 436 // 对数据库的查询操作 public ResultSet queryExectue(String sql,String []paras){ try { //3 、创建 ps ps=ct.prepareStatement(sql); // 给 ps 的问号赋值 for(int i=0;i<= 380); repaint(); try { Thread.sleep(70); i++;// i=0 j = j - 6;// j=40 u = u + 10;// u=10 if (tt == 3) width = width - 20; // tt=0,width=180 if (i == 4) { tt++; if (ifok && x > 120 + k * 20) k++;// k=0 if (k >= gg.length - 1) ifok = false; x = x + 10; i = 0; j = 40; u = 10; dian++; if (dian > 3) dian = 0; } } catch (InterruptedException e) { e.printStackTrace(); } 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 365 | 436 } } public void paintComponent(Graphics g) { // super.paintComponent(g); Image image; image = Toolkit.getDefaultToolkit().getImage("image/index/index.jpg"); // 获得背景图片 g.drawImage(image, 0, 0, this.getWidth(), 200, this); int r = (int) (Math.random() * 255); int b = (int) (Math.random() * 255); int y = (int) (Math.random() * 255); g.setColor(new Color(253, 250, 250));// White g.fillRect(x, 210, 380 - x, 30); g.setColor(new Color(253, 250, 250)); // white if (i > 1) g.fillRect(x, 235 - (j + 20) / 2, 10, j + 10); // 领头的长方块儿 if (j > 25) g.setColor(new Color(r, b, y)); else g.setColor(new Color(123, 194, 252)); // light blue g.fillRect(x, 235 - (j + 20) / 2, 10, j); // 后面跟着的短方块儿 ,10 代表闪 动条的宽度, j 代表闪动条的高度 g.setColor(new Color(123, 194, 252)); // light blue g.drawRect(10, 210, 380, 30); if (x < 120) { for (int l = 0; l < gg.length; l++) { g.setColor(new Color(0, 0, 0)); g.drawString(gg[l], 120 + l * 20, 230); } for (int l = 0; l < dian; l++) { g.setColor(new Color(0, 0, 0)); g.drawString("*", 300 + l * 10, 235); } g.drawString("*", 300 + dian * 10, 235); } else { // 设置写字的颜色和位置 g.setColor(new Color(23, 23, 230)); g.drawString(gg[k], 120 + k * 20, 230); for (int l = k + 1; l < gg.length; l++) { 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 366 | 436 g.setColor(new Color(0, 0, 0)); g.drawString(gg[l], 120 + l * 20, 230); } if (x > 300 + dian * 10) g.setColor(new Color(23, 23, 230)); for (int l = 0; l < dian; l++) { g.drawString("*", 300 + l * 10, 235); } g.drawString("*", 300 + dian * 10, 235); } // ------------ 逐字写诗 if (tt < 3) { for (int rr = 0; rr <= tt; rr++) { g.setColor(new Color(250, 0, 0)); g.drawString(shi[rr], 180, 60 + rr * 20); } g.drawString(shi[tt], 180, 60 + tt * 20); } if (tt >= 3 && tt < 8) { g.setColor(new Color(230, 0, 0)); for (int rr = 0; rr < 3; rr++) g.drawString(shi[rr], 180, 60 + rr * 20); g.setColor(new Color(r, b, y)); if (tt < 8) for (int rr = 3; rr <= tt; rr++) g.drawString(shi[rr], 150, rr * 20); if (tt >= 7) for (int rr = 3; rr < 8; rr++) g.drawString(shi[rr], 150, rr * 20); } if (tt >= 8 && tt < 13) { g.setColor(new Color(230, 0, 0)); for (int rr = 0; rr < 3; rr++) g.drawString(shi[rr], 180, 60 + rr * 20); for (int rr = 3; rr <= 7; rr++) g.drawString(shi[rr], 150, rr * 20); g.setColor(new Color(r, b, y)); if (tt < 13) for (int rr = 8; rr <= tt; rr++) g.drawString(shi[rr], 120, rr * 20 - 100); if (tt >= 13) for (int rr = 8; rr < 13; rr++) 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 367 | 436 g.drawString(shi[rr], 120, rr * 20 - 100); } if (tt >= 13 && tt < 18) { g.setColor(new Color(230, 0, 0)); for (int rr = 0; rr < 3; rr++) g.drawString(shi[rr], 180, 60 + rr * 20); for (int rr = 3; rr <= 7; rr++) g.drawString(shi[rr], 150, rr * 20); for (int rr = 8; rr < 13; rr++) g.drawString(shi[rr], 120, rr * 20 - 100); g.setColor(new Color(r, b, y)); if (tt < 18) for (int rr = 13; rr <= tt; rr++) g.drawString(shi[rr], 90, rr * 20 - 200); if (tt >= 18) for (int rr = 13; rr < 13; rr++) g.drawString(shi[rr], 90, rr * 20 - 200); } if (tt >= 18 && tt < 23) { g.setColor(new Color(230, 0, 0)); for (int rr = 0; rr < 3; rr++) g.drawString(shi[rr], 180, 60 + rr * 20); for (int rr = 3; rr <= 7; rr++) g.drawString(shi[rr], 150, rr * 20); for (int rr = 8; rr < 13; rr++) g.drawString(shi[rr], 120, rr * 20 - 100); for (int rr = 13; rr < 18; rr++) g.drawString(shi[rr], 90, rr * 20 - 200); g.setColor(new Color(r, b, y)); if (tt < 23) for (int rr = 18; rr <= tt; rr++) g.drawString(shi[rr], 60, rr * 20 - 300); if (tt >= 23) for (int rr = 18; rr < 23; rr++) g.drawString(shi[rr], 60, rr * 20 - 300); } if (tt >= 23 && tt < 30) { g.setColor(new Color(230, 0, 0)); for (int rr = 0; rr < 3; rr++) g.drawString(shi[rr], 180, 60 + rr * 20); for (int rr = 3; rr <= 7; rr++) g.drawString(shi[rr], 150, rr * 20); for (int rr = 8; rr < 13; rr++) g.drawString(shi[rr], 120, rr * 20 - 100); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 368 | 436 for (int rr = 13; rr < 18; rr++) g.drawString(shi[rr], 90, rr * 20 - 200); for (int rr = 18; rr < 23; rr++) g.drawString(shi[rr], 60, rr * 20 - 300); g.setColor(new Color(r, b, y)); if (tt < 30) for (int rr = 23; rr <= tt; rr++) g.drawString(shi[rr], 30, rr * 20 - 400); if (tt >= 30) { tt = 0; for (int rr = 18; rr < 23; rr++) g.drawString(shi[rr], 30, rr * 20 - 300); } } if (tt > 30) { g.setColor(new Color(230, 0, 0)); for (int rr = 0; rr < 3; rr++) g.drawString(shi[rr], 180, 60 + rr * 20); for (int rr = 3; rr <= 7; rr++) g.drawString(shi[rr], 150, rr * 20); for (int rr = 8; rr < 13; rr++) g.drawString(shi[rr], 120, rr * 20 - 100); for (int rr = 13; rr < 18; rr++) g.drawString(shi[rr], 90, rr * 20 - 200); for (int rr = 18; rr < 23; rr++) g.drawString(shi[rr], 60, rr * 20 - 300); for (int rr = 23; rr < 30; rr++) g.drawString(shi[rr], 30, rr * 20 - 400); } } } ******************************************************************************* [UserLogin.java] 登录界面源代码 /** * 用户登录界面 */ package com.mhl.view; import com.mhl.model.UserModel; import com.mhl.tools.*; import java.awt.Color; import java.awt.Container; import java.awt.Font; 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 369 | 436 import java.awt.GradientPaint; import java.awt.Graphics; import java.awt.Image; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPasswordField; import javax.swing.JTextField; public class UserLogin extends JDialog implements ActionListener{ // 定义 需要的组件 JLabel jl1,jl2,jl3; JTextField jName; JPasswordField jPasswd; JButton jConf,jCancel; public static void main(String []args){ UserLogin ul=new UserLogin(); } public UserLogin(){ // 把一个组件放入到 JFrame 或者 JDialog 可以直接放 // 也可以先放到 Container Container ct=this.getContentPane(); // 空布局 this.setLayout(null); // 创建各个组件 jl1=new JLabel(" 请输入用户名 :"); jl1.setBounds(60, 190, 150, 30); jl1.setFont(MyTools.f1); ct.add(jl1); jName=new JTextField(20); jName.setFocusable(true); jName.setBounds(180, 190, 120, 30); jName.setBorder(BorderFactory.createLoweredBevelBorder());// 下凹 ct.add(jName); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 370 | 436 jl2=new JLabel("( 或员工号 )"); jl2.setForeground(Color.red);// 前景色 jl2.setFont(MyTools.f2); jl2.setBounds(100, 210, 100, 30); ct.add(jl2); jl3=new JLabel(" 请输入密 码:"); jl3.setBounds(60, 240, 150, 30); jl3.setFont(MyTools.f1); ct.add(jl3); jPasswd=new JPasswordField(20); jPasswd.setBounds(180, 240, 120, 30); jPasswd.setBorder(BorderFactory.createLoweredBevelBorder()); ct.add(jPasswd); jConf=new JButton(" 确定 "); jConf.setFont(MyTools.f1); jConf.setBounds(110, 300, 70, 30); ct.add(jConf); jConf.addActionListener(this); jCancel=new JButton(" 取消 "); jCancel.setFont(MyTools.f1); jCancel.setBounds(210, 300, 70, 30); ct.add(jCancel); jCancel.addActionListener(this); // 创建一个 BackImage 对象 BackImage bi=new BackImage(); // 把位置确定 bi.setBounds(0, 0, 360, 360); // 不使用上下框 ct.add(bi); // this.add(bi); this.setUndecorated(true); this.setSize(360, 360); this.setLocationRelativeTo(null); this.setVisible(true); } // 内部类 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 371 | 436 class BackImage extends JPanel{ Image im; public BackImage(){ try { im=ImageIO.read(new File("image/index/login.gif")); } catch (IOException e) { e.printStackTrace(); } } public void paintComponent(Graphics g){ g.drawImage(im, 0, 0, 360, 360, this); } } // 响应用户登录的请求 public void actionPerformed(ActionEvent e) { if(e.getSource()==jConf){ // 取出员工号,密码 String u=this.jName.getText().trim(); String p=new String(this.jPasswd.getPassword()); UserModel um=new UserModel(); String res=um.checkUser(u, p); if(res.equals("SystemAd")||res.equals(" 经理 ")||res.equals(" 主管 ")){ new Windows1(); this.dispose(); }else{ JOptionPane.showMessageDialog(this, " 您无权限登录或用户名密 码错误 ", " 登录提示 ", JOptionPane.ERROR_MESSAGE); return; } } else if(e.getSource()==jCancel){ this.dispose(); System.exit(0); } } } ******************************************************************************* [Windows1.java] 主界面源代码 /** * 这是系统管理员、经理、主管可以进入的管理操作界面 * 完成界面的顺序,从上到下,从左到右 */ 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 372 | 436 package com.mhl.view; import com.mhl.tools.*; import java.awt.BorderLayout; import java.awt.CardLayout; import java.awt.Container; import java.awt.Cursor; import java.awt.GridLayout; import java.awt.Image; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.io.File; import java.io.IOException; import java.util.Calendar; import javax.imageio.ImageIO; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JSplitPane; import javax.swing.JToolBar; import javax.swing.Timer; public class Windows1 extends JFrame implements ActionListener,MouseListener{ // 定义需要的组件 Image titleIcon,timeBg; JMenuBar jmb; // 一级菜单 JMenu jm1,jm2,jm3,jm4,jm5,jm6; // 二级菜单 JMenuItem jmm1,jmm2,jmm3,jmm4,jmm5,jmm6,jmm7,jmm8,jmm9,jmm10,jmm11,jmm12; // 二级菜单图标 ImageIcon jmm1_Icon,jmm2_Icon,jmm3_Icon,jmm4_Icon,jmm5_Icon,jmm6_Icon,jmm7_Icon,jmm8_Icon ,jmm9_Icon,jmm10_Icon,jmm11_Icon,jmm12_Icon; // 工具栏 JToolBar jtb; 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 373 | 436 JButton jb1,jb2,jb3,jb4,jb5,jb6,jb7,jb8,jb9,jb10; // 定义需要的五个 JPanel JPanel p1,p2,p3,p4,p5; // 显示当前时间的 Label JLabel timeNow; JLabel p1_lab1,p1_lab2,p1_lab3,p1_lab4,p1_lab5,p1_lab6,p1_lab7,p1_lab8; // 给 p2 面板定义需要的 JLabel JLabel p2_lab1,p2_lab2; //javax.swing 包中的 Timer 可以定时的触发 Action 事件,我们可以利用它来完成一 些事情 Timer t; ImagePanel p1_imgPanel; JSplitPane jsp; // 卡片布局 CardLayout cardP2,cardP3; public static void main(String[] args) { new Windows1(); } // 初始化菜单 public void initMenu(){ // 创建图标 jmm1_Icon=new ImageIcon("image/Windows1/30/jb1.png"); jmm2_Icon=new ImageIcon("image/Windows1/30/jb2.png"); jmm3_Icon=new ImageIcon("image/Windows1/30/jb3.png"); jmm4_Icon=new ImageIcon("image/Windows1/30/jb4.png"); jmm5_Icon=new ImageIcon("image/Windows1/30/jb5.png"); jmm6_Icon=new ImageIcon("image/Windows1/30/jb6.png"); jmm7_Icon=new ImageIcon("image/Windows1/30/jb7.png"); jmm8_Icon=new ImageIcon("image/Windows1/30/jb8.png"); jmm9_Icon=new ImageIcon("image/Windows1/30/jb9.png"); jmm10_Icon=new ImageIcon("image/Windows1/30/jb10.png"); jmm11_Icon=new ImageIcon("image/Windows1/30/jb11.png"); jmm12_Icon=new ImageIcon("image/Windows1/30/jb12.png"); // 创建菜单栏 jmb=new JMenuBar(); // 创建一级菜单 jm1=new JMenu(" 系统管理 "); jm1.setFont(MyTools.f2); // 创建系统管理二级菜单 jmm1=new JMenuItem(" 切换用户 ", jmm1_Icon); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 374 | 436 jmm2=new JMenuItem(" 切换收款界面 ", jmm2_Icon); jmm3=new JMenuItem(" 登录管理 ", jmm3_Icon); jmm4=new JMenuItem(" 万年历 ", jmm4_Icon); jmm5=new JMenuItem(" 退出 ", jmm5_Icon); // 将二级菜单加入到一级菜单 jm1.add(jmm1); jm1.add(jmm2); jm1.addSeparator(); // 分割符 jm1.add(jmm3); jm1.addSeparator(); jm1.add(jmm4); jm1.addSeparator(); jm1.add(jmm5); jm2=new JMenu(" 人事管理 "); jm2.setFont(MyTools.f2); jmm6=new JMenuItem(" 人事登记 ", jmm6_Icon); jm2.add(jmm6); jm3=new JMenu(" 菜单服务 "); jm3.setFont(MyTools.f2); jmm7=new JMenuItem(" 菜谱及价格录入 ", jmm7_Icon); jm3.add(jmm7); jm4=new JMenu(" 报表统计 "); jm4.setFont(MyTools.f2); jmm8=new JMenuItem(" 报表统计 ", jmm8_Icon); jm4.add(jmm8); jm5=new JMenu(" 成本及库房 "); jm5.setFont(MyTools.f2); jmm9=new JMenuItem(" 成本控制 ", jmm9_Icon); jm5.add(jmm9); jm6=new JMenu(" 帮助 "); jm6.setFont(MyTools.f2); jmm10=new JMenuItem(" 动画帮助 ", jmm10_Icon); jmm11=new JMenuItem(" 文本帮助 ", jmm11_Icon); jmm12=new JMenuItem(" 关于 ", jmm12_Icon); jm6.add(jmm10); jm6.add(jmm11); jm6.add(jmm12); // 将一级菜单加入到菜单栏 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 375 | 436 jmb.add(jm1); jmb.add(jm2); jmb.add(jm3); jmb.add(jm4); jmb.add(jm5); jmb.add(jm6); // 将 jmb 菜单栏加入到 JFrame this.setJMenuBar(jmb); } // 初始化工具栏 public void initToolBar(){ // 处理工具栏的组件 jtb=new JToolBar(); // 设置工具栏 JToolBar 不浮动 jtb.setFloatable(false); jb1=new JButton(new ImageIcon("image/Windows1/20/jb1.png")); jb1.setToolTipText(" 切换用户 "); jb2=new JButton(new ImageIcon("image/Windows1/20/jb2.png")); jb2.setToolTipText(" 切换界面 "); jb3=new JButton(new ImageIcon("image/Windows1/20/jb3.png")); jb3.setToolTipText(" 登录管理 "); jb4=new JButton(new ImageIcon("image/Windows1/20/jb4.png")); jb4.setToolTipText(" 万年历 "); jb6=new JButton(new ImageIcon("image/Windows1/20/jb6.png")); jb6.setToolTipText(" 人事管理 "); jb7=new JButton(new ImageIcon("image/Windows1/20/jb7.png")); jb7.setToolTipText(" 菜谱及价格录入 "); jb8=new JButton(new ImageIcon("image/Windows1/20/jb8.png")); jb8.setToolTipText(" 报表统计 "); jb9=new JButton(new ImageIcon("image/Windows1/20/jb9.png")); jb9.setToolTipText(" 成本控制 "); jb10=new JButton(new ImageIcon("image/Windows1/20/jb11.png")); jb10.setToolTipText(" 帮助 "); jb5=new JButton(new ImageIcon("image/Windows1/20/jb5.png")); jb5.setToolTipText(" 退出系统 "); // 将按钮加入 JToolBar 中 jtb.add(jb1); jtb.add(jb2); jtb.add(jb3); jtb.add(jb4); jtb.add(jb6); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 376 | 436 jtb.add(jb7); jtb.add(jb8); jtb.add(jb9); jtb.add(jb10); jtb.add(jb5); } // 初始化中间的四个 Panel public void initAllPanels(){ // 处理 p1 面板 p1=new JPanel(new BorderLayout()); Image p1_bg=null; try { p1_bg = ImageIO.read(new File("image/Windows1/jp1_bg.jpg")); } catch (IOException e1) { e1.printStackTrace(); } // 定义手形光标 Cursor myCursor=new Cursor(Cursor.HAND_CURSOR); p1_imgPanel=new ImagePanel(p1_bg); p1_imgPanel.setLayout(new GridLayout(8,1)); // 网格布局 //p1 的第一个 Label p1_lab1=new JLabel(new ImageIcon("image/Windows1/p1_mhl.jpg")); p1_imgPanel.add(p1_lab1); // 加入第 2 个 Label p1_lab2=new JLabel(" 人 事 管 理 ",new ImageIcon("image/Windows1/30/jb6.png"),0); p1_lab3=new JLabel(" 登 录 管 理 ",new ImageIcon("image/Windows1/30/jb3.png"),0); p1_lab4=new JLabel(" 菜 谱 价 格 ",new ImageIcon("image/Windows1/30/jb7.png"),0); p1_lab5=new JLabel(" 报 表 统 计 ",new ImageIcon("image/Windows1/30/jb8.png"),0); p1_lab6=new JLabel(" 成 本 及 库 房 ",new ImageIcon("image/Windows1/30/jb9.png"),0); p1_lab7=new JLabel(" 系 统 设 置 ",new ImageIcon("image/Windows1/30/sys.png"),0); p1_lab8=new JLabel(" 动 画 帮 助 ",new ImageIcon("image/Windows1/30/jb11.png"),0); // 初始化 Label 为不可用 p1_lab2.setEnabled(false); p1_lab3.setEnabled(false); p1_lab4.setEnabled(false); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 377 | 436 p1_lab5.setEnabled(false); p1_lab6.setEnabled(false); p1_lab7.setEnabled(false); p1_lab8.setEnabled(false); // 鼠标移动到 JLabel 上变成手形提示 p1_lab1.setCursor(myCursor); p1_lab2.setCursor(myCursor); p1_lab3.setCursor(myCursor); p1_lab4.setCursor(myCursor); p1_lab5.setCursor(myCursor); p1_lab6.setCursor(myCursor); p1_lab7.setCursor(myCursor); p1_lab8.setCursor(myCursor); // 注册鼠标事件监听 p1_lab1.addMouseListener(this); p1_lab2.addMouseListener(this); p1_lab3.addMouseListener(this); p1_lab4.addMouseListener(this); p1_lab5.addMouseListener(this); p1_lab6.addMouseListener(this); p1_lab7.addMouseListener(this); p1_lab8.addMouseListener(this); // 将 label 加入到 p1_imgPanel 中 p1_imgPanel.add(p1_lab2); p1_imgPanel.add(p1_lab3); p1_imgPanel.add(p1_lab4); p1_imgPanel.add(p1_lab5); p1_imgPanel.add(p1_lab6); p1_imgPanel.add(p1_lab7); p1_imgPanel.add(p1_lab8); p1.add(p1_imgPanel); // 处理 p2,p3,p4 面板 p4=new JPanel(new BorderLayout()); // 边界布局 cardP2=new CardLayout(); p2=new JPanel(cardP2); // 卡片布局 p2_lab1=new JLabel(new ImageIcon("image/Windows1/jp2_left.jpg")); p2_lab2=new JLabel(new ImageIcon("image/Windows1/jp2_right.jpg")); // 监听 p2_lab1.addMouseListener(this); p2_lab2.addMouseListener(this); // 把 p2_lab1 加入到 p2 中 p2.add(p2_lab1,"0"); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 378 | 436 p2.add(p2_lab2,"1"); // 给 P3 创建卡片布局 cardP3=new CardLayout(); p3=new JPanel(cardP3); // 先给 p3 加入一个主界面的卡片 (ImagePanel) Image zhu_image=null; try { zhu_image = ImageIO.read(new File("image/Windows1/p3_bj.jpg")); } catch (IOException e1) { e1.printStackTrace(); } ImagePanel ip=new ImagePanel(zhu_image); p3.add(ip,"0"); // 对 p3 做添加几个 JLabel-- 测试,正式写要放 Panel 进去 // 创建 EmpInfo 对象 (JPanel) EmpInfo eInfo=new EmpInfo(); p3.add(eInfo,"1"); // 把显示报表的 JPanel 创建出来 Chart myChart=new Chart(); // p3.add(myChart,"4"); // 把 p2,p3 加入到 p4 p4.add(p2,"West"); p4.add(p3,"Center"); // 做一个拆分窗口 , 分别存放 p1 和 p4 jsp=new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,true,p1,p4); // 指定左边的面板占多大范围 jsp.setDividerLocation(120); // 把边界线设置为 0 jsp.setDividerSize(0); } // 构造函数 public Windows1(){ // 创建组件 try { titleIcon=ImageIO.read(new File("image/Windows1/jb.jpg")); } catch (IOException e) { e.printStackTrace(); } // 调用初始化菜单函数 this.initMenu(); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 379 | 436 // 调用初始化工具栏函数 this.initToolBar(); // 调用初始化中间的四个 Panel 函数 this.initAllPanels(); // 处理 p5 面板 p5=new JPanel(new BorderLayout()); // 创建 Timer t=new Timer(1000, this); // 每隔 1 秒触发 Action 事件 // 启动定时器 t.start(); timeNow=new JLabel(" 当 前 时 间 : "+Calendar.getInstance().getTime().toLocaleString()+" "); timeNow.setFont(MyTools.f2); try { timeBg=ImageIO.read(new File("image/Windows1/time_bg.jpg")); } catch (IOException e) { e.printStackTrace(); } ImagePanel ip1=new ImagePanel(timeBg); ip1.setLayout(new BorderLayout()); ip1.add(timeNow,"East"); p5.add(ip1); // 创建主容器 Container ct=this.getContentPane(); ct.add(jtb,"North"); ct.add(jsp,"Center"); ct.add(p5,"South"); // 设置大小 int w=Toolkit.getDefaultToolkit().getScreenSize().width; int h=Toolkit.getDefaultToolkit().getScreenSize().height; this.setSize(w, h-30); // 关闭窗口时,退出系统 this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 设置 titel 图标 this.setIconImage(titleIcon); this.setTitle(" 满汉楼餐饮管理系统 "); // 窗口打开最大化 this.setExtendedState(JFrame.MAXIMIZED_BOTH); this.setVisible(true); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 380 | 436 } @Override public void actionPerformed(ActionEvent e) { this.timeNow.setText(" 当 前 时 间 : "+Calendar.getInstance().getTime().toLocaleString()+" "); } // 鼠标点击事件 public void mouseClicked(MouseEvent e) { // 判断用户点击哪个操作 JLabel if(e.getSource()==p1_lab1){ cardP3.show(p3,"0"); }else if(e.getSource()==p1_lab2){ cardP3.show(p3,"1"); }else if(e.getSource()==p1_lab3){ cardP3.show(p3,"2"); }else if(e.getSource()==p1_lab4){ cardP3.show(p3,"3"); }else if(e.getSource()==p1_lab5){ cardP3.show(p3,"4"); }else if(e.getSource()==p1_lab6){ cardP3.show(p3,"5"); }else if(e.getSource()==p1_lab7){ cardP3.show(p3,"6"); }else if(e.getSource()==p1_lab8){ cardP3.show(p3,"7"); } //p2 左右伸缩功能 else if(e.getSource()==p2_lab1){ // 把显示各种操作的界面 P1 隐藏起来 cardP2.show(p2,"1"); jsp.setDividerLocation(0); }else if(e.getSource()==p2_lab2){ // 把显示各种操作的界面 P1 显示出来 cardP2.show(p2,"0"); jsp.setDividerLocation(120); } } // 鼠标按下事件 public void mousePressed(MouseEvent e) { // TODO Auto-generated method stub } 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 381 | 436 // 鼠标弹起事件 public void mouseReleased(MouseEvent e) { // TODO Auto-generated method stub } // 鼠标移动到事件 public void mouseEntered(MouseEvent e) { // 如果用户选中了某个操作 JLabel 则高亮提示 if(e.getSource()==p1_lab2){ p1_lab2.setEnabled(true); }else if(e.getSource()==p1_lab3){ p1_lab3.setEnabled(true); }else if(e.getSource()==p1_lab4){ p1_lab4.setEnabled(true); }else if(e.getSource()==p1_lab5){ p1_lab5.setEnabled(true); }else if(e.getSource()==p1_lab6){ p1_lab6.setEnabled(true); }else if(e.getSource()==p1_lab7){ p1_lab7.setEnabled(true); }else if(e.getSource()==p1_lab8){ p1_lab8.setEnabled(true); } } // 鼠标离开事件 public void mouseExited(MouseEvent e) { // 如果用户鼠标离开选中了某个操作 JLabel 则高亮关闭提示 if(e.getSource()==p1_lab2){ p1_lab2.setEnabled(false); }else if(e.getSource()==p1_lab3){ p1_lab3.setEnabled(false); }else if(e.getSource()==p1_lab4){ p1_lab4.setEnabled(false); }else if(e.getSource()==p1_lab5){ p1_lab5.setEnabled(false); }else if(e.getSource()==p1_lab6){ p1_lab6.setEnabled(false); }else if(e.getSource()==p1_lab7){ p1_lab7.setEnabled(false); }else if(e.getSource()==p1_lab8){ p1_lab8.setEnabled(false); } 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 382 | 436 } } ******************************************************************************* [EmpInfo.java] 人事资料界面源代码 /** * 这是用于显示人事管理的界面 */ package com.mhl.view; import java.awt.BorderLayout; import java.awt.Color; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextField; import com.mhl.model.EmpModel; public class EmpInfo extends JPanel implements ActionListener{ // 定义需要的各个组件 JPanel p1,p2,p3,p4,p5; JLabel p1_lab1,p3_lab1; JTextField p1_jtf1; JButton p1_jb1,p4_jb1,p4_jb2,p4_jb3,p4_jb4; // 这个是用于显示人事信息的 JTable jtable; JScrollPane jsp; EmpModel em; // 构造函数 public EmpInfo(){ // 创建需要的组件 //p1 面板 p1=new JPanel(new FlowLayout(FlowLayout.CENTER)); // 流布局居中显示 p1_lab1=new JLabel(" 请输入姓名 ( 员工号或职位 ):"); p1_jtf1=new JTextField(20); p1_jb1=new JButton(" 查询 "); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 383 | 436 // 把它们加入到 p1 p1.add(p1_lab1); p1.add(p1_jtf1); p1.add(p1_jb1); //p2 面板 em=new EmpModel(); String []paras={"1"}; em.query("select empid' 员工号 ',empname' 姓名 ',sex' 性别 ',zhiwei' 职位 ' from rszl where 1=?",paras); jtable=new JTable(em); jsp=new JScrollPane(jtable); p2=new JPanel(new BorderLayout()); // 边界布局 p2.add(jsp); // 处理 p3,p4,p5 面板 p3=new JPanel(new FlowLayout(FlowLayout.LEFT)); p3_lab1=new JLabel(" 共有 "+jtable.getRowCount()+" 条记录 "); p3.add(p3_lab1); p4=new JPanel(new FlowLayout(FlowLayout.RIGHT)); p4_jb1=new JButton(" 详细信息 "); p4_jb2=new JButton(" 添加 "); p4_jb3=new JButton(" 修改 "); p4_jb4=new JButton(" 删除 "); // 监听事件 p4_jb1.addActionListener(this); p4_jb2.addActionListener(this); p4_jb3.addActionListener(this); p4_jb4.addActionListener(this); // 将按钮添加到 p4 面板 p4.add(p4_jb1); p4.add(p4_jb2); p4.add(p4_jb3); p4.add(p4_jb4); p5=new JPanel(new BorderLayout()); p5.add(p3,"West"); p5.add(p4,"East"); // 把主面板设为 BorderLayout this.setLayout(new BorderLayout()); // 把 p1 加入到 JPanel 中 this.add(p1,"North"); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 384 | 436 this.add(p2,"Center"); this.add(p5,"South"); this.setVisible(true); } @Override public void actionPerformed(ActionEvent e) { // 如果用户要删除某个员工 if(e.getSource()==p4_jb1){ // 详细信息 }else if(e.getSource()==p4_jb2){ // 添加 }else if(e.getSource()==p4_jb3){ // 修改 }else if(e.getSource()==p4_jb4){ // 删除 int selRowNum=jtable.getSelectedRow(); // 选中的行 if(selRowNum!=1){ JOptionPane.showMessageDialog(null, " 请选中要删除的数据 "," 删除 提示 ",JOptionPane.INFORMATION_MESSAGE); } String empNo=(String)em.getValueAt(selRowNum, 0); if(em.delEmpById(empNo)){ JOptionPane.showMessageDialog(null, " 删 除 数据 成 功 "," 删 除 提示 ",JOptionPane.INFORMATION_MESSAGE); }else{ JOptionPane.showMessageDialog(null, " 删 除 数据 失 败 "," 删 除 提示 ",JOptionPane.ERROR_MESSAGE); } // 更新显示一下 em=new EmpModel(); String []paras={"1"}; em.query("select empid' 员工号 ',empname' 姓名 ',sex' 性别 ',zhiwei' 职位 ' from rszl where 1=?", paras); jtable.setModel(em); } } } ******************************************************************************* com.mhl.medel( 业务逻辑包 ) [UserModel.java] 用户登录业务逻辑源代码 /** * 这是用户表数据模型,用它完成对用户的各种操作 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 385 | 436 * [ 这里主要是编写项目需要的业务操作 ] */ package com.mhl.model; import java.sql.ResultSet; import com.mhl.db.SqlHelper; public class UserModel { /** * * @param userId 用户编号 * @param passwd 用户密码 * @return 该用户的职位 , 如果该用户不存在,则返回 "" */ public String checkUser(String userId,String passwd){ String zhiwei=""; SqlHelper sp=null; try { // 组织 sql 语句和参数列表 String sql="select r.zhiwei from login l,rszl r where l.empid=r.empid and l.empid=? and l.passwd=?"; String paras[]={userId,passwd}; sp=new SqlHelper(); ResultSet rs=sp.query(sql, paras); if(rs.next()){ // 取出职位 zhiwei zhiwei=rs.getString(1); } } catch (Exception e) { e.printStackTrace(); }finally{ sp.close(); } return zhiwei; } } ******************************************************************************* [EmpModel.java] 人事管理业务逻辑源代码 /** * 这是人事的数据模型类,主要完成对人事表的各种操作 (CRUD增、删、改、查 ) */ package com.mhl.model; 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 386 | 436 import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.Vector; import javax.swing.AbstractListModel; import javax.swing.table.AbstractTableModel; import com.mhl.db.SqlHelper; public class EmpModel extends AbstractTableModel{ Vector colums; Vector rows; SqlHelper sh; // 提供一个通过员工号来删除员工的函数 public boolean delEmpById(String empId){ boolean b=true; String sql="delete from rszl where empId=?"; String []paras={empId}; sh=new SqlHelper(); try { b=sh.exeUpdate(sql, paras); } catch (Exception e) { e.printStackTrace(); }finally{ sh.close(); } return b; } // 写一个方法用于查询需要显示的人事信息 public void query(String sql,String []paras){ // 初始化列 this.colums=new Vector(); this.rows=new Vector(); // 创建 SqlHelper 对象 sh=new SqlHelper(); ResultSet rs=sh.query(sql, paras); // 把 rs 的结果放入到 rows try { // 从 rs 对象中可以得到一个 ResultSetMetaData //rsmt 可以得到结果有多少列,而且可以知道每列的名字 ResultSetMetaData rsmt=rs.getMetaData(); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 387 | 436 for(int i=0;i temp=new Vector(); for(int i=0;i(); // 向 hashmap中添加一个客户端通讯线程 public static void addClientThrea(String uid,SerConClientThread scct){ hm.put(uid,scct); } public static SerConClientThread getClientThrea(String uid){ return (SerConClientThread)hm.get(uid); } // 返回当前在线的人的好友情况 public static String getAllOnLineUserid(){ // 使用迭代器完成 Iterator it=hm.keySet().iterator(); String res=""; while(it.hasNext()){ res+=it.next().toString()+" "; } 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 414 | 436 return res; } } ******************************************************************************* com.qq.common [Message.java] /** * 为 Message 规定规则 * mesType1--> 表明登录成功 * mesType2--> 表明登录失败 * mesType3--> 表明普通消息包 */ package com.qq.common; import java.io.Serializable; public class Message implements Serializable{ private String mesType; private String sender; private String getder; private String con; private String sendTime; public String getGetder() { return getder; } public void setGetder(String getder) { this.getder = getder; } public String getSender() { return sender; } public void setSender(String sender) { this.sender = sender; } public String getCon() { return con; } public void setCon(String con) { 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 415 | 436 this.con = con; } public String getSendTime() { return sendTime; } public void setSendTime(String sendTime) { this.sendTime = sendTime; } public String getMesType() { return mesType; } public void setMesType(String mesType) { this.mesType = mesType; } } ******************************************************************************* [MessageType.java] /** * 定义消息包的种类的接口 */ package com.qq.common; public interface MessageType { String message_succeed="1"; // 登录成功包 String message_login_fail="2"; // 登录失败包 String message_comm_mes="3"; // 普通消息包 String message_get_onLineFriend="4"; // 要求在线的好友包 String message_ret_onLineFriend="5"; // 返回在线好友包 } ******************************************************************************* [User.java] /** * 这是用户信息类 */ package com.qq.common; import java.io.Serializable; public class User implements Serializable{ private String userId; 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 416 | 436 private String passwd; public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public String getPasswd() { return passwd; } public void setPasswd(String passwd) { this.passwd = passwd; } } ******************************************************************************* 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 417 | 436 Client 端源代码 com.qq.client.view [QqClientLogin.java] /** * 功能: QQ客户端登陆界面 */ package com.qq.client.view; import java.awt.Color; import java.awt.Cursor; import java.awt.FlowLayout; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException; import java.io.ObjectOutputStream; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPasswordField; import javax.swing.JTabbedPane; import javax.swing.JTextField; import javax.swing.UIManager; import com.qq.client.model.QqClientUser; import com.qq.client.tools.ManageClientConServerThread; import com.qq.client.tools.ManageQqFriendList; import com.qq.common.Message; import com.qq.common.MessageType; import com.qq.common.User; public class QqClientLogin extends JFrame implements ActionListener{ // 定义北部需要的组件 JLabel jbl1; // 定义中部需要的组件 // 中部有三个 JPanel, 有一个叫选项卡窗口管理 JTabbedPane jtp; JPanel jp2,jp3,jp4; JLabel jp2_jbl1,jp2_jbl2,jp2_jbl3,jp2_jbl4; JButton jp2_jb1; 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 418 | 436 JTextField jp2_jtf; JPasswordField jp2_jpf; JCheckBox jp2_jcb1,jp2_jcb2; // 定义南部需要的组件 JPanel jp1; JButton jp1_jb1,jp1_jb2,jp1_jb3; public static void main(String[] args) { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Exception e) { e.printStackTrace(); } new QqClientLogin(); } public void initNorthLayout(){ // 处理北部 jbl1=new JLabel(new ImageIcon("image/qqview.jpg")); } public void initCenterLayout(){ // 处理中部 jp2=new JPanel(); jp2.setLayout(null); jp2_jbl1=new JLabel("QQ 号码 :"); jp2_jbl1.setBounds(30, 15, 60, 25); jp2_jbl2=new JLabel("QQ 密码 :"); jp2_jbl2.setBounds(30, 50, 60, 25); jp2_jbl3=new JLabel(" 忘记密码 "); jp2_jbl3.setForeground(Color.blue); jp2_jbl3.setBounds(260, 50, 80, 25); jp2_jbl3.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); jp2_jbl4=new JLabel(" 申请密码保护 "); jp2_jbl4.setForeground(Color.blue); jp2_jbl4.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); jp2_jbl4.setBounds(250, 85, 100, 25); jp2_jb1=new JButton(" 清除号码 "); jp2_jb1.setBounds(245, 15, 80, 25); jp2_jtf=new JTextField(); jp2_jtf.setBounds(80, 15, 150, 25); jp2_jpf=new JPasswordField(); jp2_jpf.setBounds(80, 50, 150, 25); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 419 | 436 jp2_jcb1=new JCheckBox(" 隐身登录 "); jp2_jcb1.setBounds(75, 85, 80, 25); jp2_jcb2=new JCheckBox(" 记住密码 "); jp2_jcb2.setBounds(155, 85, 80, 25); // 把控制按顺序加入 jp2 jp2.add(jp2_jbl1); jp2.add(jp2_jtf); jp2.add(jp2_jb1); jp2.add(jp2_jbl2); jp2.add(jp2_jpf); jp2.add(jp2_jbl3); jp2.add(jp2_jcb1); jp2.add(jp2_jcb2); jp2.add(jp2_jbl4); //jp3,jp4 jp3=new JPanel(); jp4=new JPanel(); // 创建选项卡窗口 jtp=new JTabbedPane(); jtp.add(jp2,"QQ 号码 "); jtp.add(jp3," 手机号码 "); jtp.add(jp4," 电子邮件 "); } public void initSouthLayout(){ // 处理南部 jp1=new JPanel(); jp1_jb1=new JButton(" 登录 "); jp1_jb1.addActionListener(this); jp1_jb2=new JButton(" 取消 "); jp1_jb2.addActionListener(this); jp1_jb3=new JButton(" 注册 "); // 把三个按钮放到 jp1 jp1.add(jp1_jb1); jp1.add(jp1_jb2); jp1.add(jp1_jb3); } // 构造函数 public QqClientLogin(){ // 布局北部 this.initNorthLayout(); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 420 | 436 // 布局中部 this.initCenterLayout(); // 布局南部 this.initSouthLayout(); this.add(jbl1,"North"); this.add(jtp,"Center"); this.add(jp1,"South"); this.setTitle("QQ 登录界面 "); this.setResizable(false); this.setSize(350, 300); this.setLocationRelativeTo(null); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setVisible(true); } @Override public void actionPerformed(ActionEvent e) { if(e.getSource()==jp1_jb1){ QqClientUser qqClientUser=new QqClientUser(); User u=new User(); u.setUserId(jp2_jtf.getText().trim()); u.setPasswd(new String(jp2_jpf.getPassword())); if(qqClientUser.checkUser(u)){ // 发送一个要求返回在线好友的请求包 try { this.dispose(); // 把创建好友列表的语句提前,否则是不能成功的 QqFriendList qqList=new QqFriendList(u.getUserId()); ManageQqFriendList.addQqFriendList(u.getUserId(), qqList); ObjectOutputStream oos=new ObjectOutputStream(ManageClientConServerThread.getClientConServerThread(u.getUs erId()).getS().getOutputStream()); // 做一个 Message Message m=new Message(); // 指明我的是这个 QQ号的好友在线情况 m.setSender(u.getUserId()); m.setMesType(MessageType.message_get_onLineFriend); oos.writeObject(m); } catch (Exception e1) { e1.printStackTrace(); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 421 | 436 } }else{ JOptionPane.showMessageDialog(this, " 帐号或密码错误,请核实后重 新登录 !"," 登录提示 ", JOptionPane.ERROR_MESSAGE); return; } }else if(e.getSource()==jp1_jb2){ System.exit(0); } } } ******************************************************************************* [QqFriendList.java] /** * 功能:我的好友列表界面 ( 也包括陌生人、黑名单 ) */ package com.qq.client.view; import java.awt.BorderLayout; import java.awt.CardLayout; import java.awt.Color; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import com.qq.client.tools.ManageQqChat; import com.qq.common.Message; public class QqFriendList extends JFrame implements ActionListener,MouseListener{ // 处理第一张卡片 ( 我的好友 ) JPanel jphy1,jphy2,jphy3; JButton jphy1_jb1,jphy1_jb2,jphy1_jb3; JScrollPane jsp1; String ownerId; JLabel []jbls; // 处理第二张卡片 ( 陌生人 ) 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 422 | 436 JPanel jpmsr1,jpmsr2,jpmsr3; JButton jpmsr_jb1,jpmsr_jb2,jpmsr_jb3; JScrollPane jsp2; // 处理第三张卡片 ( 黑名单 ) JPanel jphmd1,jphmd2,jphmd3; JButton jphmd_jb1,jphmd_jb2,jphmd_jb3; JScrollPane jsp3; // 把整个 JFrame 设置成 CardLayout CardLayout cl; // public static void main(String[] args) { // new QqFriendList(); // } public void initCard1(){ // 处理第一张卡片 ( 显示好友列表 ) jphy1_jb1=new JButton(" 我的好友 "); jphy1_jb2=new JButton(" 陌生人 "); jphy1_jb2.addActionListener(this); jphy1_jb3=new JButton(" 黑名单 "); jphy1_jb3.addActionListener(this); jphy1=new JPanel(new BorderLayout()); // 假定有 50 个好友 jphy2=new JPanel(new GridLayout(50, 1, 4, 4)); // 给 jp_hy2 初始化 50 个好友 jbls=new JLabel[50]; for(int i=0;i(); // 把创建好的 ClientConServerThread 放入到 hm中 public static void addClientConServerThread(String qqId,ClientConServerThread ccst){ hm.put(qqId, ccst); } // 可以通过 qqId 取得该线程 public static ClientConServerThread getClientConServerThread(String qqId){ return (ClientConServerThread)hm.get(qqId); 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 433 | 436 } } ******************************************************************************* [ManageQqChat.java] /** * 这是一个管理用户聊天界面的类 */ package com.qq.client.tools; import java.util.HashMap; import com.qq.client.view.QqChat; public class ManageQqChat { private static HashMap hm=new HashMap(); // 加入 public static void addQqChat(String loginIdAndFriendId,QqChat qqChat){ hm.put(loginIdAndFriendId, qqChat); } // 取出 public static QqChat getQqChat(String loginIdAndFriendId){ return (QqChat)hm.get(loginIdAndFriendId); } } ******************************************************************************* [ManageQqFriendList.java] /** * 管理 qq 好友、陌生人、黑名单界面类 */ package com.qq.client.tools; import java.util.HashMap; import com.qq.client.view.QqFriendList; public class ManageQqFriendList { private static HashMap hm=new HashMap(); // 加入 public static void addQqFriendList(String qqid,QqFriendList qqFriendList){ hm.put(qqid, qqFriendList); } // 取出 public static QqFriendList getQqFriendList(String qqId){ return (QqFriendList)hm.get(qqId); } 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 434 | 436 } ******************************************************************************* com.qq.common [Message.java] /** * 为 Message 规定规则 */ package com.qq.common; import java.io.Serializable; public class Message implements Serializable{ private String mesType; private String sender; private String getder; private String con; private String sendTime; public String getGetder() { return getder; } public void setGetder(String getder) { this.getder = getder; } public String getSender() { return sender; } public void setSender(String sender) { this.sender = sender; } public String getCon() { return con; } public void setCon(String con) { this.con = con; } public String getSendTime() { return sendTime; } public void setSendTime(String sendTime) { this.sendTime = sendTime; } public String getMesType() { return mesType; 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 435 | 436 } public void setMesType(String mesType) { this.mesType = mesType; } } ******************************************************************************* [MessageType.java] /** * 定义消息包的种类的接口 */ package com.qq.common; public interface MessageType { String message_succeed="1"; // 登录成功包 String message_login_fail="2"; // 登录失败包 String message_comm_mes="3"; // 普通消息包 String message_get_onLineFriend="4"; // 要求在线的好友包 String message_ret_onLineFriend="5"; // 返回在线好友包 } ******************************************************************************* [User.java] /** * 这是用户信息类 */ package com.qq.common; import java.io.Serializable; public class User implements Serializable{ private String userId; private String passwd; public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public String getPasswd() { return passwd; } public void setPasswd(String passwd) { this.passwd = passwd; } } ******************************************************************************* 韩顺平 Java从入门到精通视频 (全 94 讲详细笔记 )和作业详解 436 | 436 至此,韩顺平 JAVA入门到精通 ( 全 94 讲) 视频到此完结。 笔记包含完整的视频 PPT内容,及所有演示示例代码,和视频中所有作业答题。 学习注意: 视频教学内容简单易学,容易上手。对于 JAVASE的内容讲解通俗易懂,不过深度不高,讲 的较为浅显。主要是让学员对 JAVASE有所了解,本人对视频印象深刻的为在企业开发中的 注意事项,及开发软件的规则。对于需要全面了解学习 JAVA的朋友来说,还需研读更深、 更全面的 JAVA书籍,及 JAVA编程思想。从而对 JAVA有全面的认识。 韩顺平讲师的后续视频笔记,将陆续放出。