在线聊天(JavaSE实战项目)学习笔记

Chat0.1

搭建客户端ChatClient窗口,有两种方式:

一、继承Frame类(比较灵活)

调用Frame类中的setLocation(int x, int y)方法设置窗口位置,setSize(int width, int height)方法设置窗口大小,setVisible(true)方法将窗口显示出来

setSize(int width, int height):其实就是定义控件的大小,有两个参数,分别对应宽度和高度;

setLocation(int x, int y):将组件移到新位置,用x 和 y 参数来指定新位置的左上角

setBounds(int x, int y, int width, int height):四个参数,既定义组件的位置,也定义控件的大小; 其实它就是上面两个函数的功能的组合

import java.awt.Frame;

public class ChatClient extends Frame{

	public static void main(String[] args) {

		new ChatClient().launchFrame();
	}
	
	public void launchFrame()
	{
		setLocation(400, 300);
		setSize(300, 300);
		setVisible(true);
	}
}

二、直接使用Frame类


Chat0.2

向客户端窗口中添加文本输入框TextField和文本输入区TextArea(可以输入多行文本),使用add方法

import java.awt.*;

public class ChatClient extends Frame{

	TextField tfTxt = new TextField();
	TextArea taContent = new TextArea();
	
	public static void main(String[] args) {
		new ChatClient().launchFrame();
	}
	
	public void launchFrame(){
		setLocation(400, 300);
		setSize(300, 300);
		add(tfTxt, BorderLayout.SOUTH);
		add(taContent, BorderLayout.NORTH);
		pack();//void pack() 使此窗口的大小适合其子组件的首选大小和布局。 
		setVisible(true);
	}

}

Chat0.3

添加客户端窗口关闭功能,使用窗口的 addWindowListener 方法

WindowListener是java中的接口。主要作用:
用于接收窗口事件的侦听器接口。旨在处理窗口事件的类要么实现此接口(及其包含的所有方法),要么扩展抽象类WindowAdapter(仅重写所需的方法)。然后使用窗口的 addWindowListener 方法将从该类所创建的侦听器对象向该 Window 注册。当通过打开、关闭、激活或停用、图标化或取消图标化而改变了窗口状态时,将调用该侦听器对象中的相关方法,并将 WindowEvent 传递给该方法。
import java.awt.*;
import java.awt.event.*;

public class ChatClient extends Frame{
	
	TextField tfTxt = new TextField();
	TextArea taContent = new TextArea();
	
	public static void main(String[] args){
		new ChatClient().launchFrame();
	}

	public void launchFrame() {
		setLocation(400, 300);
		setSize(300, 300);
		add(tfTxt, BorderLayout.SOUTH);
		add(taContent, BorderLayout.NORTH);
		pack();
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
		setVisible(true);
	}
}

Chat0.4

向客户端中添加功能:在文本输入框TextFiled中输入内容按回车键后,内容会显示到文本输入区TextArea中

取文本内容getText()方法,设置文本内容setText()方法

import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class ChatClient extends Frame{
	
	TextField tfTxt = new TextField();
	TextArea taContent = new TextArea();
	
	public static void main(String[] args){
		new ChatClient().launchFrame();
	}

	public void launchFrame() {
		setLocation(400, 300);
		setSize(300, 300);
		add(tfTxt, BorderLayout.SOUTH);
		add(taContent, BorderLayout.NORTH);
		pack();
		addWindowListener(new WindowAdapter() {

			@Override
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
			
		});
		tfTxt.addActionListener(new TFListener());
		setVisible(true);
	}
	
	private class TFListener implements ActionListener{

		@Override
		public void actionPerformed(ActionEvent e) {
			String s = tfTxt.getText().trim();
			taContent.setText(s);
			tfTxt.setText("");
		}
		
	}
}

Chat0.5

创建ChatSever服务端

1、使用ServerSocket创建服务端(ServerSocket对象用于监听来自客户端的Socket连接)

        ServerSocket(int port):用指定的端口port来创建一个ServerSocket。该端口应该有一个有效的端口整数值,即0~65535。

