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.它来自于独立于平台的平台 (即系统结构中立)语言的需要,可以创建嵌入微波炉、遥控器等各种家庭的语言 电气设备软件。
万维网(WWW)由不同类型的计算机和操作组成的分布式系统 作系统和CPU。尽管许多类型的平台可以连接到因特网,但用户仍然希望它们能够运行同样的平台 样品程序。曾经是一个麻烦但不需要优先考虑的问题,现在已经成为一个迫切需要解决的问题(可移植语言)。
1.2 java常用语
-
Java设计的目的是让专业程序员感觉易学易用。
-
借鉴近几十年面向对象软件的优势,Java在纯进化论者的任何事情 实用主义者不讨论对象不对象的论点之间找到了平衡。Java的 对象模型简单易扩展,对于简单的数据类型,如整数,保持高性能,但不是 象。
-
因为Java它是一种严格的语言类型 编译时不仅要检查代码,还要检查运行时的代码。
面向对象 异常处理机制
-
设计Java目标之一是满足人们创建互动在线程序的需要。Java支持多 所以你用线程编程Java编写的应用程序可以同时执行多个任务。
-
Java程序代码的耐久性和可移植性是设计师考虑的一个主要问题。一个程序员面临 主要问题是今天编写的程序明天能否在同一台机器上顺利运行。升级操作系统, 核心系统资源的处理器升级和变化都可能导致程序无法继续运行。Java对此设计师 我尝试了很多问题,Java虚拟机(JVM)试着解决这个问题。他们的目标是只要 写一个程序,这个程序可以在任何地方、任何时行。在很大程度上,Java实现了 这个目标。
-
Java为Internet由于其处理,设计了分布式环境TCP/IP协议。
-
Java该程序在运行过程中有多种类型的信息来验证和解决对象访问问题。
第 2 章 Java 语言概述
2.1 面向对象编程
2.1.1 两种范型
-
第一种方法被称为面向过程的模型(process-oriented model)面向过程的模型可以认为代码作用于数据
-
第二种方法是面向对象的编程(object-oriented programming)面向对象的编程围绕其数据(即对象)和严格的数据 定义的接口来组织程序。
2.1.2 抽象
-
面向对象编程的一个实质性元素是抽象。人们抽象(abstraction)处理复杂性。
-
使用层次分类是管理抽象的有效方法。它允许你将复杂的系统分解成更多更容易处理的小块。
2.1.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在中间,可以组成两个或两个以上的句子,称为程序块 (Codeblocks)。在花括号中实现程序块。
2.4 基 本 词 汇
Java 该程序由空白分隔符、标识符、注释、文本、计算符、分隔符和关键字组成。
2.4.1 空白分隔符(whitespace)
在Java中,空白 分隔符可以是空格,Tab跳格键或换行符。
2.4.2 标识符(identifiers)
标识符可以是大写和小写字母,数字, 任何顺序组合下划线和美元符号,但不能从一个数字开始。
2.4.3 常量(literal)
p>在Java中,常量用literal表示。常量能在任何地方被它所允许的类型使用,代表的是所属类型的一个值。
2.4.4 注释(comments)
Java定义了的类型。
-
文档注释提供将程序信息 嵌入程序的功能。开发者可以使用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所示。
保护方法,实现对象的浅复制,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常。
final方法,获得运行时类型。
该方法用得比较多,一般子类都有覆盖。
该方法用于释放资源。因为无法确定该方法什么时候被调用,很少使用。
该方法是非常重要的一个方法。一般equals和==是不一样的,但是在Object中两者是一样的。子类一般都要重写这个方法。
该方法用于哈希查找,重写了equals方法一般都要重写hashCode方法。这个方法在一些具有哈希功能的Collection中用到。
一般必须满足obj1.equals(obj2)==true。可以推出obj1.hash- Code()==obj2.hashCode(),但是hashCode相等不一定就满足equals。不过为了提高效率,应该尽量使上面两个条件接近等价。
wait方法就是使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。wait()方法一直等待,直到获得锁或者被中断。wait(long timeout)设定一个超时间隔,如果在规定时间内没有获得锁就返回。
调用该方法后当前线程进入睡眠状态,直到以下事件发生。
(1)其他线程调用了该对象的notify方法。
(2)其他线程调用了该对象的notifyAll方法。
(3)其他线程调用了interrupt中断该线程。
(4)时间间隔到了。
此时该线程就可以被调度了,如果是被中断的话就抛出一个InterruptedException异常。
该方法唤醒在该对象上等待的某个线程。
该方法唤醒在该对象上等待的所有线程。
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 同步性
因为多线程在你的程序中引入了一个异步行为,所以在你需要的时候必须有加强同步 性的方法。举例来说,如果你希望两个线程相互通信并共享一个复杂的数据结构,例如链 表序列,你需要某些