合工大Java实验报告
实 验
报
告
课程名称:
Java 技术
学生姓名:
学号:
专业班级:
指导教师:
年
月
日
实验一 Java 开发环境的安装与配置 学院 信息工程系 专业 班级
姓名 学号
成绩
课程 名称 Java 技术 实验项目
名
称
实验一 Java 开发环境的安装与配置 指导教师
教师评语
教师签名:
年
月
日 一、实验目的 1. 掌握 JDK 的安装步骤。
2. 理解环境变量 PATH, CLASSPATH 的作用,以及它们的设置方法(Win XP、WIN7、WIN8、WIN10、Linux 下的不同设置方法)。
3. 熟悉 TextPad(JCreator 或 Eclipse)编辑环境,编写简单的 Application 程序,并编译与解释执行。
4. 记录编译与执行 Java 程序当中的系统错误信息提示,并给出解决办法。
二、实验原理 1、源程序编译:使用 Eclipse 或者 Notepad++ 2、程序编译:使用 JDK 中的 javac 工具 3、程序运行:使用 java 工具或者使用 Eclipse 直接运行 4、掌握安装 JDK 以及环境变量的设置 5、
在 Notepad++环境下编写一个 HelloWorld、java 程序,在 DOS 提示符下编译并执行这个程序 6、
编写一个类 A,它位于包 a 中,保存到 A、java 中,再编写一个类 B,它位于包 b中,保存到 B、java 中。在类 B 中实例化类 A 的一个对象。分别编译类 A 与类 B。
三、使用硬件、软件环境 硬件环境:i5-7200U+8G 内存+256G 硬盘 软件环境:Windows 10 操作系统 开发工具:Eclipse 四、实验过程、步骤及原始记录( 算法、原程序、测试结果, 分析等)
1.从 下载最新版本的 JDK,并安装。(或者用已有文件安装) 安装过程: 安装Jdk集成环境,安装成功后,配置path,classpath路径,让用户在任何目录下均可用到 Java 的系统资源 ① 先配置%JAVA_HOME%环境变量,路径为 jdk 的目录; ②
配置 path 环境变量,路径为%JAVA_HOME%\bin; ③ 再 配 置 classpath 环 境 变 量 路 径为;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools、jar 2.设置环境变量 PATH, CLASSPATH, 使得 Java 程序能正确编译与执行。
3.在 Textpad(JCreator 或 Eclipse)环境下编写一个 HelloWorld、java 程序,在DOS 提示符下编译并执行这个程序。
实验过程: 在 Notepad++中写出如下代码,并保存为 HelloWorld、java: 源代码: public class HelloWorld {
public static void main(String[] args) {
System、out、println("Hello World!");
} } 在命令行中进入到该文件路径,并输入 javac HelloWorld、java 完成编译,再输 入 java HelloWorld 完成运行 运行结果:
4.编写一个类 A,它位于包 a 中,保存到 A、java 中,再编写一个类 B,它位于包b 中,保存到 B、java 中。在类 B 中实例化类 A 的一个对象。分别编译类 A与类 B。
实验过程: 用 Eclipse 编写包 a 包 b 的程序,并用 DOS 命令行运行。
源代码: A: package a; public class A {
public void OUT() {
System、out、println("this is a!");
} } B: package b; import a、*; public class B {
public static void main(String[] args) {
A a = new A();
a、OUT();
} } 运行结果:
五、实验结论、分析、思考题与心得体会 心得体会 通过本次实验,我对于 Java 的一些基本知识有所了解,下面我将进行总结: 1、我学习了如何安装 JDK,以及配置 JAVA 环境 2、我学习了使用 Notepad++记事本环境下编写 Java 程序,并使用命令行来编译执行程序 3、我学会了在 Eclipse 环境下编写与运行 Java 程序。
4、我对于 Java 的一些基本语法与使用有所了解,包括: ①文件名必须与public类的类名相同,一个Java应用程序最多只允许有一个public 类,并且有且只允许有一个主类, ②Java 对于大小写敏感,同时支持中文标识符 ③开发一个 Java 程序需要经过三个步骤:编写源程序、编译源文件生成字节码、加载运行字节码 ④ 在用 DOS 命令运行包中的 Java 文件时,要先编译 A、Java,再编译 B、Java,同时注意运行有包名的主类时,要使用包名、主类名,即 java b、B 思考题 1. 什么就是 JVM,它的作用就是什么? JVM 就是 Java 虚拟机。它就是一个虚构出来的计算机。可在实际的计算机上模拟各种计算机功能。
作用:将、class 字节码文件编译成机器语言,以便机器识别。
2. 如何理解 PATH 与 CLASSPATH,如何设置它们。
path 就是系统用来指定可执行文件的完整路径 java 的各种操作命令就是在其安装路径中的 bin 目录下,所以在 path 中设置
了JDK的安装目录后就不用再把java文件的完整路径写出来了,它会自动去path 中设置的路径中去找; classpath 就是指定您在程序中所使用的类(、class)文件所在的位置 在引入一个类时:import javax、swing、JTable 这句话就是告诉编译器要引入javax、swing 这个包下的 JTable 类,而 classpath 就就是告诉编译器该到哪里去找到这个类 假设 JDK 安装路径: E:\Program Files\Java\jdk 变量名:PATH 变量值:E:\Program Files\Java\jdk\bin
变量名:CLASSPATH 变量值:E:\Program Files\Java\jdk1\lib\tools、jar; E:\Program Files\Java\jdk1\jre\lib\dt、jar
实验二 类的封装、继承、多态
学院 信息工程系 专业 班级
姓名 学号
成绩
课程 名称 Java 技术 实验项目
名
称
实验二 类的封装、继承、多态 指导教师
教师评语
教师签名:
年
月
日 一、实验目的 1. 复习、理解 OOP 的三大特征——封装、继承与多态。
2. 学会使用 Java 编写简单的类。理解类的属性与方法。
3. 掌握关键字 private, protected, public 的作用,掌握静态类,内部类的概念。
4. 掌握多态的概念。
二、实验原理 1、分别编写两个类 Point2D,Point3D 来表示二维空间与三维空间的点,使之满足下列要求: (1) Point2D有两个整型成员变量x, y (分别为二维空间的X,Y方向坐标),Point2D的构造方法要实现对其成员变量 x, y 的初始化。
(2) Point2D 有一个 void 型成员方法 offset(int a, int b),它可以实现 Point2D 的平移。
(3) Point3D 就是 Point2D 的直接子类,它有有三个整型成员变量 x,y,z (分别为三维空间的 X,Y,Z 方向坐标),Point3D 有两个构造方法:Point3D(int x,int y,int z)与Point3D(Point2D p,int z),两者均可实现对 Point3D 的成员变量 x, y,z 的初始化。
(4) Point3D 有一个 void 型成员方法 offset(int a, int b,int c),该方法可以实现Point3D 的平移。
(5) 在 Point3D 中的主函数 main()中实例化两个 Point2D 的对象 p2d1,p2d2,打印出它们之间的距离,再实例化两个 Point3D 的对象 p3d1,p3d2,打印出她们之间的距离。
2、创建一个数组,随机生成 Point2D 或者 Point3D 的对象放于其中。最后依次调用数组中每个对象的“打印方法” ,显示数组中存储的对象就是什么。
提示:java、lang、Math、random()方法
或者 java、util、Random 类 三、使用硬件 、软件环境 硬件环境:i5-7200U+8G 内存+256G 硬盘 软件环境:Windows 10 操作系统 开发工具:Eclipse 四、实验过程、步骤及原始记录( 算法、原程序、测试结果, 分析等) 1、分别编写两个类 Point2D,Point3D 来表示二维空间与三维空间的点: (1) Point2D 有两个整型成员变量 x, y (分别为二维空间的 X,Y 方向坐标),Point2D 的构造方法要实现对其成员变量 x, y 的初始化。
(2) Point2D有一个void 型成员方法 offset(int a, int b),它可以实现 Point2D的平移。
(3) Point3D就是Point2D的直接子类,它有有三个整型成员变量x,y,z (分别为三维空间的 X,Y,Z 方向坐标),Point3D 有两个构造方法:Point3D(int x,int y,int z)与 Point3D(Point2D p,int z),两者均可实现对 Point3D 的成员变量 x, y,z 的初始化。
(4) Point3D 有一个 void 型成员方法 offset(int a, int b,int c),该方法可以实现Point3D 的平移。
(5) 在 Point3D 中的主函数 main()中实例化两个 Point2D 的对象 p2d1,p2d2,打印出它们之间的距离,再实例化两个 Point3D 的对象 p3d1,p3d2,打印出她们之间的距离。
利用类的继承写一个 point2D 类,其子类就是 point3D 。子类 Point3D 的构造函数调用了父类的构造函数; 计算平面两点的距离函数与计算空间两点的距离函数写在父类 Point2D 中,并且她们就是静态方法, 在子类继承后, 在其主方法 (主方法就是静态的) 中可以直接调用 (或者通过类名调用) ;另外平移函数可以对点进行平移 源代码: import java、util、*; import java、lang、Math; class Point2D {
int X, Y;
public Point2D()
{
//无形参的构造方法,一定要有
}
public Point2D(int x,int y)
{
this、X=x;
this、Y=y;
}
public void offset(int a, int b)//2D平移方法
{
this、X+=a;
this、Y+=b;
}
public void printInfo()
{
System、out、println("X= "+this、X+"\nY= "+this、Y);
}
public void distance(Point2D p)
{
double DT=1;
DT*=(this、X-p、X)*(this、X-p、X)+(this、Y-p、Y)*(this、Y-p、Y);
System、out、println("2D 距离:"+Math、sqrt(DT));
} } class Point3D extends Point2D {
int Z;
public Point3D()
{
//无形参的构造方法,一定要有
}
public Point3D(int x,int y,int z)
{
this、X=x;
this、Y=y;
this、Z=z;
}
Point3D(Point2D p,int z)
{
this、X=p、X;
this、Y=p、Y;
this、Z=z;
}
public void offset(int a, int b,int c)//3D平移方法
{
this、X+=a;
this、Y+=b;
this、Z+=c;
}
public void printInfo()
{
System、out、println("X= "+this、X+"\nY= "+this、Y+"\nZ= "+this、Z);
}
public void distance(Point3D p)
{
double DT=1;
DT*=(this、X-p、X)*(this、X-p、X)+(this、Y-p、Y)*(this、Y-p、Y)+(this、Z-p、Z)*(this、Z-p、Z);
System、out、println("3D 距离:"+Math、sqrt(DT));
} } public class Alex
{
public static void main(String args[])
{
System、out、print("*****录入信息*****\n");
Scanner cin = new Scanner(System、in);
int x[]=new int[2];
int y[]=new int[2];
int z[]=new int[2];
for(int i=1;i<3;i++)
{
System、out、print("录入第 "+ i +" 个 2D 平面坐标\n
输入横坐标X:");
x[i-1]=cin、nextInt();
System、out、print("
输入纵坐标Y:");
y[i-1]=cin、nextInt();
}
Point2D _2Dp1=new Point2D(x[0],y[0]);
Point2D _2Dp2=new Point2D(x[1],y[1]);
_2Dp1、printInfo();
_2Dp2、printInfo();
System、out、println("现在将 2D 平面图,3D 化,请给出 竖坐标Z的值");
for(int i=1;i<3;i++)
{
System、out、print("录入第 "+ i +" 个 3D 平面坐标\n
输入竖坐标Z:");
z[i-1]=cin、nextInt();
}
Point3D _3Dp1=new Point3D(_2Dp1,z[0]);
Point3D _3Dp2=new Point3D(_2Dp2,z[1]);
_3Dp1、printInfo();
_3Dp2、printInfo();
System、out、println("平移 2D 图形:");
for(int i=1;i<3;i++)
{
System、out、print("录入第 "+ i +" 个 2D 图形的平移量\n
输入横坐标X的平移量:");
x[i-1]=cin、nextInt();
System、out、print("
输入纵坐标Y的平移量:");
y[i-1]=cin、nextInt();
}
_2Dp1、offset(x[0], y[0]);
_2Dp2、offset(x[1], y[1]);
_2Dp1、printInfo();
_2Dp2、printInfo();
for(int i=1;i<3;i++)
{
System、out、print("录入第 "+ i +" 个 3D 图形的平移量\n
输入竖坐标Z的平移量:");
z[i-1]=cin、nextInt();
}
_3Dp1、offset(x[0],y[0],z[0]);
_3Dp2、offset(x[1],y[1],z[1]);
_3Dp1、printInfo();
_3Dp2、printInfo();
_2Dp1、distance(_2Dp2);
_3Dp1、distance(_3Dp2);
}
} 运行结果:
2、创建一个数组,随机生成 Point2D 或者 Point3D 的对象放于其中。最后依次调用数组中每个对象的“打印方法” ,显示数组中存储的对象就是什么。
思想:使用 Math、random()生成数组个数,点的个数 1-5 个,接着依次给 Point2D 数组 P 随机输入一个 1-50 的整数,接着每次调用,调用 Point2D 中方法 printInfo(),输出点,除了第一次每次调用 P[i]、distance(P[i - 1]),输出当前点与上一个点的距离。
Point3D 数组同上操作 源代码:除了主类外,其它同 1 中的代码,下面给出主类 public class Point
{
public static void main(String[] args) {
Point2D []P=new Point2D[(int)(Math、random()*5) + 1];//随机生成数组个数
System、out、println("输出2D数组,并输出与上一点的距离:");
for(int i=0;i<P、length;i++)
{
int x=1+(int)(Math、random()*50);
int y=1+(int)(Math、random()*50);
System、out、println("第" + (i+1) +"个点:");
P[i]=new Point2D(x,y);
P[i]、printInfo();
if(i != 0)
{
System、out、println("与上一点的距离为:");
P[i]、distance(P[i - 1]);
}
}
System、out、println();
System、out、println("输出3D数组,并输出与上一点的距离:");
Point3D []P1=new Point3D[(int)(Math、random()*5) + 1];//随机生成数组个数
for(int i=0;i<P1、length;i++)
{
int x=1+(int)(Math、random()*50);
int y=1+(int)(Math、random()*50);
int z=1+(int)(Math、random()*50);
P1[i]=new Point3D(x,y,z);
System、out、println("第" + (i+1) +"个点:");
P1[i]、printInfo();
if(i != 0)
{
System、out、println("与上一点的距离为:");
P1[i]、distance(P1[i - 1]);
}
}
} }
五、实验结论、分析、思考题与心得体会
心得体会
通过本次实验,我对于 Java 如何实现类的继承、封装、多态有了初步的了解,并且学会了如何使用 Java 语言编写简单的类,理解了类的属性与方法,同时掌握关键字 private, protected, public 的作用,以及静态类,内部类、多态的概念 在实验过程中,也有了一些心得体会: ①子类继承父类的非私有成员,但不能继承构造方法,必须用 super()来调用父类的构造方法。
②构造方法可以通过形参的个数、类型、排列不同来重载,同时也学会了如何实现类方法的多态。
③Static 静态方法只能直接调用静态成员,不能直接调用非静态成员, ④基本掌握了 Math 类中静态方法,Math、pow() 与 Math、sqrt()的使用,同时学会了如何使用 Math、 random()生成随机数,与如何建立对象的数组。
思考题 什么就是类的多态性。
一就是操作名称的多态,即多个操作具有相同的名字,但这些操作所接收的信息类型必须不同。所谓操作名称的多态,就是指可以向操作传递不同的信息,以便让对象根据相应的信息来产生一定的行为。
另一种多态就是与继承有关的多态,就是指同一个操作数被不同类型对象调用时可能产生不同的行为。
实验三 输入输出流
学院 信息工程系 专业 班级
姓名 学号
成绩
课程 名称 Java 技术 实验项目
名
称
实验三 输入输出流 指导教师
教师评语
教师签名:
年
月
日 一、实验目的 1. 掌握 Java I/O 基本原理。
2. 学会使用 Java 提供的实用类来完成特定的功能。
3. 掌握、抽象类的基本使用方法。
4. 掌握、、BufferedReader、BufferedWriter 抽象类的基本使用方法。
二、 实验原理 1. 使用、、、、BufferedReader、BufferedWriter 抽象类实现从文件中读取内容,并添加所想要输入的内容,接着一行一行输入到另一个文件中。
2. 实现给出的 Java Application 程序,并分析其功能。
3. 现 有如下格式的成绩单(文本格式)score、txt: 姓名:张三,数学 72 分,物理 67 分,英语 70 分、 姓名:李四,数学 92 分,物理 98 分,英语 88 分、 姓名:周五,数学 68 分,物理 80 分,英语 77 分、 要求按给定的程序模板编写一个 Java 程 序,能 按行读入上述格式的成绩单,并在该行的后面尾加上该同学的总成绩,然后再将该行写入到一个名字为socreAnalysis、txt 的文件中。
三、使用硬件、软件环境 硬件环境:i5-7200U+8G 内存+256G 硬盘 软件环境:Windows 10 操作系统 开发工具:Eclipse 四、实验过程、步骤及原始记录( 算法、原程序、测试结果, 分析等) 1.该程序的功能就是通过处理字节流的抽象类:InputStream 与 OutputStream
完成文件的复制:先使用字节流从“copy”文件中读取数据,接着将读取到的数据写入到“temp、txt”文件中去,实现 copy 功能。
源代码: import java、io、*; public class CopyFile {
public static void main(String[] args) {
try {
fis = new ("src/Copy");
fos = new ("temp、txt");
int read = fis、read();
while ( read != -1 ) {
fos、write(read);
read = fis、read();
}
fis、close();
fos、close();
}
catch (IOException e) {
System、out、println(e);
} } } 运行结果: 2、 、
AnalysisResult、java 源代码: import java、io、*;
import java、util、*; public class AnalysisResult{
public static void main(String args[]){
File("score、txt");
File("scoreAnalysis、txt");
try{
Writer out= new (fWrite,true);//以尾加方式创建指向文件fWrite的out流
BufferedWriter bufferWrite=new BufferedWriter(out); //创建指向out的bufferWrite流
Reader in=new (fRead); //创建指向文件fRead的in流
BufferedReader bufferRead=new BufferedReader(in); //创建指向in的bufferRead流
String str=null;
while ((str=bufferRead、readLine())!=null){
double totalScore =Fenxi、getTotalScore(str);
str=str+"总分:"+totalScore;
System、out、println(str);
bufferWrite、write(str);
bufferWrite、newLine();
}
bufferRead、close();
bufferWrite、close();
}
catch(IOException e){
System、out、println(e、toString());
}
} } Fenxi、java 源代码: import java、util、*; public class Fenxi{
public static double getTotalScore(String s){
Scanner scanner=new Scanner(s);
scanner、useDelimiter("[^0123456789、]+");
double totalScore=0;
while(scanner、hasNext()){
try{
double score=scanner、nextDouble();
totalScore=totalScore+score;
}
catch(InputMismatchException exp){
String t=scanner、next();
}
}
return totalScore;
} } 运行结果:
记事本信息:
五、实验结论、分析、思考题与心得体会 通过本次实验,我对于 Java 语言关于输入输出流的部分有了一定的了解,下面就是我的一些收获: 1. 掌握 Java I/O 基本原理:Java 中的 IO 包中的类可以处理不同类型的流,例如:字节流(byte[])、字符流(character)、文件流、对象流等。
java、io 中的抽象类包括:处理字节流的抽象类:InputStream 与 OutputStream,处理过滤流的抽象类:FilterOutputStream 与 FilterInputStream,处理字符流的抽象类:Reader 与 Writer,处理压缩流的抽象类:InflaterInputStream 与DeflaterOutputStream 2、学会如何使用 Java 给出的各种输入输出流来实现一系列的问题,包括:从文件的读取数据、使用输出流对数据进行加工存储到文件中等。
3、掌握了、抽象类的基本使用方法,并实际操作实现了读取与存储拷贝。
4、掌握了、、BufferedReader、BufferedWriter 抽象类的基本使用方法,实现修改读取的内容,添加内容存储进入文件中。
实验四 基于 GUI 的网络通信程序设计
学院 信息工程系 专业 班级
姓名 学号
成绩
课程 名称 Java 技术 实验项目
名
称
实验四 基于 GUI 的网络通信程序设计 指导教师
教师评语
教师签名:
年
月
日 一、实验目的 1. 掌握 Java 中 GUI 程序的编写,包括事件监听机制。
2.
掌握 Java 的网络通信编程,ServerSocket,Socket 类的使用。
3.
掌握 Java 中多线程的编程,Thread 类,Runnable 接口的使用。
4.
掌握用面向对象的方法分析与解决复杂问题。
二、实验原理 使用 Java Swing 中的组件实现 GUI 程序的编写,包括使用监听器、ServerSocket,Socket 类实现输入输出数据。
同时使用 Thread 类,Runnable 接口,实现多线程执行程序。
(1)设计一个基于 GUI 的客户-服务器的通信应用程序,如图 1,图 2 所示。
图 1 Socket 通信服务器端界面 图 2 Socket 通信客户端界面 (2)图 1 为 Socket 通信服务器端界面,点击该界面中的【Start】按钮,启动服务器监听服务(在图 1 界面中间的多行文本区域显示“Server starting…”字样)。图 2为 Socket 通信客户端界面,点击该界面中的【Connect】按钮与服务器建立链接,并在图 2 所示界面中间的多行文本区域显示“Connect to server…”字样,当服务器端监听到客户端的连接后,在图 1 界面中间的多行文本区域追加一行“Client connected…”字样,并与客户端建立 Socket 连接。
(3)当图 1 所示的服务器端与图 2 所示的客户机端建立 Socket 连接后,编程实现这两端的数据通信,每次将接收到对方的数据追加显示在多行文本框中。
三、使用硬件、软件环境 硬件环境:i5-7200U+8G 内存+256G 硬盘 软件环境:Windows 10 操作系统 开发工具:Eclipse 四、实验过程、步骤及原始记录( 算法、原程序、测试结果,分 分 析等) 1、编写两个文件 Client、java 与 Server、java,两个 Java 文件的内容相似,首先在构造方法中写了调用了实现 GUI 的函数,即使用 JFrame 类建立窗口,以及加入相应的组件,使用 FlowLayout 布局,,也为按钮注册了监听器。在不同的内部类中写了不同监听器所调用的 actioPerformed()方法。
通过写一个主类,与一个实现类,主类通过创建实现类的对象来调用其构造方法来实现功能。实现类中包括各种方法与内部类通过方法的层层调用,来实现所需要的结果。
2、在服务器中创建 ServerSocked 对象来接受客户端的连接请求,并指定端口号,客户端通过 Socket 对象与客户端的 Socket 对象连接。连接成功后通过 IO流来通信,服务器的输入流就是客户端的输出流,服务器的输出流就是客户端的输入流,通过 BufferedReader 读取相应套接字 socket 中获取的输入流的内容,并放入对应的文本框中。
服务器代码: import java、awt、*;
import java、awt、event、*;
import java、util、*;
import java、io、*;
import java、net、*;
import javax、swing、*;
public class Server{
public static void main(String[] args){
MyFrame serve = new MyFrame();
serve、setTitle("服务器");
serve、setVisible(true);
serve、setResizable(false); //设置此窗体就是否可由用户调整大小
serve、setDefaultCloseOperation(JFrame、EXIT_ON_CLOSE); //设置默认关闭操作
} }
class MyFrame extends JFrame{
JTextField port;
JButton start;
JTextArea content;
JTextField cin;
JButton say;
Socket socket;
MyFrame(){
init();
StartListen sListen = new StartListen();
SayListen stListen = new SayListen();
start、addActionListener(sListen); //为按钮 start 注册一个监听器
say、addActionListener(stListen); //为按钮 say注册一个监听器
}
void init(){
setLayout(new FlowLayout()); //设置窗体为流式布局
setSize(400,400);
setLocation(400,100);
add(new JLabel("Port:"));
port = new JTextField("8888",25);
add(port);
start = new JButton("Start");
add(start);
content = new JTextArea(15,35);
JScrollPane scroll = new JScrollPane(content); //设置滚动条
add(scroll);
add(new JLabel("Say:"));
cin = new JTextField("Hello!",26);
add(cin);
say = new JButton("Say");
add(say);
}
class StartListen implements ActionListener{
public void actionPerformed(ActionEvent e){
start、setEnabled(false);
try {
ServerSocket s = new ServerSocket(Integer、parseInt(port、getText())); // 创建一个服务器套接字对象 s,形参为从 port 文本框中读取的整型(端口号)
socket = s、accept();
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket、getOutputStream())),true);// 创建一个打印输出流对象,其形参为从套接字 socket 对象中获取的输出流
out、println("Connected");
content、append("Client connected"+"\n"); //对两个字符串进行拼接
ServerThread st = new ServerThread(); //创建一个 ServerThread 对象st,并调用其构造方法
st、start(); //启动一个线程,并调用 run()方法
} catch (Exception ex) {}
}
}
class SayListen implements ActionListener{
String str;
public void actionPerformed(ActionEvent e){
try {PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket、getOutputStream())),true);// 创建一个打印输出流,形参为从套接字socket 中获取的输出流
str=cin、getText();
if(!str、isEmpty()){
out、println(new Date()+"\n"+str); //打印输出日期与发送的消息( str)
content、append(new Date()+" \n me:"+str+"\n");
out、flush(); //清空缓存区
}
cin、setText("");
} catch (Exception ex) {}
}
}
class ServerThread extends Thread{
public void run(){
try {
BufferedReader in = new BufferedReader(new InputStreamReader(socket、getInputStream())); //创建一个缓冲输出流,其形参为从套接字 socket 中获取的输入流
String str;
while(true){
str = in、readLine(); //按行读取
content、append( str+"\n");
}
} catch (Exception ex) {}
}
}
} 客户端代码: import java、awt、*;
import java、awt、event、*;
import java、util、*;
import java、io、*;
import java、net、*;
import javax、swing、*;
import java、util、Calendar;
public class Client{
public static void main(String[] args) {
MyFrame client=new MyFrame();
client、setTitle("客户端");
client、setVisible(true);
client、setResizable(false); //设置此窗体就是否可由用户调整大小
client、setDefaultCloseOperation(JFrame、EXIT_ON_CLOSE); // 设置关闭操作
}
}
class MyFrame extends JFrame {
JTextField ip;
JTextField port;
JTextField cin;
JTextArea content;
JButton connect;
JButton say;
Socket socket;
MyFrame(){
init();
ConnectListen cListener=new ConnectListen();
SayListen sListener = new SayListen();
connect、addActionListener(cListener); //注册监听器
say、addActionListener(sListener); //注册监听器
}
void init(){
setLayout(new FlowLayout()); //设置窗体为流式布局
setSize(440,500);
setLocation(800,100);
add(new JLabel("Server:ip"));
ip=new JTextField("127、0、0、1",8);
add(ip);
add(new JLabel("Server:port"));
port=new JTextField("8888",8);
add(port);
connect=new JButton("connect");
add(connect);
content=new JTextArea(16,35);
JScrollPane scroll=new JScrollPane(content); //设置滚动条
add(scroll);
add(new Label("Say:"));
cin=new JTextField("您好!",25);
add(cin);
say=new JButton("say");
add(say);
}
class ConnectListen implements ActionListener{
int portNum;
public void actionPerformed(ActionEvent e){
connect、setEnabled(false); //按下 connect 按钮后, connect 不可再次点击
try {
content、setText("Connect to server、、、、\n"); //在文本区中显示 "Connect to server、、、、\n"
portNum =Integer、parseInt(port、getText()); //读取 port 文本框中的字符串,并将字符串转化为整型赋给 portNum
socket = new Socket(ip、getText(),portNum); //定义对象 socket,并指定主机号(host)与端口号 portNum
ClientThread ct = new ClientThread(); //定义一个 ClientThread 类的对象 ct
ct、start(); //启动一个线程,并调用ClientThread 类中的 run()方法
} catch (Exception ex) {}
}
}
class SayListen implements ActionListener{
String str;
public void actionPerformed(ActionEvent e){
try {
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket、getOutputStream())),true); //从 socket 获取字节输出流,并将其最终转化为 PrintWriter
str=cin、getText(); //从文本框中获取字符串赋给 str
if(!str、isEmpty()){
out、println(new Date()+ "\n"+ str); //打印日期与 str
content、append(new Date()+"\n me:"+str+"\n");
out、flush(); //清空缓存区
}
cin、setText("");
} catch (Exception ex) {}
}
}
class ClientThread extends Thread{
public void run(){
try {
BufferedReader in = new BufferedReader(new InputStreamReader(socket、getInputStream())); //创建一个缓冲输出流,其形参为从套接字 socket 中获取的输入流
String str;
while(true){
str = in、readLine(); //按行读取
content、append( str+"\n");
}
} catch (Exception ex) {}
}
}
} 运行结果:
五、实验结论、分析、思考题与心得体会
通过本次实验,我对于 GUI 程序的便编写,以及网络通信与多线程编程有了一定的了解,并且也亲自实现了一个基于 GUI 的客户-服务器的通信应用程序,在实验过程中,我也遇到了不少的问题并加以解决: 1、因为服务器的 GUI 界面有 start 与 say 按钮,客户端有 connect 与 say 按钮,按钮被点击后会触发动作事件。而不同的按钮要执行不同的操作,也就意味着要写多个 actionPerformed()方法,可就是一个类里面只能写一个 actionPerformed()方法,因此可以写几个实现了 ActionPerformed()方法,在内部类中再写一个actionPerformed()方法,这样就写了好几个不同的 actionPerformed()方法,在注册监听器的时候,按钮需要实现哪种功能,就用哪个内部类的对象来监听就可以了。
2、在服务器中创建 ServerSocket 对象来接受客户端的连接请求, 并指定端口号, 客户端通过 Socket 对象来向服务器的 ip 与端口发送连接请求。服务器在接到连接请求后,服务器会创建一个新的 Socket 对象与客户端的 Socket 对象连接。连接成功后通过 IO 流来通信,服务器的输入流就是客户端的输出流,服务器的输出流时客户端的输入流