2、接收来自客户端Socket的连接请求,使用accept()方法

        ServerSocket包含一个监听来自客户端连接请求的方法,即accept()方法

        Socket accept():如果接收到一个客户端Socket的连接请求,该方法将返回一个与客户端Socket对应的Socket;否则该方法将一直处于等待状态,线程也被阻塞。

注意:服务端只有一个,客户端有多个,需使用while循环来接收多个客户端

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class ChatServer {
	public static void main(String[] args) {
		try{
			ServerSocket ss = new ServerSocket(8888);
			while(true) {//用于接收多个客户端
				Socket s = ss.accept();
                                System.out.println("a client connected");//用于验证客户端是否已连接成功			
			}
		}
		catch(IOException e) {
			e.printStackTrace();
		}	
	}
}

Chat0.6

ChatClient

1、在显示客户端窗口的同时,将客户端与服务端进行连接,将连接步骤封装成connect()方法

2、connect()方法

(1)创建客户端对象:客户端通常使用Socket的构造器来连接到指定的服务器

Socket(InetAddress, int port):创建连接到指定远程主机、远程端口的Socket,该构造器没有指定本地地址、本地端口,默认使用本地主机的默认IP地址,默认使用系统动态分配的端口。

import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;

public class ChatClient extends Frame{
	Socket s = null;
	TextField tfTxt = new TextField();
	TextArea taContent = new TextArea();
	
	public static void main(String[] args) {
		new ChatClient().launchFrame();
	}
	
	public void launchFrame() {
		setLocation(400, 300);
		setSize(300, 300);
		add(tfTxt, BorderLayout.SOUTH);
		add(taContent, BorderLayout.NORTH);
		pack();
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
		tfTxt.addActionListener(new TFListener());
		setVisible(true);
		connect();
	}
	
	public void connect() {
		try {
			s = new Socket("127.0.0.1", 8888);
System.out.println("connected");
		}catch(UnknownHostException e) {
			e.printStackTrace();
		}catch(IOException e) {
			e.printStackTrace();
		}
	}
	
	public class TFListener implements ActionListener{
		public void actionPerformed(ActionEvent e) {
			String str = tfTxt.getText().trim();
			taContent.setText(str);
			
		}
	}

}

ChatServer

接收客户端发送过来的数据

当客户端、服务端产生了对应的Socket之后,,程序无须再区分服务器端、客户端,而是通过各自的Socket通信。Socket提供了如下两个方法来获取输入流和输出流。

(1)InputStream getInputStream():返回该Socket对象对应的输入流,让程序通过该输入流从Socket中取出数据。

(2)OutputStream getOutputStream():返回该Socket对象对应的输出流,让程序通过该输出流向Socket中输出数据。

import java.io.DataInputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class ChatServer {

	public static void main(String[] args) {
		try {
			ServerSocket ss = new ServerSocket(8888);
			while(true) {
				Socket s = ss.accept();
System.out.println("a client connected");
				DataInputStream dis = new DataInputStream(s.getInputStream());
				String str = dis.readUTF();
				System.out.println(str);
				dis.close();
			}
		}catch(IOException e) {
			e.printStackTrace();
		}
	}

}

Chat0.7

ChatClient

将从文本输入框TextField中获取到数据发送到服务端(客户端---->服务端)

OutputStream getOutputStream():返回该Socket对象对应的输出流,让程序通过该输出流向Socket中输出数据。

import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;


public class ChatClient extends Frame{
	Socket s = null;
	TextField tfTxt = new TextField();
	TextArea taContent = new TextArea();
	
	public static void main(String[] args) {
		new ChatClient().launchFrame();
	}

	public void launchFrame() {
		setLocation(400, 300);
		setSize(300, 300);
		add(tfTxt, BorderLayout.SOUTH);
		add(taContent, BorderLayout.NORTH);
		pack();
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
		tfTxt.addActionListener(new TFListener());
		setVisible(true);
		connect();
	}
	
	public void connect() {
		try {
			s = new Socket("127.0.0.1", 8888);
System.out.println("connected");
		}catch(UnknownHostException e) {
			e.printStackTrace();
		}catch(IOException e) {
			e.printStackTrace();
		}
	}
	
