首页资源分类其它科学普及 > java经典教程

java经典教程

已有 451370个资源

下载专区

文档信息举报收藏

标    签:java

分    享:

文档简介

一本JAVA经典教程

文档预览

Java实用教程 Java Java编程经典—— 2010新版Java教程 Java实用教程 目录 第1章 Java环境及配置 第2章 Java基本语法 第3章 类和接口 第4章 Java Applet 第5章 Java图形处理 第6章 Java用户界面技术 第7章 异常、事件和多线程机制 第8章 输入输出技术 第9章 Java数据库技术 第10章 Java安全技术 第11章 Java网络技术(一) 第12章 Java网络技术(二) 第13章 Servlet技术 第14章 Java读写XML技术 Java实用教程 第1章Java环境及配置 1.1 Java概述 1.2 Java语言的特点 1.3 Java应用分类 1.4 JDK包的下载与安装 1.5 Java环境配置 1.6 例子程序 习题 Java实用教程 1.1 Java 概 述 Java是一种编程语言,它提供了一个同时用于程序开发、 应用和部署的环境。Java语言主要定位于网络编程,使得程 序可以最大限度地利用网络资源。 Java实用教程 1.2 Java 语 言 的 特 点 1. 跨平台性 所谓的跨平台性,是指软件可以不受计算机硬件和操作系 统的约束而在任意计算机环境下正常运行。这是软件发展的趋 势和编程人员追求的目标。之所以这样说,是因为计算机硬件 的种类繁多,操作系统也各不相同,不同的用户和公司有自己 不同的计算机环境偏好,而软件为了能在这些不同的环境里正 常运行,就需要独立于这些平台。 Java实用教程 而在Java语言中,Java自带的虚拟机很好地实现了跨平台 性。Java源程序代码经过编译后生成二进制的字节码是与平台 无关的,但是可被Java虚拟机识别的一种机器码指令。Java虚 拟机提供了一个字节码到底层硬件平台及操作系统的屏障,使 得Java语言具备跨平台性。 Java实用教程 2. 面向对象 面向对象是指以对象为基本粒度,其下包含属性和方法。 对象的说明用属性表达,而通过使用方法来操作这个对象。面 向对象技术使得应用程序的开发变得简单易用,节省代码。 Java是一种面向对象的语言,也继承了面向对象的诸多好处, 如代码扩展、代码复用等。 Java实用教程 3. 安全性 安全性可以分为四个层面,即语言级安全性、编译时安全 性、运行时安全性、可执行代码安全性。 语言级安全性指Java的数据结构是完整的对象,这些封装 过的数据类型具有安全性。编译时要进行Java语言和语义的检 查,保证每个变量对应一个相应的值,编译后生成Java类。运 行时Java类需要类加载器载入,并经由字节码校验器校验之后 才可以运行。Java类在网络上使用时,对它的权限进行了设置, 保证了被访问用户的安全性。 Java实用教程 4. 多线程 多线程在操作系统中已得到了最成功的应用。多线程是指 允许一个应用程序同时存在两个或两个以上的线程,用于支持 事务并发和多任务处理。Java除了内置的多线程技术之外,还 定义了一些类、方法等来建立和管理用户定义的多线程。 Java实用教程 5. 简单易用 Java源代码的书写不拘泥于特定的环境,可以用记事本、 文本编辑器等编辑软件来实现,然后将源文件进行编译,编译 通过后可直接运行,通过调试则可得到想要的结果。 Java实用教程 1.3 Java 应 用 分 类 1. 应用程序 典型的通用程序可以在具备Java运行环境的设备中独立运 行,它又分为: GUI应用程序:即图形用户界面程序,可实现丰富的输入 界面和输出显示。 命令行程序:无需界面,只需在命令行下运行,运行结果 只在后台发生变化,可以将输出存放到文件中。 嵌入式应用程序:Java语言的平台独立性决定了它可以嵌 入到不同的设备中,且只需具备必要的运行环境即可。 Java实用教程 2. Servlets服务器端应用程序 服务器端的应用程序用来收集客户端的数据输入,对数据 进行处理之后,返回相应的响应给客户。它主要用来实现与客 户端的交互。 Java实用教程 3. Applets小应用程序 Applets应用于网络上,嵌入在HTML网页中,支持Java的 浏览器都可以对它进行解释并运行。通常通过一个HTML标签 来识别并运行Applets。小应用程序的 类在服务器端,当浏览器显示网页时,它随之下载到本地, 由本地的浏览器载入运行。 Java实用教程 1.4 JDK包的下载与安装 Java Develop Kit简称为JDK,是Sun公司免费发行的软件包, 可以从Sun网站http://www.sun.com免费下载,也可以从其它国 内地址下载。JDK版本从1.02开始,目前版本发展到1.4,其中 高级版本对低级版本实现向下兼容。运用这个软件包,就可以 对Java源程序进行编译和运行。本书中下载使用的JDK包为 j2sdk-1_4_0_012-windows-i586.exe。 下载后双击图标,即可进 行安装,默认的安装目录为C:\j2sdk1.4.0_01。本书作者将安装 目录改为D:\j2sdk1.4.0_01。 Java实用教程 1.5 Java 环 境 配 置 JDK包安装完成后,需要设置环境变量。用鼠标右键单击 桌面上的图标“我的电脑”,选择“属性”项,出现标题为 “系统特性”的对话框,点击“高级”标签,可以看见有一个 “环境变量”按钮,如图1.1所示。 Java实用教程 图1.1 “系统特性”对话框 Java实用教程 单击“环境变量”按钮,可以看见本机环境变量,如图1.2 所示。上面为用户变量,下面为系统变量,随着操作系统或用户 环境的不同,变量名、值有所不同。这里需要修改三个用户变量: include、lib和path,分别将JDK包安装之后的相应路径包含到这 三个用户变量中。 Java实用教程 图1.2 “环境变量”对话框 Java实用教程 选中include变量,单击“编辑”按钮,弹出标题为“编辑 用户变量”的对话框,如图1.3所示。在变量值一栏的最后添加 “; D:\j2sdk1.4.0_01\include”,“;”表示与前面的各项隔开,后 面的路径是JDK包的安装路径下的include目录。图1.3为作者修 改include变量的情况,注意你的安装路径可能与作者的有所不 同,要以你的安装路径为基准进行修改。 Java实用教程 图1.3 编辑include变量 Java实用教程 选中lib变量,单击“编辑”按钮,弹出标题为“编辑用户 变量”的对话框,如图1.4所示。在变量值一栏的最后添加“; D:\j2sdk1.4.0_01\lib”,“;”表示与前面的各项隔开,后面的路 径是JDK包的安装路径下的lib目录。图1.4为作者修改lib变量的 情况,注意你的安装路径可能与作者的有所不同,要以你的安 装路径为基准进行修改。 Java实用教程 图1.4 编辑lib变量 Java实用教程 选中path变量,单击“编辑”按钮,弹出标题为“编辑用 户变量”的对话框,如图1.5所示。在变量值一栏的最后添加“; D:\j2sdk1.4.0_01\bin”,“;”表示与前面的各项隔开,后面的路 径是JDK包的安装路径下的bin目录。图1.5为作者修改path变量 的情况,注意你的安装路径可能与作者的有所不同,同样要以 你的安装路径为基准进行修改。 Java实用教程 图1.5 编辑path变量 Java实用教程 1.6 例 子 程 序 【例1.1】源程序名称为HelloWorld.java,命令行提示符下输 出字符串“Hello World”。源代码如下: //程序文件名称为HelloWorld.java public class HelloWorld { public static void main(String args[]) { System.out.println("Hello World"); } } Java实用教程 用记事本或者专用的编辑工具如EditPlus等进行编辑,并将 文件存为HelloWorld.java。建议使用像EditPlus这样的编辑软件, 可使得代码更加清晰且风格良好。 运行“开始”菜单→程序→附件→命令提示符,载入命令 行程序,在命令行状态下,进入源程序所在的目录,图1.6所示 的例子程序的目录在“E:\_Work\Java\sample”下,然后键入命令 “javac HelloWorld.java”。若编译不通过,会产生错误提示。若 编译通过,则没有任何提示,同时进入命令行等待状态,如图 1.6所示。这时,命令行虽然没有提示,但在源程序的路径下生 成一个新的文件为HelloWorld.class。这个.class文件就是编译后 生成的类文件,运行此文件,需在命令行状态中键入命令“java HelloWorld”,然后按回车键,此时程序就会运行并输出“Hello World”。输出完毕,立即退出程序,进入命令行等待状态,如 图1.7所示。 Java实用教程 图1.6 编译源程序HelloWorld Java实用教程 图1.7 运行HelloWorld应用程序 Java实用教程 这里用到的命令Javac和Java都是JDK软件包自带的。从 JDK安装路径的bin目录下可以看到javac.exe,这是编译程序, 源程序编译通过后就生成.class文件;而Java.exe就是载入类的 运行程序,运行时根据源程序的指令要求产生正确的输出或结 果。如果没有进行环境配置,直接编译或者运行Java源程序, 系统会提示找不到这些命令,所以必须进行环境配置后再使用。 Java实用教程 【例1.2】小应用程序的例子。输出“Hello World!”,如 图1.8所示。源程序代码如下: //程序文件名称为HelloApplet.java import java.awt.Graphics; import java.applet.Applet; public class HelloApplet extends Applet { public void paint (Graphics g ) { g.drawString ("Hello World!",50,25); } } Java实用教程 小应用程序代码书写和编译完成后,无法独立运行,需要 一个载体或者容器。下面的HTML网页代码就是小应用程序载 入的容器。 HTML Test Page Java实用教程 HelloApplet will appear below in a Java enabled browser.
Java实用教程 图1.8 Applet显示“Hello World!” Java实用教程 习题 1. 简述Java的特点。 2. 简述Java的分类情况。 3. 进行Java环境的安装和配置。 4. 编写应用程序,屏幕上输出“欢迎来到Java世界!”。 5. 编写Applet,输出“欢迎来到Java世界!”。 Java实用教程 第2章 Java基本语法 2.1 Java程序的构成 2.2 数据类型、变量和常量 2.3 运算符和表达式 2.4 流程控制 2.5 数组的使用 习题 Java实用教程 2.1 Java程序的构成 2.1.1 逻辑构成 Java源程序逻辑构成分为两大部分:程序头包的引用和类 的定义。 1. 程序头包的引用 主要是指引用JDK软件包自带的包,也可以是自己定义的类。 引用之后程序体中就可以自由应用包中的类的方法和属性等。 Java实用教程 2. 类的定义 Java源程序中可以有多个类的定义,但必须有一个主类, 这个主类是Java程序运行的入口点。在应用程序中,主类为包 含main方法的类;在Applet中,主类为用户自定义的系统Applet 类的扩展类。在Java源程序中,主类的名字同文件名一致。 类的定义又包括类头声明和类体定义。类体中包括属性声 明和方法描述。下面来看一个例子,其中斜体表示的语句行为 主类类头,主类类头下面从大括号“{”开始到“}”结束的部分 称为主类类体。 Java实用教程 【例2.1】下面是一个应用程序,也是一个Applet,既可以 在命令行下运行,也可以嵌入到HTML网页中用appletviewer命 令运行。运行时在界面上的第一个文本框中输入你的名字,按 回车键后,在第二个文本框中会显示“XXX,欢迎你来到Java 世界!”,运行结果如图2.1所示。 //程序文件名称为WelcomeApplet.java 注释语句 import java.applet.*; import java.awt.*;   引入包 import java.awt.event.*; public class WelcomeApplet extends Applet implements ActionListener 主类类头 { Java实用教程 TLeaxbteFlileblldNtxatmNea; me; 属 性 TextField txtDisp;  publicvoidinit()  {   lblName new Label(" 请输入您的名字" ); txtName  new TextField(8);   txtDisp new TextField(20); add(lblName);   init方法  add(txtName);  add(txtDisp);   t xt N ame.ad d A cti o n L i s t enre(t h i s );  }   Java实用教程 publicvoidactionP erformed(ActionEvente)  { actionPerformed txtDisp.setText(txtName.getText()  " 欢迎你来到Java世界" );方法   Java实用教程 publicstaticvoidmain(String args[])  {   Fr ame f  new Frame(" 欢迎" );  f.addWindowListenern( ew WindowAdapter()){ publicvoidwindowClosing(WindowEventevt)  {   System.exit(0);  } }    main主方法 ;   WelcomeApplet a  new WelcomeApplet();  a.init();   f.add(" Center", a);  f.setSize(400,300);   f.show();  a.start();   }  Java实用教程 图2.1 程序界面 Java实用教程 2.1.2 物理构成 Java源程序物理上由三部分构成,分别为语句、块和空白。 (1) 语句指一行以分号“;”结束的语句。 (2) 块指用括号对{}界定的语句序列,块可以嵌套使用。 (3) 空白指语句之间、块内部或者块之间的空白行。空白 不影响Java源程序的编译和运行,适当地运用空白,可以形成 良好的代码风格。 Java实用教程 在例1.1中, Label lblName; TextField txtName; TextField txtDisp; 都是语句,而 { lblName = new Label("请输入您的名字:"); txtName = new TextField(8); txtDisp = new TextField(20); add(lblName); add(txtName); add(txtDisp); txtName.addActionListener(this); } 是块,语句之间、块之间或块内部的空行都为空白。 Java实用教程 2.1.3 注释语句 注释语句主要用来进行一些说明,或者标记一些无用的程 序语句。有两种注释方法,行注释为以//开始的行;块注释以/* 开始和*/结束,Java编译器忽略注释后的程序语句或说明。 例如,下面的语句就是注释语句用来说明程序文件名称的。 //程序文件名称为WelcomeApplet.java 上述的语句注释可以更改为: /*程序文件名称为WelcomeApplet.java*/ 或 /* 程序文件名称为 WelcomeApplet.java */ Java实用教程 2.1.4 标识符、关键字和转义符 在Java语言中,标识符是赋予变量、类和方法等的名称。 标识符由编程者自己指定,但需要遵循一定的语法规范: (1) 标识符由字母、数字、下划线(_)、美元符号($)组成, 但美元符号用得较少。 (2) 标识符从一个字母、下划线或美元符号开始。 (3) Java语言中,标识符大小写敏感,必须区别对待。 (4) 标识符没有最大长度的限制,但最好表达特定的意思。 (5) 标识符定义不能是关键字。 Java实用教程 关键字又称保留字,是指Java语言中自带的用于标志数据 类型名或者程序构造名等的标识符,如public、double等。 转义符是指一些有特殊含义的、很难用一般方式表达的字 符,如回车、换行等。所有的转义符以反斜线(\)开头,后面跟 着一个字符来表示某个特定的转义符,如表2.1所示。 Java实用教程 表2.1 转 义 符 引用方法 \b \t \n \f \r \' \" \\ 含义 退格 水平制表符 Tab 换行 表格符 回车 单引号 双引号 反斜线 Java实用教程 2.2 数据类型、变量和常量 2.2.1 数据类型 Java编程语言定义了八种基本的数据类型(见表2.2),共分为 四类:整数类(byte、short、int、long)、文本类(char)、浮点类 (double、float)和逻辑类(boolean)。 Java实用教程 表2.2 Java的数据类型 分类 整数类 文本类 浮点类 逻辑类 数据类型 字节型 短整型 整型 长整型 字符型 浮点型 双精度型 逻辑型 关键字 byte short int long char float double boolean 占字节数 8 16 32 64 16 32 64 8 缺省数值 0 0 0 0 ′\u 0000′ 0.0F 0.0D False 取值范围 -2 7~2 7-1 -2 15~2 15-1 -2 31~2 31-1 -2 63~2 63-1 ′\u 0000′ ~ ′\u FFFF′ — — True、False Java实用教程 1. 整数类 (1) 采用三种进制——十进制、八进制和十六进制。 2 —— 十进制值是2; 077 —— 首位的0表示这是一个八进制的数值; 0xBAAC —— 首位的0x表示这是一个十六进制的数值。 (2) 具有缺省int。 (3) 用字母“L”和“l”定义long。 (4) 所有Java编程语言中的整数类型都是带符号的数字。 Java实用教程 2. 文本类 (1) 代表一个16 bit Unicode字符。 (2) 必须包含用单引号(' ')引用的文字。 (3) 使用下列符号: 'a'——一个字符。 '\t'--一个制表符。 '\u???? '--一个特殊的Unicode字符,????应严格使用四个十 六进制数进行替换。 Java实用教程 3. 浮点类 默认为double类型,如果一个数字包括小数点或指数部分, 或者在数字后带有字母F或f(float)、D或d(double),则该数字为 浮点数。 Java实用教程 4. 逻辑类 boolean数据类型有两种值:true和false。 例如:boolean flag = true; 上述语句声明变量flag为boolean 类型,它被赋予的值为true。 Java实用教程 2.2.2 变量与常量 常量是指整个运行过程中不再发生变化的量,例如数学中 的π= 3.1415……,在程序中需要设置成常量。而变量是指程序 的运行过程中发生变化的量,通常用来存储中间结果,或者输 出临时值。 变量的声明也指变量的创建。执行变量声明语句时,系统 根据变量的数据类型在内存中开辟相应的存储空间并赋予初始 值。变量有一个作用范围,超出它声明语句所在的块就无效。 Java实用教程 下面看一个使用各种类型变量声明并改变的示例。程序中pi 为常量,s1、i1、l1、ch1、f1、d1、b1为全局变量,可以在方法 change中发生改变,然后在方法main中输出。而s2、i2、l2、ch2、 f2、d2、b2是方法main的局部变量,它们的作用范围只局限于方 法main中。 【例2.2】测试不同数据类型的变量,程序输出如图2.2所示。 源程序代码如下: //程序文件名称为SetVariable.java public class SetVariable { //全局变量 Java实用教程 static double pi = 3.141592654;//数学常量 static short s1; static int i1; static long l1; static char ch1; static float f1; static double d1; static boolean b1; public static void main(String args[]) { Java实用教程 //局部变量 short s2 = 35; int i2 = -32; long l2 = 34555L; char ch2 = 'A'; float f2 = 897.89F; double d2 = 34.345; boolean b2 = false; //输出常量 System.out.println("数学常量pi = " + pi); //输出局部变量 Java实用教程 System.out.println("******局部变量******"); System.out.println("短整型变量s2 = " + s2); System.out.println("整型变量i2 = " + i2); System.out.println("长整型变量l2 = " + l2); System.out.println("字符变量ch2 = " + ch2); System.out.println("浮点数类型f2 = " + f2); System.out.println("双精度型变量d2 = " + d2); System.out.println("布尔型变量b2 = " + b2); //调用方法修改全局变量的值 Java实用教程 change(); //输出全局变量的值 System.out.println("******全局变量******"); System.out.println("短整型变量s1 = " + s1); System.out.println("整型变量i1 = " + i1); System.out.println("长整型变量l1 = " + l1); System.out.println("字符变量ch1 = " + ch1); System.out.println("浮点数类型f1 = " + f1); System.out.println("双精度型变量d1 = " + d1); System.out.println("布尔型变量b1 = " + b1); } Java实用教程 //方法:修改全局变量的值 public static void change() { s1 = 125; i1 = 88; l1 = 987654321L; ch1 = 'B'; f1 = 3.2590F; d1 = -1.04E-5; b1 = true; } } Java实用教程 图2.2 变量输出结果 Java实用教程 2.3 运算符和表达式 Java常用的运算符分为五类:算术运算符、赋值运算符、 关系运算符、布尔逻辑运算符、位运算符。位运算符除了简单 的按位操作外,还有移位操作。按位操作返回布尔值。 表达式是由常量、变量、对象、方法调用和操作符组成的 式子。表达式必须符合一定的规范,才可被系统理解、编译和 运行。表达式的值就是对表达式自身运算后得到的结果。 根据运算符的不同,表达式相应地分为以下几类:算术表 达式、关系表达式、逻辑表达式、赋值表达式,这些都属于数 值表达式。 Java实用教程 2.3.1 算术运算符及算术表达式 Java中常用的算术运算符如下: + 加运算符 - 减运算符 * 乘运算符 / 除运算符 % 取模运算(除运算的余数) ++ 增量运算符 -- 减量运算符 Java实用教程 【例2.3】测试运算符及表达式,程序输出如图2.3所示。源 程序代码如下: //程序文件名称为NumberOper.java public class NumberOper { public static void main(String args[]) { //变量初始化 int a = 30; int b = 20; //定义结果变量 int r1,r2,r3,r4,r5,r6,r7,r8,r9; //计算结果 r1 = a + b; Java实用教程 r2 = a-b; r3 = a * b; r4 = a / b; r5 = a % b; r6 = a ++; r7 = b--; r8 = ++ a; r9 = -- b; //输出结果 System.out.println("a = " + a + " b = " + b); //a,b的值 System.out.println("a+b = " + r1); System.out.println("a-b = " + r2); Java实用教程 System.out.println("a*b = " + r3); System.out.println("a/b = " + r4); System.out.println("a%b = " + r5); System.out.println("a++ =" + r6); System.out.println("b-- =" + r7); System.out.println("++a =" + r8); System.out.println("--b =" + r9); } } Java实用教程 图2.3 程序输出结果 Java实用教程 2.3.2 关系运算符 关系运算符用于比较两个数据之间的大小关系,关系运算 表达式返回布尔值,即“真”或“假”。Java中的常用关系运 算符如下: == 等于 != 不等于 > 大于 < 小于 >= 大于等于 <= 小于等于 Java实用教程 【例2.4】编写程序,测试关系运算符及其表达式,程序输 出如图2.4所示。源程序代码如下: //程序文件名称为TestRelation.java public class TestRelation { public static void main(String args[]) { //变量初始化 int a = 30; int b = 20; //定义结果变量 boolean r1,r2,r3,r4,r5,r6; //计算结果 Java实用教程 r1 = a == b; r2 = a != b; r3 = a > b; r4 = a < b; r5 = a >= b; r6 = a <= b; //输出结果 System.out.println("a = " + a + " b = " + b); System.out.println("a==b = " + r1); System.out.println("a!=b = " + r2); System.out.println("a>b = " + r3); System.out.println("a=b = " + r5); System.out.println("a<=b = " + r6); } } Java实用教程 图2.4 程序输出结果 Java实用教程 2.3.3 布尔逻辑运算符 表2.3 布尔运算符及规则 运算符 ! & | ^ && || 含义 取反 非简洁与 非简洁或 异或 简洁与 简洁或 示例 !a a&b a|b a ^b a && b a || b 规则 a 为真时,结果为假;a 为假时,结果为真 a、b 都为真时,结果为真;a、b 有一个为假时,结果为假 a、b 有一个为真时,结果为真;a、b 都为假时,结果为假 a、b 不同真假时结果为真;a、b 同真或同假时,结果为假 a、b 都为真时,结果为真;a、b 有一个为假时,结果为假 a、b 有一个为真时,结果为真;a、b 都为假时,结果为假 Java实用教程 图2.3为布尔逻辑运算符及其规则示例等。其中简洁与和简 洁或的执行结果分别与非简洁与和非简洁或的执行结果是一致 的,不同在于简洁与检测出符号左端的值为假时,不再判断符 号右端的值,直接将运算结果置为假;而简洁或与非简洁或的 不同在于简洁或检测出符号左端为真时,不再判断符号右端的 值,直接将运算结果置为真。 例如: Boolean a = false; Boolean b = true; a && b检测到a为假,则无需判断b的值,直接将值置为假; 而b || a时检测到b为真,则无需判断a的值,直接将值置为真。 Java实用教程 【例2.5】测试布尔表达式,程序输出结果如图2.5所示。源 程序代码如下: //程序文件名称为TestLogic.java public class TestLogic { public static void main(String args[]) { //变量初始化 boolean a = false; boolean b = true; //定义结果变量 boolean r1,r2,r3,r4,r5,r6; //计算结果 Java实用教程 } } r1 = !a; r2 = a & b; r3 = a | b; r4 = a ^ b; r5 = a && b; r6 = a || b; //输出结果 System.out.println("a = " + a + " b = " + b); System.out.println("!a = " + r1); System.out.println("a&b = " + r2); System.out.println("a|b = " + r3); System.out.println("a^b = " + r4); System.out.println("a&&b = " + r5); System.out.println("a||b = " + r6); Java实用教程 图2.5 程序输出结果 Java实用教程 2.3.4 位运算符 Java中的常用位运算符如下: ~ 位求反 & 按位与 | 按位或 ^ 按位异或 << 左移 >> 右移 >>> 不带符号右移 右移运算符对应的表达式为x>>a,运算的结果是操作数x被 2的a次方来除,左移运算符对应的表达式为x<>,程序输出结果如图2.6所示。 源程序代码如下: //程序文件名称为TestBit.java public class TestBit { public static void main(String args[]) { //变量初始化 int a = 36; int b = 2; //定义结果变量 int r1,r2; Java实用教程 //计算结果 r1 = a >> b; r2 = a << b; //输出结果 System.out.println("a = " + a + " b = " + b); System.out.println("a>>b = " + r1); System.out.println("a<>= >>>= 含义 加并赋值运算符 减并赋值运算符 乘并赋值运算符 除并赋值运算符 取模并赋值运算符 与并赋值运算符 或并赋值运算符 或并赋值运算符 左移并赋值运算符 右移并赋值运算符 右移并赋值运算符 示例 a += b a-= b a *= b a /= b a %= b a &= b a |= b a ^= b a <<= b a >>= b a >>>= b 等价表达式 a=a+b a = a-b a=a*b a=a/b a=a%b a=a&b a=a|b a =a ^b a = a << b a = a >> b a = a >>> b Java实用教程 2.3.6 其它操作符及其表达式 三目运算符(?:)相当于条件判断,表达式x?y:z用于判断x是 否为真,如果为真,表达式的值为y,否则表达式的值为z。 例如: int x = 5; int a = (x>3)?5:3; 则a的值为5。如果x = 2,则a的值为3。 Java实用教程 对象运算符(instanceof)用来判断一个对象是否属于某个指 定的类或其子类的实例,如果是,返回真(true),否则返回假 (false)。 例如: boolean b = userObject instanceof Applet 用来判断userObject类是否是Applet类的实例。 Java实用教程 2.3.7 优先级 表2.5 运算符优先级 优先级 1 2 3 4 5 6 7 8 9 10 11 12 13 14 含义描述 分隔符 单目运算、字符串运算 算术乘除运算 算术加减运算 移位运算 大小关系运算、类运算 相等关系运算 按位与,非简洁与 按位异或运算 按位或,非简洁或 简洁与 简洁或 三目条件运算 简单、复杂赋值运算 运算符 [] () ; , ++ -- + - ~ ! (类型转换符) */% +- << >> >>> < > <= >= instanceof == != & ^ | && || ?: = *= /= %= += - = <<= >>= &= ^= |= 结合性 >>>= *右到左 左到右 左到右 左到右 左到右 左到右 左到右 左到右 左到右 左到右 左到右 *右到左 *右到左 Java实用教程 2.4 流 程 控 制 流程控制分为三种基本结构:顺序结构、分支结构和循环 结构。顺序结构是指命令行顺序执行,这是最常见的一个格式; 分支结构是一种选择结构,根据条件的值选择不同的执行流程, 可以得到不同的结果。分支结构包括单分支语句(if-else语句)和 多分支语句(switch语句);循环结构是指对于一些重复执行的语 句,用户指定条件或次数,由机器自动识别执行。循环结构包 括次数循环语句(for语句)和条件循环语句(while语句)。 Java实用教程 2.4.1 分支语句 分支语句分为两类:单分支语句和多选语句。 1. if-else语句 if-else语句的基本格式为: if(布尔表达式) { 语句或块1; } else { 语句或块2; } Java实用教程 其中: (1) 布尔表达式返回值为true或false。 (2) 如果为true,则执行语句或块1,执行完毕跳出if-else语 句。 (3) 如果为false,则跳过语句或块1,然后执行else下的语句 或块2。 Java实用教程 【例2.7】测试if-else语句,如果x>10,则输出x的值,并提 示结果正确,否则输出x= 10,提示结果不正确。程序输出结果 如图2.7所示。源程序代码如下: //程序文件名称为TestIf.java public class TestIf { //声明全局变量x static int x; public static void main(String args[]) { x = 12; if(x>10) { Java实用教程 System.out.println("x = " + x + " 结果正确"); } else System.out.println("x = 10" + " 结果不正确"); change(); System.out.println("修改x的值之后"); if(x>10) { System.out.println("x = " + x + " 结果正确"); } else System.out.println("x = 10" + " 结果不正确"); } Java实用教程 //change方法:修改x的值 public static void change() { x = 5; } } Java实用教程 图2.7 程序输出结果 Java实用教程 2. switch语句 switch语句的基本格式为: switch(表达式1) { case 表达式2: 语句或块2; break; case表达式3: 语句或块3; break; case 表达式4: 语句或块4; break; default: 语句或块5; break; } Java实用教程 其中: (1) 表达式1的值必须与整型兼容。 (2)  case分支要执行的程序语句。 (3) 表达式2、3、4是可能出现的值。 (4) 不同的case分支对应着不同的语句或块序列。 (5)  break表示跳出这一分支。 Java实用教程 【例2.8】测试switch语句,当x=1、2、3时,分别打印1、2、 3,x不为这三个值时,打印x的值。程序输出结果如图2.8所示。 源程序代码如下: //程序文件名称为TestSwitch.java public class TestSwitch { public static void main(String args[]) //声明变量x int x; x = 12; Java实用教程 System.out.println("x=12时打印的值"); choose(x); x = 3; System.out.println("x=3时打印的值"); choose(x); } //choose方法:switch语句结构 public static void choose(int x) { switch(x) { Java实用教程 } } } case 1: System.out.println(1); break; case 2: System.out.println(2); break; case 3: System.out.println(3); break; default: System.out.println(x); Java实用教程 图2.8 程序输出结果 Java实用教程 2.4.2 for循环语句 for循环语句实现已知次数的循环,其基本格式为: for(初始化表达式;测试表达式;步长) { 语句或块; } Java实用教程 其执行顺序如下: (1) 首先运行初始化表达式。 (2) 然后计算测试表达式,如果表达式为true,执行语句或 块;如果表达式为false,退出for循环。 (3) 最后执行步长。 Java实用教程 【例2.9】用for循环统计1~100(包括100)之间数的总和。程 序输出结果如图2.9所示。源程序代码如下: //程序文件名称为TestFor.java public class TestFor { public static void main(String args[]) { int sum = 0; for(int i = 1; i<=100; i++) sum += i; System.out.println("1到100(包括100)的数的总和为:" + sum); } } Java实用教程 图2.9 程序输出结果 Java实用教程 2.4.3 while循环语句 while循环语句实现受条件控制的循环,其基本格式为: while(布尔表达式) { 语句或块; } 当布尔表达式为true时,执行语句或块,否则跳出while循 环。 Java实用教程 上面for循环语句的例子改为while语句后如下所示: int sum = 0; int i = 1; while (i<=100) { sum += i; i++; } System.out.println("1到100(包括100)的数的总和为:" + sum); Java实用教程 2.4.4 do语句 do语句实现受条件控制的循环,其基本格式为: do { 语句或块; } while(布尔表达式) Java实用教程 先执行语句或块,然后再判断布尔表达式。与while语句不 同,当布尔表达式一次都不为true时,while语句一开始判断就跳 出循环,不执行语句或块,而在do语句中则要执行一次。上面 那个例子改为do循环为: int sum = 0; int i = 1; do { sum += i; i++; } while (i<=100); System.out.println("1到100(包括100)的数的总和为:" + sum); Java实用教程 2.5 数 组 的 使 用 2.5.1 数组声明 数组的定义如下: (1) 首先是一个对象。 (2) 存放相同的数据类型,可以是原始数据类型或类类型。 (3) 所有的数组下标默认从0开始,而且访问时不可超出定 义的上限,否则会产生越界错误。 Java实用教程 数组声明时实际是创建一个引用,通过代表引用的这个名 字来引用数组。数组声明格式如下: 数据类型 标识符[] 例如: int a[];//声明一个数据类型为整型的数组a pencil b[];//声明一个数据类型为pencil类的数组b Java实用教程 2.5.2 创建数组 由于数组是一个对象,所以可以使用关键字new来创建一 个数组,例如: a = new int[10];//创建存储10个整型数据的数组a b = new pencil[20];//创建存储20个pencil类数据的数组b 数组创建时,每个元素都按它所存放数据类型的缺省值被 初始化,如上面数组a的值被初始化为0,也可以进行显式初始 化。在Java编程语言中,为了保证系统的安全,所有的变量在 使用之前必须是初始化的,如果未初始化,编译时会提示出错。 有两种初始化数组的方式,分别如下: Java实用教程 (1) 创建数组后,对每个元素进行赋值。 a[0]=5; a[1]=4; ... a[9] = 10; (2) 直接在声明的时候就说明其值,例如: int a[] = {4,5,1,3,4,20,2}; 说明了一个长度为7的一维数组。 Java实用教程 【例2.10】编写程序测试数组,程序输出结果如图2.10所示。 源程序代码如下: //程序文件名称为TestArray.java public class TestArray { public static void main(String args[]) { //声明数组 int a[]; char b[]; //创建数组 Java实用教程 a = new int[3]; b = new char[2]; //数组初始化 for (int i = 0; i<3; i++) { a[i] = i*3; } b[0] = 'a'; b[1] = 'b'; //快速初始化数组 int c[] = {0,1*3,2*3}; //输出结果 System.out.print("数组a\n"); Java实用教程 for (int i = 0; i<2; i++) { System.out.print(b[i] + " "); } System.out.print("\n数组c\n"); for (int i = 0; i<3; i++) { System.out.print(c[i] + " "); } } } Java实用教程 图2.10 程序输出结果 Java实用教程 习题 1. 给出下列表达式的值。 (1) 3++4<<2^-8 (2) "abc"&123||8<<2 (3) 36>>2*4&&48<<8/4+2 (4) 2*4&&0<2||4%2 2. 编写程序,统计课程编号为1001、1002、2001和3001的平 均成绩并输出。学生成绩表如图2.11所示。【每个课程编号的成 绩用数组存储,读取时循环操作】 Java实用教程 图2.11 习题2.2的成绩表 Java实用教程 3. 根据上题得出的考生平均成绩进行判断,如果在90分以 上,屏幕上输出“课程编号为XXXX的考生平均成绩为优”;在 80~90分之间输出“课程编号为XXXX的考生平均成绩为良”; 在70~80分之间输出“课程编号为XXXX的考生平均成绩为中”, 在60~70分之间输出“课程编号为XXXX的考生平均成绩为及 格”;60分以下输出“课程编号为XXXX的考生平均成绩为不及 格”。 4. 编写程序,用数组实现乘法小九九的存储和输出。【提 示:采用多个一维数组。】 Java实用教程 第3章类和接口 3.1 类 3.2 接口 3.3 常用数据结构及类 习题 Java实用教程 3.1 类 3.1.1 类的定义和声明 Java编程语言是面向对象的,处理的最小的完整单元为对 象。而现实生活中具有共同特性的对象的抽象就称之为类。类 由类声明和类体构成,类体又由变量和方法构成。下面给出一 个例子来看一下类的构成。 【例3.1】自定义一个apple类,在主类SetApple中创建实例 并调用方法,输出结果如图3.1所示。源程序代码如下: Java实用教程 //程序文件名为SetApple.java public class SetApple { public static void main(String[] args) { apple a = new apple();//创建apple类 a.appleweight = 0.5;//实例变量赋值 System.out.println("苹果的重量为1两"); System.out.println(a.bite());//调用实例方法 a.appleweight = 5; System.out.println("苹果的重量为5两"); System.out.println(a.bite()); } } Java实用教程 //自定义类 class apple { //属性 long applecolor;//对应苹果的颜色 double appleweight;//苹果的重量 boolean eatup;//是否吃完 //类方法 public boolean bite() { if (appleweight<1) { System.out.println("苹果已经吃完了!哈哈"); eatup = true; } Java实用教程 else { System.out.println("苹果吃不下了!:("); eatup = false; } return eatup; } } Java实用教程 图3.1 自定义类的应用 Java实用教程 1. 类声明的基本格式 访问说明符 class 类名 extends 超类名 implements 接口名 其中: (1) 访问说明符为public或者缺省。public用来声明该类为公 有类,可以被别的对象访问。声明为公有的类存储的文件名为 类名。 (2) 类名:用户自定义的标识符,用来标志这个类的引用。 (3) 超类名:是指已经存在的类,可以是用户已经定义的, 也可以是系统类。 (4) 接口名:即后面讲到的接口。 Java实用教程 例如: public class HelloApplet extends Applet 访问说明符为public,类名HelloApplet,扩展类为JDK包 自带的java.applet.Applet类。由于public的存在,所以文件名 必须存为HelloApplet.java,同类名保持一致。 Java实用教程 2. 类体 类体包括成员变量和方法。 (1) 成员变量:指类的一些属性定义,标志类的静态特征, 它的基本格式如下: 访问说明符 数据类型 变量名 其中: ●访问说明符有public、private和protected三种: public:省略时默认为公有类型,可以由外部对象进行访问。 private:私有类型,只允许在类内部的方法中使用,若从 外部访问,必须通过构造函数间接进行。 Protected:受保护类型,子类访问受到限制。 ● 数据类型包括基本类型以及用户自定义的扩展类型。 Java实用教程 (2) 方法:是类的操作定义,标志类的动态特征,它的基 本格式如下: ●访问说明符 数据类型 方法名(数据类型1 变量名1, 数据 类型2 变量名2) 其中: ●访问说明符为public、private和protected,其使用方法与 成员变量访问说明符的使用方法一致。 ●数据类型:包括基本数据类型和用户自定义的扩展类型。 ●数据类型为参数。 Java实用教程 3. 创建类的实例 使用关键字 new进行创建,例如: HelloApplet hp = new HelloApplet(); 例3.1中,自定义类apple,访问标识符缺省,定义三个属性: long applecolor;//对应苹果的颜色 double appleweight;//苹果的重量 boolean eatup;//是否吃完 Java实用教程 一个方法为: public boolean bite()//类方法{...} 公有类SetApplet中引用自定义类,首先创建类的实例: apple a = new apple(); 其次赋初值: a.appleweight = 0.5;//实例变量赋值 最后调用它的方法: System.out.println(a.bite());//调用实例方法 Java实用教程 3.1.2 类的单继承性 Java编程语言中允许用extends关键字从一个类扩展出一个 新类,新类继承超类的成员变量和方法,并可以覆盖方法。 【例3.2】测试类的单继承性,程序输出结果如图3.2所示。 源程序代码如下: //程序文件名TestExtend.java public class TestExtend extends Employee { public static void main(String[] args) { ",500)); System.out.println("覆盖的方法调用:" + getSalary("王一 Java实用教程 System.out.println("继承的方法调用:" + getSalary2("王一",500)); System.out.println("覆盖的方法调用:" + getSalary("王飞",10000)); System.out.println(“继承的方法调用:” + getSalary2(“王飞 ",10000)); } public static String getSalary(String name, int salary) { String str; if (salary>5000) str = "名字: " + name + " Salary: " + salary; else str = "名字: " + name + " Salary: 低于5000"; Java实用教程 return str; } }; class Employee { public String name;//名字 public int salary;//薪水 public static String getSalary(String name, int salary) { String str; str = "名字: " + name + " Salary: " + salary; return str; } Java实用教程 public static String getSalary2(String name, int salary) { String str; str = "名字: " + name + " Salary: " + salary; return str; } }; Java实用教程 程序中定义了父类Employee类,它有两个方法getSalary和 getSalary2,方法体的实现都是一致的,都为输出名字和薪水 的值。在TextExtend主类中覆盖了getSalary方法,方法体重新 定义为薪水低于5000时并不输出薪水的值而是输出“低于 5000”,用于和继承的getSalary2方法进行比较。由图3.2可以看 出覆盖的方法按主程序中重定义的方法调用,而继承的方法直 接调用父类中的方法。 Java实用教程 图3.2 测试单继承性程序的输出结果 Java实用教程 3.1.3 特殊变量 类中有两个特殊变量super和this。 1. super 类声明中用关键字extends扩展了其超类之后,super用在扩 展类中引用其超类中的成员变量。 【例3.3】使用super变量,输出结果如图3.3所示。源程序 代码如下: //程序文件名为UseSuper.java public class UseSuper { Java实用教程 public static void main(String[] args) { Manager m = new Manager(); m.name = "王飞"; m.salary = 10000; m.department = "业务部"; System.out.println(m.getSalary()); } } class Employee { Java实用教程 public String name;//名字 public int salary;//薪水 //方法 public String getSalary() { String str; str = "名字: " + name + "\nSalary: " + salary; return str; } } class Manager extends Employee Java实用教程 { public String department;//部门 //方法 public String getSalary() { //使用super变量调用超类的方法 return super.getSalary() + "\nDepartment: " + department; } } Java实用教程 图3.3 测试super变量的输出 Java实用教程 2. this this变量指向当前对象或实例。 str = "名字: " + name + "\nSalary: " + salary; 上例中的语句可以换成下面的语句。 str = "名字: " + this.name + "\nSalary: " + this.salary; 这两者是等同的,因为在Java编程语言中,系统自动将this 关键字与当前对象的变量相关联。但有一种情况例外,就是当 在某些完全分离的类中调用一个方法并将当前对象的一个引用 作为参数传递时。例如: Day d = new Day(this); Java实用教程 3.1.4 构造函数 类中的构造函数用来初始化一个类。构造函数为公有类型, 无返回值,用来从类实例中访问类时初始化此类的私有变量。 【例3.4】基于例3.3将公有变量改成私有变量之后,增加两 个构造函数,访问通过外部调用构造函数实现初始化赋值,得 到如图3.3所示的结果。 //程序文件名为UseConstruct.java public class UseConstruct { public static void main(String[] args) { Java实用教程 Manager m = new Manager("王飞",10000,"业务部");//初始化赋值 System.out.println(m.getSalary()); } } class Employee { private String name;//名字 private int salary;//薪水 //构造函数 public Employee(String _name, int _salary) { Java实用教程 name = _name; salary = _salary; } public String getSalary() { String str; str = "名字: " + name + "\nSalary: " + salary; return str; } } class Manager extends Employee { private String department; Java实用教程 //构造函数 public Manager(String _name, int _salary, String _department) { super(_name,_salary); department = _department; } public String getSalary() { return super.getSalary() + "\nDepartment: " + department; } } Java实用教程 3.1.5 包 计算机操作系统使用文件夹或者目录来存放相关或者同类 的文档,在Java编程语言中,提供了一个包的概念来组织相关 的类。包在物理上就是一个文件夹,逻辑上代表一个分类概念。 包就是指一组类。例如一个名叫Company的包,可以包含 一组类,如Employee(雇员)、Manager(管理者)和Department(部 门)等。声明包的基本格式如下: Package 包名; Java实用教程 其中:Package为关键字,包名为标识符。 使用包时的注意事项如下: (1) Package语句要作为程序非注释语句的第一行语句。 (2) 包内的类名惟一。 (3) 引用包中的类时,使用import语句。import语句的基本 格式为import 包名.类名,其中import为关键字,包名和类名之 间用圆点(.)隔开。 Java实用教程 【例3.5】编写程序测试包,先建立一个Company文件夹,然 后建立名为Manager.java的类文件。源程序代码如下: //程序文件名为Manager.java package Company;//声明包名Company class Employee { public String name;//名字 public int salary;//薪水 public String getSalary() { Java实用教程 String str; str = "名字: " + name + "\nSalary: " + salary; return str; } } public class Manager extends Employee { public String department;//部门 public String getSalary() { return super.getSalary() + "\nDepartment: " + department; } } Java实用教程 对此文件进行编译,生成类文件Manager.class。 在原目录建立源程序文件UsePackage.java。源程序代码如下: //程序文件名UsePackage.java import Company.Manager;//引入包中的类 public class UsePackage { public static void main(String[] args) { Manager m = new Manager(); m.name = "王飞"; m.salary = 10000; m.department = "业务部"; System.out.println(m.getSalary()); } } Java实用教程 编译后,在命令提示符状态下运行,输出结果如图3.4所 示。从图3.4中可以看出首先进入Company目录,编译 Manager.java文件,然后返回上层目录,编译UsePackage.java 文件,最后执行UsePackage类文件,输出正确的结果。 Java实用教程 图3.4 测试包的输出结果 Java实用教程 3.2 接 口 Java编程语言中禁止多继承属性,但可以通过接口来帮助类 扩展方法。接口中可以定义大量的常量和方法,但其中的方法 只是一种声明,没有具体的实现,使用接口的类自己实现这些 方法。接口与类的不同在于: (1) 没有变量的声明,但可以定义常量。 (2) 只有方法的声明,没有方法的实现。 接口声明的基本格式如下: public interface 接口名 extends 接口列表 Java实用教程 【例3.6】测试接口,定义接口文件Product.java,定义了 两个常量,声明了一个方法。接口文件如下: //程序文件名Product.java public interface Product { static final String MAKER = "计算机制造厂"; static final String ADDRESS = "上海"; public int getPrice(); } Java实用教程 使用接口的源文件代码如下: //程序文件名UseInterface.java public class UseInterface { public static void main(String[] args) { Computer p = new Computer(); System.out.print(p.ADDRESS + p.MAKER); System.out.println(" 计算机的价格:" + p.getPrice()+ " 万元"); } } Java实用教程 class Computer implements Product { public int getPrice() { return 1; } } Java实用教程 首先编译接口文件“javac Product.java”,然后编译使用这 个接口的类文件“javac.UseInterface.java”,最后执行类“java UseInterface”,输出结果如图3.5所示。 图3.5 测试接口的输出结果 Java实用教程 3.3 常用数据结构及类 3.3.1 Vector类 Vector类似于一个数组,但与数组相比在使用上有以下两个 优点。 (1) 使用的时候无需声明上限,随着元素的增加,Vector的 长度会自动增加。 (2) Vector提供额外的方法来增加、删除元素,比数组操作 高效。 Vector类有三个构造函数,分别如下: public Vector(); 该方法创建一个空的Vector。 Java实用教程 public Vector(int initialCapacity); 该方法创建一个初始长度为initialCapacity的Vector。 public Vector(int initialCapacity, int capacityIncrement); 该方法创建一个初始长度为initialCapacity的Vector,当向 量需要增长时,增加capacityIncrement个元素。 Java实用教程 (1) Vector类中添加、删除对象的方法如下: public void add(int index, Object element) 在index位置添加对象element。 public boolean add(Object o) 在Vector的末尾添加对象o。 public Object remove(int index) 删除index位置的对象,后面的对象依次前提。 Java实用教程 (2) Vector类中访问、修改对象的方法如下: public Object get(int index) 返回index位置对象。 public Object set(int index, Object element) 修改index位置的对象为element。 Java实用教程 (3) 其它方法: public String toString() 将元素转换成字符串。 public int size() 返回对象的长度。 Java实用教程 【例3.7】操作Vector对象,进行元素的添加、插入、修改和 删除。程序输出结果如图3.6所示。源程序代码如下: //程序文件名为UseVector.java import java.util.Vector;//引入JDK的Vector类 public class UseVector { public static void main(String[] args) { Java实用教程 Vector vScore = new Vector(); vScore.add(" 86"); //添加元素 vScore.add(" 98"); //添加元素 vScore.add(1, " 99"); //插入元素 //输出结果 for (int I = 0; I < vScore.size(); I++) { System.out.print(vScore.get(i) + " "); } vScore.set(1, " 77"); //修改第二个元素 vScore.remove(0); //删除第一个元素 Java实用教程 System.out.println(″\n修改并删除之后″); for (int I = 0; I< vScore.size(); I++) { System.out.print(vScore.get(i) + " "); } System.out.println(" \n转换成字符串之后的输出\n" + vScore.toString()); } }; Java实用教程 图3.6 操作Vector对象的输出结果 Java实用教程 3.3.2 Hashtable类 Hashtable类存储的是对象的名-值对。将对象的名和它的值 相关联同时存储,并可以根据对象名来提取它的值。在 Hashtable中,一个键名只能对应着一个键值,然而一个键值可 以对应多个键名,键名必须是惟一的。构造函数以及常用方法 如下: public Hashtable() 构建散列表。 public Hashtable(int initialCapacity) 构建长度为initialCapacity的散列表。 public int size() Java实用教程 返回散列表的名的个数。 public Object remove(Object key) 删除散列表中key名及其对应的value值。 public Object put(Object key,Object value) 将对象名key和对象值value存放到散列表中。 public Object get(Object key) 返回散列表key名对应的值。 public String toString() 转换成字符串。 Java实用教程 【例3.8】操作Hashtable对象,进行添加、修改、删除等操 作,输出结果如图3.7所示。源程序代码如下: //程序文件名为UseHashtable.java import java.util.Hashtable; public class UseHashtable { public static void main(String[] args) { Hashtable hScore = new Hashtable(); hScore.put("张一","86"); Java实用教程 hScore.put("李二","98"); hScore.put("海飞","99"); System.out.println("转换成字符串之后的输出:" + hScore.toString()); hScore.put("李二","77"); hScore.remove("张一"); System.out.println("修改并删除之后"); System.out.println("转换成字符串之后的输出:" + hScore.toString()); } } Java实用教程 图3.7 操作Hashtable对象的输出结果 Java实用教程 3.3.3 Enumeration接口 实现Enumeration接口的对象生成一系列元素,通过 nextElement()方法依次读取下一个元素。只有以下两个方法: public boolean hasMoreElements() 测试是否还有元素。 public Object nextElement() 返回枚举的下一个元素。 Enumeration接口及其方法通常与Vector、Hashtable一起连 用,用来枚举Vector中的项和Hashtable中的键名,例如: for (Enumeration e = v.elements() ; e.hasMoreElements() ;) System.out.println(e.nextElement()); Java实用教程 【例3.9】使用Enumeration接口枚举Vector中的对象和 Hashtable对象中的键名,并进行输出,结果如图3.8所示。源 程序代码如下: //程序文件名UseEnumeration.java import java.util.*; public class UseEnumeration { public static void main(String[] args) { Vector vScore = new Vector(); vScore.add("86"); vScore.add("98"); Java实用教程 vScore.add(1,"99"); System.out.println("Vector:" + vScore.toString()); for (Enumeration e = vScore.elements() ; e.hasMoreElements() ;) System.out.println(e.nextElement()); Hashtable hScore = new Hashtable(); hScore.put("张一","86"); hScore.put("李二","98"); hScore.put("海飞","99"); System.out.println("Hashtable:" + hScore.toString()); Java实用教程 for (Enumeration e = hScore.keys() ; e.hasMoreElements() ;) { String str = (String)e.nextElement(); System.out.print(str + ":"); System.out.println(hScore.get(str)); } } } Java实用教程 图3.8 使用Enumeration接口枚举输出 Java实用教程 3.3.4 Date类 Date类用来指定日期和时间,其构造函数及常用方法如下: public Date() 从当前时间构造日期时间对象。 public String toString() 转换成字符串。 public long getTime() 返回自新世纪以来的毫秒数,可以用于时间计算。 Java实用教程 【例3.10】测试执行循环花费的时间(数量级为毫秒),具体 时间情况如图3.9所示。源程序代码如下: //程序文件名为UseDate.java import java.util.Date; public class UseDate { public static void main(String[] args) { Date dOld = new Date(); long lOld = dOld.getTime(); System.out.println("循环前系统时间为:" +dOld.toString()); Java实用教程 int sum = 0; for (int i=0; i<100; i++) { sum += i; } Date dNew = new Date(); long lNew = dNew.getTime(); System.out.println("循环后系统时间为:" +dNew.toString()); System.out.println("循环花费的毫秒数为:" + (lNew - lOld)); } } Java实用教程 图3.9 循环时间测试 Java实用教程 3.3.5 String类 String类用于操作非数值型字符串,它提供了七类方法操 作,分别为字符串创建、字符串长度、字符串比较、字符串检 索、字符串截取、字符串运算和数据类型转换。 1. 字符串创建 public String() 构造一个空字符串。 public String(char[] value) 使用字符数组value中的字符以构造一个字符串。 public String(String original) 使用原字符串original的拷贝以构造一个新字符串。 Java实用教程 2. 字符串长度 public int length() 返回字符串的长度。 3. 字符串比较 public boolean equals(Object anObject) 比较字符串是否与anObject代表的字符串相同(区分大小写)。 public boolean equalsIgnoreCase(String anotherString) 比较字符串是否与anotherString相同(不区分大小写)。 Java实用教程 4. 字符串检索 public int indexOf(String str) 返回一个字符串中str第一次出现所在的位置。 public int indexOf(String str, int fromIndex) 返回从fromIndex开始字符串str出现所在的位置。 Java实用教程 5. 字符串截取 public String substring(int beginIndex, int endIndex) 返回benginIndex到endIndex之间的字符串。 6. 字符串运算 运算符为“+”,表示连接运算。下面的行语句输出连接的字符串。 System.out.println("Hashtable:" + hScore.toString()); Java实用教程 【例3.11】操作字符串,输出结果如图3.10所示。源程序 代码如下: //程序文件名为TestString.java public class TestString { public static void main(String[] args) { String str = new String("The substring begins at the specified beginIndex."); String str1 = new String("string"); String str2 = new String(); int size = str.length();//字符串长度 Java实用教程 int flag = str.indexOf("substring"); str2 = str.substring(flag,flag + 9);//取子字符串 System.out.println("字符串" + str + "\n总长度为:" + size); if(str1.equals(str2))//判断是否相等 System.out.println("截取的字符串为:" + str1); else System.out.println("截取的字符串为:" + str2); } } Java实用教程 图3.10 操作字符串的输出 Java实用教程 7. 数据类型转换 各种原始数据类型与String类型之间可以通过方法相互转换。 valueOf()系列的静态方法用于从其它对象(原始数据类型对 象)转换成字符串。例如: public static String valueOf(Boolean b) public static String valueOf(char c) public static String valueOf(int i) public static String valueOf(long l) public static String valueOf(float f) public static String valueOf(double d) Java实用教程 具体实例如下: (1) 从int转换到String。 例如: int intvar = 1; String strvar; strvar = String.valueOf (intvar); //"1" Java实用教程 (2) 从float转换到String。 例如: float fltvar = 9.99f; String strvar; strvar = String.valueOf(fltvar); //"9.99" Java实用教程 (3) 从double转换到String。 例如: double dblvar = 99999999.99; String strvar; strvar = String.valueOf (dblvar); //"9.999999999E7" Java实用教程 (4) 从char转换到String。 例如: char chrvar = 'a'; String strvar; strvar = String.valueOf (chrvar); //"a" Java实用教程 (5) 从String转换到int、float、long、double。 例如: String intstr = "10"; String fltstr = "10.1f"; String longstr = "99999999"; String dblstr = "99999999.9"; int i = Integer.parseInt(intstr); //10 float f = Float.parseFloat(fltstr); //10.1 long lo = Long.parseLong(longstr); //99999999 double d = Double.parseDouble(dblstr); //9.99999999E7 Java实用教程 (6) 从String转换到byte、short。 例如: String str = "0"; byte b = Byte.parseByte(str); //0 short sh = Short.parseShort(str);//0 Java实用教程 (7) 从String转换到char。 例如: String str = "abc"; char a = str.charAt(0);//返回字符a Java实用教程 (8) 从String转换到boolean。 例如: String str = "true"; Boolean flag = Boolean.valueOf(str);//true Java实用教程 3.3.6 StringBuffer类 StringBuffer类提供了一个字符串的可变序列,类似于String 类,但它对存储的字符序列可以任意修改,使用起来比String类 灵活得多。它常用的构造函数为: StringBuffer() 构造一个空StringBuffer对象,初始容量为16个字符。 StringBuffer(String str) 构造一个StringBuffer对象,初始内容为字符串str的拷贝。 对于StringBuffer类,除了String类中常用的像长度、字 符串截取、字符串检索的方法可以使用之外,还有两个较为 方便的方法系列,即append方法系列和insert方法系列。 Java实用教程 (1) append方法系列根据参数的数据类型在StringBuffer对象 的末尾直接进行数据添加。 public StringBuffer append(boolean b) public StringBuffer append(char c) public StringBuffer append(char[] str) public StringBuffer append(char[] str, int offset, int len) public StringBuffer append(double d) public StringBuffer append(float f) public StringBuffer append(int i) public StringBuffer append(long l) public StringBuffer append(Object obj) public StringBuffer append(String str) public StringBuffer append(StringBuffer sb) Java实用教程 (2) insert方法系列根据参数的数据类型在StringBuffer的 offset位置进行数据插入。 public StringBuffer insert(int offset, boolean b) public StringBuffer insert(int offset, char c) public StringBuffer insert(int offset, char[] str) public StringBuffer insert(int index, char[] str, int offset, int len) public StringBuffer insert(int offset, double d) public StringBuffer insert(int offset, float f) public StringBuffer insert(int offset, int i) public StringBuffer insert(int offset, long l) public StringBuffer insert(int offset, Object obj) public StringBuffer insert(int offset, String str) Java实用教程 (3) 下面这个方法用于将stringbuffer对象的数据转换成字符串: public String toString() Java实用教程 【例3.12】基于例3.11进行修改,使用StringBuffer对象得到 如图3.10所示的输出界面。 //程序文件名为TestString.java public class TestString { public static void main(String[] args) { StringBuffer str = new StringBuffer("The substring begins at the specified beginIndex."); StringBuffer str1 = new StringBuffer("string"); String str2 = new String(); int size = str.length(); int flag = str.indexOf("substring"); Java实用教程 str2 = str.substring(flag,flag + 9); StringBuffer strOut = new StringBuffer("字符串"); strOut.append(str); strOut.append("总长度为:"); strOut.append(size); int f = strOut.indexOf("总"); strOut.insert(f,'\n'); System.out.println(strOut.toString()); if(str1.toString().equals(str2)) System.out.println("截取的字符串为:" + str1.toString()); else System.out.println("截取的字符串为:" + str2); } } Java实用教程 3.3.7 StringTokenizer类 StringTokenizer类是一个实现Enumeration接口的类,它使 得应用程序可以将字符串分成多个记号,默认情况下以空格为 分隔符,例如将字符串“this is a test”分成四个单词记号。用户 也可以指定分隔符。分隔符为false,分割字符串;分隔符为 true,则将分隔符自身作为分割后的字符串的一部分。其构造 函数和常用方法如下: StringTokenizer(String str) 以字符串str构建StringTokenizer对象。 Java实用教程 StringTokenizer(String str, String delim) 使用delim分隔符,以初始字符串str构建StringTokenizer对象。 int countTokens() 返回识别的总记号数。 boolean hasMoreTokens() 测试是否还有识别的记号。 boolean nextToken(String delim) 返回字符串delim分隔的下一个记号。 String nextToken() 返回下一个识别的记号。 Java实用教程 【例3.13】使用StringTokenizer类分割字符串,字符串的分 割情况如图3.11所示。源程序代码如下: import java.util.*; public class UseToken { public static void main(String[] args) { String str = "数学::英语::语文::化学"; StringTokenizer st = new StringTokenizer(str,"::"); System.out.println(str + "\n课程数为:" +st.countTokens()); Java实用教程 while (st.hasMoreTokens()) { System.out.println(st.nextToken("::")); } str = "Hello this is a test"; st = new StringTokenizer(str); System.out.println(str + "\n单词数为:" +st.countTokens()); while (st.hasMoreTokens()) { System.out.println(st.nextToken()); } } } Java实用教程 图3.11 StringTokenizer分割单词的结果输出 Java实用教程 习题 1. 定义一个类Student,属性为学号、姓名和成绩;方法为 增加记录SetRecord和得到记录GetRecord。SetRecord给出学号、 姓名和成绩的赋值,GetRecord通过学号得到考生的成绩。 2. 给出上题中设计类的构造函数,要求初始化一条记录(学 号、姓名、成绩)。 3. 假设一个学生所选课程为语文、数学、英语、政治、物 理、化学,给出此学生所选课程的Vector列表,并访问物理存放 在Vector中的位置。 Java实用教程 4. 对于图3.12中的Shebei表,将设备编码和设备名称作为 Hashtable中的键和值进行存储,然后访问此Hashtable,找到键 0008和0016并输出设备编码为0008、0016的设备名称。 图3.12 习题3.4中的Shebei表 Java实用教程 5. 编写程序,测试字符串“你好,欢迎来到Java世界”的 长度,将字符串的长度转换成字符串进行输出,并对其中的 “Java”四个字母进行截取,输出截取字母以及它在字符串中的 位置。 6. 对于图3.12中的Shebei表,将设备编码和设备名称用 :: 进行连接,形成新的字符串,存储到Vector向量对象中,如 0001::打印机、0008::书桌,然后访问Vector对象中设备编码为 0010、0014的项,使用字符串操作的方法读取这两项设备编码 对应的设备名称并输出。 Java实用教程 7. 编写程序,测试1~50的阶乘所耗费的毫秒级时间。 8. 编写程序,将设备编码对应设备名称的记录添加到一个 StringBuffer对象中,编码和名称之间用::隔开,每条记录之间 用**隔开。 9. 编写程序,将字符串“打印机*钟表//自行车**雨伞%% 收音机??电脑”进行拆分,输出每个设备的名字。 Java实用教程 第4章 Java Applet 4.1 Applet简介 4.2 显示Applet 4.3 载入图片 4.4 载入声音 4.5 Applet控制浏览器环境 4.6 服务器下配置Applet文件 4.7 使用插件载入Applet 4.8 JAR文件 4.9 Applet和应用程序 习题 Java实用教程 4.1 Applet 简 介 4.1.1 Applet的定义 Applet是Java语言编写的,无法独立运行,但可以嵌入到 网页中执行。它扩展了传统的编程结构和方法,可以通过互联 网发布到任何具有Java编译环境浏览器的个体计算机上。 Java实用教程 4.1.2 Applet的用途 用户可以静态显示Applet,像显示一幅图片或者一段文本 一样;Applet也可以是一个动态交互过程,用户输入简单的数 据,就会产生相应的响应。 Java实用教程 4.1.3 Applet的编写格式 编写Applet时,首先要引入java.applet包中的类,这个类里 包含三个接口和Applet的类: import java.applet.*; import java.applet.Applet; 类头定义为: public class MyApplet extends Applet; 用来声明自定义类是从Applet类扩展而来的。 Java实用教程 类体中没有应用程序中必须具备的main方法,取而代之的 是下面几个常用方法: public void init(); 初始化——在这个方法中设置一些变量的初始化,像界面 布局设置等。 public void start() 启动——Applet开始执行。 public void stop() 停止——Applet停止执行。 public void destroy() 撤消——销毁Applet。 Java实用教程 【例4.1】编写Applet,显示系统的当前时间。源程序代码如下: //程序文件名UseApplet.java import java.awt.*; import java.applet.Applet; import java.util.Date; public class UseApplet extends Applet { String strTime = new String(); public void init() { } Java实用教程 public void start() { Date d = new Date(); strTime = d.toString(); repaint(); } public void paint(Graphics g) { g.drawString("当前时间为:" + strTime,20,30); } }; Java实用教程 4.2 显 示 Applet 4.2.1 工作流程 Applet是嵌入在HTML网页中显示的。首先从服务器请求 HTML网页,检测到Applet的类请求时,将所需类下载到本地, 然后运行,其工作流程如图4.1所示。 请 求 HTML页 载 入 HTML页 客户端 Internet 发 现 Applet标 记 请 求 类 文 件 载入类文件 图4.1 客户端显示Applet 服务器 Java实用教程 HTML页面中引用Applet的标签为,浏览 器中执行Applet的步骤如下: (1) 浏览器请求HTML页面。 (2) 读HTML页面的过程中发现标签,然后继续向服 务器请求标签中声明的类文件。 (3) 浏览器获取该类文件。 (4) 字节码验证这个类是否合法。 (5) 如果合法就开始执行类文件。 Java实用教程 有时可能需要载入多个类文件,直到将所有所需的类文件 下载完毕为止。 为上面的UseApplet.class类写一个最简单的网页UseApplet.html: Java实用教程 图4.2 Applet输出时间 Java实用教程 图4.3 网页下显示输出时间的Applet Java实用教程 4.2.2 参数设置 在HTML页面中嵌入Applet类文件时,可以在标签 中设置属性以控制Applet类文件的外观显示,也可以传递一些 用户自定义属性。嵌入的格式为: ... Java实用教程 其中: (1) 标签内为Applet的信息。 (2) 标记在之间进行设置,然后 由Applet自带的方法获取。 (3) 标记有两个自己的属性:name和value。例如: (4) attribute1和attribute2的属性设置如表4.1所示。 Java实用教程 表4.1 属性设置及其描述 属性列表 attribute1 Attribute2 放置 属性 code codebase height width vspace hspace align alt archive object name value 描述 使用的 Applet 类文件的名字 基目录的 URL,Applet 的类文件都存放在这里 Applet 网页上占据的垂直像素高度 Applet 网页上占据的水平像素宽度 Applet 和其它 HTML 语句之间的垂直距离 Applet 和其它 HTML 语句之间的水平距离 与页中其余部分的对齐方式 不显示 Applet 时,显示的实际文本 浏览器预加载的其它文档资源的列表 代替 code 属性出现,将 Applet 类文件作为一个对象调用 Applet 程序中所需参数名 Applet 程序中所需参数传递的值 Java实用教程 其中,code属性是必须的,height和width属性用来设置高 度和宽度,如果都为0,那么Applet将隐藏。 对于例4.1中UseApplet.html,如果有 那么说明网页加载的类名为UseApplet.class,类显示的高度为 200像素点,宽度为300像素点。 表4.1中列出的attibute1属性为定义的属性。用户 还可以根据Applet程序的需要,传递一些程序自身属性,这些 属性通过attribute2中name属性给出所需参数的名,value属性给 出所需参数的值。 public String getParameter(String name) Java实用教程 【例4.2】基于例4.1,在加载类的网页上设置一个用户名, 使得Applet输出为“XXX,你好,当前时间为:(具体时间)”, 如图4.4所示。源程序代码如下: //程序文件名UsePara.java import java.awt.*; import java.applet.Applet; import java.util.Date; public class UsePara extends Applet { String strTime = new String(); String strUser = new String(); public void init() { Java实用教程 //得到网页的参数:用户名 strUser = getParameter("USER"); } public void start() { Date d = new Date(); strTime = d.toString(); repaint(); } public void paint(Graphics g) { g.setColor(Color.red); g.drawString(strUser + " 你好,当前时间为:" + strTime,20,30); } }; Java实用教程 在UseApplet.html中添加一个用户参数设置: 使修改后的网页程序如下: Java实用教程 图4.4 网页设置参数后的Applet输出 Java实用教程 放在浏览器中查看时,显示效果如图4.5所示。 图4.5 浏览器中查看获取网页参数的Applet输出 Java实用教程 4.2.3 生命周期 Applet的生命周期是指Applet存在的时间,即某些方法还在 被调用的时间。根据Applet的四个方法init()、start()、stop()、 destroy(),可以得出Applet的生命周期,如图4.6所示。 初始化 离开网页 启动 停止 重新加载浏览器或 改变浏览器尺寸或 返回网页 退出浏览器 撤消 图4.6 Applet的生命周期 Java实用教程 4.3 载 入 图 片 在java.applet包中存在一个接口AppletStub。当一个Applet创 建之后,一个Applet Stub使用setStub方法附加到Applet上,这个 Stub用来充当Applet和浏览器环境之间的接口。在这个接口中一 个重要的方法: public URL getDocumentBase() 该方法返回的是Applet类文件所在网页的网络路径。 例如,如果一个Applet类文件嵌入在下面网页中 http://java.sun.com/products/jdk/1.2/index.html 那么返回的路径为 http://java.sun.com/products/jdk/1.2/ Java实用教程 通过这个网络路径可以得到图片,从而由Applet类载入, 载入图片的方法为: public Image getImage(URL url, String name) 其中: (1) url给出图片所在的网路路径。 (2) name给出图片的名字。 例如:url路径可以为http://java.sun.com/products/jdk/1.2/, 而name可以为路径下的图片index_01.gif。 Java实用教程 【例4.3】编写Applet,载入Applet类文件所在路径下的图片 index_01.gif,然后如图4.7所示显示图片。源程序代码如下: //程序文件名UseImage.java import java.awt.*; import java.applet.Applet; import java.net.*; public class UseImage extends Applet { //定义图像对象 Image testImage; public void init() { Java实用教程 //得到图片 testImage = getImage(getDocumentBase(),"index_01.gif"); } public void paint(Graphics g) { g.drawImage(testImage,0,0,this); } } 载入UseImage.class类的UseImage.html文件如下: Java实用教程 图4.7 Applet载入图片显示 Java实用教程 4.4 载 入 声 音 Applet类提供一个用于载入声音的方法,即 public AudioClip getAudioClip(URL url, String name) 该方法返回由url和name决定的AudioClip对象。 其中: (1) url:音频剪辑的绝对URL地址; (2) name:相对于上面的url,为音频剪辑的相对地址,通 常指名字。 Java实用教程 【例4.4】编写载入声音的Applet。源程序代码如下: //程序文件名UseAudio.java import java.awt.*; import java.applet.Applet; public class UseAudio extends Applet { public void init() { } public void start() { //播放Applet所在目录下的tiger.au声音文件 getAudioClip(getDocumentBase(),"tiger.au").play(); Java实用教程 } }; 载入类的HTML文件如下: 在浏览器加载或者appletviewer命令启动时可以听见老虎的 叫声,但必须保证tiger.au在UseAudio.class类文件所在的目录。 Java实用教程 4.5 Applet控制浏览器环境 java.applet包中提供一个接口AppletContext,对应着Applet 的环境,主要指包含Applet的网页文档等,在这个接口内有两 个重要方法: pubilc void showDocument(URL url) 浏览器下载Applet时,showDocument可以将当前Applet页 面用于显示url网址的内容。 url 给出页面的绝对网络路径。 public void showDocument(URL url, String target) target可以表明url显示的位置,有四种情况,如表4.2所示。 Java实用教程 表4.2 target 取 值 target 选项 _self _parent _top _blank 描述 将 url 表示的页面显示在 Applet 框架中 将 url 表示的页面显示在父框架中,如果不存在,情况如同_self 将 url 表示的页面显示在 Applet 窗口的顶层框架,如果不存在,情况如同_self 将 url 表示的页面显示在新窗口中 public void showStatus(String status) 字符串status显示在状态栏中,告知用户当前类文件运行中的状态。 Java实用教程 【例4.5】编写Applet,在状态栏显示鼠标单击Applet的次数, 结果如图4.8所示。源程序代码如下: //程序文件名ShowStatus.java import java.applet.*; import java.applet.Applet; import java.awt.event.*; public class ShowStatus extends Applet { int count = 0; public void init() Java实用教程 { } public boolean mouseClicked(MouseEvent e) { count ++; getAppletContext().showStatus("你好,你已经点击 了" + count + "次了!"); return true; } }; Java实用教程 图4.8 状态栏显示单击次数信息 Java实用教程 【例4.6】编写Applet,在一个框架中显示不同来源的网页 信息,如图4.9所示。左框架为西安交通大学首页,右框架为新 浪网首页。源程序代码如下: //程序文件名ShowHtml.java import java.applet.*; import java.applet.Applet; import java.net.URL; public class ShowHtml extends Applet { public void init() { } Java实用教程 public void start() { try { //创建URL对象 URL urlName=new URL("http://www.xjtu.edu.cn"); //在左框架显示网页 getAppletContext().showDocument(urlName,"left"); urlName = new URL("http://www.sina.com.cn"); //右框架显示网页 getAppletContext().showDocument(urlName,"right"); } Java实用教程 catch(MalformedURLException e) { System.out.println(e.getMessage()); } } } 载入Applet的网页Head.html的代码如下: Java实用教程

