@ 网络编程/发送邮件/多线程编程/Applet 基础/文档注释

一、Java 网络编程

网络编程是指编写运行在多个设备(计算机)的程序,这些设备都通过网络连接起来。

java.net 包中 J2SE 的 API 包含有类和接口,它们提供低层次的通信细节。你可以直接使用这些类和接口,来专注于解决问题,而不用关注通信细节。

java.net 包中提供了两种常见的网络协议的支持:

TCP:TCP(英语:Transmission Control Protocol,传输控制协议) 是一种面向连接的、可靠的、基于字节流的传输层通信协议,TCP 层是位于 IP 层之上,应用层之下的中间层。TCP 保障了两个应用程序之间的可靠通信。通常用于互联网协议,被称 TCP / IP。

UDP:UDP (英语:User Datagram Protocol,用户数据报协议),位于 OSI 模型的传输层。一个无连接的协议。提供了应用程序之间要发送数据的数据报。由于UDP缺乏可靠性且属于无连接协议,所以应用程序通常必须容许一些丢失、错误或重复的数据包。

本教程主要讲解以下两个主题。

Socket 编程:这是使用最广泛的网络概念,它已被解释地非常详细。

1.1 URL 处理

URL(Uniform Resource Locator)中文名为统一资源定位符,有时也被俗称为网页地址。表示为互联网上的资源,如网页或者 FTP 地址。

本章节我们将介绍 Java 是如何处理 URL 的。URL 可以分为如下几个部分。

protocol://host:port/path?query#fragment

protocol(协议)可以是 HTTP、HTTPS、FTP 和 File,port 为端口号,path为文件路径及文件名。

HTTP 协议的 URL 实例如下:

http://www.baidu.com/index.html?language=cn

URL 解析:

协议为(protocol):http
主机为(host:port):www.runoob.com
端口号为(port): 80 ,以上URL实例并未指定端口,因为 HTTP 协议默认的端口号为 80。
文件路径为(path):/index.html
请求参数(query):language=cn
定位位置(fragment):j2se,定位到网页中 id 属性为 j2se 的 HTML 元素位置 。
URL 类方法
在java.net包中定义了URL类,该类用来处理有关URL的内容。对于URL类的创建和使用,下面分别进行介绍。

java.net.URL提供了丰富的URL构建方式,并可以通过java.net.URL来获取资源。

序号 方法描述
1 public URL(String protocol, String host, int port, String file) throws MalformedURLException.
通过给定的参数(协议、主机名、端口号、文件名)创建URL。
2 public URL(String protocol, String host, String file) throws MalformedURLException
使用指定的协议、主机名、文件名创建URL,端口使用协议的默认端口。
3 public URL(String url) throws MalformedURLException
通过给定的URL字符串创建URL
4 public URL(URL context, String url) throws MalformedURLException
使用基地址和相对URL创建
URL类中包含了很多方法用于访问URL的各个部分,具体方法及描述如下:

序号 方法描述
1 public String getPath()
返回URL路径部分。
2 public String getQuery()
返回URL查询部分。
3 public String getAuthority()
获取此 URL 的授权部分。
4 public int getPort()
返回URL端口部分
5 public int getDefaultPort()
返回协议的默认端口号。
6 public String getProtocol()
返回URL的协议
7 public String getHost()
返回URL的主机
8 public String getFile()
返回URL文件名部分
9 public String getRef()
获取此 URL 的锚点(也称为"引用")。
10 public URLConnection openConnection() throws IOException
打开一个URL连接,并运行客户端访问资源。
实例
以上实例演示了使用java.net的URL类获取URL的各个部分参数:

URLDemo.java
import java.net.*;
import java.io.*;public class URLDemo
{public static void main(String [] args){try{URL url = new URL("http://www.baidu.com/index.html?language=cn");System.out.println("URL 为:" + url.toString());System.out.println("协议为:" + url.getProtocol());System.out.println("验证信息:" + url.getAuthority());System.out.println("文件名及请求参数:" + url.getFile());System.out.println("主机名:" + url.getHost());System.out.println("路径:" + url.getPath());System.out.println("端口:" + url.getPort());System.out.println("默认端口:" + url.getDefaultPort());System.out.println("请求参数:" + url.getQuery());System.out.println("定位位置:" + url.getRef());}catch(IOException e){e.printStackTrace();}}
}

以上实例编译运行结果如下:

URL 为:http://www.baidu.com/index.html?language=cn
协议为:http
验证信息:www.baidu.com
文件名及请求参数:/index.html?language=cn
主机名:www.runoob.com
路径:/index.html
端口:-1
默认端口:80
请求参数:language=cn
定位位置:j2se
URLConnections 类方法
openConnection() 返回一个 java.net.URLConnection。

例如:

如果你连接HTTP协议的URL, openConnection() 方法返回 HttpURLConnection 对象。

如果你连接的URL为一个 JAR 文件, openConnection() 方法将返回 JarURLConnection 对象。

等等…

URLConnection 方法列表如下:

序号 方法描述
1 Object getContent()
检索URL链接内容
2 Object getContent(Class[] classes)
检索URL链接内容
3 String getContentEncoding()
返回头部 content-encoding 字段值。
4 int getContentLength()
返回头部 content-length字段值
5 String getContentType()
返回头部 content-type 字段值
6 int getLastModified()
返回头部 last-modified 字段值。
7 long getExpiration()
返回头部 expires 字段值。
8 long getIfModifiedSince()
返回对象的 ifModifiedSince 字段值。
9 public void setDoInput(boolean input)
URL 连接可用于输入和/或输出。如果打算使用 URL 连接进行输入,则将 DoInput 标志设置为 true;如果不打算使用,则设置为 false。默认值为 true。
10 public void setDoOutput(boolean output)
URL 连接可用于输入和/或输出。如果打算使用 URL 连接进行输出,则将 DoOutput 标志设置为 true;如果不打算使用,则设置为 false。默认值为 false。
11 public InputStream getInputStream() throws IOException
返回URL的输入流,用于读取资源
12 public OutputStream getOutputStream() throws IOException
返回URL的输出流, 用于写入资源。
13 public URL getURL()
返回 URLConnection 对象连接的URL
实例
以下实例中URL采用了HTTP 协议。 openConnection 返回HttpURLConnection对象。

URLConnDemo.java

import java.net.*;
import java.io.*;
public class URLConnDemo
{public static void main(String [] args){try{URL url = new URL("http://www.runoob.com");URLConnection urlConnection = url.openConnection();HttpURLConnection connection = null;if(urlConnection instanceof HttpURLConnection){connection = (HttpURLConnection) urlConnection;}else{System.out.println("请输入 URL 地址");return;}BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));String urlString = "";String current;while((current = in.readLine()) != null){urlString += current;}System.out.println(urlString);}catch(IOException e){e.printStackTrace();}}
}

