CoreJava辅导资料


CoreJava辅导资料 作者: heimeiyingwang http://heimeiyingwang.javaeye.com 主要是针对java基础部分做一些相应的辅导,对初学者有一定的帮助。 http://www.javaeye.com - 做最棒的软件开发交流社区 第 1 / 150 页 本书由JavaEye提供的电子书DIY功能自动生成于 2008-12-09 目 录 1. COREJAVA 1.1 COREJAVA(二) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 1.2 corejava辅导(1--1) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 1.3 corejava辅导(1--2) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 1.4 corejava辅导(1--3) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 1.5 corejava辅导(2--1) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 1.6 corejava辅导(2--2) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 1.7 corejava辅导(3) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 1.8 corejava辅导(4--1) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 1.9 corejava辅导(4--2) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 1.10 corejava辅导(4--3) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 1.11 corejava辅导(5--1) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 1.12 corejava辅导(5--2) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 1.13 corejava辅导(5--3) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 1.14 corejava辅导(6) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 1.15 corejava辅导(7--1) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 1.16 corejava辅导(7--2) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 1.17 corejava辅导(7--3) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 1.18 corejava辅导(8--1) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 http://heimeiyingwang.javaeye.com 第 2 / 150 页 1.19 corejava辅导(8--2) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 1.20 corejava辅导(8--3) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 1.21 corejava辅导(9) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 1.22 corejava辅导(10--1) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82 1.23 corejava辅导(10--2) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86 1.24 corejava辅导(11--1) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 1.25 corejava辅导(11--2) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91 1.26 corejava辅导(12--1) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 1.27 corejava辅导(12--2) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 1.28 corejava辅导(12--3) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .100 1.29 corejava辅导(13--1) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .102 1.30 corejava辅导(13--2) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .105 1.31 corejava辅导(14--1) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .108 1.32 corejava辅导(14--2) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .111 1.33 corejava辅导(14--3) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .113 1.34 corejava辅导(14--4) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .117 1.35 corejava辅导(15) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .120 1.36 corejava辅导(16--1) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .123 1.37 corejava辅导(16--2) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .127 1.38 corejava辅导(16--3) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .131 1.39 corejava辅导(16--4) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .135 1.40 corejava辅导(17--1) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .139 http://heimeiyingwang.javaeye.com 第 3 / 150 页 1.41 corejava辅导(17--2) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .142 1.42 corejava辅导(17--3) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .146 http://heimeiyingwang.javaeye.com 第 4 / 150 页 1.1 COREJAVA(二) 发表时间: 2008-12-02 关键字: corejava Java中的变量 局部变量,定义在函数(方法)内部的变量。 例: public class Test{ static void test(){ boolean falg=false;//falg是局部变量,他的有效范围市整个方法体 if(!falg){ int a=20; //局部变量a,是必须进行初始化的且只在if块中有效 } a=10;//注意,这一行是会报编译错误:未声明变量a } } 注意: 1,对于局部变量要先赋值后使用 2,局部变量局部有效,在定义这个变量的代码块也就是在“{}”中有效 3,在重合的有效范围内,不允许两个局部变量发生命名冲突。 Java的数据类型 Java的数据类型,分为两种,基本类型和对象类型。 java的基本数据类型 整型及其兼容类型 byte 1字节8位 -128到127 short 2字节16位 -2^15到2^15-1 int 4字节32位 -2^31到2^31-1 long 8字节64位 -2^63到2^63-1 浮点类型(实型) http://heimeiyingwang.javaeye.com 1.1 COREJAVA(二) 第 5 / 150 页 float 4字节 32位 double 8字节 64位 字符类型(UniCode编码方式) char 2字节 16位 布尔型 boolean false/true 注意:自动类型提升 a 运算符 b 对于这个表达式, a,b中有任意一个是double型,表达运算的结果就是double型 a,b中有任意一个是float型,表达式的运算的结果就是float型 a,b中有任意一个是long型,表达式的运算的结果就是long型 a,b中没有double、float、long型,那么表达式的结果就默认提升为int型。 注意: 1) char是无符号的16位整数,字面值必须用单引号括起来‘a’, 2) 字符串是使用String的,String是类,非原始数据类型,是对象类型,字符串要用双引号“” 。 3) 长整型数字有一个后缀为“L”或“l”,八进制前缀为“0”,十六进制前缀为“0x”。 4) 黙认浮点类型为double。 5) float数据类型有一个后缀为“f”或“F”,double数据类型后可跟后缀“D”或“d“。 6) char类型也可以用通用转译字符,也可以使用ASCII码。可以用“\u0000”这种格式,因为char型中使用的 是unicode编码方式, “\u”后所写的是四位十六进制数。 7)Java中布尔值只能使用true和false这两的字面值,不可以使用!0和0了 注:整型值存放,正数存放原码(二进制码),负数则存放补码(原码按位取反末位加一)。 注:实型值在存储时会损失精度,所以不要直接比较两个实型值。系统默认的实型都是double型,要使用时要在数据后加 个f,或者强行转换。强转(占字节数大的类型转到占字节数小的类型)时会放弃高位值只取低位值。 http://heimeiyingwang.javaeye.com 1.1 COREJAVA(二) 第 6 / 150 页 java中的数字数据类型由占字节数小的类型到占字节数大的类型的会进行自动转换,反之则需要强行转换,char型和int型之 间可以相互强制转换。char和short不能像户转换。 所有基本数据类型在使用时会事先分配空间,只本身就存在空间中,在传递时,就是值传递,不是引用传递。 在类中定义的方法在返回值前加上static修饰符就可以在main方法中调用了。如果不用static那就需要在main方法中创建对 象,使用对象来调用对象的方法。 public class Test{ public static void main(String[] args){ Test t=new Test(); int b=1; int c=2; int[] a=new int[10]; t.sqort(a); add(b,c) } public int[] sqort(int[] a){ span http://heimeiyingwang.javaeye.com 1.1 COREJAVA(二) 第 7 / 150 页 1.2 corejava辅导(1--1) 发表时间: 2008-12-02 关键字: 辅导 一、Java简介 Java语言是编译后再解释执行,Java源码是通过编译生成一种特殊的.class的中间字节码文件,然后再有JVM进行解释执 行,JVM(Java虚拟机)是运行在操作系统中,用来屏蔽的系统间的差异。Java虚拟机处理编译后的字节码,并根据不同的 系统来申请相应的资源,这样就可以保证程序的运行正常,在Java虚拟机的基础之上,由解释器来解释执行字节码文件。 Java虚拟机+解释器=JRE(Java RunTime Environment)Java运行环境 JRE+Java系统类库=JDK(Java Deveple Kit)JAVA开发工具包 Java简单特性: ① JVM本身是不能垮平台的。 ② java语言对指针进行了上层的封装,它保证能够通过这个指针(引用),来访问有效的内存单元。 ③ java语言不允许多继承,使继承关系成树状图,每个类都只能由一个父类。 ④ java语言的开发效率高,但执行效率低。(相当于c++的55%) ⑤ java的垃圾回收机制,在java中new的对象不需要向c++一样进行delete操作,JVM会根据情况回收垃圾对象(懒汉机 制,等待资源没有的时候才回收)。我们只能够建议JVM进行垃圾回收,例如(System.gc() RunTime.gc()这两个方法就是 建议JVM进行垃圾回收的方法)。 JDK —— java开发工具包(类库和运行命令) JRE —— java运行环境 JVM —— java虚拟机(解释执行的核心,对字节码进行翻译成运行环境的机器码,它可以屏蔽平台差异。但JVM是不跨平台 的。) http://heimeiyingwang.javaeye.com 1.2 corejava辅导(1--1) 第 8 / 150 页 二、使用Java是需要进行配置的环境变量 JAVA_HOME, 指明JDK安装的位置; CLASSPATH, 指明类文件的位置; PATH, 指明命令的可执行文件的位置。 例: Unix/Linux中JAVA环境变量的配置 在(.profile(Unix) /.bash_profile(Linux) /.bashrc(Linnx))这些文件中作以下配置 JAVA_HOME=xxx/xxxx (指定JDK的安装目录) CLASSPATH=. (指定类文件的所在位置,类路径) PATH=…:$JAVA_HOME/bin:. (指明JAVA需要使用的命令的位置) Java的一些特点: ① Java是一种纯面向对象的语言,在Java中所有的方法必须写在class(类)中,包括main方法。Java源文件都是 以“.java”为后缀的。 ② java源文件的文件名必须和Java源文件中定义的public class(公开类)的类名相同。在Java源文件中只能写一个public class(公开类),一个Java源文件中可以写多个class(类),也可以在一个类中写另一个类,这是内部类的写法,在以后的 课程中会讲到,一般我们在源文件中的类是并列的,也就是: public class Test1{} class Test2{} http://heimeiyingwang.javaeye.com 1.2 corejava辅导(1--1) 第 9 / 150 页 ③ Java中的(package)包,是一种特殊的目录结构,他会要求编译好的文件在指定的目录结构中,要使用包时需要使 用package关键字。 注意:package关键字必须出现在代码的第一行,下面的代码中写了包,编译之后的.class文件需要在/test/java下,并且包 在一个Java源文件中只能定义一个 例:第一个Java程序 package test.java; //java中的一种用以区分同名类的设置——包 public class HelloWorld{ public static void main(String[] args){ //主方法,JVM主线程 System.out.println("Hello world"); } } 相应的在写完源代码保存的文件名必须和原码中写的 public class后写的类名一致,也就是HelloWorld.java java源代码中的main方法的定义写法。main方法是程序的入口。 public static void main(String[] args){ System.out.println("Hello world"); } java源文件也要先编译,使用javac xxx.java格式的命令得来编译,要运行一个java程序时,需要使用java命令,java 类 名,运行编译后的字节码(.class)文件。 http://heimeiyingwang.javaeye.com 1.2 corejava辅导(1--1) 第 10 / 150 页 定义包结构要放在有效代码的第一行,package xxx.xxx,包的定义在一个程序中只能由一个,在加上包定义之后编译 可以使用javac -d 路径 xxxx.java,这个-d这个命令行的参数可以指定包结构的位置“.”代表当前目录。在运行时要使用类的 全限定名。 java xxx.xxx.xxxx用包名以点分隔。运行时要在包结构的上一层目录来运行。 package xxx.xxx; 定义包名 public class Xxx{} xxx.xxx.Xxx,包名加类名,就是类的全限定名 例: 我们以上面的第一个java文件为例,那个文件中定义的类的全限定名就是test.java.HelloWorld http://heimeiyingwang.javaeye.com 1.2 corejava辅导(1--1) 第 11 / 150 页 1.3 corejava辅导(1--2) 发表时间: 2008-12-03 关键字: 辅导 接下来带包的类是需要生成在指定的目录结构中的,javac命令的 –d 命令行参数可以自动生成包的目录结构 javac –d . HelloWorld.java (–d . 指定包结构生成在当前目录中) java test.java.HelloWorld 注意:在运行有包的类文件时,一定要在包的所在的目录 import 关键字,在使用其他包中的类文件,在类中,可以不必写全限定名直接写类名就可以了,这个关键字和C++中 的#include “xxx”(表示包含,会将xxx插入到文件中)不同,他只不过是告知Java虚拟机导入了该类,在使用的时候不用 标明导入类的全限定名。 package关键字的使用 例1: package test1.a; public class Test{ } import test1.a.*; public class Test2{ static public void main(String[] args){ Test t=new Test(); } } http://heimeiyingwang.javaeye.com 1.3 corejava辅导(1--2) 第 12 / 150 页 import关键字的使用 例2:使用JAVA类库中的类 package test.java; import java.util.*; public class Test{ public static void main(String[] args){ ArrayList al=new ArrayList(); //不是用import就要写成这样 java.util.ArrayList list=new java.util.ArrayList(); /* ArrayList是在java.util包中的一个类,所以在代码中需要导入 使用import关键字,import xxx.xxx.Xxxx,导入包,从而不必 再写类的全限定名,而只写类名就可以了,这个导入的概念和C++ include是不同的概念。 ArrayList是一个类似于C++中模板容器的类 */ } } http://heimeiyingwang.javaeye.com 1.3 corejava辅导(1--2) 第 13 / 150 页 注意:系统会在每个java程序中隐含导入了java.lang这个包。 三、Java的常用package(包) java.lang包,这是一个基础包。 java.util包, 这个包是工具类的包。 java.io包, 这个包是用于输入输出操作的 java.net包, 这个包是用于网络编程。 java.awt,java.swing,javax.swing java.event包,这些包用于java的图形编程用的包。 applaction java的应用程序,java应用程序中必须有一个main()方法。 四、Java程序的运行过程 Java程序的运行过程,执行java命令后,首先是启动java虚拟机,然后就是去找.class文件,并进行加载,先是从系统的 类库中找(系统之会在跟目录下查找,所以需要完整类名),如果找不到的话会去CLASSPATH所设置的目录去找。然后加 载到java虚拟机中。 五、java注释 单行注释 //...... 多行注释 /* .......*/ 文档注释/** ........

