学习笔记(java)

ztips

tips 赛百空间

赛百空间是由计算机和网络组成的一个信息世界,它是对现实世界的高度浓缩与映射。人们进入赛百空间无非是获取信息与提供信息。

tips applet(小应用程序)

小应用 程序是可以在Internet中传输并在兼容Java的Web浏览器中运行的应用程序。小应用程序实 际上就是小型的Java程序,能像图像文件、声音文件和视频片段那样通过网络动态下载,它与其他文件的重要差别是,小应用程序是一个智能的程序,能对用户的输入作出反应, 并且能动态变化,而不是一遍又一遍地播放同一动画或声音。

tips 字节码

字节码是一套设计用来在Java运行时系统下执行的 高度优化的指令集,该Java运行时系统称为Java虚拟机(JavaVirtual Machine,JVM)。在其标 准形式下,JVM 就是一个字节码解释器。对字节码进行解释是编写真正可移植性程序的最容易的方法。

tips 解释性语言和编译性语言

1.解释性语言的定义

解释性语言的程序不需要编译,在运行程序的时候才翻译,每个语句都是执行的时候才翻译。这样解释性语言每执行一次就需要逐行翻译一次,效率比较低。 现代解释性语言通常把源程序编译成中间代码,然后用解释器把中间代码一条条翻译成目标机器代码,一条条执行。

2.编译性语言的定义

编译性语言写的程序在被执行之前,需要一个专门的编译过程,把程序编译成为机器语言的文件,比如exe文件,以后要运行的话就不用重新翻译了,直接使用编译的结果就行了(exe文件),因为翻译只做了一次,运行时不需要翻译,所以编译型语言的程序执行效率高。

3.比较

(1) 一般,编译性语言的运行效率比解释性语言更高;但是不能一概而论,部分解释性语言的解释器通过在运行时动态优化代码,甚 至能使解释性语言的性能超过编译性语言; (2)编译性语言的跨平台特性比解释性语言差一些;

4. java是 编译性语言还是解释性语言?

java语言应是编译性-解释性语言,因为其同时具备编译性和解释性两种特性; java文件先编译成与平台无关的.class的字节码文件,然后.class的字节码文件既可以在Windows平台上的java虚拟机(JVM). 上进 行解释运行,也可以在Linux平台 上的JVM.上解释运行;而JVM的翻译过程时解释性的,JVM从.class的字节码文件中读出一 条指 令,翻译一条指令,然后执行一条指令, 这个过程就称为java的解释执行;

tips 类库(Class Library)

类库(Class Library)是一个综合性面向对象可重用类型的集合,这些类型包括:接口抽象类和具体。类库可以解决一系列常见编程任务(包括诸如字符串管理、数据收集、数据库连接以及文件访问等任务),还可以解决多种专用开发任务(桌面应用程序WEB应用程序控制台应用程序等)。java

tips 前中后缀表达式

java

一、java语言

第 1 章 java起源

1.1 java的产生

因素

1.而是源于对独立于平台 (也就是体系结构中立)语言的需要,这种语言可创建能够嵌入微波炉、遥控器等各种家 用电器设备的软件。

2.万维网(WWW)因特网由不同的、分布式的系统组成,其中包括各种类型的计算机、操 作系统和CPU。尽管许多类型的平台都可以与因特网连接,但用户仍希望他们能够运行同 样的程序。曾经是一个令人烦恼却无需优先考虑的问题现在变成了急需解决的问题(可移植性语言)。

1.2 java常用语

  • 简单(Simple)

    Java的设计目的是让专业程序员觉得既易学又好用。

  • 安全(Secure)

  • 可移植(Portable)

  • 面向对象(Object-oriented)

    通过对近几十年面向对象软件优点的借鉴,Java设法在纯进化论者的“任何事 物都是一个对象”和实用主义者的“不讨论对象不对象”的论点之间找到了平衡。Java的 对象模型既简单又容易扩展,对于简单数据类型,例如整数,它保持了高性能,但不是对 象。

  • 健壮(Robust)

    因为Java是一种严格的类型语言,它 不但在编译时检查代码,而且在运行时也检查代码。

    面向对象 的异常处理机制

  • 多线程(Multithreaded)

    设计Java的目标之一是为了满足人们对创建交互式网上程序的需要。为此,Java支持多 线程编程,因而你用Java编写的应用程序可以同时执行多个任务。

  • 体系结构中立(Architecture-neutral)

    Java设计者考虑的一个主要问题是程序代码的持久性和可移植性。程序员面临的一个 主要问题是,不能保证今天编写的程序明天能否在同一台机器上顺利运行。操作系统升级、 处理器升级以及核心系统资源的变化,都可能导致程序无法继续运行。Java设计者对这个 问题做过多种尝试,Java虚拟机(JVM)就是试图解决这个问题的。他们的目标是“只要 写一次程序,在任何地方、任何时间该程序永远都能运行”。在很大程度上,Java实现了 这个目标。

  • 解释执行(Interpreted)

  • 高性能(High performance)

  • 分布式(Distributed)

    Java为Internet的分布式环境而设计,因为它处理TCP/IP协议。

  • 动态(Dynamic)

    Java程序带有多种的运行时类型信息,用于在运行时校验和解决对象访问问题。

第 2 章 Java 语言概述

2.1 面向对象编程

2.1.1 两种范型

  • 第一种方法被称为面向过程的模型(process-oriented model)面向过程的模型可认为是代码作用于数据

  • 第二种方式也就是面向对象的编程(object-oriented programming)面向对象的编程围绕它的数据(即对象)和为这个数据严格 定义的接口来组织程序。

2.1.2 抽象

  • 面向对象编程的一个实质性的要素是抽象。人们通过抽象(abstraction)处理复杂性。

  • 使用层级分类是管理抽象的一个有效方法。它允许你根据物理意义将复杂的系统分解为更多更易处理的小块。

2.1.3 面向对象编程的3个原则

  • 封装

    封装(Encapsulation)是将代码及其处理的数据绑定在一起的一种编程机制,该机制 保证了程序和数据都不受外部干扰且不被误用。

    Java封装的基本单元是类。

  • 继承

    继承(Inheritance)是一个对象获得另一个对象的属性的过程。

    继承性与封装性相互作用。如果一个给定的类封装了一些属性,那么它的任何子类将 具有同样的属性,而且还添加了子类自己特有的属性

    新的子类继承它的所有祖先的所有属性。 它不与系统中其余的多数代码产生无法预料的相互作用。

  • 多态

    多态性(Polymorphism,来自于希腊语,表示“多种形态”)是允许一个接口被多个 同类动作使用的特性,具体使用哪个动作与应用场合有关

  • 多态性、封装性与继承性相互作用

    如果用得当,在由多态性、封装性和继承性共同组成的编程环境中可以写出比面向过 程模型环境更健壮、扩展性更好的程序。

2.2 第一个程序

/* 
This is a simple Java program. 
Call this file "Example.java". 
*/ 
class Example { 
    // Your program begins with a call to main(). 
    public static void main(String args[]) { 
        System.out.println("This is a simple Java program."); 
    } 
}

2.2.1 键入程序

在Java中,一个源程序文件被称为一个编译单元(compilation unit)。它是一个包含一 个或多个类定义的文本文件。

2.3 程序块

在Java中,可以将2个或2个以上的语句组成一组,这样的一组语句称为程序块 (Codeblocks)。程序块是通过将所属语句放在花括号中来实现。

2.4 基 本 词 汇

Java 程序由空白分隔符、标识符、注释、文字、运算符、分隔符,以及关键字组成。

2.4.1 空白分隔符(whitespace)

在Java中,空白 分隔符可以是空格,Tab跳格键或是换行符。

2.4.2 标识符(identifiers)

一个标识符可以是大写和小写字母、数字、 下划线、美元符号的任意顺序组合,但不能以一个数字开始。

2.4.3 常量(literal)

在Java中,常量用literal表示。

常量能在任何地方被它所允许的类型使用,代表的是所属类型的一个值。

2.4.4 注释(comments)

Java定义了3种注释的类型。

  • 单行注释(single-line comment)

  • 多行注释 (multiline comment)

  • 文档注释(documentation comment)

    文档注释提供将程序信息 嵌入程序的功能。开发者可以使用javadoc工具将信息取出,然后转换为HTML文件。文档 注释提供了编写程序文档的便利方式。javadoc工具生成的文档几乎人人都看过,因为Sun 的Java API文档库就是这么生成的。

第 3 章 数据类型、变量、数组

3.1 Java语言是强类型语言语言

java中每个变量有类型,每个表达式 有类型,而且每种类型是严格定义的。

3.2 简单数据类型

Java定义了8个简单(或基本)的数据类型:字节型(byte),短整型(short),整型 (int),长整型(long),字符型(char),浮点型(float),双精度型(double),布尔 型(boolean),这些类型可分为4组:

  • 整数:该组包括字节型(byte),短整型(short),整型(int),长整型(long), 它们代表有符号整数。

  • 浮点型数:该组包括浮点型(float),双精度型(double),它们代表有小数精度 要求的数字。

  • 字符:这个组包括字符型(char),它代表字符集的符号,例如字母和数字。

  • 布尔型:这个组包括布尔型(boolean),它是一种特殊的类型,表示真/假值。

简单数据类型代表单值,而不是复杂的对象。Java是完全面向对象的,但简单数据类 型不是。他们类似于其他大多数非面向对象语言的简单数据类型。

3.3 整 数 类 型

3.3.1 字节型(byte)

最小的整数类型是字节型。它是有符号的8位类型,数的范围是-128~127。当你从网 络或文件处理数据流的时候,字节类型的变量特别有用。

3.3.2 短整形(short)

short是有符号的16位类型,数的范围是 –32,768~32,767 。这种类型主要适用于16位 计算机,然而这种计算机现在已经很少见了

3.3.3 整型(int)

最常用的整数类型是int。它是有符号的32位类型,数的范围是-2,147,483,648~ 2,147,483,647。任何时候你的整数表 达式包含byte,short,int及字面量数字,在进行计算以前,所有表达式的类型被提升 (promoted)到整型。

3.3.4 长整型(long)

long是有符号的64位类型,它对于那些整型不足以保存所要求的数值时是有用的。

3.4 浮点型(Floating-Point Types)

3.4.1 单精度浮点型(float)

单精度浮点型(float)专指占用32位存储空间的单精度(single-precision)值。

3.4.2 双精度型(double)浮点型

双精度型,正如它的关键字“double”表示的,占用64位的存储空间。

3.5 字 符

在Java中,存储字符的数据类型是char 。

在C/C++中,char的宽是8位整数。

Java中的char 类型是16位,其范围是0~ 65,536,没有负数的char。

3.5.1 字符字面量

Java用Unicode字符集来表示字符。Java的字符是16位值,可以被转换为整数并可进行 像加或减这样的整数运算。

3.6 布 尔 型

Java有一种表示逻辑值的简单类型,称为布尔型。它的值只能是真或假这两个值中的 一个。

3.6.1 布尔型字面量

布尔型字面量很简单。布尔型字面量仅仅有2个逻辑值,真或假。真值或假值不会改变 任何数字的表示。Java中,真字面量的值不等于1,假字面量的值也不等于0,他们仅仅能 被赋给已定义的布尔变量,或在布尔的运算符表达式中使用。

3.7 变量

变量是Java程序的一个基本存储单元。变量由一个标识符,类型及一个可选初始值的 组合定义。此外,所有的变量都有一个作用域,定义变量的可见性,生存期。

3.7.1 变量的作用域和生存期

方法定义的作用域以它的左大括号开始。

作为一个通用规则,在一个作用域中定义的变量对于该作用域外的程序是不可见(即 访问)的。

外部作用域定义的对象对于内部 作用域中的程序是可见的。但是,内部作用域定义的对象对于外部是 不可见的。

变量在其作用域内被创建,离开其作用域时被撤消。

3.8 类型转换与强制类型转换

3.8.1 Java的自动转换

如果下列2个条件都能满足,那么将一种类型的数据赋给另外一种类型变量时,将执行 自动类型转换(automatic type conversion)

  • 这2种类型是兼容的。

  • 目的类型数的范围比来源类型的大。

当以上2个条件都满足时,拓宽转换(widening conversion)发生。对于拓宽转换,数字类型,包括整数(integer)和浮点(floating-point)类型都是彼此 兼容的,但是,数字类型和字符类型(char)或布尔类型(bollean)是不兼容的。字符类 型(char)和布尔类型(bollean)也是互相不兼容的。

3.8.2 不兼容类型的强制转换

为了完成两种不兼容类型之间的转换,你就必须进行强制类型转换。所谓强制类型转 换只不过是一种显式的类型变换。

格式

(target-type)value

其中目标类型(target-type)指定了要将指定值转换成的类型。

当把浮点值赋给整数类型时一种不同的类型转换发生了:截断(truncation)。

// Demonstrate casts. 
class Conversion { 
    public static void main(String args[]) { 
        byte b; 
        int i = 257; 
        double d = 323.142; 
        System.out.println("\nConversion of int to byte."); 
        b = (byte) i; 
        System.out.println("i and b " + i + " " + b); 
        System.out.println("\nConversion of double to int."); 
        i = (int) d; 
        System.out.println("d and i " + d + " " + i); 
        System.out.println("\nConversion of double to byte."); 
        b = (byte) d;
        System.out.println("d and b " + d + " " + b); 
    } 
}
该程序的输出如下:
Conversion of int to byte. 
i and b 257 1 
Conversion of double to int. 
d and i 323.142 323 
Conversion of double to byte. 
d and b 323.142 67 

让我们看看每一个类型转换。当值257被强制转换为byte变量时,其结果是257除以256 (256是byte类型的变化范围)的余数1。当把变量d转换为int型,它的小数部分被舍弃了。 当把变量d转换为byte型,它的小数部分被舍弃了,而且它的值减少为256的模,即67。

3.9 表达式中类型的自动提升

自动类型提升有好处,但它也会引起令人疑惑的编译错误。例如,这个看起来正确的 程序却会引起问题:

byte b = 50; 
b = b * 2; // Error! Cannot assign an int to a byte!