以上实例编译运行结果如下:

$ javac URLConnDemo.java
$ java URLConnDemo
…这里会输出菜鸟教程首页(http://www.baidu.com)的 HTML 内容…

1.2 Socket 编程

套接字使用TCP提供了两台计算机之间的通信机制。 客户端程序创建一个套接字,并尝试连接服务器的套接字。

当连接建立时,服务器会创建一个 Socket 对象。客户端和服务器现在可以通过对 Socket 对象的写入和读取来进行通信。

java.net.Socket 类代表一个套接字,并且 java.net.ServerSocket 类为服务器程序提供了一种来监听客户端,并与他们建立连接的机制。

以下步骤在两台计算机之间使用套接字建立TCP连接时会出现:

服务器实例化一个 ServerSocket 对象,表示通过服务器上的端口通信。

服务器调用 ServerSocket 类的 accept() 方法,该方法将一直等待,直到客户端连接到服务器上给定的端口。

服务器正在等待时,一个客户端实例化一个 Socket 对象,指定服务器名称和端口号来请求连接。

Socket 类的构造函数试图将客户端连接到指定的服务器和端口号。如果通信被建立,则在客户端创建一个 Socket 对象能够与服务器进行通信。

在服务器端,accept() 方法返回服务器上一个新的 socket 引用,该 socket 连接到客户端的 socket。

连接建立后,通过使用 I/O 流在进行通信,每一个socket都有一个输出流和一个输入流,客户端的输出流连接到服务器端的输入流,而客户端的输入流连接到服务器端的输出流。

TCP 是一个双向的通信协议,因此数据可以通过两个数据流在同一时间发送.以下是一些类提供的一套完整的有用的方法来实现 socket

1.3 ServerSocket 类的方法

服务器应用程序通过使用 java.net.ServerSocket 类以获取一个端口,并且侦听客户端请求。

ServerSocket 类有四个构造方法:

创建非绑定服务器套接字。 如果 ServerSocket 构造方法没有抛出异常,就意味着你的应用程序已经成功绑定到指定的端口,并且侦听客户端请求。

这里有一些 ServerSocket 类的常用方法:

1.4 Socket 类的方法

java.net.Socket 类代表客户端和服务器都用来互相沟通的套接字。客户端要获取一个 Socket 对象通过实例化 ,而 服务器获得一个 Socket 对象则通过 accept() 方法的返回值。

Socket 类有五个构造方法.


当 Socket 构造方法返回,并没有简单的实例化了一个 Socket 对象,它实际上会尝试连接到指定的服务器和端口。

下面列出了一些感兴趣的方法,注意客户端和服务器端都有一个 Socket 对象,所以无论客户端还是服务端都能够调用这些方法

InetAddress 类的方法
这个类表示互联网协议(IP)地址。下面列出了 Socket 编程时比较有用的方法:

Socket 客户端实例
如下的 GreetingClient 是一个客户端程序,该程序通过 socket 连接到服务器并发送一个请求,然后等待一个响应

// 文件名 GreetingClient.javaimport java.net.*;
import java.io.*;public class GreetingClient
{public static void main(String [] args){String serverName = args[0];int port = Integer.parseInt(args[1]);try{System.out.println("连接到主机:" + serverName + " ,端口号:" + port);Socket client = new Socket(serverName, port);System.out.println("远程主机地址:" + client.getRemoteSocketAddress());OutputStream outToServer = client.getOutputStream();DataOutputStream out = new DataOutputStream(outToServer);out.writeUTF("Hello from " + client.getLocalSocketAddress());InputStream inFromServer = client.getInputStream();DataInputStream in = new DataInputStream(inFromServer);System.out.println("服务器响应: " + in.readUTF());client.close();}catch(IOException e){e.printStackTrace();}}
}

Socket 服务端实例
如下的GreetingServer 程序是一个服务器端应用程序,使用 Socket 来监听一个指定的端口。

// 文件名 GreetingServer.javaimport java.net.*;
import java.io.*;public class GreetingServer extends Thread
{private ServerSocket serverSocket;public GreetingServer(int port) throws IOException{serverSocket = new ServerSocket(port);serverSocket.setSoTimeout(10000);}public void run(){while(true){try{System.out.println("等待远程连接,端口号为:" + serverSocket.getLocalPort() + "...");Socket server = serverSocket.accept();System.out.println("远程主机地址:" + server.getRemoteSocketAddress());DataInputStream in = new DataInputStream(server.getInputStream());System.out.println(in.readUTF());DataOutputStream out = new DataOutputStream(server.getOutputStream());out.writeUTF("谢谢连接我:" + server.getLocalSocketAddress() + "\nGoodbye!");server.close();}catch(SocketTimeoutException s){System.out.println("Socket timed out!");break;}catch(IOException e){e.printStackTrace();break;}}}public static void main(String [] args){int port = Integer.parseInt(args[0]);try{Thread t = new GreetingServer(port);t.run();}catch(IOException e){e.printStackTrace();}}
}

$ javac GreetingServer.java
$ java GreetingServer 6066
等待远程连接,端口号为:6066…

新开一个命令窗口,执行以上命令来开启客户端:

$ javac GreetingClient.java
$ java GreetingClient localhost 6066
连接到主机:localhost ,端口号:6066
远程主机地址:localhost/127.0.0.1:6066
服务器响应: 谢谢连接我:/127.0.0.1:6066
Goodbye!

二、Java 发送邮件

使用Java应用程序发送 E-mail 十分简单,但是首先你应该在你的机器上安装 JavaMail API 和Java Activation Framework (JAF) 。

您可以从 Java 网站下载最新版本的 JavaMail,打开网页右侧有个 Downloads 链接,点击它下载。
您可以从 Java 网站下载最新版本的 JAF(版本 1.1.1)。
你也可以使用本站提供的下载链接:

JavaMail mail.jar 1.4.5
JAF(版本 1.1.1) activation.jar
下载并解压缩这些文件,在新创建的顶层目录中,您会发现这两个应用程序的一些 jar 文件。您需要把 mail.jar 和 activation.jar 文件添加到您的 CLASSPATH 中。

如果你使用第三方邮件服务器如QQ的SMTP服务器,可查看文章底部用户认证完整的实例
发送一封简单的 E-mail
下面是一个发送简单E-mail的例子。假设你的本地主机已经连接到网络。

// 文件名 SendEmail.javaimport java.util.*;
import javax.mail.*;
import javax.mail.internet.*;
import javax.activation.*;public class SendEmail
{public static void main(String [] args){   // 收件人电子邮箱String to = "abcd@gmail.com";// 发件人电子邮箱String from = "web@gmail.com";// 指定发送邮件的主机为 localhostString host = "localhost";// 获取系统属性Properties properties = System.getProperties();// 设置邮件服务器properties.setProperty("mail.smtp.host", host);// 获取默认session对象Session session = Session.getDefaultInstance(properties);try{// 创建默认的 MimeMessage 对象MimeMessage message = new MimeMessage(session);// Set From: 头部头字段message.setFrom(new InternetAddress(from));// Set To: 头部头字段message.addRecipient(Message.RecipientType.TO,new InternetAddress(to));// Set Subject: 头部头字段message.setSubject("This is the Subject Line!");// 设置消息体message.setText("This is actual message");// 发送消息Transport.send(message);System.out.println("Sent message successfully....");}catch (MessagingException mex) {mex.printStackTrace();}}
}

$ java SendEmail
Sent message successfully…

如果你想发送一封e-mail给多个收件人,那么使用下面的方法来指定多个收件人ID:

void addRecipients(Message.RecipientType type,Address[] addresses)
throws MessagingException

下面是对于参数的描述:

type:要被设置为 TO, CC 或者 BCC,这里 CC 代表抄送、BCC 代表秘密抄送。举例:Message.RecipientType.TO

addresses: 这是 email ID 的数组。在指定电子邮件 ID 时,你将需要使用 InternetAddress() 方法

发送一封 HTML E-mail
下面是一个发送 HTML E-mail 的例子。假设你的本地主机已经连接到网络。

和上一个例子很相似,除了我们要使用 setContent() 方法来通过第二个参数为 “text/html”,来设置内容来指定要发送HTML 内容

// 文件名 SendHTMLEmail.javaimport java.util.*;
import javax.mail.*;
import javax.mail.internet.*;
import javax.activation.*;public class SendHTMLEmail
{public static void main(String [] args){// 收件人电子邮箱String to = "abcd@gmail.com";// 发件人电子邮箱String from = "web@gmail.com";// 指定发送邮件的主机为 localhostString host = "localhost";// 获取系统属性Properties properties = System.getProperties();// 设置邮件服务器properties.setProperty("mail.smtp.host", host);// 获取默认的 Session 对象。Session session = Session.getDefaultInstance(properties);try{// 创建默认的 MimeMessage 对象。MimeMessage message = new MimeMessage(session);// Set From: 头部头字段message.setFrom(new InternetAddress(from));// Set To: 头部头字段message.addRecipient(Message.RecipientType.TO,new InternetAddress(to));// Set Subject: 头字段message.setSubject("This is the Subject Line!");// 发送 HTML 消息, 可以插入html标签message.setContent("<h1>This is actual message</h1>","text/html" );// 发送消息Transport.send(message);System.out.println("Sent message successfully....");}catch (MessagingException mex) {mex.printStackTrace();}}
}

$ java SendHTMLEmail
Sent message successfully…

发送带有附件的 E-mail
下面是一个发送带有附件的 E-mail的例子。假设你的本地主机已经连接到网络

// 文件名 SendFileEmail.javaimport java.util.*;
import javax.mail.*;
import javax.mail.internet.*;
import javax.activation.*;public class SendFileEmail
{public static void main(String [] args){// 收件人电子邮箱String to = "abcd@gmail.com";// 发件人电子邮箱String from = "web@gmail.com";// 指定发送邮件的主机为 localhostString host = "localhost";// 获取系统属性Properties properties = System.getProperties();// 设置邮件服务器properties.setProperty("mail.smtp.host", host);// 获取默认的 Session 对象。Session session = Session.getDefaultInstance(properties);try{// 创建默认的 MimeMessage 对象。MimeMessage message = new MimeMessage(session);// Set From: 头部头字段message.setFrom(new InternetAddress(from));// Set To: 头部头字段message.addRecipient(Message.RecipientType.TO,new InternetAddress(to));// Set Subject: 头字段message.setSubject("This is the Subject Line!");// 创建消息部分BodyPart messageBodyPart = new MimeBodyPart();// 消息messageBodyPart.setText("This is message body");// 创建多重消息Multipart multipart = new MimeMultipart();// 设置文本消息部分multipart.addBodyPart(messageBodyPart);// 附件部分messageBodyPart = new MimeBodyPart();String filename = "file.txt";DataSource source = new FileDataSource(filename);messageBodyPart.setDataHandler(new DataHandler(source));messageBodyPart.setFileName(filename);multipart.addBodyPart(messageBodyPart);// 发送完整消息message.setContent(multipart );//   发送消息Transport.send(message);System.out.println("Sent message successfully....");}catch (MessagingException mex) {mex.printStackTrace();}}
}

$ java SendFileEmail
Sent message successfully…

用户认证部分
如果需要提供用户名和密码给e-mail服务器来达到用户认证的目的,你可以通过如下设置来完成:

props.put(“mail.smtp.auth”, “true”);
props.setProperty(“mail.user”, “myuser”);
props.setProperty(“mail.password”, “mypwd”);

e-mail其他的发送机制和上述保持一致。

需要用户名密码验证邮件发送实例:
本实例以 QQ 邮件服务器为例,你需要在登录QQ邮箱后台在"设置"=》账号中开启POP3/SMTP服务 ,如下图所示:

QQ 邮箱通过生成授权码来设置密码:

// 需要用户名密码邮件发送实例
//文件名 SendEmail2.java
//本实例以QQ邮箱为例,你需要在qq后台设置import java.util.Properties;import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;public class SendEmail2
{public static void main(String [] args){// 收件人电子邮箱String to = "xxx@qq.com";// 发件人电子邮箱String from = "xxx@qq.com";// 指定发送邮件的主机为 smtp.qq.comString host = "smtp.qq.com";  //QQ 邮件服务器// 获取系统属性Properties properties = System.getProperties();// 设置邮件服务器properties.setProperty("mail.smtp.host", host);properties.put("mail.smtp.auth", "true");// 获取默认session对象Session session = Session.getDefaultInstance(properties,new Authenticator(){public PasswordAuthentication getPasswordAuthentication(){return new PasswordAuthentication("xxx@qq.com", "qq邮箱授权码"); //发件人邮件用户名、授权码}});try{// 创建默认的 MimeMessage 对象MimeMessage message = new MimeMessage(session);// Set From: 头部头字段message.setFrom(new InternetAddress(from));// Set To: 头部头字段message.addRecipient(Message.RecipientType.TO,new InternetAddress(to));// Set Subject: 头部头字段message.setSubject("This is the Subject Line!");// 设置消息体message.setText("This is actual message");// 发送消息Transport.send(message);System.out.println("Sent message successfully....from runoob.com");}catch (MessagingException mex) {mex.printStackTrace();}}
}

三、Java 多线程编程

Java 给多线程编程提供了内置的支持。 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

多线程是多任务的一种特别的形式,但多线程使用了更小的资源开销。

这里定义和线程相关的另一个术语 - 进程:一个进程包括由操作系统分配的内存空间,包含一个或多个线程。一个线程不能独立的存在,它必须是进程的一部分。一个进程一直运行,直到所有的非守护线程都结束运行后才能结束。

多线程能满足程序员编写高效率的程序来达到充分利用 CPU 的目的。

一个线程的生命周期
线程是一个动态执行的过程,它也有一个从产生到死亡的过程。

下图显示了一个线程完整的生命周期。

新建状态:
使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程。

就绪状态:
当线程对象调用了start()方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。

运行状态:
如果就绪状态的线程获取 CPU 资源,就可以执行 run(),此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。

阻塞状态:
如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种:

等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。

同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)。

其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。

死亡状态:
一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态

3.1 线程的优先级

每一个 Java 线程都有一个优先级,这样有助于操作系统确定线程的调度顺序。

Java 线程的优先级是一个整数,其取值范围是 1 (Thread.MIN_PRIORITY ) - 10 (Thread.MAX_PRIORITY )。

默认情况下,每一个线程都会分配一个优先级 NORM_PRIORITY(5)。

具有较高优先级的线程对程序更重要,并且应该在低优先级的线程之前分配处理器资源。但是,线程优先级不能保证线程执行的顺序,而且非常依赖于平台。

创建一个线程
Java 提供了三种创建线程的方法:

通过实现 Runnable 接口;
通过继承 Thread 类本身;
通过 Callable 和 Future 创建线程。
通过实现 Runnable 接口来创建线程
创建一个线程,最简单的方法是创建一个实现 Runnable 接口的类。

为了实现 Runnable,一个类只需要执行一个方法调用 run(),声明如下:

public void run()
你可以重写该方法,重要的是理解的 run() 可以调用其他方法,使用其他类,并声明变量,就像主线程一样。

在创建一个实现 Runnable 接口的类之后,你可以在类中实例化一个线程对象。

Thread 定义了几个构造方法,下面的这个是我们经常使用的:

Thread(Runnable threadOb,String threadName);

这里,threadOb 是一个实现 Runnable 接口的类的实例,并且 threadName 指定新线程的名字。

新线程创建之后,你调用它的 start() 方法它才会运行。

void start();
下面是一个创建线程并开始让它执行的实例:

实例

class RunnableDemo implements Runnable {private Thread t;private String threadName;RunnableDemo( String name) {threadName = name;System.out.println("Creating " +  threadName );}public void run() {System.out.println("Running " +  threadName );try {for(int i = 4; i > 0; i--) {System.out.println("Thread: " + threadName + ", " + i);// 让线程睡眠一会Thread.sleep(50);}}catch (InterruptedException e) {System.out.println("Thread " +  threadName + " interrupted.");}System.out.println("Thread " +  threadName + " exiting.");}public void start () {System.out.println("Starting " +  threadName );if (t == null) {t = new Thread (this, threadName);t.start ();}}
}public class TestThread {public static void main(String args[]) {RunnableDemo R1 = new RunnableDemo( "Thread-1");R1.start();RunnableDemo R2 = new RunnableDemo( "Thread-2");R2.start();}
}

编译以上程序运行结果如下:

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.

3.2 通过继承Thread来创建线程

创建一个线程的第二种方法是创建一个新的类,该类继承 Thread 类,然后创建一个该类的实例。

继承类必须重写 run() 方法,该方法是新线程的入口点。它也必须调用 start() 方法才能执行。

该方法尽管被列为一种多线程实现方式,但是本质上也是实现了 Runnable 接口的一个实例。

实例

class ThreadDemo extends Thread {private Thread t;private String threadName;ThreadDemo( String name) {threadName = name;System.out.println("Creating " +  threadName );}public void run() {System.out.println("Running " +  threadName );try {for(int i = 4; i > 0; i--) {System.out.println("Thread: " + threadName + ", " + i);// 让线程睡眠一会Thread.sleep(50);}}catch (InterruptedException e) {System.out.println("Thread " +  threadName + " interrupted.");}System.out.println("Thread " +  threadName + " exiting.");}public void start () {System.out.println("Starting " +  threadName );if (t == null) {t = new Thread (this, threadName);t.start ();}}
}public class TestThread {public static void main(String args[]) {ThreadDemo T1 = new ThreadDemo( "Thread-1");T1.start();ThreadDemo T2 = new ThreadDemo( "Thread-2");T2.start();}
}

编译以上程序运行结果如下:

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.

3.3 Thread 方法

下表列出了Thread类的一些重要方法:

序号 方法描述
1 public void start()
使该线程开始执行;Java 虚拟机调用该线程的 run 方法。
2 public void run()
如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。
3 public final void setName(String name)
改变线程名称,使之与参数 name 相同。
4 public final void setPriority(int priority)
更改线程的优先级。
5 public final void setDaemon(boolean on)
将该线程标记为守护线程或用户线程。
6 public final void join(long millisec)
等待该线程终止的时间最长为 millis 毫秒。
7 public void interrupt()
中断线程。
8 public final boolean isAlive()
测试线程是否处于活动状态。

上述方法是被 Thread 对象调用的,下面的方法是 Thread 类的静态方法。

序号 方法描述
1 public static void yield()
暂停当前正在执行的线程对象,并执行其他线程。
2 public static void sleep(long millisec)
在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。
3 public static boolean holdsLock(Object x)
当且仅当当前线程在指定的对象上保持监视器锁时,才返回 true。
4 public static Thread currentThread()
返回对当前正在执行的线程对象的引用。
5 public static void dumpStack()
将当前线程的堆栈跟踪打印至标准错误流。
实例
如下的ThreadClassDemo 程序演示了Thread类的一些方法:

DisplayMessage.java 文件代码:

// 文件名 : DisplayMessage.java
// 通过实现 Runnable 接口创建线程
public class DisplayMessage implements Runnable {private String message;public DisplayMessage(String message) {this.message = message;}public void run() {while(true) {System.out.println(message);}}
}GuessANumber.java 文件代码:
// 文件名 : GuessANumber.java
// 通过继承 Thread 类创建线程public class GuessANumber extends Thread {private int number;public GuessANumber(int number) {this.number = number;}public void run() {int counter = 0;int guess = 0;do {guess = (int) (Math.random() * 100 + 1);System.out.println(this.getName() + " guesses " + guess);counter++;} while(guess != number);System.out.println("** Correct!" + this.getName() + "in" + counter + "guesses.**");}
}

ThreadClassDemo.java 文件代码:

// 文件名 : ThreadClassDemo.java
public class ThreadClassDemo {public static void main(String [] args) {Runnable hello = new DisplayMessage("Hello");Thread thread1 = new Thread(hello);thread1.setDaemon(true);thread1.setName("hello");System.out.println("Starting hello thread...");thread1.start();Runnable bye = new DisplayMessage("Goodbye");Thread thread2 = new Thread(bye);thread2.setPriority(Thread.MIN_PRIORITY);thread2.setDaemon(true);System.out.println("Starting goodbye thread...");thread2.start();System.out.println("Starting thread3...");Thread thread3 = new GuessANumber(27);thread3.start();try {thread3.join();}catch(InterruptedException e) {System.out.println("Thread interrupted.");}System.out.println("Starting thread4...");Thread thread4 = new GuessANumber(75);thread4.start();System.out.println("main() is ending...");}
}

运行结果如下,每一次运行的结果都不一样。

Starting hello thread…
Starting goodbye thread…
Hello
Hello
Hello
Hello
Hello
Hello
Goodbye
Goodbye
Goodbye
Goodbye
Goodbye

通过 Callable 和 Future 创建线程

  1. 创建 Callable 接口的实现类,并实现 call() 方法,该 call() 方法将作为线程执行体,并且有返回值。

  2. 创建 Callable 实现类的实例,使用 FutureTask 类来包装 Callable 对象,该 FutureTask 对象封装了该 Callable 对象的 call() 方法的返回值。

  3. 使用 FutureTask 对象作为 Thread 对象的 target 创建并启动新线程。

  4. 调用 FutureTask 对象的 get() 方法来获得子线程执行结束后的返回值。

实例

public class CallableThreadTest implements Callable<Integer> {public static void main(String[] args)  {  CallableThreadTest ctt = new CallableThreadTest();  FutureTask<Integer> ft = new FutureTask<>(ctt);  for(int i = 0;i < 100;i++)  {  System.out.println(Thread.currentThread().getName()+" 的循环变量i的值"+i);  if(i==20)  {  new Thread(ft,"有返回值的线程").start();  }  }  try  {  System.out.println("子线程的返回值:"+ft.get());  } catch (InterruptedException e)  {  e.printStackTrace();  } catch (ExecutionException e)  {  e.printStackTrace();  }  }@Override  public Integer call() throws Exception  {  int i = 0;  for(;i<100;i++)  {  System.out.println(Thread.currentThread().getName()+" "+i);  }  return i;  }
}

创建线程的三种方式的对比

  1. 采用实现 Runnable、Callable 接口的方式创建多线程时,线程类只是实现了 Runnable 接口或 Callable 接口,还可以继承其他类。

  2. 使用继承 Thread 类的方式创建多线程时,编写简单,如果需要访问当前线程,则无需使用 Thread.currentThread() 方法,直接使用 this 即可获得当前线程。

3.4 线程的几个主要概念

在多线程编程时,你需要了解以下几个概念:

线程同步
线程间通信
线程死锁
线程控制:挂起、停止和恢复

3.5 多线程的使用

有效利用多线程的关键是理解程序是并发执行而不是串行执行的。例如:程序中有两个子系统需要并发执行,这时候就需要利用多线程编程。

通过对多线程的使用,可以编写出非常高效的程序。不过请注意,如果你创建太多的线程,程序执行的效率实际上是降低了,而不是提升了。

请记住,上下文的切换开销也很重要,如果你创建了太多的线程,CPU 花费在上下文的切换的时间将多于执行程序的时间!

四、Java Applet 基础

Applet 是一种 Java 程序。它一般运行在支持 Java 的 Web 浏览器内。因为它有完整的 Java API支持,所以Applet 是一个全功能的 Java 应用程序。

如下所示是独立的 Java 应用程序和 applet 程序之间重要的不同:

Java 中 Applet 类继承了 java.applet.Applet 类。
Applet 类没有定义 main(),所以一个 Applet 程序不会调用 main() 方法。
Applet 被设计为嵌入在一个 HTML 页面。
当用户浏览包含 Applet 的 HTML 页面,Applet 的代码就被下载到用户的机器上。
要查看一个 Applet 需要 JVM。 JVM 可以是 Web 浏览器的一个插件,或一个独立的运行时环境。
用户机器上的 JVM 创建一个 Applet 类的实例,并调用 Applet 生命周期过程中的各种方法。
Applet 有 Web 浏览器强制执行的严格的安全规则,Applet 的安全机制被称为沙箱安全。
Applet 需要的其他类可以用 Java 归档(JAR)文件的形式下载下来。

4.1 Applet的生命周期

Applet 类中的四个方法给我们提供了一个框架,你可以在该框架上开发小程序:

init: 该方法的目的是为你的 Applet 提供所需的任何初始化。在 Applet 标记内的 param 标签被处理后调用该方法。
start: 浏览器调用 init 方法后,该方法被自动调用。每当用户从其他页面返回到包含 Applet 的页面时,则调用该方法。
stop: 当用户从包含 Applet 的页面移除的时候,该方法自动被调用。因此,可以在相同的 Applet 中反复调用该方法。
destroy: 此方法仅当浏览器正常关闭时调用。因为 Applet 只有在 HTML 网页上有效,所以你不应该在用户离开包含 Applet 的页面后遗漏任何资源。
paint: 该方法在 start() 方法之后立即被调用,或者在 Applet 需要重绘在浏览器的时候调用。paint() 方法实际上继承于 java.awt。
“Hello, World” Applet:
下面是一个简单的 Applet 程序 HelloWorldApplet.java:

HelloWorldApplet.java 文件代码:

import java.applet.*;
import java.awt.*;public class HelloWorldApplet extends Applet
{public void paint (Graphics g){g.drawString ("Hello World", 25, 50);}
}

这些 import 语句将以下类导入到我们的 Applet 类中:

java.applet.Applet.
java.awt.Graphics.

没有这些 import 语句,Java 编译器就识别不了 Applet 和 Graphics 类。

4.2 Applet 类

每一个 Applet 都是 java.applet.Applet 类的子类,基础的 Applet 类提供了供衍生类调用的方法,以此来得到浏览器上下文的信息和服务。

这些方法做了如下事情:

得到 Applet 的参数
得到包含 Applet 的 HTML 文件的网络位置
得到 Applet 类目录的网络位置
打印浏览器的状态信息
获取一张图片
获取一个音频片段
播放一个音频片段
调整此 Applet 的大小
除此之外,Applet 类还提供了一个接口,该接口供 Viewer 或浏览器来获取 Applet 的信息,并且来控制 Applet 的执行。

Viewer 可能是:

请求 Applet 作者、版本和版权的信息
请求 Applet 识别的参数的描述
初始化 Applet
销毁 Applet
开始执行 Applet
结束执行 Applet
Applet 类提供了对这些方法的默认实现,这些方法可以在需要的时候重写。

"Hello,World"applet 都是按标准编写的。唯一被重写的方法是 paint 方法。

4.3 Applet 的调用

Applet 是一种 Java 程序。它一般运行在支持 Java 的 Web 浏览器内。因为它有完整的 Java API 支持,所以 Applet 是一个全功能的 Java 应用程序。

标签是在HTML文件中嵌入 Applet 的基础。以下是一个调用"Hello World"applet的例子;

HTML 代码:

<html>
<title>The Hello, World Applet</title>
<hr>
<applet code="HelloWorldApplet.class" width="320" height="120">
If your browser was Java-enabled, a "Hello, World"
message would appear here.
</applet>
<hr>
</html>

注意: 你可以参照 HTML Applet 标签来更多的了解从 HTML 中调用 applet 的方法。

< applet> 标签的属性指定了要运行的 Applet 类。width 和 height 用来指定 Applet 运行面板的初始大小。Applet 必须使用 </ applet> 标签来关闭。

如果 Applet 接受参数,那么参数的值需要在 标签里添加,该标签位于 和 之间。浏览器忽略了 applet 标签之间的文本和其他标签。

不支持 Java 的浏览器不能执行 和 。因此,在标签之间显示并且和 applet 没有关系的任何东西,在不支持的 Java 的浏览器里是可见的。

Viewer 或者浏览器在文档的位置寻找编译过的 Java 代码,要指定文档的路径,得使用 标签的 codebase 属性指定。

如下所示:

< applet codebase=“http://amrood.com/applets”
code=“HelloWorldApplet.class” width=“320” height=“120”>

如果 Applet 所在一个包中而不是默认包,那么所在的包必须在 code 属性里指定,例如:

< applet code=“mypackage.subpackage.TestApplet.class”
width=“320” height=“120”>

4.4 获得applet参数

下面的例子演示了如何使用一个 Applet 响应来设置文件中指定的参数。该 Applet 显示了一个黑色棋盘图案和第二种颜色。

第二种颜色和每一列的大小通过文档中的 Applet 的参数指定。

CheckerApplet 在 init() 方法里得到它的参数。也可以在 paint() 方法里得到它的参数。然而,在 Applet 开始得到值并保存了设置,而不是每一次刷新的时候都得到值,这样是很方便,并且高效的。

Applet viewer 或者浏览器在 Applet 每次运行的时候调用 init() 方法。在加载 Applet 之后,Viewer 立即调用 init() 方法(Applet.init()什么也没做),重写该方法的默认实现,添加一些自定义的初始化代码。

Applet.getParameter() 方法通过给出参数名称得到参数值。如果得到的值是数字或者其他非字符数据,那么必须解析为字符串类型。

下例是 CheckerApplet.java 的修改:

CheckerApplet.java 文件代码:
i

mport java.applet.*;
import java.awt.*;
public class CheckerApplet extends Applet
{int squareSize = 50;// 初始化默认大小public void init () {}private void parseSquareSize (String param) {}private Color parseColor (String param) {}public void paint (Graphics g) {}
}

下面是 CheckerApplet 类的 init() 方法和私有的 parseSquareSize() 方法:

public void init ()
{String squareSizeParam = getParameter ("squareSize");parseSquareSize (squareSizeParam);String colorParam = getParameter ("color");Color fg = parseColor (colorParam);setBackground (Color.black);setForeground (fg);
}
private void parseSquareSize (String param)
{if (param == null) return;try {squareSize = Integer.parseInt (param);}catch (Exception e) {// 保留默认值}
}

该 Applet 调用 parseSquareSize(),来解析 squareSize 参数。parseSquareSize() 调用了库方法 Integer. parseInt() 该方法将一个字符串解析为一个整数,当参数无效的时候,Integer.parseInt() 抛出异常。

因此,parseSquareSize() 方法也是捕获异常的,并不允许 Applet 接受无效的输入。

Applet 调用 parseColor()方法将颜色参数解析为一个 Color 值。parseColor() 方法做了一系列字符串的比较,来匹配参数的值和预定义颜色的名字。你需要实现这些方法来使 Applet 工作。

4.5 指定 applet 参数

如下的例子是一个HTML文件,其中嵌入了 CheckerApplet 类。HTML文件通过使用 标签的方法给 applet 指定了两个参数。

<html>
<title>Checkerboard Applet</title>
<hr>
<applet code="CheckerApplet.class" width="480" height="320">
<param name="color" value="blue">
<param name="squaresize" value="30">
</applet>
<hr>
</html>

注意: 参数名字大小写不敏感。

4.6 应用程序转换成 Applet

将图形化的 Java 应用程序(是指,使用AWT的应用程序和使用 java 程序启动器启动的程序)转换成嵌入在web页面里的applet是很简单的。

下面是将应用程序转换成 Applet 的几个步骤:

编写一个 HTML 页面,该页面带有能加载 applet 代码的标签。
编写一个 JApplet 类的子类,将该类设置为 public。否则,Applet 不能被加载。
消除应用程序的 main()方法。不要为应用程序构造框架窗口,因为你的应用程序要显示在浏览器中。
将应用程序中框架窗口的构造方法里的初始化代码移到 Applet 的 init() 方法中,你不必显示的构造 Applet 对象,浏览器将通过调用 init() 方法来实例化一个对象。
移除对 setSize() 方法的调用,对于 Applet 来讲,大小已经通过 HTML 文件里的 width 和 height 参数设定好了。
移除对 setDefaultCloseOperation() 方法的调用。Applet 不能被关闭,它随着浏览器的退出而终止。
如果应用程序调用了 setTitle() 方法,消除对该方法的调用。applet 不能有标题栏。(当然你可以给通过 html 的 title 标签给网页自身命名)
不要调用 setVisible(true),Applet 是自动显示的。

4.7 事件处理

Applet 类从 Container 类继承了许多事件处理方法。Container 类定义了几个方法,例如:processKeyEvent() 和processMouseEvent(),用来处理特别类型的事件,还有一个捕获所有事件的方法叫做 processEvent。

为了响应一个事件,Applet 必须重写合适的事件处理方法。

ExampleEventHandling.java 文件代码:

import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;
import java.applet.Applet;
import java.awt.Graphics;public class ExampleEventHandling extends Appletimplements MouseListener {StringBuffer strBuffer;public void init() {addMouseListener(this);strBuffer = new StringBuffer();addItem("initializing the applet ");}public void start() {addItem("starting the applet ");}public void stop() {addItem("stopping the applet ");}public void destroy() {addItem("unloading the applet");}void addItem(String word) {System.out.println(word);strBuffer.append(word);repaint();}public void paint(Graphics g) {//Draw a Rectangle around the applet's display area.g.drawRect(0, 0,getWidth() - 1,getHeight() - 1);//display the string inside the rectangle.g.drawString(strBuffer.toString(), 10, 20);}public void mouseEntered(MouseEvent event) {}public void mouseExited(MouseEvent event) {}public void mousePressed(MouseEvent event) {}public void mouseReleased(MouseEvent event) {}public void mouseClicked(MouseEvent event) {addItem("mouse clicked! ");}
}

如下调用该 Applet:

<html>
<title>Event Handling</title>
<hr>
<applet code="ExampleEventHandling.class"
width="300" height="300">
</applet>
<hr>
</html>

最开始运行,Applet 显示 “initializing the applet. Starting the applet.”,然后你一点击矩形框,就会显示 “mouse clicked” 。

4.8 显示图片

Applet 能显示 GIF,JPEG,BMP 等其他格式的图片。为了在 Applet 中显示图片,你需要使用 java.awt.Graphics 类的drawImage()方法。

如下实例演示了显示图片的所有步骤:

ImageDemo.java 文件代码:

import java.applet.*;
import java.awt.*;
import java.net.*;
public class ImageDemo extends Applet
{private Image image;private AppletContext context;public void init(){context = this.getAppletContext();String imageURL = this.getParameter("image");if(imageURL == null){imageURL = "java.jpg";}try{URL url = new URL(this.getDocumentBase(), imageURL);image = context.getImage(url);}catch(MalformedURLException e){e.printStackTrace();// Display in browser status barcontext.showStatus("Could not load image!");}}public void paint(Graphics g){context.showStatus("Displaying image");g.drawImage(image, 0, 0, 200, 84, null);g.drawString("www.javalicense.com", 35, 100);}
}

如下调用该applet:

<html>
<title>The ImageDemo applet</title>
<hr>
<applet code="ImageDemo.class" width="300" height="200">
<param name="image" value="java.jpg">
</applet>
<hr>
</html>

4.9 播放音频

Applet 能通过使用 java.applet 包中的 AudioClip 接口播放音频。AudioClip 接口定义了三个方法:

public void play(): 从一开始播放音频片段一次。
public void loop(): 循环播放音频片段
public void stop(): 停止播放音频片段
为了得到 AudioClip 对象,你必须调用 Applet 类的 getAudioClip() 方法。无论 URL 指向的是否是一个真实的音频文件,该方法都会立即返回结果。

直到要播放音频文件时,该文件才会下载下来。

如下实例演示了播放音频的所有步骤:

AudioDemo.java 文件代码:

import java.applet.*;
import java.awt.*;
import java.net.*;
public class AudioDemo extends Applet
{private AudioClip clip;private AppletContext context;public void init(){context = this.getAppletContext();String audioURL = this.getParameter("audio");if(audioURL == null){audioURL = "default.au";}try{URL url = new URL(this.getDocumentBase(), audioURL);clip = context.getAudioClip(url);}catch(MalformedURLException e){e.printStackTrace();context.showStatus("Could not load audio file!");}}public void start(){if(clip != null){clip.loop();}}public void stop(){if(clip != null){clip.stop();}}
}

如下调用applet:

<html>
<title>The ImageDemo applet</title>
<hr>
<applet code="ImageDemo.class" width="0" height="0">
<param name="audio" value="test.wav">
</applet>
<hr>

五、Java 文档注释

Java 支持三种注释方式。前两种分别是 // 和 /* /,第三种被称作说明注释,它以 /* 开始,以 */结束。

说明注释允许你在程序中嵌入关于程序的信息。你可以使用 javadoc 工具软件来生成信息,并输出到HTML文件中。

说明注释,使你更加方便的记录你的程序信息。

5.1 javadoc 标签

javadoc 工具软件识别以下标签:
标签 描述 示例
@author 标识一个类的作者 @author description
@deprecated 指名一个过期的类或成员 @deprecated description
{@docRoot} 指明当前文档根目录的路径 Directory Path
@exception 标志一个类抛出的异常 @exception exception-name explanation
{@inheritDoc} 从直接父类继承的注释 Inherits a comment from the immediate surperclass.
{@link} 插入一个到另一个主题的链接 {@link name text}
{@linkplain} 插入一个到另一个主题的链接,但是该链接显示纯文本字体 Inserts an in-line link to another topic.
@param 说明一个方法的参数 @param parameter-name explanation
@return 说明返回值类型 @return explanation
@see 指定一个到另一个主题的链接 @see anchor
@serial 说明一个序列化属性 @serial description
@serialData 说明通过writeObject( ) 和 writeExternal( )方法写的数据 @serialData description
@serialField 说明一个ObjectStreamField组件 @serialField name type description
@since 标记当引入一个特定的变化时 @since release
@throws 和 @exception标签一样. The @throws tag has the same meaning as the @exception tag.
{@value} 显示常量的值,该常量必须是static属性。 Displays the value of a constant, which must be a static field.
@version 指定类的版本 @version info

5.2 文档注释

在开始的 /** 之后,第一行或几行是关于类、变量和方法的主要描述。

之后,你可以包含一个或多个各种各样的 @ 标签。每一个 @ 标签必须在一个新行的开始或者在一行的开始紧跟星号(*).

多个相同类型的标签应该放成一组。例如,如果你有三个 @see 标签,可以将它们一个接一个的放在一起。

下面是一个类的说明注释的实例:

/*** 这个类绘制一个条形图
* @author runoob
* @version 1.2
*/

5.3 javadoc 输出什么

javadoc 工具将你 Java 程序的源代码作为输入,输出一些包含你程序注释的HTML文件。

每一个类的信息将在独自的HTML文件里。javadoc 也可以输出继承的树形结构和索引。

由于 javadoc 的实现不同,工作也可能不同,你需要检查你的 Java 开发系统的版本等细节,选择合适的 Javadoc 版本。

实例
下面是一个使用说明注释的简单实例。注意每一个注释都在它描述的项目的前面。

在经过 javadoc 处理之后,SquareNum 类的注释将在 SquareNum.html 中找到。

import java.io.*;/**
* 这个类演示了文档注释
* @author Ayan Amhed
* @version 1.2
*/
public class SquareNum {/*** This method returns the square of num.* This is a multiline description. You can use* as many lines as you like.* @param num The value to be squared.* @return num squared.*/public double square(double num) {return num * num;}/*** This method inputs a number from the user.* @return The value input as a double.* @exception IOException On input error.* @see IOException*/public double getNumber() throws IOException {InputStreamReader isr = new InputStreamReader(System.in);BufferedReader inData = new BufferedReader(isr);String str;str = inData.readLine();return (new Double(str)).doubleValue();}/*** This method demonstrates square().* @param args Unused.* @return Nothing.* @exception IOException On input error.* @see IOException*/public static void main(String args[]) throws IOException{SquareNum ob = new SquareNum();double val;System.out.println("Enter value to be squared: ");val = ob.getNumber();val = ob.square(val);System.out.println("Squared value is " + val);}
}

$ javadoc SquareNum.java
Loading source file SquareNum.java…
Constructing Javadoc information…
Standard Doclet version 1.5.0_13
Building tree for all the packages and classes…
Generating SquareNum.html…
SquareNum.java:39: warning - @return tag cannot be used
in method with void return type.
Generating package-frame.html…
Generating package-summary.html…
Generating package-tree.html…
Generating constant-values.html…
Building index for all the packages and classes…
Generating overview-tree.html…
Generating index-all.html…
Generating deprecated-list.html…
Building index for all classes…
Generating allclasses-frame.html…
Generating allclasses-noframe.html…
Generating index.html…
Generating help-doc.html…
Generating stylesheet.css…
1 warning
$

菜鸟教程,学习记录

Java基础了解-12-网络编程/发送邮件/多线程编程/Applet 基础/文档注释相关推荐

  1. 初学者怎样看懂python代码_Python零基础入门-(如何让人读懂你的代码)文档注释

    目标注释的作用 单行注释(行注释) 多行注释(块注释) 01. 注释的作用使用用自己熟悉的语言,在程序中对某些代码进行标注说明,增强程序的可读性 02. 单行注释(行注释)以 # 开头,# 右边的所有 ...

  2. devc中文注释显示问号_Python零基础入门-(如何让人读懂你的代码)文档注释

    目标 注释的作用 单行注释(行注释) 多行注释(块注释) 01. 注释的作用 使用用自己熟悉的语言,在程序中对某些代码进行标注说明,增强程序的可读性 02. 单行注释(行注释) 以 # 开头,# 右边 ...

  3. java文档注释的模板设置

    设置位置:在preference > java > code style > code templates > comments 中: 1.类的文档注释模板: /*** @au ...

  4. 响应式编程(反应式编程)的来龙去脉(同步编程、多线程编程、异步编程再到响应式编程)

    响应式编程的来龙去脉(同步编程.多线程编程.异步编程再到响应式编程) 文章目录 响应式编程的来龙去脉(同步编程.多线程编程.异步编程再到响应式编程) 简介 1. 示例 2. 同步编程 3. 多线程编程 ...

  5. java计算机毕业设计网络课程考试源代码+数据库+系统+lw文档

    java计算机毕业设计网络课程考试源代码+数据库+系统+lw文档 java计算机毕业设计网络课程考试源代码+数据库+系统+lw文档 本源码技术栈: 项目架构:B/S架构 开发语言:Java语言 开发软 ...

  6. 动态生成word文档原来如此简单!Aspose.Words助力以Java编程方式创建丰富的Word文档

    近年来,Word文档的动态生成已成为组成报告,报价,发票和其他类型文档的流行功能.各种制造公司都基于数据库中存储的数据生成发票.在这种情况下,文档自动化可以节省手动文档创建过程中所需的时间,精力和资源 ...

  7. java计算机毕业设计网络学习平台源代码+数据库+系统+lw文档

    java计算机毕业设计网络学习平台源代码+数据库+系统+lw文档 java计算机毕业设计网络学习平台源代码+数据库+系统+lw文档 本源码技术栈: 项目架构:B/S架构 开发语言:Java语言 开发软 ...

  8. java计算机毕业设计网络教学系统源程序+mysql+系统+lw文档+远程调试

    java计算机毕业设计网络教学系统源程序+mysql+系统+lw文档+远程调试 java计算机毕业设计网络教学系统源程序+mysql+系统+lw文档+远程调试 本源码技术栈: 项目架构:B/S架构 开 ...

  9. java计算机毕业设计网络城市交通应急管理系统MyBatis+系统+LW文档+源码+调试部署

    java计算机毕业设计网络城市交通应急管理系统MyBatis+系统+LW文档+源码+调试部署 java计算机毕业设计网络城市交通应急管理系统MyBatis+系统+LW文档+源码+调试部署 本源码技术栈 ...

最新文章

  1. 请你描述一下 cookies,sessionStorage 和 localStorage 的区别?
  2. poj3617 贪心
  3. OS / Linux / Inode 详解
  4. 【Android】开发优化之——调优工具:TrackView,Method Profiling
  5. 关于svn、git生成版本号脚本的改进
  6. Google 又逆天:语音输入离线实时输出文字,仅占 80 MB !然而……
  7. java2实用教程第六版习题答案
  8. Cognos常见错误解决办法
  9. 新北京交通限行时间、尾号查询
  10. matlab指标之间的关系分析,基于相关性分析和主成分分析的变量筛选方法
  11. 键盘功能键F1~F2的基本功能
  12. 基于matlab的步进电机仿真(一)
  13. 小Q系列故事——为什么时光不能倒流
  14. html 标签中的 alt 和 title 的作用
  15. python打印转义双引号和单引号
  16. c#做动态(gif)中文验证码
  17. mcrypt php 加密解密,PHP mcrypt启用、加密以及解密过程详解
  18. 8.3 Dirac定理(1952)
  19. SAP价值流程帮助请求流程-011
  20. 基于http协议的Melux掌静脉模组

热门文章

  1. java,jxl.jar,如何让Excel表格设置密码
  2. ssm+JSP计算机毕业设计远程心电诊断系统q97tp【源码、程序、数据库、部署】
  3. 华为的全局复制怎么用不了了_史上最强大复制神器>全局复制来了
  4. Sublime内网安装插件教程
  5. 支付宝统一下单接口的接入(1)
  6. import torchaudio UserWarning: No audio backend is available.
  7. 【Vue】关于开发中本地图片加载失败的经验总结
  8. 理论【5】基带、射频,到底是干什么用的?(11)
  9. 数据库概论(王珊 萨师煊著)第5版 预习笔记
  10. 没准考证怎样查询计算机等级考试成绩