	public class TFListener implements ActionListener{
		public void actionPerformed(ActionEvent e) {
			String str = tfTxt.getText().trim();
			taContent.setText(str);
			tfTxt.setText("");
			
			try {
				DataOutputStream dos = new DataOutputStream(s.getOutputStream());
				dos.writeUTF(str);
				dos.flush();
				dos.close();
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		}
	}
}

Chat0.8

ChatClient

在关闭窗口的同时关闭输出流,关闭Socket

import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;


public class ChatClient extends Frame{
	Socket s = null;
	DataOutputStream dos = null;
	TextField tfTxt = new TextField();
	TextArea taContent = new TextArea();
	
	public static void main(String[] args) {
		new ChatClient().launchFrame();
	}

	public void launchFrame() {
		setLocation(400, 300);
		setSize(300, 300);
		add(tfTxt, BorderLayout.SOUTH);
		add(taContent, BorderLayout.NORTH);
		pack();
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				disconnect();
				System.exit(0);
			}
		});
		tfTxt.addActionListener(new TFListener());
		setVisible(true);
		connect();
	}
	
	public void connect() {
		try {
			s = new Socket("127.0.0.1", 8888);
			dos = new DataOutputStream(s.getOutputStream());
System.out.println("connected");
		}catch(UnknownHostException e) {
			e.printStackTrace();
		}catch(IOException e) {
			e.printStackTrace();
		}
	}
	
	public void disconnect() {
		try{
			dos.close();
			s.close();
		}catch(IOException e) {
			e.printStackTrace();
		}
		
	}
	public class TFListener implements ActionListener{
		public void actionPerformed(ActionEvent e) {
			String str = tfTxt.getText().trim();
			taContent.setText(str);
			tfTxt.setText("");
			
			try {
				dos.writeUTF(str);
				dos.flush();
				//dos.close();
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		}
	}
}

ChatServer

在之前的版本中服务端不能连续读取客户端发送过来的数据。

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.io.DataInputStream;

public class ChatServer {

	public static void main(String[] args) {
		boolean started = false;
		try{
			ServerSocket ss = new ServerSocket(8888);
			started = true;
			while(started) {//该while循环用于接收多个客户端
				boolean bConnected = false;
				Socket s = ss.accept();
System.out.println("a client connected");
				bConnected = true;
				DataInputStream dis = new DataInputStream(s.getInputStream());
				while(bConnected) {//该while循环可以连续读取客户端发送过来的信息
					String str = dis.readUTF();
					System.out.println(str);
				}
				
				dis.close();
			}
		}catch(IOException e) {
			e.printStackTrace();
		}
		
	}

}

Chat0.9

ChatClient无改动

ChatServer

异常处理:

(1)服务器端启动后,若再次启动服务端,则会产生BindException异常。原因是服务器端启动后,端口已经被占用,无法二次启动。

(2)启动服务器端和客户端后,若关闭客户端则会发生EOFException。

产生原因:服务端读取客户端发过来的数据使用的是readUTF()方法,该方法是阻塞式方法。在客户端关闭后,服务端并不知晓,仍在等待接收数据。



通过这个API,我们可以得出以下信息:

  • 这是一个IO异常的子类,名字也是END OF FILE的缩写,当然也表示流的末尾
  • 它在表明一个信息,流已经到末尾了,而大部分做法是以特殊值的形式返回给我们,而不是抛异常

  也就是说这个异常是被主动抛出来的,而不是底层或者编译器返回给我的,就像NullPointerException或IndexOutOfBoundsException一样。

详细解释见:https://www.cnblogs.com/yiwangzhibujian/p/7107084.html

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.io.DataInputStream;

public class ChatServer {
	public static void main(String[] args) {
		boolean started = false;
		try{
			ServerSocket ss = new ServerSocket(8888);
			started = true;
			while(started) {//该while循环用于接收多个客户端
				boolean bConnected = false;
				Socket s = ss.accept();
System.out.println("a client connected");
				bConnected = true;
				DataInputStream dis = new DataInputStream(s.getInputStream());
				while(bConnected) {//该while循环可以连续读取客户端发送过来的信息
					String str = dis.readUTF();
					System.out.println(str);
				}
				dis.close();
			}
		}catch(IOException e) {
			e.printStackTrace();
		}	
	}
}