该程序试图将一个完全合法的byte型的值50*2再存储给一个byte型的变量。但是当表达 式求值的时候,操作数被自动地提升为int型,计算结果也被提升为int型。这样,表达式的 结果现在是int型,不强制转换它就不能被赋为byte型。

3.9.1 类型提升的约定

除了将byte型和shorts型提升到int型以外,Java定义了若干适用于表达式的类型提升规 则(type promotion rules)。首先,如刚才描述的,所有的byte型和short型的值被提升到 int 型。其次,如果一个操作数是long型,整个表达式将被提升到long型;如果一个操作数是float 型,整个表达式将被提升到float型;如果有一个操作数是double型,计算结果就是double型。

3.10 数组

数组(array)是相同类型变量的集合,可以使用共同的名字引用它。

3.10.1 一维数组(one-dimensional array)

通用的一维数组的声明格式是: type var-name[ ] 或 type[ ] var-name; (定义了一个数组,但是没有为其分配内存)

变成实际的、物理上存在的数组(new 方法):array-var = new type[size];

数组可以在声明时被初始化。这个过程和简单类型初始化的过程一样。数组的初始化 (array initializer)就是包括在花括号之内用逗号分开的表达式的列表。如:

int[] month_days = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

3.10.2 多维数组(multidimensional arrays)

多维数组(multidimensional arrays)实际上是数组的数组。

3.11 字符串的简单介绍

字 符串(String)在Java中被定义为对象,要完全理解它需要理解几个和对象相关的特征。

字符串(String)类型被用来声明字符串变量。你也可以定义字符串数组。一个被引号 引起来的字符串字面量可以被分配给字符串变量。

第 4 章 运 算 符

Java有4大类运算符:算术运算、位运算、关系运算和 逻辑运算。

4.1 算术运算符

算术运算符的运算数必须是数字类型。算术运算符不能用在布尔类型上,但是可以用 在char类型上,因为实质上在Java中,char类型是int类型的一个子集。

4.1.1 基本算术运算符

基本算术运算符——加、减、乘、除可以对所有的数字类型操作。减运算也用作表示 单个操作数的负号。记住对整数进行“/”除法运算时,所有的余数都要被舍去。

4.1.2 模运算符

模运算符%,其运算结果是整数除法的余数。它能像整数类型一样被用于浮点类型(这 不同于C/C++,在C/C++中模运算符%仅仅能用于整数类型)。

4.1.3 算术赋值运算符

Java提供特殊的算术赋值运算符,该运算符可用来将算术运算符与赋值结合起来。

Java的二元(即需要两个操作数的)运算符都适用。其语句格式为:

var= var op expression;

可以被重写为:

var op= expression;

这种赋值运算符有两个好处。第一,它们比标准的等式要紧凑。第二,它们有助于提 高Java的运行效率。

4.2 位 运 算 符

Java定义的位运算(bitwise operators)直接对整数类型的位进行操作,这些整数类型 包括long,int,short,char,and byte。表4-2列出了位运算:

4.2.1 位逻辑运算符

位逻辑运算符有“与”(AND)、“或”(OR)、“异或(XOR)”、“非(NOT)”, 分别用“&”、“|”、“^”、“~”表示,4-3表显示了每个位逻辑运算的结果。

4.2.2 左移运算符

左移运算符<<使指定值的所有位都左移规定的次数。它的通用格式如下所示:

value << num

这里,num指定要移位值value移动的位数。也就是,左移运算符<<使指定值的所有位 都左移num位。每左移一个位,高阶位都被移出(并且丢弃),并用0填充右边。

每次左移都可以使原来的操作数翻倍

4.2.3 右移运算符

右移运算符>>使指定值的所有位都右移规定的次数。它的通用格式如下所示:

value >> num

这里,num指定要移位值value移动的位数。也就是,右移运算符>>使指定值的所有位 都右移num位。

将值每右移一次,就相当于将该值除以2并且舍弃了余数。

右移时,被移走的最高位(最左边的位)由原来最高位的数字补充。例如,如果要移 走的值为负数,每一次右移都在左边补1,如果要移走的值为正数,每一次右移都在左边补 0,这叫做符号位扩展(保留符号位)(sign extension),在进行右移操作时用来保持负数 的符号。

4.2.4 无符号右移

移位后总是在高位(最左边)补0。这就是人们所说的无符号移动(unsigned shift)。

无符号右移运算符>>>

4.3 关系运算符

关系运算符(relational operators)决定值和值之间的关系。

4.4 布尔逻辑运算符

布尔逻辑运算符的运算数只能是布尔型。而且逻辑运算的结果也是布尔类型

4.4.1 短路(short-circuit)逻辑运算符

如果运 用||和&&形式,而不是|和&,那么一个运算数就能决定表达式的值,Java的短路版本就不 会对第二个运算数求值,只有在需要时才对第二个运算数求值。

第 5 章 程序控制语句

编程语言使用控制(control)语句来产生执行流,从而完成程序状态的改变,如程序 顺序执行和分支执行。Java的程序控制语句分为以下几类:选择,重复和跳转。根据表达式 结果或变量状态选择(Selection)语句来使你的程序选择不同的执行路径。

5.1 Java的选择语句

Java支持两种选择语句:if语句和switch语句。

5.1.1 if语句

嵌套 if 语句 嵌套(nested)if语句是指该if语句为另一个if或者else语句的对象。当你使用嵌套if语句时,需记住的要点就是:一个else语句总是对应着和它 在同一个块中的最近的if语句,而且该if语句没有与其他else语句相关联。

5.1.2 switch语句

switch语句是Java的多路分支语句。它提供了一种基于一个表达式的值来使程序执行不 同部分的简单方法。

格式

switch (expression) { 
    case value1: 
        // statement sequence 
        break; 
    case value2: 
        // statement sequence 
        break; 
    
      . 
      . 
    case valueN: 
        // statement sequence 
        break; 
    default: // 可选
        // default statement sequence 
}

表达式expression必须为byte,short,int或char类型。每个case语句后的值value必须是 与表达式类型兼容的特定的一个常量(它必须为一个常量,而不是变量)。重复的case值 是不允许的。

break语句是可选的。如果你省略了break语句,程序将继续执行下一个case语句。有时 需要在多个case语句之间没有break语句。

嵌套 switch 语句 可以将一个switch语句作为一个外部switch语句的语句序列的一部分,这称为嵌套 switch语句。

5.2 循 环 语 句

Java的循环语句有for,while和 do-while。

5.2.1 while语句

while语句是Java最基本的循环语句。当它的控制表达式是真时,while语句重复执行一 个语句或语句块。它的通用格式如下:

while(condition) { 
    // body of loop 
}

条件condition可以是任何布尔表达式。只要条件表达式为真,循环体就被执行。当条 件condition为假时,程序控制就传递到循环后面紧跟的语句行。

5.2.2 do-while循环

do-while循环总是执行它的循环体至少一 次,因为它的条件表达式在循环的结尾。它的通用格式如下:

do { 
    // body of loop 
} while (condition); 

5.2.3 for循环

for循环是一个功能强大且形式 灵活的结构。下面是for循环的通用格式:

for(initialization; condition; iteration) { 
    // body 
}

在 for 循环中声明循环控制变量,控制for循环的变量经常只是用于该循环,而不用在程序的其他地方。

当你在for循环内声明变量时,必须记住重要的一点:该变量的作用域在for语句执行后就 结束了(因此,该变量的作用域就局限于for循环内)。

5.3 跳 转 语 句

Java 支持 3 种跳转语句:break,continue和return。这些语句把控制转移到程序的其 他部分。

注意:除了这里讨论的跳转语句,Java还支持另一种能改变你程序执行流程的方 法:通过异常处理。异常处理提供了一种结构化的方 法,通过该方法可以使你的程 序捕获并处理运行时刻错误。它由下列五个关键字来控制:try,catch,throw, throws,和finally。 实质上,异常处理机制允许你的程序完成一个非局部的分 支跳转。

5.3.1 使用break语句

在Java中,break语句有3种作用。第一,你已经看到,在switch语句中,它被用来终止 一个语句序列。第二,它能被用来退出一个循环。第三,它能作为一种“先进”的goto 语 句来使用。

在一系列嵌套循环中使用break语句时,它将仅仅终止最里面的循环。

标签break语句的通用格式如下所示:

break label;

tips:这里结束的就是标签label所代表的代码块

这里,标签label是标识代码块的标签。当这种形式的break执行时,控制被传递出指定 的代码块。被加标签的代码块必须包围break语句,但是它不需要是直接的包围break的块。 这意味着你可以使用一个加标签的break语句退出一系列的嵌套块。但是你不能使用break 语句将控制传递到不包含break语句的代码块。 要指定一个代码块,在其开头加一个标签即可。标签(label)可以是任何合法有效的 Java标识符后跟一个冒号。一旦你给一个块加上标签后,你就可以使用这个标签作为break 语句的对象了。这样做会使执行在加标签的块的结尾重新开始。

例如,下面的程序示例了 3 个嵌套块,每一个都有它自己的标签。break语句使执行向前跳,调过了定义为标签second 的代码块结尾,跳过了2个 println ( )语句。

// Using break as a civilized form of goto. 
class Break { 
    public static void main(String args[]) { 
        boolean t = true; 
        first: { 
            second: { 
                third: { 
                    System.out.println("Before the break."); 
                    if(t) break second; // break out of second block 
                    System.out.println("This won't execute"); 
                } 
                System.out.println("This won't execute"); 
            } 
            System.out.println("This is after second block."); 
        } 
    } 
}
运行该程序,产生如下的输出:
    Before the break. 
    This is after second block. 

记住如果一个标签不在包围break的块中定义,你就不能break到该标签。例如,下面的 程序就是非法的,且不会被编译:

// This program contains an error. 
class BreakErr { 
    public static void main(String args[]) { 
        one: for(int i=0; i<3; i++) { 
            System.out.print("Pass " + i + ": "); 
        } 
        for(int j=0; j<100; j++) { 
            if(j == 10) break one; // WRONG 
            System.out.print(j + " "); 
        } 
    } 
}

因为标签为one的循环没有包围break语句,所以不能将控制传递到该块。

5.3.2 使用continue语句

有时强迫一个循环提早反复是有用的。也就是,你可能想要继续运行循环,但是要忽 略这次重复剩余的循环体的语句。

5.3.3 使用return语句

return语句用来明确地从一个方法返回。也就是,return语 句使程序控制返回到调用它的方法。

第 6 章 介 绍 类

类是Java的核心和本质。它是Java语言的基础,因为类定义了对象的本性。

一个类定义一个新的数据类型。

6.1 类 基 础

6.1.1 类的通用格式

使用关键字class来创建类。在这一点上,类实际上被限制在它的完全格式中。类可以 (并且常常)是一个组合体。类定义的通用格式如下所示:

class classname { 
    type instance-variable1; 
    type instance-variable2; 
    // ... 
    type instance-variableN; 
    type methodname1(parameter-list) { 
        // body of method 
    } 
    type methodname2(parameter-list) { 
        // body of method 
    } 
    // ... 
    type methodnameN(parameter-list) { 
        // body of method 
    }
}

在类中,数据或变量被称为实例变量(instance variables),代码包含在方法(methods) 内。定义在类中的方法和实例变量被称为类的成员(members)。

注意类的通用格式中并没有指定main()方法。Java类不 需要main( )方法。main()方法只是在定义您程序的起点时用到。而且,Java小应用程序也不 要求main( )方法。

6.2 声 明 对 象

6.2.1 深入研究new运算符

理解new运算符是在运行期间为对象分配内存的是很重要的。

类创建一种新的数据类型,该种类型能被用来 创建对象。

6.3 给对象引用变量赋值

注意:当你将一个对象引用赋值给另一个对象引用时,你并没有创建该对象的一 个拷贝,而是仅仅对引用的一个拷贝。

6.4 方 法

方法一般的形式:

type name(parameter-list) { 
// body of method 
}

其中,type指定了方法返回的数据类型。这可以是任何合法有效的类型,包括你创建 的类的类型。如果该方法不返回任何值,则它的返回值type必须为void 。方法名由name指 定。除了被当前作用域中的其他项使用的标识符以外,方法名可以是任何合法的标识符。 parameter-list (自变量列表)是一系列类型和标识符对,用逗号分开。自变量本质上是变 量,它接收方法被调用时传递给方法的参数值。如果方法没有自变量,那么自变量列表就 为空。

6.4.1 加入带自变量的方法

区分自变量(parameter)和参数(argument)这两个术语是很重要的。自变量是方法 定义的一个变量,当方法被调用时,它接收一个值。例如在square()中,i就是一个自变量。 参数是当一个方法被调用时,传递给该方法的值。

6.5 构 造 函 数

构造函数(constructor)在对象创建时初始化。

构 造函数看起来有点奇怪,因为它没有任何返回值,即使是void型的值也不返回。这是因为 一个类的构造函数内隐藏的类型是它自己类的类型。

如果你不显式为类定义一个构造函数,Java将为该类 创建一个默认的构造函数。

6.6 this关键字

this可以在 引用当前对象的所有方法内使用。也就是,this总是调用该方法对象的一个引用。你可以在 当前类的类型所允许对象的任何地方将this作为一个引用。

6.7 垃 圾 回 收

垃圾回收( garbage collection)技术,它是这样工作的:当一个对象的引用不存 在时,则该对象被认为是不再需要的,它所占用的内存就被释放掉。

6.8 finalize( )方法

Java提供了被称为收尾(finalization)的机制。使用该机制 你可以定义一些特殊的操作,这些操作在一个对象将要被垃圾回收程序释放时执行。 要给一个类增加收尾(finalizer),你只要定义finalize ( )方法即可。Java回收该类的一 个对象时,就会调用这个方法。

finalize()方法的通用格式如下:

protected void finalize( ) 
{ 
// finalization code here 
}  

6.9 一个堆栈类

下面是一个叫做Stack的类,实现整数的堆栈。