这是一个框架网页,上面的框架隐藏载入applet类文件,由 applet控制左框架显示西安交通大学的主页,右框架显示新浪网的主 页。 装配的框架网页ShowHtml.html的源代码如下,可以看见其中框架名 字左边的为left而右边的为right。 Java实用教程 Java实用教程 图4.9 框架网页显示 Java实用教程 4.6 服务器下配置Applet文件 由于Applet文件是客户端浏览器从服务器端下载的HTML网 页,所以将文件配置到服务器端,由客户进行访问。 本机中使用的服务器为Tomcat 4.0,安装成功后重启动,则 服务器开始运转,在浏览器的网址栏键入 http://192.100.100.43:8080/index.html,如果出现如图4.10所示的 Tomcat主网页,则证明服务器测试正常。 Java实用教程 图4.10 Tomcat主页 Java实用教程 配置自己的文件时,推荐在安装目录D:\Apache Tomcat 4.0\webapps\ROOT下建立自己的文件夹,这样有利于管理。本 书作者在此文件夹下建立user目录,以为载入图片的Applet为例, 将UseImage.html、UseImage.class和Image_01.gif拷贝到user目录 下,并在IE浏览器的地址栏键入网址: http://192.100.100.43:8080/user/UseImage.html,浏览器显示结果 如图4.11所示,与前面例4.3中图4.7载入的图片效果一致,但可 以看出地址栏的网址不同。 Java实用教程 图4.11 配置到服务器端的网页显示 Java实用教程 4.7 使用插件载入Applet Java插件(Plug-in)扩展了网络浏览器的功能,使得无论在哪 个浏览器(IE浏览器或者Netscape浏览器)下,Java Applet可在Sun 的Java运行环境(JRE)下运行,而不是在浏览器自带的JRE环境下 运行。Java插件是Sun的JRE环境的一部分,当安装JRE时,插件 自动安装。当你安装J2sdk-1.4.0_01时,JRE环境版本号也为 1.4.0_01。使用插件最大的不同是将IE浏览器中网页原有的 标签改成了标签,在Netscape中则改成, 这里只讨论IE浏览器中的使用。 Java实用教程 J2sdk1.4提供了一个叫做HtmlConverter的工具,用于将包含 普通标签的HTML文件转换成包含对象的文件。在命令 行提示符键入命令HtmlConverter后按回车键,出现如图4.12所示 对话框。 其中: (1) “指定文件”为要转换的文件。 (2) “模板文件”为操作系统和浏览器适用类型,操作系统有 Windows和Solaris,浏览器分为IE和Netscape。本书选择适用于 Windows和Solaris的IE浏览器。 Java实用教程 (3) 在“适用于小应用程序的Java版本”栏中选中第一项 “只适用于Java1.4.0_01”,这是因为作者使用的JDK安装版本为 Java1.4.0_01。 将这几项进行设置之后,单击“转换”按钮,则将原有的 UseImage.html文件内容转换为: Java实用教程 --> . HtmlConverter Java实用教程 图 4 12 工 具 界 面 Java实用教程 其中codebase="http://java.sun.com/products/plugin/autodl/jinstall1_4_0_01-win.cab#Version=1,4, 0, 10">表示如果客户端浏览器 不存在此插件,可以从codebase指定的网址下载,由上述语句 行可以看出HtmlConverter生成的插件文件的插件下载地址为 Sun公司的网站。如果本机上放置了插件的安装程序,那么此 处可以改为从本机下载,以加快下载速度。如果在网站上发布 你的Applet的网页,建议使用插件方式载入Applet,可以与多 种浏览器兼容。 Java实用教程 4.8 JAR 文 件 4.8.1 操作JAR文件 在JDK的安装目录的bin子目录下有一个jar.exe文件,这就 是JAR文件的操作工具,用它及一系列选项来实现对JAR文件的 操作。jar命令的格式如下: jar {ctxu}[vfm0M] [jar-文件] [manifest-文件] [-C 目录] 文件名 ... Java实用教程 其中: (1) ctxu四者必选其一,各选项的含义如下: -c 创建新的存档; -t 列出存档内容的列表; -x 展开存档中命名的(或所有的)文件; -u 更新已存在的存档。 Java实用教程 (2) vfm0M为可选项,各选项的含义如下: -v 生成详细输出到标准输出上; -f 指定存档文件名; -m 包含来自标明文件的标明信息; -0 只存储方式,未用ZIP压缩格式; -M 不产生所有项的清单(manifest)文件; -C 改变到指定的目录,并且包含下列文件。 Java实用教程 (3) 清单(manifest)文件名和存档文件名都需要指定,指定的 顺序依照命令行中“m”和“f”标志的顺序。 例如: ① 将两个class文件存档到一个名为“classes.jar”的存档文件 中: jar cvf classes.jar Foo.class Bar.class ② 用一个存在的清单(manifest)文件“mymanifest”将foo/目录 下的所有文件存档到一个名为“classes.jar”的存档文件中: jar cvfm classes.jar mymanifest -C foo/ . 对JAR文件常用的操作有三种:创建JAR文件、列出JAR文 件和抽取JAR文件。 Java实用教程 1. 创建JAR文件 jar cvf UseImage.jar UseImage.class index_01.gif 当用JAR工具创建新的档案时,自动增加一个声明文件到 文档中。如果用户需要创建自己的声明文件时,则指定m选项。 可以看到本目录下多了一个UseImage.jar文件。创建JAR文件的 过程如图4.13所示。 图4.13 创建JAR文件 Java实用教程 2. 列出JAR文件的内容 jar tvf UseImage.jar 执行命令后列出JAR文件中的内容,如图4.14所示。 图4.14 列出JAR文件 Java实用教程 3. 抽取JAR文件 jar xvf UseImage.jar 抽取JAR文件是将JAR中包含的类以及相关文件逐一恢复。 在E:\_Work\Java\sample目录下建立JAR文件夹,将JAR文件放 入此文件夹,然后进行抽取,可以看见JAR目录下除了 UseImage.class和index_01.gif,还有META-INF子目录,下面有 一个文件MANIFEST.MF。图4.15给出抽取JAR文件的过程。 Java实用教程 图4.15 抽取JAR文件 Java实用教程 4.8.2 客户端使用JAR文件 标签中添加一个属性名字为archive,它的值为要载 入的.jar文件。例如archive="UseImage.jar"。 例如,将D:\Apache Tomcat 4.0\webapps\ROOT\user\UseImage.html文件代码改为: Java实用教程 4.9 Applet和应用程序 【例4.7】修改例4.1的Applet,使得它可以从命令提示符状 态下访问。 (1) 基于例4.1的UseApplet添加一个main方法如下: public static void main(String[] args) { //创建一个框架 Frame f = new Frame("时间"); //关闭窗口时退出系统 f.addWindowListener(new WindowAdapter() { Java实用教程 public void windowClosing(WindowEvent evt) { System.exit(0); } }); //创建一个AppletApp对象 AppletApp a = new AppletApp(); //将对象载入框架 f.add("Center",a); //设置框架大小 f.setSize(300,200); //显示框架 Java实用教程 f.show(); //初始化对象 a.init(); //启动对象 a.start(); } Java实用教程 (2) 修改后的源程序代码如下: //程序文件名AppletApp.java import java.awt.*; import java.awt.event.*; import java.applet.Applet; import java.util.Date; public class AppletApp extends Applet { String strTime = new String(); public void init() { } Java实用教程 public void start() { Date d = new Date(); strTime = d.toString(); repaint(); } public void paint(Graphics g) { g.drawString("当前时间为:" + strTime,20,30); } public static void main(String[] args) { Java实用教程 //创建一个框架 Frame f = new Frame("时间"); //关闭窗口时退出系统 f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent evt) { System.exit(0); } }); //创建一个AppletApp对象 AppletApp a = new AppletApp(); Java实用教程 a.init(); //将对象载入框架 f.add("Center",a); f.setSize(200,400); f.show(); a.start(); } }; Java实用教程 (3) 编译通过并生成UseApplet.class类后,在命令提示符状 态下键入“java UseApplet”,得到如图4.2所示的时间输出界面。 Java实用教程 【例4.8】修改例4.2,在命令提示符状态下输入用户名参数, 使得可以在命令提示符状态下进行访问。 (1) 从命令行状态输入用户名参数,应用程序的读取如下: if (args.length < 1) { System.out.println("缺少用户参数"); System.exit(0); } else strUser = new String(args[0]); Java实用教程 (2) 添加一个变量 static boolean inApplet = true; 用于控制取参数的方式,如果以应用程序调用,则从命令 行取参数;如果是载入Applet,则从网页中取参数。 Java实用教程 (3) 源程序代码如下: //程序文件名AppPara.java import java.awt.*; import java.awt.event.*; import java.applet.Applet; import java.util.Date; public class AppPara extends Applet { String strTime = new String(); static String strUser = new String(); static boolean inApplet = true; public void init() { Java实用教程 //如果从Applet载入,从网页得到参数 if(inApplet) strUser = getParameter("USER"); } public void start() { Date d = new Date(); strTime = d.toString(); repaint(); } public void paint(Graphics g) { Java实用教程 g.setColor(Color.red); g.drawString(strUser + " 你好,当前时间为:" + strTime,20,30); } public static void main(String[] args) { inApplet = false; //如果从命令行提示符状态进入,获取参数 if (args.length < 1) { System.out.println("缺少用户参数"); System.exit(0); } else Java实用教程 strUser = new String(args[0]); //创建一个框架 Frame f = new Frame("时间"); //关闭窗口时退出系统 f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent evt) { System.exit(0); } }); //创建一个AppletApp对象 AppPara a = new AppPara(); Java实用教程 //初始化 a.init(); //将对象载入框架 f.add("Center",a); //设置框架大小 f.setSize(400,200); //显示框架 f.show(); //启动对象 a.start(); } } Java实用教程 (4) 在命令提示符状态键入命令“java AppPara 王飞”后 按回车键,弹出如图4.5所示的界面。 Java实用教程 习题 1. 编写Applet,载入图片的同时响起音乐。 2. 将上题的Applet类、图片文件、音乐文件进行压缩并生成 JAR文件,然后载入运行。 Java实用教程 3. 编写程序,既可用作Applet,又可用作应用程序,在出 现的界面中显示下面的内容,括号内表示显示的颜色。 特点:(蓝色显示) (1) 跨平台性(以下均为红色显示) (2) 面向对象 (3) 安全性 (4) 多线程 (5) 简单易用 Java实用教程 4. 在上题的基础上,输入参数“Java语言”,使得显示内 容如下所示,要求既可以从命令行输入,也可以从网页内输入。 Java语言特点: (1) 跨平台性 (2) 面向对象 (3) 安全性 (4) 多线程 (5) 简单易用 Java实用教程 第5章 Java图形处理 5.1 Java图形 5.2 Paint方法、Update方法和Repaint方法 5.3 Graphics类 5.4 Color类 5.5 Graphics2D类 习题 Java实用教程 5.1 Java图形 抽象窗口化工具(AWT)为图形用户界面编程提供API编程接 口,使得Java可以提供较好的图形用户界面。AWT把图形处理 分为两个层次:一是处理原始图形,这一层较原始,图形直接 以点、线和面的形式画到界面上;二是提供大量组件,实现可 定制的图形用户界面。本章主要讨论如何在界面上画图形及所 画图形的特征。Java编程语言中的图形坐标系统不同于数学中的 坐标系,屏幕左上角为(0,0),右下角为屏幕水平向右和垂直向 下增长的像素数。 Java实用教程 5.2 Paint方法、Update方法和Repaint方法 1. Paint方法 public void paint(Graphics g) 以画布为参数,在画布上执行画图方法。在Applet中,不显 式地调用paint方法。 2. Repaint方法 Applet重画时系统自动调用paint方法。 3. Update方法 public void update(Graphics g) 更新容器,向Repaint发出刷新小应用程序的信号,缺省的 Update方法清除Applet画图区并调用Paint方法。 Java实用教程 5.3 Graphics类 Graphics类是所有图形上下文的抽象基类,允许应用程序在 各种设备上实现组件的画图。图形对象封装了Java支持的基本渲 染操作的状态信息,包括画图的组件对象、渲染区域的坐标 (coordinates)、区域(clip)、颜色(color)、字体(font)、画图模式等。 Graphics类提供画各种图形的方法,其中包括线、圆和椭圆、矩 形和多边形、图像以及各种字体的文本等。这些方法具体如下: public abstract void clipRect(int x, int y, int width, int height) 指定的区域切分。 Java实用教程 public abstract void drawLine(int x1, int y1, int x2, int y2) 使用当前颜色,在点(x1, y1) 和 (x2, y2) 之间画线。 public abstract void drawOval(int x, int y, int width, int height) 画椭圆。 public abstract void fillOval(int x, int y, int width, int height) 画实心椭圆。 public abstract void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) 画x和y坐标定义的多边形。 Java实用教程 public void drawRect(int x, int y, int width, int height) 画矩形。 public void drawRect(int x, int y, int width, int height) 画实心矩形。 public abstract void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) 使用当前颜色画圆角矩形。 public abstract void drawString(String str, int x, int y) 使用当前字体和颜色画字符串str。 Java实用教程 public abstract void setColor(Color c) 设置图形上下文的当前颜色。 public abstract void setPaintMode() 设置画模式。 public abstract boolean drawImage(Image img, int x, int y, ImageObserver observer) 画特定图。 public abstract void setFont(Font font) 设置特定的font字体。使用时首先得到font对象的一个实例, Font类常用构造函数为: public Font(String name, int style, int size) Java实用教程 通过指定的name、style和size创建字体实例。name指字体 名,像“隶书”、“TimesRoman”等,字体风格为粗体、斜体, size指字号大小。 例如: Font f = new Font("TimesRoman",Font.BOLD + Font.ITALIC, 12); 创建了具有粗斜体风格的12磅的TimesRoman字体。 Java实用教程 【例5.1】设置Graphics对象画图,显示结果如图5.1所示。源 程序代码如下: //程序文件名SimpleGUI.java import java.awt.*; import java.applet.*; public class SimpleGUI extends Applet { Image samImage; public void init() { samImage=getImage(getDocumentBase(),"sample.gif"); Java实用教程 } public void paint(Graphics g) { //g.clipRect(50,50,180,180); //画线 g.drawLine(0,0,20,30); //输出字符串 g.drawString("图形显示",100,30); //设置颜色 Color c = new Color(255,200,0); g.setColor(c); //设置字体 Java实用教程 Font f = new Font("TimesRoman",Font.BOLD+ Font.ITALIC,24); g.setFont(f); g.drawString("图形显示",180,30); g.drawLine(20,20,100,50); g.drawLine(20,20,50,100); //矩形 g.drawRect(40,40,40,40); g.fillRect(60,60,40,40); g.setColor(Color.red); //3D矩形 g.draw3DRect(80,80,40,40,true); Java实用教程 g.draw3DRect(100,100,40,40,false); g.fill3DRect(120,120,40,40,true); //椭圆 g.drawOval(150,150,30,40); g.fillOval(170,170,20,20); g.setColor(Color.blue); //圆角矩形 g.drawRoundRect(180,180,40,40,20,20); g.fillRoundRect(200,200,40,40,20,20); Java实用教程 //多边形 int xC[] = {242,260,254,297,242}; int yC[] = {240,243,290,300,270}; g.drawPolygon(xC,yC,5); //图片 g.drawImage(samImage,250,50,this); } } Java实用教程 图5.1 简单的图形界面 Java实用教程 将例5.1注释的程序语句 // g.clipRect(50,50,180,180); 的注释符号去掉,重新编译执行,可以看见如图5.2所示的结果。 图5.2 裁剪后的图形界面 Java实用教程 5.4 Color类 Color类是用来封装颜色的,在上面的例子中多次用到。使 用Color对象较为简单的方法是直接使用Color类提供的预定义的 颜色,像红色Color.red、橙色Color.orange等;也可以使用RGB 颜色模式进行定义。所谓RGB颜色模式是指使用三种基色:红、 绿、蓝,通过三种颜色的调整得出其它各种颜色,这三种基色 的值范围为0~255。例如Color c = new Color(255,200,0);定义橙 色。表5.1给出常用颜色的RGB值以及对应的类预定义参数。 Java实用教程 表5.1 常用颜色的RGB值以及对应的类预定义参数 颜色名 白色 浅灰色 灰色 深灰色 黑色 红色 粉红色 橙色 黄色 绿色 品红色 深蓝色 蓝色 预定义颜色值 Color.white Color.lightGray Color.gray Color.darkGray Color.black Color.red Color.pink Color.orange Color.yellow Color.green Color.magenta Color.cyan Color.blue 红色值 255 192 128 64 0 255 255 255 255 0 255 0 0 绿色值 255 192 128 64 0 0 175 200 255 255 0 255 0 蓝色值 255 192 128 64 0 0 175 0 0 0 255 255 255 Java实用教程 Color还有一个构造函数,它构造的Color对象用于是否透 明显示颜色。 public Color(int red, int green, int blue, int alpha) 其中:前三个分量即RGB颜色模式中的参数,第四个alpha 分量指透明的程度。当alpha分量为255时,表示完全不透明, 正常显示;当alpha分量为0时,表示完全透明,前三个分量不 起作用,而介于0~255之间的值可以制造出颜色不同的层次效 果。 Java实用教程 【例5.2】测试Color对象,界面如图5.3所示。源程序代码如下: //程序文件名UseColor.java import java.awt.*; import java.applet.*; import java.awt.geom.*; public class UseColor extends Applet { public void paint(Graphics oldg) { Graphics2D g = (Graphics2D)oldg; Java实用教程 g.setColor(Color.blue); g.fill(new Ellipse2D.Float(50,50,150,150)); g.setColor(new Color(255,0,0,0)); g.fill(new Ellipse2D.Float(50,50,140,140)); g.setColor(new Color(255,0,0,64)); g.fill(new Ellipse2D.Float(50,50,130,130)); g.setColor(new Color(255,0,0,128)); g.fill(new Ellipse2D.Float(50,50,110,110)); g.setColor(new Color(255,0,0,255)); g.fill(new Ellipse2D.Float(50,50,90,90)); g.setColor(new Color(255,200,0)); g.fill(new Ellipse2D.Float(50,50,70,70)); } } Java实用教程 图5.3 颜色测试界面 Java实用教程 5.5 Graphics2D类 Graphics2D类继承于Graphics类,提供几何学、坐标变换、 颜色管理以及文本排列等的更高级控制。Graphics2D类是Java平 台上渲染二维图形、文字、以及图片的基础类,提供较好的对绘 制形状、填充形状、旋转形状、绘制文本、绘制图像以及定义颜 色的支持。 在AWT编程接口中,用户通过Paint方法接收Graphics对象作 为参数,若是使用Graphics2D类,就需要在Paint方法中进行强制 转换。 Public void paint(Graphics old) { Graphics2D new = (Graphics2D)old; } Java实用教程 5.5.1 绘制形状 Graphics2D提供以下两个方法进行形状的绘制: public abstract void draw(Shape s) 根据Graphics2D的环境设置画出形状s,其中Shape接口包 含的类如表5.2所示。 public abstract void fill(Shape s) 画实心形状s。 Java实用教程 表5.2 Graphics2D绘制的图形类 类 Line2D Rectangle2D RoundRectangle2D Ellipse2D GeneralPath 描述 线 矩形 圆角矩形 椭圆 几何路径 Java实用教程 其中GeneralPath是一般的几何路径,它的构造函数为: public GeneralPath() 构造一个空的对象。 常用的方法有四个,分别如下: public void lineTo(float x, float y) 从当前坐标点到(x,y)坐标点画一条直线,将此点添加到路径上。 public void moveTo(float x, float y) 移动到坐标点(x,y),在路径上添加此点。 Java实用教程 public void quadTo(float x1, float y1, float x2, float y2) 以坐标点(x1,y1)为控制点,在当前坐标点和坐标点(x2, y2)之间插入二次曲线片断。 public void curveTo(float x1, float y1, float x2, float y2, float x3, float y3) 以(x1,y1)和(x2,y2)为控制点,在当前坐标点和(x3,y3) 之间插入曲线片断。 Java实用教程 在Draw方法中提到Graphics2D的环境设置。所谓的环境设 置是指设置画图的笔画和填充属性等,设置方法分别如下: public abstract void setStroke(Stroke s) 设置笔画的粗细。其中Stroke接口中常用BasicStroke类来实 现,一个较简单的构造函数为 public BasicStroke(float width) 创建实线笔画宽度为width。 public abstract void setPaint(Paint paint) Java实用教程 设置Graphics2D环境的填充属性。其中,paint的值可以为渐 变填充类java.awt.GradientPaint,也可以为图形填充类 java.awt.TexturePaint,后者将在5.5.3节绘制图像中讲到。渐变填 充类常用构造函数为 public GradientPaint(float x1, float y1, Color color1, float x2, float y2, Color color2, boolean cyclic) 构建一个渐变GradientPaint对象,在起始坐标点到目标坐标 点之间从颜色color1到color2渐变,cyclic为真,循环渐变。 Java实用教程 【例5.3】演示了几何形状、笔画变换以及颜色渐变显示。 其中直线的笔画宽度为10,其它笔画宽度为5,中间三个图形实 现绿色到蓝色的循环渐变,后三个图形实现红色到黄色的循环 渐变,如图5.4所示。 //程序文件名GUI2D.java import java.awt.*; import java.applet.*; import java.awt.geom.*; public class GUI2D extends Applet { Java实用教程 public void paint(Graphics oldg) { Graphics2D g = (Graphics2D)oldg; //设置笔画宽度 BasicStroke stroke = new BasicStroke(10); g.setStroke(stroke); //画线 Line2D line = new Line2D.Float(0,0,20,30); g.draw(line); line = new Line2D.Float(50,50,100,50); g.draw(line); Java实用教程 line = new Line2D.Float(50,50,50,100); g.draw(line); stroke = new BasicStroke(5); g.setStroke(stroke); //设置渐变填充 GradientPaint gt = new GradientPaint(0,0,Color.green,50,30,Color.blue,true); g.setPaint((Paint)gt); //画矩形 Rectangle2D rect = new Rectangle2D.Float(80,80,40,40); Java实用教程 g.draw(rect); rect = new Rectangle2D.Float(100,100,40,40); g.fill(rect); //画椭圆 Ellipse2D ellipse = new Ellipse2D.Float(120,120,30,40); g.draw(ellipse); gt = new GradientPaint(0,0,Color.red,30,30,Color.yellow,true); g.setPaint((Paint)gt); ellipse = new Ellipse2D.Float(140,140,20,20); g.fill(ellipse); Java实用教程 //画圆角矩形 RoundRectangle2D roundRect = new RoundRectangle2D.Float(160,160,40,40,20,20); g.draw(roundRect); roundRect = new RoundRectangle2D.Float(180,180,40,40,20,20); g.fill(roundRect); //画几何图形 GeneralPath path = new GeneralPath(); path.moveTo(150,0); path.lineTo(160,50); path.curveTo(190,200,240,140,200,100); g.fill(path); } } Java实用教程 图5.4 通过Graphics2D对象绘制形状 Java实用教程 5.5.2 绘制文本 Graphics2D类提供一个文本布局(TextLayout)对象,用于实 现各种字体或段落文本的绘制。其构造函数为: public TextLayout(String string, Font font, FontRenderContext frc) 通过字符串string和字体font构造布局。 public void draw(Graphics2D g2, float x, float y) 将这个TextLayout对象画到Graphics2D对象g2上的x,y坐标 处。 public Rectangle2D getBounds() 返回TextLayout对象的区域。 Java实用教程 【例5.4】测试绘制文本功能,如图5.5所示。源程序代码如下: //程序文件GUIText.java import java.awt.*; import java.applet.*; import java.awt.geom.*; import java.awt.font.*; public class GUIText extends Applet { public void paint(Graphics oldg) { Java实用教程 Graphics2D g = (Graphics2D)oldg; //设置字体 Font f1 = new Font("Courier",Font.PLAIN,24); Font f2 = new Font("helvetica",Font.BOLD,24); FontRenderContext frc = g.getFontRenderContext(); String str = new String("这是一个文本布局类的实现"); String str2 = new String("扩充绘制文本的功能"); //构造文本布局对象 TextLayout layout = new TextLayout(str, f1, frc); Point2D loc = new Point2D.Float(20,50); Java实用教程 //绘制文本 layout.draw(g, (float)loc.getX(), (float)loc.getY()); //设置边框 Rectangle2D bounds = layout.getBounds(); bounds.setRect(bounds.getX()+loc.getX(), bounds.getY()+loc.getY(), bounds.getWidth(), bounds.getHeight()); g.draw(bounds); layout = new TextLayout(str2,f2,frc); g.setColor(Color.red); layout.draw(g,20,80); } } Java实用教程 图5.5 Graphics2D对象绘制文本 Java实用教程 5.5.3 绘制图像 绘制图像用到BufferedImage类,BufferedImage类是指存放 图像数据的可访问的缓冲。其构造函数为: public BufferedImage(int width, int height, int imageType) 使用宽度(width)、高度(height)和imageType类型构造 BufferedImage对象。 public Graphics2D createGraphics() Java实用教程 用图片填充椭圆的具体过程如下: (1) 创建一个Graphics2D,可以画到BufferedImage中。 例如构建一个BufferedImage对象buf。 BufferedImage buf = new BufferedImage (img.getWidth(this), img.getHeight(this),BufferedImage.TYPE_INT_ARGB); 创建一个临时Graphics2D对象: Graphics tmpG = buf.createGraphics(); 将图像画入临时缓冲: tmpG.drawImage(img,10,10,this); Java实用教程 (2) 用TexturePaint类进行填充: public TexturePaint(BufferedImage txtr, Rectangle2D anchor) 构造TexturePaint对象,需要一个Rectangle2D对象来存放该对象: Rectangle2D rect = new Rectangle2D.Float(0,0,h,w); TexturePaint t = new TexturePaint(buf,rect); (3) 然后设置填充模式,并进行填充: g.setPaint(t); g.fill(new Ellipse2D.Float(100,50,60,60)); Java实用教程 【例5.5】完成图像显示,并将区域蓝色透明显示,然后进 行图片填充,如图5.6所示。源程序代码如下: //程序文件名GUIImage.java import java.awt.*; import java.applet.*; import java.awt.geom.*; import java.awt.font.*; import java.awt.image.*; import java.net.*; Java实用教程 public class GUIImage extends Applet { public void paint(Graphics oldg) { Graphics2D g = (Graphics2D)oldg; try { URL imgURL = new URL(getDocumentBase(),"sample.gif"); Image img = getImage(imgURL); int h = img.getHeight(this); int w = img.getWidth(this); Java实用教程 //构造缓冲图像对象 BufferedImage buf = new BufferedImage(w,h,BufferedImage.TYPE_INT_ARGB); //放入临时图形类 Graphics tmpG = buf.createGraphics(); tmpG.drawImage(img,10,10,this); g.drawImage(buf,10,20,this); //设置透明颜色对象 Color transBlue = new Color(0,0,255,100); g.setColor(transBlue); GeneralPath path = new GeneralPath(); Java实用教程 path.moveTo(60,0); path.lineTo(50,100); path.curveTo(160,230,240,140,200,100); g.fill(path); transBlue = new Color(0,0,255,240); g.fill(new Ellipse2D.Float(100,100,50,50)); Rectangle2D rect = new Rectangle2D.Float(0,0,h,w); //图片填充 TexturePaint t = new TexturePaint(buf,rect); Java实用教程 g.setPaint(t); g.fill(new Ellipse2D.Float(100,50,60,60)); } catch(Exception e) { System.out.println("Error:" + e.getMessage()); } } } Java实用教程 图5.6 通过Graphics2D对象绘制图像 Java实用教程 习题 1. 使用Graphics类进行图形绘制,要求绘制深蓝色矩形和红 色椭圆形,然后分别进行填充。 2. 使用Graphics2D类绘制粉红色到蓝色的渐变,填充到圆 角矩形、多边形,笔画宽度为10。 3. 绘制文本“欢迎来到Java世界”,其中“欢迎来到”为 蓝色显示,而“Java世界”为橙色显示,文本用矩形框起来, 底色为黄色。 4. 画一个三角形区域,然后用图片进行填充。 Java实用教程 第6章 Java用户界面技术 6.1 用户界面对象 6.2 布局 6.3 java.swing包 习题 Java实用教程 6.1 用户界面对象 用户界面上经常用到的组件对象有Button(按钮)、 Checkbox(复选框)、Choice(组合框)、Label(标签)、List(列表)、 Scrollbar(滚动条)、TextComponent(TextArea(文本区域)、 TextField(文本框))和Panel(面板)。这些组件类的继承情况如下: java.lang.Object | +--java.awt.BorderLayout +--java.awt.FlowLayout +--java.awt.Component Java实用教程 | +--java.awt.Button +--java.awt.Canvas +--java.awt.Checkbox +--java.awt.Choice +--java.awt.Container | +--java.awt.Panel +--java.awt.Label +--java.awt.List +--java.awt.Scrollbar +--java.awt.TextComponent | +--java.awt.TextArea +--java.awt.TextField Java实用教程 6.1.1 按钮 Button类创建一个带标签的按钮对象,当按下一个按钮时, 可以引发一些事件,包含一系列的动作或操作。例如单击按钮, 使得界面颜色发生变化等。它的构造函数以及主要的方法如下: public Button() 构建一个没有标签的按钮。 public Button(String label) 构建一个显示为label的按钮。 public void setLabel(String label) 设置显示标签为字符串label。 public String getLabel() 获取按钮的标签,返回为字符串。 Java实用教程 【例6.1】测试Button类的Applet。用户界面如图6.1所示。 源程序代码如下: //程序文件名UseButton.java import java.awt.*; import java.applet.*; import java.applet.Applet; public class UseButton extends Applet { String str1 = new String(); //声明按钮对象 Button b1; Button b2; Java实用教程 public void init() { //构造对象 b1 = new Button(); b2 = new Button("按钮对象2"); //添加到界面 this.add(b1); this.add(b2); } public void start() { Java实用教程 b1.setLabel("按钮对象1"); str1 = b2.getLabel(); repaint(); } public void paint(Graphics g) { g.drawString(str1,20,30); } }; Java实用教程 启动Applet的HTML页面代码如下: Java实用教程 图6.1 测试Button类的界面 Java实用教程 6.1.2 复选框和单选按钮 复选框是一个图形组件,有两个状态,即“选中”(true)和 “未选中”(false)。单击复选框时可以在“选中”、“未选中” 之间进行切换。在Java编程语言中,单选按钮没有单独的类, 而是作为复选框的特例存在,用户通过把一组复选框放置在同 一个复选框组中创建一套单选按钮。它的构造函数和其它方法 如下: public Checkbox() 创建一个没有标签的复选框。 public Checkbox(String label) 创建一个标签为lable的复选框。 Java实用教程 public Checkbox(String label, boolean state) 创建一个标签为lable的复选框,并设置初始状态。 public CheckboxGroup() 创建一个复选框组,用来放置单选按钮。 public Checkbox(String label, CheckboxGroup group, boolean state) 创建一个标签为lable的复选框,添加到group组中并设置初 始状态,作为单选按钮的形式出现。 Java实用教程 public String getLabel() 获得复选框的标签。 public void setLabel(String label) 设置标签。 public boolean getState() 返回复选框所在的状态,是选中还是未选中。 public void setState(boolean state) 设置状态,用来初始化复选框的状态。 Java实用教程 【例6.2】测试复选框和单选按钮的用法,用户界面如图6.2 所示。源程序代码如下: //程序文件名UseCheckbox.java import java.awt.*; import java.applet.*; import java.applet.Applet; public class UseCheckbox extends Applet { String str1 = new String(); boolean b1 = false; boolean b2 = false; Java实用教程 Checkbox c1,c2,c3; Checkbox cRadio1,cRadio2; CheckboxGroup c; public void init() { c1 = new Checkbox(); c2 = new Checkbox("复选框对象2"); c3 = new Checkbox("复选框对象3",true); //构造单选按钮 c = new CheckboxGroup(); cRadio1 = new Checkbox("单选按钮1",c, false); Java实用教程 cRadio2 = new Checkbox("单选按钮2",c,true); //添加到界面 this.add(c1); this.add(c2); this.add(c3); this.add(cRadio1); this.add(cRadio2); } public void start() { c1.setLabel("复选框对象1"); Java实用教程 str1 = c2.getLabel(); b1 = c3.getState(); b2 = cRadio1.getState(); repaint(); } public void paint(Graphics g) { g.drawString("获取第二个对象的标签:" + str1,40,80); g.drawString("复选框3的状态为:" + b1,40,100); g.drawString("单选按钮1的状态为:" + b2, 40,120); } }; Java实用教程 图6.2 复选框和单选按钮测试 Java实用教程 6.1.3 组合框 组合框代表一系列选择的弹出式菜单,当前选择显示为菜 单的标题。它的构造函数和其它常用方法如下: public Choice() 构建一个选择项菜单。 public void add(String item) 将item添加到选择菜单中。 public String getItem(int index) 返回选择菜单中index位置的项,注意索引是从0开始的, 而项数从1开始。 Java实用教程 public int getItemCount() 返回选择菜单总的项数。 public String getSelectedItem() 返回当前选中的项。 public int getSelectedIndex() 返回当前选中项的索引。 public void insert(String item, int index) 在index处插入字符串item。 public void remove(int position) 删除position位置的项。 Java实用教程 public void remove(String item) 删除item项。 public void removeAll() 删除所有的项。 public void select(int pos) 将pos处的项设为选中状态,通常用于初始化。 public void select(String str) 将str项设为选中状态,通常用于初始化。 Java实用教程 【例6.3】测试Choice类,用户界面如图6.3所示。源程序代码如下: //程序文件名UseChoice.java import java.awt.*; import java.applet.*; import java.applet.Applet; public class UseChoice extends Applet { String str1 = new String(); String str2 = new String(); int count = 0; int i1 = 0; Java实用教程 boolean b1 = false; Choice c1;//声明组合框对象 public void init() { //初始化组合框对象, c1 = new Choice(); c1.add("语文"); c1.add("数学"); c1.add("物理"); c1.add("化学"); c1.add("生物"); c1.select(3); this.add(c1); } Java实用教程 public void start() { count = c1.getItemCount(); str1 = c1.getItem(2); str2 = c1.getSelectedItem(); i1 = c1.getSelectedIndex(); repaint(); } public void paint(Graphics g) { g.drawString("元素总个数为:" + count,10,80); g.drawString("第2项元素为:" + str1,10,100); g.drawString("选中项的元素为:" + str2,10,120); g.drawString("选中项的位置为:" + i1,10,140); } }; Java实用教程 图6.3 测试Choice实例的用户界面 Java实用教程 在上例的基础上添加一个方法operate,并在start方法中调用此 方法,程序段如下: public void operate() { c1.insert("英语",3); c1.remove("生物"); } public void start() { operate(); count = c1.getItemCount(); ... } Java实用教程 图6.4 修改操作后的用户界面 Java实用教程 6.1.4 标签 标签对象就是将文本放入一个容器内的组件,显示一行只 读文本。文本可以由程序修改,用户无法直接修改。它的构造 函数和其它常用方法如下: public Label() 构建一个空标签。 public Label(String text) 构建一个text内容的标签,默认为左对齐。 public Label(String text, int alignment) Java实用教程 构建一个内容为text,以alignment方式对齐的标签,其中 alignment的取值如表6.1所示。 表6.1 标签alignment的属性取值 alignment 可选值 Label.LEFT Label.RIGHT Label.CENTER 对应数值 0 2 1 对齐方式 左对齐 右对齐 中间对齐 Java实用教程 public String getText() 获得标签文本。 public void setText(String text) 设置标签文本。 public int getAlignment() 获得标签文本对齐方式,返回为整型值。 Java实用教程 【例6.4】测试Label类,用户界面如图6.5所示。源程序代码如下: //程序文件名UseLabel.java import java.awt.*; import java.applet.*; import java.applet.Applet; public class UseLabel extends Applet { String str1 = new String(); int i1 = 0; Label l1;//声明对象 Label l2; Java实用教程 Label l3; public void init() { l1 = new Label(); l2 = new Label("标签对象2"); l3 = new Label("标签对象3",Label.CENTER); this.add(l1); this.add(l2); this.add(l3); } public void start() { Java实用教程 l1.setText("标签对象1"); str1 = l2.getText(); i1 = l3.getAlignment(); repaint(); } public void paint(Graphics g) { g.drawString("获取第二个对象的文本:" + str1,40,60); g.drawString("标签对象3的对齐方式为:" + i1,40,80); } }; Java实用教程 图6.5 Label对象的界面 Java实用教程 6.1.5 列表 List展示给用户一个滚动的文本项列表。用户可以选择其中 一项或多项。它的构造函数和其它常用方法如下: public List() 构建一个新的空滚动列表。 public List(int rows) 构建一个新的rows可见行的滚动列表。 public List(int rows, boolean multipleMode) 构建一个新的rows可见行的滚动列表,并设置是否可以多 项选择。multipleMode为true时,允许用户多项选择。 Java实用教程 public void add(String item) 在滚动列表最后添加新的一项item。 public void add(String item, int index) 在index位置添加item项。 public String getItem(int index) 返回index位置的项。 public int getItemCount() 返回列表中项的数目。 public String[] getItems() 返回列表中的项,为一个字符串数组。 Java实用教程 public int getSelectedIndex() 返回列表中选中项的索引。 public String getSelectedItem() 返回列表中选中的项。 public boolean isIndexSelected(int index) 判断index项是否选中。 public void remove(int position) 删除position项。 public void remove(String item) 删除item项。 Java实用教程 public void removeAll() 删除列表中所有元素。 public void replaceItem(String newValue, int index) 将index位置的项替换为newValue。 public void select(int index) 选中index位置的项,通常用于初始化。 Java实用教程 【例6.5】测试List类,用户界面如图6.6所示。源程序代码如下: //程序文件名UseList.java import java.awt.*; import java.applet.*; import java.applet.Applet; public class UseList extends Applet { String str1 = new String(); String str2 = new String(); int i1 = 0; int i2 = 0; Java实用教程 List l1,l2,l3;//声明对象 public void init() { l1 = new List(); l2 = new List(5); l3 = new List(5,true); //列表添加内容 l1.add("苹果"); l1.add("香蕉"); l1.add("梨"); l2.add("语文"); l2.add("数学"); Java实用教程 l2.add("英语"); l2.add("化学"); l3.add("钢笔"); l3.add("铅笔"); l1.select(1); l3.select(1); this.add(l1); this.add(l2); this.add(l3); } public void start() { Java实用教程 str1 = l1.getItem(2); i1 = l1.getItemCount(); l2.replaceItem("英语",2); str2 = l3.getSelectedItem(); repaint(); } public void paint(Graphics g) { g.drawString("第一个对象的索引为2的元素:" + str1,40,100); g.drawString("第一个对象的元素个数:" + i1,40,120); g.drawString("第三个对象选中的元素为:" + str2,40,140); } }; Java实用教程 图6.6 List对象的界面 Java实用教程 6.1.6 滚动条 Scrollbar给用户提供一个组件,方便用户在一系列范围的 值中进行选择。它的常用属性如表6.2所示。 表6.2 Scrollbar类的常用属性及缺省值 属性 Orientation(方向) Minimum(最小值) Maximum(最大值) Value(数值) Unit increment(单位移动) Block increment(块移动) 描述 水平还是垂直 滚动条的最小值 滚动条的最大值 滚动条的值 单击滚动条两端箭头时移动的单位 单击滚动条空白处时移动的单位 缺省值 Scrollbar.VERTICAL(1) 0 100 0 1 10 Java实用教程 它的构造函数和其它常用方法如下: public Scrollbar() 构建一个新的垂直滚动条。 public Scrollbar(int orientation) 构建一个指定方向的滚动条。Orientation的值为 HORIZONTAL(0)表示水平滚动条,值为VERTICAL(1)表示垂直 滚动条。 public Scrollbar(int orientation, int value, int visible, int minimum, int maximum) 构建一个指定方向、初始值、可见性、最小值和最大值的滚动 条。 Java实用教程 public int getValue() 返回滚动条的当前值。 public int getMinimum() 返回最小值。 public int getMaximum() 返回最大值。 Java实用教程 【例6.6】测试Scrollbar类,用户界面如图6.7所示。源程序代码如下 //程序文件名UseScrollbar.java import java.awt.*; import java.applet.*; import java.applet.Applet; public class UseScrollbar extends Applet { int i1 = 0; int i2 = 0; int i3 = 0; int i4 = 0; int i5 = 0; Scrollbar s1;//声明对象 Java实用教程 Scrollbar s2; Scrollbar s3; public void init() { s1 = new Scrollbar(); s2 = new Scrollbar(Scrollbar.HORIZONTAL); s3 = new Scrollbar(Scrollbar.VERTICAL,50,0,10,500); this.add(s1); this.add(s2); this.add(s3); } public void start() { Java实用教程 i1 = s1.getOrientation(); i2 = s2.getOrientation(); i3 = s3.getValue(); i4 = s3.getMinimum(); i5 = s3.getMaximum(); repaint(); } public void paint(Graphics g) { g.drawString("第一个对象的方向:" + i1,40,80); Java实用教程 g.drawString("第二个对象的方向:" + i2,40,100); g.drawString("第三个对象的滑块值:" + i3,40,120); g.drawString("第三个对象的最小值:" + i4,40,140); g.drawString("第三个对象的最大值:" + i5,40,160); } }; Java实用教程 图6.7 Scrollbar对象的测试界面 Java实用教程 6.1.7 文本框 TextField对象用作单行文本的编辑。它的构造函数和其它常用 方法如下: public TextField() 构建一个空的文本框。 public TextField(int columns) 构建一个文本框,columns给出文本框的宽度。 public TextField(String text) 构建一个文本框,用text给出初始化内容。 public TextField(String text, int columns) Java实用教程 构建一个文本框,text给出初始化的内容,columns给出文 本框的宽度。 public void setText(String t) 将文本框的内容设置为特定文本t。 public String getText() 返回文本框的内容,返回值为字符串。 public void setEditable(boolean b) 设定文本框内容是否是用户可编辑的,b为false时,表示不 可编辑,b为true时,表示可编辑。通常创建一个文本框时默认 为用户可编辑的。 public int getColumns() 获取列数。 Java实用教程 【例6.7】TextField类的测试,用户界面如图6.8所示。源程 序代码如下: //程序文件名UseTextField.java import java.awt.*; import java.applet.*; import java.applet.Applet; public class UseTextField extends Applet { String str1 = new String(); int i1 = 0; int i2 = 0; TextField tf1, tf2, tf3, tf4; public void init() { Java实用教程 tf1 = new TextField(); tf2 = new TextField(20); tf3 = new TextField("文本对象3"); tf4 = new TextField("文本对象4", 30); add(tf1); add(tf2); add(tf3); add(tf4); } public void start() { Java实用教程 tf1.setText("文本对象1"); tf2.setText("文本对象2"); str1 = tf3.getText(); i1 = tf3.getColumns(); i2 = tf4.getColumns(); tf4.setEditable(false); repaint(); } public void paint(Graphics g) { g.drawString("第三个对象的文本内容为:" + str1,20,140); g.drawString("第三个对象的列数为:" + i1,20,160); g.drawString("第四个对象的列数为:" + i2,20,180); } }; Java实用教程 图6.8 TextField对象的界面 Java实用教程 6.1.8 文本区域 TextArea对象用于允许多行编辑的文本区域,可以设置为可 编辑的,也可以设为只读属性。 public TextArea() 构建一个空文本区域。 public TextArea(int rows, int columns) 构建一个行数为rows、列数为columns的空文本区域。 public TextArea(String text) 构建一个文本为text的文本区域。 Java实用教程 public TextArea(String text, int rows, int columns) 构建一个文本为text、行数为rows、列数为columns的文本区 域。 public TextArea(String text, int rows, int columns, int scrollbars) 构建一个文本为text、行数为rows、列数为columns的文本 区域。滚动条的情况由scrollbars参数决定。Scrollbars的取值如 表6.3所示。 Java实用教程 表6.3 TextArea中的滚动条属性值 参数 描述 值 SCROLLBARS_BOTH 创建和显示水平滚动条和垂直滚动条 0 SCROLLBARS_VERTICAL_ONLY 创建和显示垂直滚动条 1 SCROLLBARS_HORIZONTAL_ONLY 创建和显示水平滚动条 2 SCROLLBARS_NONE 没有任何滚动条 3 Java实用教程 public void append(String str) 将非空str字符串文本添加到文本区域中。 public void insert(String str, int pos) 在指定位置pos插入非空字符串str。 public void replaceRange(String str, int start, int end) 将start开始位置到end结束位置的字符串替换成非空字符串 str,其中start位置的字符被替换,end位置的字符仍保留。 public void setText(String t) 将文本框的内容设置为特定文本t。 Java实用教程 public String getText() 返回文本框的内容,返回值为字符串。 public void setEditable(boolean b) 设定文本框内容是否是用户可编辑的。b为false时,表示不 可编辑。b为true时,表示可编辑。通常创建一个文本框时,默 认为用户可编辑的。 public int getColumns() 返回列数。 public int getRows() 返回行数。 Java实用教程 【例6.8】测试TextArea类,用户界面如图6.9所示。源程序 代码如下: //程序文件名UseTextArea.java import java.awt.*; import java.applet.*; import java.applet.Applet; public class UseTextArea extends Applet { String str1 = new String(); String str2 = new String(); int i1,i2,i3; TextArea t1,t2,t3,t4,t5;//声明对象 Java实用教程 public void init() { t1 = new TextArea(); t2 = new TextArea(2,20); t3 = new TextArea("文本区域对象3"); t4 = new TextArea("文本区域对象4", 3, 10); t5 = new TextArea("文本区域对象5", 2, 24, TextArea.SCROLLBARS_BOTH); this.add(t1); this.add(t2); this.add(t3); this.add(t4); this.add(t5); } Java实用教程 public void start() { t1.setText("文本区域对象1"); t2.append("文本区域对象2"); t3.insert("\"插入3\"",4); str1 = t3.getText(); t4.replaceRange("\"替换\"",2,6); str2 = t4.getText(); i1 = t4.getRows(); i2 = t5.getColumns(); i3 = t5.getScrollbarVisibility(); t5.setEditable(false); repaint(); Java实用教程 } public void paint(Graphics g) { g.drawString("第三个对象的文本内容为:" + str1,40,400); g.drawString("第四个对象的文本内容为:" + str2,40,420); g.drawString("第四个对象的行数为:" + i1,40,440); g.drawString("第五个对象的列数为:" + i2,40,460); g.drawString("第五个对象的滚动条情况为:" + i3,40,480); } }; Java实用教程 图6.9 TextArea对象的界面 Java实用教程 6.2.1 流式布局器 6.2 布 局 流式布局将组件按照从左到右的顺序自然排列,是缺省的设 置方式。其构造函数如下: FlowLayout() 构建一个新的流式布局器,中央对齐,对象之间以5单元水 平和垂直间隔。 FlowLayout(int align) 构建一个新的流式布局器,通过align设置对齐方式,对象之 间以5单元水平和垂直间隔。 FlowLayout(int align, int hgap, int vgap) 构建一个新的流式布局器,通过align设置对齐方式,对象之 间以hgap单元水平间隔并以vgap单元垂直间隔。 Java实用教程 6.2.2 边缘布局器 边缘布局器是一个分为北(NORTH)、南(SOUTH)、东 (EAST)、西(WEST)和中央(CENTER)五部分的容器。其构造函 数如下: BorderLayout() 构建一个新的边缘布局,对象之间没有间隔。 BorderLayout(int hgap, int vgap) 构建一个新的边缘布局,对象之间的水平间隔为hgap,垂 直间隔为vgap。 Java实用教程 6.2.3 面板 面板是最简单的容器类,应用程序可以在面板提供的空间 里放置任意组件及其它的面板。 Panel() 使用缺省的布局管理器创建一个新的面板。缺省的布局管 理器为流式管理器。 Panel(LayoutManager layout) 用指定的layout布局管理器创建一个面板。 public void setLayout(LayoutManager mgr) 设置布局管理器。 Java实用教程 【例6.9】下面是一个综合性实例,采用本章介绍的界面对 象设置用户界面并进行布局管理。经过布局后的界面如图6.10 所示。 //程序文件名UsePanel.java import java.awt.*; import java.applet.*; import java.applet.Applet; public class UsePanel extends Applet { Label lblName,lblNumber,lblSex,lblJob,lblText; TextField tfName,tfNumber; Checkbox chMale, chFemale; Java实用教程 CheckboxGroup c; TextArea taText; Choice chJob; Button btnOk,btnCancel; Panel p1,p2,p3,p4,p5,p6,p7,p8,p9; public void init() { lblName = new Label("姓名:"); lblNumber = new Label("身份证号:"); lblSex = new Label("性别"); lblJob = new Label("职业"); lblText = new Label("个性化宣言:"); Java实用教程 tfName = new TextField(23); tfNumber = new TextField(20); taText = new TextArea(10,20); c = new CheckboxGroup(); chMale = new Checkbox("男",c,true); chFemale = new Checkbox("女",c,false); chJob = new Choice(); chJob.add("计算机业"); chJob.add("医生"); chJob.add("教师"); chJob.add("军队"); btnOk = new Button("确定"); btnCancel = new Button("取消"); Java实用教程 p1 = new Panel(); p2 = new Panel(); p3 = new Panel(); p4 = new Panel(); p5 = new Panel(); p6 = new Panel(); p7 = new Panel(new BorderLayout()); p8 = new Panel(); p9 = new Panel(new BorderLayout()); p1.add(lblName); p1.add(tfName); p2.add(lblNumber); p2.add(tfNumber); p3.add(lblSex); Java实用教程 p3.add(chMale); p3.add(chFemale); p4.add(lblJob); p4.add(chJob); p5.add(p3); p5.add(p4); p6.setLayout(new BorderLayout()); p6.add(p1,BorderLayout.NORTH); p6.add(p2,BorderLayout.CENTER); p6.add(p5,BorderLayout.SOUTH); p7.add(lblText,BorderLayout.NORTH); p7.add(taText,BorderLayout.CENTER); Java实用教程 p8.setLayout(new FlowLayout(FlowLayout.CENTER,30,10)); p8.add(btnOk); p8.add(btnCancel); p9.add(p6,BorderLayout.NORTH); p9.add(p7,BorderLayout.CENTER); p9.add(p8,BorderLayout.SOUTH); add(p9); } }; Java实用教程 图6.10 经过布局后的界面 Java实用教程 6.3 java.swing包 6.3.1 基本组件 JButton为轻量级按钮组件,对应着Button组件类。 JLabel为轻量级标签组件,对应着Label组件类。 JCheckBox为轻量级复选框,对应CheckBox类。 JradioButton为轻量级单选按钮,需要添加在ButtonGroup组中。 JRadioButton jMale = new JRadioButton("男"); JRadioButton jFemale = new JRadioButton("女"); Java实用教程 ButtonGroup group = new ButtonGroup(); group.add(jMale); group.add(jFemale); JComoBox对应Choice组件,但添加项的方法不同,使用的 是addItem方法,例如: JComboBox cmbJob = new JComboBox(); cmbJob.addItem("计算机业"); cmbJob.addItem("医生"); cmbJob.addItem("教师"); Java实用教程 cmbJob.addItem("军队"); JTextField组件为允许对单行文本进行编辑的轻量级组件, 对应TextField类。 JTextArea组件用于在多行区域中显示纯文本并进行编辑。 Jpanel为轻量级面板控件,对应原来的Panel类。 JApplet类继承自Applet类。 Java实用教程 6.3.2 JTable JTable是用于显示和编辑的两维表单元。它的构造函数和常 用方法为: public JTable() 构造一个空的JTable对象。 public void setModel(TableModel dataModel) 为表对象设置数据模型dataModel,并将新数据模型进行注册。 DefaultTableModel是一个实现模型,使用一系列Vector对象 实现表单元数据的填充。它的构造函数和常用方法为: public DefaultTableModel() 构造函数。 Java实用教程 public void addColumn(Object columnName) 添加一列标题。 public void addRow(Vector rowData) 在模型对象的末尾添加一行Vector对象的数据。 构造Jtable对象的步骤如下: (1) 构造一个空JTable对象。 JTable tblInf = new JTable(); (2) 构造DefaultTableModel对象,用setModel方法将此对象 绑定到JTable上。 DefaultTableModel dtm = new DefaultTableModel(); Java实用教程 (3) 具体实现DefaultTableModel对象(addColomn方法实现列 标题设置,addRow方法实现数据行添加)。 ① 初始化Vector列表,添加列标题。 Vector vCdata = new Vector(); vCdata.add("姓名"); vCdata.add("身份证号"); vCdata.add("性别"); tblInf.setModel(dtm); for (int i=0; i”,单击“编辑规 则项目”按钮,弹出如图10.10所示窗口。权限列表中可以看 出对普通属性都有读的权限。这是客户端对所有远程代码的默 认的安全限制列表。 Java实用教程 图10.10 所有远程代码访问的默认权限列表 Java实用教程 这个默认的java.policy文件对应的源文件如下: // Standard extensions get all permissions by default grant codeBase "file:${java.home}/lib/ext/*" { permission java.security.AllPermission; }; // default permissions granted to all domains Java实用教程 grant { // Allows any thread to stop itself using the java.lang.Thread.stop() // method that takes no argument. // Note that this permission is granted by default only to remain // backwards compatible. // It is strongly recommended that you either remove this permission // from this policy file or further restrict it to code sources // that you specify, because Thread.stop() is potentially unsafe. Java实用教程 // See "http://java.sun.com/notes" for more information. permission java.lang.RuntimePermission "stopThread"; // allows anyone to listen on un-privileged ports permission java.net.SocketPermission "localhost:1024-", "listen"; // "standard" properies that can be read by anyone permission java.util.PropertyPermission "java.version", "read"; permission java.util.PropertyPermission "java.vendor", "read"; permission java.util.PropertyPermission "java.vendor.url", "read"; Java实用教程 permission java.util.PropertyPermission "java.class.version", "read"; permission java.util.PropertyPermission "os.name", "read"; permission java.util.PropertyPermission "os.version", "read"; permission java.util.PropertyPermission "os.arch", "read"; permission java.util.PropertyPermission "file.separator", "read"; permission java.util.PropertyPermission "path.separator", "read"; permission java.util.PropertyPermission "line.separator", "read"; Java实用教程 permission java.util.PropertyPermission "java.specification.version", "read"; permission java.util.PropertyPermission "java.specification.vendor", "read"; permission java.util.PropertyPermission "java.specification.name", "read"; permission java.util.PropertyPermission "java.vm.specification.version", "read"; permission java.util.PropertyPermission "java.vm.specification.vendor", "read"; permission java.util.PropertyPermission "java.vm.specification.name", "read"; permission java.util.PropertyPermission "java.vm.version", "read"; permission java.util.PropertyPermission "java.vm.vendor", "read"; permission java.util.PropertyPermission "java.vm.name", "read"; }; Java实用教程 10.5 签名及发布的例子 10.5.1 步骤 在命令提示符状态下进入路径D:\Apache Tomcat 4.0\webapps\ROOT\user,所有操作都在服务器路径下操作,也 可以在普通路径下操作,完成后将一系列文件配置到服务器端。 本书作者使用前者,在user目录下建立AppletSecurity.java文件, 源代码即为例10.1,编译后生成三个类:AppletSecurity.class、 AppletSecurity$1.class和AppletSecurity$2.class。 (1) 将生成的类文件打包成文档文件。 jar cvf a.jar *.class Java实用教程 (2) 为刚才创建的文件创建keystore。 keytool -genkey -alias a -keypass xueliang -keystore a.keystore storepass xueliang (3) 使用刚才生成的钥匙来对jar文件进行签名。 jarsigner -keystore a.keystore -storepass xueliang a.jar a (4) 将公共钥匙导入到一个cer文件中。 keytool -export -alias a -file a.cer -keystore a.keystore -storepass xueliang Java实用教程 (5) 网页转换及修改。 嵌入类的index.html写成: Java实用教程 使用htmlConverter工具,将index.html转换成使用插件的文 件。源文件如下: Java实用教程 --> Java实用教程 10.5.2 结果 通过IE访问index.html,在类加载过程中,弹出一个“Java 安全警告”窗口,如图10.11所示。 图10.11 证书的安全警告窗口 Java实用教程 单击“授予该会话”按钮,则出现Applet界面,如图10.12 所示,在文件名栏敲入E:\a.txt,然后按回车键以显示文本内容, 如图10.13所示。 图10.12 载入的Applet界面 Java实用教程 图10.13 显示的文本内容 Java实用教程 习题 1. 编写Applet,在客户端建立一个文件,测试Applet的安全 限制和许可访问类,要求文件路径为“D:\Hello.txt”,并存入数 据“你好,欢迎来到Java世界”。编写的界面如图10.14所示, 文件名中写入路径,文件内容中写入数据,单击“存储”按钮, 将数据存入客户端文件,单击“打开”按钮,又可以显示内容, 将可能出现的异常输出到文本区域内。 2. 使用PolicyTool工具建立一个new.policy文件,要求对网 址http://192.100.100.43::79端口下所有访问进行许可授权。 3. 为习题1的Applet加入数字签名,并进行访问。 Java实用教程 图10.14 用户界面 Java实用教程 第11章 Java网络技术(一) 11.1 TCP Sockets基础 11.2 UDP Sockets基础 11.3 网页显示控件 习题 Java实用教程 11.1 TCP Sockets基础 Sockets是一个编程抽象概念,它是网络上与另一个应用程 序通信连接的句柄。Sockets编程将用户代码与TCP/IP协议堆栈 的底层实现隔离开,允许用户灵活地实现自己的编程。 基于TCP协议的TCP Sockets需要四个方面的数据: (1) 本地系统的IP地址。 (2) 本地应用程序正在使用的TCP端口号。 (3) 通信的远程系统的IP地址。 (4) 通信的远程系统响应的TCP端口号。 Java实用教程 TCP Sockets的应用模型通常是客户/服务器模型,一个服务 器在一个特定端口等待远程计算机请求资源,给予响应。客户 程序绑定到这个端口,建立一个可靠连接来用于通信。 面向连接的操作使用TCP协议,在这个模式下的Socket必须 在发送数据之前与目的地的Socket取得一个连接。连接建立后, Socket就可以使用一个流接口:打开—读—写—关闭。所有发送 的信息都会在另一端以同样的顺序被接收。面向连接的操作比 无连接的操作效率低,但是数据的安全性更高。由于Socket使用 是双方的,所以在客户端和服务器端的使用稍有不同。 Java实用教程 (1) 客户端请求Socket的步骤如下: ① 建立客户端Socket连接; ② 得到Socket的读和写的流; ③ 利用流; ④ 关闭流; ⑤ 关闭Socket。 使用一个服务器端的Socket请求比使用一个客户端Socket请 求要麻烦一些。服务器并不是主动地建立连接。相反地,服务 器被动地监听客户端的连接请示,然后给它们服务。 Java实用教程 (2) 服务器端Socket要完成以下的基本的步骤: ① 建立一个服务器Socket并开始监听; ② 使用accept()方法取得新的连接; ③ 建立输入和输出流; ④ 在已有的协议上产生会话; ⑤ 关闭客户端流和Socket; ⑥ 回到②或者转到⑦; ⑦ 关闭服务器Socket。 Java实用教程 建 立 Socket (返 回 Socket号 S1) 绑定 (Socket与 本 地 地 址 相 连 ) 监听 (通 知 TCP准 备 接 收 连 接 ) 连接 (建 立 新 的 Socket号 S2) 建立连接 数据交换 请 求 /应 答 建 立 Socket (返 回 Socket号 S1) 连接 (与 主 机 相 连 ) 数据交换 关 闭 Socket S2 关 闭 Socket S1 关 闭 Socket, 结束对话 服务器 客户端 图11.1 面向连接的Socket协作流程图 Java实用教程 例如,HTTP请求通过服务器的80端口实现,服务器端类 似于Socket监听,端口号为80。如果客户端希望通过应用程序 获得网页,只需采用面向连接的Socket,请求80端口,获取网 页数据。首先打开一个连接,请求主机为服务器网址,请求端 口号为80,然后发送命令请求“GET / HTTP/1.0\r\n\r\n”,得到 返回的网页。 Java实用教程 11.1.1 InetAddress类 InetAddress对象表示一个Internet主机地址。这个主机地址 可以通过名字和IP地址来标识。名字即主机名,例如本机名字 为snowing,为字符串类型;IP地址为192.100.100.43,为四字节 的数字,书写形式为a.b.c.d。InetAddress类的几个常用方法如下: public static InetAddress getByName(String host) throws UnknownHostException 通过名字可以得到主机的IP地址。 Java实用教程 public String getHostAddress() 返回IP地址的字符串格式。 public String getHostName() 返回IP地址的主机名。 public static InetAddress getLocalHost() throws UnknownHostException 以InetAddress类封装的格式返回本机地址。 public String toString() 转换成字符串格式。 Java实用教程 【例11.1】InetAddress对象应用的测试。获取本机地址并转 换成字符串输出,输出本地主机名和IP地址以及通过局域网内 计算机的名字得到它的IP地址。程序源代码如下: //程序文件名FindHost.java import java.net.*; public class FindHost { public static void main(String[] args) { try { Java实用教程 InetAddress h = InetAddress.getLocalHost(); System.out.println("toString():" + h.toString()); System.out.println("getHostName():" +h.getHostName()); System.out.println("getHostAddress():"+h.getHostAddress()); h = InetAddress.getByName("engine"); System.out.println(h.getHostName() +":" + h.getHostAddress()); } catch(UnknownHostException e) { System.out.println(e.getMessage()); } } } Java实用教程 编译后生成FindHost.class文件,运行后输出结果界面如 图11.2所示。由图11.2可以看出本地主机名为snowing,IP地址 192.100.100.43;engine为局域网内另一台计算机的名字,可以 得到它的IP地址为192.100.100.186。 Java实用教程 图11.2 程序结果输出界面 Java实用教程 11.1.2 Socket类 Socket类用来实现客户端的Socket。常用的构造方法有以 下三种: public Socket() 创建一个无连接的Socket。 public Socket(InetAddress address, int port) 创建流式Socket,将它连接到InetdAdress类指明的主机和 port端口上。 public Socket(String host, int port) 创建流式Socket并将它连接到特定host的特定port端口上。 Java实用教程 【例11.2】 建立客户端程序,访问网址 http://www.xjtu.edu.cn,返回网址的首页写入文件xjtu.html。 1. 程序建立的步骤 (1) 建立到http://www.xjtu.edu.cn且端口为80的Socket连接。 Socket clientSocket = new Socket("www.xjtu.edu.cn", 80); Java实用教程 (2) 初始化字节流。连接建立后的数据传输通过数据输入输 出流实现,写文件又通过文件输入输出流来实现。各种流对象 的初始化如下: DataOutputStream outbound = new DataOutputStream(clientSocket.getOutputStream()); DataInputStream inbound = new DataInputStream(clientSocket.getInputStream()); InputStreamReader inS = new InputStreamReader(inbound); File f = new File("xjtu.html"); FileOutputStream fOut = new FileOutputStream(f); PrintStream p = new PrintStream(fOut); Java实用教程 (3) 发送请求。 outbound.writeBytes("GET / HTTP/1.0\r\n\r\n"); (4) 返回数据后,循环写入文件。 int c; while((c = inS.read()) != -1) p.print((char)c); Java实用教程 (5) 关闭流。 inS.close(); outbound.close(); inbound.close(); clientSocket.close(); Java实用教程 2. 程序源文件 //程序文件名ReadClient.java import java.io.*; import java.net.*; public class ReadClient { public static void main(String args[]) { try { Java实用教程 //初始化Socket对象 Socket clientSocket = new Socket("www.xjtu.edu.cn", 80); System.out.println("Client1: " + clientSocket); //初始化流对象 DataOutputStream outbound = new DataOutputStream( clientSocket.getOutputStream() ); DataInputStream inbound = new DataInputStream( clientSocket.getInputStream() ); InputStreamReader inS = new InputStreamReader(inbound); File f = new File("xjtu.html"); Java实用教程 FileOutputStream fOut = new FileOutputStream(f); PrintStream p = new PrintStream(fOut); outbound.writeBytes("GET / HTTP/1.0\r\n\r\n"); //写入文件 int c; while((c = inS.read()) != -1) p.print((char)c); //关闭流 inS.close(); outbound.close(); inbound.close(); clientSocket.close(); Java实用教程 } catch (UnknownHostException uhe) { System.out.println("UnknownHostException: " + uhe); } catch (IOException ioe) { System.err.println("IOException: " + ioe); } } } Java实用教程 3. 输出结果 图11.3为程序输出的xjtu.html,而图11.4为网址 http://www.xjtu.edu.cn的首页,可以看出程序输出的网页图形丢 失,这是因为此处的数据输入输出流只实现文本的读取,而并 未考虑图形的处理。 Java实用教程 图11.3 程序输出的xjtu.html Java实用教程 图11.4 网址http://www.xjtu.edu.cn的首页 Java实用教程 11.1.3 ServerSocket类 ServerSocket类实现服务器Socket,服务器Socket等待从网 络到达的请求,基于这些请求完成操作,然后返回相应的结 果给请求者。ServerSocket类有一个重要的方法: public Socket accept() 用户监听并接收一个连接。 【例11.3】编写TCP通信程序,服务器端发送字符串到客 户端。 Java实用教程 1. 服务器端程序建立的步骤 (1) 创建服务器Socket(端口82,限制5个连接)和接收客户连 接的Socket。 serverSocket = new ServerSocket(82, 5); Socket clientSocket = new Socket(); (2) 等待客户端连接。 clientSocket = serverSocket.accept(); Java实用教程 (3) 初始化输入输出流。 DataInputStream inbound = new DataInputStream( client.getInputStream()); DataOutputStream outbound = new DataOutputStream( client.getOutputStream()); Java实用教程 (4) 当接收到“hello”字符串时,输出字符串“http://www.xjtu.edu.cn StringBuffer buffer = new StringBuffer("\"http://www.xjtu.edu.cn/\"\r\n"); String inputLine; while ((inputLine = inbound.readLine()) != null) { if ( inputLine.equals("hello") ) { outbound.writeBytes(buffer.toString()); break; } } Java实用教程 (5) 关闭流以及Socket。 outbound.close(); inbound.close(); clientSocket.close(); Java实用教程 2. 服务器端程序源文件 //程序文件名SimpleWebServer.java import java.io.*; import java.net.*; public class SimpleWebServer { public static void main(String args[]) { ServerSocket serverSocket = null; Socket clientSocket = null; int connects = 0; try { Java实用教程 //创建服务器Socket,端口82,限制5个连接 serverSocket = new ServerSocket(82, 5); while (connects < 5) { //等待连接 clientSocket = serverSocket.accept(); //操作连接 ServiceClient(clientSocket); connects++; } serverSocket.close(); } Java实用教程 catch (IOException ioe) { System.out.println("Error in SimpleWebServer: " + ioe); } } public static void ServiceClient(Socket client) throws IOException { DataInputStream inbound = null; DataOutputStream outbound = null; try { //获取输入输出流 inbound = new DataInputStream( client.getInputStream()); Java实用教程 outbound = new DataOutputStream( client.getOutputStream()); StringBuffer buffer = new StringBuffer("\"http://www.xjtu.edu.cn/\"\r\n"); String inputLine; while ((inputLine = inbound.readLine()) != null) { //判断输入为hello时输出字符串 if ( inputLine.equals("hello") ) { outbound.writeBytes(buffer.toString()); break; Java实用教程 } } } finally { //打印清除连接,关闭流及Socket System.out.println("Cleaning up connection: " + client); outbound.close(); inbound.close(); client.close(); } } } Java实用教程 3. 客户端程序 //程序文件名为ReadClient.java import java.io.*; import java.net.*; public class ReadClient { public static void main(String args[]) { try { //与服务器建立连接 Java实用教程 Socket clientSocket = new Socket("192.100.100.43",82); System.out.println("Client1: " + clientSocket); //初始化流对象 DataOutputStream outbound = new DataOutputStream( clientSocket.getOutputStream() ); DataInputStream inbound = new DataInputStream( clientSocket.getInputStream() ); InputStreamReader inS = new InputStreamReader(inbound); //发送数据 outbound.writeBytes("hello\r\n"); Java实用教程 System.out.println("hello"); outbound.flush(); int c; while((c = inS.read()) != -1) { System.out.print((char)c); } } catch (UnknownHostException uhe) { System.out.println("UnknownHostException: " + uhe); } Java实用教程 catch (IOException ioe) { System.err.println("IOException: " + ioe); } finally { //关闭流及clientSocket inS.close(); outbound.close(); inbound.close(); clientSocket.close(); } } } Java实用教程 4. 通信结果输出 通信结果如图11.5所示。上面的部分为服务器端的输出, 清除每次连接的Socket,下面的部分为客户端显示,首先打印 客户端Socket情况,然后打印发送的hello数据,最后输出从服 务器端返回的字符串。 Java实用教程 图11.5 基于TCP的Socket通信结果输出界面 Java实用教程 11.2 UDP Sockets 基 础 数据报Socket是包发送服务的接收和发送点,它接收和发 送的每个包都是单独访问和路由的。从一个机器发送到另一个 机器的包可能有不同的路由,而且可能以任意顺序到达。数据 报Socket构造函数有三个,分别如下: public DatagramSocket() 构建数据报Socket,绑定到本地主机上的任意端口。 public DatagramSocket(int port) 构建一个数据报Socket,将它绑定到指定的port端口。 Java实用教程 public DatagramSocket(int port, InetAddress laddr) 构建一个数据报Socket,绑定到指定的laddr本地地址和port端口。 数据报可以通过connect方法建立连接,也可以直接使用send方 法发送数据,使用receive方法接收数据,方法如下: public void connect(InetAddress address, int port) 将建立的数据报Socket连接到远程地址address的port端口。 public void receive(DatagramPacket p) 接收数据报包p。 public void send(DatagramPacket p) 发送数据报包p。 Java实用教程 11.2.1 DatagramPacket类 从TCP的例子程序可以看出TCP Socket发送的数据是流式 数据,而UDP Socket发送的数据是分块的数据包,这就用到 DatagramPacket类。数据报Socket传输数据前首先构造数据报 包,然后传输这个数据报包。数据报包的构造函数如下: DatagramPacket(byte[] buf, int length) 构建数据报包,接收length长度的包并放入buf。 DatagramPacket(byte[] buf, int length, InetAddress address, int port) 构建数据报包,发送length长度的包到address指定的主机 的port端口。 Java实用教程 【例11.4】客户端循环发送数据“Client:Hello”到服务器端, 服务器端截取字符串Hello输出,并将源字符串返回给客户端。 1. 程序建立的步骤 (1) 服务器端程序建立的步骤。 ●建立数据报Socket。 DatagramSocket mysock = new DatagramSocket(1719); ● 建立数据报包,准备接收。 byte[] buf = new byte[1024]; DatagramPacket p = new DatagramPacket(buf,buf.length); ●接收或者发送。 mysock.receive(p); ... mysock.send(p); Java实用教程 (2) 客户端程序建立的步骤。 ● 建立数据报Socket。 DatagramSocket mysock = new DatagramSocket(); ● 建立数据报包,准备接收。 DatagramPacket p = new DatagramPacket(buf,buf.length,InetAddress.getLocalHost(),1719); ● 接收或者发送。 mysock.receive(p); ... mysock.send(p); Java实用教程 2. 服务器端源程序 //程序文件名为DatagramServer.java import java.net.*; public class DatagramServer extends Object { public static String ReadRAS(String str) { int indexstart = str.indexOf(':'); int indexend = str.indexOf("o"); String Msg = "Server:" + Java实用教程 str.substring(indexstart+1,indexend+1); return Msg; } public static void main(String[] args) { try { DatagramSocket mysock = new DatagramSocket(1719); byte[] buf = new byte[1024]; DatagramPacket p = new DatagramPacket(buf,buf.length); while(true) { Java实用教程 mysock.receive(p); System.out.println("RECEIVE:"+ new String(p.getData()).trim()); System.out.println(ReadRAS(new String(p.getData()).toString())); mysock.send(p); System.out.println("SEND:"+ new String(p.getData()).trim()); } } catch(Exception e) { System.out.println(e.getMessage()); } } } Java实用教程 3. 客户端源程序 //程序文件名为DatagramClient.java import java.net.*; import java.io.*; public class DatagramClient extends Object { public static void main(String[] args) { try { Java实用教程 DatagramSocket mysock = new DatagramSocket(); byte[] buf = new byte[1024]; String sendData = new String("Client:Hello"); buf = sendData.getBytes(); DatagramPacket p = new DatagramPacket(buf,buf.length,InetAddress.getLocalHost(),1719); while(true) { mysock.send(p); System.out.println("SEND:"+ new String(p.getData()).trim()); Java实用教程 mysock.receive(p); System.out.println("GET:"+ new String(p.getData()).trim()); } } catch(Exception e) { System.out.println(e.getMessage()); } } } Java实用教程 4. 通信结果显示 如图11.6所示,上面的一部分为客户端,SEND标志发送 数据“Client:Hello”,下面部分为服务器端,可以看见 RECEIVE标志的接收到的字符串为客户端发送的数据,然后 服务器端将接收到的数据进行截取,显示Hello字符串,前面 加了Server标志,最后将原数据返回,在客户端又显示GET标 志的接收到的字符串。 Java实用教程 图11.6 数据报Socket通信结果输出界面 Java实用教程 11.2.2 音频采集、播放实例 【例11.5】下面给出一个音频采集与播放实例,使用UDP Socket和多线程技术实现局域网内部的声音采集与传输。实例 采用对等访问模式,使用时只需输入Java UDPTalk “对方服务 器IP地址”,然后单击“通话”按钮即可,如图11.7所示。本 例是Applet和应用程序共用的,如果通过Applet进行访问,需 要获取SERVER_NAME参数,或者在程序内写成定值。另外, 还需为此Applet进行数字签名,否则无权在客户端的机器上进 行音频采集。 Java实用教程 //程序文件名为TalkSelf.java import java.io.*; import java.applet.*; import java.applet.Applet; import java.awt.*; import java.awt.event.*; import javax.sound.sampled.*; import java.net.*; public class TalkSelf extends Applet implements Runnable, ActionListener { Java实用教程 private static String SERVER_NAME;// = "192.100.100.42"; private static int SRTPPort = 1734; private static int MAXBUFFER = 8192; final int bufSize = 16384; private static boolean PlayButton = false;//是否播放按钮 private static boolean keepRunning = true;//控制循环 private boolean bRun = false;//控制播放 private Thread TalkThread; private static PlaybackAudio PlayAudio; //播放音频实例 private static CaptureAudio CapAudio;//采集音频实例 Button PlayBtn; //通话按钮 Button CaptureBtn;//停止按钮 Java实用教程 //初始化界面 public void init() { PlayBtn = new Button("通话"); PlayBtn.addActionListener(this); add(PlayBtn); CaptureBtn = new Button("停止"); CaptureBtn.addActionListener(this); add(CaptureBtn); } Java实用教程 //启动线程 public void start() { if(TalkThread == null) { TalkThread = new Thread(this); TalkThread.start(); } } //响应动作事件 public void actionPerformed(ActionEvent evt) { String btnCaption = evt.getActionCommand(); if(btnCaption.equals("通话")) { Java实用教程 PlayButton = true; } if(btnCaption.equals("停止")) { PlayButton = false; bRun = false; } } //实现run函数 public void run() { while(keepRunning) { if(PlayButton && !bRun) Java实用教程 { try { bRun = true; CapAudio = new CaptureAudio(SERVER_NAME, SRTPPort); CapAudio.start(); PlayAudio = new PlaybackAudio(SRTPPort); PlayAudio.start(); } catch(Exception e) { Java实用教程 System.out.println(e.getMessage()); } } } } //音频播放类 class PlaybackAudio extends Thread implements Runnable { SourceDataLine line; Thread thread; DatagramSocket s; //数据报Socket DatagramPacket p; //数据报包 int RTPPort; //构造函数:取得接收端口 Java实用教程 PlaybackAudio(int RTPPort) { this.RTPPort = RTPPort; } public void start() { thread = new Thread(this); thread.setName("PlaybackAudio"); thread.start(); } public void run() { AudioFormat format =new Java实用教程 AudioFormat(8000,16,2,true,true);//设置音频格式 DataLine.Info info = new DataLine.Info(SourceDataLine.class,format);//设置数据线 try { line = (SourceDataLine)AudioSystem.getLine(info);// 获得源数据线信息 line.open(format, bufSize);//打开源数据线 } catch (LineUnavailableException ex) { return; } Java实用教程 byte[] data = new byte[MAXBUFFER]; int numBytesRead = 0; line.start();//启动源数据线 try { s = new DatagramSocket(RTPPort); } catch (IOException e) { return; } while (thread != null) { Java实用教程 try { p = new DatagramPacket(data, data.length); s.receive(p);//接收包 numBytesRead = p.getLength(); line.write(p.getData(), 0, numBytesRead);//写入源数据线 } catch(IOException e) { break; } } Java实用教程 s.close();//关闭数据报Socket if (thread != null) { line.drain(); } line.stop(); line.close(); line = null; } } //音频采集类 class CaptureAudio extends Thread implements Runnable { Java实用教程 TargetDataLine line; Thread thread; DatagramSocket s; DatagramPacket p; String SERVER_NAME; int RTPPort; //构造函数:取得远程服务器名和端口,用于发送数据 CaptureAudio(String SERVER_NAME, int RTPPort) { this.SERVER_NAME = SERVER_NAME; this.RTPPort = RTPPort; } public void start() { Java实用教程 thread = new Thread(this); thread.setName("CaptureAudio"); thread.start(); } public void run() { AudioFormat format =new AudioFormat(8000,16,2,true,true);//AudioFormat(float sampleRate, int sampleSizeInBits, int channels, boolean signed, boolean bigEndian) DataLine.Info info = new DataLine.Info(TargetDataLine.class,format); Java实用教程 try { line = (TargetDataLine)AudioSystem.getLine(info);//设置目标数 据线信息 line.open(format,line.getBufferSize()); //打开目标数据线 } catch (Exception ex) { return; } byte[] data = new byte[MAXBUFFER]; int numBytesRead=0; line.start(); //启动目标数据线 try Java实用教程 { //构造数据报Socket s = new DatagramSocket(); } catch (Exception ex) { return; } while (thread != null) { try { numBytesRead = line.read(data, 0, MAXBUFFER);//读取采集数据 Java实用教程 p = new DatagramPacket(data, numBytesRead, InetAddress.getByName(SERVER_NAME), RTPPort); s.send(p);//发送数据 } catch (Exception ex) { break; } } s.close(); line.stop(); line.close(); line = null; } } Java实用教程 //主函数 public static void main(String args[]) { SERVER_NAME = new String(args[0]); TalkSelf t = new TalkSelf(); Frame f = new Frame(); f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent evt) { System.exit(0); } }); Java实用教程 t.init(); f.setSize(300,300); f.add("Center", t); f.show(); t.start(); } } Java实用教程 图11.7 简单的通话界面 Java实用教程 11.3 网页显示控件 11.3.1 JEditorPane JEditorPane类是一个文本组件,通过实现相应的EditorKit接 口可以编辑一些特殊格式的内容。它的内容类型有三种: (1) text/plain:使用默认的DefaultEditorKit的扩展,处理普 通文本。 (2) txt/html:使用javax.swing.text.html.HTMLEditorKit提供 HTML3.2的帮助,用以处理HTML文本,针对HTML中存在的一 些链接,进行点击时可以激活超链接事件。 (3) txt/rtf:使用javax.swing.text.rtf.RTFEditorKit实现对RTF 格式文本的处理。 Java实用教程 这里侧重于处理HTML文本的情况,JEditorPane类的构造 函数和处理HTML常用到的方法如下: public JEditorPane() 构建一个空JeditorPane。 public JEditorPane(String url) 构建一个基于URL声明的字符串的JEditorPane。 public JEditorPane(URL initialPage) 构建一个基于特定URL对象的JeditorPane。 public void addHyperlinkListener(HyperlinkListener listener) 添加一个超链接监听者,通知任何变化,例如选中一个链 接并进入时。 Java实用教程 public void setPage(String url) 设置显示的URL页面。 字符串url 表示页面的URL地址。 public void setPage(URL page) 设置显示的URL对象代表的page页面。 public void setText(String t) 设置指定t内容。 public void setEditable(boolean b) b为true时,可编辑;b为false时,不可编辑,但只有当b为false时, 才可以响应超链接事件。 Java实用教程 11.3.2 HyperlinkListener和HyperlinkEvent HyperlinkListener是超链接事件监听者接口,继承于 EventListener接口,只有一个事件:超链接更新,当点击链接或 者进入链接时引发。这个事件的方法为: public void hyperlinkUpdate(HyperlinkEvent e) 当更新一个超链接时调用此方法。 HyperlinkEvent是超链接事件,用于通知有关超文本链接的 变化,它有两个常用方法,一个方法用来获得事件的类型,另 一个方法是获得超链接指向的URL网址。 public HyperlinkEvent.EventType getEventType() Java实用教程 表11.1 超链接事件的三种类型 HyperlinkEvent.EventType HyperlinkEvent.ACTIVATED HyperlinkEvent.ENTERED HyperlinkEvent.EXITED 描述 激活超链接 进入超链接的文本 退出超链接的文本 public URL getURL() 返回超链接指向的URL地址。 Java实用教程 【例11.6】使用JEditorPane显示网页,当单击其中的链接 时能够给予响应。 1. 分析 (1) 创建JEditorPane对象。 JEditorPane jep = new JEditorPane(); (2) 设置可编辑属性为false。 jep.setEditable(false); (3) 添加超链接事件监听器。 jep.addHyperlinkListener(new LinkFollower(jep)); Java实用教程 (4) 显示网页。 jep.setPage(str); (5) 链接更新事件的处理。 public void hyperlinkUpdate(HyperlinkEvent evt) { if(evt.getEventType() == HyperlinkEvent.EventType.ACTIVATED) jep.setPage(evt.getURL()); } Java实用教程 2. 源程序 //程序文件名为DisplayHtml.java import java.io.*; import java.net.*; import javax.swing.*; import javax.swing.event.*; public class DisplayHtml { //在新窗口显示网页 public static void showNetPage(String str) { Java实用教程 JEditorPane jep = new JEditorPane(); jep.setEditable(false); jep.addHyperlinkListener(new LinkFollower(jep)); try { jep.setPage(str); } catch(IOException e) { jep.setContentType("text/html"); jep.setText("Could not load "+ str + " "); } Java实用教程 JScrollPane jscrollp = new JScrollPane(jep); JFrame f = new JFrame("西安交通大学主页"); f.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); f.setContentPane(jscrollp); f.setSize(600, 400); f.show(); } public static void main(String[] args) { String getURL = "http://www.xjtu.edu.cn"; showNetPage(getURL); } } Java实用教程 //类:新开的网页窗口响应链接点击事件 class LinkFollower implements HyperlinkListener { private JEditorPane jep; public LinkFollower(JEditorPane jep) { this.jep = jep; } //超链接更新事件的处理 public void hyperlinkUpdate(HyperlinkEvent evt) { //判断是否是激活事件 if(evt.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { Java实用教程 try { //显示新的网址 jep.setPage(evt.getURL()); } catch(Exception e) { System.out.println(e.getMessage()); } } } } Java实用教程 3. 结果分析 图11.8 JEditorPane显示的网页 Java实用教程 图11.9 响应链接后进入的网页 Java实用教程 习题 1. 建立TCP Socket读取http://www.263.net网址的首页,将之 存入文件h2.html并在IE中显示此文件。 2. 建立TCP Socket进行通信,服务器端向客户端传送日期数 据。 3. 使用UDP Socket进行通信,服务器和客户相互传送日期 数据。 4. 仔细学习本章音频操作的实例,修改其中的一些数据, 如缓冲值或音频流初始化参数,看是否会影响到音频的质量。 5. 使用java.swing包中的高级控件显示http://www.263.net网 址的首页。 Java实用教程 第12章 Java网络技术(二) 12.1 URL类 12.2 URLEncoder类 12.3 URLDecoder类 12.4 URLConnection类 12.5 HttpURLConnection类 12.6 新IO包的Socket应用 习题 Java实用教程 12.1 URL 类 URL类代表统一资源定位符(Uniform Resource Locator),指 向WWW上的资源,资源可以是一个文件或者一个目录,也可 以是一个更加复杂的对象,如对数据库的查询或者搜索引擎的 查询。通常,一个URL可以被拆分成几个部分,例如: http://192.100.100.43:8080/web/index.html?search="Java " 其中: (1) http用来描述使用的协议为超文本链接协议。 Java实用教程 (2) 192.100.100.43是信息存放的主机IP地址(也可以是主机 名,如www.sohu.com.cn)。 (3) 端口号为8080,默认都为80端口。 (4) web/index.html为HTTP服务器上文件的虚拟路径。 (5) ?search="Java"为网页上表单使用GET方法进行查询的 附加部分,?表示后面跟的是提交的表单的名-值对,格式为 “名=值”。search为查询词的名字,Java为查询词的值,即用 户要查询的值,提交搜索引擎时可以有0个到多个这样的查询名 -值对。 Java实用教程 URL类用来定位WWW上的资源,从而进行处理,如读取网 页等。它的构造函数以及一系列常用的方法如下: public URL(String spec) 从指定的字符串spec创建一个URL对象。 public URL(String protocol, String host, int port, String file) 从指定的protocol协议、host主机、port端口号和file文件名 创建一个URL对象。 public URL(String protocol, String host, String file) 从指定的protocol协议、主机名host和文件名file创建一个 URL对象。 Java实用教程 public Object getContent() 得到URL的内容。 public String getContentType() 返回网页内容类型,普通网页为“text/html”。 public String getFile() 得到URL文件名。 public String getHost() 得到URL的主机名。 public String getPath() 得到URL的路径部分。 public int getPort() 得到URL的端口号。 Java实用教程 public String getProtocol() 得到URL的协议名。 public String getQuery() 得到URL的查询部分。 public URLConnection openConnection() 返回一个URLConnection对象,代表到URL远程对象的连接。 public InputStream openStream() 打开到URL的连接,返回读取连接的输入流。 public String toExternalForm() 构建代表URL对象的字符串。 public String toString() 转换成字符串,覆盖来自对象的toString()方法。 Java实用教程 12.2 URLEncoder类 URLEncoder类是一个工具类,用于HTML表单的编码。类 只包含一个静态方法,这个方法将字符串转换成application/xwww-form-urlencoded MIME格式。该方法如下: public static String encode(String s, String enc) throws UnsupportedEncodingException 使用指定的enc编码格式将字符串s转换为application/xwww-form-urlencoded格式,得以在网上传输。 Java实用教程 其中: (1) s为要转换的字符串。 (2) enc是字符编码格式名称,包括US-ASCII、ISO-8859-1、 UTF-8等。 Java实用教程 【例12.1】将查询表单提交的网址和相应的两个查询“名值对”使用“UTF-8”编码格式进行编码。 1. 分析 (1) 在程序中定义了一个QueryString类,实现多个名-值对 的编码和连接。其中一对名-值对编码如下: query = URLEncoder.encode(name.toString(),"UTF-8") + "=" + URLEncoder.encode(value.toString(),"UTF-8"); Java实用教程 (2) 名-值对之间用符号&连接。 if(!query.trim().equals("")) query += "&"; (3) 主函数中对QueryString类的引用。 QueryString q = new QueryString("cdtype","GB"); q.add("word","Java"); Java实用教程 2. 源程序 //程序文件名UseEncode.java import java.net.*; import java.io.*; public class UseEncode { public static void main(String[] args) { String fullURL = "http://bingle.pku.edu.cn/scripts/ftp_search.exe?"; //新建QueryString对象,调用方法 Java实用教程 QueryString q = new QueryString("cdtype","GB"); q.add("word","Java"); fullURL += q.toString(); //打印编码后的字符串 System.out.println("编码后的字符串:" + fullURL); } } //类:处理请求串,编码成网页识别格式 class QueryString { Java实用教程 private String query; //构造函数,初始名值对的编码 public QueryString(Object name, Object value) { try { query = URLEncoder.encode(name.toString(),"UTF-8") + "=" + URLEncoder.encode(value.toString(),"UTF-8"); } catch(UnsupportedEncodingException e) { System.err.println(e); } } Java实用教程 //构造函数 public QueryString() { query = ""; } //添加名值对,之间用符号&进行连接 public synchronized void add(Object name, Object value) { if(!query.trim().equals("")) query += "&"; try { query += URLEncoder.encode(name.toString(),"UTF-8") + "=" + URLEncoder.encode(value.toString(),"UTF-8"); Java实用教程 } catch(UnsupportedEncodingException e) { System.err.println(e); } } //返回编码后的字符串 public String toString() { return query; } //清空 public void clear() { query = ""; } } Java实用教程 3. 结果输出 图12.1为搜索引擎提交的查询字符串编码的结果。可以看 见提交网址的?后跟了两个名值对,cdtype=GB 和word=Java, 它们之间用符号&隔开。 图12.1 编码后字符串输出结果 Java实用教程 12.3 URLDecoder类 URLDecoder类是URLEncoder类的解码类。它的构造函数 和解码方法如下: public URLEncoder() public static String decode(String s, String enc) 使用编码格式enc对application/x-www-form-urlencoded字符 串s进行解码。 Java实用教程 12.4 URLConnection类 抽象类URLConnection代表应用程序和URL之间通信连接的 类的超类。类的实例可以用来读取和写入URL代表的资源。 URLConnection类实现的两个方法如表12.1所示。 表12.1 URLConnection类实现的两个方法 方法 openConnection() connect() 描述 处理影响到远程资源的连接参数 同资源进行交互,查询头文件和内容 Java实用教程 上述两个方法的实现步骤如下: (1) 调用openConnection方法建立连接对象。 (2) 操作建立参数和普通请求参数。 (3) 调用connect方法建立到远程对象的实际连接。 (4) 远程对象可用,头文件和远程对象的内容可以访问。 Java实用教程 【例12.2】编写程序,访问天网主页(http://e.pku.edu.cn)并查 询Java一词,将查询结果存入result.html文件。 1. 分析 (1) 建立URL对象。 u = new URL(fullURL); (2) 打开到URL对象的连接。 conn = u.openConnection(); (3) 获取输入流。 theData =conn.getInputStream(); (4) 输出到文件。 p.println(line); Java实用教程 2. 源程序 //程序文件名Search.java import java.net.*; import java.io.*; public class Search { public static void main(String args[]) { String fullURL = "http://bingle.pku.edu.cn/scripts/ftp_search.exe?"; URLConnection conn = null; Java实用教程 OutputStream theControl =null; InputStream theData =null; URL u=null; //建立URL对象,参数为请求地址+编码后的请求串 try { fullURL += URLEncoder.encode("cdtype","UTF-8") + "=" + URLEncoder.encode("GB","UTF-8"); fullURL += "&" + URLEncoder.encode("word","UTF-8") + "=" + URLEncoder.encode("Java","UTF-8"); u = new URL(fullURL); } Java实用教程 catch(UnsupportedEncodingException e) { System.err.println(e); } catch(MalformedURLException e) { System.err.println("网页错误:"+fullURL+""+e); System.exit(1); } //打开连接,读入网页流数据 try { conn = u.openConnection(); theData =conn.getInputStream(); //得到网页类型:text/html Java实用教程 String contentType=conn.getContentType(); //建立文件对象和读取的流对象 File f = new File("result.html"); FileOutputStream fOut = new FileOutputStream(f); PrintWriter p = new PrintWriter(fOut); if(contentType.toLowerCase().startsWith("text")) { BufferedReader in = new BufferedReader(new InputStreamReader(theData)); String line; while ((line = in.readLine())!=null) { Java实用教程 //输出到文件 p.println(line); } } else { System.out.println("程序只处理文本响应"); System.out.println("得到的类型为:"+contentType); } } catch(IOException e) { System.err.println(e); System.exit(2); } } } Java实用教程 3. 结果分析 程序运行结果如图12.2所示,左部分为浏览器中天网检索 的结果,右部分为程序检索结果result.html,由于没有考虑图 片的读取,可以看出程序输出缺少所有的图片,但是文本字符 和检索结果都是一致的。 Java实用教程 图12.2 程序检索结果和天网检索结果的对比 Java实用教程 12.5 HttpURLConnection类 HttpURLConnection类继承URLConnection类,专门支持 HTTP协议相关的特征。每个HttpURLConnection实例完成一个 单一的请求,其构造函数如下: protected HttpURLConnection(URL u) 构建一个到URL对象u代表的网络资源的 HttpURLConnection连接。 public int getResponseCode() throws IOException Java实用教程 返回HTTP状态码,如: HTTP/1.0 200 OK HTTP/1.0 401 Unauthorized HttpURLConnection类中有一系列的常量值对应着这些状 态码。例如HTTP_OK对应着上面列出的第一个状态码,而 HTTP_UNAUTHORIZED对应着第二个状态码。 Java实用教程 【例12.3】返回www.sohu.com.cn网址的首页,并与从浏 览器获得的网页进行比较。 //程序文件名为UseHttp.java import java.io.*; import java.net.*; public class UseHttp { public static void main(String[] args) { String urlstring = "http://www.sohu.com.cn"; String httpresp = new String(); String status = new String("good"); try { Java实用教程 //构造URL对象 URL currenturl = new URL(urlstring); urlstring = currenturl.toString(); //判断是否是HTTP协议 if(!currenturl.getProtocol().equals("http")) { status = currenturl.getProtocol() + " protocol"; } else { //打开连接 URLConnection conn = currenturl.openConnection(); //建立HttpURLConnection对象 Java实用教程 HttpURLConnection httpconn = (HttpURLConnection)conn; //判断是否正确返回 if(httpconn.getResponseCode() == HttpURLConnection.HTTP_OK) { if(httpconn.getContentType().equals("text/html")) { //构造文件读写流对象,写入文件 InputStreamReader isr = new InputStreamReader(conn.getInputStream()); File f = new File("sohu.html"); FileOutputStream fOut = new FileOutputStream(f); PrintWriter p = new PrintWriter(fOut); Java实用教程 int c; while((c = isr.read()) != -1) { p.write(c); } isr.close(); httpconn.disconnect(); } else status = "Not text/html"; } else status = "bad"; } } Java实用教程 catch(Exception e) { status = e.toString(); System.out.println("Exception:" + e.getMessage()); } if(status.equals("good")) { System.out.println(urlstring); } else { System.out.println(status); System.out.println("Bad URL = " + urlstring); } } } Java实用教程 由图12.3可以看出,左边的页面是网址首页,右边的网页 是程序生成的sohu.html页面。比较可得,两个页面是一致的。 可以看出随着类的依次封装,可应用领域变窄(从Socket到URL, 再到针对HTTP协议的URL),但相对专门的应用而言,用户使 用起来更为简单。 Java实用教程 图12.3 程序输出页面和网址首页的比较 Java实用教程 12.6 新IO包的Socket应用 在J2sdk1.4中提供了一个新I/O包(java.nio),通过引入四个基 本抽象类,开发网络Socket连接的非阻塞应用。对于第11章Java 编程中的多个Socket连接,用线程实现时会遇到一些问题,如操 作系统限制、死锁、线程安全违反等。而新I/O提供的特性可以很 好地解决这些问题。引入的四个基本抽象类如下: Buffer:包含读写的数据线性流。 Charset:将Unicode字符与字节流之间进行相互转换。 Channels:可以是Socket、文件或管道,代表双边通信的管道。 Selectors:多元异步I/O操作,应用于单个线程或多个线程。 Java实用教程 12.6.1 Buffers Buffer是一个线性、有序的数据集,提供了一种在内存容 器中保存一系列原始数据的机制。Buffer进行特定的封装之后 只允许读写一种数据类型,例如char、int或double等。共有七 种读写不同数据类型的Buffer,如表12.2所示。 表12.2 读写不同数据类型的Buffer Buffer 名字 Buffer ByteBuffer CharBuffer DoubleBuffer FloatBuffer IntBuffer LongBuffer ShortBuffer 存放数据类型 抽象基类 字节 字符 双精度数 单精度数 整数 长整数 短整数 Java实用教程 Buffer中涉及到的四个基本概念是capacity(容量)、 position(位置)、limit(限制)和mark(标记)。 ● capacity——Buffer的大小(>=size); ● position——在Buffer中目前读写的位置(<=limit); ● limit——第一个不应该被读取元素的位置的index(索引 号)(<=capacity); ● mark—— 用mark方法设置的可设位置,mark方法可以 使用reset来重置position(<=position,>=0)。 Java实用教程 【例12.4】下面给出一段缓冲操作的代码,依次演示 capacity、position和limit的值,代码段为: ByteBuffer buf = ByteBuffer.allocateDirect(8); buf.put( (byte)0xca ); buf.putShort( (short)0xfeba ); buf.put( (byte)0xbe ); buf.flip(); Java实用教程 代码段分析如下: ByteBuffer buf = ByteBuffer.allocateDirect(8); 分配8字节的字节缓冲,position=0、capacity=8、limit=8, 如图12.4(a)所示。 buf.put( (byte)0xca ); buf.putShort( (short)0xfeba ); buf.put( (byte)0xbe ); 依次放入三个数据,两个字节数据和一个短整型数据,其 中短整型数据占两个字节,position=4、capacity=8,如图12.4(b) 所示。 buf.flip(); Java实用教程 上面这行语句是填充数据之后、写入通道之前需要调用 的方法,将position重定位到0,将limit定位到数据结束位置, 准备好序列写入通道。position=0、capacity=8、limit=4,如图 12.4(c)所示。 Java实用教程 capacity= 8 limit= 8 position= 0 (a) capacity= 8 0xca 0xfe 0xba 0xbe position= 4 (b) limit= 4 capacity= 8 0xca 0xfe 0xba 0xbe position= 0 (c) 图12.4 缓冲的变化过程显示 Java实用教程 12.6.2 Charset Charset(字符集)定义了Unicode和字节之间的映射。字符集 根据IANA标准定义,Java中字符集由java.nio.charset.Charset实 例代表,使用Charset.forName()得到合适实例。 Charset.availableCharsets()给出支持字符集名的映射和它们的 Charset实例。JDK1.4包括8个字符集:US-ASCII、ISO-8859-1、 ISO-8859-15、UTF-8、UTF-16等。Charset构造CharsetEncoder 和CharsetDecoder,使得有序字符和字节之间可以进行转换, 输出时使用encoder,对输入请求使用decoder。以下代码段是 对字符buffer进行编码的情况。 Java实用教程 Charset charset = Charset.forName("UTF-8");//ISO-8859-1US-ASCII ByteBuffer buffer = charset.newEncoder().encode(chars); ByteBuffer directBuffer = ByteBuffer.allocateDirect(buffer.limit()); directBuffer.put(buffer); Java实用教程 12.6.3 Channels 1. ServerSocketChannel Java.nio.channels.ServerSocketChannel与 java.net.ServerSocket一样,用于创建一个监听线程来接收到来 的连接,只是既不能读也不能写。ServerSocketChannel.socket() 提供对底层ServerSocket的访问,因此可以设置Socket选项。这 个通道可以使用ServerSocketChannel.open()工厂方法创建。 ServerSocketChannelaccept()为新建立连接的客户返回 java.nio.channel.SocketChannel。如果ServerSocketChannel进入阻 塞模式,accept()不会返回,直到一个有连接请求到达;而在非 阻塞模式,不管Socket是否为空,总是立刻返回。 Java实用教程 2. SocketChannel Java.nio.channels.SocketChannel在应用程序中封装了 java.net.Socket并添加非阻塞模式和状态机。SocketChannel可 以通过两种方法创建:SocketChannel.open()创建一个新的、 无连接的SocketChannel;通过ServerSocketChannel.accept()返 回的Socket,实际上有一个开放和连接的SocketChannel附加在 它上面。 Java实用教程 3. FileChannel 文件通道允许使用操作系统的文件缓冲直接进行文件传输。 文件通道可以将文件区域映射到内存。 MappedByteBuffer是一个专门用于直接缓冲的ByteBuffer, 这个类用字节缓冲来映射一个文件。想要映射一个文件到 MappedByteBuffer,必须先取得这个文件的通道(channel)。通 道是某种已建立的连接,如管道(Pipe)、套接口(Socket)或文件 (File)等能够完成I/O操作的对象。 Java实用教程 如果是文件通道,你可以通过FileInputStream(文件输入 流)、FileOutputStream(文件输出流)或RandomAccessFile(随机 存取文件)的getChannel方法来获得一个通道。一旦你取得这个 通道,就可以通过它的map方法指明映射模式,来把你想映射 的那一部分文件映射到缓冲中去。文件通道可以使用 FileChannel.MapMode的任一个常数打开:只读(READ_ONLY)、 私有/写时拷贝(PRIVATE)或读写(READ_WRITE)。 Java实用教程 【例12.5】使用文件通道打开一个文件并输出文件内容。 1. 分析 (1) 通过文件输入流对象得到通道。 FileInputStream input = new FileInputStream(filename); FileChannel channel = input.getChannel(); (2) 映射到字节缓冲。 int fileLength = (int)channel.size(); MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, fileLength); Java实用教程 (3) 字符集进行解码。 Charset charset = Charset.forName("ISO-8859-1");// CharsetDecoder decoder = charset.newDecoder(); CharBuffer charBuffer = decoder.decode(buffer); (4) 输出文件内容。 System.out.println(charBuffer); Java实用教程 2. 源程序 //程序文件名为UseFchannel.java import java.io.*; import java.nio.*; import java.nio.channels.*; import java.nio.charset.*; class UseFchannel { public static void main(String[] args) { try { Java实用教程 String filename = "f.txt"; FileInputStream input = new FileInputStream(filename); FileChannel channel = input.getChannel(); int fileLength = (int)channel.size(); MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, fileLength); Charset charset = Charset.forName("ISO-8859-1");// CharsetDecoder decoder = charset.newDecoder(); CharBuffer charBuffer = decoder.decode(buffer); System.out.println(charBuffer); Java实用教程 } catch(Exception e) { System.out.println("Error:" + e.getMessage()); } } } Java实用教程 3. 结果分析 图12.5上一部分显示打开的文件内容,下一部分显示程序 输出的内容,可以看出两者是一致的。 图12.5 源文件内容与程序输出的内容对比 Java实用教程 12.6.4 Selectors 非阻塞I/O围绕为多元选择通道准备的Selectors(选择器)对 象构建。选择器对象保持一系列选择键,这些键在应用中可由 某个事件激活。选择器本身管理键,编程人员使用键的状态管 理回调来完成客户请求。 构造函数如下: protected Selector() 初始化一个实例。 选择器可以通过调用自带的open方法进行创建: Selector s = Selector.open(); Java实用教程 下面的两个方法用来返回选择键值的个数和键值集合。 public abstract int select() throws IOException 返回键值的个数。 public abstract Set selectedKeys() 返回选择器选中的键值集合。 对于一个Socket通道,只有将它本身发生的事件(如监听、 连接、读、写等)在选择器上进行注册,才可以被选择器识别, 从而进行处理,这个注册就用到SelectionKey类。SelectionKey 类包括四个注册值,将通道支持的事件注册到相应的选择器上。 它还提供四个判断键值状态的方法,从而进行相应的事件处理, 如表12.3所示。 Java实用教程 表12.3 SelectionKey类的注册值及其方法 注册值 OP_ACCEPT OP_CONNECT OP_READ OP_WRITE 注册事件 接收 连接 读取 写入 键值状态判断函数 public boolean isAcceptable() public boolean isConnectable() public boolean isReadable() public boolean isWritable() 函数描述 测试通道是否可接收 测试通道连接完成或失败 测试通道是否可读 测试通道是否可写 Java实用教程 例如,接收新连接的通道应该注册为: ServerSocketChannel ch = ServerSocketChannel.open(); SelectionKey acceptKey = ch.register(s,SelectionKey.OP_ACCEPT); 一个读取和写入数据的通道应该注册为: SelectionKey readWriteKey = ch.register(s,SelectionKey.OP_READ|SelectionKey.OP_WRITE); 当用户发送一个请求时,选择器通过返回键进行工作。 //循环实现 While((keysAdded = s.select())>0) { Java实用教程 //返回键值集合 set readyKeys = s.selectedKeys(); //使用Iterator枚举 Iterator I = readKeys.iterator(); While(i.hasNext()) { SelectionKey sk = (SelectionKey)i.next(); ...接收连接处理请求; } } Java实用教程 具体的处理可以根据键值的状态进行,上面的“接收连 接处理请求”就可以为: i.remove(); if ( key.isAcceptable() ) { ... } else if ( key.isWritable() ) { ... } Java实用教程 12.6.5 阻塞模式 在阻塞模式下,服务器端和客户端的程序基本相同,惟一 不同的是客户端为Connect方法,服务器端为Accept方法。 新I/O包处理Socket的读写操作时使用java.net包中的 InetSocketAddress类指定链接地址,并用前面介绍的 SocketChannel类来完成实际的读写操作。InetSocketAddress类提 供一个用来绑定、连接或者返回数值的远程对象。它常用的构 造函数为: InetSocketAddress(String hostname, int port) 以名字hostname和端口号port创建socket地址。 Java实用教程 客户端使用SocketChannel建立连接的步骤如下: (1) 首先获得InetSocketAddress的对象。 String host = "www.sohu.com.cn"; InetSocketAddress socketAddress = new InetSocketAddress(host, 80); (2) 打开一个到InetSocketAddress代表的主机的连接。 使用SocketChannel取代以前从Socket对象的输入流来读取、 向Socket的输出流写入的所有操作: SocketChannel channel = SocketChannel.open(); channel.connect(socketAddress); Java实用教程 (3) 发送一个HTTP请求,发送请求之前进行编码。 Charset charset = Charset.forName("ISO-8859-1"); CharsetEncoder encoder = charset.newEncoder(); String request = " GET / HTTP/1.0\r\n\r\n "; channel.write(encoder.encode(CharBuffer.wrap(request))); Java实用教程 (4) 从通道中读取服务器的响应。 ByteBuffer buffer = ByteBuffer.allocateDirect(1024); CharBuffer charBuffer = CharBuffer.allocate(1024); while ((channel.read(buffer)) != -1) { buffer.flip(); decoder.decode(buffer, charBuffer, false); charBuffer.flip(); System.out.println(charBuffer); buffer.clear(); charBuffer.clear(); } Java实用教程 【例12.6】下面这个程序通过一个HTTP请求来读取站点 www.xjtu.edu.cn的首页,直接输出到屏幕上,可以看见是网页 的文本文件。源程序代码如下: //程序文件名为ReadURL.java import java.io.*; import java.net.*; import java.nio.*; import java.nio.channels.*; import java.nio.charset.*; Java实用教程 public class ReadURL { public static void main(String args[]) { SocketChannel channel = null; String host = "www.xjtu.edu.cn"; try { //建立连接 InetSocketAddress socketAddress = new InetSocketAddress(host, 80); Java实用教程 Charset charset = Charset.forName("ISO-8859-1"); CharsetDecoder decoder = charset.newDecoder(); CharsetEncoder encoder = charset.newEncoder(); //分配缓冲 ByteBuffer buffer = ByteBuffer.allocateDirect(1024); CharBuffer charBuffer = CharBuffer.allocate(1024); //连接 channel = SocketChannel.open(); channel.connect(socketAddress); //发送请求 String request = "GET / HTTP/1.0\r\n\r\n"; channel.write(encoder.encode(CharBuffer.wrap(request))); while ((channel.read(buffer)) != -1) { Java实用教程 buffer.flip(); //解码 decoder.decode(buffer, charBuffer, false); //输出 charBuffer.flip(); System.out.println(charBuffer); buffer.clear(); charBuffer.clear(); } } catch (UnknownHostException e) { System.err.println(e); } catch (IOException e) { System.err.println(e); Java实用教程 } finally { if (channel != null) { try { channel.close(); } catch (IOException ignored) {} } } } } Java实用教程 12.6.6 非阻塞模式 1. 非阻塞客户端 (1) 创建可选择通道,配置成非阻塞模式并进行连接。 String host = "192.100.100.43"; InetSocketAddress socketAddress = new InetSocketAddress(host, 80); channel = SocketChannel.open(); channel.configureBlocking(false); channel.connect(socketAddress); 这时得到的通道channel是一个可选择通道(SelectableChannel), 通过一个Selector来工作。将通道注册到一个Selector,同时声明 一些事件,当事件发生时通道会通过回调执行。 Java实用教程 (2) 创建Selector实例。 Selector selector = Selector.open(); (3) 通道向选择器的注册。对于SocketChannel类来说,有 效的操作事件是OP_CONNECT、OP_READ 和 OP_WRITE, 因此可以进行如下注册: channel.register(selector, SelectionKey.OP_CONNECT | SelectionKey.OP_READ); Java实用教程 (4) 处理通道事件。当有事件在通道上发生时,Selector进 行通知,然后使用一个while (selector.select() > 0)循环进行处 理。发出请求后得到响应的代码都放入这一段,当作读写事 件进行处理。 (5) 加入异常处理代码。加入必要的 try{...}catch(Exception e){...}语句,并在finally代码段中加入关 闭通道的代码。 Java实用教程 【例12.7】下面是完整的例子程序,结果是得到本机 tomcat主页并显示在标准输出上。用户也可以将它输出到文件 中,以方便与原网页进行比较。源程序代码如下: //程序文件名为NBReadURL.java import java.io.*; import java.net.*; import java.nio.*; import java.util.*; import java.nio.channels.*; import java.nio.charset.*; Java实用教程 public class NBReadURL { static Selector sele; public static void main(String args[]) { String host = "192.100.100.43"; SocketChannel channel = null; try { Java实用教程 //初始化 InetSocketAddress sockAddr = new InetSocketAddress(host, 8080); Charset charset = Charset.forName("ISO-8859-1"); CharsetDecoder decoder = charset.newDecoder(); CharsetEncoder encoder = charset.newEncoder(); //分配缓冲 ByteBuffer buf = ByteBuffer.allocateDirect(1024); CharBuffer cbuf = CharBuffer.allocate(1024); //连接 channel = SocketChannel.open(); channel.configureBlocking(false); channel.connect(sockAddr); Java实用教程 //打开选择器 sele = Selector.open(); channel.register(sele, SelectionKey.OP_CONNECT|SelectionKey.OP_READ); //Wait for something of interest to happen while(sele.select(500)>0) { //得到对象 Set readyKeys = sele.selectedKeys(); Iterator readyItor = readyKeys.iterator(); Java实用教程 //遍历对象集 while(readyItor.hasNext()) { //得到键 SelectionKey k = (SelectionKey)readyItor.next(); //Remove current entry readyItor.remove(); //得到通道 SocketChannel keyChannel = (SocketChannel)k.channel(); if(k.isConnectable()) { Java实用教程 //完成连接 if(keyChannel.isConnectionPending()) { keyChannel.finishConnect(); } //发送请求 String request = "GET /index.html \r\n\r\n"; keyChannel.write(encoder.encode(CharBuffer.wrap(request))); } else if(k.isReadable()) { Java实用教程 //读取数据 keyChannel.read(buf); buf.flip(); //解码 decoder.decode(buf, cbuf, false); //显示 cbuf.flip(); System.out.print(cbuf); //清除缓冲 buf.clear(); cbuf.clear(); } else { Java实用教程 System.err.println("Ooops"); } } } } catch(UnknownHostException e) { System.err.println(e); } catch(IOException e) { System.err.println(e); } finally { if(channel != null) Java实用教程 { try { channel.close(); } catch(IOException ignored) { } } } System.out.println(); } } Java实用教程 2. 非阻塞服务器 使用新I/O包实现的非阻塞Web服务器,不必为每个连接都 提供一个线程就可以实现Web服务器的功能。非阻塞服务器程 序编写的步骤如下: (1) 创建接收通道,配置非阻塞模式并绑定到 InetSocketAddress对象。 ServerSocketChannel channel = ServerSocketChannel.open(); channel.configureBlocking(false); InetSocketAddress isa = new InetSocketAddress(port); channel.socket().bind(isa); Java实用教程 (2) 创建Selector实例。 Selector selector = Selector.open(); (3) 注册事件。服务器端需要注册的是OP_ACCEPT键值: channel.register(selector, SelectionKey.OP_ACCEPT); (4) 处理通道事件。当有事件在通道上发生时,Selector进 行通知,然后使用一个while (selector.select() > 0)循环进行处理。 发出请求得到响应的代码都放入这一段,当作读写事件进行处 理。 Java实用教程 (5) 添加异常处理代码。加入必要的try{...}catch(Exception e){...}语句,并在finally代码段中加入关闭通道的代码。 可以看出非阻塞模式下服务器和客户端编程的步骤都是一 致的,只是有些步骤下编写的代码有所不同。 Java实用教程 【例12.8】给出一个基本的单线程的服务器,对每一个响应 都发回一段文字信息来表示时间。源程序代码如下: //程序文件名为Server.java import java.io.*; import java.net.*; import java.nio.*; import java.nio.channels.*; import java.util.*; public class Server { Java实用教程 private static int port = 4321; public static void main(String args[]) throws Exception { Selector selector = Selector.open(); ServerSocketChannel channel = ServerSocketChannel.open(); channel.configureBlocking(false); InetSocketAddress isa = new InetSocketAddress(port); channel.socket().bind(isa); //注册 channel.register(selector, SelectionKey.OP_ACCEPT); while (selector.select() > 0) { Java实用教程 Set readyKeys = selector.selectedKeys(); Iterator readyItor = readyKeys.iterator(); while (readyItor.hasNext()) { SelectionKey key = (SelectionKey)readyItor.next(); readyItor.remove(); ServerSocketChannel keyChannel = (ServerSocketChannel)key.channel(); ServerSocket serverSocket = keyChannel.socket(); Socket socket = serverSocket.accept(); //返回时间 Java实用教程 PrintWriter out = new PrintWriter(socket.getOutputStream(), true); Date now = new Date(); out.println("Hello, now time is: " + now); out.close(); }//End of While }//End of While }//End of main } Java实用教程 为了服务器与客户端能够进行通信,对例12.7的客户端程 序进行修改,将InetSocketAddress对象sockAddr中的端口号改 成4321,使得客户端请求的端口号与此服务器监听的端口号一 致,即将 InetSocketAddress sockAddr = new InetSocketAddress(host, 8080); 改为 InetSocketAddress sockAddr = new InetSocketAddress(host, 4321); 然后重新编译,生成类文件。 启动两个命令提示符,其中一个为运行命令“java Server”, 另一个为键入命令“java NBReadURL”,可以看见如图12.6的 通信结果。客户端显示服务器发送的一段时间信息。如果希望 在服务器端显示内容,还需修改服务器程序,注册服务器通道 的读、写事件。 Java实用教程 图12.6 非阻塞模式下的通信输出 Java实用教程 习题 1. 给出字符串,熟悉URLEncoder和URLDecoder类的规范。 2. 从天网主页http://e.pku.edu.cn检索包含“网络”一词的文件。 3. 使用HttpURLConnection对象打开网页并输出到文件中。 4. 使用文件通道将例12.6的程序输出改成输出到文件中。 5. 编写非阻塞模式下的Socket通信。 Java实用教程 第13章 Servlet技术 13.1 Servlet概述 13.2 Servlet生命周期 13.3 使用Servlet 13.4 Applet与Servlet通信 习题 Java实用教程 13.1 Servlet 概 述 Servlet是用Java编写的且协议和平台都独立的服务器端的组 件。与客户端组件Applet相对应。Servlet扩展了面向请求/响应 的服务器的模块,使用平台专用的API进行服务器端的编程。 Servlet为服务器和基于Web的客户之间的通信提供了一条更为简 单的途径。它的特殊用途包括: (1) 允许用户之间的合作。一个Servlet可以同时并发处理大 量的请求,而且可以同步请求,因此使Servlets能够支持像在线 会议这样的系统。Servlets能够并发地服务多个客户。 Java实用教程 (2) 转发请求。Servlets能够转发请求到其它的服务器和 Servlets,因此Servlets能够被用来在多个镜像同一个内容的服 务器之间来平衡负载,在多个服务器上根据任务类型或者组织 边界分割单一的逻辑服务。 Java实用教程 13.2 Servlet生命周期 服务器 Servlet代 码 载 入 Servlet代 码 服务器 处理 用户请求 客户 客户 服务器 销毁 Servlet代 码 图13.1 Servlet的生命周期 Java实用教程 1. 初始化Servlet 当服务器载入一个Servlet时,服务器运行Servlet的init方法。 初始化在客户请求被处理和Servlet被销毁之前完成。 Java实用教程 2. Servlet_Client交互 初始化成功后,HTTP Servlet调用Service方法处理客户请求, Service方法将每个请求分配到处理这个请求的方法,从而支持 标准的HTTP客户请求。HttpServlet类中的方法处理客户请求时 使用以下两个参数: (1) HttpServletRequest对象:封装了从客户来的数据,主要 提供了访问初始请求数据的方法和字段;访问客户数据时使用 getParameter方法得到一个已命名参数的值。 (2) HttpServletResponse对象:封装了对客户的响应。使用 getWriter方法返回文本数据给客户(可以以HTML网页的形式表 现出来)。 Java实用教程 Service方法支配的HTTP请求如表13.1所示。 表13.1 Service方法支配的HTTP请求 doGet doPost doPut deDelete Service 方法 处理的 HTTP 请求 处理 GET、条件 GET 和 HEAD 请求 处理 POST 请求 处理 PUT 请求 处理 DELETE 请求 Java实用教程 通常,编写的Servlet应该重载处理它支持的HTTP交互的方 法。如果出错,这些方法返回一个BAD_REQUEST(400)错误。 当Servlet收到OPTIONS请求时,HttpServlet的Service方法调用 doOptions方法。默认的doOptions的实现自动地决定了支持何种 HTTP选项和返回信息。HTTP Servlets通常能够并发地服务多 个客户。如果Servlet中的这个方法对于客户访问共享资源是可 行的,那么你可以通过创建在某一时刻只能处理一个客户请求 的Servlet来处理并发。 Java实用教程 3. 销毁Servlet Servlet一直运行直到服务器销毁它们,比如在系统管理员 的要求下。当一个服务器销毁一个Servlet时,服务器运行 Servlet的Destroy()方法。方法只运行一次,服务器将不再运行 Servlet,直到服务器重新载入和重新初始化Servlet。 Java实用教程 13.3 使用Servlet 13.3.1 编写Servlet 【例13.1】 在客户端填写“用户注册信息”网页,并将此 网页提交到后台服务器端Servlet,服务器端Servlet程序给予响 应,并以网页的形式按行输出用户提交的基本信息。 1. 客户端 客户端是一个“用户注册信息”的HTML网页,如图13.2所 示。用户输入个人信息,点击“确定”按钮,将表单数据提交 到服务器,然后等待服务器的响应。Index.html源文件代码如下: Java实用教程 用户注册信息收集