Chat1.0

启动服务器端后,若开启多个客户端窗口,则服务器端显示只能连接一个客户端,其他客户端窗口连接不上服务器,向服务器发送数据也无法显示。

原因:服务器端读取客户端发送过来的数据使用的是readUTF()方法,该方法为阻塞式方法,主方法运行后,会卡在该方法处,一直等待接收数据。这也就导致服务器端只能处理一个客户端。

处理方法:开启多线程

import java.io.*;
import java.net.*;

public class ChatServer {
	boolean started = false;
	ServerSocket ss = null;
	
	public static void main(String[] args) {
		new ChatServer().start();
	}

	public void start() {
		try {
			ss = new ServerSocket(8888);
		} catch(BindException e) {
			System.out.println("端口使用中......");
			System.out.println("请关掉相关程序,并重新运行!");
			System.exit(0);
		} catch(IOException e) {
			e.printStackTrace();
		}
		
		try {
			started = true;
			while (started) {
				Socket s = ss.accept();
				Client c = new Client(s);
				new Thread(c).start();
			}
		} catch (IOException e) {
			e.printStackTrace();	
		} finally {
			try {
				ss.close();
			} catch(IOException e1) {
				e1.printStackTrace();
			}
		}
	}
	class Client implements Runnable {
		private Socket s;
		private DataInputStream dis;
		private boolean bConnected = false;
		
		public Client(Socket s) {
			this.s = s;
			try {
				dis = new DataInputStream(s.getInputStream());
				bConnected = true;
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		public void run() {
			System.out.println("a client connected");
			try {
				while (bConnected) {
					String str = dis.readUTF();
					System.out.println(str);
				}
			} catch(EOFException e) {
				System.out.println("Client closed");
			} catch (IOException e) {
				e.printStackTrace();	
			} finally {
				try {
					dis.close();
					s.close();
				} catch(IOException e1) {
					e1.printStackTrace();
				}
			}
		}
	}
}

Chat1.1

将从某一客户端接收到的数据转发给其他客户端。

List<Client> clients = new ArrayList<>();//将线程对象存储起来,一个线程对象即代表一个客户端
while (bConnected) {
	String str = dis.readUTF();
        System.out.println(str);
	for(int i = 0; i < clients.size(); i++) {
		Client c = clients.get(i);
		c.send(str);
	}
}
将从客户端读取到的数据,通过对List集合的逐一遍历,发送给每个客户端对象。
import java.io.*;
import java.net.*;
import java.util.*;

public class ChatServer {
	ServerSocket ss = null;
	boolean started = false;
	List<Client> clients = new ArrayList<>();
	
	public static void main(String[] args) {
		new ChatServer().start();
	}
	
