Java程序设计实用教程 by 朱战立 & 沈伟
学习笔记之JAVA多线程(http://www.cnblogs.com/pegasus923/p/3995855.html)
国庆休假前学习了多线程,休假花了两天时间把整本书学完了。看书还就得一鼓作气。
第一章 概述
- 1995年SUN正式发布Java,前身是Oak。
- 1998年发布带有JDK1.2的Java 2。
- JDK(JAVA DEVELOPMENT KIT),也称作JAVA SDK(JAVA SOFTWARE DEVELOPMENT KIT)。
- J2ME(JAVA 2 MICRO EDITION)
- J2SE(JAVA 2 STANDARD EDITION)
- J2EE(JAVA 2 ENTERPRISE EDITION)
- 简单、面向对象和与现有高级语言形式类似。
- 鲁棒性和安全性。可靠性依靠JAVA的编译时检查和运行时检查两层检查机制实现。主要用于分布式的网络环境。
- 结构中立。JAVA先编译产生字节码(不依赖于任何硬件和操作系统的中间代码),然后用解释的方法产生最终在具体计算机上运行的机器码。
- 高性能。解释性程序设计语言运行速度慢,JAVA是半解释型,但JAVA的解释执行能全速进行,不用检查运行时的环境(因该环境已在编译时保证)。自动垃圾回收线程定义成优先级很低的后台线程,只在系统空闲时启动执行,也保证了运行速度。
- 解释型、多线程和动态性。只要安装JAVA解释器,JAVA字节码就能在任何计算机上解释执行。JAVA的多线程机制可提高复杂应用程序的运行速度,并且有系统提供的同步功能做安全保证。JAVA的对象绑定是动态的,类在被要求的时候才被从指定任意位置导入。
- 和C++等相比,JAVA是纯面向对象的高级语言。
- 独立于各种操作平台。先按编译方式翻译到字节码,然后把字节码按解释方式翻译到具体机器的机器语言。这种半编译、半解释的高级语言翻译方式,使独立于硬件环境和操作系统平台。
- 安全性好。
- 多线程。操作系统多任何和分时,允许同一时间运行多个程序。主要有多进程和多线程两种方式,多线程效率更高。同步机制能保证多线程正确运行。
- 字节码(BYTECODE)是和任何具体机器环境无关的中间代码。
- JAVA程序文件为.JAVA,字节码文件.CLASS。
- JAVA虚拟机(JAVA VIRTUAL MACHINE, JVM)上有JAVA解释器。
- JAVA一次编写,任意运行(WRITE ONCE, RUN ANYWHERE),解决了硬件环境和操作系统平台的异构问题。
- 网络环境下应用软件的开发模式多是B/S(BROWSE/SERVER)模式,即应用软件放在服务器端,客户端通过浏览器来进行应用。B/S模式的应用系统特别需要异构环境的支持。
- 嵌入HTML的JAVA程序称作APPLET程序(小程序)。
- 如果把JAVA源程序在浏览器上按解释方式运行,客户计算机的运行速度将非常慢。
- 当JAVA虚拟机采用硬件直接实现时,运行速度将大大快于目前的运行速度。
- JDK的文件夹结构:BIN,包含编译器、解释器等可执行文件;DEMO,程序示例;INCLUDE,头文件,用于本地机的C语言;INCLUDE-OLD,头文件,用于兼容支持旧接口;JRE,JAVA运行时环境的根路径;LIB,可执行程序使用的包文件。
- set path设置了JAVA编译运行程序的路径。
- set classpath设置了JAVA包的路径,最前面的“.”表示在当前工作路径下可执行JAVA程序。
- JAVA源程序文件名必须和类名完全一样;JAVA文件名的命名也是大小写敏感;JAVA源程序文件名后缀必须为.JAVA。
- 编译命令JAVAC将编译.JAVA,若编译正确,产生相应字节码文件(类文件).CLASS。
- 运行命令JAVA可运行.CLASS。
- JAVA程序主要有两种:JAVA APPLICATION(应用程序)和JAVA APPLET(小程序)。
- JAVA APPLET是嵌入在网页中、用浏览器加载后才能解释执行的程序。
第二章 JAVA语言基础
- JAVA语言的字符使用UNICODE编码标准。
- 标识符由字母数字下划线_和美元符$组成,必须以字母_或$开头,字符个数有限的字符序列。字母符号大小写敏感,区分大小写。
- JAVA有47个固定含义的标识符,关键字。
- 变量必须先定义(声明),才能赋值。
- 变量定义是指示编译器为特定数据类型的数值保存在内存中分配适当的内存空间。
- 变量的使用范围称作变量的作用域。
- 常见的程序块形式是if、while、for等后面跟随的一对花括号。
- 整个程序运行期间保持不变的变量称为常量。
- 定义常量用关键字final。
- 常量名通常全大写字母。
- 数据类型规定一类数据的数据位长度(字符个数),取值范围,以及对该类数据所能进行的操作。
- JAVA定义了8种基本数据类型:整型,byte/short/int/long;浮点型,float/double;逻辑型,boolean;字符型,char。
- byte 8 bits, short 16 bits, int 32 bits, long 64 bits.
- 十进制首位不能为0;八进制以0打头;十六进制以0x或0X打头。
- 字面值是程序中用到的显示数据值。所有整型字面值都隐含为int型。若要表示为long型时,在后面加L或l,如12345L。
- 浮点型由整数部分和小数部分组成。两种表示方式标准记数法和科学记数法,指数部分由e(E)后跟带正负号的整数表示。
- float 32 bits, double 64 bits.
- 所有浮点型数的字面值隐含为double。若要表示为float,需加F或f,如123.123F。
- 逻辑型用来定义保存逻辑值的变量,也称布尔型。
- 一个UNICODE标准下的编码称作一个字符。
- 字符型字面值用一对单引号括起来。
- 转义字符:\r 回车,\\ 反斜杠,\' 单引号,\“ 双引号。
- JAVA是强类型语言。强类型语言是指对数据类型的匹配要求十分严格。如果表达式的数据类型不一致,则编译器给出类型不一致的出错信息。
- 赋值语句的类型匹配有两种:类型相同和类型兼容。类型兼容是指赋值号左端的数据类型比赋值号右端的数据类型长。数据类型长,是指数据类型的位数长。
- 类型不兼容时,可以重新定义赋值号,或用强制类型转换。强制类型转换可能丢失数据或损失数据的精度。
- JAVA在基本关键字、运算符、表达式、赋值语句、流程控制语句等方面,是和C/C++基本相同的。
- JAVA运算符分为四类:算术运算符、关系运算符、逻辑运算符和位运算符。
- 算术运算符分为一元和二元,操作数必须是数值类型。
- 一元运算符:+/-/++/--。一元运算符与其前后的操作数之间不允许有空格,否则编译出错。
- 二元运算符:+/-/×///%。取余运算符可用于整数和浮点数的情况。
- 二元运算的所得结果的数据类型与精度较高(位数更长)的那种数据类型一致。
- 关系运算符:==/!=/>/>=/</<=。
- 逻辑运算符:&&/||/!/^/&/|。
- &和|运算是把逻辑表达式全部计算完,而&&和||运算具有短路计算功能。短路计算,指系统从左至右进行逻辑表达式的计算,一旦出现计算结果已经确定的情况,则计算过程即被终止。短路计算功能可以提高程序的运算速度。在程序设计时使用&&和||运算符,而不使用&和|。
- 位运算是以二进制位为单位进行的运算,其操作数和运算结果都是整型值。
- 位运算符:&/|/~/^/>>/<</>>>。位运算相应的操作数和运算结果都是二进制整数,而逻辑运算相应的操作数和运算结果都是逻辑值。
- 右移是将一个二进制数按指定位数向右移位,移掉的被丢弃,左边移进的部分补0(该数为正时),或者补1(该数为负时)。整数在机器内部采用补码表示法,正数符号位为0,负数的符号位为1。
- 0填充的右移>>>:不论正负,左边移进的部分一律补0。
- 赋值运算符还可以与二元算术运算符、逻辑运算符和位运算符组合成简捷运算符,如 +=。
- []是数组运算符,其中数值为数组下标。
- ()用于改变表达式中运算符的优先级。
- 操作数是字符串时,+运算符用来合并两个字符串;当一边是字符串,一边是数值时,机器自动将数值转换为字符串。
- 条件运算符(?:)
- 对象运算符instanceof用来测试一个指定对象是否是指定类(或其子类)的实例。
- 点运算符(.)功能:一是引用类中成员;二是指示包的层次等级。
- 用运算符和圆括号把运算对象连接起来的、符合JAVA语言语法规则的式子称作表达式。
- 表达式按照运算符优先级高的先运算;同一优先级的运算符,按照运算符的结合性(从左向右还是从右向左)的次序进行运算。大多数从左向右,少数(赋值、条件运算等)是从右向左。
- 表达式还可以是某个类的方法调用。
- 流程控制语句用来控制程序的执行流程:条件选择,循环,和转移语句。
- 基本结构:顺序结构,分支结构和循环结构。
- 一个以;结束的符号串称为语句。
- JAVA流程控制语句有:分支语句,if, switch;循环语句,for, while, do-while;转移语句,break, continue。
- 函数或类的成员函数运行结束后需要返回原调用处,并可能需要带回返回值的流程控制用return语句。
- if实现二路分支,switch多路分支。
- if-else中,else语句是任选的。
- JAVA规定:else总是与最近的一个if语句匹配。
- switch, case, default是关键字,default语句是可选的。
- switch表达式和case常量值的类型可以是byte,short,int,long和char,但不能为boolean,并且要求两者的数据类型必须一致。
- switch语句中的break语句结束switch语句的执行。
- for语句中的循环初始化,循环条件判断和循环变量修改都可以任选,即for (;;)。
- 循环过程永不结束,为死循环。
- do-while至少执行一次循环体,while可以一次也不执行。
- break通常和switch或循环语句配合使用;continue通常和循环语句配合使用。
- continue语句仅跳过当前层中循环体的剩余语句。
- 若函数为void类型,则return语句后没有返回值;若为非void,则return语句后需要有返回值,且返回值的累心个必须和函数的类型一致。
- 当return语句不带返回值,并且位于函数的最后时,它可以省略。
- 单行注释以//开头,至行尾;多行注释以/*开头,以*/结束;文件注释用来自动生成一个HTML文档,为程序自动提供网络环境下的文档说明,以/**开头,以*/结束。
- 数组是连续内存单元中一组名字和数据类型相同的数据元素的有限集合。数组中每个数据元素称作数组元素。JAVA还可以构造不规则数组。
- JAVA使用一维数组分三步:定义一堆数组变量、为数组分配内存单元和使用数组元素。
- 数组定义后,系统将给数组标识符分配一个内存单元,用于指示数组在内存中的实际存放位置。由于数组变量定义时,数组元素本身在内存中的实际存放位置还没给出,所以此时该数组名的值为空NULL。
- new运算符:向系统申请指定数据类型所需的内存单元空间。new运算符返回所申请内存单元的首地址。
- JAVA规定,在数组分配内存单元后,系统将自动给每个数组元素赋初值,数值型为0,逻辑型为false,类类型为null。
- 数组下标由0开始。
- 数组名是指向内存中存放数组元素的一片连续内存单元的首地址。
- 数组名的类型是引用类型。引用类型是指该类型的标识符所表示的是一片内存连续地址的首地址。字符串名和数组名,所有对象名都是引用类型。
- 数组的定义和为数组分配内存空间两步可以结合起来。数组元素的初始化赋值也可以结合一起。
- JAVA提供了length成员变量返回数组元素的个数。
- 如果一维数组的每个数组元素都是一个一维数组,则构成二维数组。若二维数组中的每个一维数组定义为不同的元素个数,就构成不规则的二维数组。
- 字符串是N(N>=0)个字符组成的序列。JAVA中字符串用双引号括起来,字符个数称作字符串长度。
- JAVA字符串变量用String来定义。String是JAVA API中定义的一个类。
- 一对双引号括起来的任何字符序列都是一个字符串常量。
- 把一片连续内存单元的首地址赋给字符串变量名,是让字符串变量指向存放字符串的内存单元的首地址。
- JAVA提供了特殊的字符串运算符+,把两个字符串连接起来。
- System.out.print()和Sytem.out.println()要求的参数是字符串或字符串表达式。
第三章 类和对象
- 类是对具有相同属性和方法的一组相似对象的抽象。对象是类的实例。包是JAVA组织和管理类的一种方法。
- 类的封装性、多态性和继承性是OOP的重要特点。
- 类的设计分为类声明和类主体设计两部分。
- 接口名多于一个时用逗号分隔开。
- 类声明的修饰符分为访问控制符和类型说明符两部分。一起使用时,访问控制符在前,类型说明符在后。
- 访问控制符为public,被定义为公共类,能被任何类访问。包中的类能互相访问,不在一个包中的类不能直接访问,必须用import导入到该包中。被导入的类必须是public。
- 没有public时,即是默认类(缺省类)。默认类表示该类只能被同一个包中的类访问,不能被其他包的类访问。JAVA文件中可以有很多类,但最多只能有一个公共类,其他为默认类。
- 类说明符为abstract时,为抽象类。抽象类不能用来定义对象,通常被设计成一些具有类似成员变量和方法的子类的父类。
- 类说明符为final时,为最终类,不能用来再派生子类。
- 由于JAVA中所有方法必定属于某个类,即方法一定是成员方法,所以成员方法简称方法。
- 声明成员变量的修饰符有private, public和protected。private成员变量只能被该类本身访问。不加任何修饰符,定义为默认修饰符,该成员变量只能被该类本身和同一个包的类访问。protected除可以被该类本身和同一个包的类访问外,还可以被它的子类(包括同一个包中的子类和不同包中的子类)访问。public可以被所有类访问。
- static指明是类成员变量,final指明该成员变量是常量,transient为临时变量,很少使用。
- 声明成员方法的修饰符有private, public和protected。static指明该方法是一个类方法。
- 方法声明中必须给出方法名和方法的返回值类型,如果没有返回值,用关键字void标记。方法名后的()是必须的,即使参数列表为空,也要加上。
- 方法体是方法的具体实现。
- 定义在类中的都是成员变量,定义在方法内的都是变量,还有定义在方法参数中的虚参变量。成员变量和变量的类型既可以是基本数据类型,也可以是已定义的类。
- 专门用来进行对象初始化的方法称为构造方法(构造函数)。一个类中至少要有一个构造方法。
- 构造方法的名字必须与类名完全相同,没有返回值,连表示空类型void的返回值都没有。一般应定义为public。
- 创建对象时,将调用类中的构造方法为对象的成员变量进行初始化赋值。
- 一个类对应一个.CLASS文件,一个程序文件中可以有一个或多个类,但只允许一个类被定义成public。类中可以没有main方法。但要运行的类必须有main方法。程序就是从main方法开始执行。
- 对象和数组一样也是引用类型,即对象定义后,系统将给对象标识符分配一个内存单元,用于存放实际对象在内存中的存放位置。
- new运算符申请对象所需的内存空间,返回所申请的内存空间的首地址。赋值语句把new运算符分配的连续地址的首地址赋给对象名。
- 程序设计时最经常使用的方法,是在定义对象的同时为对象分配内存空间和进行初始化赋值。
- 对象可以像变量一样赋值。不同的是,对象赋值不是把取值赋给另一个对象,而是让另一个对象名存储的对象的首地址和这个对象名存储的对象的首地址相同,即对象的赋值是对象的首地址的赋值。
- 对象也可以像变量一样,作为方法的参数使用。不同的是,变量作为实参时,系统把实参的数值复制给虚参;对象作为实参时,系统把实参对象名(该对象必须已创建)指示的对象的首地址赋给虚参对象名。
- 变量的内存空间是系统在变量定义时自动分配的;当变量超出作用范围时,系统将自动回收该变量的内存空间。
- 对象的内存空间是用new创建的。对象也有作用范围,超出作用范围的对象(不再使用的对象)为垃圾对象。JAVA中,收集和释放内存由自动垃圾回收线程负责。自动垃圾回收线程在系统空闲时自动运行,这个线程监视用户程序中所以对象的有效作用范围;当某个对象超出其作用范围时,该线程就对这样的对象做上垃圾对象标识,并在适当的时候一次性回收这些垃圾对象。
- 类有实例成员变量与类成员变量。类成员变量也称作静态成员变量。
- 类定义中没用关键字static的成员变量就是实例成员变量,不同对象的实例成员变量的值不相同。
- 用static的成员变量称为类成员变量。一个类的所以对象共享该类的类成员变量,类成员变量可以用来保存和类相关的信息,或用来在一个类的对象间交流信息。
- 类有实例方法与类方法。类方法称作静态方法。
- 没用static的方法就是实例方法。它只能通过对象来调用。实例方法可以访问类成员变量和类变量。
- 用static的方法是类方法。类方法通过类名来调用,也可以用对象,但类名调用类方法程序的可读性更好。类方法只能访问类变量,不能访问实例变量。类防范主要用来处理和整个类相关的数据。
- 类的各种方法(包括构造方法)都允许重写(重载)。方法重写overloading,指一个方法名定义多个方法实现。不同的方法,其参数类型或参数个数要有所不同。这就是C++提到的函数签名。
- 方法重写必须要么参数个数不同,要么参数类型不同,仅返回值类型的不同则是不允许的。
- OOP一个特点是公共类资源可以重用。
- 包package是JAVA提供的文件(公共类)的组织方式。一个包对应一个文件夹,一个包可以有很多类文件。包中还可以有子包,称为包等级。
- JAVA可以把类文件存放在可以有包等级的不同的包中。
- 同一个包中的文件名必须唯一,不同包中的文件名可以相同。
- package指出该语句所在文件所有的类属于哪个包。
- 如果一个JAVA文件中有package语句,则必须写在源文件的第一行。
- 当多个JAVA源文件中都有package语句,且包名相同时,说明这些类同属一个包。
- 包中存放的是编译后的类文件.CLASS。通过import,可以导入某个包中的某个类,也可以导入某个包中的全部类,但不包含其子包。
- Windows文件用\表示一条路径下的子路径,JAVA用.表示一个包的子包。
- JDK规定:在一个树形结构的包中,上层包可以导入下层包,而下层包不可以导入上层包。下层包的类要使用上层包的类时,要在类前面加上包名。
- 图形用户界面设计,需要导入系统包java.awt中的所有类;事件处理,需要导入事件处理包java.awt.event中的所有类。
- 一个类被嵌套定义在另一个类中,称为内部类INNER CLASSES或内隐类。包含内部类的类称为外部类。
- 当一个类只在某个类中使用,并且不允许除外部类外的其他类访问时,可考虑设计成内部类。
- 在外部类中,一般通过一个内部类的对象来访问内部类的成员变量或方法;在内部类中,可以直接访问外部类的所有成员变量和方法。
- 当外部类引用内部类时,必须给出完整的名称,且内部类的类名不能与外部类的类名相同。
- 内部类主要用来实现接口。
- JAVA是按类划分程序模块的,很好的实现了类的封装性。
- OOP中,保证模块正确性的基本方法是类的封装性。类的封装性是指类把成员变量和方法封装为一个整体,这就划分了模块的界限。
- 保证模块正确性的措施是由信息的隐藏性实现的。允许其他包程序访问修改的成员变量/方法定义为public,只允许同一包中的其他类以及该类的子类访问修改的成员变量/方法定义为protected,不允许其他类(内部类除外)访问修改的成员变量/方法定义为private。
- 和其他OOP语言C++相比,JAVA增加了包的概念。这样同一包中类之间的信息传递就比较方便。
package classAndObject; public class MyMatrix
{
private int[][] table;
private int height;
private int width; private void init(int m, int n)
{
table = new int[m][n]; for (int i = 0; i < m; i ++)
for (int j = 0; j < n; j ++)
{
table[i][j] = (int)(Math.random() * 100);
}
} public MyMatrix(int n)
{
height = n;
width = n;
this.init(height, width);
} public MyMatrix(int m, int n)
{
height = m;
width = n;
this.init(height, width);
} public int getHeight()
{
return height;
} public int getWidth()
{
return width;
} public int[][] getTable()
{
return table;
} public MyMatrix add(MyMatrix b)
{
if (this.getHeight() != b.getHeight() && this.getWidth() != b.getWidth())
{
System.out.println("the two matrix don't match");
return null;
} MyMatrix result = new MyMatrix(b.getHeight(), b.getWidth());
for (int i = 0; i < b.getHeight(); i ++)
for (int j = 0; j < b.getWidth(); j ++)
{
result.table[i][j] = this.table[i][j] + b.table[i][j];
} return result;
} public MyMatrix subtract(MyMatrix b)
{
if (this.getHeight() != b.getHeight() && this.getWidth() != b.getWidth())
{
System.out.println("the two matrix don't match");
return null;
} MyMatrix result = new MyMatrix(b.getHeight(), b.getWidth());
for (int i = 0; i < b.getHeight(); i ++)
for (int j = 0; j < b.getWidth(); j ++)
{
result.table[i][j] = this.table[i][j] - b.table[i][j];
} return result;
}
}
package classAndObject; public class TestMyMatrix
{
public static void main(String[] args)
{
MyMatrix mm1 = new MyMatrix(4, 4);
MyMatrix mm2 = new MyMatrix(4, 4);
MyMatrix mm3 = new MyMatrix(4, 5);
MyMatrix mm4 = new MyMatrix(4, 5); MyMatrix add_result = mm1.add(mm2);
int [][] add_table = add_result.getTable();
MyMatrix subtract_result = mm3.subtract(mm4);
int [][] subtract_table = subtract_result.getTable(); System.out.println("two matrix add result: ");
for (int i = 0; i < add_result.getHeight(); i ++)
{
for (int j = 0; j < add_result.getWidth(); j ++)
{
System.out.println(add_table[i][j] + " ");
}
System.out.println();
} System.out.println("two matrix subtract result: ");
for (int i = 0; i < subtract_result.getHeight(); i ++)
{
for (int j = 0; j < subtract_result.getWidth(); j ++)
{
System.out.println(subtract_table[i][j] + " ");
}
System.out.println();
}
}
}
第四章 类与继承
- 继承就是一个新类拥有全部被继承类的成员变量和方法,它使得大型应用程序的维护和设计变得更加简单。
- OOP的继承机制提供了一种重复利用原有程序模块资源的途径。通过新类对原有类的继承,既可以扩充旧的程序模块功能以适应新用户需求,也可以满足新的应用系统的功能要求。
- 由继承而得到的新类为子类,被继承的类为父类超类。子类直接的上层父类为直接父类,简称父类。一个子类只能有一个直接父类。
- JAVA所有类都是由OBJECT类继承派生而来。
- 继承有两种:多继承和单继承。JAVA只支持单继承,但接口使JAVA实际上实现了多继承。
- JAVA所有类构成一颗类的层次树结构。
- 定义类有两种:不指明父类和显示的指明父类。若定义时不指明父类,则其父类是OBJECT类。显示指明父类,用extends。
- 子类继承原则:能继承public和protected的成员变量方法,不能继承private和默认的成员变量方法。若子类声明一个与父类同名的成员变量方法,则不能继承,称子类的成员变量隐藏了父类的同名成员变量,子类方法重写了父类的同名方法。子类不能继承父类的构造方法。
- JAVA中,每个对象都有对自身引用的访问权,为this引用。
- super可以引用被子类隐藏的父类的成员变量方法,为super引用。经常用在子类的构造方法中。
- 子类隐藏父类的成员变量,不提倡,很少见;父类的某个方法不适合子类时,子类可以重定义它,为子类对父类方法的覆盖overriding,这是OOP常用的设计方法。
- 方法的重写overloading和方法的覆盖overriding是不同的概念,实现的功能也不同。
- 子类覆盖父类方法时,参数个数和参数类型必须相同。
- 子类对父类方法继承有:完全继承、完全覆盖和修改继承。
- JAVA以及所有OOP语言中,对象访问方法的匹配原则是:从对象定义的类开始,逐层向上匹配寻找对象要访问的方法。
- 继承一方面可以大大简化程序设计的代码,另一方面使得大型软件的功能修改和功能扩充较传统的软件设计方法容易许多。
- 方法的多态polymorphism指若以父类定义对象,并动态绑定对象,则该对象的方法随绑定对象不同而不同。
- 对象名和实际对象的这种联系称作对象的绑定binding。
- 对象的动态绑定,指定一位类树上层的对象名,可以绑定为所定义层类以及下层类的对象。对象的动态绑定和类的继承相结合使对象的方法有多态性。
- 方法的多态性支持Vector类的copyInto()方法用Object类参数(Object []anArrary)定义一次,就可以适合于所有类的对象。
- 构造方法不能被声明为抽象的。
- 不能有abstract static方法。
- 任何包含抽象方法的类必须被声明为抽象类。抽象类不能直接用来定义对象。抽象类主要用于定义为若干个功能类同的类的父类。
- 抽象类一定是某个类或某些类的父类。若干个抽象类的子类要实现一些同名的方法。
- 用final指明不能被子类覆盖的方法,为最终方法。
- 最终类可以保证一些关键类的所有方法,不会再以后的程序维护中,由于不经意的定义子类而被修改;最终方法可以保证一些类的关键方法,不会在以后的程序维护中,由于不经意的定义子类和覆盖子类的方法而被修改。
- abstract和final不能合用。习惯上,public放在abstract/final的前面。
- 单继承有结构简单,层次清楚,易于管理,安全可靠的特点。多继承则功能强大。
- 接口和抽象类非常相似,都是只定义了类中的方法,没有给出方法的实现。
- 接口定义修饰符为缺省时,只能被同一包中的方法访问;public时,接口被任何类的方法访问。
- 若接口定义为默认型访问权限,则接口中的成员变量全部隐含为final static型。意味着它们不能被实现接口方法的类改变,并且为默认访问权限。
- 接口中定义的所有成员变量必须设置初值。
- 接口定义为public时,接口中的所有方法和成员变量全部隐含为public型。
- 保存接口的文件名必须与接口名相同。一个文件可以包含若干个接口,但最多只能有一个public,其他必须为默认。
- 为了实现接口,类必须实现定义在接口中的所有方法。若要实现多个接口,则用逗号分隔开接口名。
- JAVA API中定义了许多接口。
package classAndInherit; class Shape
{
public void draw()
{
System.out.println("Draw a Shape");
}
} class Circle extends Shape
{
public void draw()
{
System.out.println("draw a Circle");
}
} class Ellipse extends Shape
{
public void draw()
{
System.out.println("draw a Ellipse");
}
} public class FInherit
{
public static void main(String args[])
{
Shape s = new Shape();
Shape c = new Circle();
Shape e = new Ellipse(); s.draw();
c.draw();
e.draw();
}
}
package classAndInherit; public class MyInter implements PrintMessage
{
private String[] v;
private int i; public MyInter()
{
v = new String[3];
i = 0;
this.putMessage("Hello world!");
this.putMessage("Hello China!");
this.putMessage("Hello XSYU!");
} public void putMessage(String str)
{
v[i ++] = str;
} @Override
public void printAllMessage()
{
for (int k = 0; k < v.length; k ++)
{
System.out.println(v[k]);
}
} @Override
public void printLastMessage()
{
System.out.println(v[v.length - 1]);
} @Override
public void printFirstMessage()
{
System.out.println(v[0]);
} public static void main(String[] args)
{
MyInter mi = new MyInter();
System.out.println("print all messages");
mi.printAllMessage();
System.out.println("print the first messages");
mi.printFirstMessage();
System.out.println("print the last messages");
mi.printLastMessage();
}
}
第五章 JAVA API基础
- JAVA语言的内核非常小,仅包含基本数据类型和语句,强大功能主要体现在JAVA完备丰富、功能强大的JAVA API上。
- JAVA API(JAVA APPLICATION PROGRAMMING INTERFACE, JAVA应用程序接口),是JAVA提供的组织成包结构的许多类和接口的集合。
- JAVA API包含在JDK中。
- JAVA API语言包java.lang,包括Object类、Class类、Runtime类、Float类、String类和Math类;实用包java.util包括Arrays类、Vector类、Data类和Enumeration接口。
- java.lang包是使用最频繁的包。为了简化编程,系统固定的默认导入java.lang包,所以使用它时不用import。
- Object类是JAVA总所有类的根,在Object类中定义的成员变量和方法,在其他类中都可以使用。
- 当两个值比较、对象或变量与值比较、两个变量比较时,使用==;当两个对象比较时,使用Object.equal()方法。
- System类提供了许多获取或重新设置系统资源的静态方法。
- System类中定义了三个和输入输出流有关的静态成员变量in, out和err。
package javaAPI; public class SystemTest
{
public static void main(String[] args)
{
System.out.println("java.version: " + System.getProperty("java.version")); System.out.println("java.vm.version: " + System.getProperty("java.vm.version")); System.out.println("java.class.path: " + System.getProperty("java.class.path")); System.out.println("os.version: " + System.getProperty("os.version")); System.out.println("user.name: " + System.getProperty("user.name")); System.out.println("user.dir: " + System.getProperty("user.dir")); System.out.println("user.home: " + System.getProperty("user.home"));
} }
- Class类的实例代表一个正在运行的JAVA应用程序的类或接口。JAVA的基本数据类型,数组和关键字void都是由Class对象来表达。
- Class类没有公共的构造方法,Class对象由Java虚拟机自动构造。
- Class类的forName()方法可用于安装驱动程序。
- 每个JAVA应用程序都有一个Runtime类的实例,从而允许应用程序与其运行的环境进行交互。可利用Runtime类直接访问运行时环境资源。
package javaAPI; public class RuntimeTest
{
public static void main(String[] args)
{
Runtime rtime = Runtime.getRuntime();
long totalMemory = rtime.totalMemory() / 1024;
long freeMemory = rtime.freeMemory() / 1024; System.out.println("totalMemory: " + totalMemory + "KB");
System.out.println("freeMemory: " + freeMemory + "KB");
}
}
- 语言包中提供了8个数据类型包装类的类,把JAVA语言的8个基本数据类型(byte/short/int/long/float/double/char/boolean)包装成相应的类:Byte, Short, Integer, Long, Float, Double, Character, Boolean。
- Math类包含了一组基本的数学运算的方法和常数。Math类中所有方法都定义为静态的。还把E和PI定义为类的静态成员变量。
- Math类是最终类final,所有不能从Math类中派生其他的新类。
- random()方法非常有用。把random()的返回值乘上一个整数,可以得到任意区间的double类型的随机数;若转换成int类型,可以得到任意区间的int类型的随机数。
- java.util包主要包含集合框架、事件模型、日期和时间机制、国际化等的类和接口。
- Arrays类中包含有数组操作的一些常用方法,如排序和查找。
- 在使用binarySearch()方法时,要求数组a中的元素已经有序排列,否则返回值未定义。
- Vector类称作向量类,实现了动态的数组,用于元素数量变化的对象数组。Vector类也用从0开始的下标,但和数组不同的是,当Vector对象创建后,数组的元素个数会随着Vector对象元素个数的增大和缩小变化。
- Date类提供了获取当前精确到毫秒时间的方法,并提供许多方法截取当前时间的年月日等数值。
- Calendar类定义了许多如YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, DAY_OF_WEEK等成员变量,get()方法可以获取这些成员变量的值。
package javaAPI; import java.util.*; public class MyDate
{
public static void main(String[] args)
{
Date date = new Date(); System.out.println(date); Calendar now = Calendar.getInstance();
int year = now.get(Calendar.YEAR);
int month = now.get(Calendar.MONTH) + 1;
int day = now.get(Calendar.DATE); System.out.println(year + "-" + month + "-" + day); int hour = now.get(Calendar.HOUR);
int minute = now.get(Calendar.MINUTE);
int second = now.get(Calendar.SECOND); System.out.println(hour + ":" + minute + ":" + second); int week = now.get(Calendar.DAY_OF_WEEK);
String str = "日一二三四五六";
int i = week - 1; System.out.println("星期" + str.substring(i, i + 1));
}
}
- Enumeration接口主要用于集合类对象的序列化。所谓对象是序列化,就是说可以依次取出该对象中的元素。
- 任何一个类,只要实现了Enumeration接口,其对象就是序列化的。
package javaAPI; import java.util.*; public class Exam5_7
{
public static void main(String[] args)
{
final int SIZE = 10;
int i;
int[] a = new int[SIZE]; for (i = 0; i < a.length; i ++)
{
a[i] = (int)(Math.random() * 100);
} System.out.println("Before sort: ");
for (i = 0; i < a.length; i ++)
{
System.out.println(a[i] + " ");
} Arrays.sort(a); System.out.println("\nAfter sort: ");
for (i = 0; i < a.length; i ++)
{
System.out.println(a[i] + " ");
}
}
}
package javaAPI; import java.util.*; public class Josephus
{
public static void main(String[] args)
{
int n = 5, s = 0, d = 2;
Vector v = new Vector(n); for (int i = 0; i < n; i ++)
v.add(new Integer(i + 1)); Enumeration e = v.elements();
while (e.hasMoreElements())
System.out.println(e.nextElement()); int current = s - 1;
while (v.size() > 1)
{
System.out.println("Vector: ");
for (int i = 0; i < v.size(); i ++)
System.out.println(((Integer)v.get(i)).intValue() + " "); int j = 0;
while (j < d)
{
current = (current + 1) % v.size();
j ++;
} System.out.println("\tcurrent = " + current + " ");
v.remove(current);
} System.out.println("The survivor is " + ((Integer)v.get(0)).intValue());
}
}
第六章 图形用户界面
- 图形用户界面是计算机程序和用户交流的图形接口。
- 图形用户界面是由各种不同的组件按照一定的布局模式排列组成的。GUI中的组件一般包括菜单、按钮、标签、文本编辑行等。同时与这些组件配合工作的还有一些相关的事件。
- JAVA中,GUI所用到的类和接口都是有AWT ABSTRACT WINDOW TOOLKIT提供。AWT是JAVA API的一部分。
- java.swing包可以根据换进过来调整GUI的外观和感觉,使得一个程序可以使用各种不同的环境。
- Component类是一个抽象类,是AWT中所有图形组件类的父类。
- add方法可用于在任何组件类对象中添加任何组件类对象。
- Container类主要用来防止其他组件,所以称作容器。它继承自Component类。容器类的派生子类有:框架Frame、面板Panel、窗口Window、对话框Dialog等。
- Panel类是一个放置其他图形组件(包括其他Panel)的容器。
- Frame类是Window的子类,主要用来放置其他组件。Frame类提供了设置标题、改变窗口大小等方法。
- Frame类对象是一个可在Window中独立运行的窗口,而Panel类对象不能单独运行,只能放在容器中(可以放在Frame中,也可以嵌入另一个Panel中)。
- Component类的子类除Container类外,还有Label标签类、Button按钮类、TextField文本输入行类、TextArea多行文本输入区类、Checkbox复选框类、List列表类、Choice下拉列表类等。任何一个容器类对象本身也可以放置在任何一个容器类对象中。
- Label类是用来显示文本text的类。
- TextField类用来创建允许用户编辑的单行文本组件。TextField可以获得焦点,而Lable不能。所以TextField可编辑,而Label不可编辑。TextField一般用作程序的输入。
- TextArea类用来创建允许用户编辑的多行文本输入组件,组件中的字符串可设定为可编辑的或只读的。TextArea类还提供水平或垂直的滚动条。
- FlowLayout布局管理器的功能是:在此框架中加入的组件将自上而下、自左而右安排放置。
package gUI; import java.awt.*; public class TestFrame extends Frame
{
public static void main(String[] args)
{
TestFrame f = new TestFrame();
f.setTitle("My First Frame");
f.setSize(260, 160);
f.setLayout(new FlowLayout());
f.setLocation(0, 0);
f.setResizable(false); Label lb1 = new Label();
lb1.setAlignment(Label.LEFT);
lb1.setText("My First Label");
f.add(lb1); Button b1 = new Button("My First Button");
f.add(b1); TextField t = new TextField();
t.setText("My First TextField");
f.add(t); TextArea t1 = new TextArea("My First TextArea", 3, 20);
t1.setEditable(false);
f.add(t1);
f.setVisible(true);
}
}
- Checkbox类用来创建复选框组件。将几个Checkbox对象组成一组需用到CheckboxGroup类。
- 框架中组件的位置由setBounds方法来确定(不使用任何布局管理器)。
package gUI; import java.awt.*; public class TestCheckbox extends Frame
{
public static void main(String[] args)
{
TestCheckbox f = new TestCheckbox();
f.setTitle("Test Checkbox");
f.setSize(300, 200);
f.setLayout(null); Checkbox checkbox1 = new Checkbox("Computer", true);
Checkbox checkbox2 = new Checkbox("Finance", true);
Checkbox checkbox3 = new Checkbox("Management", false); checkbox1.setBounds(10, 30, 60, 20);
checkbox2.setBounds(10, 50, 60, 20);
checkbox3.setBounds(10, 70, 60, 20);
f.add(checkbox1);
f.add(checkbox2);
f.add(checkbox3); CheckboxGroup zct = new CheckboxGroup();
Checkbox c1 = new Checkbox("Maths", zct, false);
Checkbox c2 = new Checkbox("English", zct, true);
Checkbox c3 = new Checkbox("Arts", zct, false);
Checkbox c4 = new Checkbox("Physics", zct, false);
c4.setCheckboxGroup(zct);
c1.setBounds(150, 30, 60, 20);
c2.setBounds(150, 50, 60, 20);
c3.setBounds(150, 70, 60, 20);
c4.setBounds(150, 90, 60, 20);
f.add(c1);
f.add(c2);
f.add(c3);
f.add(c4);
f.setVisible(true);
}
}
- List组件给用户提供了一个滚动的文本项清单,用户可以选中其中一项或多项文本。
- Choice是一个下拉式的数据选项,当前的选项会显示在选中列表框中。
- 列表只能显示当前选择的项目,而下拉列表可以显示多个项目。
package gUI; import java.awt.*; public class TestChoiceList extends Frame
{
public static void main(String[] args)
{
TestChoiceList f = new TestChoiceList();
f.setTitle("Test ChoiceList");
f.setSize(300, 200);
f.setLayout(new FlowLayout()); List list1 = new List();
list1.setMultipleMode(true);
list1.add("Liberty");
list1.add("Maths");
list1.add("Arts");
list1.add("Physics");
list1.add("KongFu");
list1.select(2);
list1.select(4);
f.add(list1); Choice choice1 = new Choice();
choice1.add("University");
choice1.add("Middle School");
choice1.add("Primary School");
choice1.add("Kindergarden");
choice1.select(2);
f.add(choice1);
f.setVisible(true);
}
}
- MenuComponent类直接继承自Object的菜单组件的基本类,它及其子类是专门用来创建菜单类组件。
- MenuBar是放置菜单的容器。可以通过Frame类的setMenuBar()方法把MenuBar对象加入一个框架中。
- Menu是菜单栏上放置的菜单。每个菜单由一些菜单项组成。
- 所以菜单中的菜单项都是MenuItem类或者它的子类的对象。
package gUI; import java.awt.*; public class TestMenu extends Frame
{
public TestMenu() {} public static void main(String[] args)
{
TestMenu frame1 = new TestMenu();
frame1.setTitle("My Menu");
frame1.setSize(200, 120); MenuBar menubar1 = new MenuBar();
Menu menu1 = new Menu("School");
Menu menu2 = new Menu("Childcare");
MenuItem menuitem1 = new MenuItem("University");
MenuItem menuitem2 = new MenuItem("Middle School");
MenuItem menuitem3 = new MenuItem("Primary School");
MenuItem menuitem4 = new MenuItem("Kindergarden");
MenuItem menuitem5 = new MenuItem("Childcare");
menubar1.add(menu1);
menubar1.add(menu2);
menu1.add(menuitem1);
menu1.add(menuitem2);
menu1.addSeparator();
menu1.add(menuitem3);
menu2.add(menuitem4);
menu2.add(menuitem5);
frame1.setMenuBar(menubar1);
frame1.setVisible(true);
}
}
- 一般在这几种情况下系统会调用paint()方法绘制图形:当一个组件第一次显示时;当容器容器重新调整大小时;当容器从非作用窗口变为作用窗口时。
- 当程序运行在较慢的平台上或计算机较忙时,应该考虑指定在多长时间内必须执行repaint()方法,否则就放弃。
- AWT调用update()方法来响应对repaint()方法的调用。调用update()或paint()之前,图形的外观将不会发生改变。update()更新图形的步骤:先通过填充组件的背景色来清除该图形,再设置图形的颜色为该图形的前景色,最后调用paint()方法完整的重新绘制该图形。
- Color类用来设置文本或图形的颜色。
- JAVA中颜色定义有两种方法:Color类有很多表示颜色的常量;用RGB值设置,每种颜色的色值范围在0~255之间,可以灵活的定义非标准色。
- Font类用来定义文字的字体、风格和大小等特性。
- Graphics类用来绘制各种图形和字符串。虽然Graphics类提供的方法是抽象方法,但编程时可以直接使用,因为系统内部已经实现了这些抽象方法。
- 当没有设置颜色时,组件会使用黑色(默认色)。
- main()方法中不需要调用paint()方法,但程序设计者需要重定义paint()方法来告诉系统需要绘制的图形。
package gUI; import java.awt.*; public class TestGraphics extends Frame
{
public void paint(Graphics g)
{
int x, y, i = 0;
Font font = new Font("Serif", Font.ITALIC|Font.BOLD, 40); g.setFont(font);
g.drawOval(60, 50, 80, 80);
g.setColor(Color.red);
g.fillOval(150, 50, 80, 80);
g.setColor(Color.pink);
g.drawOval(240, 50, 80, 80);
g.setColor(Color.green);
g.drawString("I love Java", 80, 260);
g.setColor(Color.blue);
for (i = 0; i < 20; i ++)
{
x = (int)(Math.random() * 300) + 30;
y = (int)(Math.random() * 200) + 130;
g.fillOval(x, y, 10, 10);
}
g.setColor(Color.orange);
y = 100;
for (i = 0; i < 40; i ++)
{
y += 5;
g.drawRect(30, 30, 320, y);
}
} public static void main(String[] args)
{
TestGraphics f = new TestGraphics();
f.setTitle("My First Graphics");
f.setSize(400, 345);
f.setLocation(0, 0);
f.setVisible(true);
}
}
- 组件在容器中的摆放方式为布局。JAVA中不使用坐标这种绝对定位的方法,而是用布局管理器进行相对定位。优点是显示界面能够自动适应不同分辨率的屏幕。
- FlowLayout布局管理器从左到右排列组件,一行放满后,再从第二行开始。它是容器类组件Panel的默认布局管理器。当容器大小发生变化时,容器上组建的排放位置会发生变化,规律是组件的大小不变,但是相对位置会发生变化。
- FlowLayout构造方法后两个参数的单位都是像素。
package gUI; import java.awt.*; public class TestFlowLayout extends Frame
{
public static void main(String[] args)
{
TestFlowLayout f = new TestFlowLayout(); f.setTitle("My FlowLayout Manager");
f.setSize(200, 120); FlowLayout fl = new FlowLayout();
fl.setHgap(10);
f.setLayout(fl);
f.add(new Button("OK"));
f.add(new Button("Cancel"));
f.add(new Button("Password"));
f.add(new Button("Reset"));
f.setVisible(true);
}
}
- BorderLayout布局管理器按照东西南北中五个区域放置容器中的组件。它是容器类组件Window、Frame和Dialog等的默认布局管理器。当容器大小发生变化时,规律是组件的相对位置不变,大小发生变化。
package gUI; import java.awt.*; public class TestBorderLayout extends Frame
{
public static void main(String[] args)
{
TestBorderLayout frame1 = new TestBorderLayout(); frame1.setTitle("My BorderLayout");
frame1.setSize(200, 200); BorderLayout border = new BorderLayout(5, 10); frame1.setLayout(border);
frame1.add(new Button("South"), BorderLayout.SOUTH);
frame1.add(new Button("West"), BorderLayout.WEST);
frame1.add(new Button("North"), BorderLayout.NORTH);
frame1.add(new Button("East"), BorderLayout.EAST);
frame1.add(new Button("Center"), BorderLayout.CENTER);
frame1.setVisible(true);
}
}
- GridLayout布局管理器可以将容器分为若干个大小相等的矩形。
- 对于复杂的布局,有时还需要用到容器Panel组件。
- 事件源是产生事件的图形组件。用户对事件源进行的操作叫做事件。事件的属性信息包含事件的名称、来源、产生时间等。
- 事件处理过程包括事件的接收和事件的处理两部分。事件的接收由系统负责。
- 事件发生后,系统把时间传递给事件处理程序的方式称为事件模型。
- 层次事件模型首先传递给直接相关的组件;若组件没对事件进行处理,则向上传递给组件所在的容器;若容器没处理,则继续向上传递给容器所在的容器。直至顶层容器。
- 委托事件模型中事件的传递由事件监听器进行管理。任何事件处理程序首先向事件监听器注册,系统监听到后就委托给事件监听器。事件监听器通过分析时间的属性信息,把事件交给已注册的相应事件处理器来处理。JDK1.1以后的版本都采用这个。
- ActionListener接口中只定义了一个处理按钮单击事件的方法actionPerformed()。
- JAVA中的组件就是事件源,它可以产生一个或多个事件。java.awt.AWTEvent类是所有事件类的父类,所以事件类都由它派生出来。
- 一个事件类对应一个事件监听器接口,命名方法是:去掉事件类后边的Event,换成Listener。不同的监听器接口中定义了不同的处理方法。
- 一个事件处理器创建了以后,需要在程序中用语句来注册。addListener()是Component类提供的方法。
- 与键盘事件KeyEvent相对应的键盘事件监听器接口是KeyListener。当键盘刚按下去时,调用keyPressed()方法;键盘抬起来时,调用keyReleased()方法;键盘单击一次时,调用keyTyped()方法。
- 程序可以有几种方式实现事件监听器接口中方法:类定义时加上implements,然后再类中实现接口中的方法;用内部类定义和实现事件监听器接口。
- 若暂时不处理某个窗口操作(事件),可以用一个空语句实现相应的方法。
- 若要实现某个事件监听器接口,就必须实现该事件监听器接口中所以的方法,即使有些方法为空,也必须实现。为了简化设计,JAVA为一些事件的Listener(监听器)接口提供了事件适配器Adapter类。WindowAdapter类实现了WindowListener接口的所有方法(内容为空)。需要实现WindowListener接口时,只需要继承WindowAdapter类,并覆盖相应方法即可。
package gUI; import java.awt.*;
import java.awt.event.*; public class PhoneBook extends WindowAdapter implements ActionListener, ItemListener
{
Frame f;
TextField tf1, tf2;
List l;
Button b1, b2; public PhoneBook()
{
f = new Frame("PhoneBook");
f.setSize(640, 480); Panel p = new Panel();
p.add(new Label("Name"));
tf1 = new TextField(10);
p.add(tf1);
p.add(new Label("PhoneNumber"));
tf2 = new TextField(20);
p.add(tf2);
b1 = new Button("Add");
b2 = new Button("Delete");
b1.addActionListener(this);
b2.addActionListener(this);
p.add(b1);
p.add(b2);
f.add(p, "North"); l = new List();
l.add("Name PhoneNumber");
l.addItemListener(this);
f.add(l); f.setVisible(true);
f.addWindowListener(this);
} public void actionPerformed(ActionEvent e)
{
if (e.getSource() == b1)
l.add(tf1.getText() + " " + tf2.getText()); if (e.getSource() == b2)
l.remove(l.getSelectedIndex());
} public void itemStateChanged(ItemEvent e)
{
String str = l.getSelectedItem();
int i = str.indexOf(' ');
tf1.setText(str.substring(0, i));
str = str.substring(i);
str = str.trim();
tf2.setText(str);
} public void windowClosing(WindowEvent e)
{
System.exit(0);
} public static void main(String[] args)
{
new PhoneBook();
}
}
package gUI; import java.awt.*;
import java.awt.event.*; public class RGBColor extends WindowAdapter implements TextListener
{
Frame f;
TextField tf1, tf2, tf3;
Panel p2; public RGBColor()
{
f = new Frame("Mixed color");
f.setSize(500, 200); Panel p1 = new Panel();
p2 = new Panel();
f.add(p1, "North");
f.add(p2);
p1.add(new Label("Red"));
tf1 = new TextField("255", 10);
p1.add(tf1); p1.add(new Label("Green"));
tf2 = new TextField("0", 10);
p1.add(tf2); p1.add(new Label("Blue"));
tf3 = new TextField("0", 10);
p1.add(tf3); tf1.addTextListener(this);
tf2.addTextListener(this);
tf3.addTextListener(this); p2.setBackground(new Color(255, 0, 0)); f.setVisible(true);
f.addWindowListener(this);
} public void textValueChanged(TextEvent e)
{
int r = (new Integer(tf1.getText()).intValue());
int g = (new Integer(tf2.getText()).intValue());
int b = (new Integer(tf3.getText()).intValue()); if (r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255)
p2.setBackground(new Color(r, g, b));
} public void windownClosing(WindowEvent e)
{
System.exit(0);
} public static void main(String[] args)
{
new RGBColor();
}
}