// This class defines an integer stack that can hold 10 values. 
class Stack { 
    int stck[] = new int[10]; 
    int tos; 
    // Initialize top-of-stack 
    Stack() { 
        tos = -1; 
    } 
    // Push an item onto the stack 
    void push(int item) { 
        if(tos==9) 
            System.out.println("Stack is full."); 
        else 
            stck[++tos] = item; 
    } 
    // Pop an item from the stack 
    int pop() { 
        if(tos < 0) { 
            System.out.println("Stack underflow."); 
            return 0; 
        } 
        else 
            return stck[tos--]; 
    } 
}

第 7 章 进一步研究方法和类

在Java中,同一个类中的2个或2个以上的方法可以有同一个名字,只要它们的参数声 明不同即可。在这种情况下,该方法就被称为重载(overloaded)

在一些情况下,Java的自动类型转换也适用于重载方法 的自变量。

只有在找不到精确匹配时,Java的自动转换才会起作用。

7.1 参数是如何传递的

总的来说,计算机语言给子程序传递参数的方法有两种。第一种方法是按值传递 (call-by-value)。这种方法将一个参数值(value)复制成为子程序的正式参数。这样,对 子程序的参数的改变不影响调用它的参数。第二种传递参数的方法是引用调用 (call-by-reference)。在这种方法中,参数的引用(而不是参数值)被传递给子程序参数。 在子程序中,该引用用来访问调用中指定的实际参数。这样,对子程序参数的改变将会影 响调用子程序的参数。

注意:当一个简单类型传递给一个方法时,使用按值传递。对象传递则按引用传 递。

7.2 返 回 对 象

既然所有的对象用关键字new动态地分配内存,你不 必担心一个对象会出范围,因为它被其创建的方法终止。只要你程序中有它的一个引用, 该对象将会继续存在。当没有该对象的引用时,在下一次垃圾回收发生时该对象将被回收。

7.3 递 归

在Java编程中,递归 是允许方法调用自身调用的属性。调用自身的方法称为是递归的(recursive)。

当一个方法调用它自身的时候,堆栈就会给新的局部变量和自变量分配内存,方法代 码就带着这些新的变量从头执行。递归调用并不产生方法新的拷贝。只有参数是新的。每 当递归调用返回时,旧的局部变量和自变量就从堆栈中清除,运行从方法中的调用点重新 开始。

对一个方法太多的递归调用会引起堆栈崩溃。因为自变量和局部变量的 存储都在堆栈中,每次调用都创建这些变量新的拷贝,堆栈有可能被耗尽。如果发生这种 情况,Java的运行时系统就会产生异常。但是,除非递归子程序疯狂运行,否则你大概不 会担心这种情况。

递归的主要优点在于:某些类型的算法采用递归比采用迭代算法要更加清晰和简单。 例如快速排序算法按照迭代方法是很难实现的。还有其他一些问题,特别是人工智能问题, 就依赖于递归提供解决方案。

7.4 介绍访问控制(access control)

一个成员如何被访问取决于修改它的声明的访问指示符(access specifier)。

Java的访问指示符有public(公共的,全局的)、private(私有的,局部的)、和protected (受保护的)。Java也定义了一个默认访问级别。指示符protected仅用于继承情况中。

当一个类成员被public指示符修饰时,该成员可以 被你的程序中的任何其他代码访问。当一个类成员被指定为private时,该成员只能被它的 类中的其他成员访问。

7.5 理解static

如果一个成员被声明为static,它就能够在它的类的任何对象创建之前被访问,而不必引用 任何对象。你可以将方法和变量都声明为static。static成员的最常见的例子是main( )。因为 在程序开始执行时必须调用main(),所以它被声明为static。

声明为static的变量实质上就是全局变量。当声明一个对象时,并不产生static变量的拷 贝,而是该类所有的实例变量共用同一个static变量。

声明为static的方法有以下几条限制:

  • 它们仅能调用其他的static方法。

  • 它们只能访问static数据。

  • 它们不能以任何方式引用this或super

如果你需要通过计算来初始化你的static变量,你可以声明一个static块,Static块仅在该 类被加载时执行一次。

如果你希望从类外面调用一个static方法,你可 以使用下面通用的格式:

classname.method( )

一个static变量可以以同样的格式来访问

7.6 介绍final

一个变量可以声明为final,这样做的目的是阻止它的内容被修改。这意味着在声明final 变量的时候,你必须初始化它(在这种用法上,final类似于C/C++中的const)。

7.7 介绍嵌套类和内部类

在另一个类中定义的类就是嵌套类(nested classes)。嵌套类的范围由装入它的类的范 围限制。这样,如果类B被定义在类A之内,那么B为A所知,然而不被A的外面所知。嵌套 类可以访问嵌套它的类的成员,包括private成员。但是,包围类不能访问嵌套类的成员。

嵌套类一般有2种类型:前面加static标识符的和不加static标识符的。一个static的嵌套 类有static修饰符。因为它是static,所以只能通过对象来访问它包围类的成员。

嵌套类最重要的类型是内部类(inner class)。内部类是非static的嵌套类。它可以访问 它的外部类的所有变量和方法,它可以直接引用它们,就像外部类中的其他非static成员的 功能一样。

一个嵌套类和 其他任何另外的编程元素没有什么不同:它仅仅在它的包围范围内是可知的。

内部 类的成员只有在内部类的范围之内是可知的,而且不能被外部类使用。

7.8 探索String类

String类包含许多操作字符串的方法。例如下面就是其中一些。你可以用equals()来检 验两个字符串是否相等。你可以调用方法length()来获得一个字符串的长度。你可以调用 charAt()来获得一个字符串指定索引的字符。这三个方法的通用格式如下所示:

boolean equals(String object) 
int length( ) 
char charAt(int index)

7.9 使用命令行参数

命令行参数是程序执行时在命令行中紧跟在程序名后的 信息。在Java程序中访问命令行参数是相当容易的——它们作为字符串存储在传递给main() 的String数组中。

注意:所有的命令行参数都是以字符串的形式传递的。

第 8 章 继 承

在Java术语学中,被继承的类叫超类 (superclass)或 父类(直接继承),继承超类的类叫子类(subclass)

8.1 继承的基础

继承一个类,只要用extends关键字把一个类的定义合并到另一个中就可以了。

Java不支持多超类的继承

8.1.1 成员的访问和继承

尽管子类包括超类的所有成员,它不能访问超类中被声明成private的成员。

8.1.2 超类变量可以引用子类对象

当一个子类对象的引用被赋给一个超类引用变量时,你只能访问超类定义的对 象的那一部分。

8.2 使用super

任何时候一个子类需要引用它直接的超类,它可以用关键字super来实现。

8.2.1 使用super调用超类构造函数

子类可以调用超类中定义的构造函数方法,用super的下面形式:

super(parameter-list);

这里,parameter-list定义了超类中构造函数所用到的所有参数。

既然构造函数可以被重载,可以用超类定义 的任何形式调用super( ),执行的构造函数将是与所传参数相匹配的那一个。

8.2.2 Super的第2种用法

Super的第2种形式,除了总是引用它所在子类的超类,它的行为有点像this。这种用法 有下面的通用形式:

super.member
这里,member既可以是1个方法也可以是1个实例变量。

Super的第2种形式多数是用于超类成员名被子类中同样的成员名隐藏的情况。

8.3 创建多级类层次

给定三个类A,B和C。C是B的一个子类,而B又是A的 一个子类。当这种类型的情形发生时,每个子类继承它的所有超类的属性。

super( )总是引用子类最接近的超类的构造函数。

8.4 何时调用构造函数

在类层次结构中,构造函数以派生的次序调用,从超类到子类。而且,尽 管super( )必须是子类构造函数的第一个执行语句,无论你用到了super( )没有,这个次序不 变。

因为超类不知道任何子类的信 息,任何它需要完成的初始化是与子类的初始化分离的,而且它可能是完成子类初始化的 先决条件。因此,它必须最先执行。

8.5 方 法 重 写

类层次结构中,如果子类中的一个方法与它超类中的方法有相同的方法名和类型声明, 称子类中的方法重写(override)超类中的方法。从子类中调用重写方法时,它总是引用子 类定义的方法。

8.6 动态方法调度

动态方法调度(dynamic method dispatch)。动态方法调度是一种在运行时而不是编译时调用重写方法的机制。动态方法调 度是很重要的,因为这也是Java实现运行时多态性的基础。

8.7 使用抽象类

声明一个抽象类,只需在类 声明开始时在关键字class前使用关键字abstract。抽象类没有对象。也就是说,一个抽象类 不能通过new操作符直接实例化。

因为Java的运行时多态是通过使用超类引用实现的,所以尽管抽象类不能用来实例化, 它们可以用来创建对象引用。这样,创建一个抽象类的引用是可行的,这样它可以用来指 向一个子类对象。

8.8 继承中使用final

8.8.1 使用final阻止重写

尽管方法重写是Java的一个最强大的特性,有些时候你希望防止它的发生。不接受方 法被重写,在方法前定义final修饰符。声明成final的方法不能被重写。

8.8.2 使用final阻止继承

有时你希望防止一个类被继承。做到这点只需在类声明前加final。声明一个final类含 蓄的宣告了它的所有方法也都是final。你可能会想到,声明一个既是abstract的又是final的 类是不合法的,因为抽象类本身是不完整的,它依靠它的子类提供完整的实现。

8.9 Object类

有一种由Java定义的特殊的类Object。所有其他的类都是Object的子类。也就是说, Object是所有其他类的超类。。这意味着一个Object类型的引用变量可以引用其他任何一个类 的对象。同样,因为数组像类一样执行,Object类型变量可以引用任何数组。

Object定义了下面的方法,意味着它们可以被用于任何对象,如表8-1所示。

(1)clone方法

保护方法,实现对象的浅复制,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常。

(2)getClass方法

final方法,获得运行时类型。

(3)toString方法

该方法用得比较多,一般子类都有覆盖。

(4)finalize方法

该方法用于释放资源。因为无法确定该方法什么时候被调用,很少使用。

(5)equals方法

该方法是非常重要的一个方法。一般equals和==是不一样的,但是在Object中两者是一样的。子类一般都要重写这个方法。

(6)hashCode方法

该方法用于哈希查找,重写了equals方法一般都要重写hashCode方法。这个方法在一些具有哈希功能的Collection中用到。

一般必须满足obj1.equals(obj2)==true。可以推出obj1.hash- Code()==obj2.hashCode(),但是hashCode相等不一定就满足equals。不过为了提高效率,应该尽量使上面两个条件接近等价。

(7)wait方法

wait方法就是使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。wait()方法一直等待,直到获得锁或者被中断。wait(long timeout)设定一个超时间隔,如果在规定时间内没有获得锁就返回。

调用该方法后当前线程进入睡眠状态,直到以下事件发生。

(1)其他线程调用了该对象的notify方法。

(2)其他线程调用了该对象的notifyAll方法。

(3)其他线程调用了interrupt中断该线程。

(4)时间间隔到了。

此时该线程就可以被调度了,如果是被中断的话就抛出一个InterruptedException异常。

(8)notify方法

该方法唤醒在该对象上等待的某个线程。

(9)notifyAll方法

该方法唤醒在该对象上等待的所有线程。

getClass( ),notify( ),notifyAll( )和wait( )方法被定义成final。

第 9 章 包 和 接 口

包和接口。包(package)是类的容器, 用来保存划分的类名空间。例如,一个包允许你创建一个名为List的类,你可以把它保存在 你自己的包中而不用考虑和其他地方的某个名为List的类相冲突。包以分层方式保存并被明 确的引入新的类定义。

接口自己不定义任何实现。尽管它们与抽象类相似,接口有一个特殊的 功能:类可以实现多个接口。与之相反,类只能继承一个超类(抽象类或其他)。

包和接口是Java程序的两个基本组成。一般来说,Java源程序可以包含下面的四个内部部分的任何一个(或所有)。

  • 单个接口声明(可选)

  • 任意数目的引入语句(可选)

  • 单个公共类声明(必须)

  • 对包来说是私有的任意数目的类(可选)

9.1 包

包既是命名机制也是可见度控制机制。 你可以在包内定义类,而且在包外的代码不能访问该类。

9.1.1 定义包

下面是package 声明的通用形式:

 package pkg;  

这里,pkg 是包名。

你可以创建包层次。为做到这点,只要将每个包名与它的上层包名用点号“.”分隔开 就可以了。

9.1.2 理解类路径(CLASSPATH)

类路径告诉javac编译器和java解释器(JVM的一部分)在哪里寻找它们要执行或导入的类。

一般类路径包含这三种项目:

  • 类目录

  • 当前目录,一般用(.)表示

  • JAR文件

9.2 访 问 保 护

类和包都是封装和容纳名称空间和变量及方法范围的方法。包就像盛装类和下级包的 容器。类就像是数据和代码的容器。类是Java的最小的抽象单元。因为类和包的相互影响, Java将类成员的可见度分为四个种类:

  • 相同包中的子类

  • 相同包中的非子类

  • 不同包中的子类

  • 不同包中的非子类

任何声明为public的 内容可以被从任何地方访问。被声明成private的成员不能被该类外看到。如果一个成员不 含有一个明确的访问说明,它对于子类或该包中的其他类是可见的。这是默认访问。如果 你希望一个元素在当前包外可见,但仅仅是元素所在类的子类直接可见,把元素定义成 protected。

表9-1仅适用于类成员。一个类只可能有两个访问级别:默认的或是公共的。如果一个 类声明成public,它可以被任何其他代码访问。如果该类默认访问控制符,它仅可以被相同 包中的其他代码访问。

9.3 引 入 包

下面是import声明的通用形式:

import pkg1[.pkg2].(classname|*);

如果在你用星号形式引用的两个不同包中存在具有相同类名的类,编译器将保持沉默, 除非你试图运用其中的一个。这种情况下,你会得到一个编译时错误并且必须明确的命名 指定包中的类。

9.4 接口(interface)

用关键字interface,你可以从类的实现中抽象一个类的接口。也就是说,用interface, 你可以指定一个类必须做什么,而不是规定它如何去做。接口在语句构成上与类相似,但 是它们缺少实例变量,而且它们定义的方法是不含方法体的。

要实现一个接口,实现接口的类必须创建完整的一套方法。然而,每个类都可以自由的决定它们自己实现的细节。

