Spring Boot核心原理-自动配置

之前在公司内部推行spring boot时,有同事跟我提到过,感觉换到spring boot这个框架后,好处是小白也能迅速上手写业务代码了。但是呢,这种情况下新手很容易写得云里雾里的,因为完全不知道背后的原理是什么,相对比在学习spring时需要深刻理解ioc、搞一堆繁琐的配置来说,的确缺少了被迫跳出舒适区去学习一些原理的过程,那么今天就讲讲,为什么spring boot能够如此简单的让我们迅速上手。

继续阅读Spring Boot核心原理-自动配置

tomcat 7.x查询乱码

做过爬虫,所以看出来是gbk乱码..

7.x和8.x的的默认配置应该不同,8,x没有这个问题

配置tomcat / conf/ server.xml

所有涉及connector的加上资源定位符的编码 URIEncoding=”UTF-8″ ,比如:

<Connector port=”7080″ protocol=”HTTP/1.1″ connectionTimeout=”20000″ redirectPort=”7443″ URIEncoding=”UTF-8″ />

Mac安装maven : org/apache/maven/cli/MavenCli : Unsupported major.minor version 51.0

在Mac上使用maven,折腾了一会才安装成功,这里作下安装记录:

1、下载maven,地址:http://maven.apache.org/download.cgi

下载后,解压到任意的目录下,这里我放到 opt/ 下,名字为apache-maven-3.3.3

2、配置环境变量

使用命令,直接打开bash_profile: vi ~/.bash_profile ,添加以下几个变量

export MAVEN_HOME=opt/apache-maven-3.3.3

export PATH=$MAVEN_HOME/bin:$PATH

export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_40.jdk/Contents/Home

注:我这里导入了java_home的路径,主要是mac自带的Java版本比较低,之前安装了1.8的版本,但却没有声明java_home,在没申明之前,运行mvn报

Exception in thread “main” java.lang.UnsupportedClassVersionError: org/apache/maven/cli/MavenCli : Unsupported major.minor version 51.0,      错误。 (官网建议也是1.7以上的jdk)

3、使环境变量生效,使用命令“source .bash_profile”

4、测试,在terminal窗口输入命令“mvn -version“,查看打印信息,如果显示正常的maven版本即安装成功

Tomcat7.x下出现The requested resource(/)is not available

TTP Status 404 -/web-inf/pages/sqcz.jsp

typeStatus report

message/web-inf/pages/sqcz.jsp

descriptionThe requested resource (/web-inf/pages/sqcz.jsp) is not available.

Apache Tomcat/6.0.18

 

反复查看了类和配置文件,都没有发现什么错误,从网上搜索解决该问题的办法,后来发现Tomcat7.x与 Tomcat5.x的默认配置有一些不同(至于其他的配置有何不同暂未研研),Tomcat6以上默认是关闭了目录浏览功能的,这个主要是出于安全性的 考虑。

 

对应的配置选项在apache-tomcat-7.x/conf/web.xml配置如下:
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

 

解决方法:
将其中的
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
设置由false改为true,即可开启目录浏览功能

win7 jdk + eclipse + ant + android sdk + phonegap corvoda

帮朋友做一个基于android的玩意儿交差…自然想到用前端方法写了之后封装,比较快..

本想以后来鼓捣的,现在就当提前了..

现在在实习,只能利用休息时间来做做。

实习的时候带的mac出来的,在虚拟机下操作真心还是比不上win7真机..

分辨率看的各种不爽。。好了,不废话了。。来点实际的。

1. 安装jdk,之前我有篇在java分类下的帖子专门说了怎么安装jdk然后配置环境。可以先看下那篇文章。

2. eclipse – ANT,我下的luna,虽然其实只是用来装下ant。。

google的源基本用不了,各位还是离线安装吧,

其实操作还是一样,只是我们不用google那个source,直接先在网上找好jar拖进去

操作:帮助-安装新文件-添加(名称随意,位置通过 ARCHIVE-找到你下载的antxxx.zip)

8A5C0C39-D762-4F2B-9A3C-E24BB4BBCA77

 

 