(换行标签)*/,用javadoc命令可以根据原码中的文档注释生成注释文档(html格式)。文档注释中可以 使用html标签。 javadoc -d 路径 (指定注释文档的保存路径) 文档注释一般写在类定义之前,方法之前,属性之前。 http://heimeiyingwang.javaeye.com 1.3 corejava辅导(1--2) 第 14 / 150 页 在文档注释中可以用 @author 表示程序的作者,@version 表示程序的版本,前两个注释符号要写在类定义之前,用 于方法的注释@param 对参数进行注释,@return 对返回值进行注释 @throws对抛出异常的注释。 例: package liucy.test; /** *这是一个用于演示javadoc使用方法的类 *@author liucy *@version 1.0 */ public class JavaDocTest{ /** *main 是程序执行的入口,他向屏幕打印“Hello” *@param args 用于保存命令行参数 *@return main 函数不需要返回类型 *@exception main函数没有抛出任何异常 */ public static void main( String args[] ){ System.out.println( "Hello world" ); } } http://heimeiyingwang.javaeye.com 1.3 corejava辅导(1--2) 第 15 / 150 页 1.4 corejava辅导(1--3) 发表时间: 2008-12-03 关键字: 辅导 六、标识符(变量名)和关键字 Java代码中的“;”、“{}”、“ ” Java语句以分号分隔,Java代码(除包、类的定义和import之外)是包含在大括号内,忽略空格。 标识符 1) 用以命名类、方法和变量、以及包遵守JAVA的命名规范类以每个单词都以大写字母开头。方法和变量第一个字母不大写, 常量名都大写,包名都用小写字母。 2) 只能以字符、“_”或“$”开头,可以使用数字,字符以及”_”、”$”作为变量名的组成部分,且Java的标识符是大小 写敏感 3) 无长度限制。 4)可以使用中文作为标识符,不可以使用关键字作为标识符。 正确的标识符: _abc , $234 , For“注意Java是大小敏感的,所以这个For不是关键字” 错误的标识符:234ad “不能以数字开头”,do “do是关键字不可用” goto,“goto虽然不是关键字,但是作为保留字也是不可以用作标识符的” 七、Java中的关键字 Java中大部分的关键字是和C++相同的但是也有些许的修改,以下是需要注意的地方。 1)goto和const在java中虽然不再使用但是还作为关键字存在 2)java中没有sizeof这个关键字了,java中的boolean类型的值只能用true和false,且这两值是不能用作命名的。 3)java语言中没有无符号这个关键字(unsigned) 七、Java中的一种特殊文件—jar包 jar命令用于打一个xxx.jar文件 用法:jar {ctxu}[vfm0Mi] [jar-文件] [manifest-文件] [-C 目录] 文件名 ... 选项: -c 创建新的存档 -t 列出存档内容的列表 -x 展开存档中的命名的(或所有的〕文件 http://heimeiyingwang.javaeye.com 1.4 corejava辅导(1--3) 第 16 / 150 页 -u 更新已存在的存档 -v 生成详细输出到标准输出上 -f 指定存档文件名 -m 包含来自标明文件的标明信息 -0 只存储方式;未用ZIP压缩格式 -M 不产生所有项的清单(manifest〕文件 -i 为指定的jar文件产生索引信息 -C 改变到指定的目录,并且包含下列文件: 如果一个文件名是一个目录,它将被递归处理。 清单(manifest〕文件名和存档文件名都需要被指定,按'm' 和 'f'标志指定的相同顺序 示例1:将两个class文件存档到一个名为 'classes.jar' 的存档文件中: jar cvf classes.jar Foo.class Bar.class 示例2:用一个存在的清单(manifest)文件 'mymanifest' 将 foo/ 目录下的所有 文件存档到一个名为 'classes.jar' 的存档文件中: jar -cvfm classes.jar mymanifest -C foo/ . 一般在使用使用jar cvf 文件名.jar 文件所在路径(xxx/xxx/xxx.class)也可以压缩一个目录,只要在制定路径是指定为 文件夹,jar命令的命令行参数在使用时可以以“-”开头,也可以不用。 http://heimeiyingwang.javaeye.com 1.4 corejava辅导(1--3) 第 17 / 150 页 1.5 corejava辅导(2--1) 发表时间: 2008-12-03 关键字: 辅导 Java中的变量 局部变量,定义在函数(方法)内部的变量。 例: public class Test{ static void test(){ boolean falg=false;//falg是局部变量,他的有效范围市整个方法体 if(!falg){ int a=20; //局部变量a,是必须进行初始化的且只在if块中有效 } a=10;//注意,这一行是会报编译错误:未声明变量a } } 注意: 1,对于局部变量要先赋值后使用 2,局部变量局部有效,在定义这个变量的代码块也就是在“{}”中有效 3,在重合的有效范围内,不允许两个局部变量发生命名冲突。 Java的数据类型 Java的数据类型,分为两种,基本类型和对象类型。 java的基本数据类型 整型及其兼容类型 byte 1字节8位 -128到127 short 2字节16位 -2^15到2^15-1 int 4字节32位 -2^31到2^31-1 long 8字节64位 -2^63到2^63-1 浮点类型(实型) http://heimeiyingwang.javaeye.com 1.5 corejava辅导(2--1) 第 18 / 150 页 float 4字节 32位 double 8字节 64位 字符类型(UniCode编码方式) char 2字节 16位 布尔型 boolean false/true 注意:自动类型提升 a 运算符 b 对于这个表达式, a,b中有任意一个是double型,表达运算的结果就是double型 a,b中有任意一个是float型,表达式的运算的结果就是float型 a,b中有任意一个是long型,表达式的运算的结果就是long型 a,b中没有double、float、long型,那么表达式的结果就默认提升为int型。 注意: 1) char是无符号的16位整数,字面值必须用单引号括起来‘a’, 2) 字符串是使用String的,String是类,非原始数据类型,是对象类型,字符串要用双引号“” 。 3) 长整型数字有一个后缀为“L”或“l”,八进制前缀为“0”,十六进制前缀为“0x”。 4) 黙认浮点类型为double。 5) float数据类型有一个后缀为“f”或“F”,double数据类型后可跟后缀“D”或“d“。 6) char类型也可以用通用转译字符,也可以使用ASCII码。可以用“\u0000”这种格式,因为char型中使用的 是unicode编码方式, “\u”后所写的是四位十六进制数。 7)Java中布尔值只能使用true和false这两的字面值,不可以使用!0和0了 注:整型值存放,正数存放原码(二进制码),负数则存放补码(原码按位取反末位加一)。 注:实型值在存储时会损失精度,所以不要直接比较两个实型值。系统默认的实型都是double型,要使用时要在数据后加 个f,或者强行转换。强转(占字节数大的类型转到占字节数小的类型)时会放弃高位值只取低位值。 http://heimeiyingwang.javaeye.com 1.5 corejava辅导(2--1) 第 19 / 150 页 java中的数字数据类型由占字节数小的类型到占字节数大的类型的会进行自动转换,反之则需要强行转换,char型和int型之 间可以相互强制转换。char和short不能像户转换。 所有基本数据类型在使用时会事先分配空间,只本身就存在空间中,在传递时,就是值传递,不是引用传递。 在类中定义的方法在返回值前加上static修饰符就可以在main方法中调用了。如果不用static那就需要在main方法中创建对 象,使用对象来调用对象的方法。 public class Test{ public static void main(String[] args){ Test t=new Test(); int b=1; int c=2; int[] a=new int[10]; t.sqort(a); add(b,c) } public int[] sqort(int[] a){ span http://heimeiyingwang.javaeye.com 1.5 corejava辅导(2--1) 第 20 / 150 页 1.6 corejava辅导(2--2) 发表时间: 2008-12-03 关键字: 辅导 循环语句 for(int i=0;i父类中是静态方法,子类中不能覆盖为非静态方法,符合覆盖规则的前提下,父子类中,父类中静态方法可以被子类中 静态方法覆盖,但是没有多态。(在使用对象调用静态方法是其实是调用编译时类型的静态方法) <2>父子类中,静态方法只能被静态方法覆盖,父子类中,非静态方法只能被非静态方法覆盖。 Java中main方法必须写成static的,类加载时无法创建对象,静态方法可以不通过对象调用所以main方法是静态的。在类加 载时就可以通过main方法入口来运行程序。 注意:组合方式,需要在方法中创建一个所需要的对象,用这个对象来调用任意所需的该对象的内容,不再受只能访问静态的 约束。 例: public class Test{ private int a; public static void main(String[] args){ } public static void test(){ Test t=new Test(); t.a=20; } http://heimeiyingwang.javaeye.com 1.11 corejava辅导(5--1) 第 40 / 150 页 } 3,static修饰初始代码块,这个初始代码块就叫做静态初始代码块,这个代码块只在类加载时被执行一次。可以用静态初始 代码块初始化一个类。 初始化代码块就是在类中的一个代码块,不是方法的实现。可用来初始化类中的属性。 例: public class Test{ private static int testnum;//这个变量叫做类变量 static{//静态初始化代码块 testnum=12; } } 动态初始代码块,写在类体中的“{}”,这个代码块是生成对象初始化属性时运行的。这种代码块叫动态初始代码块。 例: public class Test{ private static int testnum;//这个变量叫做类变量 {//动态初始化代码块 testnum=12; } } 类在什么时候会被加载, 构造(创建)对象必会加载该类。 调用类中静态方法或访问静态属性也会加载这个静态方法真正所在的类。 构造父类对象时,没有调用子类类中静态方法或访问静态属性,就不会加载子类。 构造子类对象时必会先加载父类。 类加载的延迟加载原则,只有在必须加载时才会加载。 单态模式,是生成一个本类的对象实例 例: public class TestSingleton{ public static void main(String[] args){ http://heimeiyingwang.javaeye.com 1.11 corejava辅导(5--1) 第 41 / 150 页 } } class LaoGong{ /* 懒汉式实现,这种方法实现的单态模式只有在使用到这个 类的对象时才产生对象,但是在多线程情况下会出现问题 */ private static LaoGong lg=null; private LaoGong(){} public static LaoGong newInstance(){ if (lg==null) lg=new LaoGong(); return lg; } } class Wife{ /* 饿汉式的实现方法,这种方法实现的单态模式也不太完美,如果 这个类没有得到使用那么就会有一个垃圾对象生成,但是在多线 程条件下不会有问题 */ private static Wife w=new Wife(); private Wife(){}//私有构造方法 public static Wife newInstance(){ return w; } } span http://heimeiyingwang.javaeye.com 1.11 corejava辅导(5--1) 第 42 / 150 页 1.12 corejava辅导(5--2) 发表时间: 2008-12-03 关键字: java辅导 final修饰符,可以修饰变量,方法,类 1, final修饰变量(包括局部变量和实例变量) 被final修饰的变量就成为常量(常量名应当大写),一旦赋值不能改变,(可以在初始化时直接赋值,在构造方法里可以为 其赋值,只能在这两种方法里二选一,常量不能不赋初值),常量没有默认初始值,final修饰符常和static修饰符一起使用。 例: public class Test{ private static final int TESTNUM=2; //有final修饰符这个变量就变成了常量 …… } 2,final修饰方法,final修饰的方法将不能被子类覆盖,保持方法的稳定不能被覆盖。 例: public class Test{ public final int test(){ 。。。。。。 } } 3,final修饰类,final修饰的类将不能被继承。final类中的方法也都是final的。 例: public final class Test{ public final int test(){ 。。。。。。 } } 注意:final,不能修饰构造方法,在父类中有常量属性,子类中使用常量属性时不会进行父类的类加载。静态常量如果值可 以确定,就不会加载该类,不能确定则会加载该常量所在的类。 http://heimeiyingwang.javaeye.com 1.12 corejava辅导(5--2) 第 43 / 150 页 不变模式,对象一旦创建属性就不会改变。用final修饰类(强不变模式),用final修饰属性(弱不变模式)。 不变模式的典型体现:java.lang.String类,不变模式可以实现对象的共享(可以用一个对象实例赋值给多个对象引用。) 池化的思想,把需要共享的数据放在池中(节省空间,共享数据) String类可以用“ ”中的字面值创建对象。String类中,以字面值创建时,会到Java方法空间的串池空间中去查找,有就返 回串池中字符串的地址,并把这个地址付给对象引用。没有会在串池里创建一个字符串对象,并返回其地址付购对象引用,当 另一个以字面值创建对象时会重复上述过程。 堆空间中创建String类的对象,不会有上述的过程。 例: public class TestString{ public static void main(String[] args){ String str1=”abc”; String str2=”abc”; String str3=new String(“abc”); System.out.println(str1==str2); System.out.println(str1==str3); } } 结果是: true false//在堆空间中创建的Srting是不会从串池中引用的 String类中的intern()方法会将在堆空间中创建的String类对象中的字符串和串池中的比对,有相同的串就返回这个串的串池 中的地址。 不变模式在对于对象进行修改,添加操作是使相当麻烦的,会产生很多的中间垃圾对象。创建和销毁的资源的开销是相当大 的。 String类在字符串连接时的效率很低,因为它所产生的对象的属性是不能修改的,连接字符串时就只能创建新的对象。 对于很多的字符串连接,应当使用StringBuffer类或者是StringBuilder,使用这个类的对象来进行字符串连接时,不会有多 余的中间对象生成,优化了效率。 http://heimeiyingwang.javaeye.com 1.12 corejava辅导(5--2) 第 44 / 150 页 例: 上边的字符串连接如果使用StringBuffer如下的写法 public class TestString{ public static void main(String[] args){ String str=“a”+“b”+”c”; /* 以上创建String对象str时会创建1个中间String对象“ab” 如果使很多字符串相连就是穿件出许多的中间对象 */ StringBuffer str=new StringBuffeter(); //使用StringBuffer就不会有中间对象生成 str.append(“a”); str.append(“b”); str.append(“c”); String strs=str.toString(); } } http://heimeiyingwang.javaeye.com 1.12 corejava辅导(5--2) 第 45 / 150 页 1.13 corejava辅导(5--3) 发表时间: 2008-12-03 关键字: java辅导 abstract(抽象)修饰符,可以修饰类和方法 1, abstract修饰类,会使这个类成为一个抽象类,这个类将不能生成对象实例,可以做为对象引用声明的类型,就是编译 时类型,抽象类就相当于一类的半成品,需要子类继承并覆盖其中的抽象方法。 例: public abstract class Test{ public int test(){ …… } ………. } 2, abstract修饰方法,会使这个方法变成抽象方法,只有声明(定义)没有实现,实现部分以";"代替。需要子类继承实现 (覆盖)。 例: public abstract class Test{ public abstract int test();//有抽象方法的类一定是抽象类 } abstract修饰方法就是要求子类覆盖(实现)这个方法。调用时以多态方式调用子类覆盖(实现)的方法,抽象方法必须在 其子类中实现,除非子类本身也是抽象类。 注意: 1) 有抽象方法的类一定是抽象类。但是抽象类中不一定都是抽象方法,也可以全是具体方法。abstract修饰符在修饰类时必 须放在类名前。 http://heimeiyingwang.javaeye.com 1.13 corejava辅导(5--3) 第 46 / 150 页 2) 父类是抽象类,其中有抽象方法,那么子类继承父类,并把父类中的所有抽象方法都实现(覆盖)了,子类才有创建对象 的实例的能力,否则子类也必须是抽象类。抽象类中可以有构造方法,是子类在构造子类对象时需要调用的父类(抽象类)的 构造方法。 修饰符组合使用问题 final和abstract,private和abstract,static和abstract,这些是不能放在一起的修饰符,因为abstract修饰的方法是必须 在其子类中实现(覆盖),才能以多态方式调用,以上修饰符在修饰方法时期子类都覆盖不了这个方法,final是不可以覆 盖,private是不能够继承到子类,所以也就不能覆盖,static是可以覆盖的,但是在调用时会调用编译时类型的方法,因为 调用的是父类的方法,而父类的方法又是抽象的方法,又不能够调用,所以上的修饰符不能放在一起。 抽象(abstract)方法代表了某种标准,定义标准,定义功能,在子类中去实现功能(子类继承了父类并需要给出从父类继 承的抽象方法的实现)。 方法一时间想不到怎么被实现,或有意要子类去实现而定义某种标准,这个方法可以被定义为抽象。(abstract) 模板方法模式 用abstract把制订标准和实现标准分开,制定的标准就是模板,实现就是按模板标准来实现,继承模板,实现模板中相应功 能的方法。模板中不允许修改的方法用final来修饰,这个方法不能是方法,为保证安全,模板类中不公开的部分 用protected(保护)修饰。 例: public class TestTemplateMethod{ public static void main(String[] ags){ XiaoPin xp=new RangYiRang(); xp.act(); } } abstract class XiaoPin{ protected abstract void jiaoliu(); protected abstract void xushi(); protected abstract void gaoxiao(); protected abstract void shanqing(); public final void act(){ jiaoliu(); http://heimeiyingwang.javaeye.com 1.13 corejava辅导(5--3) 第 47 / 150 页 xushi(); gaoxiao(); shanqing(); } } class ZuYu extends XiaoPin{ protected void jiaoliu(){ System.out.println("ShunKouLiu"); } protected void xushi(){ System.out.println("ZuDiAnMo"); } protected void gaoxiao(){ System.out.println("LiHeYouMen"); } protected void shanqing(){ System.out.println("Sleep..."); } } class RangYiRang extends XiaoPin{ protected void jiaoliu(){ System.out.println("XiaogSiNiMenLe"); } protected void xushi(){ System.out.println("DuChe"); } protected void gaoxiao(){ System.out.println("MaLuJieHun"); } protected void shanqing(){ System.out.println("RangYiRang"); } /* protected void act(){ jiaoliu(); http://heimeiyingwang.javaeye.com 1.13 corejava辅导(5--3) 第 48 / 150 页 xushi(); shanqing(); gaoxiao(); } */ } http://heimeiyingwang.javaeye.com 1.13 corejava辅导(5--3) 第 49 / 150 页 1.14 corejava辅导(6) 发表时间: 2008-12-03 关键字: java辅导6 java中的接口 接口是一种程序结构,是特殊的抽象类。接口中的方法都是公开的抽象方法(public abstract),接口中的属性都是公开静 态常量(public static final)。 声明一个接口用 interface 关键字,接口是一种类型,编译之后生成相应字节码,他的声明规范也要符合类型的定义(一个源文 件中只能有一个public interface,接口名和源文件名相同,有public interface,就不能写public class了)。接口中的属性 可以不加修饰符,方法也不用加修饰符。 接口可以继承,只能由接口继承,用类去实现(继承)时要换用 implements 关键字,类和接口的关系不叫做继承关系,叫 做实现关系,其实质也是继承。 一个类只能继承另外一个类,可以实现多个接口,其语法是在implements后面写接口名,多个接口以“,”分隔。 接口可以多继承,其语法和类的继承语法相同,接口多继承时,在extends后写接口名,继承多个接口,接口名以“,”分 隔,接口的继承关系是把其父接口中的抽象方法继承到子接口中。实现接口就必须实现接口中的所有方法,否则实现类必须是 抽象类。 一个类在继承一个类的同时也可以实现一个或多个接口。采用接口就绕开了单继承限制。 接口类型可以做为编译时类型,其实际的运行时类型必须是完全实现接口的类的对象实例,这样就使多态变得很灵活了, 例: public interface A{ int test(); } interface B extends A{ void count(); } class D{} class C extends D implements A,B{ http://heimeiyingwang.javaeye.com 1.14 corejava辅导(6) 第 50 / 150 页 //C类既实现了A,B两个接口,也继承D类 public int test(){ …… } public void count(){ …… } } 注意: 实现接口时,实现(覆盖)抽象方法,注意必须在方法的返回值类型前加public修饰符,否则就无法覆盖。 没有完全实现接口中的方法,那么这个类就只能是抽象类,不能创建对象。 接口的是实质就是特殊的抽象类。接口没有构造方法。 接口的意义: 1) 接口和匿名内部类可以实现多继承。 2) 用接口可以实现混合类型(主类型,副类型),java中通过接口可以分出主次类型。主类型使用继承,副类型,使用接口 实现。 3) 接口进一步深化了标准的思想,接口本身就是一个标准,起到了降低耦合性的作用。 接口使方法的定义和实现相分离,将接口的定义者和实现者相分离。 接口可以用于降低模块间或系统间的耦合性。 针对接口编程可以屏蔽不同实现间的差异,看到的只是实现好的功能, 接口:定义标准, 接口的实现:实现标准 接口的调用者:标准的使用 针对接口编程原则,也就是按照标准实现。 先有接口的定义,再有接口使用者,最后把接口的实现类对象作参数传入接口的使用者中相应的方法中,接口的使用者会通过 接口来调用接口实现者的方法。 http://heimeiyingwang.javaeye.com 1.14 corejava辅导(6) 第 51 / 150 页 接口的回调 接口的定义者定义好标准,接口的使用者事先写好使用代码。接口的实现者写好实现后把实现类对象传入接口的使用者中,调 用接口中方法也就是调用接口实现类中的方法。这种过程叫做接口的回调。 尽量使用接口类型作为编译时类型,尽量将抽取到的共性行为写在接口中。 接口隔离原则,用若干个小接口取代一个大接口。 把一个类的功能作成接口,暴露想暴露的方法,接口隔离原则可以实现更高层次的封装,针对的对象不同,暴露的方法也不 同。 java中的根类Object java中所有的类的父类,或直接或间接的或隐含的都是Object类。 java不允许循环继承,互相继承是不可以的。 Object类中的finalize()方法是在一个对象被垃圾收集的时候调用的,会由JVM调用这个对象的finalize()方法 Object类的String toString()方法,返回该对象的字符串表示。未覆盖时,toString()方法返回的是类名加上对象实例地址 的一个字符串。在子类中推荐覆盖toString()方法。 Object类中的boolean equals(Object o)方法是用来比较对象的内容是否相等,其返回值是boolean类型的值,相同为 真,不同则为假。未覆盖的equals方法 实际上比较的还是对象地址。String类覆盖了equals()方法,比较的是对象中的内容 是否相同。子类中也推荐覆盖Object类中继承的equals()方法。 equals()的覆盖原则, 自反性 x.equals(x) 为true 对称性 y.equals(x) 和 x.equals(y) 的值要相同,要么都为true,要么都为false。 传递性 x.equals(y)为true, y.equals(z)也为true ,那么x.equals(z)一定也为true。 覆盖equals()方法的步骤 boolean equals(Object o){ if(this==o) return true;//1,判断是不是同一个对象 if(o==null) return true;//2,判断本对象是不是空 if(!(o instanceof 本类类名)) return false;//判断是不是本类对象 http://heimeiyingwang.javaeye.com 1.14 corejava辅导(6) 第 52 / 150 页 ......//根据本类设计。 } 例: public class Student{ private int id; private String name; private String address; public String getAddress() { return address; } public void setAddress(String address) { p MsoPlainTe http://heimeiyingwang.javaeye.com 1.14 corejava辅导(6) 第 53 / 150 页 1.15 corejava辅导(7--1) 发表时间: 2008-12-03 关键字: java辅导 Java封装类 Java为每一个简单数据类型提供了一个封装类,每个简单数据类型可以封装成对象类型。 除int(Integer)和char(Character),其余类型首字母大写即成封装类类型名。double (Double), float(Float),long(Long), short(Short),byte(Byte),boolean(Boolean) 转换字符的方式: int I=10; String s=I+” ”; String s1=String.valueOf(i); Int I=10; Interger I_class=new integer(I); 封装类.字符串.基本类型 Interger--------------------(Double(x.toString))--------------->Double String ---------------------(Integer.valueOf() )---------------->Integer Integer---------------------(x.toString() )-------------------->String int-------------------------(100+””)------------------------->String String----------------------(Integer.parseInt() )--------------->int Integer---------------------(Integer.intValue() )--------------->int 学会查看java的帮助文档。先要关注使用方法的返回值类型,也就是要获得内容的类型,然后看方法名,JDK中的方法名基本 上是见名知义,参数表,看需要什么才可以获得的需要的内容,也要看自己能够提供什么作为参数。 注意:“==”在任何时候都是比较地址,这种比较永远不会被覆盖。 程序员自己编写的类和JDK类是一种合作关系。(因为多态的存在,可能存在我们调用JDK类的情况,也可能存在JDK自动调 用我们的类的情况。) http://heimeiyingwang.javaeye.com 1.15 corejava辅导(7--1) 第 54 / 150 页 注意:类型转换中Double\Interger\String之间的转换最多。 (注:所有使用内部类的地方都可以不用内部类,但使用内部类可以使程序更加的简洁,便于命名规范和划分 层次结构)。 。 内部类 内部类是指在一个外部类的内部再定义一个类。 *内部类可为静态,可用protected和private修饰。(而外部类不可以:顶级类只能使用public和default)。 *JAVA文件中没有publie class 可以类名和文件不同名 内部类的分类 成员内部类、 局部内部类、 静态内部类、 匿名内部类(图形是要用到,必须掌握)。 成员内部类 四个访问权限修饰符都可以修饰成员内部类。 内部类和外部类在编译时是不同的两个类,内部类对外部类没有任何依赖。 内部类是一种编译时语法,在编译时生成各自的字节码文件,内部类和外部类没有关系。 内部类中可以访问外部类的私有成员。 内部类是作为外部类的一个成员存在,与外部类的属性、方法并列。 内部类和外部类的实例变量可以共存。 在内部类中访问实例变量:this.属性 在内部类访问外部类的实例变量:外部类名.this.属性。 在外部类的外部访问内部类,使用out.inner. 成员内部类的特点: http://heimeiyingwang.javaeye.com 1.15 corejava辅导(7--1) 第 55 / 150 页 1.内部类作为外部类的成员,可以访问外部类的私有成员或属性。(即使将外部类声明为private,但是对于处于其内部的 内部类还是可见的。) 2.用内部类定义在外部类中的不可访问的属性。这样就在外部类中实现了比外部类的private还要小的访问权限。 注意:内部类是一个编译时的概念,一旦编译成功,就会成为完全不同的两类。 对于一个名为outer的外部类和其内部定义的名为inner的内部类。编译完成后出现outer.class和outer$inner.class两类。 3.成员内部类不能含有静态成员。 建立内部类对象时应注意: 在外部类的内部可以直接使用inner s=new inner();(因为外部类知道inner是哪个类,所以可以生成对象。) 而在外部类的外部,要生成(new)一个内部类对象,需要首先建立一个外部类对象(外部类可用),然后在生成一个内部 类对象。内部类的类名是外部类类名.内部类类名。 例: public class Test{ public static void main(String[] args){ Outer o=new Outer(); Outer.Inner in=o.new Inner(); Outer.Inner in=(new Outer).new Inner(); } } class Outer{ private int a class Inner{ private int b; public Inner(){ this.b=Outer.this.a } } …… } 静态内部类 http://heimeiyingwang.javaeye.com 1.15 corejava辅导(7--1) 第 56 / 150 页 (注意:前三种内部类与变量类似,所以可以对照参考变量) 静态内部类定义在类中,任何方法外,用static class定义。 静态内部类只能访问外部类的静态成员。 静态内部类和成员内部类的区别 创建(new)一个静态内部类不需要外部类成员:这是静态内部类和成员内部类的区别。 静态内部类的对象可以直接生成: Outer.Inner in=new Outer.Inner(); 而不需要通过生成外部类对象来生成。静态内部类成为了一个和外部类平等的类。静态内部类不可定义为private。 例: public class Test{ public static void main(String[] args){ Outer.Inner in=new Outer.Inner(); } } class Outer{ private static int a static class Inner{ private int b; public Inner(){ this.b=Outer.this.a } } …… } 注意:当类与接口(或者是接口与接口)发生方法命名冲突的时候,此时必须使用内部类来实现。用接口不能 完全地实现多继承,用接口配合内部类才能实现真正的多继承。 例子: 对于两个类,拥有相同的方法: class People { run(); http://heimeiyingwang.javaeye.com 1.15 corejava辅导(7--1) 第 57 / 150 页 } interface Machine{ run(); } 此时有一个robot类: class Robot extends People implement Machine. 此时run()不可直接实现。 interface Machine { void run(); } class Person { void run(){System.out.println("run");} } class Robot extends Person { private class MachineHeart implements Machine { public void run(){System.out.println("heart run");} } public void run(){System.out.println("Robot run");} Machine getMachine(){return new MachineHeart();} } class Test { public static void main(String[] args) { Robot robot=new Robot(); Machine m=robot.getMachine(); m.run(); robot.run(); } } http://heimeiyingwang.javaeye.com 1.15 corejava辅导(7--1) 第 58 / 150 页 1.16 corejava辅导(7--2) 发表时间: 2008-12-03 关键字: java辅导 局部内部类 局部内部类是定义在方法中的内部类。 局部内部类不能够加权限修饰符,其范围为定义它的代码块。 注意:局部内部类不仅可以访问外部类私有实例变量,但可以访问外部类的局部常量(也就是局部变量必须为final的) 局部内部类的特点:不能直接访问局部内部类(保证局部内部类对外是不可见的),只有在方法中才能访问其局部内部类。 局部内部类的作用 通过内部类和接口达到一个强制的弱耦合,用局部内部类来实现接口,并在方法中返回接口类型,使局部内部 类不可见,屏蔽实现类的可见性。 局部内部类写法 public class TestLocalInnerClass{ public static void main(String[] args){ Outer o=new Outer(); final int a=9; o.print(a); } } class Outer{ private int index=100; public void print(final int a){ final int b=10; System.out.println(a); class Inner{ public void print(){ System.out.println(index); System.out.println(a); System.out.println(b); http://heimeiyingwang.javaeye.com 1.16 corejava辅导(7--2) 第 59 / 150 页 } } Inner i=new Inner(); i.print(); } } 匿名内部类 匿名内部类是一种特殊的局部内部类,可通过匿名类隐式的实现接口。 匿名内部类的特点: 1,一个类用于继承其他类或是实现接口,并不需要增加额外的方法,只是对继承方法的事先或是覆盖。 2,只是为了获得一个对象实例,不许要知道其实际类型。 3,类名没有意义,也就是不需要使用到。 注:一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类,没有类名,根据多态,我们使用其父类名。 匿名内部类的特点 1) 因其为局部内部类,那么局部内部类的所有限制都对其生效。 2) 匿名内部类是唯一一种无构造方法类。 3)大部分匿名内部类是用于接口回调用的。 4)匿名内部类在编译的时候由系统自动起名Out$1.class。 5)一个对象编译时的类型是接口,那么其运行的类型为实现这个接口的类。 6)因匿名内部类无构造方法,所以其使用范围非常的有限。 匿名内部类和局部内部类的区别 需要返回多个对象时,使用局部内部类,局部内部类的应用相对较多。匿名内部类中不写构造方法。 匿名内部类的写法: interface A{ void ia(); } class B{ public A bc(){ return new A{ void ia(){ http://heimeiyingwang.javaeye.com 1.16 corejava辅导(7--2) 第 60 / 150 页 System.out.println(“ia”) } }; } } 使用匿名内部类: public class Test{ public static void main(String[] args){ B b=new B(); A a=b.bc(); a.ia(); } } Exception(例外/异常) 对于程序可能出现的错误应该做出预案。 异常是程序中所有出乎意料的结果。(关系到系统的健壮性) JAVA会将所有的异常封装成为一个对象,其根本父类为Throwable。 异常的分类 Throwable有两个子类:Error和Exception。 Error对象表示程序错误,是底层的、低级的、不可恢复的严重错误。此时程序一定会退出,已经失去了运行所必须的物理环 境。对于Error错误无法进行处理。因为我们是通过程序来应对错误,可是程序已经退出了,就无法处理了。 我们可处理的只是Exception类的对象表示的程序异常(例外/异常)。 Exception有两个子类:Runtime exception:(未检查异常)可以在编程时避免,可处理可不处理 非Runtime exception:(已检查异常)必须进行处理。 注意:无论是未检查异常还是已检查异常在编译的时候都不会被发现,在编译的过程中检查的是程序的语法错 误,而异常是一个运行时程序出错的概念。 http://heimeiyingwang.javaeye.com 1.16 corejava辅导(7--2) 第 61 / 150 页 未检查异常是因程序员没有进行必要的检查,因疏忽和错误而引起的异常。属于虚拟机内部的异常(比如空指针)。 应对未检查异常就是养成良好的检查习惯。 已检查异常是不可避免的,对于已检查异常必须事先定义好处理方法。 已检查异常是跨越出了虚拟机的范围外的异常。(比如“未找到文件”) 异常的传递 如何处理已检查异常(对于所有的已检查异常都要进行处理): 首先了解异常形成的机制: 一个方法中有一条语句出现了异常,会throw(抛出)一个例外对象(throw 异常对象),其后的语句不会执行并将异常返 回给上一级方法,上一级方法接受到了例外对象后,可能对这个异常进行处理,也可能将这个异常继续向上传递。 注意:当一个方法中出现了异常,没有进行异常处理,方法就会把异常对象作为返回值返回。如果有异常进入 虚拟机,那么虚拟机就会立刻中止程序的执行。 异常的处理方式 非RuntimeException 已检查异常必须处理,不处理编译不通过。 已检查异常处理方式:throws和try..catch(...){}方法。 注意:抛异常的方法可能是JDK定义的,也可能是程序员写的程序,无论谁写的,抛出一定用throw。 方法的定义中声明方法可能抛出的异常,用(throws 异常类名,异常类名) ,声明这个方法不处理异常,把异常交给上一 级方法处理。可以抛出的是实际产生异常或其父类的异常对象。 例:public void print() throws Exception{} 对于方法a,定义了throws Exception。它调用的方法b返回异常对象时,方法a并不处理,将这个异常对象向上一级返回, 所有的方法均不进行处理,异常返回到主方法,程序会中止。(要避免所有的方法都向上级抛异常,因为这样出现一个很小的 异常就会令程序中止)。 throws(抛)异常时,可以使用多态,一个方法声明抛出异常时,调用这个方法的方法就要处理该异常(已检查异常),要 么抛出一个兼容类型的异常(调用的方法抛出异常的父类或者是相同类型) 例: http://heimeiyingwang.javaeye.com 1.16 corejava辅导(7--2) 第 62 / 150 页 public class Test{ public static void main(String[] args)throws Exception{ Test t=new Test() t.a() } public void a()throws IOException,EOFException{ b(); …… } public void b()throws EOFException{ …… } } 在方法的程序中有一行throw new Exception(),抛出异常,其后的程序不再执行。异常对象抛出后,后面的程序没有执行 机会,JAVA认为异常出现后的程序没有存在的必要。 try..catch捕获异常 对于try……catch格式: try { 可能出现错误的代码块 }catch(Exception e){ 进行处理的代码 } 用这种方法,代码正确,程序不经过catch语句直接向下运行; 代码不正确,则将抛出的异常对象和e的类型进行匹配,匹配成功,运行相应异常处理代码即catch块中代码。 (用Exception来声明e的话,Exception为所有异常对象的父类,所有肯定匹配成功)。处理完代码后这个例外就完全处理 完毕,程序会接着捕获异常的catch块的地方向下执行,最后程序正常退出。 try块中的代码如果没有出现异常,就会跳过catch,正常执行。 try块中抛出了异常,即跳出try块去匹配catch块,try块中抛出异常之后的语句不会执行,在try块中不能写return语句。 一个try块可以跟多个catch块,用于处理不同情况。一个try块中抛出异常后只匹配一个和处理抛出类型异常兼容 的catch块。 http://heimeiyingwang.javaeye.com 1.16 corejava辅导(7--2) 第 63 / 150 页 我们可以写多个catch块,不能将声明处理try块中抛出实际异常类型的父类型异常的catch块,写在声明处理try块中抛出的 实际类型异常的catch块之前。 try块中抛出的异常,先匹配处理其实际异常类型的父类型的catch块,处理抛出实际类型异常的catch块成了永远不会被执行 的代码,java中是不允许写这样的代码,编译不通过。 例: EOFException是IOException的子类,以下写法是错误的,编译不通过 try{ …… }catch(IOException e){ …… }catch(EOFException ex){ …… } http://heimeiyingwang.javaeye.com 1.16 corejava辅导(7--2) 第 64 / 150 页 1.17 corejava辅导(7--3) 发表时间: 2008-12-03 关键字: java辅导 finally关键字 finally{……}在finally语句块中的代码无论如何都会运行 try,catch后还可以再跟一个finally块。finally块中的代码语句无论如何(无论有没有异常)都会执行(finally块多写一些 释放资源,关闭连接的代码)。finally块中的代码在和try块中的代码的冲突时,finally块中的代码一定会执行且会忽略try块 中的代码。但是System.exit(0);(虚拟机退出语句)后则不执行fianlly中的代码。 try{..}catch(..){..} try{..}catch(..){..}finally{..} try{..}finally{..} 以上三种写法都可以。 程序中抛出异常就要处理,无论是使用throws,还是用捕获是用try,catch,不对异常进行处理,编译不通过。 如何知道在编写的程序中会出现例外呢 1.调用方法,查看API中查看方法中是否有已检查错误。 2.在编译的过程中看提示信息,然后加上相应的处理。 Throwable有一个message属性。在使用catch的时候可以调用: try{……}Catch(IOException e){System.out.println(e.message());}//异常的信息的显示 try{……}Catch(IOException e){e. printStackTrace();}//异常堆栈信息的显示 printStackTrace()方法是打印异常堆栈信息,是常用的异常处理的访法,它是异常的方法。 以上两条语句都可打印出错的信息。告诉我们出错类型及代码的运行过程,在调试的中非常有用。 例: public class TestHundredException{ public static void main(String[] args){ MyClass mc=new MyClass(); try{//在这个try语句块中抛出的异常会得到处理 http://heimeiyingwang.javaeye.com 1.17 corejava辅导(7--3) 第 65 / 150 页 System.out.println(mc.add(10,80)); } catch(HundredException e){ //捕获try块中抛出的异常 e.printStackTrace(); } try{ System.out.println(mc.add(30,70)); } catch(HundredException e){ e.printStackTrace(); }finally{ System.exit(0); } } } class HundredException extends Exception{//自定义异常 public HundredException(String message){ super(message); } } class MyClass{ public int add(int a,int b) throws HundredException{ int c=a+b; if (c==100) { throw new HundredException("a+b can\'t be 100"); else{ return c; } } } 自定义异常 自定义异常要是Exception的子类,以下是一个例子: 自己定义异常类必须是Excepiton或者RuntimeException的子类。 http://heimeiyingwang.javaeye.com 1.17 corejava辅导(7--3) 第 66 / 150 页 public class TestMyException{ public static void main(String[] args){ int n=Integer.parseInt(args[0]); A a=new A(); try{ a.calculate(n); } catch(Exception e){ e.printStackTrace(); } System.out.println("OK"); } } class A{ public void calculate(int n) throws ZhiShuException{ for(int i=2;ie.getAge()) return -1; else if (this.salary()e.getSalary()) return -1; else return this.name.compareTo(e.getName()); } } import java.util.*; public class TestEmployee { public static void main(String[] args){ List l=new ArrayList(); l.add(new Employee("Liucy",40,2000)); l.add(new Employee("Hiloo",40,8000)); l.add(new Employee("Chenzq",18,300)); http://heimeiyingwang.javaeye.com 1.18 corejava辅导(8--1) 第 72 / 150 页 l.add(new Employee("George",45,10000)); l.add(new Employee("BaoJie",18,300)); Collections.sort(l); http://heimeiyingwang.javaeye.com 1.18 corejava辅导(8--1) 第 73 / 150 页 1.19 corejava辅导(8--2) 发表时间: 2008-12-03 关键字: java辅导 实现堆栈 1,数组(ArrayList,增删效率比较低,不适合) 2,LinkedList(实现堆栈的好方法) 3,java.util.Stack类,Stack是Vector的子类,Vector类是一个线程安全的(是一个重量级的类),并继承了Vector的方 法,Verctor类(这个类也是List接口的实现类)和ArrayList的功能近乎相同。(不推荐使用Stack类来实现堆栈)。 Set接口的实现类 Set接口 SortedSet接口 TreeSet类 HashSet类 LinkedSet类 1)HashSet Set的实现类的集合对象中不能够有重复元素,HashSet也一样他是使用了一种标识来确定元素的不重复,HashSet用一种算 法来保证HashSet中的元素是不重复的,HashSet的底层实现还是数组。 Object类中的hashCode()的方法是所有子类都会继承这个方法,这个方法会用Hash算法算出一个Hash(哈希)码值返 回,HashSet会用Hash码值去和数组长度取模,模(这个模就是对象要存放在数组中的位置)相同时才会判断数组中的元素 和要加入的对象的内容是否相同,如果不同才会添加进去。如果数组中的元素和要加入的对象的hashCode()返回了相同 的Hash值(相同对象),才会用equals()方法来判断两个对象的内容是否相同。 Hash算法是一种散列算法。 注意:所以要存入HashSet的集合对象中的自定义类必须覆盖hashCode(),equals()两个方法,才能保证集合中元素容不重 复。在覆盖和hashCode()方法时,要使相同对象的hashCode()方法返回相同值,覆盖equals()方法再判断其内容。为了保 证效率,所以在覆盖hashCode()方法时,也要尽量使不同对象尽量返回不同的Hash码值。 例: http://heimeiyingwang.javaeye.com 1.19 corejava辅导(8--2) 第 74 / 150 页 要向HashSet中的添加自定义类型的对象并保证对象在HashSet中的唯一性的话,就要覆盖hashCode()方法 和equals()方法。 import java.util.*; public class TestSet { public static void main(String[] args) { Set s=new HashSet(); TarenaStudent s1=new TarenaStudent("Liucy",30); TarenaStudent s2=new TarenaStudent("Hiloo",29); TarenaStudent s3=new TarenaStudent("Chenzq",33); TarenaStudent s4=new TarenaStudent("Liucy",30); s.add(s1); s.add(s2); s.add(s3); s.add(s4); System.out.println(); print(s); } static void print(Collection c){ Iterator it=c.iterator(); while(it.hasNext()){ System.out.println(it.next()); } } } class TarenaStudent{ String name; int age; public TarenaStudent(String name, int age) { super(); // TODO Auto-generated constructor stub this.name = name; this.age = age; } public String toString(){ return "Student: "+name+" age="+age; http://heimeiyingwang.javaeye.com 1.19 corejava辅导(8--2) 第 75 / 150 页 } public boolean equals(Object o){ System.out.println(this+" equals "+o); if (o==null) return false; if (this==o) return true; if (o.getClass()!=this.getClass()) return false; TarenaStudent t=(TarenaStudent)o; if ((this.name.equals(t.name)) && this.age==t.age) return true; else return false; } public int hashCode(){ return this.name.hashCode()+this.age; } } LinkedSet是Set接口的实现类,他的底层是用链表实现的,他的增删效率很高,常用于过滤重复对象。 SortedSet接口是Set的子接口。 TreeSet是SortedSet接口的实现类,他可以对集合中的元素进行排序。 要存放在TreeSet中自定义类的对象,这个类要么是已经实现了Comparable接口,要么是能给出Comparator比较 器,TreeSet可以自动过滤掉重复元素所以不用重载hashCode()方法,TreeSet会根据比较规则判断元素内容是否相 同,TreeSet会在元素存入世就进行了排序。(在TreeSet给出排序规则时,一定要注意对象内容相等的条件,一定要注意在 主观的认为两个对象内容相同时,才可以使用比较少的条件来进行判断) 在要排序时才使用TreeSet类(存储效率比较低),HashSet的存储效率比较高,在需要为HashSet的对象排序时,就可以 把HashSet中的元素放入TreeSet。 Map接口的实现类 Map接口 SortedMap接口 TreeMap类 HashMap类 Hashtable类 Properties类 http://heimeiyingwang.javaeye.com 1.19 corejava辅导(8--2) 第 76 / 150 页 Map中只可以存放键值对(Key,value),其中Key是不可以重复的。Key和value是一一对应的。 http://heimeiyingwang.javaeye.com 1.19 corejava辅导(8--2) 第 77 / 150 页 1.20 corejava辅导(8--3) 发表时间: 2008-12-03 关键字: java辅导 HashMap,是Map接口的实现类,Key时无序存放的,其中Key是不可以重复的,它也是通过Hash码值来保证Key不重复 的,Key和value是一一对应的。如果要加入的键值对和HashMap中键值对的Key是相同的就会将这个集合中的Key所队应 的value值进行覆盖,在使用自定义类型作为Key时,那就是要覆盖hashCode(),equals()方法,也就是和HashSet中要放入 自定义类型是的处理方法相同。这个类的对象是线程不安全的。 在遍历Map时,要使用其keySet()方法获得Key的一个Set集合,可以通过遍历这个Set,用get()方法来获得Key所对应 的value,也就遍历了Map。 Hashtable,也是Map接口的实现类,他和HashMap比较相似,只不过这个类对象是重量级的,是线程安全的。他不允 许Key和value为null。 Properties,这个类是Hashtable的子类,他的Key和value只能是字符串String类型。 SortedMap是Map的子接口 TreeMap,是SortedMap的实现类,他会按照Key进行排序。和TreeSet类一样,在使用自定义类作Key时,要用自定义类 实现Comparable接口。 注意:其实HashSet底层就是一个HashMap,只不过其中的value值都是null值,而HashMap的底层是用数组实现的。 完整的集合框架 Collection接口 List接口 ArratList类 LinkedList类 Set接口 SortedSet接口 TreeSet类 HashSet类 LinkedSet类 http://heimeiyingwang.javaeye.com 1.20 corejava辅导(8--3) 第 78 / 150 页 Map接口 SortedMap接口 TreeMap类 HashMap类 Hashtable类 Properties类 http://heimeiyingwang.javaeye.com 1.20 corejava辅导(8--3) 第 79 / 150 页 1.21 corejava辅导(9) 发表时间: 2008-12-03 关键字: java辅导 java中的图形界面 GUI,图形化的用户接口,为了人机交互使用的。 构造图形界面的步骤 1,选择一个容器 2,设置容器的布局管理器 3,向容器添加组件 4,事件的监听 容器(Container)用于管理其他的组件的对象。组件必须放到容器里。 JFrame,这是一个最顶层的窗体容器,所有其他的组件必须放在顶层容器里。 JDialog 对话框容器,他要依附于其父组件,他不是一个顶层容器。 JPanel,他不是顶层容器,必须放在顶层容器中,任何一个容器都有add()方法,Panel面板是透明的(默认)。他也是一个 组件。 布局管理:对于任何一个容器类中都有setLayout()方法,用容器对象调用这个方法,来设置容器的布局管理器 (LayoutManager这是一个接口,所有布局管理器都实现了这个接口)。 可用的布局管理器: FlowLayout,流式布局管。Panel的默认布局管理就是FlowLayout。 BorderLayout,按方位进行布局管理,(North,South,East,West,Middle)不明确指定,就会默认加载在中间 (Middle),JFrame的默认布局管理器是BorderLayout add(Component comp,String place)这个方法是在指定的位置添加组件。 GridLayout,网格布局,通过行列,间距,来用网格分割,把组件放入如网格中,先行后列摆放组件。 CardLayout,卡片布局,面板重叠放置。 GridBogLayout,组件可以跨行跨列的网格布局。 注意:一定要在图形界面都其他功能都设置好之后才能设置可见性。 JButton :按钮 JTextField:单行文本域 JTextArea:多行文本区 http://heimeiyingwang.javaeye.com 1.21 corejava辅导(9) 第 80 / 150 页 JScrollPane:滚动窗体 JComboBox:下拉选择框 JRadioButton:单选按钮 JCheckBox:多选按钮 JList:多行列表 JLabel:标签 JPasswordField:密码输入框 JEditorPane:显示结构化文档 Border:边框 JMenuBar:菜单条 JMenu:菜单 JMenuItem:菜单项 JPopupMenu:弹出式菜单 JSlider:滑动条 JProgressBar:进度条 JTabbedPane:分层面板 JSplitPane:分隔面板 JToolBar:工具条 JFileChooser:文件选择器 JColorChooser:颜色选择器 显示对话框 JoptionPane 里面有很多静态方法可以弹出对话框 注意:具体的方法可以去参看Java2 SE的API文档。 http://heimeiyingwang.javaeye.com 1.21 corejava辅导(9) 第 81 / 150 页 1.22 corejava辅导(10--1) 发表时间: 2008-12-03 关键字: java辅导 awt事件模型(观察者模式)(重点) 事件模型中,包括事件源对象,事件处理者(事件监听者对象),事件对象。 事件源和事件处理者之间建立了授权关系,事件源类中有一个事件处理者的对象作为属性,也可能是一个事件处理者的集合。 事件对象 事件源————————〉事件处理者 事件模型的机制,事件源对象发送一个消息(事件对象),事件处理者调用相应的方法处理事件。 事件监听器接口中定义的方法,都以事件对象为参数。 一个事件源可以注册多个同类型的监听器,也可以注册多种多个事件监听器,一个事件监听器也可以为多个事件源服务。 了解一下什么是发消息:A,B,C三个类,分别作为事件源,事件处理者,事件对象。在A类中有一个B类的属性或者是一个 内容为B类对象的集合,事件源和事件处理者之间的建立了授权关系,在B类需要实现一个自定义的接口,这个自定义的接口 继承了EventListener,EventListener接口中没有定义任何方法,EventListener是一个标记接口。实现在自定义接口中定 义好的用于事件处理的方法,C类要继承EventObject类。这些方法是以事件对象为参数的b(C c),在A类a(C c)方法中使 用B类的对象调用B类中的b(C c)方法,并把事件对象作为参数,并在main方法中用A类的对象调用了a(c)方法,叫做A类对 象给B类发送了消息。 例: public class Test{ public static void main(String[] args){ B bt=new B() A at=new A(bt); at.a(new c()); } } class A{ private B b; http://heimeiyingwang.javaeye.com 1.22 corejava辅导(10--1) 第 82 / 150 页 public A(){} public A(B b){ this.b=b; } public void a(C c){ b.b(c); } } class B{ public void b(C c){ System.out.println(“this is message ”+c.c()) } } class C{ public void c (){ System.out.println(“C Object”); } } 事件源对象间接调用了事件监听器的方法,以事件对象为实参传到事件监听器的方法中,事件源给事件监听器的方法发了一个 消息(事件对象)。 例子如下: import java.util.*; //事件源类 class A{ private String test; private List li=new ArrayList(); public A(String test){ this.test=test; } public String getTest(){return this.test;} public void addB(B b){ this.li.add(b); } public void removeB(B b){ http://heimeiyingwang.javaeye.com 1.22 corejava辅导(10--1) 第 83 / 150 页 this.li.remove(b); } public void fire(){ C c=new C(this); Iterator it=li.iterator(); while(it.hasNext()){ B b=(B)it.next(); b.b(c); } } } //事件监听器的接口,要继承EventListener标记接口 interface Blistener extends EventListener{ void b(C c); } //事件监听器,实现接口 class B implements Blistener{ public void b(C c){ A a=(A)c.getSource(); System.out.println(a.getTest()+" "+c.getMessage()); } } //事件对象类 class C extends EventObject{ private String message; public C(Object src){ super(src); } public void setMessage(String message){ this.message=message; } public String getMessage(){return this.message;} } public class Test{ public static void main(String[] args){ A a1=new A("Event"); B b1=new B(); http://heimeiyingwang.javaeye.com 1.22 corejava辅导(10--1) 第 84 / 150 页 c1.setMessage("Test"); a1.addB(b1);//注册监听器 a1.fire();//发送事件 } } 以上代码只是事例,在引入包之后可以运行。 事件对象继承自EventObject类,并可以通过getSource()方法获得事件源对象,当然需要在构造事件对象时将事件源对象传 入,来区分是哪个事件源发出的事件,所以要用事件对象作为参数。 事件源,事件对象,监听器接口,在java.awt包中提供了很多已经定义好的,只需要实现监听接口就好了。 http://heimeiyingwang.javaeye.com 1.22 corejava辅导(10--1) 第 85 / 150 页 1.23 corejava辅导(10--2) 发表时间: 2008-12-03 关键字: java辅导 在Java的图形编程中,所有动作(事件)都已经提供了相应的事件对象和事件监听接口,例如:实现窗口的关闭按钮,点击关 闭按钮会发出相应的事件对象,相应的调用监听器中实现好的方法。相应的方法清参阅Java2 SE API帮助文档。 在图形界面中的添加事件监听的方法 1,组件是事件源,我们实现监听器借口 2,对组件调用addXXXListener()方法,把监听器注入进去。 在java.awt.event包中的ActionEvent类,在以下操作中会发送这个事件, 1,JButton组件,按钮被点击 2,JTextField组件,在单行文本域中按Enter键。 3,JCheckBox组件,选中了复选框。 4,JRadioButton组件,选中了单选按钮。 5,JMenu组件,选中菜单项。 例: Xxxx.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { 。。。。。。 } }); 缺省适配模式,通过一个抽象类实现接口,抽象类中的接口方法实现,都是一个无意义的空实现,可以继承这个抽象类,只覆 盖想覆盖的方法。 注意:在java.awt.event包中,会有一些适配类,也就是把相应的XXXListener,换成XXXAdapter就是适配类。 http://heimeiyingwang.javaeye.com 1.23 corejava辅导(10--2) 第 86 / 150 页 1.24 corejava辅导(11--1) 发表时间: 2008-12-03 关键字: java辅导 Java多线程编程 进程,即运行中的程序,多任务操作系统中并发的一个任务(CPU是分时间片执行多个进程的),线程,其本质是进程中顺序 的执行流程,进程有独立的进程空间进程中的数据存放空间(对空间和栈空间)是独立的。线程没有独立的存放数据的空间, 数据存储空间(堆空间)是共享的,线程间的栈空间是独立的,线程消耗的资源比进程小。 线程,是进程(运行中的程序)中顺序的执行流程,进程可以划分出多个线程。 JVM(java虚拟机)本身就是一个进程,java只能够申请创建线程。 操作系统决定线程是否有优先级,独占式的操作系统中系统会有优先级的概念,共享式的操作系统则不会优先级的。 Java中的线程也是对象,线程类是Thread类,线程是操作系统创建并进行维护的资源,线程对象表示一个线程,本身不是线 程。通过线程对象来申请创建,中止线程,访问底层的线程资源。 线程包含了三部分,cpu资源,代码,数据存储空间。 线程对象调用start()方法,线程对象就会向操作系统申请线程启动,除了申请的线程,还有main方法的线程,也就是主线 程。 注意:只有运行状态的线程才有机会执行代码,主线程的中止不会影响其他的正在运行中的线程,朱线程中止也就 是main()方法退出了。只有进程中的所有线程都中止时,进程(JVM进程)才会退出,只要有线程没有中止,进程就不会退 出。 线程编程的两种方法 1, 写一个类,继承Thread类,覆盖Thread类中继承来的run()方法,这样就写好了自定义的线程类。 例: public class Test{ public static void main(String[] args){ Thread t=new A(); t.start(); } http://heimeiyingwang.javaeye.com 1.24 corejava辅导(11--1) 第 87 / 150 页 class A extends Thread{ public void run(){ ... } } 2,写一个类,实现Runable接口,实现其中的run()方法。这种方法写好的类的对象需要作为线程类创建对象时构造方法的 参数。 例: public class Test{ public static void main(String[] args){ Runable r=new b();//目标对象 Thread t=new Thread(r);//用目标对象构造线程对象 t.start(); } class b implements Runable{ public void run(){ ... } } Thread类的方法 public static void sleep(long millis) throws InterruptedException 括号中以毫秒为单位, 使线程停止一段时间,间隔期满后,线程不一定立即恢复执行。 当main()运行完毕,即使在结束时时间片还没有用完,CPU也放弃此时间片,继续运行其他程序。 try{ Thread.sleep(1000); }catch(InterruptedException e){ e.printStackTrace(e); } public final void join() throws InterruptedException 表示其他运行线程放弃执行权,进入阻塞状态,直到调用线程结束。 实际上是把并发的线程变为串行运行。 http://heimeiyingwang.javaeye.com 1.24 corejava辅导(11--1) 第 88 / 150 页 线程的优先级:1-10,越大优先级越高,优先级越高被OS选中的可能性就越大。(不建议使用,因为不同操作系统的优先级 并不相同,使得程序不具备跨平台性,这种优先级只是粗略地划分)。 注:程序的跨平台性:除了能够运行,还必须保证运行的结果。 Public static void field() 使当前线程马上交出执行权,回到可运行状态,等待OS的再次调用。 Public final Boolean isActive() 验证当前线程是否是活动的,不管它是否正在运行。 线程的生命周期 下面为线程中的7中非常重要的状态:(有的书上也只有认为前五种状态:而将“锁池”和“等待池”都看成是“阻塞”状态 的特殊情况:这种认识也是正确的,但是将“锁池”和“等待池”单独分离出来有利于对程序的理解) 阻塞 结束 ① ⑴ run()方法运行结束 ② ⑵ ③ ⑶ start() OS分配CPU http://heimeiyingwang.javaeye.com 1.24 corejava辅导(11--1) 第 89 / 150 页 可运行 CPU时间片结束 运行 或调用yield() o.wait() 等待锁标记 o.notify() 1, 初始状态,线程创建,线程对象调用start()方法。 2,可运行状态,也就是等待Cpu资源,等待运行的状态。 3,运行状态,获得了Cpu资源,正在运行状态。 4,阻塞状态,也就是让出Cpu资源,进入一种等待状态,而且不是可运行状态,有三种情况会进入阻塞状态。 1)如等待输入(输入设备进行处理,而CPU不处理),则放入阻塞,直到输入完毕,阻塞结束后会进入可运行状态。 2)线程休眠,线程对象调用sleep()方法,阻塞结束后会进入可运行状态。 3)线程对象2调用线程对象1的join()方法,那么线程对象2进入阻塞状态,直到线程对象1中止。 5,中止状态,线程执行结束。所有线程都进入中止状态Java虚拟机进程才结束。 6,锁池状态 7,等待队列 http://heimeiyingwang.javaeye.com 1.24 corejava辅导(11--1) 第 90 / 150 页 1.25 corejava辅导(11--2) 发表时间: 2008-12-03 关键字: java辅导 共享数据的并发处理 多线程同时并发访问的资源叫做临界资源。 多个线程同时访问对象并要求操作相同资源时分割了原子操作就会出现问题。(原子操作,不可再分的操作)会出现数据的不 一致或数据不完整,为避免这种现象采用对访问的线程做限制的方法。 Synchronized关键字 1.Synchronized修饰代码块(同步代码块), public void push(char c){ synchronized(this)//只有持有当前对象的锁标记才能访问这个代码块 { ... } } 对括号内的对象加锁,只有拿到锁标记的对象才能执行该代码块 2.Synchronized修饰方法 public synchronized void push(char c) { ... } 对当前对象的加锁,只有拿到锁标记的对象才能执行该方法。 互斥锁机制,利用每个对象都有一个monitor(锁标记),当线程拥有这个锁标记时才能访问加了同步的这个资源,没有锁标记 便进入锁池。任何一个对象系统都会为其创建一个互斥锁,这个锁是为了分配给线程的,防止打断原子操作。每个对象的锁只 能分配给一个线程。 注意:构造方法不能Synchronized修饰,静态方法可以用Synchronized修饰(是对类对象加锁,类对象会在反射时讲 到)。抽象方法不能用Synchronized修饰,不影响子类覆盖,子类在覆盖这个方法是可以加Synchronized,也可以不 加Synchronized,所以根据Java不允许写废代码的特点是不能写在一起。 注意:对当前对象加锁,一个代码块或者方法是同步的(Synchronized),当前对象的锁标记没有分配出去时,这个对象的锁 标记为分配时,线程来访问这个代码块,会得到这个对象的锁标记,直到这个线程结束才会释放着个锁标记,其他访问这个代 http://heimeiyingwang.javaeye.com 1.25 corejava辅导(11--2) 第 91 / 150 页 码块或者是方法线程就会进入这个对象锁池,没有得到当前对象的锁标记,不能访问这个代码块或者方法。当一个线程想要获 得某个对象锁标记而进入锁池,这个线程又持有其他对象的锁标记,这个线程也不会释放其持有的锁标记。 注:方法的Synchronized特性本身不会被继承。 线程因为未拿到锁标记而发生阻塞进入锁池(lock pool)。每个对象都有自己的一个锁池的空间,用于放置等待运行的线 程。由系统决定哪个线程拿到锁标记并运行。 使用互斥锁的注意事项 举例:男孩和女孩例子,每个女孩是一个对象,每个男孩是个线程。每个女孩都有自己的锁池。每个男孩可能在锁池里等待。 class Girl{ public void hand(){ } public syncronized void kiss(){ } } class Boy extends Thread{ public void run(){ } } 注意:只读不用加同步,只写也不用加同步,只有读写操作兼而有之时才加同步。 注意:在java.io包中Vector 和 HashTable 之所以是线程安全的,是因为每个方法都有synchronized修饰。Static 方法可 以加 synchronized , 锁的是类对象。但是Vector 是 jdk 1.0 的 ArrayList 是 jdk1.2 所以实际应用还是使用ArrayList。 注意:内同步,外同步,内同步,即,类内的方法加同步(synchronized)修饰,外同步即,在需要控制只能由一个线程进行访 问时,把需要控制的方法写在同步代码块里。 http://heimeiyingwang.javaeye.com 1.25 corejava辅导(11--2) 第 92 / 150 页 1.26 corejava辅导(12--1) 发表时间: 2008-12-03 关键字: java辅导 死锁问题 多线程不释放自己拥有的锁标记,而想申请其他线程拥有的锁标记,就会造成死锁。 没有获得加锁对象的锁标记的线程,不能访问只有获得该对象所标记才能访问的同步方法,但可以访问这个对象的非同步的方 法。 死锁的两种处理方法 统一排列锁顺序(解决不同方法中对多个共享资源的访问) 对象1的方法 synchronized(a) synchronized(b) 对象2的方法 synchronized(a) synchronized(b) java线程间通信(也就是线程间的相互协调) 等待通知机制 线程间通信使用的空间称之为对象的等待对列(wait pool),该队列也是属于对象的空间的。 进入等待池 使用Object类中wait()的方法,在运行状态中,线程调用wait(),此时表示线程将释放自己所有的锁标记和CPU的占用,同 时进入这个对象的等待池。等待池的状态也是阻塞状态,只不过线程释放自己的锁标记。在对该对象加锁的同步代码块里,才 能调用该对象的wait()方法,表示线程将会释放所有锁标记,进入等待队列,线程将进入等待队列状态。 一个线程进入了对一个对象加锁的同步代码块,并对该对象调用了wait()方法,释放自己拥有的所有锁标记,进入该对象等待 队列,另一个线程获得了该对象的锁标记,进入代码块对该对象调用了notify()方法(对该对象调用了notifyAll()方法,会释 放等待队列里所有的线程),对该对象调用方法的线程也不会释放所拥有的锁标记(对自身没有影响),也就是从等待队列里 http://heimeiyingwang.javaeye.com 1.26 corejava辅导(12--1) 第 93 / 150 页 释放出一线程,释放出的这个线程要继续运行也就还要进入那个同步代码块,因为得不到要访问代码块对象的锁标记,而进入 该对象的锁池,等待所标记释放。 注意:用notifyAll()取代notify(),因为在调用notify()方法时,是由系统决定释放出哪个线程。 退出等待池进入锁池 注意:只能对加锁的资源进行wait()和notify()。 1) wait():交出锁和CPU的占用,进入该对象的、等待队列。 2) notify():从对象的等待队列中释放任意的一个线程。 3) notifyAll(): 从对象等待队列中释放所有线程并放到锁池中。 Java的I/O流与文件 Java中的文件操作 File类(java.io.File)可表示文件或者目录(在JAVA中文件和目录都属于这个类中,而且区分不是非常的明显)。 File下的方法是对磁盘上的文件进行磁盘操作,但是无法读取文件的内容。 注意:File类的对象实施表示一个文件并不是真正的文件,只是代理而已,通过代理来操作文件创建一个文件对象和创建一个 文件在JAVA中是两个不同的概念。前者是在虚拟机中创建了一个文件,但却并没有将它真正地创建到OS的文件系统中,随 着虚拟机的关闭,这个创建的对象也就消失了。而创建一个文件才是在系统中真正地建立一个文件。 例如: File f=new File(“11.txt”);//创建一个名为11.txt的文件对象 f.CreateNewFile();//真正地创建文件 File类的方法 boolean createNewFile() //创建文件 boolean mkdir() //创建目录 boolean mkdirs() //创建多个目录 boolean delete() //删除文件,删除的是创建File对象时指定与之关联创建的那个文件。 http://heimeiyingwang.javaeye.com 1.26 corejava辅导(12--1) 第 94 / 150 页 boolean deleteOnExit(); //在JVM进程退出的时候删除文件,这样的操作通常用在临时文件的删除。 String[] List()://返回当前File对象下所以显文件和目录名(相对路径) File[] ListFiles()://返回当前File对象(必须是目录)所有Files对象,可以用getName()来访问到文件名。 isDirectory()和isFile()//来判断究竟是目录还是文件。 String getParent()//得到父类文件名,只有在构造对象时传入了Parent对象才有。 File getParentFile()//父路径名的抽象路径名,如果没有指定Parent对象,则返回 null。 String getPath()//获得相对路径。 exists() //判断文件或文件夹是否存在。 getAbsolutePath() //获得文件的绝对路径 使用File类的实例 例:这个类是实现了删除_desktop.ini文件的功能 import java.io.*; public class LsitFile { public static void main(String[] args) throws Exception{ File f=new File("C:\\"); print(f); } static void print(File f){ File[] fs=f.listFiles(new MyFilter()); for(int i=0;i c = null; private String[] belle = new String[4]; public Foreach() { belle[0] = "西施"; belle[1] = "王昭君"; belle[2] = "貂禅"; belle[3] = "杨贵妃"; c = Arrays.asList(belle); http://heimeiyingwang.javaeye.com 1.36 corejava辅导(16--1) 第 124 / 150 页 } public void testCollection(){ for (String b : c){ System.out.println("曾经的风化绝代:" + b); } } public void testArray(){ for (String b : belle){ System.out.println("曾经的青史留名:" + b); } } public static void main(String[] args){ Foreach each = new Foreach(); each.testCollection(); each.testArray(); } } 对于集合类型和数组类型的,我们都可以通过foreach语法来访问它。上面的例子中,以前我们要依次访问数组,挺麻烦: for (int i = 0; i < belle.length; i++){ String b = belle[i]; System.out.println("曾经的风化绝代:" + b); } 现在只需下面简单的语句即可: for (String b : belle){ System.out.println("曾经的青史留名:" + b); } 对集合的访问效果更明显。以前我们访问集合的代码: for (Iterator it = c.iterator(); it.hasNext();){ String name = (String) it.next(); System.out.println("曾经的风化绝代:" + name); http://heimeiyingwang.javaeye.com 1.36 corejava辅导(16--1) 第 125 / 150 页 } 现在我们只需下面的语句: for (String b : c){ System.out.println("曾经的风化绝代:" + b); } Foreach也不是万能的,它也有以下的缺点: 在以前的代码中,我们可以通过Iterator执行remove操作。 for (Iterator it = c.iterator(); it.hasNext();){ it.remove(); } 但是,在现在的for-each版中,我们无法删除集合包含的对象。你也不能替换对象。 同时,你也不能并行的for-each多个集合。所以,在我们编写代码时,还得看情况而使用它。 http://heimeiyingwang.javaeye.com 1.36 corejava辅导(16--1) 第 126 / 150 页 1.37 corejava辅导(16--2) 发表时间: 2008-12-03 关键字: java辅导 可变长的参数 在java5.0中,可以使用一种变长参数,也就是例如m(String… s)的东西,编译器会自动的将方法调用时的参数适当的封装成 数组 5.0之前 public class Test{ public static void main(String[] args){ } } JVM收到数据封装在数组里,然后传入方法 5.0之后 public class Test{ public static void main(String... s){ m();//此时实际调用的是那个无参的m()方法 //注意:调用可变长参数的方法,只在必要时调用 m(1,“abc”,”bcd”); } public static void m(){ System.out.println(“m()”); } public static void m(int a,String… s){ for(String s2:s){ System.out.println(s2+a); } } } 注意:只在必要的时候进行。同时有参数为数组,就不能使用变长参数,有变长参数,就不能使用数组,不能共存。一个方法 最多只能有一个变长参数,而且是最后一个参数。 格式化输出 格式化I/O(Formatted I/O) java.util.Sacner类可以进行格式化的输入,可以使用控制台输入,结合了BufferedReader和StringTokenizer的功能。 http://heimeiyingwang.javaeye.com 1.37 corejava辅导(16--2) 第 127 / 150 页 增加了类似C的格式化输入输出,简单的例子: public class TestFormat{ public static void main(String[] args){ int a = 150000, b = 10; float c = 5.0101f, d = 3.14f; System.out.printf("%4d %4d%n", a, b); System.out.printf("%x %x%n", a, b); System.out.printf("%3.2f %1.1f%n", c, d); System.out.printf("%1.3e %1.3e%n", c, d*100); } } 输出结果为: 150000 10 249f0 a 5.01 3.1 5.010e+00 3.140e+02 类型安全的枚举 枚举也是一个类型,枚举中的对象只能定义一次并在定义时给其初始化,定义之后不能再改变其值,只能从枚举中选择其一。 enum 枚举名{ 枚举值1(..),枚举值2(..),.....; } 在5.0之前使用模式做出枚举 final class Season{ public static final Season SPRING=new Season(); public static final Season WINTER=new Season(); public static final Season SUMMER=new Season(); public static final Season AUTUMN=new Season(); private Season(){} } 完全等价于 enum Season2{ SPRING(..),//枚举值 SUMMER(..), http://heimeiyingwang.javaeye.com 1.37 corejava辅导(16--2) 第 128 / 150 页 AUTUMN(..), WINTER(..); ...... } 枚举是一个反射关联的典型,反射关联,即在类的定义中有自身类型的属性。 枚举本质上也是一个类,Enum是枚举的父类。 枚举中的values()方法会返回枚举中的所有枚举值 枚举中可以定义方法和属性,最后的一个枚举值要以分号和类定义分开,枚举中可以定义的构造方法。 枚举可以实现接口,枚举不能有子类也就是final的,枚举的构造方法是private(私有的),枚举中可以定义抽象方法,可以 在枚举值的值中实现抽象方法,枚举值就是枚举的对象,枚举默认是final,枚举值可以隐含的匿名内部类来实现枚举中定义 抽象方法。 枚举类(Enumeration Classes)和类一样,具有类所有特性。Season2的父类是java.lang.Enum; 隐含方法Season2[] ss=Season2.values(); 每个枚举类型都有的方法。enum可以在switch,case语法中使用(不加类 名)。 例: switch( s ){ case SPRING: ……………. case SUMMER: ……………. ………….. } 枚举类可以写有参构造方法,注意这个构造方法的权限修饰符要是private即私有的,且枚举类的构造方法默认权限修饰符不 是default而是private enum Season2{ SPRING(“春”), SUMMER(“夏”), AUTUMN(“秋”), WINTER(“冬”);//注意这个分号,它代表枚举值结束 private String name; Season2(String name){ this.name=name; } String getName(){ http://heimeiyingwang.javaeye.com 1.37 corejava辅导(16--2) 第 129 / 150 页 return name; } } Season2.SPRING.getName(); 枚举的高级用法: 枚举类中可以定义抽象方法,虽然枚举类是不能有子类的但是,枚举值可以覆盖枚举类中的定义的抽象方法。 例如下: enum Operation{ ADD{//可以在枚举之中覆盖抽象方法 public double calculate(double s1,double s2){ return s1+s2; } }, SUBSTRACT{ public double calculate(double s1,double s2){ return s1-s2; } }, MULTIPLY{ public double calculate(double s1,double s2){ return s1*s2; } }, DIVIDE{ public double calculate(double s1,double s2){ return s1/s2; } }; public abstract double calculate(double s1 ,double s2);//抽象方法 } 有抽象方法枚举元素必须实现该方法。 http://heimeiyingwang.javaeye.com 1.37 corejava辅导(16--2) 第 130 / 150 页 1.38 corejava辅导(16--3) 发表时间: 2008-12-03 关键字: java辅导 java5.0中的泛型 说明 增强了java的类型安全,可以在编译期间对容器内的对象进行类型检查,在运行期不必进行类型的转换。而在java se5.0之前 必须在运行期动态进行容器内对象的检查及转换,泛型是编译时概念,运行时没有泛型 减少含糊的容器,可以定义什么类型的数据放入容器 List aList = new ArrayList(); aList.add(new Integer(1)); // ... Integer myInteger = aList.get(0); 支持泛型的集合,只能存放制定的类型,或者是指定类型的子类型。 我们可以看到,在这个简单的例子中,我们在定义aList的时候指明了它是一个只接受Integer类型的ArrayList,当我们调 用aList.get(0)时,我们已经不再需要先显式的将结果转换成Integer,然后再赋值给myInteger了。而这一步在早先 的Java版本中是必须的。也许你在想,在使用Collection时节约一些类型转换就是Java泛型的全部吗?远不止。单就这个例 子而言,泛型至少还有一个更大的好处,那就是使用了泛型的容器类变得更加健壮:早先,Collection接口 的get()和Iterator接口的next()方法都只能返回Object类型的结果,我们可以把这个结果强制转换成任何Object的子类,而 不会有任何编译期的错误,但这显然很可能带来严重的运行期错误,因为在代码中确定从某个Collection中取出的是什么类 型的对象完全是调用者自己说了算,而调用者也许并不清楚放进Collection的对象具体是什么类的;就算知道放进去的对 象“应该”是什么类,也不能保证放到Collection的对象就一定是那个类的实例。现在有了泛型,只要我们定义的时候指明 该Collection接受哪种类型的对象,编译器可以帮我们避免类似的问题溜到产品中。我们在实际工作中其实已经看到了太多 的ClassCastException。 用法 声明及实例化泛型类: http://heimeiyingwang.javaeye.com 1.38 corejava辅导(16--3) 第 131 / 150 页 HashMap hm = new HashMap(); 编译类型的泛型和运行时类型的泛型一定要一致。没有多态。 不能使用原始类型 GenList nList = new GenList(); //编译错误 Java SE 5.0目前不支持原始类型作为类型参数(type parameter) 定义泛型接口: public interface GenInterface { void func(T t); } 定义泛型类: public class ArrayList { ... } public class GenMap { ... } 例1: public class MyList extends LinkedList { public void swap(int i, int j){ Element temp = this.get(i); this.set(i, this.get(j)); this.set(j, temp); } public static void main(String[] args){ MyList list = new MyList(); list.add("hi"); list.add("andy"); System.out.println(list.get(0) + " " + list.get(1)); list.swap(0,1); http://heimeiyingwang.javaeye.com 1.38 corejava辅导(16--3) 第 132 / 150 页 System.out.println(list.get(0) + " " + list.get(1)); } } 泛型的通配符"?" ? 是可以用任意类型替代。 泛型通配符表示任意类型 表示这个类型是某个类型的子类型,或是某个接口的实现类 表示这个类型是某个类型的父类型。 例:泛型通配符、带范围的泛型通配符 import java.util.*; import static java.lang.System.*; public class TestTemplate { /** * @param args */ public static void main(String[] args) { List l1=new ArrayList(); l1.add("abc"); l1.add("def"); List l2=new ArrayList(); l2.add(1.3); l2.add(11); List l3=new ArrayList(); l3.add(123); l3.add(456); // print(l1); print(l2); print(l3); } static void print(List l//泛型通配符){ //所有Comparable接口的实现类可以作为泛型参数 http://heimeiyingwang.javaeye.com 1.38 corejava辅导(16--3) 第 133 / 150 页 for(Object o:l){ out.println(o); } } static void print(List l//带范围的泛型通配符){ //所有Number的子类可以作为泛型参数 for(Object o:l){ out.println(o); } } static void print(List l){ //所有Comparable接口的实现类可以作为泛型参数 for(Object o:l){ out.println(o); } } static void print(List l){ //所有Number的父类可以作为泛型参数 for(Object o:l){ out.println(o); } } } "?"可以用来代替任何类型, 例如使用通配符来实现print方法。 public static void print(GenList list) {}) http://heimeiyingwang.javaeye.com 1.38 corejava辅导(16--3) 第 134 / 150 页 1.39 corejava辅导(16--4) 发表时间: 2008-12-03 关键字: java辅导 泛型方法的定义 把数组拷贝到集合时,数组的类型一定要和集合的泛型相同。 <...>定义泛型,其中的"..."一般用大写字母来代替,也就是泛型的命名,其实,在运行时会根据实际类型替换掉那个泛型。 需要泛型参数或返回值同时又是某个类的子类又是某个接口的实现类的时候,可以使用 这种写法,注意:接口类型要放在类的后面,且只能使用’&’符。 例: public class Test{ void copyArrayToList(E[] os,List lst){ for(E o:os){ lst.add(o); } } static void copyArrayToList(E[] os,List lst){ for(E o:os){ lst.add(o); } } static void copyArrayToList(E[] os,List lst){ for(E o:os){ lst.add(o); } } } 受限泛型是指类型参数的取值范围是受到限制的。 extends关键字不仅仅可以用来声明类的继承关系, 也可以用来声明类型参数(type parameter)的受限关系。例如, 我们只需 要一个存放数字的列表, 包括整数(Long, Integer, Short), 实数(Double, Float), 不能用来存放其他类型, 例如字符串(String), 也就是说, 要把类型参数T的取值泛型限制在Number极其子类中.在这种情况下, 我们就可以使用extends关键字把类型参 数(type parameter)限制为数字 只能使用extends不能使用 super,只能向下,不能向上。 http://heimeiyingwang.javaeye.com 1.39 corejava辅导(16--4) 第 135 / 150 页 注意:只有参数表中可以使用 ,定义泛型时用 泛型类的定义 我们也可以在定义类型中使用泛型 注意:静态方法中不能使用类的泛型,因为泛型类是在创建对象的时候给定泛型。 例: class MyClass{ public void show(E a){ System.out.println(a); } public E get(){ return null; } } 受限泛型 class MyClass { public void show(E a){ } } 泛型与异常 泛型参数在catch块中不允许出现,但是能用在方法的throws之后。例: import java.io.*; interface Executor { void execute() throws E; } public class GenericExceptionTest { public static void main(String args[]) { try { Executor e = new Executor() { public void execute() throws IOException{ http://heimeiyingwang.javaeye.com 1.39 corejava辅导(16--4) 第 136 / 150 页 // code here that may throw an // IOException or a subtype of // IOException } }; e.execute(); } catch(IOException ioe) { System.out.println("IOException: " + ioe); ioe.printStackTrace(); } } } 泛型的一些局限型 catch不能使用泛型,在泛型集合中,不能用泛型创建对象,不允许使用泛型的对象。 不能实例化泛型 T t = new T(); //error 不能实例化泛型类型的数组 T[] ts= new T[10]; //编译错误 不能实例化泛型参数数 Pair[] table = new Pair(10); // ERROR 类的静态变量不能声明为类型参数类型 public class GenClass { private static T t; //编译错误 } 静态方法可以是泛型方法,但是不可以使用类的泛型。 泛型类不能继承自Throwable以及其子类 http://heimeiyingwang.javaeye.com 1.39 corejava辅导(16--4) 第 137 / 150 页 public GenExpection extends Exception{} //编译错误 不能用于基础类型int等 Pair //error Pair //right http://heimeiyingwang.javaeye.com 1.39 corejava辅导(16--4) 第 138 / 150 页 1.40 corejava辅导(17--1) 发表时间: 2008-12-03 关键字: java辅导 JAVA5.0 的注释 (Annotation) 描述代码的代码。给编译器看的代码,作用是规范编译器的语法。 class Student{ @Override public String toString(){ return “student”; } } 类型(接口) 1. 标记注释 标记注释中没有属性,所以也不需要为属性赋值 @Override 2. 单值注释 单值注释中只能定义一个属性。 @注释名(prameter=10) int parameter 特例: @注释名 (value “134” )(当单值注释的属性名为value时,可以省略属性名,直接写值) @SuperessWarning({“ddd”,”aaa”,”ccc”}) //JVM还没有实现这个注释 3.普通注释(多值注释) (key1=value,……) 4.自定义注释 public @interface Test{ http://heimeiyingwang.javaeye.com 1.40 corejava辅导(17--1) 第 139 / 150 页 } 在自定义注释时,要用注释来注释(描述)注释。 @Target(value={……}),用来描述自定义注释所适用的程序元素的种类。单值注释 这个注释的值只能是ElementType枚举值,只能使用以下的值 ANNOTATION_TYPE 注释类型声明 CONSTRUCTOR 构造方法声明 FIELD 属性声明(包括枚举常量) LOCAL_VARIABLE 局部变量声明 METHOD 方法声明 (常用) PACKAGE 包声明 PARAMETER 参数声明 TYPE 类、接口(包括注释类型)或枚举声明(常用) 例: @Target({ElementType.METHOD, ElementType .TYPE})//表示这个注释可用的范围,这个注释可以用在方法和类型及 接口。 @Retention(value=……),描述(注释)注释能够保留到什么时候。单值注释 其中的值只能是以下的RetentionPolicy枚举的值 CLASS 编译器将把注释记录在类文件中,但在运行时 VM 不需要保留注释。 RUNTIME 编译器将把注释记录在类文件中,在运行时 VM 将保留注释,因此可以反射性地读取。 SOURCE 编译器要丢弃的注释。 例: @Retention(RetentionPolicy.RUNTIME) // 编译器将把注释记录在类文件中,在运行时 VM 将保留注释,因此可以反射性地读取。 @Documented表示某一类型的注释将通过 javadoc 和类似的默认工具进行文档化 @Inherited 表示注释类型该注释会被自动继承 注释的属性类型可以是8种基本类型、String、Enum、Class、Annotation以及它们的数组 例: @Test() public class MyClass2 { @Test() public void study(String name){ http://heimeiyingwang.javaeye.com 1.40 corejava辅导(17--1) 第 140 / 150 页 System.out.println("Study "+name); } @Test(value="Meal")//单值注释 @Author(value={@Name(firstName="Liu",lastName="Chunyang"),@Name(firstName="Xue",lastName="Hiloo")})//单 值注释中是用数组类型地赋值方法 public void eat(String food){ System.out.println("Eat "+food); } } 自定义注释的写法 例: import java.lang.annotation.*; @Target({ElementType.METHOD}) //表示这个注释可用的范围,这个注释只能用在方法之上。 @Retention(RetentionPolicy.RUNTIME) // 编译器将把注释记录在类文件中,在运行时 VM 将保留注释,因此可以反射性地读取。public @interface Author { Name[] value(); /* 定义注释的属性,注意属性后面要价括号,这个属性既是属性又是方法,可以返回属性的值 */ } import java.lang.annotation.*; @Target({ElementType.METHOD,ElementType.TYPE})//这个注释可用于类,接口和方法 @Retention(RetentionPolicy.RUNTIME) public @interface Test { String value() default "ABC" ;//定义注释的属性及其默认值 } http://heimeiyingwang.javaeye.com 1.40 corejava辅导(17--1) 第 141 / 150 页 1.41 corejava辅导(17--2) 发表时间: 2008-12-03 关键字: java辅导 处理自定义注释的类 例: import java.lang.reflect.*; public class TestFramework { public static void main(String[] args) throws Exception { Class c=Class.forName("MyClass2");//获取有注释的类的类对象 Method[] ms=c.getMethods();//获得该类中有的方法对象 Object o=c.newInstance();//获得该类的实例 for(Method m:ms){ boolean flag=m.isAnnotationPresent(Test.class); /* isAnnotationPresent(Class c)这个方法是判断这个方法是不是加上了注释注意这是方法对象的方法 */ if (flag){ Test t=m.getAnnotation(Test.class); /* getAnnotation(Class c)方法是获得该方法的注释,得到注释对象t 可以通过注释对象 ”属性名()”也就是value(),获得注释的属性的值 */ String value=t.value(); m.invoke(o,value); } flag=m.isAnnotationPresent(Author.class); if (flag){ Author a=m.getAnnotation(Author.class); Name[] ns=a.value(); for(Name n:ns){ String fn=n.firstName(); String ln=n.lastName(); System.out.println(fn+ " "+ ln); } } } http://heimeiyingwang.javaeye.com 1.41 corejava辅导(17--2) 第 142 / 150 页 } } 例2: 定义注释 import java.lang.annotation.*; @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface Test { String name(); String sex(); } 使用注释 public class TestAnntion { @Test(name="liucy",sex="man") public void test(String name,String sex){ System.out.println(name+" "+sex); } } 处理注释 import java.lang.reflect.Method; public class TestT { public static void main(String[] args) throws Exception { Class c=Class.forName(args[0]); Method[] ms=c.getMethods(); Object o=c.newInstance(); for(Method m:ms){ boolean flag=m.isAnnotationPresent(Test.class); if (flag){ Test t=m.getAnnotation(Test.class); String name=t.name(); String sex=t.sex(); m.invoke(o, name,sex); http://heimeiyingwang.javaeye.com 1.41 corejava辅导(17--2) 第 143 / 150 页 } } } 三个新加的多线程包 Java 5.0里新加入了三个多线程包: java.util.concurrent, java.util.concurrent.atomic, java.util.concurrent.locks. java.util.concurrent包含了常用的多线程工具,是新的多线程工具的主体。 java.util.concurrent.atomic包含了不用加锁情况下就能改变值的原子变量,比如说AtomicInteger提供 了addAndGet()方法。Add和Get是两个不同的操作,为了保证别的线程不干扰,以往的做法是先锁定共享的变量,然后在 锁定的范围内进行两步操作。但用AtomicInteger.addAndGet()就不用担心锁定的事了,其内部实现保证了这两步操作是 在原子量级发生的,不会被别的线程干扰。 java.util.concurrent.locks包包含锁定的工具。 Callable 和 Future接口 Executor接口替代了Thread类,他可以创建定量的和动态以及周期性的线程池。 ExecutorService接口,线程池,用来存放线程来节省创建和销毁资源的消耗。 Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其它线程执行的任务。 Callable和Runnable有几点不同: Callable规定的方法是call(),而Runnable规定的方法是run(). Callable的任务执行后可返回值,而Runnable的任务是不能返回值的。 call()方法可抛出异常,而run()方法是不能抛出异常的。 Future对象可以获得线程运行的返回值 运行Callable任务可拿到一个Future对象,通过Future对象可了解任务执行情况,可取消任务的执行,还可获取任务执行的 结果。 以下是Callable的一个例子: public class DoCallStuff implements Callable{ // *1 private int aInt; public DoCallStuff(int aInt) { this.aInt = aInt; } http://heimeiyingwang.javaeye.com 1.41 corejava辅导(17--2) 第 144 / 150 页 public String call() throws Exception { //*2 boolean resultOk = false; if(aInt == 0){ resultOk = true; } else if(aInt == 1){ while(true){ //infinite loop System.out.println("looping...."); Thread.sleep(3000); } } else { throw new Exception("Callable terminated with Exception!"); //*3 } if(resultOk){ return "Task done."; } else { return "Task failed"; } } } http://heimeiyingwang.javaeye.com 1.41 corejava辅导(17--2) 第 145 / 150 页 1.42 corejava辅导(17--3) 发表时间: 2008-12-03 关键字: java辅导 *1: 名为DoCallStuff类实现了Callable,String将是call方法的返回值类型。例子中用了String,但可以是任何Java类。 *2: call方法的返回值类型为String,这是和类的定义相对应的。并且可以抛出异常。 *3: call方法可以抛出异常,如加重的斜体字所示。 以下是调用DoCallStuff的主程序。 import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class Executor { public static void main(String[] args){ //*1 DoCallStuff call1 = new DoCallStuff(0); DoCallStuff call2 = new DoCallStuff(1); DoCallStuff call3 = new DoCallStuff(2); //*2 ExecutorService es = Executors.newFixedThreadPool(3); //*3 Future future1 = es.submit(call1); Future future2 = es.submit(call2); Future future3 = es.submit(call3); try { //*4 System.out.println(future1.get()); //*5 Thread.sleep(3000); System.out.println("Thread 2 terminated? :" + future2.cancel(true)); //*6 System.out.println(future3.get()); } catch (ExecutionException ex) { ex.printStackTrace(); } catch (InterruptedException ex) { ex.printStackTrace(); } http://heimeiyingwang.javaeye.com 1.42 corejava辅导(17--3) 第 146 / 150 页 } } *1: 定义了几个任务 *2: 初始了任务执行工具。任务的执行框架将会在后面解释。 *3: 执行任务,任务启动时返回了一个Future对象,如果想得到任务执行的结果或者是异常可对这个Future对象进行操 作。Future所含的值必须跟Callable所含的值对映,比如说例子中Future对印Callable *4: 任务1正常执行完毕,future1.get()会返回线程的值 *5: 任务2在进行一个死循环,调用future2.cancel(true)来中止此线程。传入的参数标明是否可打断线程,true表明可以打 断。 *6: 任务3抛出异常,调用future3.get()时会引起异常的抛出。 运行Executor会有以下运行结果: looping.... Task done. //*1 looping.... looping....//*2 looping.... looping.... looping.... looping.... Thread 2 terminated? :true //*3 //*4 java.util.concurrent.ExecutionException: java.lang.Exception: Callable terminated with Exception! at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:205) at java.util.concurrent.FutureTask.get(FutureTask.java:80) at concurrent.Executor.main(Executor.java:43) ……. *1: 任务1正常结束 *2: 任务2是个死循环,这是它的打印结果 *3: 指示任务2被取消 *4: 在执行future3.get()时得到任务3抛出的异常 lock接口 实现类ReentrantLock 我们可以用lock对象,来对临界资源加锁调用lock对象的lock()方法,使得没有得到锁的线程阻塞,解锁则调用lock对象 的unlock()方法,并且释放锁,只有获得lock对象才能访问临界资源,如果没有获得lock对象,就会进入lock对象的锁 池。trylock()方法会返回布尔值,这个方法是用来判断这个锁对象是不是已经被线程获取,如果返回值为true,则会直接获 得这个锁对象,如果返回false,线程不会阻塞还会继续运行。 Lock lock=new ReentrantLock(); http://heimeiyingwang.javaeye.com 1.42 corejava辅导(17--3) 第 147 / 150 页 publci void test(){ try{ if(lock.trylock){//判断锁是否已经分配出去 lock.lock(); //如果锁没有被分配,就会获得锁,没有得到锁,就阻塞 }else{ ...... } .....//需要加锁的临界资源。 }finally{ lock.unlock();//解锁,释放锁。 } } ReadWriteLock读写锁接口 ReentrantReadWriteLock是ReadWriteLock的实现类。 ReentrantReadWriteLock的Lock readLock()方法会分配读锁对象,读锁可以分配多个线程,但是在分配读锁后所有读锁 释放前,写锁是不能被分配的。 ReentrantReadWriteLock的Lock writeLock()方法会分配写锁对象,且只能分配给一个线程,在分配写锁后,在写锁释 放前,读锁是不能被分配。 Condition接口和实现类 Condition是等待对列的对象,它是通过lock对象的newCondition()方法得到的 Condition实现类的await()替代了wait()方法。 notify(),notifyAll() 在JDK5.0中已经用Condition实现类的signal() ,signalAll()方法替换掉了,在JDK5.0中,可以使用 多个等待队来存放等待的线程,并对线程进行分类。 Queue接口(Collection的子接口,队列接口) LinkedList也实现了这个在JDK5.0中的新接口Queue,并且这个类自动的实现了生产者和消费者的同步。 JDK5.0的高级同步 Semaphore类(信号量)也就是可以向线程分配许可证,指定许可证数量可以实现多线程的同步。 Semaphore s=new Semaphore(4); //可以分配4个许可证,许可证都被分配出去时,得不到许可证的线程就会阻塞。 Semaphore类的acquire(…)方法,获得许可证。Semaphore类的release(…) 方法,释放一个许可证,也有相应的方法指 定释放和获得许可证的数量的方法。 CountDownLatch类 http://heimeiyingwang.javaeye.com 1.42 corejava辅导(17--3) 第 148 / 150 页 CountDownLatch中有个计数器,访问这个类的对象就会从计数器中减一,countDown()方法会将原有的设置的计数器值 减一,当countdown计数器为零时会使放所有await()的线程。 CyclicBarrier类 CyclicBarrier和CountDownLatch比较相似 CyclicBarrier在构造时给出线程数,只有等待的线程数到了构造方法中指定的数量,当最后一个线程等待后,所有的线程都 会被释放,这个类是一个多线程汇合的工具。 Exchanger类,用exchange()方法可以使两个线程间相互交换对象,在两线程的同步点,等待第二个线程。在同步点时,交 换对象,并同时被释放。 http://heimeiyingwang.javaeye.com 1.42 corejava辅导(17--3) 第 149 / 150 页 以上内容仅供参考!谢谢关注 wangyanjun@tarena.com.cn CoreJava辅导资料 作者: heimeiyingwang http://heimeiyingwang.javaeye.com 本书由JavaEye提供电子书DIY功能制作并发行。 更多精彩博客电子书,请访问:http://www.javaeye.com/blogs/pdf http://www.javaeye.com - 做最棒的软件开发交流社区 第 150 / 150 页

还剩149页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 20 金币 [ 分享pdf获得金币 ] 1 人已下载

下载pdf

pdf贡献者

eric_1987

贡献于2011-02-15

下载需要 20 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf