第三章 JavaScript和Java语言
2011-07-04 09:34 Rollen Holt 阅读(5295) 评论(0) 编辑 收藏 举报第三章 JavaScript和Java语言
[本章导读]
为什么学习JSP之前必须掌握JavaScript和Java语言?因为JSP是基于Java语言的,JSP是Java的网络应用,所以理所当然要熟悉Java语言,而JavaScript是一种基于对象的脚本语言,主要负责客户端的界面控制等工作,能让你在开发过程中事半功倍,而且减轻服务器负荷。还能通过采用事件驱动机制,使其能在客户端(浏览器)与用户实现大量的交互,还能创建出惊人的特效。本章先介绍JavaScript的基本语法,然后介绍Java语言的具体特性。
3.1 JavaScript
JavaScript是一种简洁的、面向对象的、跨平台的描述语言,和VBScript一样,它可以被嵌入到HTML文件中,直接被浏览器执行,从而产生多种多样的动态网页效果。
3.1.1 JavaScript概述
JavaScript和Java很类似,但并不相同。Java是一种比JavaScript复杂得多的语言,由Sun公司开发;而JavaScript则是简单而小巧的语言,由Netscape公司推出。
表3.1 JavaScript与Java的对照
JavaScript |
Java |
在用户端(client)解释执行,无须编译 |
运行前需在服务器端编译好 |
基于对象:一般使用内建对象,没有类或继承的语法 |
面向对象:对象导向、对象类别、对象继承等 |
嵌入在HTML文件中 |
通过HTML调用,没有嵌入在HTML文件中 |
变量无须说明类型(弱类型) |
变量必须说明类型(强类型) |
动态连接:对象的参考在运行阶段完成 |
静态连接:对象的参考必须在编译时完成 |
安全性:不能写入硬盘 |
安全性:不能写入硬盘 |
1.JavaScript的特点
JavaScript是一种基于对象(Object Based)和事件驱动(Event Driven)并具有安全性能的脚本语言。它弥补了HTML语言的缺陷,是Java与HTML折衷的选择,具有以下几个基本特点:
l 基于对象:它能自己创建或运用脚本环境内建对象。
l 简单性:基本语法结构与其他面向对象的高级语言类似,但舍弃了许多复杂特性;语法要求不是很严格,方便书写;与HTML标识结合在一起,在运行过程中被逐行解释执行。
l 安全性:JavaScript不允许访问本地硬盘,不能将数据存入服务器,不允许修改或删除网络文档,只能通过浏览器实现信息浏览或动态交互,从而有效地保证了数据的安全性。
l 动态性:JavaScript采用事件驱动的方式直接响应用户的操作。
l 跨平台:JavaScript依赖于浏览器,与操作系统无关,只要浏览器支持JavaScript就可正确执行。
2.JavaScrip运行和编辑环境
运行环境:Netscape Navigator 3.0以上或Internet Explorer 4.0以上。
编辑环境:任何可以编辑HTML文档的文本编辑器(Notepad、Wordpad等)或专门的网页编辑器(FrontPage、Dreamweaver等)。
3.在HTML中嵌入JavaScript脚本
在HTML中使用JavaScript时,应将JavaScript程序放在<script></script>标记之间。看看下面这个输出“Hello,World!” 的程序,该程序的运行结果如图3.1所示,文件名为0301.htm。
【例3.1】 <html><head><title>我的第一个JavaScript程序</title></head>
<body>
<Script Language="JavaScript">
document.write("Hello, World!")
</Script>
</body></html>
图3.1 一个简单的JavaScript程序
Script标记可放在HTML文档的head或body中,但通常建议把Script标志放于文档头部,以使文档中所有的JavaScript定义均在显示文档的主体部分之前。
Script标记开始时,Language="JavaScript"指定了Script的属性Language为JavaScript,即脚本语言采用JavaScript。脚本中惟一的语句的功能是:使用document对象的write方法向当前的document对象(即当前的HTML文档)写出一个字符串“Hello, World!”。
在HTML中加入已有的JavaScript脚本文件,可以使用Script标记的src属性来加入一个已存在的JavaScript脚本文件,从而实现了代码的重用。例如:
<Script Language="JavaScript" src="program.js"> //把program.js中的程序包含进来
</Script>
此处的program.js指明了一个JavaScript程序文件,文件的扩展名应为.js。
上例中若program.js的内容如下,则可等同于例11.1中<script></script>间的脚本程序。
document.write("Hello, World! ") //输出Hello, World!
3.1.2 JavaScript语言结构
1.数据和运算符
JavaScript有6种数据类型。如表3.2所示。
表3.2 JavaScript的数据类型
保留字 |
类型名 |
说明 |
备注 |
|
float |
数值 |
浮点型 |
整数可以为正数、0或者负数 |
如:365,0,-168 |
int |
整型 |
浮点数可使用实数的普通形式或科学计数法 |
如:3.14159,1.26E-3 |
|
string |
字符串类型 |
字符串是用单引号或双引号来说明的(使用单引号来输入包含引号的字符串) |
如:'Hello World!'或"Beijing 2008" |
|
boolean |
布尔型 |
可能的值有true和false |
不能用1和0 |
|
undefined |
不定类型 |
指变量被创建但未被赋值时所具有的值 |
|
|
null |
空 类 型 |
没有任何值,什么也不表示 |
|
|
object |
对象类型 |
|
在JavaScript中变量用来存放脚本中的值,这样在需要用这个值的地方就可以用变量来代表,一个变量可以存放数值(整数或实数)、文本等。
JavaScript是一种对数据类型变量要求不太严格的语言,所以不必声明每一个变量的类型,变量声明尽管不是必须的,但在使用变量之前先进行声明是一种好的习惯。可以使用var语句来进行变量声明。如:
var men = true; // men 中存储的值为 Boolean 类型
但变量命名必须遵循以下规则:
(1)变量名必须以字母、下划线_或美元符$开始。
(2)变量名可以包含字母、数字、下划线或美元符。
(3)变量名的长度是任意的。
(4)JavaScript区分大小写,因此MyVar、myvar、Myvar、myVar是不一样的。
(5)变量名不能是保留字,JavaScript的保留字参见表3.3。
表3.3 JavaScript保留字一览
abstract |
extends |
Int |
super |
boolean |
false |
Interface |
switch |
break |
final |
Long |
synchronized |
byte |
finally |
Native |
this |
case |
float |
New |
throw |
catch |
for |
Null |
throws |
char |
function |
Package |
transient |
class |
goto |
Private |
true |
const |
if |
Protected |
try |
continue |
implements |
Public |
var |
default |
import |
Return |
void |
do |
in |
Short |
while |
double |
instanceof |
Static |
with |
else |
|
|
|
保留字不可用作变量名、函数名、对象名等;表中某些保留字暂未使用,留待以后扩展。
运算符是完成操作的一系列符号,在JavaScript中有算术运算符、比较运算符、逻辑布尔运算符、字符串运算符、位操作运算符、赋值运算符、条件运算符等。
(1)算术运算符。TavaSeript中的算术运算符如表3.4所示。
表3.4 JavaScript的算术运算符
+(加)、-(减)、*(乘)、 |
双目 |
-(取反)、++(自增1)、--(自减1) |
单目 |
(2)比较运算符。比较操作符用于测试一个值是否大于、等于或小于另一个值,并按比较的条件成立与否返回一个布尔值(true或false)。JavaScript共有6个比较运算符,如表3.5所示。
表3.5 JavaScript的比较运算符
< |
小于 |
<= |
小于等于 |
> |
大于 |
>= |
大于等于 |
== |
等于 |
!= |
不等于 |
(3)逻辑运算符。逻辑操作符把多个比较运算组织起来,形成复合条件,并进行测试,以决定复杂的条件是否为真。JavaScript中使用了3个布尔逻辑运算符,如表3.6所示。
表3.6 JavaScript的逻辑运算符
&& |
逻辑与 |
|| |
逻辑或 |
! |
取反 |
(4)字符串运算符。字符串操作符用于比较和连接字符串。字符串比较操作符= =和!=可以用来测试两个字符串是否相等(仅当两个字符串中每个字符都相等),而字符串连接操作符“+”可用来连接两个字符串。
(5)位运算符。位运算符用于对数值的位进行操作,JavaScript中的位运算符见表3.7。
表3.7 JavaScript位运算符
|(按位或)、&(按位与)、^(按位异或) <<(左移)、>>(带符号右移)、>>>(填充零右移) |
双目 |
~(取补) |
单目 |
(6)赋值运算符。简单赋值表达式将赋值符(=)右边表达式的值存放到赋值符左边的变量中去。而复合赋值表达式混合了其他操作(算术操作、位操作)和赋值操作,如:
total += price 等同于 total = total + price
total /= count 等同于 total = total / count
JavaScript中的赋值运算符如表3.8所示。
表3.8 JavaScript的赋值运算符
= |
简单赋值 |
+= |
递增 |
-= |
递减 |
*= |
自乘后赋值 |
/= |
自除后赋值 |
%= |
求余后赋值 |
&= |
与之后赋值 |
|= |
或之后赋值 |
^= |
异或之后赋值 |
<<= |
左移之后赋值 |
>>= |
带符号右移之后赋值 |
>>>= |
填充零右移之后赋值 |
(7)条件运算符。条件运算符来自C、C++和Java,其格式如下:
(条件)?expression1:expresion2
若条件为真,则条件表达式的结果取expression1的值,否则取expresion2的值。
2.语句和程序控制
语句组成JavaScript程序,并控制程序流。JavaScript所提供的语句分为以下几大类:
1)一般语句
(1)数据声明语句。声明变量的语法如下:
var 变量名[=初始值]
例:var computer=32 //定义computer是一个变量,且有初值为32
(2)赋值语句。由赋值表达式组成的语句。如days=365、months=12。
(3)注释语句。JavaScript使用和C++和Java相同的注释语句。
//:单行注释,从“//”开始到本行行尾都为注释。
/*....*/:多行注释,从“/*”开始到“*/”结束为注释。
2)选择结构
(1)if...else语句。if...else语句完成了程序流程块中的分支功能:如果其中的条件成立,则程序执行紧接着条件的语句或语句块;否则程序执行else中的语句或语句块。语法如下:
if (条件)
{
执行分支语句1
}
else
{
执行分支语句2
}
例:if (result == true)
{
response = "你答对了!"
}
else
{
response = "你错了!"
}
(2)switch语句。分支语句switch可以根据一个变量的不同值采取不同的处理方法。其语法如下:
switch (expression)
{
case label1: 语句串1;
case label2: 语句串2;
case label3: 语句串3;
...
default : 语句串3;
}
如果表达式取的值同程序中提供的任何一条语句都不匹配,将执行default中的语句。
3)循环结构
(1)for语句。其一般语法如下:
for (循环变量初始化; 循环变量结束条件; 循环变量自增/减变化)
{
循环体
}
只要循环的条件成立,循环体就被反复执行。
(2)while语句。while语句所控制的循环不断测试循环条件,如果条件成立,则执行循环体,直到条件不再成立。其语法如下:
while (循环条件)
{
循环体
}
(3)do-while语句。do-while语句类似于while语句,惟一的差别是条件检查放在循环末尾而不是循环开头,这样可保证括号内的语句至少执行一次。do while语句的语法如下:
do
{
循环体
}while(循环条件);
下面程序是分别用for、while、do-while语句来实现。
for (i=0; i<10; i++) { document.write(i+" }
|
i=0 while (i<10) { ++i document.write(i+" } |
i=0 do { ++i document.write(i+" } while(i<10); |
(4)break语句。break语句结束当前的各种循环,并执行循环语句的下一条语句。
(5)continue语句。continue语句结束当前的循环,跳过本次循环并马上开始下一个循环。
4)函数定义语句:function,return
函数必须先定义后使用,因此一般被放在HTML文档头中。函数定义的语法如下:
function 函数名(参数列表)
{
函数功能的实现部分
return 表达式 //return语句将表达式的值返回主调程序
}
其中:函数名是函数被调用时引用的名称;参数是函数被调用时接收传入数值的变量名。大括号中的语句是函数的执行语句。下面的函数计算参数的平方并返回给主调程序:
function square (x)
{ return x*x }
5)语句的注意事项
(1)多个语句可以放在同一行,只要每个语句之间用分号分开即可。
(2)分号是JavaScript的分行符,但不同行之间也可不用分号。
(3)较长的JavaScript语句可以由多行文本组成,不需要续行符。
(4)语句前可加标号语句确定执行程序的转移点。
3.1.3 JavaScript的事件驱动
虽然JavaScript程序可以在页面装入后立即运行,但是在大部分时候都是依靠事件的触发来运行。通过事件触发机制,JavaScript使Web页面得以和用户交互。
1.什么是事件
在JavaScript程序中,任何能引起JavaScript代码运行的操作,都称为事件(event)。事件是浏览器响应用户交互操作的一种机制,JavaScript的事件处理机制可以改变浏览器响应用户操作的方式,这样就开发出具有交互性,并易于使用的网页。
事件大多数是由Web用户触发的。普通的事件包括:页面元素上的单击(单选按钮、submit按钮、链接等)。位于HTML源文件中的JavaScript程序将经常被它们所触发。因此,必须学习都有哪些事件,如何监测并等待事件,如何调用事件处理器处理发生的事件。
浏览器自身的一些操作也可以产生事件。比如,当载入一个页面时,就会发生load事件,卸载一个页面时,就会发生unload事件等。
2.事件类型
每个事件都有一个可被引用的名字。常用事件如表3.9所示。
表3.9 用户与web页面交互时的常用事件
事件名 |
说明 |
Click |
当用户使用鼠标在超级链接或表单元素上单击时,产生该超级链接或表单元素的单击(click)事件。表单元素包括按钮、复选框、Reset和Submit按钮 |
Focus |
当用户单击鼠标或用Tab键激活某一表单元素时,产生该表单元素的聚焦(Focus)事件。注意,这与用户往元素中输入有所不同:Focus仅在表单元素被激活时出现 |
Blur |
与Focus文件相反,它发生在当前激活表单元素从激活状态变为非激活状态的时候。如果用户使用单击,或按Tab键,将Focus从当前元表单至其他非激活元素,或在页面的其他非激活区域单击,则产生该表单元素的Blur事件 |
Change |
当用户改变表单元素的原有状态(如在Input域的文本输入区输入或删除文字,在选择框中改变原有选项)后,将产生该表单元素的Change事件。需要注意的是:只有当被修改元素失去Focus时,该事件才会出现 |
MouseOver |
当鼠标指针位于链接的位置之上时,产生MouseOver事件。如:每当鼠标指针移至页内的某个链接上时,链接的URL地址会出现在状态行上 |
|
表3.9 用户与web页面交互时的常用事件(续表) |
事件名 |
说明 |
Select |
当用户在表单文本输入元素内选取一段文本时(按下并拖动鼠标左键,使文本高亮显示),会产生Select事件 |
Submit |
当用户单击表单元素的Submit按钮时,会产生Submit事件。注意:Submit事件在表单真正提交数据之前产生(像在<FORM>标记中定义的那样)。因此,该事件允许你在提交数据之前,进行计算和分析,从而可以根据计算和分析的结果决定是否采取进一步的行动 |
3.如何监测事件
对每个特定的页面元素(链接、表单等),都可以指定监视事件。监视事件的方法与定义该元素的其他属性一样,具体形式为:onEvent="JavaScript program"。下面是一个简单的例子。
在HTML文档,链接是这么定义的:
<A HREF="URL"> 这是一个链接 </A>
当用户浏览该页时,链接被以另一种颜色显示出来。如果用户单击,将转到指定的URL。
假设需要在鼠标移到链接的上方时,运行某个JavaScript程序。那么,需要一个MouseOver触发器。只要设置onMouseOver属性(attribute)为“JavaScript program”,把这一属性加入定义链接的标记:
<A HREF="URL" onMouseOver="JavaScript program"> 这是一个链接 </A>
这样在用户浏览该页时,当鼠标移到链接的上方,就会触发MouseOver事件,从而执行onMouseOver属性指定的“JavaScript program”程序。
4.如何调用事件处理器
事件监视器形如onEvent=" JavaScript program"。双引号中的部分用来说明触发后如何处理事件,被称为事件处理器,实际上是JavaScript程序代码。
双引号之间的事件处理器有两种基本形式:函数调用和直接代码。
(1)函数调用
函数调用是最常用也是最合适的事件处理器。这也是函数如此有用的原因所在。一个设计良好的Web页面,一般将函数在页面头部的<HEAD>部分进行定义。然后在Web页面的其余部分利用函数调用设置事件处理器。
如果以函数调用作为事件处理器,上面的例子可能变成这样:
<A HREF="URL" onMouseOver="myFunction(arguments)"> 这是一个链接 </A>
本例中,如果用户将鼠标指针置于链接之上时,myFunction(arguments)将被调用,其中arguments是函数myFunction()的参数列表。如果单击该链接,将进入URL所指向的网页。
(2)直接代码
除使用函数调用处,还可以通过直接在双引号间书写JavaScript代码来实现事件处理器。虽然多条语句的事件处理器应使用函数来实现,但在双引号之间写上整个程序也无所谓。不过有两条规则必须遵守。
1)各条语句间要用分号(;)分开。
2)不能使用双引号(")。双引号的出现意味着事件处理器定义的结束,故只能在需要引号的地方使用单引号(')。(在函数调用中传递参数时,也是如此。因此,如果要使用字符串作为函数参数,必须使用单引号。)
3)事件处理器里无法引用一个外部文件。但是可以通过在Web页面的<HEAD>部分使用<SCRIPT src="URL of file".js></SCRIPT>标记来载入外部程序,而在onEvent属性中调用这些函数作为事件处理器。
3.1.4 JavaScript的对象
JavaScript没有提供像抽象、继承、重载等面向对象语言的复杂功能,而是把常用的对象封装起来提供给用户,用户可以使用JavaScript的内置对象、浏览器提供的对象、服务器提供的对象,还可以创建自己的对象扩展JavaScript的功能。这些对象组成了一个非常强大的对象系统,为用户提供了强大的功能。
1.对象的概念
(1)对象的基本结构
JavaScript中的对象是由属性(properties)和方法(methods)两个基本的元素构成的。属性是对象的内置变量,用于存放该对象的特征参数等信息;方法是对象的内置函数,用于对该对象进行操作。
(2)引用对象的途径
可以采取以下几种方式获得一个对象:①引用JavaScript内部对象;②引用由浏览器提供的对象;③创建新对象。
在引用一个对象之前,这个对象必须存在,否则引用将失去意义而出错。
(3)对象专有的操作符和语句
JavaScript提供了几个用于操作对象的语句、关键词和运算符。
1)for...in语句。
格式如下:
for(属性名 in 对象名)
说明:该语句用于对对象的所有属性进行操作的控制循环,而无需知道属性的个数。
下列函数是显示数组中的内容:
Function showData(object)
for (var i=0; i<30;i++)
document.write(object[i]);
该函数是通过数组下标顺序值来访问对象的每个属性,使用这种方式首先必须知道数组的下标值,否则若超出范围,就会发生错误。而使for...in语句,则根本不需要知道对象属性的个数:
Function showData(object)
for(var prop in object)
document.write(object[prop]);
使用该函数时,在循环体中,for自动将它的属性取出来,直到最后为止。
2)with语句。使用该语句的意思是:在该语句体内,任何对变量的引用被认为是这个对象的属性,以节省一些代码。
with object
{
[JavaScript语句]
}
所有在with语句后的花括号中的语句,都是在后面object对象的作用域的。
3)this关键词。this是对当前的引用,在JavaScript由于对象的引用是多层次、多方位的,往往一个对象的引用又需要对另一个对象的引用,而另一个对象有可能又要引用另一个对象,这样有可能造成混乱,最后自己已不知道现在引用的是哪一个对象,为此JavaScript提供了一个用于将对象指定为当前对象的语句this。
4)new运算符。虽然在JavaScript中对象的功能已经是非常强大的了。但更强大的是设计人员可以按照需求来创建自己的对象,以满足某一特定的要求。使用new运算符可以创建一个新的对象。其创建对象使用如下格式:
Newobject=new Object(Parameters table);
其中,Newobject是创建的新对象,object是已经存在的对象;parameters table是参数表;new是JavaScript中的命令语句。如创建一个日期新对象
newData=new Data()
birthday=new Data (December 12.1998)
之后就可使newData、birthday作为一个新的日期对象了。
(4)对象属性的引用
对象属性的引用可由下列方式之一实现,如表3.10所示。
表3.10 对象属性的引用
引用方式 |
举例 |
||
使用点运算符(.) |
person.Name="李刚" person.City="长沙" person.Birth="1980" |
||
以数组形式 访问属性 |
person[0]="李刚" person[1]="长沙" person[2]="1980" |
||
function
PrintPerson1 (object) |
或 |
function
PrintPerson2 (object) |
|
使用属性名 (字符串) |
person["Name"]="李刚" person["City"]="长沙" person["Birth"]="1980" |
(5)对象方法的引用
JavaScript中对象方法的引用很简单:
ObjectName.methods()
如我们在前面用过的:
document.write("Hello, World! "); //其中write()是document对象的方法
或
with(document)
{
write("Hello, World!");
}
2.JavaScript内部对象的属性和方法
1)常用内部对象
JavaScript提供了一些内部对象,在此介绍最常用的三种对象,包括string(字符串)、math(数值计算)和Date(日期)。
JavaScript中的对象可以分为两种:其一是静态对象,在引用其属性、方法时不需要为它创建实例;而另一种是动态对象,在引用其对象、方法时必须创建实例。
(1)string:字符串对象。
string对象用来存放字符串,是静态对象,它有一个属性length和19个方法。如表3.11所示。
表3.11 string对象的主要属性和方法
串长属性 |
length |
字符串的长度(字符串中的字符个数) |
||
锚点 |
anchor() |
该方法创建如HTML文件中一样的anchor标记。使用anchor如用HTML中的<A Name="">一样。通过下列格式访问:string.anchor(anchorName) |
||
字符显示 |
big() |
用大字体显示字符串 |
small() |
用小体字显示字符串 |
bold() |
用粗体字显示字符串 |
Italics() |
用斜体字显示字符串 |
|
fixed() |
用固定高亮字显示字符串 |
blink() |
显示字符串时字符闪烁 |
|
fontsize(size) |
指定字体大小为size |
fontcolor(color) |
指定字体颜色为color |
|
大小写转换 |
toLowerCase() |
将字符串转换成小写 |
toUpperCase() |
将字符串转换成大写 |
字符搜索 |
indexOf(char,from) |
从from指定的位置开始搜索字符char第一次出现的位置 |
||
获得子串 |
substring(start,end) |
返回字符串从start开始到end的字符组成的子串 |
(2)math:算术对象。
math对象提供除加、减、乘、除以外的数值运算,如对数、平方根等。它是静态对象,主要有8个属性和18个方法。如表3.12所示。
(3)date:日期及时间对象。
date对象提供一个有关日期和时间的对象。它是动态对象,使用时必须用New运算符创建一个实例(如:MyDate=New Date())。date对象没有提供直接访问的属性,只有获取和设置日期和时间的方法。如表3.13所示。
表3.12 math对象的主要属性和方法
主要属性 |
E |
欧拉常数e |
PI |
圆周率 |
LN10 |
10的自然对数 |
LN2 |
2的自然对数 |
|
LOG10E |
以10为底E的对数 |
LOG2E |
以2为底E的对数 |
|
SQRT1_2 |
1/2的平方根 |
SQRT2 |
2的平方根 |
|
主要方法 |
abs() |
绝对值 |
round() |
取整四舍五入 |
sqrt() |
平方根 |
pow(base,exp) |
base的exp次方幂 |
|
sin()和cos() |
正弦、余弦 |
asin()和acos() |
反正弦、反余弦 |
|
tan()和atan() |
正切、反正切 |
|
|
表3.13 math对象的主要方法
获取日期和 时间的方法 |
getYear() |
返回年数 |
getMonth() |
返回当月号数 |
getDate() |
返回当日号数 |
getDay() |
返回星期几 |
|
getHours() |
返回小时数 |
getMintes() |
返回分钟数 |
|
getSeconds() |
返回秒数 |
getTime() |
返回毫秒数 |
|
设置日期 和时间 |
setYear() |
设置年 |
setDate() |
设置当月号数 |
setMonth() |
设置当月份数 |
setHours() |
设置小时数 |
|
setMintes() |
设置分钟数 |
setSeconds() |
设置秒数 |
|
setTime () |
设置毫秒数 |
|
|
2)JavaScript中的系统函数
JavaScript中的系统函数又称内部方法。如表3.14所示。它提供了与任何对象无关的系统函数,使用这些函数不需创建任何实例,可直接调用。
表3.14 JavaScript的系统函数
eval(字符串表达式) |
返回字符串表达式中的值 |
如:test=eval("8+9+5/2") |
unEscape (string) |
返回字符串ASCII码 |
|
escape(character) |
返回字符的编码 |
|
parseFloat(floustring) |
返回实数 |
|
parseInt(numbestring ,radix) |
返回不同进制的数 |
radix是数的进制,numbs数字串 |
3.浏览器内部对象系统
使用浏览器的内部对象系统,可实现与HTML文档进行交互。它的作用是将相关元素组织包装起来,提供给程序设计人员使用,从而减轻编程者的劳动,提高设计Web页面的能力。
(1)浏览器对象层次及其主要作用
在前面我们已经用过了文档Document对象,此外,浏览器中还提供了窗口(Window)对象以及历史(History)对象和位置(Location)对象。
Window:窗口对象,处于对象层次的最顶层,提供了处理浏览器窗口的方法和属性。
Location:位置对象,提供了处理当前URL的方法和属性,是一个静态对象。
History:历史对象,提供了与浏览器访问的历史记录有关的信息。
Document:文档对象,包含了与文档元素一起工作的对象。它位于最低层,对于实现动态Web页起关键作用,是对象系统的核心。
Navigator:浏览器对象,提供有关浏览器的信息。
(2)文档(Document)对象功能及其作用
在浏览器中,document文档对象是核心,其主要作用是把HTML页面的基本元素(如links,anchor等)封装起来,提供给编程人员使用。
1)文档对象中的对象。在document中,anchors、links、form三个对象最为重要。
l anchors:锚对象。anchors对象相当于HTML页中的书签,是<A Name=...> </A>标记被包含在HTML页中而产生的对象。document.anchors是一个数组,数组长度(document.anchors.length)是当前页中书签的个数,数组中顺序存放着当前页所有的anchors信息。
l links:链接对象。link对象相当于HTML中的超链接,是<A Href=...> </A>标记被包含在HTML页中而产生的对象。document.links也是一个数组,其长度(document.links.length)是当前页中链接的个数,数组中顺序存放着当前页所有的链接信息。
l Form:表单对象。表单属性是<Form>...</Form>标记被包含在HTML页中而产生的对象,由length指定。虽然document.links也是一个数组,但它储存的对象信息具有多种格式,可以对其编程进行文字输入或动态地改变文档的行为。本章的稍后部分将对其作专门介绍。
2)文档对象中的属性。Document对象中的attribute属性,主要用于在引用Href标识时,控制着有关颜色的格式和有关文档标题、文档原文件的URL以及文档最后更新的日期。这部分元素的主要含义如下:
l 链接颜色:alinkcolor。这个元素主要用于,当鼠标移动到一个链接上时,链接对象本身的颜色就按alinkcolor指定的颜色改变。
l 链接颜色:linkcolor。当用户使用<A Href=...> Text string </A>链接后,Text string的颜色就会按Linkcolor所指定的颜色更新。
l 浏览过后的颜色:vlinkcolor。该属性表示的是已被浏览存储为已浏览过的链接颜色。
l 背景颜色:bgcolor。指定HTML文档背景的颜色,可以通过修改它随时改变背景颜色。
l 前景颜色:fgcolor。该元素包含HTML文档中文本的前景颜色,可以通过修改它随时改变前景颜色。
3)文档对象中的方法。
l clear方法:clear()方法一经调用,将清除当前窗口中的内容。注意,它既不改变由HTML定义的文档的实际内容,也不清除诸如变量值等其他内容。它只是将显示区清空。当然,如果不是想输出新内容,你是不会清除窗口内容的,以下两个方法就用于输出。
l write()和writeln()方法:这两个方法用于向当前窗口输出HTML代码。其参数是想在窗口中输出的HTML代码字符串。
例如:假设你希望向页面中输出大号的字符串""。可以通过<H1></H1>标记来实现大号字体,输出串为<H1>Hello! User.</H1>。整个调用形式如下:
document.write("<H1>Hello! User.</H1>")
write()与wtiteln()的区别在于writeln()在输出串后自动添加一个文本换行符(不是HTML的换行标记<BR>)。不过,由于HTML的标记特性,除非被输出的文本处于<PRE></PRE>标记块中,文本换行符都将被忽略。因此,再大多数情况下,这两种方法没有什么区别。
【例3.2】这个简单的例子示范了文档对象的一般应用,文件名为0302.htm。
<html><body>
<Form Name="mytable">请输入数据: //在网页上放置1个
<Input Type="text" Name="text1" Value=""> //表单元素:输入框
</Form>
<A name="Link1" href="121.htm">第一个链接</a><br> //在网页上放置3个
<A name="Link2" href="122.htm">第二个链接</a><br> //超级链接
<A name="Link2" href="123.htm">第三个链接</a><br>
<A href="#Link1">第一个锚点</a> //在网页上放置3个
<A href="#Link2">第二个锚点</a> //锚点
<A Href="#Link3">第三个锚点</a>
<BR>
<Script Language="JavaScript">
document.write("文档有"+document.links.length+"个链接"+"<br>");
//显示链接数
document.write("文档有"+document.anchors.length+"个锚点"+"<br>");
//显示锚点数
document.write("文档有"+document.forms.length+"个表单"); //显示表单数
</script></body></HTML>
运行结果如图3.2所示。
图3.2 范例运行结果
(3)窗口(Window)对象及输入输出
JavaScript是基于对象的脚本编程语言,它的输入输出也是通过对象来完成的。其中输出可通过文档(document)对象的方法来实现,而输入通过窗口(Window)对象来实现。
1)窗口对象。该对象包括许多有用的属性、方法和事件驱动程序,编程人员可以利用这些对象控制浏览器窗口显示的各个方面,如对话框、框架等。
2)窗口对象的事件驱动。窗口对象主要有装入Web文档事件onload和卸载时onunload事件,用于文档载入和停止载入时开始和停止更新文档。
3)窗口对象的方法。窗口对象的方法主要用来提供信息或输入数据以及创建一个新的窗口。
① 创建一个新窗口open()。使用window.open(参数表)方法可以创建一个新的窗口。其格式如:
window.open("URL","窗口名字","窗口属性")
window属性参数是一个字符串列表项,由逗号分隔,指明新建窗口的属性。如表3.15所示。
表3.15 window.open函数的窗口属性列表
参数 |
设定值 |
含义 |
Toolbar |
yes/no |
建立或不建立标准工具条 |
Location |
yes/no |
建立或不建立位置输入字段 |
Directions |
yes/no |
建立或不建立标准目录按钮 |
Status |
yes/no |
建立或不建立状态条 |
Menubar |
yes/no |
建立或不建立菜单条 |
Scrollbar |
yes/no |
建立或不建立滚动条 |
Revisable |
yes/no |
能否改变窗口大小 |
Width |
yes/no |
确定窗口的宽度 |
Height |
yes/no |
确定窗口的高度 |
open()方法经常被用来弹出一个网站的公告或广告。
【例3.3】 下面是一个简单的例子。
文件0303_01.htm:
<HTML><Head>
<script language="JavaScript">
window.open("0303_02.html",null,"width=180,height=70,toolbar=no,statusebar=no,menubar=no")
</script></Head></HTML>
同一目录下文件0303_02.htm:
<html><h1 align="center"><font color="#FF0000">
热烈庆祝中国gongchandang建党八十周年!
</font></h1></html>
当浏览器打开1.html文件时,运行情况如图3.3所示。
图3.3 0303_01.Html运行情况
②弹出警示对话框。警示对话框是只有一个OK按钮的对话框,用来向用户发出警告或提示信息。
alert("message")方法能创建警示对话框。其中message是将要显示在对话框中的警告或提示信息。如:
alert("您输入的密码无效!");
③弹出确认对话框。确认对话框是有OK和Cancel两个按钮的对话框,用来给用户提供一个选择。
confirm("message")方法可以创建确认对话框。其中message是将要显示在对话框中的提示信息。如:
confirm("您输入的密码正确无误吗?");
④弹出可接受输入的对话框。prompt()方法允许用户在对话框中输入信息,其基本格式如下:
prompt("提示信息",默认值)
【例3.4】 下面这个例子通过prompt()方法让用户输入姓名,然后使用document对象的write()方法输出,实现了最简单的交互。文件名为0304.htm。
<HTML>
<Head>
<script languaga="JavaScript">
var UserName=window.prompt("请输入你的姓名:" ",");
document.write("你好!"+UserName);
</script>
</Head>
</HTML>
运行的结果如图3.4所示。
4)窗口对象中的属性。窗口对象的属性主要用来对浏览器中存在的各种窗口和框架的引用,主要有以下几个:
l Frames:指明文档中帧的数目。
l Parent:指明当前窗口或帧的父窗口。
l DefaultStatus:默认状态,它的值显示在窗口的状态栏中。
l Status:包含文档窗口帧中的当前信息。
l Top:用以实现所有的下级窗口的窗口。
l Window:指的是当前窗口。
l Self:引用当前窗口。
【例3.5】 范例:窗口的地震效果。文件名存为0305.htm。
<html><head>
<script LANGUAGE="JavaScript">
function shake(n) //定义shake()函数
{
if (self.moveBy)
{
for (i = 10; i > 0; i--)
{
for (j = n; j > 0; j--)
{
self.moveBy(0,i); //调用window对象的moveBy
self.moveBy(i,0); //函数,使窗口分别向下、
self.moveBy(0,-i); //左、上、右移动i个
self.moveBy(-i,0); //像素,产生震动效果
}
}
}
}
// End -->
</script></head>
<body>窗口地震效果的示范程序
<form> //定义按钮,并
<input type="button" onClick="shake(10)" value="看看效果">
//设置鼠标点击时
</form> //执行shake(10)函数
</body>
该程序的效果请读者上机查看。
(4)表单(Form)对象
表单对象可以使设计人员能用表单中不同的元素与客户机用户相交互,而用不着在之前首先进行数据输入,就可以实现动态改变Web文档的行为。在本书的前面章节已经介绍过关于表单的基础知识。要使用JavaScript实现动态交互,必须掌握有关表单对象(Form)更为深入的知识。
1)表单对象的定义。表单(Form)是构成Web页面的基本元素之一,一个Web页面通常包含一个或几个表单元素。浏览器封装了与表单相关的HTML代码,以对象的形式提供给JavaScript,其最主要的功能就是能够直接访问HTML文档中的表单。表单中的基本元素有:Text单行文本输入框、Textarea多行输入框、Select选择元素、Button按钮、CheckBox复选框、Radio单选钮、Password口令输入框、Submit提交按钮等。
2)访问表单对象。必须先在HTML页面中用<FORM>标识创建表单,才能对其进行访问。在JavaScript中访问表单对象有两种方法。
①通过名称访问表单。在表单对象的属性中首先必须指定其表单名,然后就可以通过下列标识访问表单。如:
document.Mytable()
②通过数组来访问表单。除了使用表单名来访问表单外,还可以使用表单对象数组来访问表单对象。但需要注意一点,因表单对象是由浏览器环境提供的,而浏览器环境所提供的数组下标是由0到n。所以可通过下列格式实现表单对象的访问:
document.forms[0]
document.forms[1]
document.forms[2]...
【例3.6】 在网页上显示一个按钮,通过单击它来改变窗口颜色。文件名为0306_01.htm。
<html><head>
<Script Language="JavaScript">
document.bgColor="blue"; // 原来的颜色设置
document.vlinkColor="white";
document.linkColor="yellow";
document.alinkcolor="red";
function ChangeColor() //改变颜色设置的函数
{ document.bgColor="red";
document.vlinkColor="blue";
document.linkColor="green";
document.alinkcolor="blue"; }
</script></HEAD>
<body bgColor="White" >
<A href="0306_01.htm"> 调用动态按钮文档</a>
<form> //定义表单元素--按钮,
<Input type="button" Value="red" OnClick="ChangeColor()">
</form> //当OnClick事件发生,
</body>
</html> //调用ChangeColor函数
动态按钮程序。文件名为0306_02.htm。
<HTML>
<p align="center"></p>
<div align="center"><center>
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td width="100%"><form name="form2" onSubmit="null">
<p><input type="submit" name="banner" VALUE="Submit"
onClick="alert('You have to put an \'action=[url]\' on the formtag!!')"><br>
<script language="JavaScript">
var id,pause=0,position=0;
function banner() {
var i,k,msg=" 这里输入你要的内容";
k=(30/msg.length)+1;
for(i=0;i<=k;i++) msg+=" "+msg; // show it to the window
document.form2.banner.value=msg.substring (position,position-30);
// set new position
if(position++==msg.length) position=0; // repeat at entered speed
id=setTimeout("banner()",60); }
// end -->
banner();
</script></p></form></td></tr></table></center></div>
<BODY><A href="0306_01.htm"> 返回</a>
</BODY></HTML>
(5)框架(Frames)对象
前面已经介绍过框架在网页中的简单应用,下面将介绍框架作为对象的使用方法。
1)框架对象的定义。使用框架可以实现更为复杂的信息交互。框架可以将窗口分割成不同的区域,每个区域显示不同的HTML文件,不同框架之间可以交换信息,从而实现交互。
浏览器把框架的属性、方法和事件封装起来,作为对象提供给JavaScript使用。框架对象是窗口对象的子对象,其本身也一类窗口,它继承了窗口对象所有的属性和方法。
2)如何访问框架。在前面我们介绍过使用document.forms[]实现单一表单中不同元素的访问。而要实现框架中多表单的不同元素的访问,则必须使用Window对象中的Frames属性。Frames属性同样也是一个数组,它在父框架集中为每一个子框架设有一项。通过下标实现不同框架的访问:
parent.frames[index1].docuement.forms[index2]
通过parent.frames.length确定窗口中表单的数目。
除了使用数组下标来访问表单外还可以使用框架名和表单名来实现各元素的访问:
parent.framesName.decument.formNames.elementName.(m/p)
4.创建新对象
JavaScript内部对象和浏览器对象的功能已十分强大,但JavaScript还是提供了创建新对象的方法,使其能完成许多更复杂的工作。
JavaScript中创建新对象十分简单:首先定义一个对象,然后为该对象创建一个实例。这个实例就是一个新对象,它具有对象的基本特征。
(1)对象的定义
JavaScript对象的定义,其基本格式如下:
Function Object(属性表)
This.prop1=prop1;
This.prop2=prop2;
...
This.meth=FunctionName1;
This.meth=FunctionName2;
...
在一个对象的定义中,可以为该对象指明其属性和方法。通过属性和方法构成了一个对象的实例。以下是一个关于School对象的定义:
This.name=name;
This.city=city;
This.creatDate=New Date(creatDate);
This.URL=URL;
其基本含义如下:
Name:指定一个单位名称。
City:“单位”所在城市。
CreatDate:记载school对象的更新日期。
URL:该对象指向一个网址。
(2)创建对象实例
一旦对象定义完成后,就可以为该对象创建一个实例了。
NewObject=New object();
其中,NewObject是新的对象,Object是已经定义好的对象。
(3)对象方法的使用
在对象中除了使用属性外,有时还需要使用方法。在对象的定义中,我们看到的This.meth=FunctionName语句,那就是为对象定义的方法。实质上对象的方法就是一个函数FunctionName,通过它实现自己的意图。
在school对象中增加一个方法,该方法是显示它本身,并返回相应的字串。
function school(name,city,createDate,URL)
This.Name=Name;
This.city=city;
This.createDate=New Date(creatDate);
This.URL=URL;
This.showschool=showschool;
其中This.showschool就是定义了一个方法—showschool()。而showschool()方法是实现school对象本身的显示。
function showschool()
for (var prop in this)
alert(prop+="+this[prop]+"");
其中alert是JavaScript中的内部函数,显示其字符串。
5.JavaScript中的数组
(1)使用New创建数组。
JavaScript中不像其他语言那样具有明显的数组类型,但可以通过function定义一个数组,并使用New对象操作符创建一个具有下标的数组,可以实现任何数据类型的存储。
1)定义对象的数组。
Function arrayName(size)
{
This.length=size;
for(var X=1; X<=size;X++)
this[X]=0;
return this;
}
其中arrayName是定义数组的一个名字,size是有关数组大小的值,即数组元素的个数。通过for循环对一个当前对象的数组进行定义,最后返回这个数组。
从中可以看出,JavaScript中的数组是从1到size,这与其他0到size的数组表示方法有所不同,当然你可根据需要将数组的下标由1到size调整到0到size-1,可由下列程序实现:
Function arrayName (size)
For (var X=0; X<=size;X++)
this[X]=0;
this.lenght=size;
return this;
从上面可以看出该方法是只是调整了this.length的位置,该位置是用于存储数组的大小的,从而调整后的数组的下标将与其他语言一致。但请读者注意正是由于数组下标顺序由1到size,使得JavaScript中的对象功能更加强大。
2)创建数组实例。
一个数组定义完成以后,还不能马上使用,必须为该数组创建一个数组实例。
Myarray=New arrayName(n);
并赋予初值:
Myarray[1]="字串1";
Myarray[2]="字串2";
Myarray[3]="字串3";
...
Myarray[n]="字串n";
一旦给数组赋了初值后,数组中就具有真正意义的数据了,以后就可以在程序设计过程中直接引用。
【例3.7】 下列程序每次从随机显示存放在tips[]数组中多个字符串中的一个。文件名为0307.htm
<HTML>
<HEAD>
<script Language="JavaScript">
<!--
tips = new Array(6);
tips[0]=" Tip1";
tips[1]=" Tip2";
tips[2]=" Tip3";
tips[3]=" Tip4";
tips[4]=" Tip5";
tips[5]=" Tip6";
index = Math.floor(Math.random() * tips.length);
document.write("<FONT SIZE=8 COLOR=DARKBLUE>" + tips[index]+"</FONT>");
</Script>
</HEAD>
</HTML>
运行结果是数组某值,刷新页面,显示结果随机变化,请读者上机操作。
(2)内部数组。
在Java中为了方便内部对象的操作,可以使用表单(Forms)、框架(Frames)、元素(elements)、链接(Links)和锚(Anchors)数组实现对象的访问。
Anchors[]:使用<A name="anchorName">标识建立的锚链接组成的数组。
Links[]:使用<A href="URL">来定义一个超文本链接。
Forms[]:在程序中使用多个表单时,可使用该数组。
Elements[]:在一个窗口中使用多个元素时,可使用该数组。
Frames[]:建立框架时,使用该数组。
3.1.5 JavaScript实例
【例3.8】 用JavaScript做成的日历。
<html>
<head>
<SCRIPT language=JavaScript>
function Year_Month(){
var now = new Date();
var yy = now.getYear();
var mm = now.getMonth()+1;
var cl = '<font color="#0000df">';
if (now.getDay() == 0) cl = '<font color="#c00000">';
if
(now.getDay() == 6) cl = '<font color="#
return(cl + yy + '年' + mm + '月</font>'); }
function Date_of_Today(){
var now = new Date();
var cl = '<font color="#ff0000">';
if (now.getDay() == 0) cl = '<font color="#c00000">';
if
(now.getDay() == 6) cl = '<font color="#
return(cl + now.getDate() + '</font>'); }
function Day_of_Today(){
var day = new Array();
day[0] = "星期日";
day[1] = "星期一";
day[2] = "星期二";
day[3] = "星期三";
day[4] = "星期四";
day[5] = "星期五";
day[6] = "星期六";
var now = new Date();
var cl = '<font color="#0000df">';
if (now.getDay() == 0) cl = '<font color="#c00000">';
if
(now.getDay() == 6) cl = '<font color="#
return(cl + day[now.getDay()] + '</font>'); }
function CurentTime(){
var now = new Date();
var hh = now.getHours();
var mm = now.getMinutes();
var ss = now.getTime() % 60000;
ss = (ss - (ss % 1000)) / 1000;
var clock = hh+':';
if (mm < 10) clock += '0';
clock += mm+':';
if (ss < 10) clock += '0';
clock += ss;
return(clock); }
function refreshCalendarClock(){
document.all.calendarClock1.innerHTML = Year_Month();
document.all.calendarClock2.innerHTML = Date_of_Today();
document.all.calendarClock3.innerHTML = Day_of_Today();
document.all.calendarClock4.innerHTML = CurentTime(); }
var webUrl = webUrl;
document.write('<table border="0" cellpadding="0" cellspacing="0"><tr><td>');
document.write('<table id="CalendarClockFreeCode" border="0" cellpadding="0" cellspacing="0" width="120" height="140" ');
document.write('style="position:absolute;visibility:hidden" bgcolor="#eeeeee">');
document.write('<tr><td align="center"><font ');
document.write('style="cursor:hand;color:#ff0000;font-family:宋体;font-size:
if (webUrl != 'netflower'){
document.write('</td></tr><tr><td align="center"><font ');
document.write('style="cursor:hand;color:#2000ff;font-family:宋体;font-size:
}
document.write('</td></tr></table>');
document.write('<table border="0"
cellpadding="0" cellspacing="0" width="122"
bgcolor="#C
document.write('<tr><td valign="top" width="100%" height="100%">');
document.write('<table border="1" cellpadding="0" cellspacing="0" width="116" bgcolor="#FEFEEF" height="134">');
document.write('<tr><td align="center" width="100%" height="100%" >');
document.write('<font
id="calendarClock1" style="font-family:宋体;font-size:
document.write('<font
id="calendarClock2"
style="color:#ff0000;font-family:Arial;font-size:
document.write('<font
id="calendarClock3" style="font-family:宋体;font-size:
document.write('<font
id="calendarClock4" style="color:#100080;font-family:宋体;font-size:
document.write('</td></tr></table>');
document.write('</td></tr></table>');
document.write('</td></tr></table>');
setInterval('refreshCalendarClock()',1000);
</SCRIPT>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>登陆</title>
<body bgcolor="#0033FF" OnLoad="Scroll()">
</body>
</html>
用浏览器打开网页,运行效果如图3.5所示。
图3.5 日历
【例3.9】 检测是否填入值是否为空。
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312"; >
<title>输入值检测</title>
<SCRIPT Language = javascript>
<!--
//下面的副程序将执行资料检查
function isValid()
{
//下面的if判断语句将检查是否输入帐号资料
if(frmLogin.id.value == "")
{
window.alert("您必须完成帐号的输入!");
//显示错误信息
document.frmLogin.elements(0).focus();
//将光标移至帐号输入栏
return false;
}
//下面的if判断语句将检查是否输入帐号密码
if(frmLogin.password.value == "")
{
window.alert("您必须完成密码的输入!");
//显示错误信息
document.frmLogin.elements(1).focus();
//将光标移至密码输入栏
return false; //离开函数
}
frmLogin.submit(); //送出表单中的资料
}
-->
</SCRIPT>
<body OnLoad="Scroll()">
<p align="center"><font color="#33FF00" size="+4" face="华文行楷">JSP学习</font></p>
<form name="frmLogin" method="post" action="" onSubmit="return isValid(this);">
<p> <div align="center">
<table width="47%" height="232" border=0 align="center" >
<tr >
<td height="44" colspan="2">
<div align="center"><font color="#0000FF" size="+2" face="华文行楷">请你输入</font></div></td>
</tr>
<tr >
<td width="35%"><div align="center"><strong><font color="#0000FF">用户名</font><font color="#FFFFFF">:</font></strong></div></td>
<td width="65%"><input name="id" type="text" id="id" size="20" maxlength="20"></td>
</tr>
<tr>
<td><div align="center"><strong> <font color="#0000FF">密码:</font></strong></div></td>
<td><input name="password" type="password" id="password" size="8" maxlength="8"></td>
</tr>
<tr >
<td colspan="2"><div align="center">
<input type="submit" name="Submit" value="登陆">
</div></td>
</tr>
</table>
</div>
</form>
</body>
</html>
运行结果如图3.6所示。
图3.6 检测用户名
3.2 Java编程语言
Java语言是由Sun公司1995年推出的新一代编程语言,Java语言一经推出,就受到了业界的广泛关注。现已成为Internet应用的主要开发语言,它彻底改变了应用软件的开发模式,为迅速发展的信息世界增添了新的活力。
Java语言产生于C++语言之后,是完全的面向对象的编程语言,充分吸取了C++语言的优点,采用了程序员所熟悉的C和C++语言的许多语法,同时又去掉了C语言中指针、内存申请和释放等影响程序健壮性的部分。在Java运行环境中,始终存在着一个系统级的线程,专门跟踪内存的使用情况,定期检测出不再使用的内存,并进行自动回收,避免了内存的泄露,也减轻了程序员的工作量。
Java语言的一个目标是跨平台,因此采用了解释执行而不是编译执行的运行环境,在执行过程中根据所在的不同的硬件平台把程序解释为当前的机器码,实现跨平台运行。而动态下载程序代码的机制完全是为了适应网络计算的特点,程序可以根据需要把代码实时的从服务器中下载过来执行,在此之前还没有任何一种语言能够支持这一点。此外,Java语言还有高安全性和多线程等特点。
Java语言程序文件以.java为后缀。Java程序编写完后,用开发环境下的编译器编译生成字节码,字节码文件以.class为后缀。Editplus、记事本等都可以用来编写Java源程序,当然也可以使用Eclipse。Java的开发环境我们在第一章已安装好,为了清楚的解释JDK下Java程序的编辑、编译和运行过程,请看下面的例子。
【例3.10】 设计显示“HELLO WORLD”的Java程序,并用JDK运行该程序。
(1)编辑
用编辑器,如Editplus和记事本等编写Java源程序。Editplus编辑窗口及键入的源程序如图3.7所示。
图3.7 编辑窗口和程序
在这一简单的Java程序中,class是类声明的关键字,HelloWorld是类名。在main方法中,用标准输出语句System.out.println("Hello World!")在屏幕上显示Hello World!
保存文件时注意Java源程序文件名必须和类名完全一样,值得注意的是Java文件名的命名也是大小写敏感的。上述Java源程序的文件名为HelloWorld.java
(2)编译
在JDK下,Java程序的编译和运行在MS-DOS窗口中进行。方法是:打开MS-DOS窗口,进入保存Java源程序文件的文件夹,输入编译命令:
d:\myjsp>javac HelloWorld.java
编译命令javac将对当前文件夹中的HelloWorld.java文件进行编译。如果编译正确,将会产生相应的字节码文件HelloWorld.class;如果编译时发现错误,系统将终止编译并给出出错信息。如果系统未找到javac命令,则说明环境变量没有正确设置。
(3)运行
输入运行命令:
d:\myjsp>java HelloWorld
运行命令java可运行字节码文件HelloWorld.class,此时.class后缀可省略。编译和运行结果如图3.8 所示。这样第一个Java程序就成功了!
图3.8 编译运行结果
3.2.1 数据类型与关键字
1.数据类型
Java语言里所有变量都必须先明确定义其数据类型后才能使用。Java语言的数据类型有两类:基本数据类型与引用类型。基本数据类型有如表所示的8种。其他为引用类型,如:数组、字符串、类、接口、用户自定义类型等。
表3.16 Java语言的基本数据类型
保留字 |
类型 |
字节数 |
值的范围 |
byte |
字节型 |
1 |
-128 ~ 127 |
short |
短整型 |
2 |
-32768 ~ 32767 |
int |
整型 |
4 |
-2147483648 ~ 2147483647 |
long |
长整型 |
8 |
-9223372036854775808 ~9223372036854775807 |
float |
单精度浮点数型 |
4 |
1.4×10-45 ~ 3.4028235×1038 |
double |
双精度浮点数型 |
8 |
4.9×10-324~1.7976931348623157×10308 |
boolean |
布尔型 |
不定 |
true或false |
char |
字符型 |
2 |
Unicode(0~65535) |
Java语言中,一个Unicode标准下的编码称作一个字符。字符型字面值用一对单引号括起来,如’a’、’A’、’#’等都是字符型字面值。由于有些符号不能在屏幕上直接显示,以及字符串中特殊符号的表示等问题,与要有特殊方法表示这些符号。Java语言采用转义字符的表示方法。表3.17给出了常见的转义字符及其含义。
表3.17 Java语言常见的转义字符及其含义
转义字符 |
含义 |
\n |
换行 |
\t |
水平制表 |
\r |
回车 |
\\ |
反斜杠\ |
\’ |
单引号’ |
\” |
双引号” |
2.关键字
Java语言中定义了如表所示关键字,有特定的含义与用途,不允许用户挪用。
表3.18 关键字
abstract |
boolean |
break |
byte |
case |
catch |
char |
class |
continue |
default |
do |
double |
else |
extends |
false |
final |
finally |
float |
for |
if |
implements |
import |
instanceof |
int |
interface |
long |
native |
new |
null |
package |
private |
protected |
public |
return |
short |
static |
super |
switch |
synchronized |
this |
throw |
throws |
transient |
true |
try |
void |
volatile |
while |
3.2.2 运算符和表达式
1.运算符
Java语言中表达各种运算的符号叫做运算符,运算符的运算对象称为操作数。在Java中有算术运算符、关系运算符、位运算符、赋值运算符、条件运算符等。运算符及相关内容如表3.19所示。
表3.19 Java的运算符
优先级 |
运算符 |
说明 |
目数 |
结合性 |
1 |
. [] () |
成员运算符 数组下标运算符 圆括号 |
|
从左至右
|
2 |
++ -- ! ~ Instanceof + - |
自加1运算 自减1运算 逻辑非 按位求反 实例运算符 正号 负号 |
单目 单目 单目 单目 双目 单目 单目 |
从右至左
|
3 |
New |
内存分配运算符 |
单目 |
|
4 |
* / % |
乘 除或取整 取余数 |
双目 |
从左至右 |
5 |
+,- |
加,减 |
||
6 |
>> >>> << |
保留符号的右移 不保留符号的右移 左移 |
||
7 |
>,>=,<,<= |
大于,大于等于,小于,小于等于 |
||
8 |
==,!= |
相等,不等 |
||
9 |
& |
位与 |
||
10 |
^ |
位异或 |
||
11 |
| |
位或 |
||
12 |
&& |
逻辑与 |
||
13 |
|| |
逻辑或 |
||
14 |
?: |
条件运算符 |
三目 |
|
15 |
=,+=,-=,*=,/=, %=,^=,&=,|=, <<=,>>=,>>>= |
赋值运算符 |
双目 |
从右往左 |
(1)算术运算符。算术运算符用于处理整型、浮点型、字符型的数据,进行算术运算。Java中没有乘幂运算符,若要进行乘幂运算,则可用类Math的pow()方法:Math.pow(x,y)。
(2)关系运算符。关系运算符用于比较两个操作数,并按比较的条件成立与否返回一个布尔值(true或false)。所有关系运算符都是二目运算符。JavaScript共有6个关系运算符,如表3.20所示。
表3.20 Java的关系运算符
< |
小于 |
<= |
小于等于 |
> |
大于 |
>= |
大于等于 |
== |
等于 |
!= |
不等于 |
(3)逻辑运算符。逻辑操作符把多个比较运算组织起来,形成复合条件,并进行测试,以决定复杂的条件是否为真。JavaScript中使用了3个布尔逻辑运算符,如表3.21所示。
表3.21 Java的逻辑运算符
&& |
逻辑与 |
|| |
逻辑或 |
! |
逻辑非 |
(4)位运算符。位运算符用于对数值的位进行操作,参与运算的操作数只能是int,long类型。在不产生溢出的情况下,左移一位相当于乘以2,用左移实现乘法运算的速度比通常的乘法运算速度要快。Java中的位运算符见表3.22。
表3.22 Java位运算符
|(按位或)、&(按位与)、^(按位异或) <<(左移)、>>(带符号右移)、>>>(不带符号右移) |
双目 |
~(取补) |
单目 |
(5)赋值运算符。简单赋值表达式将赋值符(=)右边表达式的值存放到赋值符左边的变量中去。而复合赋值表达式混合了其他操作(算术操作、位操作)和赋值操作,如:
Sum += price 等同于 Sum = Sum + price
Sum /= count 等同于 Sum = Sum / count
Java中的赋值运算符如表3.23所示。
表3.23 Java的赋值运算符
= |
简单赋值 |
+= |
递增 |
-= |
递减 |
*= |
自乘后赋值 |
/= |
自除后赋值 |
%= |
求余后赋值 |
&= |
与之后赋值 |
|= |
或之后赋值 |
^= |
异或之后赋值 |
<<= |
左移之后赋值 |
>>= |
带符号右移之后赋值 |
>>>= |
填充零右移之后赋值 |
(6)条件运算符。条件运算符来自C、C++和Java,其格式是e1?e2:e3。若e1为真,则条件表达式的结果取e2的值,否则取e3的值。
2.表达式
用运算符和圆括号把运算对象连接起来,符合Java语法规则的式子称为表达式。每个表达式经过运算后都会产生一个确定的值,称为表达式的值。Java表达式既可以是单独组成的一个语句,也可出现在变量声明、循环条件测试、方法的调用参数等场合,它是Java程序的重要组成要素。
3.2.3 流程控制语句
与C、 C++相同, Java程序通过流控制来执行程序流,完成一定任务的语句。Java语言中,一个以分号(;)结束的符号串称为一条语句。这些语句可以是单一的一条语句(如c=a+b;),也可以复合语句。流程控制语句用来控制程序的执行流程。Java流程控制语句主要有分支语句、循环语句和异常处理语句三种。
1.分支语句
分支语句提供了一种控制机制,使得程序的执行可以跳过某些语句不执行,而转去执行特定的语句。
1)条件语句if-else.
if-else语句根据判定条件的真假来执行两种操作中的一种,格式为:
if(条件表达式)
{
语句串1;
}
else
{
语句串2;
}
条件表达式是任意一个返回布尔型数据的表达式(这比C、 C++的限制要严格)。每个单一的语句后都必须有分号,语句串1和语句串2可以为复合语句,这时要用大括号{}。建议对单一的语句也用大括号括起,这样程序的可读性强,而且有利于程序的扩充(可以在其中填加新的语句),{}外面不加分号。
若条件表达式的值为true,则程序执行语句串1,否则执行语句串2。else子句是任选的,当没有else语句时,若条件表达式的值为flase,就执行if语句后面的语句。
if-else语句的一种特殊形式为:
if(条件表达式1){
语句串1
}else if (条件表达式2){
语句串2
}……
}else if (条件表达式M){
语句串M
}else {
语句串N
}
这种情况称为if语句嵌套。此时,else是和哪个if语句匹配容易产生混淆。为此Java语言规定: else子句不能单独作为语句使用,它必须和if配对使用。else总是与离它最近的if配对。可以通过使用大括号{}来改变配对关系。
【例3.11】 判断某一年是否为闰年。闰年的条件是符合下面二者之一:①能被4整除,但不能被100整除;②能被4整除,又能被100整除。文件名为LeapYear.java
public class LeapYear{
public static void main( String args[] ){
int year=1989; //method 1
if( (year%4==0 && year%100!=0) || (year%400==0) )
System.out.println(year+" is a leap year.");
else
System.out.println(year+" is not a leap year.");
year=2000; //method 2
boolean leap;
if( year%4!=0 )
leap=false;
else if( year%100!=0 )
leap=true;
else if( year%400!=0 )
leap=false;
else
leap=true;
if( leap==true )
System.out.println(year+" is a leap year.");
else
System.out.println(year+" is not a leap year.");
year=2050; //method3
if( year%4==0){
if( year%100==0 ){
if( year%400==0)
leap=true;
else
leap=false;
}else
leap=false;
}else
leap=false;
if( leap==true )
System.out.println(year+" is a leap year.");
else
System.out.println(year+" is not a leap year.");
}
}
运行结果为
1989 is not a leap year.
2000 is a leap year.
2050 is not a leap year.
该例中,方法1用一个逻辑表达式包含了所有的闰年条件,方法2使用了if-else语句的特殊形式,方法3则通过使用大括号{}对if-else进行匹配来实现闰年的判断。大家可以根据程序来对比这三种方法,体会其中的联系和区别,在不同的场合选用适合的方法。
2)多分支语句switch
switch语句(又称开关语句)是和case语句一起使用的,其功能是根据某个表达式的值在多个case引导的分支语句中选择一个来执行。一个switch语句可以代替多个if—else语句组成的分支结构,而switch语句从思路上显得更清晰。它的一般格式如下:
switch(表达式)
{
case 判断值1:语句块1;[break;]
case 判断值2:语句块2;[break;]
……
case 判断值n:语句块n;[break;]
[default:语句块n+1]
}
switch后面括号中表达式的值必须是符合byte,char,short,int类型的常量表达式,而不能用浮点类型或long类型,也不能为一个字符串。多分支语句把表达式返回的值与每个case子句中的值相比。如果匹配成功,则运行该case子句后的语句序列。case子句中的值values必须是常量, 而且所有case子句中的值是不同的。
default子句是任选的。当表达式的值与任一case子句中的都不匹配时,程序执行default后面的语句。如果表达式的值与任一case子句中的值都不匹配且没有default子句,则程序不作任何操作,而是直接跳出switch语句。
break语句用来在执行完一个case分支后,使程序跳出switch语句,即终止switch语句的执行。因为case子句只是起到一个标号的作用,用来查找匹配的入口,从此处开始执行,对后面的case子句不再进行匹配,而是直接执行其后的语句序列,因此在每个case分支后,要用break来终止后面的case分支语句的执行。在一些特殊情况下,多个不同的case值要执行一组相同的操作,这时可以不用break。case分支中包括多个执行语句时,可以用大括号{}括起。
【例3.12】 根据考试成绩的等级打印出百分制分数段。
public class GradeLevel{
public static void main(String args[])
{
System.out.println("\n** first situation **");
char grade='C'; //normal use
switch( grade ){
case 'A' : System.out.println(grade +" is 85~100");
break;
case 'B' : System.out.println(grade +" is 70~84");
break;
case 'C' : System.out.println(grade +" is 60~69");
break;
case 'D' : System.out.println(grade +" is <60");
break;
default : System.out.println("input error");
}
System.out.println("\n** second situation **");
grade='A'; ∥creat error without break statement
switch( grade ){
case 'A' : System.out.println(grade+" is 85~100");
break;
case 'B' : System.out.println(grade+" is 70~84");
break;
case 'C' : System.out.println(grade+" is 60~69");
break;
case 'D' : System.out.println(grade+" is <60");
break;
default : System.out.println("input error");
}
System.out.println("\n** third situation **");
grade='B'; ∥several case with same operation
switch( grade )
{
case 'A' :
case 'B' :
case 'C' : System.out.println(grade+" is >=60");
break;
case 'D' : System.out.println(grade+" is <60");
break;
default : System.out.println("input error");
}
}
}
运行结果为
**** first situation ****
C is 60~69
**** second situation ****
A is 85~100
**** third situation ****
B is >=60
从该例中我们可以看到break语句的作用。
3)返回语句return
return语句从当前方法中退出,返回到调用该方法的语句处,继续程序的执行。返回语句有两种格式:
(1)return 表达式;
返回一个值给调用该方法的语句,返回值的数据类型必须与方法声明中的返回值类型一致。可以使用强制类型转换来使类型一致。
(2)return;
当方法中用void声明返回类型为空时,应使用这种格式,不返回任何值。return语句通常用在一个方法体的最后,以退出该方法并返一个值。Java语言中单独的return语句用在一个方法体的中间时,会产生编译错误,因为这时有一些语句执行不到。但可以通过把return语句嵌入某些语句(如if-else)来使程序在未执行完方法中的所有语句时退出。
2.循环语句
循环结构是程序中一种重要的基本结构,是指在一定的条件下反复执行某段程序,被反复执行的这段程序称为“循环体”。Java中有三种语句来实现循环结构,分别是while,do-while和for语句。
1)while语句
while语句的格式如下:
while(条件表达式)
{
循环体语句;
}
在循环刚开始时,会计算一次“条件表达式”的值。当条件为假时,将不执行循环体,直接跳转到循环体外,执行循环体外的后续语句;当条件为真时,便执行循环体。每执行完一次循环体,都会重新计算一次条件表达式,当条件为真时,便继续执行循环体,直到条件为假才结束循环。
2)do-while语句
do-while语句的格式如下:
do
{
循环体语句;
}while(条件表达式)
do-while循环与while循环的不同在于:它先执行循环中的语句,然后再判断条件是否为真,如果为真则继续循环;如果为假,则终止循环。因此,do-while循环至少要执行一次循环语句。
3)for语句
for语句是三个循环语句中功能最强,使用最广泛的一个。for语句的格式如下:
for(表达式1;表达式2;表达式3)
{
循环体语句;
}
表达式1一般是一个赋值语句,它用来给循环控制变量赋初值;表达式2是一个布尔类型的表达式,它决定什么时候退出循环;表达式3一般用来修改循环变量,控制变量每循环一次后按什么方式变化。这三个部分之间用“;”分开。
for语句的执行过程:
(1)在循环刚开始时,先计算表达式1,在这个过程中,一般完成的是初始化循环变量或其它变量。
(2)根据表达式2的值来决定是否执行循环体。表达式2是一个返回布尔值的表达式,若该值为假,将不执行循环体,并退出循环;若该值为真,将执行循环体。
(3)执行完一次循环体后,计算表达式3。在这个过程中一般会修改循环变量。
(4)转入第(2)步继续执行。
4)continue语句
continue语句用来结束本次循环,跳过循环体中下面尚未执的语句,接着进行终止条件的判断,以决定是否继续循环。对于for语句,在进行终止条件判断前,还要先执行迭代语句。它的格式为:
continue;
【例3.13】 下例分别用while、 do-while和for语句实现累计求和。
public class Sum{
public static void main( String args[] ){
System.out.println("\n** while statement **");
int n=10,sum=0; ∥initialization
while( n>0 ){ ∥termination
sum+=n; ∥body
n--; ∥iteration
}
System.out.println("sum is "+sum);
System.out.println("\n** do_while statement **");
n=0; ∥initialization
sum=0;
do{
sum+=n; ∥body
n++; ∥iteration
}while( n<=10 ); ∥termination
System.out.println("sum is "+sum);
System.out.println("\n** for statement **");
sum=0;
for( int i=1; i<=10; i++){
∥initialization,termination,iteration
sum+=i;
}
System.out.println("sum is "+sum);
}
}
运行结果为:
**whilestatement**
sumis55
**do_whilestatement**
sumis55
**forstatement**
sumis55
可以从中来比较这三种循环语句,从而在不同的场合选择合适的语句。
【例3.14】 求100~200间的所有素数
public class PrimeNumber{
public static void main( String args[] ){
System.out.println(" ** prime numbers between 100 and 200 **");
int n=0;
outer:for(int i=101;i<200;i+=2){ ∥outer loop
int k=15; ∥select for convinence for(int j=2;j<=k;j++){ ∥inner lop
if( i%j==0 )
continue outer;
}
System.out.print(" "+i);
n++; ∥output a new line
if( n<10 ) ∥after 10 numbers
continue;
System.out.println();
n=0;
}
System.out.println();
}
}
运行结果为:
** prime numbers between 100 and 200 **
101 103 107 109 113 127 131 137 139 149
151 157 163 167 173 179 181 191 193 197
199
该例通过一个嵌套的for语句来实现。
3.异常处理语句
在Java程序中,用try-catch(或try-catch-finally)语句来抛出、捕捉和处理异常。
try-catch-finally语句的语法格式是:
try
{
可能抛出异常的语句模块;
}
catch (异常类型1)
{
处理异常类型1语句;
}
catch (异常类型2)
{
处理异常类型2语句;
}
……
catch (异常类型n)
{
处理异常类型n语句;
}
finally
{
无论是否抛出异常都要执行的语句;
}
所有可能抛出异常的语句都放入try模块中。try模块中的语句是程序正常流程要执行的语句,如果像前面程序设计例子那样没有使用try模块,则除了系统定义的异常外,语句执行过程中出现的其他异常不会被抛出。
catch模块主要负责对抛出的异常做相应的处理,每一模块负责一种类型的异常。finally模块中的语句是必须执行的语句。无论try模块中是否抛出异常,finally模块中的语句都要被执行。这个模块是可选的。如果设计了finally模块,通常在这个模块中做一些资源回收的工作。
4.注释语句
Java中可以采用三种注释方式:
(1)∥ 用于单行注释。注释从∥开始,终止于行尾。
(2)/*…*/用于多行注释。注释从/*开始,到*/结束,且这种注释不能互相嵌套。
(3)/**…*/是Java所特有的doc注释。它以/**开始,到*/结束。这种注释主要是为支持JDK工具javadoc而采用的。javadoc能识别注释中用标记@标识的一些特殊变量,并把doc注释加入它所生成的HTML文件。
3.2.4 面向对象程序设计
在传统的结构化程序设计中,数据和对数据的操作是相分离的。Java语言是优秀的面向对象程序设计语言,它将数据以及对数据的处理操作“封装”到一个类中,用“类”或“接口”这些较高层次的概念来表达应用问题,类的实例就是对象。
面向对象中最重要的思想就是类,类是模板,从类中构造一个对象,即创建了一个类的实例。(类好比一个建材市场,其中有许多子类——各种各样的装饰材料,而装修的房子就要选择需要的材料,为了建立程序,必须选择需要的类)这个比喻可以很形象的解释类是什么。
在面向对象程序设计中,我们将问题空间中的元素以及他们在方案空间中的表示物称作对象(object)。所有的东西都是对象。程序是一大堆对象的集合,他们通过消息传递,各个对象之间知道要做些什么。每个对象都分配有自己的存储空间,可容纳其他对象。每个对象都有一个类型。同一类的所有对象能接收相同的消息。而所有的编程语言的最终目的是提供一种抽象方法。我们向对象发出请求是通过它的接口定义的,对象的类型决定了它的接口形式。
1.Java中的类
(1)类的基本概念
Java程序的基本单位是类,类的实例就是对象,或者说对象是类定义的数据类型的变量。建立类之后,就可用它来建立许多你需要的对象。Java把每一个可执行的成分都变成类。
类的定义形式如下:
[decoration]class classname [extends superclassname]
{
……
}
这里,classname和superclassname必须是合法的标识符。类名的英文单词的首字母最好要大写,若由多个单词组成,则每个单词的首字母都要大写。关键词extends用来表明classname是superclassname派生的子类。
在类定义的开始与结束处必须使用花括号。例如建立一个长方形类,那么可以用如下代码:
public class Rectangle
{
......
}
(2)类的基本组成
一个类中通常都包含数据与函数两种类型的元素,一般把它叫做属性和成员函数,在很多时候也把成员函数称为方法(method)。将数据与方法通过类紧密结合在一起,就形成了现在非常流行的封装的概念。
class <classname>
<member data declarations>
<member function declarations>
(3)类的实例创建
矩形类Rectangle中,如果想把矩形的相关信息写入类,如:width, height。现在,类的定义如下所示:
public class Retangle
{
int width, height;
Retangle(){
//构造方法
}
void setWidth(int width1){
width=width1;
}
void setHeight(int height1){
height=height1;
}
String getWidth(){
return width;
}
String getHeight(){
return height;
}
}
在类的定义中,与类名同名的方法称为构造方法,构造方法主要用于在创建对象的过程中初始化对象的成员变量。该类中定义了2个以set为前缀的方法,主要用于设置当前对象的变量值。另外还定义了2个以get为前缀的方法,主要用于返回当前对象的变量值。
2.JAVA中的对象
当创建了自己的类之后,通常需要使用它来完成某种工作。可以通过定义类的实例——对象来实现这种需求。
对象是通过new来创建,例如上例中实现成员函数如下:Rectangle myrect=new Rectangle(),当然,此时对象myrect并没有做任何什么事;它只保存了矩形的长和宽的信息。有了对象以后,我们怎样使用对象内部的数据呢?下面是几个例子:
myrect.width=10;
myrect.height=20;
类的成员函数也是用“.”运算符来被引用的。例如
myrect.setWidth(20);
3.JAVA中的包
一旦你创建了一个类,并想重复地使用它,那么把它放在一个包中将是非常有效的,包(package)是一组类的集合,例如,Java本身提供了许多包,如java.io和java.lang,它们存放了一些基本类,如System和String。你可以为自己的几个相关的类创建一个包。
把类放入一个包内后,对包的引用可以替代对类的引用。此外,包这个概念也为使用类的数据与成员函数提供了许多方便。没有被public、private修饰的类成员也可以被同一个包中的其它类所使用。这就使得相似的类能够访问彼此的数据和成员函数,而不用专门去做一些说明。
(1)定义一个包
可以用下面的方式去说明一个包:
package PackageName;
比如,你可以把Rectangle类放入一个名为shapes的包中:
package shapes
此后,当用javac来编译这个文件时,将会在当前路径下得到一个字节代码文件Rectangle.class。但还需要将它移至java类库所在路径的shapes子目录下(在此之前,必须建立一个名为shapes的子目录),这样以后才能应用shapes包中的Rectangle类。当然可以用-d选项来直接指定文件的目的路径,这样就无需编译后再移动。
包的名称将决定它应放的不同路径。例如用下面的方式来构造一个包。
package myclass.Shapes;
归入该包的类的字节代码文件应放在java的类库所在路径的myclass子目录下。现在包的相对位置已经决定了,但java类库的路径还是不定的。事实上,java可以有多个存放类库的目录,其中的缺省路径为java目录下的lib子目录,可以通过使用-classpath选项来确定当前想选择的类库路径,具体成员函数可参考第三章的内容。除此之外,还可以在CLASSPATH环境变量中设置类库路径。
(2)引用已定义过的包
为了使用已定义过的包,必须使用引用命令import,可以用以下三种方式引用包中的一个类:
①在每一个类名前给出个包名:
Shapes.Rectangle REET=new Shapes.Rectangle(10,20)
②引用类本身:
import Shapes.Reckargle;
③引用整外包:
import Shapes;
3.2.5 多线程
Java提供的多线程功能使得在一个程序里可同时执行多个小任务。因为Java实现的多线程技术,所以比C和C++更键壮。多线程带来的更大的好处是更好的交互性能和实时控制性能。
应用程序在执行过程中存在一个内存空间的初始入口点地址、一个程序执行过程中的代码执行序列以及用于标识进程结束的内存出口点地址,在进程执行过程中的每一时间点均有唯一的处理器指令与内存单元地址相对应。
Java语言中定义的线程(Thread)同样包括一个内存入口点地址、一个出口点地址以及能够顺序执行的代码序列。但是进程与线程的重要区别在于线程不能够单独执行,它必须运行在处于活动状态的应用程序进程中,因此可以定义线程是程序内部的具有并发性的顺序代码流。
Unix操作系统和Microsoft Windows操作系统支持多用户、多进程的并发执行,而Java语言支持应用程序进程内部的多个执行线程的并发执行。多线程的意义在于一个应用程序的多个逻辑单元可以并发地执行。但是多线程并不意味着多个用户进程在执行,操作系统也不把每个线程作为独立的进程来分配独立的系统资源。进程可以创建其子进程,子进程与父进程拥有不同的可执行代码和数据内存空间。而在用于代表应用程序的进程中多个线程共享数据内存空间,但保持每个线程拥有独立的执行堆栈和程序执行上下文(Context)。
基于上述区别,线程也可以称为轻型进程 (Light Weight Process,LWP)。不同线程间允许任务协作和数据交换,使得在计算机系统资源消耗等方面非常廉价。
需要注意的是:在应用程序中使用多线程不会增加 CPU 的数据处理能力。只有在多CPU 的计算机或者在网络计算体系结构下,将Java程序划分为多个并发执行线程后,同时启动多个线程运行,使不同的线程运行在基于不同处理器的Java虚拟机中,才能提高应用程序的执行效率。
1.建立线程
在JAVA中建立线程并不困难,所需要的三要素:执行的代码、代码所操作的数据和执行代码的虚拟CPU。其中虚拟CPU包装在Thread类的实例中,建立Thread对象时,必须提供执行的代码和代码所处理的数据。JAVA的面向对象模型要求程序代码只能写成类的成员方法。数据只能作为方法中的自动(或本地)变量或类的成员存在。这些规则要求为线程提供的代码和数据应以类的实例的形式出现。
2.Java的线程类与Runnable接口
Thread类的构造方法有:
(1)public Thread():创建线程对象。
(2)public Thread(Runnable target):其中target称为被创建线程的目标对象,负责实现Runnable接口。
Thread类有三个有关线程优先级的静态常量:MIN_PRIORITY,MAX_PRIORITY,NORM_PRIORITY。新建线程将继承创建它的线程的优先级,用户可以调用Thread类的setPriority(int a)来修改。其中a的取值可以是三个静态常量中的任何一个。
Thread类主要方法有:
(1)start():启动线程
(2)run():定义线程操作
(3)sleep():使线程休眠
(4)sleep(int millsecond): 以毫秒为单位的休眠时间
(5)sleep(int millsecond,int nanosecond):以纳秒为单位的休眠时间
(6)currentThread():判断谁在占用CPU的线程
3.线程的管理
单线程的程序都有一个main执行体,当程序执行完成,同时结束运行。在Java中要得到相同的应答,必须稍微进行改动。只有当所有的线程退出后,程序才能结束。只要有一个线程一直在运行,程序就无法退出。
线程包括四个状态:new(开始),running(运行),wait(等候)和done(结束)。第一次创建线程时,都位于new状态,在这个状态下,不能运行线程,只能等待。然后,线程由方法start开始或者送往done状态,位于done中的线程已经结束执行,这是线程的最后一个状态。一旦线程位于这个状态,就不能再次出现,而且当JAVA虚拟机中的所有线程都位于done状态时,程序就强行中止。
当前正在执行的所有线程都位于running状态,在程序之间用某种方法把处理器的执行时间分成时间片,位于running状态的每个线程都是能运行的,但在一个给定的时间内,每个系统处理器只能运行一个线程。与位于running状态的线程不同,可以把已经位于waiting状态的线程从一组可执行线程中删除。如果线程的执行被中断,就回到waiting状态。用多种方法能中断一个线程。
线程能被挂起,在系统资源上等候,或者被告知进入休眠状态。该状态的线程可以返回到running状态,也能由方法stop送入done状态。
多线程的几种状态方法如表3.24所示
表3.24 多线程的几种状态方法
方法 |
描述 |
有效状态 |
目的状态 |
Start() |
开始执行一个线程 |
开始 |
运行 |
Stop() |
结束执行一个线程 |
开始或运行 |
结束 |
Sleep(long) |
暂停一段时间(毫秒) |
运行 |
等待 |
Sleep(long,int) |
暂停片刻,(纳秒) |
运行 |
等待 |
Suspend() |
挂起执行 |
运行 |
等待 |
Resume() |
恢复执行 |
等待 |
运行 |
Yield() |
明确放弃执行 |
运行 |
运行 |
4.线程的调度
线程运行的顺序以及从处理器中获得的时间数量主要取决于开发者,处理器给每个线程分配一个时间片,而线程的运行不能影响整个系统。处理器线程的系统可以是抢占式的,也可以是非抢占式的。系统中的所有线程都有自己的优先级,抢占式系统在任何给定的时间内将运行最高优先级的线程。Thread.NORM_PRIORITY是线程的缺省值,Thread类提供了setPriority和getPriority方法来设置和读取优先权,使用setPriority方法能改变Java虚拟机中的线程的重要性,它调用一个整数,类变量Thread.MIN_PRIORITY和Thread.MAX_PRIORITY决定这个整数的有效范围。Java虚拟机是抢占式的,它能保证运行优先级最高的线程。在JAVA虚拟机中我们把一个线程的优先级改为最高,那么他将取代当前正在运行的线程,除非这个线程结束运行或被休眠命令到waiting状态,否者将一直占用所有的处理器的时间。如果遇到两个优先级相同的线程,操作系统可能影响线程的执行顺序。而且这个区别取决于时间片(time slicing)的概念。
管理几个线程并不是真正的难题,对于上百个线程它是怎样管理的呢?当然可以通过循环,来执行每一个线程,但是这显然是冗长、乏味的。JAVA创建了线程组。线程组是线程的一个谱系组,每个组包含的线程数不受限制,能对每个线程命名并能在整个线程组中执行(Suspend)和停止(Stop)这样的操作。
5.死锁以及怎样避免死锁
为了防止数据项目的并发访问,应将数据项目标为专用,只有通过类本身的实例方法的同步区访问。为了进入关键区,线程必须取得对象的锁。假设线程要独占访问两个不同对象的数据,则必须从每个对象各取一个不同的锁。现在假设另一个线程也要独占访问这两个对象,则该进程必须得到这两把锁之后才能进入。由于需要两把锁,编程如果不小心就可能出现死锁。假设第一个线程取得对象A的锁,准备取对象B的锁,而第二个线程取得了对象B的锁,准备取对象A的锁,两个线程都不能进入,因为两者都不能离开进入的同步块,即两者都不能放弃目前持有的锁。避免死锁要认真设计。线程因为某个先决条件而受阻时,如需要锁标记时,不能让线程的停止本身禁止条件的变化。如果要取得多个资源,如两个不同对象的锁,必须定义取得资源的顺序。如果对象A和B的锁总是按字母顺序取得,则不会出现前面提到的饿死条件。
6.Java多线程的优缺点
由于JAVA的多线程功能齐全,各种情况面面俱到,它带来的好处显然易见。多线程带来的更大的好处是更好的交互性能和实时控制性能。当然实时控制性能还取决于系统本身(UNIX,Windows,Macintosh 等),在开发难易程度和性能上都比单线程要好。当然一个好的程序设计语言肯定也难免有不足之处。由于多线程还没有充分利用基本操作系统(OS)的这一功能,对于不同的系统,上面的程序可能会出现截然不同的结果,这使编程者偶会感到迷惑不解。相信不久的将来JAVA的多线程能充分利用到操作系统,变得更加完善。
【例3.15】在学习进程互斥中,有个著名的问题:生产者——消费者问题。这个问题是一个标准的、著名的同时性编程问题的集合:一个有限缓冲区和两类线程,它们是生产者和消费者,生产者把产品放入缓冲区,相反消费者便是从缓冲区中拿走产品。
生产者在缓冲区满时必须等待,直到缓冲区有空间才继续生产。消费者在缓冲区空时必须等待,直到缓冲区中有产品才能继续读取。在这个问题上主要考虑的是:缓冲区满或缓冲区空以及竞争条件(race condition)。
以下是一个含竞争条件的生产者——消费者问题实例。ThreadTest.java代码如下:
import java.io.InterruptedIOException;
/**
*1.制作出基本的生产者、消费者多线程模式
*2.在1的基础上,增加同步
*3.在2的基础上优化同步
*/
public class ThreadTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
Productable p=new Product();
Producer put=new Producer(p);
Consumer get=new Consumer(p);
}
}
//定义产品接口
interface Productable{
void get();
void put(int productID);
boolean isHasProduct();
void reset();
}
//定义产品类
class Product implements Productable{
int productID=0;
private volatile boolean hasProduct=false;
public boolean isHasProduct() {
return this.hasProduct;
}
public void reset() {
this.productID=0;
}
synchronized public void get() {
if(!this.isHasProduct()){
try {
wait();
} catch (InterruptedException e) {
System.out.println("get process interrupted!");
}
}
System.out.println("get : "+this.productID);
this.hasProduct=false;
this.reset();
notify();
}
synchronized public void put(int productID) {
if(this.isHasProduct()){
try {
wait();
} catch (InterruptedException e) {
System.out.println("put process interrupted!");
}
}
this.productID=productID;
System.out.println("put : "+this.productID);
this.hasProduct=true;
notify();
}
}
//定义生产者线程
class Producer implements Runnable{
Productable p;
public Producer(Productable p) {
this.p=p;
new Thread(this,"Producer").start();
}
public void run() {
int i=2;
while(true){
p.put(++i);
}
}
}
//定义消费者类
class Consumer implements Runnable{
Productable p;
public Consumer(Productable p) {
this.p=p;
new Thread(this,"Consumer").start();
}
public void run() {
while(true){
p.get();
}
}
}
有兴趣的读者可以调试一下运行结果。
本章小结
本章学习了JavaScript的语言规则,初步了解了JavaScript事件驱动机制和丰富的对象体系。我们经常会使用JavaScript实现一些动态特效,使网页靓起来,或者实现一些交互,使网页活起来。但要学好JavaScript,还需要阅读大量的JavaScript程序,并通过大量的上机实践来融会贯通。
Java按应用主要分为三大块:
1.J2SE(JAVA 2 Platform,Standard Edition),主要用于桌面程序和Java小程序(Applet)的开发;
2.J2EE(JAVA 2 Platform,Enterprise Edition),主要用于企业级的开发(如电子商务,ERP);
3.J2ME(JAVA 2 Platform,Micro Edition),主要用于手持设备(手机、PDA等)的开发(如手机游戏)。
Java语法组成如下图所示。
图3.9 JAVA语法结构图
课后习题
一.填空题
1.JavaScript是事件驱动的语言,在JavaScript中,鼠标事件一共有六种:________、________、________、________、________、________,键盘事件一共有三种:________、________、________。
2.定义方法时,需要声明其返回的数据类型(如int、boolean之类),当某方法不需要返回数据时,其数据类型声明为:________。
3.定义一double型常量PI,语句代码可以为:________ double PI = 3.14。
4.下列代码不能编译的原因是 ________。
Class A{
Private int x;
Public static void main(String args[])
{
new B();
}
class B{
B(){System.out.println(x);
}
}
}
5.Java中类成员的限定词有以下几种:private, public, ________, ________。其中, ________的限定的范围最大。
6.Java中所有类都是类 ________的子类。
7.Java中的线程由 、代码、数据等三部分组成。
二.选择题
1.Java技术是由下面哪个公司推出的( )
A.Sun Microsystems B.Microsoft
C.IBM D.BEA
2.下面对Java相关的技术叙述正确的是( )
A.Java仅仅是一种编程语言
B.Java只是一种虚拟的平台
C.Java即是开发环境又是开发平台
D.Java就是JavaScript
3.对下面的应用程序叙述正确的是(SCJP题目)( )
public class MyProgram
{ public void main()
{ System.out.println(“Who moved my cheese?”);
}
}
A.该程序没有错误
B.该程序在编译过程中会出错
C.该程序在编译过程中不会出错,运行时才会出错
D.编译和运行都不会出错,但运行时无结果输出
4.下面哪些选项是正确的main方法说明( )
A. public main(String args[])
B. public static void main(String args[])
C. private static void main(String args[])
D. void main()
5.对Java、JavaScript、Visual J++的叙述正确的是:( )
A.Java和JavaScript完全是一回事
B.JavaScript只是对Java语法稍作修改,实际上差别并不大
C.Visual J++是基于Java的一门开发工具,但微软在其中还嵌入了其它一些与Sun的Java不兼容的一些功能
D.Visual J++可用来开发基于sun的JVM所有Java程序
6.以下编译Java程序“A.java”正确的方法是:( )
A.javac A B.javac a.java
C.javac a D.java A.java
7.import,package,class在程序中出现的正确顺序是:( )
A.import package class B.package import class
C.package class import D.import class package
8.给定下面的代码片段()
1) String str = null;
2) if ((str != null) && (str.length() > 10)) {
3) System.out.println("more than 10");
4) }
5) else if ((str != null) & (str.length() < 5)) {
6) System.out.println("less than 5");
7) }
8) else { System.out.println("end"); }
哪些行会导致错误?
A.line 1 B.line 2
C.line 5 D.line 8
三.简答题
1.简述JavaScript能够使用哪几种对象。
2.简述浏览器的内部对象。
3.如何通过javascript判断一个窗口是否已经被屏蔽。
4.简述JavaScript与Java的区别。
5.Java中线程间怎么通讯?什么叫死锁?
四.操作题
1.编写JavaScript程序完成以下功能:弹出窗口询问用户的生日,计算出用户的年龄并显示在浏览器的状态栏上。
2.编写一个JAVA程序让用户从键盘输入一个元音字母,如果输入的不是元音字母,则显示出一个出错信息,类名为GetVoweL。
3.创建一个名为Auto的抽象类,该类包含的数据成员有车的品牌和价格。包含这些成员的set和get方法。setPrice()方法是抽象的。为每个汽车制造商创建两个子类(例如,Ford或Chevy)并且在每个子类里包含合适的setPrice()方法。最后,使用Auto类和子类编写一个程序并显示不同的车的信息。
==============================================================================
本博客已经废弃,不在维护。新博客地址:http://wenchao.ren
我喜欢程序员,他们单纯、固执、容易体会到成就感;面对压力,能够挑灯夜战不眠不休;面对困难,能够迎难而上挑战自我。他
们也会感到困惑与傍徨,但每个程序员的心中都有一个比尔盖茨或是乔布斯的梦想“用智慧开创属于自己的事业”。我想说的是,其
实我是一个程序员
==============================================================================