接口声明中可以声明变量。它们一般是final 和static型的,意思是它们的值不能通过实 现类而改变。它们还必须以常量值初始化。

9.4.1 实现接口

如果一个类实现两个声明了同样方法的接口,那么相同的方法将被其中 任一个接口客户使用。

一个接口引用变量仅仅知道 被它的接口定义声明的方法。

如果一个类包含一个接口但是不完全实现接口定义的方法,那么该类必须定义成 abstract型。

9.4.2 接口可以扩展

接口可以通过运用关键字extends被其他接口继承。

第 10 章 异 常 处 理

异常(exception)是在运行时代码序列中产生一种异常情 况。

10.1 异常处理基础

Java异常是一个描述在代码段中发生的异常(也就是出错)情况的对象。

Java异常处理通过5个关键字控制:try、catch、throw、throws和 finally。

  • throws关键字:异常处理的第一种方式,交给别人处理 作用: 当方法内部抛出异常对象的时候,那么我们就必须处理这个异常对象 可以使用throws关键字处理异常对象,会把异常对象声明抛出给方法的调用者处理(自己不处理,给别人处理),最终交给JVM---》中断处理 使用格式: 在方法声明是使用: 修饰符 返回值类型 方法名(参数列表) throws AAAException,BBBException{ throw new AAAException("产生原因"); throw new BBBException("产生原因"); ... }

    注意: 1.throws关键字必须写在方法什么处 2.throws关键字后边声明的异常必须是Exception或者是Exception的子类 3.方法内部如果抛出了多个异常对象,那么throws后边必须也声明多个异常 如果抛出的多个异常对象有子父类关系,那么直接声明父类异常即可 4.调用了一个声明抛出异常的方法,我们就必须处理声明的异常 要么继续使用throws声明抛出,交给方法的调用者处理,最终交给JVM 要么try...catch自己处理异常

  • try...catch:异常处理的第二种方式,自己处理异常 格式 try{ 可能产生异常的代码 }catch(定义一个异常的变量,用来接收try中抛出的异常对象){ 异常的处理逻辑,产生异常对象之后,怎么处理异常对象 一般在工作中,会把异常的信息记录到一个日志中 } ... catch(异常类名 变量名){ } 注意: 1.try中可能会抛出多个异常对象,那么可以使用多个catch来处理这些异常对象 2.如果try中产生了异常,那么就是执行catch中的异常处理逻辑,执行完毕catch中的处理逻辑,继续执行try...catch之后的代码 如果try中没有产生异常,那么就不会执行catch中的处理逻辑,执行try中的代码,继续执行try...catch之后的代码

  • finally代码块 格式:try{ 可能产生异常的代码 }catch(定义一个异常的变量,用来接收try中抛出的异常对象){ 异常的处理逻辑,产生异常对象之后,怎么处理异常对象 一般在工作中,会把异常的信息记录到一个日志中 } ... catch(异常类名 变量名){ }finally{ 无论是否出现异常都会执行 } 注意: 1.finally不能单独使用,必须和try一起使用 2.finally一般用于资源释放(资源回收),无论程序是否出现异常,最后都要资源释放(IO) 3.如果finally中有return语句,必定返回finally中的语句。我们要避免这种情况

下面是一个异常处理块的通常形式:

try { 
    // block of code to monitor for errors 
} 
catch (ExceptionType1 exOb) { 
    // exception handler for ExceptionType1 
} 
catch (ExceptionType2 exOb) { 
    // exception handler for ExceptionType2 
} 
// ... 
finally { 
    // block of code to be executed before try block ends 
} 

这里,ExceptionType 是发生异常的类型。

10.2 异 常 类 型

所有异常类型都是内置类Throwable的子类。

java.lang.Throwable类是java语言中所有错误或者异常的超类 Exception:编译期异常,进行编译(写代码)java程序出现的问题 RuntimeException:运行期异常,java运行过程中的问题 异常就相当于程序得了一个小毛病,把异常处理掉,程序可以继续执行 Error:错误 错误就相当于程序得了一个无法治愈的毛病,必须修改源代码,程序才能继续执行

10.3 使用try和catch

尽管由Java运行时系统提供的默认异常处理程序对于调试是很有用的,但通常你希望 自己处理异常。这样做有两个好处。第一,它允许你修正错误。第二,它防止程序自动终止。

一旦异常被引发,程序控制由try块转到catch块。执行永远不会从catch块“返回”到try块。

构造catch子句的目的是解决异常情况并且像错误没有发生一样继续运行。

10.3.1 显示一个异常的描述

Throwable重载toString( )方法(由Object定义),所以它返回一个包含异常描述的字符 串。

10.4使用多重catch 语句

当你用多catch语句时,记住异常子类必须在它们任何父类之前使用是很重要的。这是 因为运用父类的catch语句将捕获该类型及其所有子类类型的异常。

10.5 嵌套try语句

Try语句可以被嵌套。也就是说,一个try语句可以在另一个try块内部。每次进入try语 句,异常的前后关系都会被推入堆栈。如果一个内部的try语句不含特殊异常的catch处理程 序,堆栈将弹出,下一个try语句的catch处理程序将检查是否与之匹配。这个过程将继续直 到一个catch语句匹配成功,或者是直到所有的嵌套try语句被检查耗尽。如果没有catch语句 匹配,Java的运行时系统将处理这个异常。

10.7 引发(throw)

Throw语句的通常形式如下:

throw ThrowableInstance;

这里,ThrowableInstance一定是Throwable类类型或Throwable子类类型的一个对象。

有两种 可以获得Throwable对象的方法:在catch子句中使用参数或者用new操作符创建。

程序执行在throw语句之后立即停止;

最紧紧包围的try块用 来检查它是否含有一个与异常类型匹配的catch语句。如果发现了匹配的块,控制转向该语 句;如果没有发现,次包围的try块来检查,以此类推。如果没有发现匹配的catch块,默认 异常处理程序中断程序的执行并且打印堆栈轨迹。

10.8 throws

如果一个方法可以导致一个异常但不处理它,它必须指定这种行为以使方法的调用者 可以保护它们自己而不发生异常。做到这点你可以在方法声明中包含一个throws子句。

下面是包含一个throws子句的方法声明的通用形式:

type method-name(parameter-list) throws exception-list 
{ 
 // body of method 
}

这里,exception-list是该方法可以引发的以有逗号分割的异常列表。

10.9 Java的内置异常

为java.lang实际上被所有的Java程序引入,多 数从RuntimeException派生的异常都自动可用。而且,它们不需要被包含在任何方法的 throws列表中。Java语言中,这被叫做未经检查的异常(unchecked exceptions )。

10.10 创建自己的异常子类

尽管Java的内置异常处理大多数常见错误,你也许希望建立你自己的异常类型来处理 你所应用的特殊情况。这是非常简单的:只要定义Exception的一个子类就可以了(Exception 当然是Throwable的一个子类)。你的子类不需要实际执行什么——它们在类型系统中的存 在允许你把它们当成异常使用。Exception类自己没有定义任何方法。当然,它继承了Throwable提供的一些方法。

10.11 使 用 异 常

异常处理为控制具有很多动态运行时特性的复杂程序提供了一个强大的机制。把try, throw,和catch当成处理错误简洁及程序逻辑上的反常边界条件是很重要的。如果你像多数 程序员一样,那么你可能习惯于在方法失败时返回一个错误代码。在你用Java编程时,你 应该打破这个习惯。当方法可能失败时,引发一个异常。这是处理失败模式的一个更简洁 的方法。 最后说明一点:Java的异常处理语句不应该被当作是一个非本地分支的通常机制,如 果你这样认为,它将困扰你的代码并使代码难于维护。

第 11 章 多线程编程