3. 怎么搭建安卓环境(这个将重点说,尽量说明白,不然很坑..)

需要Android\android-sdk目录下的:

onepic

platforms, platform-tools, build-tools, system-images这几个目录下的包版本名一致,

其中platform-tools下面直接放你用的版本文件解压后的所有内容,不要加任何目录。

build-tools下的文件夹名以 19.0.1 这样的格式命名,这个也是我看一个寻找build文件的配置里面看见的,它是以这样的方式来查找的。

EXTRAS里面放support包.

workspace\phonegap\XXX(你生成的安卓项目名字)\platforms\android下的project.properties和workspace\phonegap\xxx\platforms\android\CordovaLib打开之后检查target的属性看下版本是否正确。

 

4. phonegap + cordova

这个很简单,网上都有很多教程,先装node.js,去官网就行。

然后进入命令行 (确定npm在path中), 分别:

npm install-g phonegap

npm install-g cordova

当然可能遇到安装失败,多半是源的问题,可以通过:

npm config set registry https://registry.npm.taobao.org 
npm info underscore (如果上面配置正确这个命令会有字符串response切换到淘宝的源,再安装,一般就没有问题了。

5.第一个cordova生成的apk文件
命令行cd到你想设定的工作目录,运行:

cordova create hello com.example.hello HelloWorld

运行:cd hello

运行:cordova platform add android 之后可以看到hello/platforms/android里出现Android项目。

运行:cordova build android 就会在/android/build/apk/outputs里面看到你导出的apk项目。

可能会遇到问题,就需要在第3步中设置好build-tools下面的命名规则,然后cordova生成的文件下有两个properties文件,把它们中间的 Android Target改为你sdk manager中可见到的最高的level即可。

mark一个, hibernate向mysql插入数据时中文乱码问题

实战岀经验.. 跟小学弟一起成长,虽然不是我做的,也学到了。

将hibernate中connection.url的内容改为:

<property name=”connection.url”><![CDATA[jdbc:mysql://localhost:3306/yzsp?useUnicode=true&characterEncoding=utf8]]></property>

 

ps :以前php写后台的时候也遇到过这个问题,当时的解决方法是连接数据库后 加上 mysql_set_charset(‘utf8’);

Java学习笔记(二)—Servlet

Servlet学习笔记

Servlet 任务
Servlet 执行以下主要任务:

读取客户端(浏览器)发送的显式的数据。这包括网页上的 HTML 表单,或者也可以是来自 applet 或自定义的 HTTP 客户端程序的表单。
读取客户端(浏览器)发送的隐式的 HTTP 请求数据。这包括 cookies、媒体类型和浏览器能理解的压缩格式等等。
处理数据并生成结果。这个过程可能需要访问数据库,执行 RMI 或 CORBA 调用,调用 Web 服务,或者直接计算得出对应的响应。
发送显式的数据(即文档)到客户端(浏览器)。该文档的格式可以是多种多样的,包括文本文件(HTML 或 XML)、二进制文件(GIF 图像)、Excel 等。
发送隐式的 HTTP 响应到客户端(浏览器)。这包括告诉浏览器或其他客户端被返回的文档类型(例如 HTML),设置 cookies 和缓存参数,以及其他类似的任务。

Servlet 生命周期

Servlet 生命周期可被定义为从创建直到毁灭的整个过程。以下是 Servlet 遵循的过程:

Servlet 通过调用 init () 方法进行初始化。
Servlet 调用 service() 方法来处理客户端的请求。
Servlet 通过调用 destroy() 方法终止(结束)。
最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。

init() 方法
init 方法被设计成只调用一次。它在第一次创建 Servlet 时被调用,在后续每次用户请求时不再调用。因此,它是用于一次性初始化,就像 Applet 的 init 方法一样。

Servlet 创建于用户第一次调用对应于该 Servlet 的 URL 时,但是您也可以指定 Servlet 在服务器第一次启动时被加载。

当用户调用一个 Servlet 时,就会创建一个 Servlet 实例,每一个用户请求都会产生一个新的线程,适当的时候移交给 doGet 或 doPost 方法。init() 方法简单地创建或加载一些数据,这些数据将被用于 Servlet 的整个生命周期。

init 方法的定义如下:

public void init() throws ServletException {
// 初始化代码…
}
service() 方法
service() 方法是执行实际任务的主要方法。Servlet 容器(即 Web 服务器)调用 service() 方法来处理来自客户端(浏览器)的请求,并把格式化的响应写回给客户端。

每次服务器接收到一个 Servlet 请求时,服务器会产生一个新的线程并调用服务。service() 方法检查 HTTP 请求类型(GET、POST、PUT、DELETE 等),并在适当的时候调用 doGet、doPost、doPut,doDelete 等方法。

下面是该方法的特征:

public void service(ServletRequest request,
ServletResponse response)
throws ServletException, IOException{
}
service() 方法由容器调用,service 方法在适当的时候调用 doGet、doPost、doPut、doDelete 等方法。所以,您不用对 service() 方法做任何动作,您只需要根据来自客户端的请求类型来重载 doGet() 或 doPost() 即可。

doGet() 和 doPost() 方法是每次服务请求中最常用的方法。下面是这两种方法的特征。

doGet() 方法
GET 请求来自于一个 URL 的正常请求,或者来自于一个未指定 METHOD 的 HTML 表单,它由 doGet() 方法处理。

public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// Servlet 代码
}
doPost() 方法
POST 请求来自于一个特别指定了 METHOD 为 POST 的 HTML 表单,它由 doPost() 方法处理。

public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// Servlet 代码
}
destroy() 方法
destroy() 方法只会被调用一次,在 Servlet 生命周期结束时被调用。destroy() 方法可以让您的 Servlet 关闭数据库连接、停止后台线程、把 Cookie 列表或点击计数器写入到磁盘,并执行其他类似的清理活动。

在调用 destroy() 方法之后,servlet 对象被标记为垃圾回收。destroy 方法定义如下所示:

public void destroy() {
// 终止化代码…
}

部署servlet
由于在MYECLIPESE中已经配置好了Tomcat,会自动部署,并且生成的servlet也会在Web.xml中自动配置好,我就不说部署的事情了。

Servlet表单方法
首先我想Get和post方法大家都不陌生,get一般用于查询,通过url传值,比如www.qq.com/hello?key1=value1 这时候我们就传了一个名称为key1值为value1的变量给www.qq.com/hello的页面

使用Servlet读取表单数据

Servlet 处理表单数据,这些数据会根据不同的情况使用不同的方法自动解析:

getParameter():您可以调用 request.getParameter() 方法来获取表单参数的值。
getParameterValues():如果参数出现一次以上,则调用该方法,并返回多个值,例如复选框。
getParameterNames():如果您想要得到当前请求中的所有参数的完整列表,则调用该方法。
前端如果是表单的,输入内容的变量名写在name=”somename”中。

Servlet 客户端 HTTP 请求

头信息 描述
Accept 这个头信息指定浏览器或其他客户端可以处理的 MIME 类型。值 image/pngimage/jpeg 是最常见的两种可能值。
Accept-Charset 这个头信息指定浏览器可以用来显示信息的字符集。例如 ISO-8859-1。
Accept-Encoding 这个头信息指定浏览器知道如何处理的编码类型。值 gzipcompress 是最常见的两种可能值。
Accept-Language 这个头信息指定客户端的首选语言,在这种情况下,Servlet 会产生多种语言的结果。例如,en、en-us、ru 等。
Authorization 这个头信息用于客户端在访问受密码保护的网页时识别自己的身份。
Connection 这个头信息指示客户端是否可以处理持久 HTTP 连接。持久连接允许客户端或其他浏览器通过单个请求来检索多个文件。值 Keep-Alive 意味着使用了持续连接。
Content-Length 这个头信息只适用于 POST 请求,并给出 POST 数据的大小(以字节为单位)。
Cookie 这个头信息把之前发送到浏览器的 cookies 返回到服务器。
Host 这个头信息指定原始的 URL 中的主机和端口。
If-Modified-Since 这个头信息表示只有当页面在指定的日期后已更改时,客户端想要的页面。如果没有新的结果可以使用,服务器会发送一个 304 代码,表示 Not Modified 头信息。
If-Unmodified-Since 这个头信息是 If-Modified-Since 的对立面,它指定只有当文档早于指定日期时,操作才会成功。
Referer 这个头信息指示所指向的 Web 页的 URL。例如,如果您在网页 1,点击一个链接到网页 2,当浏览器请求网页 2 时,网页 1 的 URL 就会包含在 Referer 头信息中。
User-Agent 这个头信息识别发出请求的浏览器或其他客户端,并可以向不同类型的浏览器返回不同的内容。

 

读取 HTTP 头的方法

下面的方法可用在 Servlet 程序中读取 HTTP 头。这些方法通过 HttpServletRequest 对象可用。

序号 方法 & 描述
1 Cookie[] getCookies()
返回一个数组,包含客户端发送该请求的所有的 Cookie 对象。
2 Enumeration getAttributeNames()
返回一个枚举,包含提供给该请求可用的属性名称。
3 Enumeration getHeaderNames()
返回一个枚举,包含在该请求中包含的所有的头名。
4 Enumeration getParameterNames()
返回一个 String 对象的枚举,包含在该请求中包含的参数的名称。
5 HttpSession getSession()
返回与该请求关联的当前 session 会话,或者如果请求没有 session 会话,则创建一个。
6 HttpSession getSession(boolean create)
返回与该请求关联的当前 HttpSession,或者如果没有当前会话,且创建是真的,则返回一个新的 session 会话。
7 Locale getLocale()
基于 Accept-Language 头,返回客户端接受内容的首选的区域设置。
8 Object getAttribute(String name)
以对象形式返回已命名属性的值,如果没有给定名称的属性存在,则返回 null。
9 ServletInputStream getInputStream()
使用 ServletInputStream,以二进制数据形式检索请求的主体。
10 String getAuthType()
返回用于保护 Servlet 的身份验证方案的名称,例如,”BASIC” 或 “SSL”,如果JSP没有受到保护则返回 null。
11 String getCharacterEncoding()
返回请求主体中使用的字符编码的名称。
12 String getContentType()
返回请求主体的 MIME 类型,如果不知道类型则返回 null。
13 String getContextPath()
返回指示请求上下文的请求 URI 部分。
14 String getHeader(String name)
以字符串形式返回指定的请求头的值。
15 String getMethod()
返回请求的 HTTP 方法的名称,例如,GET、POST 或 PUT。
16 String getParameter(String name)
以字符串形式返回请求参数的值,或者如果参数不存在则返回 null。
17 String getPathInfo()
当请求发出时,返回与客户端发送的 URL 相关的任何额外的路径信息。
18 String getProtocol()
返回请求协议的名称和版本。
19 String getQueryString()
返回包含在路径后的请求 URL 中的查询字符串。
20 String getRemoteAddr()
返回发送请求的客户端的互联网协议(IP)地址。
21 String getRemoteHost()
返回发送请求的客户端的完全限定名称。
22 String getRemoteUser()
如果用户已通过身份验证,则返回发出请求的登录用户,或者如果用户未通过身份验证,则返回 null。
23 String getRequestURI()
从协议名称直到 HTTP 请求的第一行的查询字符串中,返回该请求的 URL 的一部分。
24 String getRequestedSessionId()
返回由客户端指定的 session 会话 ID。
25 String getServletPath()
返回调用 JSP 的请求的 URL 的一部分。
26 String[] getParameterValues(String name)
返回一个字符串对象的数组,包含所有给定的请求参数的值,如果参数不存在则返回 null。
27 boolean isSecure()
返回一个布尔值,指示请求是否使用安全通道,如 HTTPS。
28 int getContentLength()
以字节为单位返回请求主体的长度,并提供输入流,或者如果长度未知则返回 -1。
29 int getIntHeader(String name)
返回指定的请求头的值为一个 int 值。
30 int getServerPort()
返回接收到这个请求的端口号。

 

设置 HTTP 状态代码的方法

下面的方法可用于在 Servlet 程序中设置 HTTP 状态码。这些方法通过 HttpServletResponse 对象可用。

序号 方法 & 描述
1 public void setStatus ( int statusCode )
该方法设置一个任意的状态码。setStatus 方法接受一个 int(状态码)作为参数。如果您的反应包含了一个特殊的状态码和文档,请确保在使用 PrintWriter 实际返回任何内容之前调用 setStatus。
2 public void sendRedirect(String url)
该方法生成一个 302 响应,连同一个带有新文档 URL 的 Location 头。
3 public void sendError(int code, String message)
该方法发送一个状态码(通常为 404),连同一个在 HTML 文档内部自动格式化并发送到客户端的短消息。

 

HTTP 状态码实例

下面的例子把 407 错误代码发送到客户端浏览器,浏览器会显示 “Need authentication!!!” 消息。

// 导入必需的 java 库
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;

// 扩展 HttpServlet 类
public class showError extends HttpServlet {
 
  // 处理 GET 方法请求的方法
  public void doGet(HttpServletRequest request,
                    HttpServletResponse response)
            throws ServletException, IOException
  {
      // 设置错误代码和原因
      response.sendError(407, "Need authentication!!!" );
  }
  // 处理 POST 方法请求的方法
  public void doPost(HttpServletRequest request,
                     HttpServletResponse response)
      throws ServletException, IOException {
     doGet(request, response);
  }
}

在web.xml中设置初始化参数

在servlet标签中加入 <init-param> <param-name>password</param-name> <param-value>1221</param-value></init-param>
但这个只能该SERVLET使用,如果想让所有的SERVLET都可以访问到这个参数,使用上下文参数(Context Param)。直接放在Web.xml中
<context-param>
<param-name>password</param-name> <param-value>1221</param-value>
</context-param>
资源注射(@Resource)
@Resource(name="messageNameInWebXml")
private String message;
使用@resource标注字符串变量message,表示message的值会在servlet运行时动态注入。

Servlet异常处理

当一个 Servlet 抛出一个异常时,Web 容器在使用了 exception-type 元素的 web.xml 中搜索与抛出异常类型相匹配的配置。

在 web.xml 中使用 error-page 元素来指定对特定异常 或 HTTP 状态码 作出相应的 Servlet 调用。

假设,有一个 ErrorHandler 的 Servelt 在任何已定义的异常或错误出现时被调用。以下将是在 web.xml 中创建的项。

<!-- servlet 定义 -->
<servlet>
        <servlet-name>ErrorHandler</servlet-name>
        <servlet-class>ErrorHandler</servlet-class>
</servlet>
<!-- servlet 映射 -->
<servlet-mapping>
        <servlet-name>ErrorHandler</servlet-name>
        <url-pattern>/ErrorHandler</url-pattern>
</servlet-mapping>

<!-- error-code 相关的错误页面 -->
<error-page>
    <error-code>404</error-code>
    <location>/ErrorHandler</location>
</error-page>
<error-page>
    <error-code>403</error-code>
    <location>/ErrorHandler</location>
</error-page>

<!-- exception-type 相关的错误页面 -->
<error-page>
    <exception-type>
          javax.servlet.ServletException
    </exception-type >
    <location>/ErrorHandler</location>
</error-page>

<error-page>
    <exception-type>java.io.IOException</exception-type >
    <location>/ErrorHandler</location>
</error-page>

如果想对所有的异常有一个通用的错误处理程序,那么应该定义下面的 error-page,而不是为每个异常定义单独的 error-page 元素:

<error-page>
    <exception-type>java.lang.Throwable</exception-type >
    <location>/ErrorHandler</location>
</error-page>

请求属性 – 错误/异常

以下是错误处理的 Servlet 可以访问的请求属性列表,用来分析错误/异常的性质。

序号 属性 & 描述
1 javax.servlet.error.status_code
该属性给出状态码,状态码可被存储,并在存储为 java.lang.Integer 数据类型后可被分析。
2 javax.servlet.error.exception_type
该属性给出异常类型的信息,异常类型可被存储,并在存储为 java.lang.Class 数据类型后可被分析。
3 javax.servlet.error.message
该属性给出确切错误消息的信息,信息可被存储,并在存储为 java.lang.String 数据类型后可被分析。
4 javax.servlet.error.request_uri
该属性给出有关 URL 调用 Servlet 的信息,信息可被存储,并在存储为 java.lang.String 数据类型后可被分析。
5 javax.servlet.error.exception
该属性给出异常产生的信息,信息可被存储,并在存储为 java.lang.Throwable 数据类型后可被分析。
6 javax.servlet.error.servlet_name
该属性给出 Servlet 的名称,名称可被存储,并在存储为 java.lang.String 数据类型后可被分析。

 

Servlet Cookies

通过 Servlet 设置 Cookies

通过 Servlet 设置 Cookies 包括三个步骤:

(1) 创建一个 Cookie 对象:您可以调用带有 cookie 名称和 cookie 值的 Cookie 构造函数,cookie 名称和 cookie 值都是字符串。

Cookie cookie = new Cookie("key","value");

请记住,无论是名字还是值,都不应该包含空格或以下任何字符:

[ ] ( ) = , " / ? @ : ;

(2) 设置最大生存周期:您可以使用 setMaxAge 方法来指定 cookie 能够保持有效的时间(以秒为单位)。下面将设置一个最长有效期为 24 小时的 cookie。

cookie.setMaxAge(60*60*24);

(3) 发送 Cookie 到 HTTP 响应头:您可以使用 response.addCookie 来添加 HTTP 响应头中的 Cookies,如下所示:

response.addCookie(cookie);

Servlet Cookies 方法

以下是在 Servlet 中操作 Cookies 时可使用的有用的方法列表。

序号 方法 & 描述
1 public void setDomain(String pattern)
该方法设置 cookie 适用的域,例如 w3cschool.cc。
2 public String getDomain()
该方法获取 cookie 适用的域,例如 w3cschool.cc。
3 public void setMaxAge(int expiry)
该方法设置 cookie 过期的时间(以秒为单位)。如果不这样设置,cookie 只会在当前 session 会话中持续有效。
4 public int getMaxAge()
该方法返回 cookie 的最大生存周期(以秒为单位),默认情况下,-1 表示 cookie 将持续下去,直到浏览器关闭。
5 public String getName()
该方法返回 cookie 的名称。名称在创建后不能改变。
6 public void setValue(String newValue)
该方法设置与 cookie 关联的值。
7 public String getValue()
该方法获取与 cookie 关联的值。
8 public void setPath(String uri)
该方法设置 cookie 适用的路径。如果您不指定路径,与当前页面相同目录下的(包括子目录下的)所有 URL 都会返回 cookie。
9 public String getPath()
该方法获取 cookie 适用的路径。
10 public void setSecure(boolean flag)
该方法设置布尔值,表示 cookie 是否应该只在加密的(即 SSL)连接上发送。
11 public void setComment(String purpose)
该方法规定了描述 cookie 目的的注释。该注释在浏览器向用户呈现 cookie 时非常有用。
12 public String getComment()
该方法返回了描述 cookie 目的的注释,如果 cookie 没有注释则返回 null。

通过 Servlet 读取 Cookies

要读取 Cookies,您需要通过调用 HttpServletRequestgetCookies( ) 方法创建一个 javax.servlet.http.Cookie 对象的数组。然后循环遍历数组,并使用 getName() 和 getValue() 方法来访问每个 cookie 和关联的值。

Cookie[] cookies = request.getCookies();
if(cookies != null){
 for (int i = 0; i < cookies.length; i++){
            cookie = cookies[i];
            out.print("名称:" + cookie.getName( ) + ",");
            out.print("值:" + cookie.getValue( )+" <br/>");
         }
}

Java学习笔记(一)-包

在一个正常的Java项目中,我们往往需要编写不止一个.java程序,最终的Java产品包括了所有的Java程序。因此,Java需要解决组织Java程序的问题。包(package)的目的就是为了更好的组织Java程序。

包的建立

包的建立非常简单。我们只用在Java程序的开始加入package就可以了。我们以Btest类为例,将它放入包中:

package com.chingzhu.test;

public class Btest {
	public static void main(String args[]){
		YourCup tea = new YourCup();
		tea.addWater(10);
		tea.drinkWater(2);
		System.out.println(tea.getWater());
		tea.drinkLikesuper(2);
		System.out.println(tea.getWater());
		tea.dropWater();
		System.out.println(tea.getWater());
	}
}

上面的第一行语句

package com.chingzhu.test;

表示该程序在com.chingzhu.test包中。com.chingzhu表示包作者的域名 。Java要求包要有域名前缀,以便区分不同作者。test为进一步的本地路径名。com.chingzhu.test共同构成了包的名字。

包为Java程序提供了一个命名空间(name space)。一个Java类的完整路径由它的包和类名共同构成,比如com.chingzhu.test.Btest。相应的Btest.java程序要放在com/chingzhu/test/下。类是由完整的路径识别的,所以不同的包中可以有同名的类,Java不会混淆。比如com.chingzhu.test.Btest和com.chingzhu.test.Atest是两个不同的类。

再看一个细节。Btest类是public的,其构造方法也是public的,所以任意其他对象都可以调用该类。我们之前说过,一个Java文件中只能有一个public的类,该类要去.java文件同名。一个类可以没有public关键字,它实际上也表示一种权限: 该类在它所在的包中可见。也就是说,包中的其他Java程序可以访问该类。这是Java中的默认访问权限。

同样,对象的成员也可以是默认权限(包中可见)。比如我们去掉方法前面的public关键字。

包的调用

我们只需要将Btest.java编译的Btest.class放入相应的文件夹就可以了。比如,我将Human.class放入com/chingzhu/test/中。实际上,你也可以把.java文件放入相应路径,Java会在使用时自动编译。

如果整个包(也就是com文件夹)位于当前的工作路径中,那么不需要特别的设置,就可以使用包了,比如下面的TestAgain.java:

import com.chingzhu.test.*;

public class TestAgain

{

    public static void main(String[] args)

    {

        Btest a = new Btest();

    }

}

import用于识别路径。利用import语句,我们可以引入相应路径下的类。*表示引入test文件夹下的所有类。在TestAgain中,我们直接使用了Btest类。

我们也可以提供类的完整的路径。这可以区分同名但不同路径的类,比如:

public class TestAgain

{

    public static void main(String[] args)

    {

        com.chingzhu.test.Btest a =

                  new com.chingzhu.test.Btest();

    }

}

由于我们提供了完整的类路径,所以不需要使用import语句。

如果包没有放在当前工作路径下,我们在使用包时,需要通知Java。比如,我们将包放在/home/chingzhu/javapackage中,这样Btest.class位于/home/chingzhu/javapackage/com/chingzhu/test/Btest.class,而我们的工作路径为/home/chingzhu。这样,包就无法被找到。一个方法是在使用javacjava时,用-classpath说明包所在的文件夹路径,比如:

$javac -classpath /home/chingzhu/javapackage:. TestAgain.java

$java -classpath /home/chingzhu/javapackage:. TestAgain

就是从/home/chingzhu/javapackage和工作路径(.)中寻找包。Java可以从/home/chingzhu/javapackage中可以找到Btest类,从.中可以找到TestAgain类。

另外也可以设置系统的CLASSPATH环境变量,将上述路径加入到该变量中,而不用每次都键入-classpath选项。

类似于包的机制在其他语言中也很常见,比如Python中的import机制。它们都是为了更好的组织和使用已有的程序。利用包,我们可以比较容易的拓展Java程序,使用已有的Java程序库。注意到,包管理的是.class文件。Java号称一次编译,处处运行 (Compile Once, run anywhere).class文件可以在任意装有Java虚拟机(JVM, Java Virtual Machine)的平台上运行,这帮助我们克服了系统差异造成的程序移植困难。

系统之间的差异可以非常大。如果我们用C语言编写程序,需要将源程序在各个平台上重新编译,以适应不同的硬件条件。 Java虚拟机衔接了平台和Java宇宙,它构成了硬件和编程逻辑的中间层。JVM隐藏了硬件差异,提供给程序员一个标准Java宇宙。而.class文件可以看做这个 Java宇宙中流通的通货。在JVM的基础设施下,加上包的管理辅助,Java程序实现了良好的可移植性 (portability)