进程(Process):操作系统中能够“同时”运行的多个应用程序(QQ、浏览器、Word、WPS)。
线程(Thread):一个应用程序中,能够“同时”运行的多个任务,比如在线播放(一边下载,一边播放),很多软件都支持线程功能,如QQ可以一边接收信息、一边用户可以发送信息,抖音可以一边下载、一边播放。
两者实际上在底层是“分时”(时间片轮转),由操作系统决定。
针对Java语言,我们讲解线程。
class Downloader extends Thread{ //①第一步:继承Thread
public void run() { //②第二步:重写run函数
for(int i=1;i<=10;i++){
try{
Thread.sleep(1000); //休息1秒
} catch(Exception ex){}
System.out.println("下载进度:"+i*10+"%");
}
}
}
class Player extends Thread{
public void run(){
for(int i=1;i<=10;i++){
try{ Thread.sleep(1000); } catch(Exception ex){}
System.out.println("播放进度:"+i*10+"%");
}
}
}
class ThreadTest{
public static void main (String[] args) {
Downloader d = new Downloader();
Player p = new Player();
d.start(); p.start(); //③第三步:用start方法开启各个线程的run函数
}
}
当要在执行某个线程一段时间后执行另一个进程时,可用以下代码:
class Downloader extends Thread{ //①第一步:继承Thread
public void run() { //②第二步:重写run函数
for(int i=1;i<=10;i++){
try{ Thread.sleep(1000); } catch(Exception ex){}
System.out.println("下载进度:"+i*10+"%");
if(i==2){ //一个线程调用另一个线程
new Player().start();
}
}
}
}
class Player extends Thread{
public void run(){
for(int i=1;i<=10;i++){
try{ Thread.sleep(1000); } catch(Exception ex){}
System.out.println("播放进度:"+i*10+"%");
}
}
}
class ThreadTest{
public static void main (String[] args) {
Downloader d = new Downloader();
d.start(); //③第三步:用start方法开启各个线程的run函数
}
}
class Downloader implements Runnable{ //①第一步:实现Runnable
public void run() { //②第二步:重写run函数
for(int i=1;i<=10;i++){
try{ Thread.sleep(1000); } catch(Exception ex){}
System.out.println("下载进度:"+i*10+"%");
}
}
}
class Player implements Runnable{
public void run(){
for(int i=1;i<=10;i++){
try{ Thread.sleep(1000); } catch(Exception ex){}
System.out.println("播放进度:"+i*10+"%");
}
}
}
class ThreadTest{
public static void main (String[] args) {
Downloader d = new Downloader(); Thread th1 = new Thread(d);
Player p = new Player(); Thread th2 = new Thread(p);
th1.start(); th2.start(); //③第三步:实例化线程,将类的对象传入线程的构造函数,再调用线程的start方法
}
}
用了多线程,多个任务完成得比以前快,不是因为多线程让CPU运行更快,是让CPU的利用率提高。
【例】下载文件,下载到30%,暂停下载5秒,5秒后继续下载,编写代码实现该功能。
class Downloader extends Thread{
public void run() {
for(int i=1;i<=10;i++){
try{ Thread.sleep(1000); } catch(Exception ex){}
System.out.println("下载进度:"+i*10+"%");
}
}
}
class ThreadTest{
public static void main (String[] args) throws Exception {
Downloader d = new Downloader();
d.start();
Thread.sleep(3200);
d.suspend();
Thread.sleep(5000);
d.resume();
}
}
【注意】suspend、resume是不建议使用的函数,有死锁倾向。
这两个函数,特别是suspend,在暂停时不会释放线程中的资源,导致资源被该线程长期持有,别人不能使用,故可能造成循环等待。所以不建议使用。可采用以下方法:线程暂停,就让该线程结束(run函数运行完毕);线程继续,新开启一个线程(start)。
class Downloader extends Thread{
boolean RUN = true;
static int i = 1;
public void run() {
for(;i<=10&&RUN;i++){
try{ Thread.sleep(1000); } catch(Exception ex){}
System.out.println("下载进度:"+i*10+"%");
}
}
}
class ThreadTest{
public static void main (String[] args) throws Exception {
Downloader d = new Downloader();
d.start();
Thread.sleep(3000);
d.RUN = false;
Thread.sleep(5000);
d = new Downloader(); //新开启一个线程继续
d.start();
}
}
//此处不能用方法1(继承thread类),定义d1、d2对象,因为synchronized的参数this打在的是对象中(synchronized运行结束this上的标记自动消亡), 这种方法会使this标记打在了两个对象,而Runnable方法可使this打在一个对象,达到目的。
class Downloader implements Runnable{
static int i = 1; //定义静态变量,可以使类中所有对象共用
public void run() {
while(true){
synchronized(this){
if(i>10) { break; }
try{ Thread.sleep(1000); } catch(Exception ex){}
System.out.println("下载进度:"+i*10+"%");
i++;
}
}
}
}
class ThreadTest{
public static void main (String[] args) throws Exception {
Downloader d = new Downloader();
new Thread(d).start(); new Thread(d).start();
}
}
IO:输入输出。
输入设备:键盘、鼠标、扫描仪
输出设备:打印机、显示器
同时属于输入输出设备:硬盘
输入设备和输出设备是站在内存的角度划分的。
将文件从硬盘上读入,QQ收到对方信息;将文件保存到硬盘,QQ输出信息给对方。
这里重点讲解文件输入输出,对应的包是java.io。
java.io.File:文件封装,得到文件信息,删除文件,重命名文件
[例1]用File类封装E:/test.txt.
import java.io.*;
class IOTest{
public static void main (String[] args) {
File f = new File("E:/test.txt");
f.delete();
}
}
[例2]列出D盘下面所有的文件,并显示.
import java.io.*;
class IOTest{
public static void main (String[] args) {
File f = new File("D:/");
File[] files = f.listFiles();
for(File file : files){
System.out.println(file.getPath() + ":" + file.length());
}
}
}
[例3]删除E:/testDir下面的所有文件.
import java.io.*;
class IOTest{
public static void main (String[] args) {
File f = new File("D:/testDir");
File[] files = f.listFiles();
for(File file : files){
file.delete();
}
}
}
[例4]编写一个病毒,用户运行,自动清空输入文件夹路径中所有的文件和文件夹。
package VirusTest;
import java.io.File;
public class VirusTest {
public static void FileDelete(File f) {
if(f.isDirectory())
{
File[] files = f.listFiles();
for (File file : files) {
FileDelete(file);
}
}
f.delete();
}
public static void main(String[] args) throws Exception{
String str = javax.swing.JOptionPane.showInputDialog("请输入您要删除的文件夹");
File f = new File(str);
FileDelete(f);
}
}
场景:test.txt里面有一些内容,读入到内存后,显示在屏幕上。
FileInputStream类一个个字节读取,对中文支持不佳。文件输入输出流,打开之后,记得及时关闭
【注】字节流和字符流
字节流以字节的形式读取文件,对于有一些“双字节字符”,支持不好。为了解决该问题,Java中推出专门支持字符流的文件输入输出类。
import java.io.*;
class IOTest{
public static void main (String[] args) throws Exception{
File f = new File("test.txt");
FileInputStream fis = new FileInputStream(f);
while(true){
int i = fis.read();
if(i==-1) break;
char ch = (char)i;
System.out.print(ch);
}
fis.close();
}
}
批量读取:
import java.io.*;
class IOTest{
public static void main (String[] args) throws Exception{
File f = new File("test.txt");
FileInputStream fis = new FileInputStream(f);
byte[] data = new byte[(int)f.length()];
fis.read(data);
String s = new String(data);
System.out.println(s);
fis.close();
}
}
字符读取,可一个个字符读,也可一块块读,支持字符。
重点针对字符特别是多字节字符讲解的不是FileReader,最常见使用的是“按行读”的另一个类:java.io.BufferedReader。如果对字符串进行读取,最佳办法是用:BufferedReader。它支持按行读字符串,和FileReader配套。
import java.io.*;
class IOTest{
public static void main (String[] args) throws Exception{
File f = new File("test.txt");
FileReader fr = new FileReader(f);
BufferedReader br = new BufferedReader(fr);
while(true){
String s = br.readLine();
if(s==null) break;
System.out.println(s);
}
fr.close();
}
}
字节流读取(FileInputStream)和字符流读取(FileReader/BufferedReader)进行比较,FileInputStream(适合图像、视频、语音、文本都支持),而字符流读取一般只适合字符和字符串。
【总结】
场景:定义一个变量,保存到test.txt中。
注意:向文件保存数据时,有两种模式:1)在文件末尾添加; 2)覆盖原有内容,用append参数确定。
import java.io.*;
class IOTest{
public static void main (String[] args) throws Exception{
File f = new File("test.txt");
FileOutputStream fos = new FileOutputStream(f, false); //append参数为false,覆盖原有内容
String str = "CSU中南大学";
fos.write(str.getBytes()); //getBytes函数转为字节数组,然后写入文件
fos.close();
}
}
[例1]将一个99乘法表保存到test.txt中。
import java.io.*;
class IOTest{
public static void main (String[] args) throws Exception{
File f = new File("test.txt");
FileOutputStream fos = new FileOutputStream(f, false);
PrintStream ps = new PrintStream(fos);
for(int i=1;i<=9;i++){
for(int j=1;j<=i;j++){
ps.print(i + "*" + j + "=" + i*j + " ");
}
ps.println();
}
fos.close();
}
}
[例2]将一个图像加密,加密方法:每个字节的值+3。
import java.io.*;
class IOTest{
public static void main (String[] args) throws Exception{
File f1 = new File("img1.jpg");
File f2 = new File("img2.jpg");
FileInputStream fis = new FileInputStream(f1);
FileOutputStream fos = new FileOutputStream(f2);
while(true){
int i = fis.read();
if(i==-1) break;
i+=3;
fos.write(i);
}
fos.close();
fis.close();
}
}
另外,RandomAccessFile类可以提供文件的随机访问,既支持文件读,又支持文件写。
本章讲述Java开发桌面应用程序,包括用Swing开发GUI程序、Java事件处理与Java绘图。
Swing:Java中的一个包,负责开发GUI程序
GUI:图形用户界面,一般指可视化桌面系统中的应用程序。
Windows:将应用程序从字符界面拓展到图形界面。
常见图形用户界面的基本结构:
界面(容器窗口)
控件(界面上的组件,如按钮、文本框等)
渲染(颜色、字体等)
事件响应(完成功能)
界面、控件、渲染中的图标使用的包:javax.swing包【注:javax的x:eXtension(扩展)】
渲染(颜色:Color、字体:Font)使用的包:java.awt包。
又称容器、窗口,提供整个界面的空间。
一般掌握第(1)种即可。
显示:setVisible函数
[例]在桌面出现一个界面,标题是:HelloWorld
用框架界面:
import javax.swing.JFrame;
class GUI1{
public static void main(String[] args) throws Exception {
JFrame jfm = new JFrame("HelloWorld");
jfm.setSize(600,400);
jfm.setLocation(300,200);
jfm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //退出框架界面
jfm.setVisible(true);
}
}
通过构造函数进行初始化:
import javax.swing.JFrame;
class GUI extends JFrame{
public GUI(){
super("HelloWorld"); //调用父类的构造函数
this.setSize(600,400);
this.setLocation(300,200);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
public static void main(String[] args) throws Exception {
new GUI();
}
}
界面上的组件,如按钮、文本框、复选框等。
注意:Java中,容器还有:面板 javax.swing.JPanel
一般我们在界面上添加一个面板,面板上增加控件。
举一反三:
import javax.swing.*;
class GUI extends JFrame{
private JLabel jlb = new JLabel("——————欢迎来到中南大学社团学生注册系统——————");
private JButton jbt = new JButton("学生注册");
private JLabel jlbAcc = new JLabel("请您输入账号");
private JTextField jtfAcc = new JTextField(20);
private JLabel jlbAdd = new JLabel("请您选择您的家乡");
private JComboBox jcbAdd = new JComboBox();
private JCheckBox jcbMember = new JCheckBox("是否立即成为会员",true);
private JLabel jlbInfo = new JLabel("请您输入个人详细描述");
private JTextArea jtaInfo = new JTextArea(20,30);
private JPanel jpl = new JPanel();
public GUI(){
jpl.add(jlb); jpl.add(jbt); jpl.add(jlbAcc); jpl.add(jtfAcc);
jpl.add(jlbAdd); jpl.add(jcbAdd); jpl.add(jlbInfo); jpl.add(jtaInfo);
jcbAdd.addItem("湖南"); jcbAdd.addItem("湖北");
jcbAdd.addItem("河南"); jcbAdd.addItem("河北");
jpl.add(jcbMember);
this.add(jpl);
this.setSize(400,600);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
public static void main(String[] args) throws Exception {
new GUI();
}
}
包含颜色、字体(java.awt)、图标(javax.swing)三部分
任何界面和控件都可以设置背景颜色和前景颜色
setBackground(颜色) setForeground(颜色) (文档可查)
凡是有字的控件,都有setFont函数(文档可查)
颜色:java.awt.Color
字体:java.awt.Font
import javax.swing.*;
import java.awt.*;
class GUI extends JFrame{
private JButton jbt = new JButton("学生注册");
private JPanel jpl = new JPanel();
public GUI(){
jpl.setBackground(new Color(0,255,255));
jbt.setBackground(Color.blue);
jbt.setForeground(Color.yellow);
Font f = new Font("微软雅黑",Font.BOLD,50);
jbt.setFont(f);
jpl.add(jbt);
this.add(jpl);
this.setSize(400,600);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE );
this.setVisible(true);
}
public static void main(String[] args) throws Exception {
new GUI();
}
}
图标:很多控件都可以设置图标,如按钮、静态文本等。但不是所有,比如文本框就不能。具体看文档。用的函数:setIcon函数
注意:Icon和ImageIcon在swing中。
主要方法有:
控件.setBackground和setForeground(颜色)
控件.setFont(字体)
控件.setIcon(图标)
【例】将按钮设置为图标形式。
import javax.swing.*;
import java.awt.*;
class GUI extends JFrame{
private JButton jbt = new JButton();
private JPanel jpl = new JPanel();
public GUI(){
ImageIcon icon = new ImageIcon("img.jpg");
jbt.setIcon(icon);
jbt.setText("这是一个按钮");
jpl.add(jbt);
this.add(jpl);
this.setSize(600,800);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE );
this.setVisible(true);
}
public static void main(String[] args) throws Exception {
new GUI();
}
}
布局:将控件有序的放在界面上,使用java.awt包。
JPanel默认的布局方式是:流式布局(FlowLayout),优先放在1行,放不下,到后面1行。该布局方式由java.awt.FlowLayout来管理;
任何容器管理类都有setLayout函数设置布局。
[例]将一个按钮,一个文本框放在界面上。
import javax.swing.*;
import java.awt.*;
class Layout1 extends JFrame{
private JTextField jtf = new JTextField(20);
private JButton jbt = new JButton("按钮");
private JPanel jpl = new JPanel();
public Layout1(){
FlowLayout fl = new FlowLayout(FlowLayout.LEFT,20,20);
jpl.setLayout(fl);
this.add(jpl); jpl.add(jtf); jpl.add(jbt);
this.setSize(300,400);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
}
public static void main(String[] args) throws Exception {
new Layout1();
}
}
网格布局,将界面设置为多行多列的格子,放置控件。该布局方式由java.awt.GridLayout来管理。
[例1]放置24个按钮在界面上。
import javax.swing.*;
import java.awt.*;
class Layout1 extends JFrame{
private JPanel jpl = new JPanel();
public Layout1(){
GridLayout gl = new GridLayout(6,4);
jpl.setLayout(gl);
this.add(jpl);
for(int i=1;i<=24;i++){
jpl.add(new JButton(String.valueOf(i)));
}
this.setSize(300,400);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
}
public static void main(String[] args) throws Exception {
new Layout1();
}
}
[例2]制作一个8*8国际象棋棋盘。
import javax.swing.*;
import java.awt.*;
class Layout1 extends JFrame{
private JPanel jpl = new JPanel();
public Layout1(){
GridLayout gl = new GridLayout(8,8);
jpl.setLayout(gl);
this.add(jpl);
for(int i=1;i<=8;i++){
for(int j=1;j<=8;j++){
JPanel pl = new JPanel();
if((i+j)%2==0) {pl.setBackground(Color.white);}
else { pl.setBackground(Color.black);}
jpl.add(pl);
}
}
this.setSize(300,400);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
}
public static void main(String[] args) throws Exception {
new Layout1();
}
}
边界布局:将界面分为东西南北中,添加控件。该布局方式由java.awt.BorderLayout来管理。
JFrame的默认布局方式是BorderLayout。
import javax.swing.*;
import java.awt.*;
class Layout1 extends JFrame{
private JPanel jpl = new JPanel();
public Layout1(){
BorderLayout bl = new BorderLayout();
jpl.setLayout(bl);
this.add(jpl);
jpl.add(new JButton("按钮"),BorderLayout.SOUTH);
jpl.add(new JTextField(),BorderLayout.NORTH);
jpl.add(new JTextArea(),BorderLayout.CENTER);
jpl.add(new JButton("按钮"),BorderLayout.WEST);
jpl.add(new JButton("按钮"),BorderLayout.EAST);
this.setSize(300,400);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
}
public static void main(String[] args) throws Exception {
new Layout1();
}
}
[注]教科书中有关于计算器的编制程序。
在完全自由布局中,控件的位置,大小,用坐标决定,而不是由界面大小决定。实际上是:设置容器布局为null,然后通过setSize设置大小,setLocation设置位置。
部分情况不适用该布局方式的原因:坐标体系在不同的操作系统不能保证相同。
[例1]设置一个按钮,从界面上方以抛物线的形式掉下来。
import javax.swing.*;
import java.awt.*;
class Layout1 extends JFrame implements Runnable{
private JButton jbt = new JButton();
int X,Y = 0;
public Layout1(){
jbt.setIcon(new ImageIcon("img.jpg"));
this.setLayout(null);
jbt.setSize(80,60);
this.add(jbt);
this.setSize(300,400);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
Thread th = new Thread(this);
th.start();
}
public void run(){
while(true){
try{Thread.sleep(20) ;} catch(Exception e){}
X++; Y=X*X/100;
jbt.setLocation(X,Y);
}
}
public static void main(String[] args) throws Exception {
new Layout1();
}
}
[例2]小球自由落体掉下,弹起来,再次自由落体。
import javax.swing.*;
import java.awt.*;
class Layout1 extends JFrame implements Runnable{
private JButton jbt = new JButton();
int Y = 0;
int DIR = 1;
public Layout1(){
Icon icon = new ImageIcon("img.jpg");
jbt.setIcon(icon);
this.setLayout(null);
jbt.setSize(icon.getIconWidth(),icon.getIconHeight());
this.add(jbt);
this.setSize(300,400);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
Thread th = new Thread(this);
th.start();
}
public void run(){
while(true){
try{Thread.sleep(20);} catch(Exception e){}
if(DIR==1) { Y+=2; if(Y>=(this.getHeight()-jbt.getHeight())) DIR=0; }
else if(DIR==0) { Y--; if(Y<=0) DIR=1; }
jbt.setLocation(60,Y);
}
}
public static void main(String[] args) throws Exception {
new Layout1();
}
}
Java事件处理在java.awt.event包中。
事件:程序对某些操作的响应。
点击按钮,打印“Hello”的三个步骤是:(其余都类似)
①实现接口(监听器)、②编写函数、③绑定,叫做事件监听机制。
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class Printer implements ActionListener{ //①实现接口
public void actionPerformed(ActionEvent e){ //②事件响应代码
System.out.println("Hello");
}
}
class EventTest extends JFrame{
private JButton jbt = new JButton("按钮");
public EventTest(){
Printer p = new Printer();
jbt.addActionListener(p); //③绑定,确保按钮发出命令,p能够执行
this.add(jbt,BorderLayout.NORTH);
this.setSize(300,400);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
}
public static void main(String[] args) {
new EventTest();
}
}
更加简洁的方法是:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class EventTest extends JFrame implements ActionListener{
private JButton jbt = new JButton("按钮");
public EventTest(){
jbt.addActionListener(this);
this.add(jbt,BorderLayout.NORTH);
this.setSize(300,400);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
}
public void actionPerformed(ActionEvent e){
System.out.println("Hello");
}
public static void main(String[] args){
new EventTest();
}
}
Java中定义,不同的事件,由不同的XXXListener来监听。
事件响应函数中,ActionEvent参数表示命令发出时,封装的命令发出方的信息。
[例]实现两个按钮,一个按钮点击,界面变红,另一个点击,界面变蓝。
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class EventTest extends JFrame implements ActionListener{
private JButton jbt1 = new JButton("变红");
private JButton jbt2 = new JButton("变蓝");
private JPanel jpl = new JPanel();
public EventTest(){
this.add(jbt1,BorderLayout.NORTH);
this.add(jbt2,BorderLayout.SOUTH);
this.add(jpl,BorderLayout.CENTER);
jbt1.addActionListener(this);
jbt2.addActionListener(this);
this.setSize(300,400);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
}
public void actionPerformed(ActionEvent e){
if(e.getSource()==jbt1){ //getSource()函数可以得知事件的源头
jpl.setBackground(Color.red);
}else{
jpl.setBackground(Color.blue);
}
}
public static void main(String[] args) {
new EventTest();
}
}
下列Listener,分别监听以下事件:
ActionListener:监听按钮点击,文本框内回车,菜单单击、其他支持单击响应的控件,以及一些拥有addActionListener函数的控件
ItemListener:监听选项变化时要响应的事件,如下拉菜单等
下拉菜单中有红绿蓝三个选项,选择时,界面自动变色
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class EventTest extends JFrame implements ItemListener {
private JComboBox jcb = new JComboBox();
private JPanel jpl = new JPanel();
public void itemStateChanged(ItemEvent e){
if(jcb.getSelectedItem().equals("红")){
jpl.setBackground(Color.red);
}else if(jcb.getSelectedItem().equals("绿")){
jpl.setBackground(Color.green);
}else{
jpl.setBackground(Color.blue);
}
}
public EventTest(){
this.add(jcb,BorderLayout.NORTH);
this.add(jpl,BorderLayout.CENTER);
jcb.addItemListener(this);
jcb.addItem("红"); jcb.addItem("绿"); jcb.addItem("蓝");
this.setSize(300,400);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
}
public static void main(String[] args) {
new EventTest();
}
}
[例1]鼠标进入按钮,按钮变红,退出,按钮变白。
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class EventTest extends JFrame implements MouseListener{
private JButton jbt = new JButton("按钮");
public EventTest(){
jbt.addMouseListener(this);
this.add(jbt,BorderLayout.NORTH);
this.setSize(300,400);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
}
public void mouseClicked(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {
jbt.setBackground(Color.red);
}
public void mouseExited(MouseEvent e) {
jbt.setBackground(Color.white);
}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public static void main(String[] args) {
new EventTest();
}
}
[例2]界面上有一个图片,鼠标进入,图片随机躲开。
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class EventTest extends JFrame implements MouseListener{
private JLabel jlb = new JLabel();
int X=50,Y=50;
public EventTest(){
Icon icon = new ImageIcon("img.jpg");
jlb.setIcon(icon);
this.setLayout(null); this.add(jlb);
jlb.setSize(icon.getIconWidth(),icon.getIconHeight());
jlb.setLocation(X,Y);
jlb.addMouseListener(this);
this.setSize(400,600);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
}
public void mouseClicked(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {
X = (int)(Math.random()*this.getWidth())-jlb.getWidth();
Y = (int)(Math.random()*this.getHeight())-jlb.getHeight();
jlb.setLocation(X,Y);
}
public void mouseExited(MouseEvent e) {}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public static void main(String[] args) {
new EventTest();
}
}
[例]鼠标在界面上移动,标题栏显示鼠标的当前坐标。
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class EventTest extends JFrame implements MouseMotionListener{
public EventTest(){
this.addMouseMotionListener(this);
this.setSize(400,600);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
}
public void mouseDragged(MouseEvent e) {
String str = e.getX() + "," + e.getY();
this.setTitle(str);
}
public void mouseMoved(MouseEvent e) {
}
public static void main(String[] args) {
new EventTest();
}
}
作业:界面上有一个图片,鼠标可以将图片从一个地方拖动到另一个地方。
作业:界面上有10个图片,鼠标可以将某个图片从一个地方拖动到另一个地方。
[例]使用键盘上的上下左右键,能控制界面上一个图片的上下左右移动。
[注意]键盘事件一般被更大的容器先截获。
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class EventTest extends JFrame implements KeyListener{
private JLabel jlb = new JLabel();
int X=50,Y=50;
public EventTest(){
Icon icon = new ImageIcon("img.jpg");
jlb.setIcon(icon);
this.setLayout(null); this.add(jlb);
jlb.setSize(icon.getIconWidth(),icon.getIconHeight());
jlb.setLocation(X,Y);
this.addKeyListener(this); //键盘事件应通过界面截获
this.setSize(400,600);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
}
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if(keyCode==KeyEvent.VK_UP){
Y-=30;
}else if(keyCode==KeyEvent.VK_DOWN){
Y+=30;
}else if(keyCode==KeyEvent.VK_LEFT){
X-=30;
}else if(keyCode==KeyEvent.VK_RIGHT){
X+=30;
}
jlb.setLocation(X,Y);
}
public void keyReleased(KeyEvent e) {}
public void keyTyped(KeyEvent e) {}
public static void main(String[] args) {
new EventTest();
}
}
[综合例题]界面中一个图片掉下,鼠标进入,暂停,离开,继续掉。
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class EventTest extends JFrame implements Runnable,MouseListener {
private JLabel jlb = new JLabel();
int X=50,Y=50;
boolean RUN = true;
public EventTest(){
Icon icon = new ImageIcon("img.jpg");
jlb.setIcon(icon);
this.setLayout(null); this.add(jlb);
jlb.setSize(icon.getIconWidth(),icon.getIconHeight());
jlb.setLocation(X,Y);
this.addMouseListener(this);
this.setSize(400,600);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
new Thread(this).start();
}
public void mouseClicked(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {
RUN = false;
}
public void mouseExited(MouseEvent e) {
RUN = true;
new Thread(this).start();
}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void run(){
while(RUN){
try{ Thread.sleep(100); }catch(Exception e){}
Y+=20;
jlb.setLocation(X,Y);
}
}
public static void main(String[] args) {
new EventTest();
}
}
如焦点到一行时上面的提示信息消失,移除后提示信息继续存在。
用控件组成的界面,一般叫做高级界面;纯粹用绘画方式组成的界面,一般叫做低级界面。
低级界面开发的原理:以面板为画布,画布上画内容,将画布放在JFrame上,画布单独编写一个类。
预备知识:
注意:Graphics有一个子类Graphics2D,画笔可以直接转换成该类型,Graphics2D内拥有更加丰富的画笔功能
基础演示:
import javax.swing.*;
import java.awt.*;
class MyCanvas extends JPanel{
public void paint(Graphics g){
Graphics2D g2d = (Graphics2D)g;
g2d.setStroke(new BasicStroke(50)); //设置粗细
g2d.setColor(Color.red);
g2d.drawLine(0,0,100,100);
}
}
class Paint1 extends JFrame{
private MyCanvas mc = new MyCanvas();
public Paint1(){
this.add(mc);
this.setSize(800,600);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
}
public static void main(String[] args) {
new Paint1();
}
}
[例1]界面上,不断随机位置出现随机颜色的线段。
import javax.swing.*;
import java.awt.*;
class MyCanvas extends JPanel implements Runnable{
public MyCanvas(){
new Thread(this).start();
}
public void paint(Graphics g){
Graphics2D g2d = (Graphics2D)g;
g2d.setStroke(new BasicStroke((int)(Math.random()*50)));
g2d.setColor(new Color((int)(Math.random()*256),(int)(Math.random()*256),(int)(Math.random()*256)));
g2d.drawLine((int)(Math.random()*this.getWidth()),
(int)(Math.random()*this.getHeight()),
(int)(Math.random()*this.getWidth()),
(int)(Math.random()*this.getHeight()));
}
public void run(){
while(true){
try{ Thread.sleep(50); } catch(Exception e){}
repaint();
}
}
}
class Paint1 extends JFrame{
private MyCanvas mc = new MyCanvas();
public Paint1(){
this.add(mc);
this.setSize(800,600);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
}
public static void main(String[] args) {
new Paint1();
}
}
[例2]界面上,鼠标拖动,可以连续画线。
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class MyCanvas extends JPanel implements MouseMotionListener{
int X=0,Y=0;
public MyCanvas(){
this.addMouseMotionListener(this);
}
public void mouseDragged(MouseEvent e) {
X = e.getX(); Y = e.getY();
this.repaint();
}
public void mouseMoved(MouseEvent e) {}
public void paint(Graphics g){
Graphics2D g2d = (Graphics2D)g;
g2d.setColor(Color.green);
g2d.fillOval(X,Y,20,20); //参数(int x,int y,int width,int height)函数用当前颜色填充由指定矩形界定的椭圆
}
}
class Paint1 extends JFrame{
private MyCanvas mc = new MyCanvas();
public Paint1(){
this.add(mc);
this.setSize(800,600);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
}
public static void main(String[] args) {
new Paint1();
}
}
绘制图像,使用的是画笔的drawImage函数。
基础演示:
import javax.swing.*;
import java.awt.*;
class MyCanvas extends JPanel{
private Image img = Toolkit.getDefaultToolkit().createImage("img.jpg");
public void paint(Graphics g){
Graphics2D g2d = (Graphics2D)g;
g2d.drawImage(img,50,60,this);
g2d.drawImage(img,200,300,200,50,this);
}
}
class Paint1 extends JFrame{
private MyCanvas mc = new MyCanvas();
public Paint1(){
this.add(mc);
this.setSize(800,600);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
}
public static void main(String[] args) {
new Paint1();
}
}
[例]一个图像,在界面上渐渐放大。
import javax.swing.*;
import java.awt.*;
class MyCanvas extends JPanel implements Runnable{
private Image img = Toolkit.getDefaultToolkit().createImage("img.jpg");
int X=0,Y=0;
public MyCanvas(){ new Thread(this).start(); }
public void run(){
while(true){
try{ Thread.sleep(50); } catch(Exception ex){}
X+=10; Y+=10;
repaint();
}
}
public void paint(Graphics g){
Graphics2D g2d = (Graphics2D)g;
g2d.drawImage(img,20,20,X,Y,this);
}
}
class Paint1 extends JFrame{
private MyCanvas mc = new MyCanvas();
public Paint1(){
this.add(mc);
this.setSize(800,600);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
}
public static void main(String[] args) {
new Paint1();
}
}
[例]将原图的左边一半,右边一半,上面一半,下面一半分别绘制。
import javax.swing.*;
import java.awt.*;
class MyCanvas extends JPanel{
private Image img = Toolkit.getDefaultToolkit().createImage("img.jpg");
public void paint(Graphics g){
Graphics2D g2d = (Graphics2D)g;
g2d.drawImage(img,0,0,100,100,0,0,img.getWidth(this)/2,img.getHeight(this), this);
g2d.drawImage(img,200,200,300,300,img.getWidth(this)/2,0,img.getWidth(this),img.getHeight(this),
this);
g2d.drawImage(img,300,50,400,100,0,0,img.getWidth(this),img.getHeight(this)/2, this);
g2d.drawImage(img,400,200,500,300,0,
img.getHeight(this)/2,img.getWidth(this),img.getHeight(this),
this);
}
}
class Paint1 extends JFrame{
private MyCanvas mc = new MyCanvas();
public Paint1(){
this.add(mc);
this.setSize(800,600);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
}
public static void main(String[] args) {
new Paint1();
}
}
利用rotate函数。 rotate(double theta,double x,double y)
import javax.swing.*;
import java.awt.*;
class MyCanvas extends JPanel{
private Image img = Toolkit.getDefaultToolkit().createImage("img.jpg");
public void paint(Graphics g){
Graphics2D g2d = (Graphics2D)g;
g2d.drawImage(img,200,300,this);
g2d.rotate(Math.PI/2,200+img.getWidth(this)/2,300+img.getHeight(this)/2);
g2d.drawImage(img,200,300,this);
}
}
class Paint1 extends JFrame{
private MyCanvas mc = new MyCanvas();
public Paint1(){
this.add(mc);
this.setSize(800,600);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
}
public static void main(String[] args) {
new Paint1();
}
}
[例]图像边移动边旋转。
import javax.swing.*;
import java.awt.*;
class MyCanvas extends JPanel implements Runnable{
private Image img = Toolkit.getDefaultToolkit().createImage("img.jpg");
double r = 0;
int X=0;
public MyCanvas(){ new Thread(this).start(); }
public void run(){
while(true){
try{ Thread.sleep(50); } catch(Exception e){}
r = r + 0.1;
X+=10;
repaint();
}
}
public void paint(Graphics g){
Graphics2D g2d = (Graphics2D)g;
g2d.setColor(Color.white);
g2d.fillRect(0,0,this.getWidth(),this.getHeight()); //实现之前经过的图像不在界面上显示
g2d.rotate(r,0+X+img.getWidth(this)/2,0+X+img.getHeight(this)/2);
g2d.drawImage(img,0+X,0+X,this);
}
}
class Paint1 extends JFrame{
private MyCanvas mc = new MyCanvas();
public Paint1(){
this.add(mc);
this.setSize(800,600);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
}
public static void main(String[] args) {
new Paint1();
}
}
网络中有两个重要的协议,分别是:
TCP:传输控制协议 面向连接 打电话
UDP:数据包协议 面向数据包 发短信
使用较多的是TCP。
网络应用程序有微信、QQ、抖音、浏览器等,Java网络编程讲解的是这些网络应用程序最底层的内容。
有两种服务器和客户端的通信模式:
C/S模式:客户端/服务器 客户安装应用程序,和服务器通信 微信、QQ
B/S模式:浏览器/服务器 客户端安装浏览器,和服务器通信 www.csu.edu.cn在浏览器中运行
信息通过客户端和服务器通信,客户端之间的通信,靠服务器转发;故网络应用程序,一定要分为客户端和服务器程序。
网络上的计算机靠IP地址来定位,出现在客户端。
用端口号(port)确定不同的网络应用程序类型,由服务器决定:
端口号用数字表示,一般0-65535之间,有些非常常见的应用程序,已经预设了端口号:HTTP(浏览器:80),FTP(21)等等。一般应用程序,建议使用4位数端口号,以免冲突
场景:客户端给服务器发送一句:你好,服务器回应,欢迎。
客户端连接服务器的步骤如下:[使用java.net包]
运用到的类如下:
Server1.java:
import java.net.*;
import java.io.*;
class Server1 {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(9999);
Socket s = ss.accept();
InputStreamReader isr = new InputStreamReader(s.getInputStream());
BufferedReader br = new BufferedReader(isr);
String msg = br.readLine();
System.out.println(msg);
PrintStream ps = new PrintStream(s.getOutputStream());
ps.println("欢迎你连上服务器!");
}
}
Client1.java:
import java.net.*;
import java.io.*;
class Client1 {
public static void main(String[] args) throws Exception {
Socket s = new Socket("172.17.10.147", 9999);
PrintStream ps = new PrintStream(s.getOutputStream());
ps.println("你好,我是客户端");
BufferedReader br =
new BufferedReader(new InputStreamReader(s.getInputStream()));
String str = br.readLine();
System.out.println(str);
}
}
[例1]客户端和服务器互相聊天:
客户端和服务器都有文本框,输入内容,回车(ActionListener),信息发给对方显示;反过来也支持。
Server2.java:
import java.net.*;
import java.io.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class Server extends JFrame implements ActionListener,Runnable{
private JTextField jtf = new JTextField();
private JTextArea jta = new JTextArea();
private BufferedReader br = null;
private PrintStream ps = null;
public Server() throws Exception{
this.setTitle("服务器");
this.add(jtf,BorderLayout.SOUTH);
this.add(jta,BorderLayout.CENTER);
jtf.addActionListener(this);
this.setSize(300,500);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
ServerSocket ss = new ServerSocket(9999);
Socket s = ss.accept();
br = new BufferedReader(new InputStreamReader(s.getInputStream()));
ps = new PrintStream(s.getOutputStream());
new Thread(this).start();
}
public void run() {
while(true){
try{
String msg = br.readLine();
jta.append(msg + "\n");
}catch(Exception e){}
}
}
public void actionPerformed(ActionEvent e){
jta.append(jtf.getText() + "\n");
ps.println("服务器说:" + jtf.getText());
}
public static void main(String[] args) throws Exception {
new Server();
}
}
Client2.java:
import java.net.*;
import java.io.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class Client extends JFrame implements ActionListener,Runnable{
private JTextField jtf = new JTextField();
private JTextArea jta = new JTextArea();
private BufferedReader br = null;
private PrintStream ps = null;
public Client() throws Exception{
this.setTitle("客户端");
this.add(jtf,BorderLayout.NORTH);
this.add(jta,BorderLayout.CENTER);
jtf.addActionListener(this);
this.setSize(300,500);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
Socket s = new Socket("172.17.10.147",9999);
br = new BufferedReader(new InputStreamReader(s.getInputStream()));
ps = new PrintStream(s.getOutputStream());
new Thread(this).start();
}
public void run() {
while(true){
try{
String msg = br.readLine();
jta.append(msg + "\n");
}catch(Exception e){}
}
}
public void actionPerformed(ActionEvent e){
jta.append(jtf.getText() + "\n");
ps.println("客户端说:" + jtf.getText());
}
public static void main(String[] args) throws Exception {
new Client();
}
}
[例2·B/S典型例子]客户端给服务器发信息,如果发N字母,服务器发给客户端一个随机数字;如果发M字母,服务器给客户端发送一个欢迎文本。
Server3.java:
import java.net.*;
import java.io.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class Server extends JFrame implements Runnable{
private BufferedReader br = null;
private PrintStream ps = null;
public Server() throws Exception{
this.setTitle("服务器");
this.setSize(200,200);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
ServerSocket ss = new ServerSocket(9999);
Socket s = ss.accept();
br = new BufferedReader(new InputStreamReader(s.getInputStream()));
ps = new PrintStream(s.getOutputStream());
new Thread(this).start();
}
public void run() {
while(true){
try{
String msg = br.readLine();
if(msg.equals("N")){ ps.println("数字:" + Math.random()); }
if(msg.equals("M")){ ps.println("文本:欢迎"); }
}catch(Exception e){}
}
}
public static void main(String[] args) throws Exception {
new Server();
}
}
Client3.java:
import java.net.*;
import java.io.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class Client extends JFrame implements ActionListener,Runnable{
private JTextField jtf = new JTextField();
private JTextArea jta = new JTextArea();
private BufferedReader br = null;
private PrintStream ps = null;
public Client() throws Exception{
this.setTitle("客户端");
this.add(jtf,BorderLayout.NORTH);
this.add(jta,BorderLayout.CENTER);
jtf.addActionListener(this);
this.setSize(300,500);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
Socket s = new Socket("172.17.10.147",9999);
br = new BufferedReader(new InputStreamReader(s.getInputStream()));
ps = new PrintStream(s.getOutputStream());
new Thread(this).start();
}
public void run() {
while(true){
try{
String msg = br.readLine();
jta.append(msg + "\n");
}catch(Exception e){}
}
}
public void actionPerformed(ActionEvent e){
ps.println(jtf.getText());
}
public static void main(String[] args) throws Exception{
new Client();
}
}
应用场合:多个客户端连上服务器,客户端之间的通信依靠服务器转发。
[例1]多个客户端连上服务器:服务器端有一个界面,界面上有一个多行文本框,多个客户端连接,连上就在服务器显示“有人连上” 。
Server1.java:
import java.net.*;
import java.io.*;
import javax.swing.*;
class Server extends JFrame implements Runnable{
private JTextArea jta = new JTextArea();
private ServerSocket ss = null;
public Server() throws Exception{
this.add(jta);
this.setSize(200,400);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
ss = new ServerSocket(9999);
new Thread(this).start();
}
public void run(){
while(true){
try{
Socket s = ss.accept();
jta.append("有人连上!!\n");
}catch(Exception ex){}
}
}
public static void main(String[] args) throws Exception {
new Server();
}
}
Client1.java:
import java.net.*;
import java.io.*;
class Client {
public static void main(String[] args) throws Exception {
Socket s = new Socket("172.17.10.148", 9999);
}
}
[例2]服务器端群聊:每个客户端都可以输入信息,回车发送,发送之后的信息,在服务器端显示。
类中类,多线程,每个客户端连接对应一个线程。
Server2.java:
import java.net.*;
import java.io.*;
import java.awt.*;
import javax.swing.*;
class Server extends JFrame implements Runnable{
private JTextArea jta = new JTextArea();
private ServerSocket ss = null;
public Server() throws Exception{
this.add(jta);
jta.setFont(new Font("宋体",Font.BOLD,30));
this.setSize(200,400);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
ss = new ServerSocket(9999);
new Thread(this).start();
}
public void run(){
while(true){
try{
Socket s = ss.accept();
ChatThread ct = new ChatThread(s); ct.start();
}catch(Exception ex){}
}
}
class ChatThread extends Thread{
BufferedReader br = null;
ChatThread(Socket s) throws Exception{
br = new BufferedReader(new InputStreamReader(s.getInputStream()));
}
public void run(){
while(true){
try{
String msg = br.readLine();
jta.append(msg + "\n");
}catch(Exception e){}
}
}
}
public static void main(String[] args) throws Exception {
new Server();
}
}
Client2.java:
import java.net.*;
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class Client extends JFrame implements ActionListener {
private JTextField jtf = new JTextField();
private PrintStream ps = null;
private String nickName = null;
public Client() throws Exception{
this.add(jtf,BorderLayout.SOUTH);
jtf.addActionListener(this);
jtf.setFont(new Font("宋体",Font.BOLD,30));
this.setSize(300,200);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
nickName = JOptionPane.showInputDialog("请您输入昵称");
Socket s = new Socket("172.17.10.148", 9999);
ps = new PrintStream(s.getOutputStream());
}
public void actionPerformed(ActionEvent e){
ps.println(nickName + "说:" + jtf.getText());
}
public static void main(String[] args) throws Exception {
new Client();
}
}
[例3]客户端群聊:每个客户端都可以输入信息,回车发送,发送之后的信息,在每个客户端显示[服务器转发]。
Server3.java:
import java.net.*;
import java.io.*;
import java.awt.*;
import java.util.*;
import javax.swing.*;
class Server extends JFrame implements Runnable{
private ServerSocket ss = null;
private ArrayList<ChatThread> users = new ArrayList<ChatThread>(); //一维变长数组,存放ChatThread类型变量
public Server() throws Exception{
this.setSize(200,400);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
ss = new ServerSocket(9999);
new Thread(this).start();
}
public void run(){
while(true){
try{
Socket s = ss.accept();
ChatThread ct = new ChatThread(s);
users.add(ct); ct.start();
}catch(Exception ex){}
}
}
class ChatThread extends Thread{
BufferedReader br = null;
PrintStream ps = null;
ChatThread(Socket s) throws Exception{
br = new BufferedReader(new InputStreamReader(s.getInputStream()));
ps = new PrintStream(s.getOutputStream());
}
public void run(){
while(true){
try{
String msg = br.readLine();
for(ChatThread ct : users){
ct.ps.println(msg);
}
}catch(Exception e){}
}
}
}
public static void main(String[] args) throws Exception {
new Server();
}
}
Client3.java:
import java.net.*;
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class Client extends JFrame implements ActionListener,Runnable {
private JTextField jtf = new JTextField();
private JTextArea jta = new JTextArea();
private PrintStream ps = null;
private BufferedReader br = null;
private String nickName = null;
public Client() throws Exception{
this.add(jta,BorderLayout.CENTER);
this.add(jtf,BorderLayout.SOUTH);
jtf.addActionListener(this);
jtf.setFont(new Font("宋体",Font.BOLD,30));
jta.setFont(new Font("宋体",Font.BOLD,30));
this.setSize(400,600);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
nickName = JOptionPane.showInputDialog("请您输入昵称");
Socket s = new Socket("172.17.10.148", 9999);
ps = new PrintStream(s.getOutputStream());
br = new BufferedReader(new InputStreamReader(s.getInputStream()));
new Thread(this).start();
}
public void run(){
while(true){
try{
String msg = br.readLine();
jta.append(msg + "\n");
}catch(Exception e){}
}
}
public void actionPerformed(ActionEvent e){
ps.println(nickName + "说:" + jtf.getText());
}
public static void main(String[] args) throws Exception {
new Client();
}
}
[例4]客户端群聊:每个客户端增加一个按钮,点击按钮,该客户端下线。其他客户端显示该客户端下线的消息。
Server4.java:
import java.net.*;
import java.io.*;
import java.awt.*;
import java.util.*;
import javax.swing.*;
class Server extends JFrame implements Runnable{
private ServerSocket ss = null;
private ArrayList<ChatThread> users = new ArrayList<ChatThread>();
public Server() throws Exception{
this.setSize(200,400);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
ss = new ServerSocket(9999);
new Thread(this).start();
}
public void run(){
while(true){
try{
Socket s = ss.accept();
ChatThread ct = new ChatThread(s);
users.add(ct); ct.start();
}catch(Exception ex){}
}
}
class ChatThread extends Thread{
BufferedReader br = null;
PrintStream ps = null;
String nickName = null;
ChatThread(Socket s) throws Exception{
br = new BufferedReader(new InputStreamReader(s.getInputStream()));
ps = new PrintStream(s.getOutputStream());
}
public void run(){
while(true){
try{
String msg = br.readLine();
String[] strs = msg.split(":");
if(strs[0].equals("NICK")){
nickName = strs[1];
}else if(strs[0].equals("XIAXIAN")){ //传递
for(ChatThread ct : users){
if(ct.nickName.equals(strs[1])){
users.remove(ct);
}else{
ct.ps.println(strs[1]+"下线啦!");
}
}
}else{
for(ChatThread ct : users){
ct.ps.println(msg);
}
}
}catch(Exception e){}
}
}
}
public static void main(String[] args) throws Exception {
new Server();
}
}
Client4.java:
import java.net.*;
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class Client extends JFrame implements ActionListener,Runnable {
private JButton jbt = new JButton("下线");
private JTextField jtf = new JTextField();
private JTextArea jta = new JTextArea();
private PrintStream ps = null;
private BufferedReader br = null;
private String nickName = null;
public Client() throws Exception{
this.add(jbt,BorderLayout.NORTH);
this.add(jta,BorderLayout.CENTER);
this.add(jtf,BorderLayout.SOUTH);
jtf.addActionListener(this);
jbt.addActionListener(this);
jtf.setFont(new Font("宋体",Font.BOLD,30));
jta.setFont(new Font("宋体",Font.BOLD,30));
this.setSize(400,600);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
nickName = JOptionPane.showInputDialog("请您输入昵称");
Socket s = new Socket("172.17.10.148", 9999);
ps = new PrintStream(s.getOutputStream());
br = new BufferedReader(new InputStreamReader(s.getInputStream()));
ps.println("NICK:"+nickName);
new Thread(this).start();
}
public void run(){
while(true){
try{
String msg = br.readLine();
jta.append(msg + "\n");
}catch(Exception e){}
}
}
public void actionPerformed(ActionEvent e){
if(e.getSource()==jtf){
ps.println(nickName + "说:" + jtf.getText());
}else{
ps.println("XIAXIAN:" + nickName);
System.exit(0);
}
}
public static void main(String[] args) throws Exception {
new Client();
}
}
另例:客户端群聊:每个客户端增加一个按钮,点击按钮,该客户端下线。其他客户端显示该客户端下线的消息——服务器要对信息进行分类处理。
客户端还要显示在线客户名单,每个客户端可以选择某人,输入信息,回车发送,发送之后的信息,在指定客户端显示。
每个用户登录,用户昵称发给服务器,服务器转发给客户端显示用户列表
客户端选择人员之后,私聊对象的昵称发给服务器端,服务器端不再将聊天信息转发给所有客户端,而发给特定的客户端(加一个判断)
Server1.java:
import java.net.*;
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.HashMap;
class Server extends JFrame implements Runnable,ActionListener{
private List users = new List();
private JButton jbt = new JButton("远程关闭");
private ServerSocket ss = null;
private HashMap<String,ChatThread> cts = new HashMap<String,ChatThread>();
public Server() throws Exception{
this.add(users,BorderLayout.CENTER);
this.add(jbt,BorderLayout.SOUTH);
jbt.addActionListener(this);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setSize(200,300);
this.setVisible(true);
ss = new ServerSocket(9999);
new Thread(this).start();
}
public void actionPerformed(ActionEvent e){
String selectedUser = users.getSelectedItem();
String msg = "LOGOUT:"+selectedUser;
ChatThread ct = cts.get(selectedUser);
ct.ps.println(msg);
users.remove(selectedUser);
cts.remove(selectedUser);
}
public void run(){
while(true){
try{
Socket s = ss.accept();
ChatThread ct = new ChatThread(s);
}catch(Exception e){}
}
}
class ChatThread extends Thread{
PrintStream ps = null;
BufferedReader br = null;
String nickName = null;
ChatThread(Socket s) throws Exception{
ps = new PrintStream(s.getOutputStream());
br = new BufferedReader(new InputStreamReader(s.getInputStream()));
this.start();
}
public void run(){
while(true){
try{
String msg = br.readLine();
String[] msgs = msg.split(":");
if(msgs[0].equals("LOGIN")){
nickName = msgs[1];
users.add(nickName);
cts.put(nickName,this);
}
}catch(Exception ex){}
}
}
}
public static void main(String[] args) throws Exception {
new Server();
}
}
Client1.java:
import java.net.*;
import java.io.*;
import javax.swing.*;
class Client extends JFrame implements Runnable{
private String nickName = null;
private PrintStream ps = null;
private BufferedReader br = null;
public Client() throws Exception{
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setSize(300,200);
this.setVisible(true);
nickName = JOptionPane.showInputDialog("输入昵称");
Socket s = new Socket("172.17.10.147", 9999);
ps = new PrintStream(s.getOutputStream());
br = new BufferedReader(new InputStreamReader(s.getInputStream()));
ps.println("LOGIN:"+nickName);
new Thread(this).start();
}
public void run(){
while(true){
try{
String msg = br.readLine();
String[] msgs = msg.split(":");
if(msgs[0].equals("LOGOUT")){
JOptionPane.showMessageDialog(this,"您被踢出!");
this.dispose();
}
}catch(Exception e){}
}
}
public static void main(String[] args) throws Exception {
new Client();
}
}
服务器可以监控各个客户端。
两个客户端输入昵称,连接到服务器,服务器显示昵称列表。选择某人,将其远程关闭
Server1.java:
import java.net.*;
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.HashMap;
class Server extends JFrame implements Runnable,ActionListener{
private List users = new List();
private JButton jbt = new JButton("远程关闭");
private ServerSocket ss = null;
private HashMap<String,ChatThread> cts = new HashMap<String,ChatThread>();
public Server() throws Exception{
this.add(users,BorderLayout.CENTER);
this.add(jbt,BorderLayout.SOUTH);
jbt.addActionListener(this);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setSize(200,300);
this.setVisible(true);
ss = new ServerSocket(9999);
new Thread(this).start();
}
public void actionPerformed(ActionEvent e){
String selectedUser = users.getSelectedItem();
String msg = "LOGOUT:"+selectedUser;
ChatThread ct = cts.get(selectedUser);
ct.ps.println(msg);
users.remove(selectedUser);
cts.remove(selectedUser);
}
public void run(){
while(true){
try{
Socket s = ss.accept();
ChatThread ct = new ChatThread(s);
}catch(Exception e){}
}
}
class ChatThread extends Thread{
PrintStream ps = null;
BufferedReader br = null;
String nickName = null;
ChatThread(Socket s) throws Exception{
ps = new PrintStream(s.getOutputStream());
br = new BufferedReader(new InputStreamReader(s.getInputStream()));
this.start();
}
public void run(){
while(true){
try{
String msg = br.readLine();
String[] msgs = msg.split(":");
if(msgs[0].equals("LOGIN")){
nickName = msgs[1];
users.add(nickName);
cts.put(nickName,this);
}
}catch(Exception ex){}
}
}
}
public static void main(String[] args) throws Exception {
new Server();
}
}
Client1.java:
import java.net.*;
import java.io.*;
import javax.swing.*;
class Client extends JFrame implements Runnable{
private String nickName = null;
private PrintStream ps = null;
private BufferedReader br = null;
public Client() throws Exception{
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setSize(300,200);
this.setVisible(true);
nickName = JOptionPane.showInputDialog("输入昵称");
Socket s = new Socket("172.17.10.147", 9999);
ps = new PrintStream(s.getOutputStream());
br = new BufferedReader(new InputStreamReader(s.getInputStream()));
ps.println("LOGIN:"+nickName);
new Thread(this).start();
}
public void run(){
while(true){
try{
String msg = br.readLine();
String[] msgs = msg.split(":");
if(msgs[0].equals("LOGOUT")){
JOptionPane.showMessageDialog(this,"您被踢出!");
this.dispose();
}
}catch(Exception e){}
}
}
public static void main(String[] args) throws Exception {
new Client();
}
}
[例1]两个客户端,每个客户端有一个图像掉下来,服务器端可以控制相应客户端暂停或继续。
定义客户端连接的信息格式为:LOGIN:昵称
Server2.java:
import java.net.*;
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.HashMap;
class Server extends JFrame implements Runnable,ActionListener{
private List users = new List();
private JButton jbt = new JButton("暂停");
private JButton jbt2 = new JButton("继续");
private ServerSocket ss = null;
private HashMap<String,ChatThread> cts = new HashMap<String,ChatThread>();
public Server() throws Exception{
this.add(users,BorderLayout.CENTER);
this.add(jbt,BorderLayout.SOUTH);
this.add(jbt2,BorderLayout.NORTH);
jbt.addActionListener(this);
jbt2.addActionListener(this);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setSize(200,300);
this.setVisible(true);
ss = new ServerSocket(9999);
new Thread(this).start();
}
public void actionPerformed(ActionEvent e){
String selectedUser = users.getSelectedItem();
String msg = null;
if(e.getSource()==jbt){
msg = "ZT:"+selectedUser;
}else{
msg = "JX:"+selectedUser;
}
ChatThread ct = cts.get(selectedUser);
ct.ps.println(msg);
}
public void run(){
while(true){
try{
Socket s = ss.accept();
ChatThread ct = new ChatThread(s);
}catch(Exception e){}
}
}
class ChatThread extends Thread{
PrintStream ps = null;
BufferedReader br = null;
String nickName = null;
ChatThread(Socket s) throws Exception{
ps = new PrintStream(s.getOutputStream());
br = new BufferedReader(new InputStreamReader(s.getInputStream()));
this.start();
}
public void run(){
while(true){
try{
String msg = br.readLine();
String[] msgs = msg.split(":");
if(msgs[0].equals("LOGIN")){
nickName = msgs[1];
users.add(nickName);
cts.put(nickName,this);
}
}catch(Exception ex){}
}
}
}
public static void main(String[] args) throws Exception {
new Server();
}
}
Client2.java:
import java.net.*;
import java.io.*;
import javax.swing.*;
class Client extends JFrame implements Runnable{
private String nickName = null;
private PrintStream ps = null;
private BufferedReader br = null;
private JLabel jlb = new JLabel();
private int X=100,Y = 0;
private ImageThread it = null;
public Client() throws Exception{
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setLayout(null); this.add(jlb);
Icon icon = new ImageIcon("img.jpg");
jlb.setIcon(icon);
jlb.setLocation(X,Y); jlb.setSize(icon.getIconWidth(),icon.getIconHeight());
this.setSize(300,500);
this.setVisible(true);
nickName = JOptionPane.showInputDialog("输入昵称");
Socket s = new Socket("172.17.10.147", 9999);
ps = new PrintStream(s.getOutputStream());
br = new BufferedReader(new InputStreamReader(s.getInputStream()));
ps.println("LOGIN:"+nickName);
new Thread(this).start();
it = new ImageThread(); it.start();
}
public void run(){
while(true){
try{
String msg = br.readLine();
String[] msgs = msg.split(":");
if(msgs[0].equals("ZT")){
it.RUN = false;
}
if(msgs[0].equals("JX")){
it = new ImageThread(); it.start();
}
}catch(Exception e){}
}
}
class ImageThread extends Thread{
boolean RUN = true;
public void run(){
while(RUN){
try{ Thread.sleep(100); Y++;
jlb.setLocation(X,Y);
}catch(Exception ex){}
}
}
}
public static void main(String[] args) throws Exception {
new Client();
}
}
[例2]两个客户端,服务器产生一个随机数,随机数从每个客户端掉下来,某一个先掉到底部,告知服务器,服务器重新产生随机数,两者同时从最上面掉下来。
定义客户端连接的信息格式为:LOGIN:昵称
Server3.java:
import java.net.*;
import java.io.*;
import java.awt.*;
import javax.swing.*;
import java.util.HashMap;
import java.util.Set;
class Server extends JFrame implements Runnable{
private List users = new List();
private ServerSocket ss = null;
private HashMap<String,ChatThread> cts = new HashMap<String,ChatThread>();
public Server() throws Exception{
this.add(users,BorderLayout.CENTER);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setSize(200,300);
this.setVisible(true);
ss = new ServerSocket(9999);
new Thread(this).start();
}
public void run(){
while(true){
try{
Socket s = ss.accept();
ChatThread ct = new ChatThread(s);
}catch(Exception e){}
}
}
class ChatThread extends Thread{
PrintStream ps = null;
BufferedReader br = null;
String nickName = null;
ChatThread(Socket s) throws Exception{
ps = new PrintStream(s.getOutputStream());
br = new BufferedReader(new InputStreamReader(s.getInputStream()));
this.start();
}
public void run(){
while(true){
try{
String msg = br.readLine();
String[] msgs = msg.split(":");
if(msgs[0].equals("LOGIN")){
nickName = msgs[1];
users.add(nickName);
cts.put(nickName,this);
}else if(msgs[0].equals("DB")){
String randStr = "SJS:"+Math.random();
Set<String> nickNames = cts.keySet();
for(String nk : nickNames){
ChatThread ct = cts.get(nk);
ct.ps.println(randStr);
}
}
}catch(Exception ex){}
}
}
}
public static void main(String[] args) throws Exception {
new Server();
}
}
Client3.java:
import java.net.*;
import java.io.*;
import javax.swing.*;
class Client extends JFrame implements Runnable{
private String nickName = null;
private PrintStream ps = null;
private BufferedReader br = null;
private JLabel jlb = new JLabel();
private int X=100,Y = 0;
private ImageThread it = null;
public Client() throws Exception{
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setLayout(null); this.add(jlb);
jlb.setText("欢迎参加本游戏"); jlb.setSize(200,50);
jlb.setLocation(X,Y);
this.setSize(300,500);
this.setVisible(true);
nickName = JOptionPane.showInputDialog("输入昵称");
Socket s = new Socket("172.17.10.147", 9999);
ps = new PrintStream(s.getOutputStream());
br = new BufferedReader(new InputStreamReader(s.getInputStream()));
ps.println("LOGIN:"+nickName);
new Thread(this).start();
it = new ImageThread(); it.start();
}
public void run(){
while(true){
try{
String msg = br.readLine();
String[] msgs = msg.split(":");
if(msgs[0].equals("SJS")){
jlb.setText(msgs[1]);
Y=0;
jlb.setLocation(X,Y);
}
}catch(Exception e){}
}
}
class ImageThread extends Thread{
boolean RUN = true;
public void run(){
while(RUN){
try{ Thread.sleep(100); Y++;
jlb.setLocation(X,Y);
if(Y>=500){
ps.println("DB:" + nickName);
}
}catch(Exception ex){}
}
}
}
public static void main(String[] args) throws Exception {
new Client();
}
}
考试题型:选择题、填空题、判断题、改错题、问答题、程序题。
模块 | 内容 | 要点 |
---|---|---|
Java语言基本语法 | Java特点 | 1、跨平台;2、运行的基本原理(代码用java文件,可执行文件是.class);3、语法和C基本相同,没有指针;程序入口是main函数 |
Java语法 | 1、变量、数据类型:float和long定义比较特殊;各种数据类型的精度顺序,高精度不能直接赋值给低精度;不能用0和非0表示真假;变量的定义必须掌握;字符数据类型有转义字符,用 ?表示 2、运算:算术运算:+ - * / % += -= *= /= ++ – ; 关系运算:> < >= <= == !=;逻辑运算:&& | |
面向对象基本概念 | 类和对象 | 类的定义(要会编程);由类来实例化对象原理;对象名的引用性质(理解对象名重新指向另一个对象的情况) |
成员变量和成员函数 | 成员变量和成员函数的定义;通过对象访问成员变量成员函数(.号);成员函数参数传递时的值传递和引用传递的区别(需要能够分析实例) | |
特殊的成员变量和成员函数 | 1、构造函数:定义方式、调用特点、垃圾收集机制 2、函数重载:三个条件满足其一即可 3、静态变量:定义方式、性质特点、如何调用(类名.或者对象名.来调用) 4、静态函数:定义方式(和静态变量类似)、性质特点(静态函数只能访问静态成员和函数中的局部变量)、如何调用(类名.或者对象名.来调用) 常见概念的英文形式必须要掌握 需要能够进行基本的编程 | |
面向对象基本特征 | 封装 | 1、包:定义包(注意包的嵌套关系);导入包中的类 2、类:public类(定义方式、特点);普通类(定义方式、特点) 3、成员:四个访问控制符:public、protected、默认、private 理解它们的具体权限 需要能够进行基本的编程 |
继承 | 1、如何实现继承(extends)?Java继承的特点(只能使用继承的非private成员、Java不支持多重继承) 2、覆盖:如何编程才算覆盖(子类定义成员和父类名称、返回类类型、参数皆相同)?覆盖有什么特点(子类对象调用时,直接调用子类成员)和要求(不允许减小子类成员的权限)? 3、父类构造函数的初始化(子类实例化时,会自动调用父类的构造函数,如果父类构造函数带参数,必须用super(参数列表)初始化父类对象,代码写在子类构造函数的第1句) 4、this和super的用法和意义 | |
多态性 | 1、多态性的定义:父类引用指向子类对象 Dialog d = new FontDialog(); 2、性质:该引用调用重写成员时,调用的是子类成员 | |
抽象类、接口等其他内容 | 1、抽象类如何定义?含有抽象函数的类,类前用abstract修饰 2、抽象类有何性质?不能被实例化;可以有普通函数;里面抽象函数必须被重写(除非子类也是抽象类) 3、接口如何定义?和抽象类有何区别?interface,用implements来实现。可以实现多个接口;接口中所有的函数都是抽象函数,并且是public;所有变量都是public的静态的final的变量(常量) 4、Object类:Java中所有类的最高父类 5、final关键字:final变量、final函数、final类特点 | |
Java语言基本功能 | 异常 | 1、try、catch、finally:匹配规则try(1)-catch(1…)-finally(0,1);程序运行的逻辑;了解Java中常见异常类和异常原因的对应(代码预测):NullPointerException、NumberFormatException、IOException等等 2、throw、throws:掌握其使用的位置 |
多线程 | 1、定义线程(能写代码):继承Thread、实现Runnable Thread.sleep(XX);知道其用法 2、调用线程:启动线程:继承Thread、实现Runnable两类有不同的启动方法 3、控制线程:暂停和继续 | |
基本API | 1、java.lang:Math重点掌握随机数;String重点掌握字符串长度、字符串按位置访问函数;StringBuffer掌握和String的区别;基本数据类型的包装类掌握字符串和数值的互相转换 以上需要会编程 2、java.util:变长数组:List系列(子类)、Set系列(子类)、Map系列(子类);掌握其区别;需要能够用它们解决实际问题(写伪代码) | |
IO | 1、java.io包 2、File、FileInputStream、FileOutputStream、BufferedReader、PrintStream、RandomAccessFile各自的功能(不编程) | |
Java语言界面开发 | 界面和控件 | javax.swing: 界面和控件,常见的必须知道意义 java.awt:颜色和字体 |
布局 | java.awt: FlowLayout/BorderLayout/GridLayout区别 | |
Java事件开发 | 事件开发 | java.awt.event包,按钮点击等简单事件用什么来监听,发出什么类型事件? |
Java绘图 | Graphics、paint函数作用;repaint函数作用 | |
Java网络编程 | 基本概念 | IP地址、端口各自区别;服务器、客户端的区别 |
具体实现 | java.net ServerSocket\Socket各自作用;ServerSocket的accept函数的意义。 |