和其他多数计算机语言不同,Java内置支持多线程编程(multithreaded programming。 多线程程序包含两条或两条以上并发运行的部分。程序中每个这样的部分都叫一个线程 (thread),每个线程都有独立的执行路径

多任务 处理有两种截然不同的类型:

  • 基于进程的:进程(process)本质上是一个执行的 程序。基于进程(process-based) 的多任务处理的特点是允许你的计算机同时运行两 个或更多的程序。

    程序是调度程序所分派的最小代码单位。

  • 基于线程的:

    线程是最小的执行单位。这意味着一 个程序可以同时执行两个或者多个任务的功能。

多进程程序处理“大图片”,而多线程程序处理细节问题。

多线程程序比多进程程序需要更少的管理费用。进程是重量级的任务,需要分配它们 自己独立的地址空间。进程间通信是昂贵和受限的。进程间的转换也是很需要花费的。

线程是轻量级的选手。它们共享相同的地址空间并且共同分享同一个进程。线程 间通信是便宜的,线程间的转换也是低成本的。当Java程序使用多进程任务处理环境时, 多进程程序不受Java的控制,而多线程则受Java控制。

11.1 Java线程模型

Java运行系统在很多方面依赖于线程,所有的类库设计都考虑到多线程。

线程的5种状态

11.1.1 线程优先级

Java给每个线程安排优先级以决定与其他线程比较时该如何对待该线程。线程优先级 是详细说明线程间优先关系的整数。线程的优先级是用来决定何 时从一个运行的线程切换到另一个。这叫“上下文转换”(context switch)。决定上下文转换 发生的规则很简单:

  • 线程可以自动放弃控制。在I/O未决定的情况下,睡眠或阻塞由明确的让步来完成。 在这种假定下,所有其他的线程被检测,准备运行的最高优先级线程被授予CPU。

  • 线程可以被高优先级的线程抢占。在这种情况下,低优先级线程不主动放弃,处理 器只是被先占——无论它正在干什么——处理器被高优先级的线程占据。基本上, 一旦高优先级线程要运行,它就执行。这叫做有优先权的多任务处理。

警告:不同的操作系统下等优先级线程的上下文转换可能会产生错误。

11.1.2 同步性

因为多线程在你的程序中引入了一个异步行为,所以在你需要的时候必须有加强同步 性的方法。举例来说,如果你希望两个线程相互通信并共享一个复杂的数据结构,例如链 表序列,你需要某些方法来确保它们没有相互冲突。

管程(monitor)。管程是一种由C.A.R.Hoare首先定义的控制机制。 你可以把管程想象成一个仅控制一个线程的小盒子。一旦线程进入管程,所有线程必须等 待直到该线程退出了管程。

11.1.3 Thread 类和Runnable 接口

Java的多线程系统建立于Thread类,它的方法,它的共伴接口Runnable基础上。

Thread类定义了好几种方法来帮助管理线程。本章用到的方法如表11-1所示

11.2 主 线 程

当Java程序启动时,一个线程立刻运行,该线程通常叫做程序的主线程(main thread)

主线程的重要性体现在两方面:

  • 它是产生其他子线程的线程

  • 通常它必须最后完成执行,因为它执行各种关闭动作。

尽管主线程在程序启动时自动创建,但它可以由一个Thread对象控制。为此,你必须 调用方法currentThread()获得它的一个引用,currentThread()是Thread类的公有的静态成员。 它的通常形式如下:

static Thread currentThread( ) 

该方法返回一个调用它的线程的引用。一旦你获得主线程的引用,你就可以像控制其 他线程那样控制主线程。

11.3 创 建 线 程

Java定义了两种创建线程方式:

  • 可以继承Thread类。

    实现步骤: 1.创建一个Thread类的子类 2.在Thread类的子类中重写Thread类这种的run方法,去设置线程任务(开启线程要做什么?) 3.创建Thread类的子类对象 4.调用Thread类的方法start方法,开启新的线程,执行run方法 void start():使该线程开始执行;java虚拟机调用该线程的run方法 结果是两个线程并发地运行;当线程(main线程)和另一个线程(创建的新线程,执行run方法)。 多次启动一个线程是非法的,特别是当前线程已经结束执行后,不能再重新启动 java程序属于抢占式调度,那个线程的优先级高,那个线程优先执行;同一个优先级,随机选择一个执行

  • 实现Runnable接口 Runnable接口应该由那些打算通过某一线程执行实例的类来实现。类必须定义一个称为run的无参方法 java.lang.Thread类的构造方法: Thread(Runnable target) 分配新的Thread对象 Thread(runnable target, String name)分配新的Thread对象

    实现步骤: 1.创建一个Runnable接口的实现类 2.在实现类中重写Runnable接口的run方法,设置线程任务 3.创建一个Runnable接口的实现类对象 4.创建Thread类的对象,构造方法中传递Runnable接口的实现类对象 5.调用Thread类中的start方法,开启新的线程执行run方法

    实现Runnable接口创建多线程程序的好处: 1.避免了单继承的局限性 一个类只能继承一个类(一个人只能有一个亲爹),类继承了Thread就不能继承其他的类 实现了Runnable接口还可以继承其他的类,实现其他的接口 2.增强了程序的扩展性,降低了程序的耦合性(解耦) 实现Runnable接口的方式,把设置线程任务和开启新线程进行了分离(解耦) 实现类中,重写run方法:用来设置线程任务 创建Thread类对象,调用start方法,开启新的线程

11.4 使用isAlive()和join()

一个线程如何知道另一线程已经 结束?

有两种方法可以判定一个线程是否结束。

  • 可以在线程中调用isAlive()。这种方法 由Thread定义,它的通常形式如下:

	final boolean isAlive( )

如果所调用线程仍在运行,isAlive()方法返回true,如果不是则返回false。

  • 等待线程结束的更常用的方法是调用join(),描述如下:

final void join( ) throws InterruptedException

作用:让主线程等待(WAITING状态),一直等到其他线程不再活动为止。

11.6 线程优先级

线程优先级被线程调度用来判定何时每个线程允许运行。

理论上,优先级高的线程比 优先级低的线程获得更多的CPU时间。

设置线程的优先级,用setPriority()方法,该方法也是Tread 的成员。

final void setPriority(int level)

这里, level指定了对所调用的线程的新的优先权的设置。 Level的值必须在 MIN_PRIORITY到MAX_PRIORITY范围内。通常,它们的值分别是1和10。

你可以通过调用Thread的getPriority()方法来获得当前的优先级设置。该方法如下:

final int getPriority( )

11.7 线 程 同 步

当两个或两个以上的线程需要共享资源,它们需要某种方法来确定资源在某一刻仅被 一个线程占用。达到此目的的过程叫做同步(synchronization)。

11.7.1 使用同步方法

解决线程安全问题的第一种方案:使用同步代码块 格式: Synchronized(锁对象){ 可能会出现线程安全问题的代码块(访问了共享数据的代码) }

注意: 1.通过代码块中的锁对象,可以使用任意对象 2.必须保证多个线程使用的锁对象是同一个 3.锁对象的作用 把同步代码块锁住,值让线程在同步代码块中执行

解决线程安全问题的第二种方案:使用同步方法 使用步骤: 1.把访问共享数据的代码抽取出来,放到一个方法中 2.在方法上添加synchronized修饰符

格式: 修饰符 synchronized 返回值类型 方法名(参数列表){ 可能会出现线程安全问题的代码块(访问了共享数据的代码)

}

11.8 线程间通信

Java包含了通过wait( ),notify( )和notifyAll( )方法实现的一个进程间通信 机制。这些方法在对象中是用final方法实现的,所以所有的类都含有它们。这三个方法仅 在synchronized方法中才能被调用。尽管这些方法从计算机科学远景方向上来说具有概念的 高度先进性,实际中用起来是很简单的:

Object类中的方法: void wait():在其他线程调用此对象的notify()方法或notifyALL()方法前,导致当前线程等待 void notify():唤醒在此对象监视器是等待的单个线程。 会继续执行wait方法之后的代码

进入到TimeWaiting(计时等待)有两种方式 1.使用sleep(long m)方法,在毫秒值结束之后,线程进入到Runnable/Blocked状态 2.使用wait(long m)方法,wait方法如果在毫秒值结束之后还没有被notify唤醒就会自动醒来,线程进入到Runnable/Blocked状态

唤醒方法: void notify():唤醒在此监视器上等待的单个线程。//如果有多个线程随机唤醒一个 void notifyAll():唤醒在此监视器上等待的所有线程

第 12 章 输入/输出、小应用程序和其他主题

12.1 输入/输出基础

12.1.1 流的概念

流是生产或消费信息的抽象。

12.1.2 字节流和字符流

  • 字节流(byte stream)为处理字节的输入和输出提供了方便的方法。

    字节流由两个类层次结构定义。在顶层有两个抽象类:InputStream 和 OutputStream。 每个抽象类都有多个具体的子类

    • java.io.InputStream:字节输入流

      此抽象类是表示字节输入流的所有超类

      定义了所有子类共性的方法: int read():重输入流中读取数据的下一个字节 int read(byte[] b):从输入流中读取一定输量的字节,并将其存储在缓冲区数组b中 void close():关闭字输入流并释放与该流相关的所有资源。

      java.io.FileInputStream extend InputSteam FileInputStream:文件字节输入流 作用:把硬盘文件中的数据,读取到内存中使用 构造方法: FileInputStream(String name) FileInputStream(File file) 参数:读取文件的数据源 String name:文件的路径 File file:文件 构造方法的作用 1.会创建一个FileInputStream对象 2.会把FileInputStream对象的指定构造方法中要读取的文件

      字节输入流的使用步骤(重点): 1.创建FileInputStream对象,构造方法中绑定要读取的数据源 2.使用FileInputStream对象中的方法read,读取文件 3.释放资源

      字节输入流一次读取多个字节的方法: int read(byte[] b):从输入流中读取一定输量的字节,并将其存储在缓冲区数组b中 明确两件事情: 1.方法的参数byte[]的作用 起到缓冲作用,存储每次读取的的多个字节 数组的长度一般定义为1024(1kb)或者是1024的整数倍 2.方法的返回值int是什么? 每次读取的有效字节个数

      String类的构造方法: String(byte[] bytes):把字节数组转换为字符串 String(byte[] bytes, int offset, int length):把字节数组的一部分转换为字符串 offset:数组多的开始索引 length:转换的字节个数

    • java.io.OutputStream:此抽象类是表示输出字节流的所有类的超类

      定义了一下子类共性的成员方法: public void close():关闭此输出流并释放与此输出流相关的任何系统资源(并在关闭之前先刷新该流) public void flush():刷新此输出流并强制任何缓冲的输出字节被写出 void write(int b):将指定字节写入此文件输出流。 public void write(byte[] b):将b.length字节从指定的字节数组写入此输出流 public void write(byte[] b, int off, int len):从指定的字节数组写入len字节,从偏移量off开始输出到此输出流 public abstract void write(int b):将指定的字节输出流

      java.io.FileOutputStream extend OutputStream FileOutputStream:文件字节输出流 作用:把内存中的数据写入到硬盘的文件中

      构造方法: FileOutputStream(String name):创建一个向具有指定名称的文件写入数据的输出文件流 FileOutputStream(File file):创建一个向指定File对象表示的文件中写入数据的文件输出流 参数:写入数据的目的地 String name:目的地是一个文件的路径 File file:目的地是一个文件 构造方法的作用: 1.创建一个FileOutputStream 2.会根据构造方法中传递的文件/文件路径,创建一个空的文件 3.会把FileOutputStream对象指向创建好的文件

      字节输出流的使用步骤(重点): 1.创建一个FileOutputStream对象,构造方法传递写入数据的目的地 2.调用FileOutputStream对象中的方法write,把数据写入到文件中 3.释放资源(流使用会占用一定的内存,使用完清空,提高程序效率)

      一次写多个字节的方法: public void write(byte[] b):将b.length字节从指定的字节数组写入此输出流 public void write(byte[] b, int off, int len):从指定的字节数组写入len字节,从偏移量off开始输出到此输出流

      追加写/续写:使用两个参数的构造方法 FileOutputStream(String name,boolean append):创建一个向具有指定name的文件中写入数据的输出文件流。 FileOutputStream(File file,boolean append):创建一个向指定File对象表示的文件中写入数据的文件输出流。 参数: String name,File file:写入数据的目的地 boolean append:追加写开关 true:创建对象不会覆盖原文件,继续在文件的末尾追加写数据 false:创建一个新文件,覆盖原文件 写换行:写换行符号(系统不一样,符号就不一样) Windows:\r\n linux:/n mac:/r

  • 字符流(character stream)为字符的输入和输出处理提供了方便。

    字符流类由两个类层次结构定义。顶层有两个抽象类:Reader和Writer。

    • java.io.Reader:字符输入流,是字符输入流的最顶层的父类,定义了一些共性的成员方法,是一个抽象类

      共性的成员方法: int read():读取单个字符并返回。 int read(char[] cbuf):一次读取多个字符,将字符读入数组。 void close():关闭该流并释放与之关联的所有资源。

      java.io.FileReader extends InputStreamReader extender Reader FileReader:文件字符输入流 作用:把硬盘文件中的数据以字符的方式读取到内容中

      构造方法: FileReader(String fileName) FileReader(File file) 参数:读取文件的数据源 String fileName:文件的路径 File file:一个文件 作用: 1.创建一个FileReader对象 2.会把FileReader对象指向要读取的文件

      字符输入流的使用步骤: 1.创建FileReader对象,够着方法中绑定要读取的数据源 2.使用FileReader对象中的方法read读取文件 3.释放资源

    • java.io.writer:字符输出流,是所有字符输出流的最顶层的父类,是一个抽象类

      共性的成员方法: void write(int c):写入单个字符。 void write(char[] cbuf):写入字符组。 abstract void write(char[] cbuf, int off, int len):写入字符数组的摸一部分,off:数组的开始索引,len:写的字符个数。 void write(String str):写入字符串。 void write(String str, int off, int len):写入字符串的某一部分,off:字符串的开始索引,len:写的字符个数。 void flush():刷新该缓冲流。 void close():关闭此流,但要先刷新它。

      java.io.FileWriter extends OutputStreamWriter extends Writer FileWriter:文件字符输出流。 作用:把内存中字符数据写入到文件中

      构造方法: FileWriter(File file):根据给定的File对象构造一个FileWriter对象。 FileWriter(String fileName):根据给定的文件构造一个FileWriter对象。 参数:写入数据的目的地 String fileName:文件的路径 File file:是一个文件

      字符输出流的使用步骤: 1.创建一个FileWriter对象,构造方法中绑定要写入数据的目的地 2.使用FileWriter中的构造方法write,把数据写入到内存缓冲区中(字符装换为字节的过程) 3.使用FileWriter中的方法flush,把内存缓冲区中的数据,刷新到文件中 4.释放资源(会先把内存缓冲区中的数据刷新到文件中)

12.2 小应用程序基础

小应用程序(applet)是访问internet 服务器,在internet上传播的,自动安装的,作为部分Web文档运行的小应用程序。

注意小应用程序没有main()方法,不像Java应用程序,小应用程序不以main()为程序起 始。实际上,大多数小应用程序甚至不含main()方法。相反,当小应用程序类名被传输到 小应用程序阅读器(applet view)或网络浏览器时它开始执行。

  • 小应用程序不一定包含 main( ) 方法。

  • 小应用程序必须在小应用程序阅读器或兼容JAVA的浏览器中运行

  • 用户输入/输出不是由Java的输入/输出流类来完成的。相反,小应用程序运用 AWT提供的界面

12.3 Transient和volatile修饰符

  • Transient:其实这个关键字的作用很好理解,就是简单的一句话:将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会被序列化。

  • volatile:用来确保将变量的更新操作通知到其他线程,当把变量声明为volatile类型后,编译器与运行时都会注意到这个变量是共享的,因此不会将该变量上的操作与其他内存操作一起重排序。然而,在访问volatile变量时不会执行加锁操作,因此也就不会使执行线程阻塞

  • synchronized关键字和volatile关键字比较: volatile关键字是线程同步的轻量级实现,所以volatile性能肯定比synchronized关键字要好。但是volatile关键字只能用于变量而synchronized关键字可以修饰方法以及代码块。synchronized关键字在JavaSE1.6之后进行了主要包括为了减少获得锁和释放锁带来的性能消耗而引入的偏向锁和轻量级锁以及其它各种优化之后执行效率有了显著提升,实际开发中使用 synchronized 关键字的场景还是更多一些。 多线程访问volatile关键字不会发生阻塞,而synchronized关键字可能会发生阻塞 volatile关键字能保证数据的可见性,但不能保证数据的原子性。synchronized关键字两者都能保证。 volatile关键字主要用于解决变量在多个线程之间的可见性,而 synchronized关键字解决的是多个线程之间访问资源的同步性

12.4 使用instanceof

instanceof关键字的作用是判断左边对象是否是右边类(这里有很多人说是对象,所以注意这里是类,并不是对象)的实例(通俗易懂的说就是:子类对象,或者右边类本身的对象)返回的boolean类型,true和false。

instanceof运算符具有下面的一般形式:

object instanceof type

这里,object是类的实例,而type是类的类型。如果object是指定的类型或者可以被强制 转换成指定类型,instanceof将它评估成true,若不是,则结果为false。

12.5 strictfp

关键字strictfp是strict floatpoint的缩写,指的是精确浮点,它用来确保浮点数运算的准确性。JVM在执行浮点数运算时,如果没有指定strictfp关键字,此时计算结果可能会不精确。用strictfp来声明一个类、接口或者方法,那么在声明的范围内,Java编译器以及运行环境会完全按照IEEE二进制浮点数算术标准(IEEE 754)来执行,在这个关键字声明的范围内所有浮点数的计算都是精确的。当一个类被strictfp修饰时,所有方法都会自动被strictfp修饰。因此,strictfp可以保证浮点数运算的精确性,而且在不同硬件平台上都会有一致的运行结果。

二、java库

第 13 章 字符串处理

13.1 String构造函数

    • String() 初始化新创建的 String对象,它代表了一个空字符序列。
      String(byte[] bytes) 通过使用平台的默认字符集解码指定的字节数组构造了一个新的 String
      String(byte[] bytes, Charset charset) 通过使用指定的 charset解码指定的字节数组构造了一个新的 String
      String(byte[] ascii, int hibyte) 过时的。 这种方法不正确地将字节转换为字符。作为 JDK 1.1,这样的首选方式是通过String构造函数带Charset,字符集名称,或使用平台的默认字符集。
      String(byte[] bytes, int offset, int length) 构建了一种新的 String通过解码指定的字节数组使用平台的默认字符集。
      String(byte[] bytes, int offset, int length, Charset charset) 构建了一种新的 String通过解码指定的字节数组使用指定的 charset
      String(byte[] ascii, int hibyte, int offset, int count) 过时的。 这种方法不正确地将字节转换为字符。作为 JDK 1.1,这样的首选方式是通过String构造函数带Charset,字符集名称,或使用平台的默认字符集。
      String(byte[] bytes, int offset, int length, String charsetName) 构建了一种新的 String通过解码指定的字节数组使用指定的字符集。
      String(byte[] bytes, String charsetName) 通过使用指定的 charset解码指定的字节数组构造了一个新的 String
      String(char[] value) 分配一个新的 String,它代表了目前包含在字符数组参数字符序列。
      String(char[] value, int offset, int count) 分配一个包含字符与字符数组数组参数的新 String
      String(int[] codePoints, int offset, int count) 分配一个包含字符子数组的数组参数的新 String Unicode code point
      String(String original) 初始化新创建的对象 String所以它代表相同的字符序列的说法;换句话说,新创建的字符串是一个副本的参数字符串。
      String(StringBuffer buffer) 分配一个新的字符串,该字符串包含当前包含在字符串缓冲区中的字符的序列的字符串。
      String(StringBuilder builder) 分配一个新的字符串,该字符串包含当前包含在字符串生成器参数中的字符的序列。

13.2 字符串长度

字符串的长度是指其所包含的字符的个数。

13.3 特殊的字符串操作

13.3.1 字符串与其他类型数据的连接

字符串可以和其他类型的数据连接。只要 + 运算符的一个运算 数是字符串(String)实例,编译器就将另一个运算数转换为它的字符串形式。

13.3.2 字符串转换和toString( )

tostring:java类根据需要重写toString方法才能使返回值更有意义。即如果不去重写这个方法那么返回值就会是 类名+符号@+对象的哈希码值

13.4 字符串常用方法

==是进行对象的地址值比较,如果确实需要字符串的内容进行比较,可以使用两个方法:

public boolean equals(object obj):参数可以是任何对象,只有参数是一个字符串并且内容相同的才会给true,否则返回false 注意事项: 1.任何对象都能用Object进行接收 2.equals方法具有对称性,也就是a.equals(b)和b.equals(a)效果一样 3.如果比较双方是一个常量和一个变量。推荐把常量字符串写在前面。 推荐:"abc".equals(str) 不推荐:str.equals("abc")

public boolean equalsIgnoreCase(String str):忽略大小写,进行内容比较

二、 String当中与获取相关的常用方法 1、public int length():获取字符串当中含有的字符个数,拿到字符串长度 2、public String concat(String str):将当前字符串和参数字符串拼接成为返回值新的字符串 3、public char charAt(int index):获取指定索引位置的单个字符。(索引从0开始) 4、public int indexOf(String str):查找参数字符串在本字符串当中首次出现的索引位置,如果没有返回-1值 5、public String valueOf(int x):将数值转换为字符串。

三、 字符串的截取方法: 1、public String substring(int index):截取从参数位置一直到字符串末尾,返回新字符串。 2、public String substring(int begin ,int end):截取从begin开始,到end结尾的字符串。 注:[begin,end),包含左边,不包含右边。

四、 String当中装换的常用方法: 1、public char[] toCharArray():将当前字符串拆分成为字符数组作为返回值 2、public byte[] getBytes():获得当前字符串底层的字节数组。 3、public String replace(CharSequence,CharSequence): 将所有出现的老字符串替换成为新的字符串,返回值为替换之后的新的字符串。 注:CharSequence意思是说可以接受字符串类型

五、 字符串的分割方法: public String[] split(String regex):按参数规则,将字符串切分成为若干部分。 注意事项: split方法的参数是一个“正则表达式”,今后学习 今天注意:如果按照英文句点“."进行切分,必须写"\."

六、

改变字符串内字符的大小写

String toLowerCase( ) :将字符串内的所有字符从大写字母改写为小写字母。 String toUpperCase( ) :将字符串内所有字符从小写字母改写为大写字母。

13.5 StringBuffer

StringBuffer是提供了大量的字符串功能的字符串(String)类的对等类。StringBuffer表示了可变长的和可 写的字符序列。

13.5.1 StringBuffer构造函数

StringBuffer定义了下面三个构造函数: StringBuffer( ) StringBuffer(int size) StringBuffer(String str)

13.5.2 length( )和capacity( )

int length( ) :得到当前StringBuffer的长度。

int capacity( ) : 得到总的分配容量。容量是新插入字符可用的存储量,超出该容量将进行分配(初始容量即默认容量为16

13.5.3 ensureCapacity()

void ensureCapacity(int capacity):确保容量至少等于指定的最小值。

13.5.4 setLength( )

public void setLength(int newLength):设置字符序列的长度。该序列被改变为一个新的字符序列,其长度由参数指定。

13.5.5 charAt( )和setCharAt( )

public char charAt(int index):返回指定索引在这个序列的 char值。

public void setCharAt(int where, char ch) :给指定索引设值

13.5.6 getChars( )

void getChars(int sourceStart, int sourceEnd, char target[ ], int targetStart):将StringBuffer的子字符串复制给数组。

13.5.7 append( )

将任一其他类型数据的字符串形式连接到调用StringBuffer对象的后面。

对所有内置的类型和Object,它都有重载形式。下面是其几种形式:

StringBuffer append(String str) 
StringBuffer append(int num) 
StringBuffer append(Object obj) 

13.5.8 insert( )

将一个字符串插入另一个字符串中。

13.5.9 reverse( )

StringBuffer reverse( ) :将StringBuffer对象内的字符串翻转

13.5.10 delete( )和deleteCharAt( )

public StringBuffer delete(int start,int end):删除的字符在字符串序列分析。子字符串从指定的 start延伸特征的指标 end - 1或序列的结束,如果没有这样的人物存在。如果 start等于end,不进行任何更改。

public StringBuffer deleteCharAt(int index):删除 char在指定的位置在这个序列。

13.5.11 replace( )

public StringBuffer replace(int start,int end,String str):在一个字符串中替换指定的 String字符这个序列的特征。子开始在指定的 start延伸特征的指标 end - 1或序列的结束,如果没有这样的人物存在。首先在子串字符删除,然后指定 String插在 start。(这个顺序将加长以容纳指定的字符串,如果必要的。)

13.5.12 substring( )

public String substring(int start):返回一个包含目前包含此字符序列的子序列的新特点 String。子字符串的指定索引处开始,延伸到这个序列结束。

第 14 章 java.lang 研究

浮点(Float)和双精度(Double)都定义了下面的常数:

MAX_VALUE 最大正值

MIN_VALUE 最小正值

NaN 非数字

POSITIVE_INFINITY 正无穷

NEGATIVE_INFINITY 负无穷

TYPE 浮点(float)或双精度(double)的类(Class)对象

14.1 Process

抽象类Process封装了一个进程(process)——也就是说一个正在执行的程序。

14.2 Runtime

Runtime类封装了运行时环境。

可以通过调用静 态方法Runtime.getRuntime( )而获得对当前Runtime对象的引用。

14.2.1 内存管理

尽管Java提供了自动垃圾回收,有时也想知道对象堆的大小以及它还剩下多少。可以 利用这些信息检验你的代码的效率,或估计对某些类型,有多少对象可以被实例化。为了 获得这些值,可以使用totalMemory( )和freeMemory( )方法。

14.3 System

System类保存静态方法和变量的集合。

14.4 ClassLoader

抽象类ClassLoader规定了类是如何加载的。

14.5 Math

14.5.1 超越函数

下面的三种方法对一个以弧度为单位的角度接收一个双精度(double)参数并且返回 它们各自的超越函数的结果:

下面的方法将超越函数的结果作为一个参数,按弧度返回产生这个结果的角度值。它 们是其非弧度形式的反。

14.5.2 指数函数

14.5.3 舍入函数

14.6 Package

在Java 2中增加了一个称为Package的类。这个类封装了与包有关的版本数据。

第 15 章 java.util 第 1 部分:类集框架

一个类集 (collection)是一组对象。

15.1 类 集 概 述

类集框架被设计用于适应几个目的。首先,这种框架是高性能的。第二点,框架必须允许不同类型的类集以相同的方式和高度互 操作方式工作。第三点,类集必须是容易扩展和/或修改的。

算法(Algorithms)是类集机制的另一个重要部分。算法提供了一个处理类集的标准方法。

由类集框架创建的另一项是Iterator接口。一个迭代程序(iterator)提供了一个多用途 的,标准化的方法,用于每次访问类集的一个元素。

除了类集之外,框架定义了几个映射接口和类。

15.2 类 集 接 口

类集框架定义了几个接口。支持类集的接口总结在如下的表中:

15.2.1 Collection接口

Collection接口是构造类集框架的基础。

Collection接口: List接口(有序的集合;允许存储重复的元素;有索引可以用普通的for循环遍历): Vector集合 ArrayList集合 LinkedList集合

Set接口(不允许存储重复元素;没有索引,不可以有普通的for1循环遍历): ​ TreeSet集合:无序的集合(存储和取出的顺序可能不一致) HashSet集合:无序的集合(存储和取出的顺序可能不一致) ​ LinkedHashSet集合:有序的集合

java.util.Collection接口: 所有单列集合的最顶层的接口,里面定义了所有单列集合共性的方法 任意的单列集合都可以使用Collection接口中的方法

共性的方法: public boolean add(E e):把给定的对象添加到当前集合当中 public void clear():清空集合中的所有元素 public boolean remove():把给定的对象在当前集合中删除 public boolean contains(E e):判断当前集合中是否包含给定的对象 public boolean isEmpty():判断当前集合是否为空 public int size():返回集合中元素的个数 public Object[] toArray():把集合中的元素,储存到数组中

15.2.2 List接口

List接口扩展了Collection并声明存储一系列元素的类集的特性。

java.util.List接口 extends Collection接口 特点: 有序的集合; 允许存储重复的元素; 有索引可以用普通的for循环遍历

接口中带索引的方法(特有): public void add(int index, E element):将指定的元素,添加到该集合的指定位置上。 public E get(int index):从集合当中获取元素,参数是索引编号,返回值是对应位置的元素。 public E remove(int index):从集合当中删除元素,参数是索引编号,返回值就是被删除元素。 public E set(int index, E element):用指定元素替换集合中指定位置的元素,返回值的更新前的元素 注意: 操作索引的时候,一定要防止索引越界异常

15.3 Collection类

15.3.1 ArrayList类

范型只能是引用类型,不能是基本类型 如果希望向集合Arraylist当中存储基本类型,必须使用基本类型对应的包装类

基本类型 包装类(引用类型,包装类都位于java.lang包下) byte Byte short Short int Integer 【特殊】 long Long float Float double Double char Character 【特殊】 boolean Boolean

Arraylist当中的常用方法:

public boolean add(E e):向集合之中添加元素,参数的类型和范型一致。返回值代表添加是否成功 备注:对应Arraylist集合来说,add添加动作一定是成功的,所以返回值可不写。 但是对于其他集合(今后学习)add,添加动作不一定成功 public E get(int index):从集合当中获取元素,参数是索引编号,返回值是对应位置的元素。 public E remove(int index):从集合当中删除元素,参数是索引编号,返回值就是被删除元素。 public int size():获取集合的尺寸长度,返回值是集合中包含的元素个数。

15.3.2 LinkedList类

java.util.LinkedList集合 implement List集合 LinkedList集合特点: 1.底层是一个链表结构:查询慢,增删快 2.里面包含了大量操作首尾元素的方法 注意:使用LinkedList集合特有的方法不能使用多态

public void addFirst(E e):将指定元素插入此列表的开头 public void addLast(E ):将指定元素添加到此列表的开头 public void push(E e):将元素推入此列表所表示的堆栈

public E getFirst():返回列表的第一个元素 public E getLast():返回列表的最后一个元素

public E removeFirst():移除并返回列表的第一个元素 public E removeFirst():移除并返回列表的最后一个元素 public E pop(E e):从此列表所表示的堆栈处弹出一个元素。相当于removeFirst

public boolean isEmpty():如果列表不包含元素,则返回true

15.3.3 HashSet类

java.util.HashSet集合 implements Set接口 特点: 1.不允许存储重复元素; 2.没有索引,不可以有普通的for循环遍历 3.无序的集合(存储和取出的顺序可能不一致) 4.底层是一个哈希表结构(查询的速度非常快)

15.3.4 TreeSet类

TreeSet是SortedSet接口的唯一实现, TreeSet可以确保集合元素处于排序状态. TreeSet并不是根据元素的插入顺序进行排序,

而是根据元素实际值来进行排序.(可以确保元素唯一并且元素排序) TreeSet采用红黑树的数据结构对元素进行排序.

15.4 通过迭代函数访问类集

java.util.Iterator接口:迭代器(对集合进行遍历) 有两个常用的方法: boolean hasNext():如果仍有元素可以迭代,则返回true,判断集合中还有没有下一个元素,有返回true,没有返回false E next():返回迭代的下一个元素。取出集合下一个元素

Iterator迭代器,是一个接口,我们无法直接使用,需要使用Iterator接口的实现对象,获取实现类的方法比较特殊 Collection接口中有一个方法,叫iterator(),这个方法就是迭代器的实现类对象 Iterator<E> iterator()返回在此collection的元素上进行迭代的迭代器

迭代器的使用步骤(重点): 1.使用集合中的方法iterator()获取迭代器的实现类对象,使用Iterator接口接受(多态) 2.使用Iterator接口中的方法hasNext判断还有没有下一个元素 3.使用Iterator接口中的方法next取出集合中的下一个元素

增强for循环:底层使用的也是迭代器,使用for循环的格式,简化了迭代器的书写

Collection<E>extends Iterable<E>:所有的单列集合都可以使用增强for public interface Iterable<T>实现这个借口允许对象成为“foreach”语句的目标

格式: for(集合/数组的数据类型 变量名: 集合名/数组名){ sout(变量名); }

15.6 处 理 映 射(map)

15.6.1 映射接口

  • Map 接口

  • SortedMap 接口

  • Map.Entry 接口

15.6.2 映射类

java.util.Map<K,V>集合 Map集合特点: 1.Map集合是一个双列集合,一个元素包含两个值(一个key,一个value) 2.Map集合中的元素,key和value的数据类型可以相同也可以不同 3.Map集合中的元素,key是不允许重复的,value是可以重复的 4.Map集合中的元素,key和value是一一对应的

java.util.HashMap<k,v>集合 implements Map<k,v>接口 HashMap集合特点: 1.HashMap集合底层是哈希表:查询的速度特别快(数组 + 单向链表/红黑树:提高查询速度) 2.HashMap集合是一个无序的集合,存储和元素和取出元素的顺序有可能不一致

java.util.LinkedHashMap<k,v>集合 extends HashMap<k,v>集合 LinkedHashMap集合的特点: 1.LinkedHashMap集合底层是哈希表 + 链表(保证迭代的顺序) 2.LinkedHashMap集合是一个有序的集合,存储和取出元素的顺序是一致的

Map集合常用方法: 1.public V put(K key,V value):把指定的键与指定的值添加到Map集合中 2.public V remove(Object key):把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元素的值 3.public V get(Object key)根据指定的键,在Map集合中获取对应的值 4.boolean containsKey(Object key)判断集合中是否包含指定的值

TreeMap 类

TreeMap类通过使用树实现Map接口。TreeMap提供了按排序顺序存储关键字/值对的有 效手段,同时允许快速检索。应

15.9 Arrays (数组)

Java 2在java.util中新增加了一个叫做Arrays的类。这个类提供了各种在进行数组运算时 很有用的方法。

asList( )方法返回一个被指定数组支持的List。它具有如下的形式:

static List asList(Object[ ] array) 

这里array是包含了数据的数组。

binarySearch( )方法使用二进制搜索寻找指定的值。该方法必须应用于排序数组。它具 有如下的形式:

static int binarySearch(byte[ ] array, byte value) 
static int binarySearch(char[ ] array, char value) 
static int binarySearch(double[ ] array, double value) 
static int binarySearch(float[ ] array, float value) 
static int binarySearch(int[ ] array, int value) 
static int binarySearch(long[ ] array, long value) 
static int binarySearch(short[ ] array, short value) 
static int binarySearch(Object[ ] array, Object value) 
static int binarySearch(Object[ ] array, Object value, Comparator c) 

这里,array是被搜索的数组,而value是被查找的值。

当array中包含的元素是不可比较 的(例如Double和StringBuffer)或者当value与array中的类型不兼容时,后两种形式引发一 个ClassCastException异常。

fill( )方法将一个值赋给数组中的所有元素。

static void fill(boolean array[ ], boolean value) 
static void fill(byte array[ ], byte value) 
static void fill(char array[ ], char value) 
static void fill(double array[ ], double value) 
static void fill(float array[ ], float value) 
static void fill(int array[ ], int value) 
static void fill(long array[ ], long value) 
static void fill(short array[ ], short value) 
static void fill(Object array[ ], Object value) 

fill( )方法的第二种形式将一个值赋给数组的一个子集。它的几种形式如下:

static void fill(boolean array[ ], int start, int end, boolean value) 
static void fill(byte array[ ], int start, int end, byte value) 
static void fill(char array[ ], int start, int end, char value) 
static void fill(double array[ ], int start, int end, double value) 
static void fill(float array[ ], int start, int end, float value) 
static void fill(int array[ ], int start, int end, int value) 
static void fill(long array[ ], int start, int end, long value) 
static void fill(short array[ ], int start, int end, short value) 
static void fill(Object array[ ], int start, int end, Object value) 

value是赋给数组array中从start开始到end–1结束的子集的值。这些方法当start大 于end时,都能引发一个IllegalArgumentException异常;而当start或end出界时,都能引发一 个ArrayIndexOutOfBoundsException异常。

sort( )方法对数组进行排序:一

static void sort(byte array[ ]) 
static void sort(char array[ ]) 
static void sort(double array[ ]) 
static void sort(float array[ ]) 
static void sort(int array[ ]) 
static void sort(long array[ ]) 
static void sort(short array[ ]) 
static void sort(Object array[ ]) 
static void sort(Object array[ ], Comparator c) 

sort( )方法对数组进行排序:二

static void sort(byte array[ ], int start, int end) 
static void sort(char array[ ], int start, int end) 
static void sort(double array[ ], int start, int end) 
static void sort(float array[ ], int start, int end) 
static void sort(int array[ ], int start, int end) 
static void sort(long array[ ], int start, int end) 
static void sort(short array[ ], int start, int end) 
static void sort(Object array[ ], int start, int end) 
static void sort(Object array[ ], int start, int end, Comparator c) 

数组中想要进行排序的范围从start到end–1。

当用于排序的数组中的元素不可比较时,这些对Object的数组进 行排序的sort( )方法将引发一个ClassCastException异常。

第 16 章 java.util 第 2 部分:更多的实用工具类

16.1 StringTokenizer(字符串标记)

对文本的处理经常包括对格式化的输入字符串进行语法分析。语法分析(Parsing)将 文本划分为一组不连续的部分,或标记(tokens),在一个确定的序列中,标记可以表达语 义。

StringTokenizer的构造函数如下所示:

StringTokenizer(String str) 
StringTokenizer(String str, String delimiters) 
StringTokenizer(String str, String delimiters, boolean delimAsToken)

在上述三种形式中,str都表示将被标记的字符串。在第一种形式中,使用默认的分割 符。在第二种和第三种形式中,delimiters是用来指定分割符的一个字符串。在第三种形式 中,如果delimAsToken为true,当字符串被分析时,分割符也被作为标记而被返回;否则, 不返回分割符。在第一种和第二种形式中,分割符不会作为标记而被返回。

StringTokenizer实现枚举(Enumeration)接口。

16.2 BitSet(置位)

这个类实现了一个向量的增长所需要的。点集的每个组件都有一个 boolean价值。一个 BitSet位以非负整数索引。单独的索引位可以检查,设置或清除。一 BitSet可以用来修改另一个 BitSet通过逻辑的内容,逻辑或,异或运算和逻辑。

默认情况下,该组中的所有位最初有价值false

每一位设置有一个当前的大小,这是目前在使用的位集的空间位的数量。请注意,大小与位集的实现有关,因此它可能会随着实现改变。位集的长度与位集的逻辑长度有关,并独立于实现的定义。

除非另有说明,传递一个null参数中的任何一个BitSet方法将导致一个NullPointerException

一个BitSet不安全的多线程的使用没有外部同步。

BitSet的构造函数如下所示:

BitSet( ) 
BitSet(int size) 

第一种形式创建一个默认的对象。第二种形式允许指定其初始大小(也就是说,它所 能包含的位的个数)。所有的位被初始化为0。

BitSet实现Cloneable接口并且定义了表16-2中列出的方法

16.3 Date(日期)

java.util.Date:表示日期和时间的类 类Date表示特定的瞬时,精确到毫秒 毫秒:千分之一秒 特定的瞬间:一个时间点,一刹那的时间

毫秒的作用:可以对时间和日期进行计算 2099-01-03到2088-01-01中间到底有多少天 可以吧日期转换为毫秒进行计算,计算完毕,在把毫秒转换为日期

把日期转换为毫秒: 当前的日期:2088-01-01 时间原点(0毫秒):1970-01-01 00:00:00 就是计算当前日期到时间原点之间一共经历了多少毫秒(1603527663698)

把毫秒转换为日期: 1天 = 246060 = 86400秒 = =86400000毫秒

注意: 中国属于东八区,会把时间增加8个小时

Date支持下面的构造函数:

Date( ) //获取的就是当前系统的日期和时间
Date(long millisec) 

第一种形式的构造函数用当前的日期和时间初始化对象。第二种形式的构造函数接收 一个参数,该参数等于从1970年1月1日午夜起至今的毫秒数的大小。

16.3.1 比较日期

有三种方法可用于比较两个Date对象。首先,可以对两个对象使用getTime( )方法获得 它们各自自1970年1月1日午夜起至今的毫秒数的大小。然后比较这两个值的大小。其次, 可以使用before( ),after( )以及equals( )方法。例如,由于每个月的12号出现在18号之前, 所以new Date(99, 2, 12).before(new Date (99, 2, 18))将返回true。最后,可以使用由Comparable 接口定义,被Date实现的compareTo( )方法。

16.4 Calendar(日历)

java.util.Calendar:日历类 Calendar类是一个抽象类,里面提供了很多操作日历字段的方法(YEAR、MONTH、DAY_OF_MONTH、HOUr) Calendar类无法直接创建对象使用,里面有一个静态方法叫getInstance(),改方法返回了Calendar类的子类对象 static Calendar getInstance()使用默认时区和语言环境获得一个日历

Calendar类的成员方法: public int get(int field):返回给定日历字段的值 public void set(int field,int value):将给定的日历字段设置为定值。 public abstract void add(int field, int amount):根据日历规则,为给定的日历字段添加或减去指定的时间量。 public Date getTime():返回一个表示Calendar时间值(从历元到现在的毫秒偏移量)的Date对象 成员方法参数: int field:日历类的字段,可以使用Calendar类的静态成员变量获取

16.5 GregorianCalendar(标准阳历)

GregorianCalendar是Calendar的一个实现大家所熟悉的标准日历(格列高利历)的具体 工具。Calendar的getInstance( )方法返回用默认的地区和时区的当前日期和当前时间所初始 化的GregorianCalendar(标准日历)

提供的三种构造函数如下

GregorianCalendar(int year, int month, int dayOfMonth) 
GregorianCalendar(int year, int month, int dayOfMonth, int hours, int minutes) 
GregorianCalendar(int year, int month, int dayOfMonth, int hours, int minutes, int seconds)

三种形式中,都设置了日,月和年。这里,year指定了从1900年起的年数。month指定 了月,以0表示一月。月中的日由dayOfMonth指定。第一种形式以午夜设置时间。第二种 形式以小时和分钟设置时间,第三种形式增加了秒。

16.6 TimeZone(时区)

另一个与时间有关的类是TimeZone。TimeZone类允许给出相对于格林威治时间 (GMT),也称为世界时间(UTC)的时区差。

16.9 Random

Random类是伪随机数的产生器。

构造函数:

Random( ) 
Random(long seed)

第一种形式创建一个使用当前时间作为起始值或称为初值的数字发生器。第二种形式 允许人为指定一个初值。

方法:

16.10 Observable (观测)

Observable类用于创建可以观测到你的程序中其他部分的子类(被观察)。当这种子类的对象发生 变化时,观测类被通知。

16.10.1 观测接口

为了观测一个可观测的对象,必须实现Observer接口。这个接口仅仅定义了如下所示 的一个方法

void update(Observable observOb, Object arg)

这里,observOb是被观测的对象,而arg是由notifyObservers( )方法传递的值。当被观测对象发生了改变,调用update( )方法。

16.11 Timer和TimerTask

提供了提前安排将来某 时间要执行任务的能力。支持这项功能的类是Timer和TimerTask。

TimerTask实现了Runnable接口;因此它可以被用于创建一个执行线程。它的构造函数 如下所示:

TimerTask( )

一旦任务被创建,它将通过一个类型Timer的对象被安排执行。Timer的构造函数如下

Timer( ) 
Timer(boolean DThread)

第一种形式创建一个以常规线程方式运行的Timer对象。第二种形式当DThread为true 时,使用后台进程线程。

第 17 章 输入/输出:探究 java.io

17.1 Java输入/输出类和接口

17.2 File(文件类)

java.io.File类:文件和目录路径名的抽象表示形式 java把电脑中的文件和文件夹(目录)封装为了一个File类,我们可以使用File类对文件夹进行操作 我们可以使用File类的方法 创建一个文件/文件夹 删除文件/文件夹 获取文件/文件夹 判断文件/文件夹是否存在 对文件夹进行遍历 获取文件的大小 File类是一个与系统无关的类,任何的操作系统都可以使用这个类中的方法

重点: 记住这三个单词 file 文件 directory 文件夹/目录 path 路径

构造函数:

File(String directoryPath) 
File(String directoryPath, String filename) 
File(File dirObj, String filename) 

这里,directoryPath是文件的路径名,filename 是文件名,dirObj 一个指定目录的File 对 象。

File类获取功能的方法: public String getAbsolutePath():返回此抽象路径名的绝对路径名字符串。 public String getPath():将此file转换为路径名字符串 public String getName():返回值file表示的文件或目录的名称 public long length():返回此file表示的文件长度

File判断功能的方法: public boolean exists():判断File表示的文件或目录是否实际存在 public boolean isDirectory():此File表示的是否为目录 public boolean isFile():此File表示的是否为文件

File创建删除的方法: public boolean createNewFile():当且仅当具有该名为文件尚不存在时,创建一个新的空文件 public boolean delete():删除由此File表示的文件或目录。 public boolean mkdir():创建有此File表示的目录 public boolean mkdirs():创建由此File表示的目录,包括任何必须但不存在的父目录

File类遍历(文件夹)目录功能: public String[] list():返回一个String数组,表示File目录中的所有字文件或目录 public File[] listFiles():返回一个File数组,表示该File目录中的所有的子文件或目录

注意: list方法和listFile方法遍历的是构造方法中给出的目录 如果构造方法中给出的目录路径不存在,就会抛出空指针异常 如果构造方法中给出的路径不是目录,也会抛出空指针异常

17.2.1 目录

目录是一个包含其他文件和路径列表的File 类。

17.2.2 使用FileFilter

java.io.FileFilter接口:用于抽象路径名(File对象)的过滤器 作用:用来过滤文件 抽象方法:用来过滤文件的方法: boolean accept(File pathname):测试指定抽象路径名是否应该包含在某个路径名列表中 参数: File pathname:使用ListFiles方法遍历目录,得到的每一个文件对象

File[] listFiles(FilenameFilter filter) java.io.FilenameFilter接口:实现此接口的实现类实例可以用于过滤文件名 作用:用于过滤文件名称 抽象方法:用来过滤文件的方法 boolean accept(File dir, String name):测试指定文件是否应该包含在某一文件列表中 参数: File dir:构造方法中传递的别遍历的目录 String name:使用ListFiles方法遍历目录,获取的每一个文件名/文件夹名称

注意: 两个过滤器接口是没有实现类,需要我们自己写实现类,重写过滤的方法accept,在此方法中定义过滤的规则

17.3 流 类

Java 的流式输入/输出建立在四个抽象类的基础上:InputStream, OutputStream, Reader和Writer。

第 18 章 网 络

18.1 网 络 基 础

18.1.1 套接字概述

网络套接字(network socket)有一点像电源插座。网络周围的各式插头有一个标准方 法传输它们的有效负载。

所谓套接字(Socket),就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制

18.1.2 客户/服务器模式(c/s)

18.1.3 保留套接字

下面是一个例子。客户请求单个文件/index.html,服务器回应它已成功找到该文 件并且把文件传输到客户:

18.1.4 代理服务器

一个代理服务器(proxy server)以客户端协议与其他服务器通信。这在客户与服务器 连接受到某些限制的情况下经常是必需的。

代理服务器具有过滤某些请求或缓存 一些这样的请求的结果以备后用的额外功能。

一个缓冲代理HTTP 服务器可用来减小局域 网连向Internet的带宽要求。

18.2 JAVA和网络

18.2.1 网络类和接口

java.net 包所包含的类如下:

18.3 InetAddress类

InetAddress 类用 来封装我们前面讨论的数字式的IP地址和该地址的域名。

18.3.1 工厂方法

InetAddress 类没有明显的构造函数。为生成一个InetAddress对象,必须运用一个可用 的工厂方法。工厂方法(factory method)仅是一个类中静态方法返回一个该类实例的约定。对于InetAddress,三个方法 getLocalHost( )、getByName( )以及getAllByName( )可以用 来创建InetAddress的实例。三个方法显示如下:

static InetAddress getLocalHost( ) throws UnknownHostException 
static InetAddress getByName(String hostName) throws UnknownHostException 
static InetAddress[ ] getAllByName(String hostName) throws UnknownHostException

getLocalHost( )仅返回象征本地主机的InetAddress 对象。getByName( )方法返回一个传 给它的主机名的 InetAddress 。如果这些方法不能解决主机名,它们引发一个 UnknownHostException异常。getAllByName( )工厂方法返回代表由一个特殊名称分解的所有地址的 InetAddresses类数组。在不能把名称分解成至少一个地址时,它将引发一个Unknown HostException异常

18.3.2 实例方法

InetAddress 类也有一些非静态的方法,列于下面,它们可以用于讨论过的方法返回的 对象:

boolean equals(Object other) 如果对象具有和other相同的Internet地址则返回true。
byte[ ] getAddress( ) 返回代表对象的Internert地址的以网络字节为顺序的有四个元素的字节数组。
String getHostAddress( ) 返回代表与InetAddress对象相关的主机地址的字符串。
String getHostName( ) 返回代表与InetAddress对象相关的主机名的字符串。
int hashCode( ) 返回调用对象的散列码。
boolean isMulticastAddress( ) 如果Internet地址是一个多播地址返回true;否则返回false。
String toString( ) 返回主机名字符串和IP地址。

Internet地址在分层的缓存服务器系列中被找到。

18.4 TCP/IP客户套接字

TCP/IP 套接字用于在主机和Internet之间建立可靠的、双向的、持续的、点对点的流式 连接。

注意:小应用程序只建立回到下载它的主机的套接字连接。

存在这个限制的原因 是:穿过防火墙的小应用程序有权使用任何机器是很危险的事情。

Java中有两类TCP套接字:

  • 一种是服务器端的,ServerSocket类设 计成在等待客户建立连接之前不做任何事的“监听器”。

  • 一种是客户端的,Socket类为建立连向服务器套接 字以及启动协议交换而设计。

一个Socket对象的创建隐式建立了一个客户和服务器的连接。没有显式的说明建立连 接细节的方法或构造函数。下面是用来生成客户套接字的两个构造函数:

Socket(String hostName, int port) 创建一个本地主机与给定名称的主机和端口的套接字连接,可以引发一个UnknownHostException异常或IOException异常。
Socket(InetAddress ipAddress, int port) 用一个预先存在的InetAddress对象和端口创建一个套接字,可以引发IOException异常。

使用下面的方法,可以在任何时候检查套接字的地址和与之有关的端口信息:

InetAddress getInetAddress( ) 返回和Socket对象相关的InetAddress。
Int getPort( ) 返回与该Socket对象连接的远程端口。
Int getLocalPort( ) 返回与该Socket连接的本地端口。

一旦Socket对象被创建,同样可以检查它获得访问与之相连的输入和输出流的权力。 如果套接字因为网络的连接中断而失效,这些方法都能够引发一个IOException异常。

InputStream getInputStream( ) 返回与调用套接字有关的InputStream类。
OutputStream getOutputStream( ) 返回与调用套接字有关的OutputStream类。
void close( ) 关闭InputStream和OutputStream。

18.5 URL

URL提供了一个相当容易理解的形式来惟一确定或对Internet上的信息进行编址。

在Java的网络类库中,URL 类为用URL在Internet 上获取信息提供了一个简单的、简洁的用户编程接口(API)。

18.5.1 格式化(Format)

一个URL规范以四个元素为基础。

  • 第一个是所用到的协议,用冒号(:)来将它与定位符 的其他部分相隔离。

  • 第二个元素是主机名或所用主机的IP地址,这由左边的双斜线(//)和 右边的单斜线(/)或可选冒号(:)限制。

  • 第三个成分,端口号,是可选的参数,由主机 名左边的冒号(:)和右边的斜线(/)限制(它的默认端口为80,它是预定义的HTTP 端 口;所以“:80”是多余的)。

  • 第四部分是实际的文件路径(文件名)。

18.6 URLConnection类

URLConnection是访问远程资源属性的一般用途的类。

18.7 TCP/IP服务器套接字

ServerSocket的构造函数反映了希望接受连接的端口号及你希望排 队等待上述端口的时间(该项可选)。队列长度告诉系统多少与之连接的客户在系统拒绝 连接之前可以挂起。队列的默认长度是50。构造函数在不利情况下可以引发IOException异 常。下面是构造函数:

ServerSocket(int port) 在指定端口创建队列长度为50的服务器套接字。
ServerSocket(int port, int maxQueue) 在指定端口创建一个最大队列长度为maxQueue的服务器套接字。
ServerSocket(int port, int maxQueue, InetAddress localAddress) 在指定端口创建一个最大队列长度为maxQueue的服务器套接
字。在一个多地址主机上,localAddress指定该套接字约束的IP地址。

ServerSocket有一个额外的accept()方法,该方法是一个等待客户开始通信的模块化调 用,然后以一个用来与客户通信的常规Socket返回。

18.8 缓存代理HTTP服务器

我们讲述一个简单的缓存代理HTTP服务器,名为http,来演示客户 与服务器套接字。

18.9 数 据 报

数据报(Datagrams)是在机器间传递的信息包

Java通过两个类实现UDP协议顶层的数据报:DatagramPacket对象是数据容器, DatagramSocket是用来发送和接受DatagramPackets的机制。

18.9.1 DatagramPacket

DatagramPackets 可以用四个构造函数中的一个创建。第一个构造函数指定了一个接收 数据的缓冲区和信息包的容量大小。它通过DatagramSocket接收数据。第二种形式允许你 在存储数据的缓冲区中指定一个偏移量。第三种形式指定了一个用于DatagramSocket决定 信息包将被送往何处的目标地址和端口。第四种形式从数据中指定的偏移量位置开始传输 数据包。想象前两种形式是建立在“盒内”的,后两种形式形成了填塞物,并为一个信封 注明了地址。下面是四个构造函数:

DatagramPacket(byte data[ ], int size) 
DatagramPacket(byte data[ ], int offset, int size) 
DatagramPacket(byte data[ ], int size, InetAddress ipAddress, int port) 
DatagramPacket(byte data[ ], int offset, int size, InetAddress ipAddress, int port)

存在几种方法可获取DatagramPacket内部状态。它们对信息包的目标地址和端口号以及 原始数据和数据长度有完全的使用权,下面是它们的概述:

InetAddress getAddress( ) 返回目标文件InetAddress,一般用于发送。
Int getPort( ) 返回端口号。
byte[ ] getData( ) 返回包含在数据包中的字节数组数据。多用于在接收数据之后从数据包来检索数据。
Int getLength( ) 返回包含在将从getData( )方法返回的字节数组中有效数据长度。通常它与整个字节数组长度不等。

第 19 章 Applet 类

19.1 Applet基础

所有的小应用程序都是Applet类的子类。

对小应用程序窗口的输出并不是由函数 System.out.println( )完成的,而是由各种不同的AWT方法来实现,例如drawString( ),这个 方法可以向窗口的某个由X,Y坐标决定的特定位置输出一个字符串。同样的,小应用程序 窗口的输入与一般的应用程序不同。

只要小应用程序经过编译,它就被包含在一个HTML文件中,并使用APPLET标记。

19.1.1 Applet类

Applet类为小应用程序的执行,如启动,中 止等提供了所有必需的支持。它还提供了装载和显示图像的方法,以及装载和播放语音片 断的方法。Applet扩展了AWT类中的Panel。

方法:

void destroy( ) 在一个小应用程序结束之前被浏览器调用。你的小应用程序在被删除之前如果需要完成任何清除工作则会重载此方法
AccessibleContext getAccessibleContext( ) 为调用对象返回可访问的上下文
AppletContext getAppletContext( ) 返回与此小应用程序相关的上下文关系
String getAppletInfo( ) 返回一个描述此小应用程序的字符串
AudioClip getAudioClip(URL url) 返回一个AudioClip对象,它封装了在由url所指定的地方找到的音频片断
AudioClip getAudioClip(URL url, String clipName) 返回一个AudioClip对象,它封装了在由url所指定的地方找到的名为														 clipName的音频片断
URL getCodeBase( ) 返回与调用小应用程序相关的URL 
URL getDocumentBase( ) 返回调用此小应用程序的HTML文档的URL 
Image getImage(URL url) 返回一个Image对象,它封装了在由url所指定的位置找到的图像
Image getImage(URL url, String imageName) 返回一个Image对象,它封装了在由url所指定的地方找到的名为imageName的图像
Locale getLocale( ) 返回一个Locale对象,它被许多的对位置敏感的类和方法使用
String getParameter(String paramName) 返回与paramName相关的参数。如果所指定的参数未能找到的话,则返回null 
String[ ] [ ] getParameterInfo( ) 返回一个描述由此小应用程序所识别的参数的String表。表中的每一条必须包含三个字符串,分别包								   含了参数名,类型或范围描述以及用途说明
void init( ) 在小应用程序开始执行时被调用。它是任何小应用程序调用的第一个方法
boolean isActive( ) 如果小应用程序已经启动则返回 true。如果小应用程序被中止则返回 false 
static final AudioClip newAudioClip(URL url) 返回一个 AudioClip 对象,它封装了在url所指定的位置找到的音频片断。此方法											 类似于getAudioClip( )除了它是静态的且可无需Applet对象就可被执行(在 Java 												2中被加入) 
void play(URL url) 如果在url指定的位置能找到一个音频片断的话,则此片断被播放
void play(URL url, String clipName) 如果在url设定的位置能找到一个音频片断且名为clipName的话,则此片断被播放
void resize(Dimension dim) 根据dim指定的尺寸调整小应用程序的大小。dimension是一个存储在java.awt中的类。它包含了两个整数`						   域:width 和 height 
void resize(int width, int height) 根据width和 height设定的尺寸调整小应用程序的大小
final void setStub(AppletStub stubObj) 使 stubObj 成为小应用程序的存根。此方法由实时运行系统使用并且通常不被小应用程序调									   用。一个存根是提供小应用程序和浏览器之间的连接的小段代码
void showStatus(String str) 在浏览器或小应用程序阅读器的状态窗口显示str。如果浏览器不支持状态窗口,则无任何动作发生
void start( ) 当小应用程序开始(或重新)执行时,被浏览器调用。它在小应用程序刚开始时在init之后被自动调用
void stop( ) 被浏览器调用以将小应用程序挂起。一旦被停止,则当浏览器调用start()时,小应用程序被启动

19.2 Applet体系结构

所谓的小应用程序是一种基于窗口的程序。

首先,小应用程序是由事件驱动的。

一个小应用程序类似于系列提供中断服务的子程序的集合。

程序就是这样运行的。在 事件发生之前,小应用程序一直处于等待状态中。一旦事件发生,小应用程序就会采取相 应措施并迅速将控制权交给AWT。

19.3 Applet主框架

几乎大多数的小应用程序都重载一套方法,这些方法提供了浏览器或小应用程序阅读 器与小应用程序之间的接口以及前者对后者的执行进行控制的基本机制。这套方法中的四 个,init( ),start( ),stop( )和destroy( )是由Applet所定义的。另一个方法,paint( )是由AWT 组件类定义的。

19.3.1 Applet的初始化与终止

懂得程序主框架中所示的各种方法的排列顺序是很重要的。当一个小应用程序开始执 行时,AWT就以如下顺序调用以下方法:

  1. init( ): init()方法是被调用的第一个方法。这是初始化变量的地方。这个方法在你的小应用 程序运行期间仅被调用一次。

  2. start( ): start()方法是在init()之后被调用。它也在小应用程序被终止后重新启动时调用。init( )仅在小应用程序第一次被装载时调用一 次,而start()却在每一次小应用程序的HTML文档被 显示在屏幕上时都被调用。因此,如果用户离开一个网页之后重新进入时,小应 用程序就 会从start()开始重新执行。

  3. paint( ): 在每一次你的小应用程序的输出必须重画窗口,paint()方法都被调用。

当一个小应用程序终止时,下列方法就以下列顺序被调用:

  1. stop(): 当Web浏览器离开包含小应用程序的HTML文件时,stop()方法就被调用,如在浏览器 去另一个页面时。当stop()被调用时,小应用程序很可能在运行。

  2. destroy(): 当环境决定了你的小应用程序需要完全从内存中移去时,destroy()方法被调用。

19.3.2 重载update()方法

在某些情况下,你的小应用程序可能需要覆盖另外一个AWT所定义的方法,叫做 update()。

19.4 简单的小应用程序显示方法

为了向小应用程序输出字符串,可以使用drawString()方法, 这个方法是Graphics类中的一个。一般来说,它在update()或paint()中被调用。它的一般形式 如下所示:

void drawString(String message, int x, int y) 

19.5 请 求 重 画

不管什么时候你的小应用程序需要更新窗口所显 示的信息,它仅仅调用repaint()就够了。

repaint()方法有四种形式:

  • void repaint( ) :这种方式使得整个窗口都被重画。

  • void repaint(int left, int top, int width, int height) :式指定了窗口中需要被重画的区域这里区域左上角的坐标由left和top两个参数规定,而区域的宽与高由weight和height所 规定。上述尺寸以像素为单位。

  • void repaint(long maxDelay):

    void repaint(long maxDelay, int x, int y, int width, int height)

    这里,参数maxDelay规定了update()被调用之前的所能经过的最大的毫秒数。要小心, 如果时间在update()能被调用之前已经过去,则update()将不被调用。这时既没有返回值, 也没有异常,因此你必须要小心。

19.6 使用状态窗口

小应用程序除了在自己的窗口上显示信息之外,还能向它所在运行的浏览器或阅读器 的状态窗口输出消息。完成此项功能,只需调用showStatus()方法并加上你想显示的字符串 即可。

19.7 HTML APPLET标记

APPLET标记被用来从HTML文件和小应用程序阅读器中启动一个小应用程序(新的 OBJECT标记也有此种功能,但本书使用APPLET)。

19.9 getDocumentBase( )和getCodeBase( )

java将允许小应用程序从启动小 应用程序的HTML文件所在的路径(文件数据库)装载数据,同样也允许小应用程序从它 的类文件所被装载的路径(代码数据库)装载数据

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值