用户注册信息
Java实用教程

姓名:
身份证号:
性别 女 Java实用教程 职业
个性化宣言
Java实用教程

Java实用教程 图13.2 “用户注册信息”网页 Java实用教程 在网页index.html中要注意表单的书写,表单的action属性 对应服务器端的Servlet,本例中取值为 http://192.100.100.43:8080/examples/Servlet/user.UserServlet; method属性是访问方法,本例中为POST方法。表13.2是表单中 的元素标签和命名,可以看到除去“确定”和“清空”,其它 的元素标签在第三栏都有一个对应的名字,Servlet通过这些名 字获得用户在界面上输入的值,而用户单击“确定”按钮时, 表单内容就提交到action属性指定的Servlet。 Java实用教程 表13.2 表单元素标签及命名 元素标签 姓名 身份证号 性别 职业 个性化宣言 确定 清空 类型 text text radio select textarea submit reset 标签命名 name number sex job ta \ \ Java实用教程 2. 服务器端 服务器端Servlet收集用户界面输入的数据(见图13.3),然后 按行返回这些内容,结果如图13.4所示。注意传输过程中中文 字符可能会有出错情况,因此再添加一个转换字段,使得 Servlet能够正确打印输出。 //程序文件名:UserServlet.java package user; import java.io.*; import javax.Servlet.*; import javax.Servlet.http.*; public class UserServlet extends HttpServlet { Java实用教程 String name,number,sex,job,ta; public void init() throws ServletException { super.init(); name = new String(); number = new String(); sex = new String(); job = new String(); ta = new String(); } //解决中文转换问题 public String parseChinese(String inStr) { Java实用教程 String s = null; byte temp[]; if (inStr == null) { //System.out.println("Warn:Chinese null founded!"); return new String(""); } try { temp=inStr.getBytes("iso-8859-1"); s = new String(temp); } catch(UnsupportedEncodingException e) { Java实用教程 System.out.println (e.toString()); } return s; } public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { //获取用户界面输入的值 name = req.getParameter("name"); number = req.getParameter("number"); sex = req.getParameter("sex"); job = req.getParameter("job"); Java实用教程 ta = req.getParameter("ta"); //进行输出 res.setContentType("text/html; charset=GB2312"); PrintWriter out = res.getWriter(); out.println("
"); out.println("注册信息返回结果
"); out.println(" 姓名:" + parseChinese(name)); out.println("
身份证号:" + number); out.println("
性别:" + parseChinese(sex) + " 职业:" + parseChinese(job)); out.println("
个性化宣言:" + parseChinese(ta) + "
"); } } Java实用教程 图13.3 用户输入注册信息 Java实用教程 图13.4 Servlet返回信息 Java实用教程 13.3.2 编译、配置Servlet 安装的Java包是没有带Servlet的JAR文件,所以将 D:\Apache Tomcat 4.0\common\lib目录下的Servlet.jar配置到路径 包的安装路径下库的扩展目录中,编译时会自动连接库,如本 书配置到的目录为D:\j2sdk1.4.0_01\jre\lib\ext。在命令行提示符 下键入命令javac UserServlet.java编译文件,生成类 UserServlet.class。 Java实用教程 Servlet是服务器端组件,所以必须配置到服务器端。对于 Tomcat 4.0服务器,将index.html配置到物理路径D:\Apache Tomcat 4.0\webapps\ROOT\user目录下,对应的网络路径就是 http://192.100.100.43:8080/user/index.html;将UserServlet配置到 物理路径下的D:\Apache Tomcat 4.0\webapps\examples\WEBINF\classes\user目录下,对应的网络地址就是 http://192.100.100.43:8080/examples/Servlet/user.UserServlet。这 些配置信息由index.html中的Action属性标明。 Java实用教程 如果希望能够配置到根目录下,则在开始->程序->Apache Tomcat 4.0->Configuration中单击EditServer Configuration,然后 找到行: ,将以上语句变成: Java实用教程 将机器重启动,使得配置文件生效,并在D:\Apache Tomcat 4.0\webapps\ROOT\WEB-INF路径下建立classes目录, 然后将UserServlet.java源文件中的语句行package user;去掉,重 新编译成.class类文件并放入此目录,则action属性对应的网络 地址为 http://192.100.100.43:8080/Servlet/ UserServlet Java实用教程 13.4 Applet与Servlet通信 Applet与Servlet的通信过程的基本原理相当于HTML网页的 POST请求。首先两者之间建立一个连接,使用URLConnection 类对象打开连接后,Applet将请求发送给Servlet,Servlet处理请 求并返回处理结果。注意,发送请求数据时一定用URLEncoder 类的Encode方法进行格式编码,在Servlet端还需用URLDecoder 类的Decode方法进行格式解码。 在HTTP协议中POST请求是以参数名=参数值的方式自动 进行URL编码后传送的,编程中要手工实现,例如名-值对 Java实用教程 qry = SELECT number,code,score from chengji WHERE code='3001' 进行URL编码如下: String qry = URLEncoder.encode("qry","UTF-8") + "=" + URLEncoder.encode(qryString,"UTF-8"); 建立连接时,注意将DbServlet配置到路径D:\Apache Tomcat 4.0\webapps\ROOT\WEB-INF\classes下。 Java实用教程 String str = "http://192.100.100.43:8080/Servlet/DbServlet"; URL urlName = new URL(str); 打开连接。 URLConnection uc = urlName.openConnection(); 设置参数。 uc.setDoOutput(true); uc.setDoInput(true); uc.setUseCaches(false); Java实用教程 uc.setRequestProperty("Content-type","application/x-wwwform-urlencoded"); 得到数据流发送格式转换后的POST请求 。 DataOutputStream dos = new DataOutputStream(uc.getOutputStream()); dos.writeBytes(qry); 在DbServlet中接收数据并进行解码。 String qry = req.getParameter("qry"); qry = URLDecoder.decode(qry,"UTF-8"); Java实用教程 【例13.2】编写Applet和Servlet交互的程序,使得用户在 Applet界面(见图13.5)上输入数据库查询语句,单击“查询”按 钮后,后台Servlet接收请求,对后台数据库进行查询,并将查 询结果返回到Applet界面的文本区域内。 图13.5 Applet用户界面 Java实用教程 URLConnection打 开 连 接 , 发送请求 Java Applet Java Servlet 流对象接收返回结果 ResultSet 对象 SQL查 询 数据库 图13.6 Applet和Servlet交互原理图 Java实用教程 13.4.1 Servlet文件 首先书写查询数据库的Servlet文件,编译通过后配置到上面 提到的路径。 //程序文件名DbServlet.java import javax.Servlet.*; import javax.Servlet.http.*; import java.util.*; import java.sql.*; import java.io.*; import java.net.*; Java实用教程 public class DbServlet extends HttpServlet { public void doPost(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { PrintWriter out = res.getWriter(); res.setContentType("text/html;charset=GB2312"); //得到Applet请求参数,解码后输出 String qry = req.getParameter("qry"); qry = URLDecoder.decode(qry,"UTF-8"); out.println(qry); Connection dbCon = null; try Java实用教程 { //同数据库建立连接 Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); String dbURL = "jdbc:odbc:STU"; dbCon = DriverManager.getConnection(dbURL,"",""); PreparedStatement p = dbCon.prepareStatement(qry); ResultSet rs = p.executeQuery(); //输出查询结果 while(rs.next()) { out.print(rs.getString(1)); out.print(rs.getString(2) + " "); out.println(rs.getInt(3)); } Java实用教程 } catch(Exception e) { out.println("读写数据库出错:" + e.getMessage()); } finally { try { dbCon.close(); out.close(); } catch(Exception e) Java实用教程 { out.println("关闭数据库连接出错:" + e.getMessage()); } } } }; Java实用教程 13.4.2 Applet文件 编写与Servlet通信的Applet文件。 //程序文件名DbApplet.java import java.awt.*; import java.applet.*; import java.awt.event.*; import java.io.*; import java.net.*; public class DbApplet extends Applet implements ActionListener { TextField tfQuery; Java实用教程 TextArea taResults; Button btnExecute; URL chatURL; public void init() { Panel pa = new Panel(); pa.setLayout(new FlowLayout(FlowLayout.LEFT)); pa.add(new Label("查询串:")); tfQuery = new TextField("SELECT number,code,score from chengji WHERE code='3001'",50); Java实用教程 pa.add(tfQuery); btnExecute = new Button("查询"); btnExecute.addActionListener(this); pa.add(btnExecute); add("North",pa); taResults = new TextArea(30,60); add("Center",taResults); chatURL = getCodeBase(); } public void actionPerformed(ActionEvent evt) { Java实用教程 String lbl = evt.getActionCommand(); if(lbl.equals("查询")) { String qryString = tfQuery.getText(); try { //查询串编码 String qry = URLEncoder.encode("qry","UTF-8") + "=" + URLEncoder.encode(qryString,"UTF-8"); //打开到DbServlet的连接 String str = "http://192.100.100.43:8080/Servlet/DbServlet"; Java实用教程 URL urlName = new URL(str); URLConnection uc = urlName.openConnection(); uc.setDoOutput(true); uc.setDoInput(true); uc.setUseCaches(false); uc.setRequestProperty("Content-type","application/xwww-form-urlencoded"); //获得输出流 DataOutputStream dos = new DataOutputStream(uc.getOutputStream()); Java实用教程 //发送编码的查询串 dos.writeBytes(qry); dos.close(); //获取结果,输出 InputStreamReader in = new InputStreamReader(uc.getInputStream()); int chr = in.read(); while(chr != -1) { taResults.append(String.valueOf((char)chr)); chr = in.read(); } Java实用教程 in.close(); } catch(MalformedURLException e) { taResults.setText(e.toString()); } catch(IOException e) { taResults.setText(e.toString()); } } } } Java实用教程 13.4.3 HTML文件 最后编写HTML文件,用户最好将它转换成使用插件的文件,使 用插件的文件具有较好的应用性。
Java实用教程 13.4.4 结果显示 本例中用到的表为STU配置下的Chengji表,部分记录如图 13.7所示。查询串分别为: SELECT number,code,score from chengji WHERE code= ' 2001' SELECT number,code,score from chengji WHERE code= ' 1002' 而查询结果如图13.8所示。对照Chengji表,得出查询结果 完全正确。 Java实用教程 图13.7 STU库中的Chengji表 Java实用教程 图13.8 查询结果的输出 Java实用教程 习题 1. 编写Servlet程序,进行数据库访问,将数据库结果以表 格的形式显示在HTML网页上。 2. 编写Applet和Servlet的交互程序,Applet请求打开一个文 本文件,Servlet接收文件的路径和名称,返回文本文件的内容。 在Applet界面上的文本框内输入文件路径以及名称,单击“请 求”按钮,得到Servlet的响应,返回的内容输出到Applet界面上 的文本区域内。设计具体界面时可参考图13.9。 Java实用教程 图13.9 用户界面 Java实用教程 第14章 Java读写XML技术 14.1 XML简介 14.2 SAX接口解析XML 14.3 DOM接口解析XML 习题 Java实用教程 14.1 XML 简 介 14.1.1 XML定义 XML是SGML一个简化而严格的子集,特别是为Web应用设 计的,具有可扩展性、结构性和可检验性。 ●可扩展性指用户可以根据需要自定义新的标识以及属性名, 更好地从语义上修饰数据。 ●结构性指XML文件结构可以嵌套,也可以复杂到任意程 度。 ●可校验性指XML文件文件可以包括一个语法描述,应用 程序可以通过语法描述对此文件进行结构检验。 Java实用教程 14.1.2 XML分类 XML (元 语 言 标 准 ) HTTP URI/URL Unicode (外 围 标 准 ) Schema DOM xInclude … … (操 作 标 准 ) (核 心 标 准 ) CSS XSL RDF XSLT … … (内 容 描 述 标 准 ) (样 式 与 链 接 标 准 ) (基 础 标 准 ) cXML … (应 用 标 准 ) 图14.1 XML相关标准的体系结构 Java实用教程 XML相关标准主要分为三类,分别是元语言标准、基础 标准和应用标准。 1. 元语言标准 用来描述标准的元语言,即XML标准。 Java实用教程 2. 基础标准 为XML进一步实用化制定的标准,共分为五类:外围标准、 核心标准、操作标准、样式与链接标准、内容描述标准。 (1) 外围标准指Internet网络上统一应用的标准: ● HTTP协议采用请求/应答方式,客户端向服务器提交请 求方式、URI、协议版本、客户端信息等,服务器向客户端返 回状态信息、实体信息以及实体内容等。 ● URI/URL指资源定位符,用来在网络上实现快速资源定 位。 ● Unicode指Internet网上统一传输数据的标准编码。 Java实用教程 (2) 核心标准是XML核心的标准。 (3) 操作标准为XML文档的处理提供有效的方法与规则, DOM是与平台无关的,提供一个编程接口。Schema是对DOM 的补充,提供一种更为严格的描述XML文档的结构、属性、 数据类型等的方法。 Java实用教程 (4) 样式与链接标准。 ●CSS是XML文档显示的样式标准。 ● XSL标准可将XML文档形成树状结构,采用元素节点匹 配的方式进行转换,因而该标准提供转换和显示的标准。 ● XSLT标准是从XSL中分离出来的,是XML文档的转换标 准,可以将XML文档转换为HTML文档并进行显示处理。 (5) 内容描述标准。 RDF(Resourse Description Format)采用XML语法格式处理元 数据的应用,是为描述图像文档和它们之间的相互关系定义的 一个简单数据模型,为进行资源描述定义了资源描述的规则。 Java实用教程 3. 应用标准 XML标准是Internet时代的ASCII标准,主要针对具体的领 域进行应用,如cXML是指电子商务XML应用标准、 voiceXML指语音XML等。 Java实用教程 14.1.3 XML文档的书写 王飞 理工大学 2663457 教授 图14.2 XML文档举例 Java实用教程 14.1.4 XML文档的解析 XML应 用 程 序 SAX接 口 DOM接 口 XML分 析 器 XML文 档 图14.3 XML文档的处理过程 Java实用教程 14.2 SAX接口解析XML 14.2.1 解析的步骤 (1) 创建SAX解析工厂的实例。 SAXParserFactory spf = SAXParserFactory.newInstance(); (2) 创建一个SAX解析器。 SAXParser sp = spf.newSAXParser(); (3) 得到SAX的处理器(处理器由用户自己编写实现)。 SAXHandler handler = new SAXHandler(); (4) 使用用户创建的处理器,解析器解析文件。 sp.parse(new InputSource(reader), handler); Java实用教程 14.2.2 相关类 在J2sdk1.4中的SAX版本为2.0,它提供 DefaultHandler(org.xml.sax.helpers.DefaultHandler)接口,通过这 个接口实现自己的解析器。接口中需要实现的解析函数为: public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException 读取XML数据的节点元素开始时触发,需要实现这个方法 进行标记元素的名字的操作。 Java实用教程 public void endElement(String uri, String localName, String qName) throws SAXException 处理节点元素终止时触发,可以添加代码来将节点数据进 行存储。 public void characters(char[] ch, int start, intlength) throws SAXException 处理节点之间的数据,可以添加代码来读取节点间的数据 值。 Java实用教程 【例14.1】编写一个SAX处理器,对14.1节中的person.xml 进行解析,输出XML文件节点的标签和节点的值。 分析:类SAXHandler是一个处理类,实现这个 DefaultHandler接口时覆盖了上述三个方法,将读取的节点标签 和节点的值存入到Hashtable对象中。类中提供了一个方法,返 回读取的名-值对的Hashtable对象。输出结果如图14.4所示。源 程序代码如下: //程序文件名为Parse.java import java.io.*; import java.util.Hashtable; import org.w3c.dom.*; Java实用教程 import org.xml.sax.*; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.helpers.*; public class Parse { public static void main(String[] args) { try { Java实用教程 File file = new File("person.xml"); FileReader reader = new FileReader(file); //创建解析工厂实例 SAXParserFactory spf = SAXParserFactory.newInstance(); //创建解析器 SAXParser sp = spf.newSAXParser(); //创建处理类实例 SAXHandler handler = new SAXHandler(); //解析 sp.parse(new InputSource(reader), handler); Hashtable hashTable = handler.getTable(); //输出数据 Java实用教程 System.out.println("教师信息表"); System.out.println("姓名:"+ (String)hashTable.get(new String("name"))); System.out.println("学院:" + (String)hashTable.get(new String("college"))); System.out.println("电话:" + (String)hashTable.get(new String("telephone"))); System.out.println("职称:" + (String)hashTable.get(new String("title"))); } catch(Exception e) { System.out.println(e.getMessage()); } } }; Java实用教程 //自定义处理类 class SAXHandler extends DefaultHandler { private Hashtable table = new Hashtable(); private String currentElement = null; private String currentValue = null; public Hashtable getTable() { return table; } //覆盖startElement方法,取出节点标签 public void startElement(String uri,String localName,String qName,Attributes attributes) { Java实用教程 currentElement = qName; } //覆盖characters方法,取出节点值 public void characters(char[] ch, int start, int length) throws SAXException { currentValue = new String(ch, start, length); } //覆盖endElement方法,放入Hashtable Java实用教程 public void endElement(String uri,String localName,String qName) throws SAXException { if (currentElement.equals(qName)) table.put(currentElement, currentValue); } }; Java实用教程 图14.4 解析person.xml文件后输出结果 Java实用教程 14.3 DOM接口解析XML 14.3.1 解析的步骤 1. 从DOM接口写XML的步骤 (1) 创建DocumentBuilderFactory的一个实例; (2) 创建DocumentBuilder的一个新实例; (3) 构建一个DOM对象; (4) 创建ROOTELEMENT对象; (5) 创建单个ELEMENT节点; (6) ELEMENT创建节点的值; (7) 将ELEMENT挂接到ROOT上; (8) 写入XML文件。 Java实用教程 2. 从DOM接口读XML的文件步骤 (1) 创建DocumentBuilderFactory的一个实例; (2) 创建DocumentBuilder的一个新实例; (3) 根据已有的XML文件构建一个DOM对象; (4) 得到ROOTELEMENT对象; (5) 得到单个ELEMENT节点; (6) 得到ELEMENT创建节点的值。 Java实用教程 14.3.2 相关类 1. DocumentBuilderFactory类 public abstract class DocumentBuilderFactory extends Object 定义工厂API,使得应用程序得到解析器从XML文档中产生的 DOM对象树。 public static DocumentBuilderFactory newInstance() throws FactoryConfigurationError 得到DocumentBuilderFactory的一个实例,这个实例某个时刻 只能用于一个线程。 public abstract DocumentBuilder newDocumentBuilder() throws ParserConfigurationException 使用当前配置的方法创建一个新的DocumentBuilder的实例。 Java实用教程 2. DocumentBuilder类 public abstract class DocumentBuilder extends Object 定义从XML文档得到DOM文档的API。 public abstract Document newDocument() 得到DOM文档对象的一个新实例,用来构建DOM树。 public Document parse(File f) throws SAXException, IOException 解析给定的XML文档f,返回DOM文档对象。 Java实用教程 3. Document类 public interface Document extends Node Document接口代表整个XML文档。 public Element createElement(String tagName) throws DOMException 创建指定的类型的元素tagName。 public Text createTextNode(String data) 使用给定的data字符串创建节点元素的值。 Java实用教程 4. Element类 public interface Element extends Node Element接口代表XML文档中的一个元素。 public NodeList getElementsByTagName(String name) 返回给定的name元素下面的所有节点列表,以前向遍历的 方式给出。 Java实用教程 5. NodeList类 NodeList接口给出一个节点集合,有以下两个方法: public int getLength() 返回节点的个数。 public Node item(int index) 返回第index个节点。 Java实用教程 6. Node类 Node接口是整个文档对象模型中最主要的数据类型,它 表示文档树中单一的节点。 Node getFirstChild() 返回节点的第一个孩子节点。 String getNodeValue() 返回叶子节点的值。 Java实用教程 14.3.3 实例 【例14.2】在用户界面(见图14.5)上输入个人信息后,单击 “确定”按钮,程序收集用户信息,存成文档user.xml并显示如 下。单击“显示”按钮,读取user.xml文件,将节点标签和对应 的节点值显示在文本区域内。 王飞 111122197904290902 军队 海纳百川,有容乃大;壁立千仞,无欲则刚 Java实用教程 1. 程序源文件 //程序文件名UsePanel.java import java.awt.*; import java.awt.event.*; import java.applet.*; import java.applet.Applet; import java.io.*; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.*; Java实用教程 public class UsePanel extends Applet implements ActionListener { Label lblName,lblNumber,lblSex,lblJob,lblText; TextField tfName,tfNumber; Checkbox chMale, chFemale; CheckboxGroup c; TextArea taText; Choice chJob; Button btnOk,btnDisplay; Panel p1,p2,p3,p4,p5,p6,p7,p8,p9; String strName,strNumber,strSex,strJob,strText; public void init() { Java实用教程 //初始化界面对象 lblName = new Label("姓名:"); lblNumber = new Label("身份证号:"); lblSex = new Label("性别"); lblJob = new Label("职业"); lblText = new Label("个性化宣言:"); tfName = new TextField(23); tfNumber = new TextField(20); taText = new TextArea(10,20); c = new CheckboxGroup(); chMale = new Checkbox("男",c,true); chFemale = new Checkbox("女",c,false); chJob = new Choice(); Java实用教程 chJob.add("计算机业"); chJob.add("医生"); chJob.add("教师"); chJob.add("军队"); btnOk = new Button("确定"); btnDisplay = new Button("显示"); p1 = new Panel(); p2 = new Panel(); p3 = new Panel(); p4 = new Panel(); p5 = new Panel(); p6 = new Panel(); Java实用教程 p7 = new Panel(new BorderLayout()); p8 = new Panel(); p9 = new Panel(new BorderLayout()); //设置界面 p1.add(lblName); p1.add(tfName); p2.add(lblNumber); p2.add(tfNumber); p3.add(lblSex); p3.add(chMale); p3.add(chFemale); Java实用教程 p4.add(lblJob); p4.add(chJob); p5.add(p3); p5.add(p4); p6.setLayout(new BorderLayout()); p6.add(p1,BorderLayout.NORTH); p6.add(p2,BorderLayout.CENTER); p6.add(p5,BorderLayout.SOUTH); p7.add(lblText,BorderLayout.NORTH); p7.add(taText,BorderLayout.CENTER); Java实用教程 p8.setLayout(new FlowLayout(FlowLayout.CENTER,30,10)); p8.add(btnOk); p8.add(btnDisplay); p9.add(p6,BorderLayout.NORTH); p9.add(p7,BorderLayout.CENTER); p9.add(p8,BorderLayout.SOUTH); add(p9); //添加监听事件 btnOk.addActionListener(this); btnDisplay.addActionListener(this); Java实用教程 btnDisplay.setEnabled(false); strName = new String(); strNumber = new String(); strSex = new String(); strJob = new String(); strText = new String(); } public void actionPerformed(ActionEvent evt) { String arg = evt.getActionCommand(); //收集用户信息并写入XML文件 if(arg.equals("确定")) { Java实用教程 strName = tfName.getText().trim(); strNumber = tfNumber.getText().trim(); if(chMale.getState()) strSex = "男"; else strSex = "女"; strJob = chJob.getSelectedItem(); strText = taText.getText().trim(); try { //创建新的文档对象 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); Java实用教程 DocumentBuilder db = dbf.newDocumentBuilder(); Document doc = db.newDocument(); //创建元素 Element root = doc.createElement("UserData"); Element eName = doc.createElement("Name"); Element eNumber = doc.createElement("Number"); Element eSex = doc.createElement("Sex"); Element eJob = doc.createElement("Job"); Element eText = doc.createElement("Text"); //添加节点 Java实用教程 root.appendChild(eName); root.appendChild(eNumber); root.appendChild(eSex); root.appendChild(eJob); root.appendChild(eText); //添加值 eName.appendChild(doc.createTextNode("\n "+ strName +" \n")); eNumber.appendChild(doc.createTextNode("\n " + strNumber + " \n")); eSex.appendChild(doc.createTextNode("\n "+ strSex +" \n")); eJob.appendChild(doc.createTextNode("\n "+ strJob +" \n")); eText.appendChild(doc.createTextNode("\n "+ strText +" \n")); Java实用教程 //创建文件对象 File f = new File("user.xml"); FileOutputStream fOut = new FileOutputStream(f); //初始化xml文件 fOut.write("\n".getBytes()); //写入文件 fOut.write(root.toString().getBytes()); fOut.flush(); fOut.close(); btnDisplay.setEnabled(true); } catch(Exception e) { Java实用教程 System.out.println(e.getMessage()); } } //读取XML文件并输出到文本区域 else if(arg.equals("显示")) { try { //得到XML文档对象 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); Document doc = db.parse("user.xml"); Element root = doc.getDocumentElement(); //获取叶子节点值 Java实用教程 strName = root.getElementsByTagName("Name").item(0) .getFirstChild().getNodeValue().trim(); strNumber =root.getElementsByTagName("Number").item(0). getFirstChild(). getNodeValue().trim(); strSex = root.getElementsByTagName("Sex").item(0). getFirstChild(). getNodeValue().trim(); strJob = root.getElementsByTagName("Job").item(0). getFirstChild(). getNodeValue().trim(); strText = root.getElementsByTagName("Text").item(0). getFirstChild(). getNodeValue().trim(); //输出到文本区域 Java实用教程 taText.setText(""); taText.append("姓名:" + strName + "\n身份证号:" +strNumber + "\n性别:" + strSex + "\n职业:" + strJob + "\n个性化宣 言:\n" + strText); } catch(Exception e) { System.out.println(e.getMessage()); } } } public static void main(String args[]) { Java实用教程 Frame f = new Frame("收集用户界面"); //关闭窗口退出程序 f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent evt) { System.exit(0); } }); //定义类实例 UsePanel p = new UsePanel(); p.init(); f.add("Center",p); f.setSize(600,450); f.show(); } }; Java实用教程 2. 结果分析 图14.5显示用户输入的信息,初始化时“显示”按钮变灰, 无法使用。单击“确定”按钮时,用户输入的信息存入 user.xml文件,“显示”按钮可以使用,此时单击“显示”按 钮,将得到如图14.6所示的输出结果。文本区域内是从user.xml 文件中读取的节点标签和相应的节点值。 Java实用教程 图14.5 信息输入 Java实用教程 图14.6 单击“显示”按钮后读出XML文件内容 Java实用教程 习题 1. 编写test.xml文件,要求在浏览器中的显示如下: 王月 交通大学 2673457 教授 Java实用教程 2. 通过SAX接口将本章person.xml文件用表的格式显示在 图形用户界面上,要求文件中的节点标签分别为表的列名称, 相应节点的值为一条记录。 3. 根据习题1设计图形用户界面,输入各项内容后,用 DOM接口存入my.xml文件。 4. 用DOM接口访问例14.1的person.xml文件,并用树形结 构显示在图形用户界面上,要求文件中的节点名称为树结点名 称,文件中的值为树的叶子结点。 5. 编写Servlet,读取例14.2的user.xml文件,将内容输出到 HTML页面上,显示结果如第13章的图13.4所示。

Top_arrow
回到顶部
EEWORLD下载中心所有资源均来自网友分享,如有侵权,请发送举报邮件到客服邮箱bbs_service@eeworld.com.cn 或通过站内短信息或QQ:273568022联系管理员 高进,我们会尽快处理。