	public void start() {
		try {
			ss = new ServerSocket(8888);
			started = true;
		} catch(BindException e) {
			System.out.println("端口使用中");
			System.out.println("请关闭相关程序重新运行服务器");
			System.exit(0);
		} catch(IOException e) {
			e.printStackTrace();
		}
		
		try {
			while(started) {
				Socket s = ss.accept();
				System.out.println("a client connected");
				Client c = new Client(s);
				new Thread(c).start();	
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				ss.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
		}
	}
	
	class Client implements Runnable {
		private Socket s;
		private DataInputStream dis;
		private DataOutputStream dos;
		private boolean bConnected = false;
		public Client (Socket s) {
			this.s = s;
			try {
				dis = new DataInputStream(s.getInputStream());
				dos = new DataOutputStream(s.getOutputStream());
				bConnected = true;
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		public void send(String str) {
			try {
				dos.writeUTF(str);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		public void run() {
			try {
				while (bConnected) {
					String str = dis.readUTF();
System.out.println(str);
					for(int i = 0; i < clients.size(); i++) {
						Client c = clients.get(i);
						c.send(str);
					}
				}
			} catch (EOFException e) {
				System.out.println("Client closed!");
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				try {
					if(dis != null) {
						dis.close();
					}
					if(s != null) {
						s.close();
					}	
					if(dos != null) {
						dos.close();
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
				
			}
		}
	}
}

Chat1.2

客户端接收从服务端发送过来的每个客户端的数据,并将数据显示到文本输入区TextArea中

当我们在向服务器端发送本地客户端的数据时,需要同时接收其他客户端发送过来的数据。因此需要使用多线程。

1.2异常处理:

开启多个客户端,同时进行聊天,当某一个客户端关闭后,会产生SocketException

原因:开启多个客户端后,在关闭其中某一个客户端时(主线程结束),会调用disconnect()方法,将客户端Socket关闭,而此时接收数据的线程中的输入流可能并未关闭,仍会从客户端Socket中读取数据,此时就会产生SocketException异常。

简单处理方式:直接进行捕捉,给出相应提示。

import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;

public class ChatClient extends Frame{
	TextField tfTxt = new TextField();
	TextArea taContent = new TextArea();
	Socket s = null;
	DataOutputStream dos = null;
	DataInputStream dis = null;
	private boolean bConnected = false;
	
	public static void main(String[] args) {
		new ChatClient().launchFrame();
	}

	public void launchFrame() {
		setLocation(400, 300);
		setSize(300, 300);
		add(tfTxt, BorderLayout.SOUTH);
		add(taContent, BorderLayout.NORTH);
		pack();
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				disconnect();
				System.exit(0);
			}	
		});
		tfTxt.addActionListener(new TFListener());
		setVisible(true);
		connect();
		new Thread(new RecvThread()).start();
	}
	
	public void connect() {
		try {
			s = new Socket("127.0.0.1", 8888);
			dos = new DataOutputStream(s.getOutputStream());
			dis = new DataInputStream(s.getInputStream());
			System.out.println("connected");
			bConnected = true;
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public void disconnect() {
		try {
			dos.close();
			dis.close();
			s.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public class TFListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			String str = tfTxt.getText().trim();
			//taContent.setText(str);
			tfTxt.setText("");
			
			try {
				dos.writeUTF(str);
				dos.flush();
			} catch (IOException e1) {
				e1.printStackTrace();
			}
			
		}
		
	}

	private class RecvThread implements Runnable {
		public void run() {
			try {
				while(bConnected) {
					String str = dis.readUTF();
					taContent.setText(taContent.getText() + str + '\n');
				}	
			} catch(SocketException e) {
				System.out.println("退出了,bye!");
			} catch(IOException e) {
				e.printStackTrace();
			}
		}	
	}
}
Chat1.3

异常处理:

(1)同时开启多个客户端进行聊天,当其中某个客户端关闭,继续进行聊天时会产生SocketException。


产生原因:服务器端会通过Socket向每个客户端发送数据,我们将每个客户端的Socket用List集合进行存储,服务器端向每个客户端发送数据时,会通过遍历List集合逐一发送,而此时关闭的客户端的Socket仍在其中,并未从List集合中移除,因此服务器端仍然会像关闭的客户端发送数据,此时便会产生SocketException异常。

处理方式:在发送数据时直接从List集合中移除,并给出提示信息。

import java.io.*;
import java.net.*;
import java.util.*;

public class ChatServer {
	ServerSocket ss = null;
	boolean started = false;
	List<Client> clients = new ArrayList<>();
	
	public static void main(String[] args) {
		new ChatServer().start();
	}
	
	public void start() {
		try {
			ss = new ServerSocket(8888);
			started = true;
		} catch(BindException e) {
			System.out.println("端口使用中");
			System.out.println("请关闭相关程序重新运行服务器");
			System.exit(0);
		} catch(IOException e) {
			e.printStackTrace();
		}
		
		try {
			while(started) {
				Socket s = ss.accept();
				System.out.println("a client connected");
				Client c = new Client(s);
				new Thread(c).start();
				clients.add(c);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				ss.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
		}
	}
	
	class Client implements Runnable {
		private Socket s;
		private DataInputStream dis;
		private DataOutputStream dos;
		private boolean bConnected = false;
		
		public Client (Socket s) {
			this.s = s;
			try {
				dis = new DataInputStream(s.getInputStream());
				dos = new DataOutputStream(s.getOutputStream());
				bConnected = true;
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		public void send(String str) {
			try {
				dos.writeUTF(str);
			} catch (SocketException e) {
				clients.remove(this);
				System.out.println("对方退出了!我从List里面去掉了!");
			} catch (IOException e) {
				clients.remove(this);
				System.out.println("对方退出了");
			}
		}
		
		public void run() {
			try {
				while (bConnected) {
					String str = dis.readUTF();
System.out.println(str);
					for(int i = 0; i < clients.size(); i++) {
						Client c = clients.get(i);
						c.send(str);
					}
				}
			} catch (EOFException e) {
				System.out.println("Client closed!");
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				try {
					if(dis != null) {
						dis.close();
					}
					if(s != null) {
						s.close();
					}	
					if(dos != null) {
						dos.close();
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
				
			}
		}
	}
}

注意:EOFException、SocketException均是IOException的子类

  • 7
    点赞
  • 60
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Java SE实践教程 源代码 2010-9-13 声明:在网上找了好久才找到这个源码,真不容易啊,请大家多多支持。 2010-9-13 内容简介:此书结合具体实例讲解,通俗易懂,又不乏深度。我觉得这本书写的确实不错,堪称经典,市面上这样的书实在太少了,所以在这里发布下,供大家共享。本书从编程技术、项目实践以及软件工程的角度出发,如果大家想学习基础语法部分,建立去下载别的书籍。当然这本书也讲解了语法,是从实战的角度讲解的。 目录回到顶部↑第1章 进驻爪哇岛——JAVA的基本语法. 1 1.1 讲解 2 1.1.1 爪哇岛的历史与演变 2 1.1.2 爪哇岛基本生存规则 4 1.1.3 爪哇岛上新人新风尚 11 1.2 练习 15 1.2.1 搭建Java开发环境 15 1.2.2 体验Java程序开发 21 1.2.3 J2SE 5.0新特性实践 26 1.3 小结 35 第2章 对象无处不在——面向对象的基本概念 37 2.1 讲解 38 2.1.1 什么是面向对象 38 2.1.2 面向对象的基本概念 38 2.1.3 Java对面向对象的支持 41 2.2 练习 42 2.2.1 JavaBeans技术开发可重用组件 42 2.2.2 面向对象的基础实践 44 2.3 小结 51 第3章 当一个变成多个——集合框架的基本概念 53 .3.1 讲解 54 3.1.1 集合概述 54 3.1.2 Collection接口 54 3.1.3 泛型(Generics) 56 3.1.4 Map接口 57 3.2 练习 59 3.2.1 创建课程管理系统 59 3.3 小结 68 第4章 数据传送的管道——JAVA I/O 71 4.1 讲解 72 4.1.1 流——Java I/O的基础 72 4.1.2 Java I/O库 72 4.2 练习 74 4.2.1 数据传送的通道 74 4.2.2 管道的一端 76 4.2.3 文件处理 78 4.2.4 基于对象的读写 80 4.2.5 NIO 85 4.3 小结 89 第5章 如何走得更稳——测试驱动的基本概念 91 5.1 讲解 92 5.1.1 什么是JUnit 92 5.1.2 使用JUnit的一般过程 92 5.1.3 安装JUnit 93 5.2 编写单元测试 93 5.2.1 第1个单元测试 93 5.3 编写单元测试的步骤 95 5.3.1 常用断言 95 5.3.2 TestSuite 96 5.3.3 JUnit框架组成 96 5.4 练习 97 5.4.1 创建JUnit单元测试 97 5.4.2 setUp和tearDown 102 5.4.3 使用TestSuite 103 5.5 补充:JUNIT 4的新增特性 104 5.5.1 测试方法 104 5.5.2 初始化方法 105 5.5.3 TestSuite初始化 106 5.5.4 兼容性 106 5.6 小结 107 第6章 三头六臂——线程和同步的基本概念 109 6.1 讲解 110 6.1.1 什么是线程 110 6.1.2 创建线程 110 6.1.3 线程的生命周期 112 6.1.4 线程的优先级 114 6.1.5 中断线程 115 6.1.6 线程组 116 6.1.7 处理未被捕获的异常 117 6.1.8 守护线程 117 6.2 同步与锁 118 6.2.1 synchronized和同步 118 6.2.2 锁对象 120 6.2.3 Condition对象 121 6.2.4 再谈synchronized 122 6.3 协调任务 124 6.3.1 线程池和Executor 124 6.3.2 Callable和Future 126 6.3.3 ScheduledExecutorService 127 6.4 线程安全的集合和同步器 128 6.4.1 阻塞队列 128 6.4.2 指定阻塞时间 130 6.4.3 同步器 131 6.4.4 Atomic类型 134 6.5 练习 134 6.5.1 线程间同步 134 6.5.2 生产者、消费者问题.. 137 6.6 小结 140 第7章 我要彩色照片——SWING的基本概念 141 7.1 讲解 142 7.1.1 Swing的基本概念 142 7.1.2 Swing组件继承关系 142 7.1.3 Swing组件一览 143 7.1.4 Swing和MVC设计模式 144 7.1.5 Swing的单线程模型 145 7.2 练习 148 7.2.1 第1个Swing程序 148 7.2.2 外观感觉 150 7.2.3 事件侦听器 151 7.2.4 Swing基本控件和窗口 155 7.2.5 Swing容器 176 7.2.6 Swing高级控件 181 7.3 小结 187 第8章 朋友们,你们在哪里——JAVA数据库运用 189 8.1 讲解 190 8.1.1 数据库的基本概念 190 8.1.2 了解Java DB 190 8.1.3 JDBC 与 JDBC 4.0 191 8.1.4 用Java让数据库动起来 192 8.1.5 事务处理简介 194 8.2 练习 195 8.2.1 数据库操作 195 8.2.2 我的联系手册 199 8.2.3 事务处理 221 8.3 小结 222 第9章 还想再见到你——数据持久化 223 9.1 讲解 224 9.1.1 数据持久化的基本概念 224 9.1.2 数据持久化技术简介 224 9.1.3 Java中的对象关系映射 225 9.1.4 对象XML序列化 227 9.2 练习 228 9.2.1 我的联系手册(JPA实现) 228 9.2.2 我的联系手册(JAXB实现) 238 9.3 小结 242 第10章 准备环球旅行——应用程序国际化 243 10.1 讲解 244 10.1.1 概念介绍 244 10.1.2 设置Locale 249 10.1.3 隔离语言环境相关数据 252 10.1.4 格式化 258 10.2 练习 266 10.2.1 对单独的文件进行国际化 266 10.2.2 在设计时国际化GUI表单 273 10.2.3 国际化整个项目 277 10.3 小结 281 第11章 请保持联系——JAVA网络连接 283 11.1 讲解 284 11.1.1 Java网络连接的基本概念 284 11.1.2 使用TCP协议的Socket网络编程 285 11.1.3 使用UDP协议的Socket 网络编程 289 11.1.4 多点传送和MulticastSocket类 290 11.1.5 NIO及相关技术 290 11.2 练习 291 11.2.1 ServerSocket与Socket示例: 开发一个Server-Client模型的程序 291 11.2.2 多点传送示例 293 11.2.3 打造你自己的QQ 295 11.3 小结 315 第12章 找个好管家——JMX 317 12.1 讲解 318 12.1.1 什么是 JMX 318 12.1.2 JMX基本概念 318 12.1.3 JMX管理应用开发 323 12.2 练习 325 12.2.1 建立JMX开发环境 325 12.2.2 创建拼词游戏程序 326 12.2.3 分布式管理扇形绘制Applet 程序 330 12.3 小结 350 第13章 让我们更专业——软件工程的基本概念 351 13.1 讲解 352 13.1.1 软件工程的基本概念 352 13.1.2 版本控制系统 356 13.1.3 统一建模语言 359 13.2 练习 360 13.2.1 建立CVS的使用环境和基本操作 360 13.2.2 使用标记和分支 373 13.3 使用UML建模 376 13.3.1 对基本结构建模 376 13.3.2 对高级结构建模 381 13.4 小结 387 索引... 389

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值