达内java学员曹同学就业感言

时间:2024.3.19

南宁达内

达内java学员曹同学就业感言

达内学员资料:曹* 网络工程专业 湘南学院 21CN世纪龙信息 使用期:3800元/月 转正:4200元/月 我叫曹*,湘南学院网络工程专业毕业的一名学生,现在已经入职了21CN世纪龙信息,入职月薪为3800元,转正后将达到4200元的月薪。其实,薪资多少,并不是很重要,对于我这么个应届生来说,毕业后找对了今后奋斗的方向,找准了奋斗目标,从事自己喜欢的工作,就已经很不错了。

从今年的就业形势来看,貌似理科生就业相比于文科生来说,要略胜一筹,但是,我们理工科学生也有我们自己的苦恼啊。毕业前,我就已经跑了很多招聘会,校招会几乎是没有错过任何一场的,还参加过社会上所举办的大型招聘会,但终究无果。所以,也可以说是在走投无路的时候,我选择了深造。我选择的是南宁达内的java课程,在作出当机立断的选择之后,我便进入了接下来的艰苦的四个月的学习。

其实,做技术这一方面的,实际操作能力和动手能力是最不能缺的,而这一点,在求职的过程中也是很受企业关注的,他们会询问你有没有什么工作经验,对于应届生来说,他们则会将关注点放在你曾经在学校或是实习的时候实际操作过哪些项目。当然,这些都是我急缺的。在南宁达内四个月的学习,我感觉我学到的东西就挺多的,弥补了之前的无知,所以,在找工作过程中,相对而言就轻松了很多。例如,南宁达内时不时会联合合作企业,一同举办双选会,平时成绩好的话,笔试基本是没多大问题的,如果你认真总结了你平时所做的项目,那么,面试这一流程,也基本上能应付好。所以,我最终被 21CN世纪龙信息录取,还是做我喜欢的java开发工作。


第二篇:达内java笔记


目录

CoreJava DAY01 Java概述 1

CoreJava DAY02 数据类型和控制结构

CoreJava DAY03 数组 11 6

CoreJava DAY04 15

CoreJava DAY05 面向对象 17

CoreJava DAY06 类的加载过程、实例化、继承、多态 20

CoreJava DAY07 修饰符

CoreJava DAY08 常用类 26 29

32 CoreJava DAY09 高级语言特征 30 CoreJava DAY10 主方法,静态导入,包装类,枚举

CoreJava DAY11 内部类 36

CoreJava DAY12 集合 List 40

CoreJava DAY13 集合 Set 46

CoreJava DAY14 集合 Map 49

CoreJava DAY15 异常、断言 52

CoreJava DAY16 反射、注释

CoreJava DAY17 GUI 64

CoreJava DAY18 awt event 81

CoreJava DAY19-20 多线程 85

CoreJava DAY21-22 IO 95

CoreJava DAY23 网络编程 107

CoreJava DAY01 Java概述

############################################################################### ########## CoreJava DAY01(2009.02.21) ############ ########## Made by NieXu ############ ###############################################################################

一、学习CoreJava的要求

1、上课一定要听懂(理解)

2、课后一定要练习

3、练完后要思考

二、Java的优势

1、Java中省去了对指标的操作,但并不是没有指标了,只是被封装了而已,代替指标的是种新的变量,叫做引用,这个引用里面也是保存的一个对象的地址,它和指针的差别就是比指针功能要弱化了,也更简单了。 内存空间自动回收,即垃圾回收,体现了其简单性。

2、安全性好,字节码的验证

3、Java的跨平台性:用这个语言开发出来的程序可以在不同系统中运行:

源码是怎样成为可执行代码的

源码-->编译-->目标码(二进制机器码)-->连接-->可执行档

由此看来,汇编、C、C++等语言都是不跨平台的,因为他们的编译过程就直接与当前系统挂钩了,C和C++源码都是跨平台的,我们所指的跨平台是基于编译过程中的跨平台,以上几种语言在不同的系统中编译出来的目标码是不同的。

Java跨平台就是编译过程中的跨平台,怎么实现的呢,那就是Java虚拟机: Java的源码编译过程:

1 57

源码-->编译-->字节码-->把字节码装载到虚拟机中运行

--JAVA虚拟机:JVM

屏蔽掉了不同平台的差异,为上层的字节码提供了一个统一的运行环境

虚拟机是为了给字节码提供统一的执行平台,每种操作系统所用的虚拟机是不同的,是为了统一JAVA字节码的解析执行方式,如果没有虚拟机,在一种操作系统上写了JAVA代码,编译成字节码后只能在本操作系统上运行,但是换一个操作系统的话就要重新再写一遍JAVA代码然后重新编译,

所以虚拟机提高了代码的复用性,实现了一次编写,多处使用的优点。

不同系统的Java虚拟机之前的源码和字节码部分都是跨平台的,从虚拟机就不是跨平台的了。

这样Java的字节码就可以直接用来传播,而不用传播源码了。

三、对Java课程总体的大纲的介绍

四、JDK/JRE/JVM

JDK:JAVA开发工具包,比JRE多了一些开发和调试的命令,比如javac、java(用于执行Java字节码文件)等等。

JRE:JAVA运行环境

JVM:JAVA虚拟机

包含关系:JDK包含JRE,JRE包含JVM

如果你搭建的Java开发环境是用来做Java开发的,那么就安一个JDK,从(最新的版本为1.6)下载,注意

如果你不做开发,而只是运行别人开发调试好的程序(或者字节码文件),那么就只安装一个JRE就可以了

一般服务器上就只安装JRE

针对不同的操作系统有不同的JDK下载

在JDK安装好后的档夹中有个bin目录,里面一般是我们经常用到的一些命令,比如javac、java

在JDK目录下有个src.zip檔,解压开后就是JDK类库中的源码,也就是rt.jar压缩檔中class檔的源码。

jre目录是JDK自带的JRE,里面也有bin目录,一般存放的是运行时的一些命令

jre活页夹中的lib文件中有一些jar文件(叫JAVA的归档文件),里面都是一些class檔(以此为后缀名表示java的字节码文件)在虚拟机运行时作为类代码其中一个比较重要的jar檔就是rt.jar,里面放的是JDK给我们提供的一整套开发的基础类库的字节码,可以直接使用。

(补充:.java为源文件,经过编译后成为.class字节码文件;了解一个类的定义和用途可以查找开发文档,如果还是没找到的话就找源文件,在src.zip中后缀名为class的文件)

五、配置环境变量

JAVA_HOME:JDK的安装路径

CLASSPATH:字节码的搜索路径

PATH:命令的搜索路径(要加上jdk.../bin)

Linux:

--一般JDK是放在/opt/jdk1.6.0_05

--配置环境变量的文件是主目录中的".bash_profile"文件

进入终端后:vi .bash_profile

在里面配置:

2

JAVA_HOME=/opt/jdk1.6.0_05

CLASSPATH=. PATH=$PATH:$JAVA_HOME/bin:....... export JAVA_HOME export CLASSPATH

export PATH

--配置完后保存退出,然后source .bash_profile

在命令行打java命令验证是否配置成功,如果成功了,注销一遍系统

Windows:

--右键我的计算机-->高级-->环境变量-->在系统变量或者用户变量上配置-->

JAVA_HOME:当前机器上JDK的文件目录 "C:\Program Files\Java\jdk1.6.0_05" CLASSPATH:类的搜索路径 "."当前目录(.;%java_home%\lib;)

Path:命令的搜索路径 %JAVA_HOME%\bin;

--开始-->运行-->cmd-->javac验证是否配置成功

六、第一个JAVA程序

一个java檔只能定义一个public类,并且public修饰的类的类名要与文件名相同 vi MyFirstJava.java

public class MyFirstJava{

public static void main(String[] args){

String name="tangliang";

int age=30;

System.out.println("my name is:"+name);

System.out.println("my age is:"+age);

}

}

写好后在命令行cd\到文件所在目录,然后打 javac MyFirstJava.java编译檔

编译成功后当前檔夹中会出现一个MyFirstJava.class文件

运行:java MyFirstJava

结果:

my name is:tangliang

my age is:30

要学会编译出错后查找错误!

(补充:1、一个Java源文件中可以定义多个类,但最多只能有一个public类,而且该public类的类名要和文件名一致。

2、一个Java源文件在编译后形成的字节码文件个数与该源文件中定义的类的相同,即每定义一个类可以形成一个字节码文件。

3、一个可运行的Java类有且只有一个main方法,而且main方法的签名是固定的,main方法是程序的的入口方法。

4、类的包:对同一个功能模块的类的统一管理,做大型开发时,一般按功能模块先来命名包,包结构的命名规则例如:com.tarena.abs.model即公司的URL+项目名称+模块名

在檔中在定义一个class Animal{}

保存编译后档中就会多一个Animal.class檔,也就是说,檔中有多少类,那么就有多少 3

类檔

java命令执行所做的东西

1、找到类的字节码文件,要用到CLASSPATH的环境变量

2、加载类到内存中

3、找类的主方法,main方法,执行代码

七、包

1、作用,java程序很庞大的话会有很多类檔,问了分类存放,那么就把相同类型的类檔放在同一个包中。

2、语法:

package 包名;

...正文;

编译时用javac -d 目录 XX.java(运行时-d后空格加上包名.类名)

编译好后,class檔会被自动放在自己定义的包(自动生成的檔夹)中,包会放在编译命令中指定的目录中执行时在包所在的当前目录下打 java 包名.类名

(练习:在原来的MyFirstJava文件内容的第一行增加package corejava.day01;然后保存;然后在DOS下先后输入命令:

javac.MyFirstJava.java -d .和Java.MyFirstJava -d此后就在D盘建立起两个文件夹,生成了名为MyFirstJava.class的文件,并在DOS下有结果显示。)

(补充:1、java命令要做3个工作:首先是启动JVM;加载PackageTest.class(如果没发现则会出现提示,此时要检查CLASSPATH中设置的内容 );运行PackageTest.main。

2、找类的顺序:先在当前所在包下找,在jre/lib/xxx.jar,最后才在CLASSPATH中找。所以不要创建和JDK中同名的类)

八、注释

三种:

1、单行注释: //...

2、多行注释: /*...*/

3、文檔注释: /**......*/ 另一种多行注释,但是这种注释可以生成API文檔(HTML格式的)

九、提取API文檔的命令:javadoc

javadoc应用,提取说明文件,根据文档中的注释生成程序文档。

javadoc XX.java -d 生成文文件路径

比如:javadoc String.java -d .\stringdoc(如果是直接在盘符下有该文件则-d后只用实心点即可,如果需要通过新建文件夹的同时生成则输入一个新的文件夹名字)

在String.java所在的檔夹中便会生成一个stringdoc檔夹,里面是html格式的解释文檔 顺便教下学生看API文檔

九、import

如果在一个java檔中用到了不在同一个包中的类的话,就要用import来引入一个类,允许在程序中使用的时候不用包名,直接用类名就可 以了。

语法:import 包名.类名

写在package后,类定义前(一个文件里面可以不说明package,有就只能有一个,可以一或二行,之后就是import声明,0或多行,也可以 不用import导入很多类,即省略;然后就是类的声明)引入一个类

注意:

package在java檔中只能出现一次,并在最前面

4

import可以有多条 写在package后,类前

十、创建jar文件命令

把指定的包中的class檔打包成jar檔K(里面是编译好的字节码文件)

语法:

jar -cvf jar文件名 要打包的檔夹

如jar cvf abc.jar ./day01(即把day01中的文件打包到abc.jar里面)

执行完后在当前目录会生成一个abc.jar的檔,解压后就是day01檔夹,里面还是class檔

cvf:create view filename创建可视文件名

如果在别的java檔中要用到此jar檔中的类,那么就要在环境变量的CLASSPATH中多配一个abc.jar

的路径。然后在类檔中直接import这个类就可以了

CLASSPATH配置完成后,JVM先从当前路径下找类,再从rt.jar中找类,然后再从abc.jar中找这个类

十一、JDK中的基础包

java.lang语言包

java.awt/javax.swing/java.awt.event 图形开发包

java.applet JAVA的applet小程序包

java.io 输入输出流包

java.net 网络包

java.util 工具包

第二章 语言元素

一、标识符

只能以字母,“_”,“$”符号开头,不能以数字开头, 但是非开头的位置可以出现数字.

二、良好的编码习惯

1、类的首字母要大写,如果有多个单词,每个单词首字母都要大写 比如:HelloWorld

2、接口名命名与类名一样

3、方法名第一个单词小写,以后每个单词的首字母都大写 比如:getName

4、变量名的命名习惯和方法名的相同

5、常量(不可改变的)的名字所有字母都大写,单词与单词之间用“_”连接 比如:DRIVER_NAME

6、包名所有字母都小写

三、关键词(50个)

自己命名变量名或者其它名字不能和关键词的一样

true,false,null不是关键词,是字面值,同样不能把这些单词作为名字

goto和const(表示常量,在JAVA中用final代替)是保留字,并不应用于java开发,也不能作为其它名字使用

其它语言中goto语句的用法(无条件跳转):在C和C++中有时用goto可以提高程序的效率(如:在多重循环嵌套中跳出最外层循环时很方便),但是在JAVA中影响程序的可读性且存在安全隐患。

java中的代替goto的是break loop; loop是个标号,标记一个循环,break loop就结束了这个循环

四、数据类型

八种基本数据类型

5

boolean 两个值true或者false 8位

byte 8位整数

short 16位整数

char 16位的Unicode编码,有足够的空间保存非英文字符的编码值,也类似于整型 int 32位整数

long 64位整数

float 32位浮点型

double 64位浮点型

CoreJava DAY02 数据类型和控制结构

############################################################################## ########## CoreJava DAY02(2009.02.23) ############## ########## Made by NieXu ############# ###############################################################################

一、数据类型

boolean 两个值true或者false,占8个二进制位(在C和C++中用0代表假,非0代表真,但在Java中则把布尔型的值和整型数值严格区分)

7种数值类型,他们之间是可以相互转换,但是转换是有前提的,实型的存储为近似存储,整型则为精确存储。

byte 8位整数

short 16位整数。

char 16位的Unicode编码(在C和C++中用ASCII码保存字符,一般由0~127,最多有256种,但是在Java中则用Unicode编码,最多有65536种,还可以赋中文汉字),有足够的空间保存非英文字符,单引号中为一个字符,双引号中为字符串。例如:

插入ucChar=‘\u0060’用单引号意思是Unicode值为0060的字符,16进制化为10进制,则代表ASCII值为96的字符。表示的值的范围:0~65535

--'A':65,'a':97,'0':48

int 32位整数

long 64位整数

float 32位浮点型

double 64位浮点型

二、String类型:是一个类,而不是基本类型

赋值的话就用双引号引起来,比如String a="abc";

String的几种常用方法:

charAt(int n);获取这个字符串的n位置的字符,n从0开始

concat(String str);把当前字符串与参数中的字符串连接到一起返回一个新字符串 其它的教学生自己去查

三、整型数据

1、整型变数赋值

int ia=0x55;//这种赋值是可以的,赋值为了一个16进制资料

byte bb=0x771;//0x771已经超出了byte的取值范围,所以编译这句话会出错 byte ba=(byte)0x771;//把0x771强制转换成byte

long la=1234567L;//给long类型的变量赋值

2、强转后值如何变化:

规则:

6

整数在内存空间中的存储方式:以补码的方式。

byte b=39;b转换成二进制是00100111(-128~127)

short s=39;b:0000 0000 0010 0111(-32768~32767)

-39为39的补码:各位取反,末位加一 1101 1001就代表-39

如果最高位是0,那么就是存的一个正整数,1就代表负整数

-128的二进制要先求128的原码0111 1111

求补码后-128的二进制表现为1000 0000

1111 1111代表-1

整型数据强转如果大转小的话直接把其二进制高位截掉,保留低位

0x771换算成二进制0111 0111 0001,强转成byte后为0111 0001

四、浮点型数据

1、赋值

float fa=123.4F//后面加个F或者f,或者使用强制类型转换(不加则编译出错,默认为double型)

double d=123.456D//后面的D跟不跟都可以,默认为double。

2、存储方式暂不用理解

数据类型之间的转换有两种:自动类型转换(从小范围的值转到大范围的值,也有可能存在数据丢失的问题,3种情况:int-—〉float;short-〉float;long-〉double;转换后两个值不等不能说明两个数不相等,但是得出的两个值相等则二者一定是相等的)和强制类型转换(会存在数据丢失的问题)。

3、数据丢失:

五、对象类型(引用类型)

1、属于所有非基本类型的其它类型

2、类型的分类:

--八种基本类型

--引用类型(类、接口、枚举、标注),引用类似于C中的指针,即保存一个地址值,把新空间的首地址赋给新的对象,然后可以用对象.XXX的方式来访问该对象的某个属性,如P.age)

--库类型

3、在内存中的存储方式

对象类型的变量实际上存储的是对象所在的内存的地址

一个对象类型占四个字节,也就是其最大寻址空间是4G。

内存被分为两块空间:栈空间和堆空间

--栈:负责给方法分配空间

main方法在栈的最下面 方法里对象的引用也是存在栈空间中的

存储对象的引用如果是定义在方法体内的也是存在栈中的

--堆:给对象分配空间

对象就相当于一个气球,引用就相当于栓着气球的绳子

一个对象可以有多个引用指向它。

六、垃圾回收

1、如果某一个对象没有引用指向它了,那么这个对象就是个垃圾对象

比如String s=new String("...");

s=null;

7

那被new出来的String对象就是一个垃圾数据了

2、垃圾回收机制

对于没有被引用的对象,java JVM会自动回收

System.gc() 提醒虚拟机进行垃圾回收,但只是提醒建议

七、错误、警告和异常(刚开始学习时很容易产生异常,即没有让引用指向任何对象,就会产生空指针异常)

1、空引用 比如String s=null s就没有指向任何对象

s.方法名,如s.charAt(0),如果s是空的话就会抛出NullPointerException(空指针异常)

2、编译的问题:

--错误(语句存在语法上的问题)

--警告(语句存在逻辑上的问题)

违背了语法的要求

3、运行时问题:

--Exception 异常(例如:程序的执行需要调用外部文件,在编译时不涉及此类调用,编译时只是检查数据类型是否是匹配,所以在运行时会发现错误,但程序还可以继续进行 --Error 错误

程序中断了,比如内存溢出了

编译器检查不出来,而是运行时检查出来的

违反了正常逻辑

八、运算符

赋值运算符12个

比如:

byte a=3;

a=a+5;//会报错,因为5是被认为是int,所以a+5得到的也是int,无法把int值赋给byte

a+=5;//不会报错,因为不管运算符右边得到的是什么类型都会把右边得到的值转化为左边的类型

相等和不等关系可以用于数值比较和引用对象引用等,即所有有效类型都可以用等和不等来比较。

关系运算符

算术运算符

即加、减、乘、除等。(一个字符串可以和任意类型相加)

移位运算符:只能针对二进制数据(整数)

<< 左移,左移一位相当于原来的数乘二,大于32位的话高出的位就不要了,如果移动的位数大于32的话java会自动把这个位数变为这个数对32求余的值。

>> 右移,右移一位相当于除2取整,两位相当于连续次除2取整而不是除4取整,看正数还是负数,正数右移的话高位补0,负数的话补1。

>>> 无符号右移(算数右移),不考虑符号位,移进来的都补0。

2、位运算符

& 按位与 两个数按位与,全部转换成二进制后按位比较,全为1才是1,其它是0,返回一个新的整数

| 按位或 两个数按位或,全部转换成二进制后按位比较,全为0才是0,其它是1,返回一个新的整数

求反~变量,如:int a=5;b=~a;

8

^按位异或

(条件)?A :B 如果?前面条件的返回值为真,那么就执行问?与:之间的A,如果返回值为假,则执行:后面的B

5、自加和自减

++ 前++的话属于先加后用,后++的话先用后加

-- 前--的话属于先减后用,后--的话先用后减

6、运算符的优先级:从高到低

--最高的:(),[],.

--第二高的:++,--,+(正),-(负),!,~

--算术运算符

--移位运算符

--关系运算符

--位运算符

--逻辑运算符

--三目运算符

--赋值运算符

优先级相同的根据结合性从左到右算或从右到左算

第三章 流程控制

重点放在循环的构建上

一、if(boolean){

...

}

if(boolean){

...

}else{

...

}

if(boolean){

...

}else if(boolean){

...

}else{

...

}

二、switch(..){

Case A: ..:......;break;

case B:..:......;break;

...

default:....;

}

1、switch后括号中的值必须是int,byte,char,short,枚举类型的变量之一,其它类型的就不行了。

9

2、每个case后面的值必须是不相等的,而且必须是常量

3、如果每个case冒号后面的语句执行完后没有break,还会继续执行后面case里的语句,所以在每个case的语句结束后加一个break

4、default代表如果和所有case后的值都不匹配,就执行这里的语句。无论default写哪都是最后执行的。

System.exit(0);

--如果系统执行到这条语句的话程序就退出了

break和continue后面可以加下标,跳出循环和继续循环。

四、for循环

--语法

for(1;2;3){

...

}

--写在1的地方是给一个值初始化,2位置的是退出循环的条件,一般是1位置的变量到什么程度退出循环,3位置是1位置值的变化,当第一次循环结束后执行一遍3位置,然后接着判断2的位置的值是真还是假,假就退出,真的话接着循环.循环的顺序便是1-->2-->循环体内代码-->3-->2-->如果为真继续执行循环体内代码-->为假退出循环

五、while循环

--语法

while(boolean){

...

}

--每循环一次就判断括号中的代码是不是为真,是真的话就继续循环,假的话就结束循环

六、do..while循环

--语法

do{

...

}while(boolean);

--无论如何都会先执行一次再判断条件是否为真,其它的和while循环规则一样

七、用循环来检测输入(主要是教学生利用控制台读取参数的方法)

1、用流的方式

--BufferedReader br=new BufferedReader(new InputStreamReader(System.in));

2、用java.util包中的Scanner类

Scanner sca=new Scanner(System.in); sca.next(); CoreJava DAY03 数组

############################################################################### ########## CoreJava DAY03(2009.02.24) ############ ########## Made by NieXu ########### ###############################################################################

一、循环嵌套

主要是通过联系来讲的

作业:

10

1.输出金字塔

2、打印99乘法表

3、搜索1000-9999之间的数字,条件:千位>百位&&十位>个位&&千位+个位= =百位+十位

二、数组

--一维数组

1、声明数组

语法:

--类型[] 数组名 or 类型 数组名[]

比如:int[] a 或者 int a[]

2、声明数组只是声明了一个数组的引用,并没有在内存中给数组开辟空间

数组是被当作对象来处理的,所以要初始化,语法:

--类型[] 数组名=new 类型[长度] 比如:int[] a=new int[10];

3、遍历数组

for(int i=0;i<a.length;i++){

System.out.println(a[i]);

}

注意:数组的下标是从0开始的,所以最后一个数组元素的下标为数组长度减1

4、也可以在初始化数组的时候就给数组赋值

比如:int a=new int[]{1,2,3,4};//声明了一个长度是4的int数组,里面的值为1234 上面的内容还可以简写为:int a={1,2,3,4};

注意:只有实例化数组的时候才可以给数组一次性赋值,以后就只能单独赋值了 --二维数组

1、声明二维数组

语法:

--int[][] a;

2、实例化

语法:

--int[][] ia=new int[3][5];

这样就声明了一个三行五列的二维数组

3、声明时赋值

4、不规则数组,也就是每一行数组的长度不一样

--就可以先声明的时候只指定第一维的下标

int a=new int[3][];//这样数组定下来是三行,但是每一行多少长度是未知的 对每一行实例化:

a[0]=new int[5];

a[1]=new int[3];

a[2]=new int[4];

那么这样这个数组就成为了一个第一行长度是5,第二行长度是3,第三行长度是4的不规则二维数组

5、遍历二维数组

for(int i=0;i<a.length;i++){

for(int j=0;j<a[i].length;j++){

System.out.println(a[i][j]);

11

}

}

注意:数组也是个对象,所以Object obj=new float[10]是成立的。

存放对象类型数据的数组

每个数组元素存放的都是对象在内存中的地址,都是对象的引用

--数组的辅助工具类和方法

1、数组拷贝:

System.arraycopy(myArray,0,hold,0,myArray.length);

方法参数从左到右依次是原数组,原数组拷贝起始位置,目标数组,目标数组起始位置,拷贝数组长度

2、数组工具类java.util.Arrays,带学生查API

3、数组元素的查找:

--线性查找:从第一个开始查找

--二分法查找:要求数组必须有序,就是从数组元素中间开始找,然后比较这个结果和要查找数组的大小,再决定从哪边再开始找

三、eclipse开发工具介绍

1、目录,在/opt目录下有个eclipse文件夹

2、打开eclipse可执行档

设置好存放编码的目录(workspace)后进入开发工具

一开始出现欢迎界面,把它X掉。

3、怎样创建一个工程

--在左边空白处点右键,new-->java project-->写上project name(工程名)-->next -->create new source folder(创建存放java文件的目录)命名为src

-->finish-->finish

这种创建工程的方式是把java檔和class檔分开的,视频上没有讲,请项目经理注意强调这种建法

4、在src目录上点右键new-->package建立一个包命名为day01(存放第一天的代码)

5、在day01包上点右键new-->class建立一个类,写上名字finish后在就可以在这个檔里写java代码开发了

6、写好代码后运行,在代码区域点击右键-->run as-->Java Application

四、作业

1.计算工资个人所得税的题目

2.倒排数字

3.输入1-100之间所有的素数

五、在主方法之外定义自己的方法

1、定义语法:在主方法之外,类范围以内

修饰符 返回值 方法名(参数类型 参数名){

[局部变量列表;]

[语句块;]

}

比如:

public static boolean isPrimeNumber(int i){

...

12

}

public static是修饰符,boolean是返回值类型,isPrimeNumber是方法名,括号里是方法的形参列表

注意:只要返回值不是void,无论如何都要返回一个返回类型的值,return

2、调用方法的过程

1、为被调用方法分配临时存储空间(栈)

2、把实参值传给形参

3、程序流程跳到被调用方法中执行

4、被调用方法执行完成,程序流程跳回主调方法并且带回返回值(如果有的话) 与此同时,被调用方法的临时空间被释放

六、方法的递归调用

一个方法直接或间接调用自己的形式,解决比较复杂而且有一定规律的逻辑问题

1.用递归求一个自然数的阶乘

2.打印诗

3.酒店管理系统

CoreJava DAY04

############################################################################### ################# CoreJava DAY04(2009.02.26) #################### ################# Made by NieXu #################### ###############################################################################

1、猜数字游戏

游戏产生一个0-1000的整数,让用户从控制台输入一

个数字来猜,如果猜大了就显示太大了,继续要求用户

输入,如果猜小了就显示猜小了,如果猜对了,就显示

恭喜你,猜对了,游戏结束,如果猜了10次还不对,那么就显示

你太笨了,下次再猜吧,游戏结束

2、五子棋游戏,游戏开始要求

输出一下棋盘,然后提示黑方和白方下子,玩家从

命令行输入:af,表示在af坐标落子,其中黑方的

子用@表示,白方子用O表示,每一方有一方落子,

则要重新输出棋盘的状态,程序还要求能判断某一方

获胜并终止程序。

棋盘初始样子如下:

a b c d e f g h i j k l m n

a * * * * * * * * * * * * * *

b * * * * * * * * * * * * * *

c * * * * * * * * * * * * * *

d * * * * * * * * * * * * * *

e * * * * * * * * * * * * * *

f * * * * * * * * * * * * * *

g * * * * * * * * * * * * * *

h * * * * * * * * * * * * * *

i * * * * * * * * * * * * * *

j * * * * * * * * * * * * * *

13

k * * * * * * * * * * * * * *

l * * * * * * * * * * * * * *

m * * * * * * * * * * * * * *

n * * * * * * * * * * * * * *

3、砸金花游戏

编写程序模拟砸金花的游戏,程序开始时要求用户输入

赌注,并在一副牌中随即发两手牌,每手牌三张,然后比较这

两副牌大小,若A比B打,则用户赢得赌注,反之则输掉赌注

比较规则:

1、三条》同花顺》同花》顺子》对子》三张

2、处于同一级别的两手牌比较最大的一张牌的大小

3、若两手牌都是对子,则应比较成对的那张牌的大小

4、扫雷游戏

要求在10x10矩阵中随机布雷,并计算出每个位置周围的地雷数,

并保存在二维数组中,若该位置是地雷,则保存-1,然后要求用户

从命令行输入坐标来排雷,排雷使用一下两种命令:

b 3 6:将坐标3,6标志为地雷

p 2 5:排除2,5坐标位置是地雷

0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 CoreJava DAY05 面向对象

4 minutes

############################################################################### ########## CoreJava DAY05(2009.02.30) ############# ########## Made by NieXu ############# ###############################################################################

一、面向对象

编程要解决的本质工作:

把现实问题抽象成计算机能解决的问题,对现实问题在计算机中建模(抽象) 抽象:

1、对数据的抽象

2、业务逻辑

设计思想:“一切皆对象”

对象-->数据-->类-->数据类型

二、类

14

1、创建类的语法:

public class 类名{

类型 变量名;

类型 变量名;

...

public void 方法名(){

...

}

...

}

例子:

public class Animal{

String name;

int age;

...

public void eat(){

...

}

public void move(){

...

}

...

}

2、创建类的对象的语法:

类名 对象名=new 类名();

Animal a=new Animal();

调用对象的成员

对象名.属性名;

对象名.方法名();

a.name=...;

a.move();

3、构造方法:

用处:

1、构造方法一般用来为属性赋初值

2、构造方法会在生成对象时被系统自动调用

特点:

1、没有返回值,写返回值的位置什么都不写

2、方法名必须和类名完全相同

构造方法也可以定义参数,也可以在里面写实现代码

但是如果一个类中只有一个构造方法,并且这个方法是有参数的,那么在创建类的对象的时候也要传参数。(当类中定义了构造方法,系统就不会再添加无参的构造函数了。) 如果类里没有写构造方法,在创建对象的时候同样会被虚拟机调用其构造方法,因为: 任何类都有构造方法,如果程序员不定义,则系统会加上一个缺省的构造方法。

比如:如果Animal没定义构造方法,那么系统会自动给这个类加上 public Animal(){} 15

这样一个无参空实现的构造方法。

如果自己定义了构造方法,则系统就不会添加这个缺省的构造方法。

4、this的用法

this等价于当前对象,调用当前对象的属性或方法就用 this.属性名,或this.方法名()。 当前对象:指谁在调用当前这个方法和属性,谁就是当前对象。在定义类的时候是不存在当前对象的。

在局部变量与外部变量同名的时候,为了区分,就要在外部变量的前面加一个this来表示这个变量是类的全局变量。

5、访问控制修饰符:

public:公共的,如果用这个修饰属性和方法,则这个属性和方法能在任何地方被调用。private:私有的,如果用这个修饰属性和方法,则这个属性和方法只能在类的内部被使用。

修饰符的作用:封装类

6、封装:

如果一个数据类型,把它不想让外部知道的属性和方法私有化,把它能让外部访问的属性和方法公共化,这就叫封装。

属性最好是被封装在内部的,因为这样公开自己内部信息的主动权就在自己身上。 现实世界的所有个体我们都可以看成一个封装体,因为他们对外展现的都只是其一部分特征行为。

但是属性的隐藏不是最终目的,是为了让外部更好的、更安全的去访问。

定义访问方法:setXXX(),getXXX()

访问的方法格式是固定的

获得属性值的方法必须返回类型是属性的类型,方法名为 get属性名(),

设置属性值的方法参数类型必须是属性的类型,方法名为 set属性名(属性类型 变量名),

以上方法名还要满足方法的命名规范,比如

public void setName(String name){

this.name=name;

}

public String getName(){

return this.name;

}

那么以后再给对象的属性赋值就写成a.setName("xiaoqiang");

获得属性的值就写成a.getName();

封装的好处:代码维护方便,如果属性名变了,其它程序根本不用做改动,还是调用这个控制属性的方法就行了

7、方法的重载:一个类中同名但参数不同的方法

this(..,..);调用本类其它的构造方法

this(..,..)这样的调用只能出现在构造方法的第一行

CoreJava DAY06 类的加载过程、实例化、继承、多态

12 minutes

############################################################################### ########## CoreJava DAY06(2009.03.04) ########### ########## Made by NieXu ########### 16

############################################################################### 回顾:

数据->类

一是要描述数据的静态特征(属性),一是要描述其动态行为(方法)。

生成对象,构造方法的调用

当生成对象时,比如:Animal a=new Animal()时,系统做了三件事:

1、给对象在堆中分配空间

2、给对象的属性初始化

boolean赋值为false,

char类型的值转换成int是0

其它基本类型就赋值为0,或0.0

引用类型赋值为null

3、调用构造方法

方法的重载/构造方法的重载

一个构造方法中调用本类其它的构造方法

this(..,..);只能放在构造方法的第一行

类的封装

属性隐藏->提供公开的访问方法

Java类的加载过程:

传统语言程序在启动(startup)过程中程序会被全部装载,紧接着进行初始化动作,然后开始执行。由于Java中每样事物都是对象,装载动作就大不相同了。

每个class都存在于一个单独的专属的檔中,这个檔只在必要时才被JVM装载(根据CLASSPATH的设置找到类文件)。一般而言,可以这么说:“class程序代码在初次使用时才被装载”。所谓初次使用,不仅是其第一个对象被构建时,也可能是在某个static数据成员或static函数被取用时。类被装载的完毕,正是静态初始化的进行时期(静态初始化只在类被装载时进行一次)。

如果类是继承而来的,那么装载动作在检测到extends关键词是转去装载父类(所以父类的进态初始化会在子类之前进行),以此类推。

类装载完毕并进行了静态初始化以后,就可以用类创建对象了(用new关键词)。这时会涉及到构造函数的调用,当有继承关系时,情况会比较复杂。在构造函数调用之前,进行两件事情:给对象分配存储空间(数据区,代码区是怎么分配的呢?);存储空间被初始化为二进制零值。

Java编译器“强迫derived class构造函数必须调用base class构造函数”。derived class 的构造函数会默认(不用显示写代码,当然可以用super(),这在调用base class的带参数的构造函数时有用)调用base class的default构造函数。其实构造函数首先会默认调用各数据成员的初始式(形如:int id = 1000;),然后才执行构造函数体。

在定义属性的位置上,在任何方法之外,定义一个代码块:(代码块的载入)

动态初始代码块:在初始化属性之前调用初始化代码块{??}

静态初始代码块:在类载入时运行static{??} 只被运行一次,往往用作一个类的准备工作 类的加载过程:

A. new 一个对象的时候-------加载

B. 没有创建对象,访问类中静态成员(方法和属性)-------加载

C. 声明一个类的引用-------不载入

17

0.1 D. 创建子类,先载入父类,再载入子类

E. 父类中的公开静态方法,子类继承,使用子类的类名调用此方法,只加载父类 class Super{

public static m(){}

}

class Sub extends Super{}

在主函数中运行以下代码:

Sub.m(); //加载了父类之后,虚拟机已经知道m()方法的调用了,就不会再加载子类 对象实例化过程:

1.类加载,执行静态语句块和静态的属性赋值(先父类后子类) 2.预开空间,所有属性设零值 3.实例化对象:(先父类后子类)

1)初始化所有的属性,和非静态语句块(自上而下执行)

2)构造函数

类加载的顺序:

[具体顺序是:先加载父类的static代码块,再加载子类的static代码块;

再加载父类的代码块,再调用父类的构造方法;

在加载子类的代码块,再调用子类的构造方法。]

1.加载静态成员/代码块:

先递归地加载父类的静态成员/代码块(Object 的最先);再依次加载到本类的静态成员。 同一个类里的静态成员/代码块,按写代码的顺序加载。

如果其间调用静态方法,则调用时会先运行静态方法,再继续加载。同一个类里调用静态方法时,可以不理会写代码的顺序。

调用父类的静态成员,可以像调用自己的一样;但调用其子类的静态成员,必须使用“子类名.成员名”来调用。

2.加载非静态成员/代码块:

先递归地加载父类的非静态成员/代码块(Object 的最先);再依次加载到本类的非静态成员。

同一个类里的非静态成员/代码块,按写代码的顺序加载。同一个类里调用方法时,可以不理会写代码的顺序。

但调用属性时,必须注意加载顺序。一般编译不通过,如果能在加载前调用,值为默认初始值(如:null或者 0)。调用父类的非静态成员(private 除外),也可以像调用自己的一样。

3.调用构造方法:

先递归地调用父类的构造方法(Object 的最先);默认调用父类空参的,也可在第一行写明调用父类某个带参的。

再依次到本类的构造方法;构造方法内,也可在第一行写明调用某个本类其它的构造方法。

注意:如果加载时遇到 override 的成员,可看作是所需创建的类型赋值给当前类型。

其调用按多态用法:只有非静态方法有多态;而静态方法、静态属性、非静态属性都没有多态。

假设子类 override 父类的所有成员,包括静态成员、非静态属性和非静态方法。

由于构造子类时会先构造父类;而构造父类时,其所用的静态成员和非静态属性是父类的,但非静态方法却是子类的;

由于构造父类时,子类并未加载;如果此时所调用的非静态方法里有成员,则这个成员是 18

子类的,且非静态属性是默认初始值的。

成员,包括变量和方法

成员变量,包括实例变量和静态变量

今天内容:

一、类中方法的调用:

1、方法调用的四个步骤:

--首先在栈中给方法开辟空间

--其次把实参传给方法的形参

--再次程序跳到被调用方法中执行方法中的代码

--最后方法中的代码执行完后再跳回主方法

2、方法中的对象类型的参数传递只有引用传递,没有值传递。

--这是因为方法和参数都是存在于栈中的,当此方法执行完毕后,参数和方法都被释放了,所以不会保留值。

--而对象类型的参数传递的是对象的内存地址,那么无论如何改变,都是改变的这个地址的对象,即使方法结束了。

--方法空间释放了,对象并没释放(因为对象是存在于堆中的),所以方法中对对象的改变是改变的同一个对象。

--但是如果方法中写的代码是对象地址的交换,并没有改变对象的话,原对象的地址还是没有变的。

二、继承(代码重用)

1、语法-->public class 子类名 extends 父类名{ ... }

2、子类的对象可以调用父类的一切公有的变量和方法,也可以扩展自己新的属性和方法,但是新扩展的部分父类的对象是无法调用的

3、super(..,..)的用法,在子类的构造方法中调用父类的构造方法,并且super要放在第一行,不能与this一起用

主要用为在构造子类的时候给父类中定义的变量赋值

4、子类的一些特点

--任何子类的构造方法都会调用父类的构造方法

--任何子类的构造方法的第一行必须是this(..,..)或super(..,..)的调用,如果程序员不写,则系统会隐含的调用super()

也就是说,子类不管怎样一定会调用父类的构造方法

5、为什么子类的构造方法一定要调用父类的构造方法呢

因为如果构造了子类的对象就一定要构造父类的对象,从反方向来讲,虚拟机会先创造一个所有类的父类对象出来,然后再对这个对象扩展,最后生成子类对象,也就是说“没有父哪来子呢”这个意思。就像上帝要创造一个科学家,他必须先创建一个人的对象出来,然后再让这个人去研究科学(扩展),最后形成科学家对象(子类对象)

6、构造了一个子类对象其实也只是创建了一个对象,只不过父类对象是子类对象的一部分,就像上帝要创造一个科学家只是创造了一个人而已。

7、如果父类的属性和子类的属性同名的话,首先来说,现实中不会有这样的需求,完全没有必要在子类中定义与父类同名的属性。

如果确实定义了的话,直接用name或者this.name就是调用的子类的(就近原则),要想调用父类的就要super.name或super.getName();

8、如果父子类中有同名的方法,如果同名不同参,返回类型可以相同也可以不同,只是一种重载;如果是同名同参的话,那子类对象调用的这个方法便是子类自己的, 这种子类 19

与父类存在同名同参的方法的形势叫做方法的覆盖(重写),也就是子类的方法把父类的覆盖了。

覆盖用来描述子类和父类有相同的行为,但两者行为方式是不同的,比如Animal可以移动,但是子类Bird可以飞。

方法覆盖的原则:

--发生在父子类之间

--同名,同参,同返回类型(可以返回子类型)

--子类的方法的修饰符不能比父类方法的修饰符更封闭,比方说父类的是public,子类的就不能为private

--抛出异常类型不能更宽泛

三、多态

1、方法的重载和覆盖就是方法多态的一种体现

2、对象的多态,一个对象多种形态,这要取决于对象的继承关系

表现对象多态的一种形式,把子类对象当作父类对象的一种形式:父类名 对象名=new 子类名();-->Animal a=new Bird();

但是这样的话,此对象不能调用父类中没有的方法

4、多态定理:

--如果我们把子类对象当作父类对象来看,那么就只能访问父类中已有定义的属性和方法(不能访问子类扩展的属性和方法)

--如果子类覆盖了父类的方法,再把子类对象当作父类对象去调用该方法时,调用的是子类覆盖后的方法。

(对象的行为不可能因为你把它当作什么来看而改变)

Animal a=new Bird();

|------| |--------|

| |

主观认为 客观存在

编译时类型 运行时类型

编译时类型:在写代码编译过程中,编译器把这个对象当作什么来看(父类对象) 运行时类型:在代码执行过程中,JVM把这个对象当作什么看(子类对象)

5、instanceof,判断一个对象是不是某一个类型的实例,用法

对象名 instanceof 类名; 返回一个布尔值,如果前者是后者的实例则返回真 一般这样用:

Animal a=new Bird();

//如果a是Bird的实例,做什么

if(a instanceof Bird){

Bird b1=(Bird)a;

a.sing();

}

并不是所有的父类都能转换成子类

如果任意强转不匹配的类型就会抛出java.lang.ClassCastException

类型转换异常:把一个原本不是这种类型的对象强转成这种对象

所以在强转之前最好用instanceof做一下判断,如果是这种类型的实例再强转 练习:

1、定义以下数据类型

20

Person:String name , int age

构造:第一个的参数String name,int age

第二个的参数String name ,age默认为20

要在第二个构造方法中调用第一个

public void work();

Person的子类:

Student:覆盖work()方法,输出学生在学习。

Teacher:覆盖work()方法,输出教师在授课。

在以上两个子类的构造方法中调用父类的构造方法,通过构造方法把name传给父类

2、使用面向对象的思想设计一个即使战略游戏的类结构

主要类如下:

1、人口类(Person)

属性:生命值(lifeValue),攻击力(attackPower),消耗资源数(needResource)

方法:进攻(attack)

子类:

工兵(Sapper)扩展方法:创建建筑createConstruction(),采集资源collectResource()

机枪兵(GunMan)

护士(Nurse)扩展方法:疗伤(cure)

2、建筑类(Construction)

属性:生命值,消耗资源数

3、玩家类(Player)

属性:玩家名称,玩家资源值,玩家所拥有的人口对象,玩家做拥有的建筑对象 在主方法中测试以上程序,创建两个玩家,分别生成人口和建筑类攻击对方 以上练习代码参见课堂代码。

CoreJava DAY07修饰符

8 minutes

############################################################################### ########## CoreJava DAY07(2009.03.06) ############ ########## Made by NieXu ############ ###############################################################################

一、修饰符

1、static

描述整体特征而不是个体特征的属性时,用静态修饰符

--静态和非静态的差别

1、空间分配时机:

静态变量是在类加载的时候分配空间,非静态对象是在生成对象的时候分配空间

2、空间分配方式:

不管有多少对象静态变量只有一份(所有对象共享),非静态变量有多少对象就分配多少个空间

3、访问方式:

静态变量是:类名.属性,比如Animal.COUNT

非静态变量:对象名.属性,比如a.name

21

--静态方法和非静态方法的区别

1、静态方法是通过类名来调用,非静态方法是通过对象来调用 2、静态方法中不能访问本类的非静态成员,但非静态方法可以访问静态成员 为什么主方法非要是静态的: 我们看执行java Test命令后的运行步骤

1、启动JVM

2、找到Test.class

3、载入Test.class

4、Test.main();

也就是说main方法是程序的入口,那么在执行main方法之前是执行不了任何代码的,所以获得不了这个类的对象,只有用这个类的类名来调用main方法,所以main方法必须为static

--静态代码块

1、静态代码块会在类被加载时被系统自动执行

2、一般可以在静态代码块中给静态属性赋值

一个静态与非静态实行先后的例子,见代码StaticTest.java

静态方法不存在多态特性,也就是静态方法无法被子类覆盖,父类对象调用此方法还是父类的,所以虽然静态方法可以被对象调用,但也不要这样用,要用类名对其进行调用类的静态代码块:在类加载时被系统自动执行,一般可以在静态代码块中给静态属性赋初值,类的静态代码块只能有一个。

静态方法可以覆盖,但没有多态,属性也一样。静态方法只属于本类,并且不能被子类的同名同参的静态方法覆盖。属性也一样,可以被覆盖但没有多态,子类定义相同的属性,该属性仍然用原来本类对象的属性值。(这里叫覆盖不合适)

其调用按多态用法:只有非静态方法有多态;而静态方法、静态属性、非静态属性都没有多态。

2、final

1、修饰属性:属性不可变,并且属性在声明的时候必须初始化,或者在构造方法中初始化一般与static一起用,一旦定义了,就不能再变了。

两种赋值方式有不同之处,声明的时候初始化所有类的对象的常量都一样,所以一般用static final声明。构造方法中声明,表示类的每个对象的常量可以是不一样的。

2、修饰方法:方法不能被覆盖

3、修饰类:类不能被继承

4、修饰局部变数:局部变量不可变(常量)

3、abstract(抽象)

1、用来修饰类和方法。

2、修饰类的话表示这个类是个抽象类,抽象类不能被实例化(生成对象)。

3、修饰方法的话表示这个方法是个抽象方法,抽象方法没有方法体。

4、如果一个类包含有一个抽象方法,那么这个类必须是抽象类。

5、如果一个类不包含抽象方法,那么该类也可以被定义成抽象类。

6、抽象类不能被实例化,但却可以定义引用。

7、抽象类一般需要实现--定义一个子类,并实现抽象方法。

8、抽象类也是有构造方法的,因为需要被子类调用。

9、子类必须实现父类的抽象方法。

--abstract和final不能共同修饰一个类或方法

22

二、界面interface

1、是一种抽象的数据类型,特殊的抽象类。 2、接口中的所有方法都是抽象方法。 3、接口中所有的属性都是final static的(静态常量)。 4、接口也不能被实例化,但可以定义的接口的引用。

5、接口没有构造方法。

6、一个类只能继承一个父类,但是可以实现多个接口,用逗号隔开。

7、接口之间可以多继承。

--接口=标准

把服务的使用者和服务的提供者分开,降低系统的耦合,有效的提高软件的可扩展性和可维护性

高内聚,低耦合

--基于抽象,不要基于实现

implements实现

abstract可以省略不写的,因为interface本身就是抽象的

第一题

1、定义一个接口Assaultable(可攻击的),该接口有一个方法attack()。

2、定义一个接口Mobile(可移动的),该接口有一个抽象方法move()。

3、定义一个抽象类Weapon,实现Assaultable接口,但并没有具体的方法实现。

4、定义3个类:Tank,Filghter,MissileTurrent都继承自Weapon,分别给出

attack()方法的不同实现,Tank和Filghter还实现了Mobile界面,也给出了move() 方法的不同实现。

5、写一个类Army,代表一支军队,这个类有一个属性Weapon数组w(用来存储该军队所拥有的所有武器);

该类还提供一个构造方法,在构造方法里通过传一个int类型的参数来限定该类能所拥有的最大武器的

数量,并用这一大小来初始化数组w。该类还提供一个方法addWeapon(Weapon wa),表示把参数中所

代表的武器加入到数组w中。在这个类中还定义了两个方法attackAll()让w数组中所有的武器攻击;

moveAll()让w中所有可移动的武器移动

6、写一个类测试以上方法

CoreJava DAY08 常用类

############################################################################### ################ CoreJava DAY08(2009.03.09) ################ ################ Made by NieXu ################# ############################################################################### 今天没有讲新课,上午和下午刚开始讲了两个例子说明了接口回调,下午讲了面向对象第一天的作业和日期类型

一、界面与类的关系和区别

子 父

类 extends 类(单一)

类 implements 接口(多重)

接口 extends 接口(多重)

23

二、例子说明问题

1、开发电子商务的网上平台,都有客户管理模块,

实现注册和登陆功能

见课堂代码user_management包

2、把不同的数据用二维表格输出

存放方式,二维字符串数组

见课堂代码table包

三、java.util.Date类

--已经过时,基本没人用了,因为没考虑时区问题

四、java.util.Calendar

--int get(int field)

返回给定字段的日期值

CoreJava DAY09 高级语言特征

4 minutes

############################################################################### ############### CoreJava DAY09(2009.03.12) ################## ############### Made by NieXu ################## ###############################################################################

第六章、高级语言特性

1、访问控制修饰符

本类 同包 子类 其它类

public YES YES YES YES

protected YES YES YES NO (所定义的成员受包和继承结构的保护) 不写修饰符 YES YES NO NO (缺省保护权,包可见权限,Default) private YES NO NO NO

局部变量不能用public修饰;局部变量只在方法体里面可见。

访问控制修饰符不能修饰局部变量。

修饰类,就可以修饰接口。接口和类相似。

static final abstract public protected default private 顶层类 N Y Y Y N Y N 属性 Y Y N Y N Y Y 方法 Y Y Y Y Y Y Y 局部变数 N Y N N N N N 内部类 Y N N N Y N Y (protected是可以定义属性的)

static ,protected, private不修饰顶层类,但是可以修饰内部类

2、java.lang.Object类(clone,equals,finalize,toString)

--只有一个无参构造方法

--其它方法11个,必须全部明白

clone():创建并返回一个当前对象的拷贝,得到和当前对象一模一样的对象,地址是不同的

这个方法是让子类覆盖的,但子类也必须同是实现java.lang.Cloneable界面 对象克隆过程:1、要让这个类实现Cloneable界面

2、要覆盖Object中的clone()方法

24

深拷贝和浅拷贝:浅拷贝只是把当前对象拷贝了,但是当前对象中有存在对别的对象的引用的属性,那么那个属性还是指向同一个对象。所以如果直接调用clone()方法的话就属于浅拷贝。

如果这个类里只有字符串对象和基本数据类型,那么也属于深拷贝。

finalize():垃圾回收器调用。实际意义不大。

equals(Object obj):判断两个对象是否相等

--反身性:对任意非空的值调用此方法自己和自己比应该返回真

--对称性:对任意非空的引用值x和y,如果x.equals(y)返回真,那么反之亦然 --传递性:x,y,z,x.equals(y)返回真,x.equals(z)返回真,z.equals(y)也应返回真 --一致性:结果应为确定的,如果对象不变,无论调用多少此都返回相同结果 --对于任意非空的引用值和空比较都应返回假

toString():输出对象时输出这个方法的返回值

System.out.println();方法输出的对象和对象的toString()方法,的结果是一样的。也就是说输出一个对象的时候,系统会自动调用toString()方法。

如:Student s=new Student(?); System.out.println(s);

System.out.println(s.toString());= ={System.out.println(s);}

String str=”Hello”+s;

3、java.lang.String类

如果String s1="hello"这样直接赋值的话,那么与同样直接赋值的比较如果字符串相等的话就相等。

字符串对象赋值不可改变。

String A=”hello”;

A=A+”hehe”;

System.out.println(A);

已经改变了A的值,因为已经建立了一个新对象A.

如果和String s3=new String("hello");这样的对象比较的话如果字符串相同才返回假 为了避免产生垃圾对象用下列两个方法:

java.lang.StringBuffer线程安全。不产生新对象。支持多线程的访问,对访问方法加锁 java.lang.StringBuilder线程不安全 不支持多线程访问 不对方法加锁

java.lang.StringBuilder效率高于java.lang.StringBuffer

--以上这两个类如果对字符串做修改的话不会创建新对象,只是在原来对象基础上改 这是为什么呢?

--串池:存储字符串的地方,如果有新字符串对象生成的话那就继续生成新的字符串,如果想要新生成字符串的话而此字符串在串池中已经有了的话就直接用已经有的。对象池中的数据不会成为垃圾。

CoreJava DAY10 主方法,静态导入,包装类,枚举

############################################################################### ############### CoreJava DAY10(2009.03.14) ################## ############### Made by MoXiaoMing ################## ###############################################################################

1、 对象池:存储对象的空间。不真正保存对象。

一般我们获得一个类的对象都是通过new的形式,如果不用这种形式的话我们就可以写一个获取对象的方法来获取对象。

25

原理:

我们生成对象以后便把此对象保存到对象池中,这样我们用完了此对象也不会被释放,以后我们再用到此对象的时候就直接在对象池里取就行了。

怎么创造对象池?

Private static Sudent[] pool=new Sudent[10];

Student stu1=Student.getStudent( “zhangsan”);

Student stu2=Student.getStudent( “zhangsan”);

Student stu3=new Student(“zhangsan”);

System.out.println(stu1==stu2);

System.out.println(stu1==stu3);

Private static int count=0;

Public static Student getStudent(){

For(int i=0;i<count;i++){

If(pool[i].name.equals(name) &&pool[i].age.equals(age)){

Return pool[i];

}

}

Student stu=new Student(name,age);

Pool[count]=stu;

Count++;

Return stu;

}

我们可以先在类中创建一个此类对象的数组,要声明成静态的。然后在此类中写一个获得对象的静态方法,一定要是静态的,不然获得对象的方法就没有什么意义了。 (New 对象)创造新的对象,不会放到对象池。

直接用双引号引用,对象可以放在对象池里面。

什么时候从对象池中拿对象,什么时候在对象池中创造对象?

2、主方法(main)声明的参数由谁传递呢

java 类名 命令所做的:

--启动虚拟机

--找到class文件

--载入类

--调用这个类的main方法

所以运行 java 类名 命令后面还可以给一些主方法的参数,这些参数都被系统当作字符串放到main方法声明的参数String[] args中,如果输入多个参数的话就以空格为分隔符依次把每个参数放入args数组,比如 java HelloWorld hello world ; hello和world就是两个参数。如果不传参数的话args就是一个0个元素的数组

在eclipse中给主方法传参数:右键run as-->run configurations..--Main class要是现在要运行的类,如果不是就要search找到-->arguments-->在上面的栏中就是给main方法传的参数,填上参数-->apply-->Run

3、可变长参数

在定义方法的时候知道要传的参数的类型,但是参数的数量不固定的时候就用可变长参数,可变长参数类型的写法是:例子:public static void m2(String... strs){ ... }

上面的参数类型在String后面多了...,这样在调用方法传参数的时候就可以传多个参数 26

或者一个参数,也可以不传参数,但参数必须都为String类型的,如果要传其它类型的时候在定义的时候改成其它类型,然后在类型后面加上...就可以了。

String….s代表的意义:相当于String[],相似但不完全相同,有差别,数组不能传递变长参数。String….s对String[]兼容。

如何使用这些参数:在方法中此参数是被当作数组类访问的,调用length就可以知道有多少参数传进来,这种参数既能接受单个元素做参数,也可以接受数组作参数。也就是说可变长的参数类型兼容了数组参数类型,但是数组参数类型不能兼容可变长参数类型。 使用可变长参数的规定:

--一个方法只能有一个可变长参数,而且该参数必须是这个方法的最后一个参数

--可变长参数的方法只有在必须的时候才被调用,也就是说,如果有不可变长参数的方法可以匹配,这种调用,那么系统会优先选择不可变长参数的方法的调用

4、静态导入

一般我们导入的话用import,后面跟的是一个类,或者此包的所有类

我们要用某个类的静态属性或方法的时候可以不用导入这个类,我们可以直接把这个类中的静态属性导入进来:

语法:

import static 包名.类名.属性名

比如import static java.lang.System.out;

这样的话我们在写输出语句的时候就可以直接写成out.println(...);

import java.util.*;

import java.util.Scanner;

1、包装类

针对八种基本类型的包装类,在基本类型和对象类型之间建立桥梁,使基本数据类型也可以当作对象来用

基本数据类型 包装类

boolean Boolean

byte Byte

short Short

char Character

int Integer

long Long

float Float

double Double

--java.lang.Integer类

注意查API

构造方法Integer(int),Integer(String)-->例如:new Integer("123");

parseInt(..);可以把不是int类型的数据转换成int类型,是静态的,可由类名直接调用 --这些包装类中很中要的一些方法是类型的相互转换

--在JDK1.5之前要获得一个基本类型的对象比如Integer只能用Integer i=new Integer(5)或者Integer i=Integer.valueOf(5)

但在JDK1.5以后可以直接写成Integer i=5;在这里虚拟机默认的为这个基本数据类型进行了包装,以上面的第二种形式即:Integer i = Integer.valueOf(5);包装了。这种自动的包装叫做自动封箱,另外还可以自动解封,比如:int a=i;这种形式就相当与int a = i.intValue(); int Integer String三者的转换

27

要注意:

除了字符串类型的对象会创建对象池,八种基本类型的包装类也会创建对象池。但是这些包装类new出来也只创建一个对象,Integer的对象池在启动的时候就创建好了,范围是-128~127之间,所以在这之间的数字对象都不会再创建新对象,超出的部分都会再创建新对象,不会在从对象池中拿。

2、枚举类型

--什么叫枚举?

比如一年的季节,一周中的七天,都是固定的,依次出现的

--枚举用来限制一定得取值范围

--定义声明枚举类型语法:

public enum Season{

SPRING,

SUMMER,

AUTUMN,

WINTER;

}

public enum Season{

SPRING(“春天”),

SUMMER(“夏天”),

AUTUMN(“秋天“),

WINTER(“冬天“);

Private String name;

Private Season(String name){

This.name=name;

}

}

public class Season{

public static Season SPRING=new Season(“春天”);

public static Season SUMMER =new Season (“夏天”);

public static Season AUTUMN =new Season (“秋天“);

public static Season WINTER =new Season(“冬天”);

Private String name;

Private Season(String name){

This.name=name;

}

}

上面两种方法可以对应和相互转换的,但是有不同的地方是,他们的公共父类不一样,class的是Object,enum的是Enum

注意:枚举类型中的枚举值,如果后面没有语句,分号(;)可以省略。

所有的构造方法都是私有的。

public enum Season{

SPRING,

SUMMER,

AUTUMN,

28

WINTER;

}

枚举类型,标准是用类名应用类型枚举值,如:Season.SUMMER

JDK1.6中static Season s;s.SUMMER;这样的也可以编译通过。

枚举类型不可以是在局部定义,如:在一个方法中定义,因为枚举类是从一个属性和方法都是静态的类,而静态的方法和类是不可以存在在局部中的。

上面声明了一个枚举类型Season,也可以把枚举看作一个类。

枚举里可以定义属性,构造方法,但是都必须定义成私有的,也可以定义方法,修饰符无限制

注意:switch()里面可以放入byte、short、int、char和枚举类,以及byte,short,int,char的包装类。

练习:

1、改砸金花(用面向物件枚举等)

请见课堂代码中的砸金花项目文文件

CoreJava DAY11 内部类

############################################################################### ############### CoreJava DAY11(2009.05.04) ################## ############### Made by MoXiaoMing ################## ############################################################################### AM:

一、所有枚举类型的父类java.lang.Enum

--name()方法,返回此枚举值的名字,必须由枚举的对象来调用

--ordinal(),返回此枚举值在枚举声明中的次序,从0开始

--在文檔中查不到的方法values(),静态方法,由枚举类型名直接调用,返回此枚举类型中所有枚举值的一个数组

二、内部类inner class

为的是隐藏一种数据类型,这种数据类型只在一个类中可见。

就像生物圈中的寄居、寄生。

四种形式的内部类:

静态内部类--

|-成员式的(存在于类体中)

成员内部类--

局部内部类--

|-局部式的

匿名内部类--

内部类的修饰符:

static final abstract public protected default private

顶层类 N Y Y Y N Y N 属性 Y Y N Y N Y Y 方法 Y Y Y Y Y Y Y 局部变数 N Y N N N N N 成员式内部类 Y Y Y Y Y Y Y 局部式内部类 N Y Y N N N N

局部变量和局部类(在方法体中)只能使用final,局部类类多一个abstract,其它的修饰 29

符都是不可以的。

内部类可以访问外部类的私有成员。

如果要访问内部类的话

1、静态内部类:

--不能访问外部类的非静态成员

--在外面访问此类的话就用 外部类名.内部类名

比如OuterA.InnerA inn=new OuterA.InnerA();创建了一个静态内部类对象 --静态内部类和外部类对象实际上是没什么关系的

补充:

静态内部类:作为一个类成员存在

修饰符和成员内部类相同public protected (Default) private abstract final static 不能访问外部类的非静态成员,可以访问静态成员 实例化(new 外部类名.内部类构造函数()) 声明(外部类名.内部类名 变数)

静态内部类里可以定义静态的属性和方法

2、成员内部类:

--可以访问外部类的静态和非静态成员

--访问成员内部类必须先生成一个外部类对象,生成局部内部类的对象用 外部类名.内部类名 对象名=外部类对象.new 内部类名();

比如:OuterA out=new OuterA();

OuterA.InnerB innb=out.new InnerB();

--如何选择用静态内部类或成员内部类:

如果外部类怎么变化都不影响内部类的话,那么推荐用静态内部类,

如果操作内部类的改变能影响外部类,那么推荐使用成员内部类。

补充:

成员内部类:作为一个对象(实例)的成员存在

修饰符可以是public protected (Default) private abstract final static

可以访问外部类的成员(外部类名.this.成员) 实例化(外部类对象的引用.new 内部类构造函数()) 声明(外部类名.内部类名 变数)

成员内部类里不能定义静态的属性和方法

3、局部内部类

--在方法体里定义的类

--如何在方法体外得到这个类的对象呢,通过方法的返回值就可以,返回值类型为Object。

但是外部得到的这个对象是没什么意义的,因为只能访问Object里的方法,此类自己的方法是访问不到的。

解决方法:

1、覆盖Object类的方法,此方法不推荐。

2、在外部定义一个接口,然后此局部内部类来实现接口,然后哦外部拿到对象后转化成此接口类型就行了。

3、反射技术

--局部内部类中不能访问外部方法中的局部变量,如果要访问的话,局部变量必须是final。

30

因为对象是存在于堆中的,而方法是存在于栈中的,对象对方法中局部变量访问的话就要创建局部变数的一个副本来存放此局部变量的值,所以其中有一个改变了,另外一个是不会改变的,所以为了保持一致性,要把这个局部变量定义为final。

--局部内部类中不能生成静态成员

补充:

局部内部类:定义在方法体里的类

修饰符可以是abstract final

可以访问外部类的成员 声明和实例化跟普通类一样 局部内部类里不能定义静态的属性和方法 局部内部类只能访问final修饰的局部变数

4、匿名内部类

--没有名字的类

--匿名内部类的声明:

声明类型 变量=new [类名 extends/implements] 声明类型(){

类的方法声明...

}

[]中的是省略的部分

--匿名内部类的声明和对象的生成是合二为一,不可分割的

得到的对象不知道是哪个类的对象,只知道是实现了某接口或者继承了某类的类的对象

--匿名内部类没有构造函数(因为没有名字),也不能被继承

--匿名内部类可以访问外部类的成员:外部类名.this.成员

--匿名内部类如果声明在方法中的话也具有局部内部类的特点,只能调用final的局部变量

--匿名内部类中不能声明静态的成员

补充:

匿名内部类:没有类名的类

可以访问外部类的成员

声明和实例化一起(声明类型 变量=new 声明类型(){类的定义});

声明类型:抽象类 接口 普通类 匿名内部类如果定义在方法体里,则具有和局部内部类相同的特征 匿名内部类可以定义在属性的赋值上

补充:内部类:

成员内部类:作为一个对象(实例)的成员存在 修饰符可以是public protected (Default) private abstract final static 可以访问外部类的成员(外部类名.this.成员) 实例化(外部类对象的引用.new 内部类构造函数()) 声明(外部类名.内部类名 变数) 成员内部类里不能定义静态的属性和方法 静态内部类:作为一个类成员存在 修饰符和成员内部类相同 不能访问外部类的非静态成员,可以访问静态成员 实例化(new 外部类名.内部类构造函数()) 31

声明(外部类名.内部类名 变数) 静态内部类里可以定义静态的属性和方法 局部内部类:定义在方法体里的类 修饰符可以是abstract final 可以访问外部类的成员 声明和实例化跟普通类一样 局部内部类里不能定义静态的属性和方法 局部内部类只能访问final修饰的局部变数 匿名内部类:没有类名的类 可以访问外部类的成员 声明和实例化一起(声明类型 变量=new 声明类型(){类的定义}); 声明类型:抽象类 接口 普通类 匿名内部类如果定义在方法体里,则具有和局部内部类相同的特征 匿名内部类可以定义在属性的赋值上 内部类的应用: 1.如果一个类需要在多个类中使用,则考虑使用普通公开类 2.如果一个类需要在一个类中多个方法里使用,考虑使用成员内部类 3.如果一个类需要在某个方法里多次使用,考虑使用局部内部类 4.如果一个类需要在某处使用一次,考虑使用匿名内部类 CoreJava DAY12 集合 List

############################################################################### ############### CoreJava DAY12(2009.05.13) ################## ############### Made by MoXiaoMing ################## ############################################################################### AM:

集合很重要,请大家务必学好。

第七章 集合框架 Collection

一、以前用的数组分配空间的时候是固定的,所以一开始定义的时候很难恰到好处的定义

二、集合的统称java.util.Collection(所有的集合类都在java.util包下面)

--子界面

List列表

--有序存放(放在List中的每一个元素都是有顺序的,有自己的位置的),允许重复(可以存放相同的元素),List可用get。而Set则不可用(因其无序)。

--实现类:

ArrayList:底层数数组实现的,实现了数组的变长,初始的数组容量默认是10。 LinkedList:实现了队列的接口,底层是链表实现的,先进先出。

Set 集合(和数学上集合的概念相似)

--无序存放,不允许重复。

--子界面:SortedSet 排序集合

--实现类:TreeSet

--实现类:HashSet

Queue 队列(先进先出)

--父接口,Iterable,可迭代的,凡是实现这个接口的实现类对象都可以用迭代的方式去循环访问

32

--iterator()方法,调用此方法可以得到一个迭代器Iterator

--父界面,Iterator 迭代器

--hasNext()方法,是否还有下个元素

--next(),表示下个元素

--remove(),移除当前跌带到的对象

--新的for循环

for(..;..){

...

}

for..each循环,第一个值是单个对象,第二个值是被迭代的对象,每迭代一次都把迭代的值放到前一个对象中,但是被迭代的对象必须是实现了Iteratable接口的对象此for循环才可用(因为for?each和Iterator的原理是一样的)

补充 集合内容:

定义:跟数组一样,可以存放多个数据。提供了一些辅助的方法。

分类: Collection:集合大接口,List和Set都是他的子界面 List:排序的,可以重复的 ArrayList:数组实现,遍历快,增加删除效率低 LinkedList:链表实现,遍历较慢,增加删除效率高

Vector:数组实现,同步的,线程安全,重量级的。(牺牲了效率,提高数据的安全性)

Set:不排序,不可重复 HashSet:数组和链表实现的。 不排序的 不能重复的(hashCode相同,则覆盖) TreeSet:跟HashSet一样的实现,额外提供了一个排序的功能 比较器:java.lang.Comparable界面,compareTo(Ojbect obj) java.util.Comparator界面,compare(Object o1,Object o2) Iterator迭代器: 作用:遍历集合 使用:所有Collection的集合都有迭代器,iterator()获得迭代器hasNext();next() Map: key-value键值对的方式存贮多个数据 HashMap: key不能重复,值可以重复,支持空值 Hashtable: 实现同步,是线程安全的,重量级的,不支持空值 SortedMap:(Map 的子界面) TreeMap: key不能重复,不能为空。提供以key排序的功能

Collections是工具类,所有方法均为有用方法,且方法为static。

有Sort方法用于给List排序。

Collections.Sort()分为两部分,一部分为排序规则;一部分为排序算法。

规则用来判断对象;算法是考虑如何排序。

对于自定义对象,Sort不知道规则,所以无法比较。这种情况下一定要定义排序规则。方式有两种:

① java.lang下面有一个界面:Comparable(可比较的)

可以让自定义对象实现一个接口,这个接口只有一个方法comparableTo(Object o)

33

其规则是当前对象与o对象进行比较,其返回一个int值,系统根据此值来进行排序。 如 当前对象>o对象,则返回值>0;(可将返回值定义为1)

如 当前对象=o对象,则返回值=0;

如 当前对象<o对象,则返回值〈0。(可将返回值定义为-1)

看TestArraylist的java代码。

我们通过返回值1和-1位置的调换来实现升序和降序排列的转换。

② java.util下有一个Comparator(比较器)

它拥有compare(),用来比较两个方法。

要生成比较器,则用Sort中Sort(List,List(Compate))

第二种方法更灵活,且在运行的时候不用编译。

注意:要想实现comparTo()就必须在类声明中写上implement comparable.

CoreJava DAY13 集合 Set

############################################################################### ############### CoreJava DAY13(2009.05.17) ################## ############### Made by MoXiaoMing ################## ###############################################################################

一、Collection的子界面Set

--存放有序,不重复对象。

注:HashMap底层也是用数组,HashSet底层实际上也是HashMap,HashSet类中有HashMap属性(我们如何在API中查属性)。HashSet实际上为(key.null)类型的HashMap。有key值而没有value值。

1、HashSet

--HashSet比较两个对象是否相等用的是equals()方法。

--底层用的是哈希散列表(长度16的数组)来存储对象,存放对象之前先做一个哈希散列运算:

1、首先得到对象的哈希码,就用对象调用hashCode()方法

Object类里toString默认返回的是:类名+@+对象

hashCode()方法返回值的16进制形式,hashCode()方法返回的是对象的地址,是整型的

2、用hashCode()方法对HashSet底层数组的长度求余,得到一个0-15之间的值,然后这个值就是存在HashSet数组中的下标,如果该下标位置上已经有元素了,如果不冲突,就把这个对象放到该位置,如果冲突的话,就对这两个对象作比较,如果不相等,就把这个对象也放到这个位置,对于是怎么放的,有可能每个数组元素都是一个链表,那么是此下标的元素如果equals比较的结果不相等,就会都放到这个链表中。如果他们比较是相等的,那么这个要被插入的对象就被抛弃掉了,没有插入成功。

--所以,只有覆盖了对象的equals方法和hashCode方法,让此方法按自己的算法运算的话才能算是相同的对象,覆盖hashCode方法的原则:

原则1:让equals相等的对象返回相同的hashCode(为了过滤掉相等的元素) 原则2:尽量保证equals不相同的对象返回不同的hashCode(为了添加不同的元素) 原则3:尽量的让对象的哈希码随即散列

2、Set下的一个子界面:SortedSet,可按自己定义的规则进行排序

--实现类

1、TreeSet:用二叉树排序的集合

构造方法:

--无参,按自然顺序排序,这个规则是程序员说了算,在定义类的时候可实现相应的比较大 34

小的方法。

===========================================================

官方解释:

public interface Comparable<T>

此接口强行对实现它的每个类的对象进行整体排序。此排序被称为该类的自然排序,类的 compareTo 方法被称为它的自然比较方法。

===========================================================

--有一个让传入Comparator比较器的实现类的对象

--如果我们想让一个类的对象按照一定的规则排序,可以让这个类实现Comparable接口,然后实现其抽象方法compareTo(Object o)

--Comparator接口的实现,如果不想让类实现Comparable接口,可以自己定义

--Comparator接口的实现类,然后把此实现类的对象在构造TreeSet的时候通过构造方法传进去,那么存入此类的对象的时候就可以按照我们在Comparator接口实现类中实现的方法中的规则进行比较,如果此类既实现了Comparable接口,又在存放该类对象的TreeSet集合中传入了Comparator接口的实现类,那么优先按照实现类中的compareTo方法比较。

注意:TreeSet必须实现compareTo(),或者comparator(),否则会报异常!

迭代器还可以这样用:

for(Iterator<String> it=set.iterator();it.hasNext();){

System.out.println(it.next());

}

--练习:见课堂代码

1、定义一个类Employee代表职员,

属性:String name;

boolean gender;

double salary;

Calendar birthday;

覆盖该类的equals方法和hashCode方法,认为如果两个Employee对象的姓名和生日都相同则这两个对象相等。

该类对象具有自然的大小顺序,大小比较规则是按照姓名的字典顺序比较。 还要为该类实现两个比较器,分别按照Salary,和birthday的大小来进行升序比较

把该类对象加入到HashSet和TreeSet中验证以上程序的正确

CoreJava DAY14 集合 Map

############################################################################### ############### CoreJava DAY14(2009.05.20) ################## ############### Made by MoXiaoMing ################## ###############################################################################

一、Map界面--键值对

Key-Value是用一个不可重复的key集合对应可重复的value集合。(典型的例子是字典:通过页码的key值找字的value值)。

注意数组和集合的区别:数组中只能存简单数据类型。Collection接口和Map接口只能存对象。

如果在HashMap中有key值重复,那么后面一条记录的value覆盖前面一条记录。

35

--实现类

1、HashMap

--key是用HashSet实现的

2、HashTable线程安全的

--子界面:

SortedMap

--实现类:

TreeMap可排序的

二、Collections工具类,把线程不安全的集合包装成线程安全的集合

比如HashSet set=new HashSet();

现在set是不安全的,

Set synSet=Collections.synchronizedSet(set);

执行完上面的代码以后,synSet就是set的线程安全的形式了,但是它还是和set是同一对象

三、java.util.Properties类

Map是它的父类,并且它的key和values都是String

直接父类是HashTable

读取配置文件:读取步骤

--获得Properties实例:Properties pro=new Properties();

--获得配置文件的输入流:FileInputStream fis=new FileInputStream("config.txt"); --用Properties实例加载输入流:pro.load(fis);

--通过配置文件中的键值获得对应结果:String ip=pro.getProperty("ServerIp");

注意:

Collections类中有很多有用的静态方法,比如排序和查找。

第八章 泛型

给类加了个参数,用来指定存储的数据类型,不可以使用基本数据类型

可以声明多个泛型的参数类型,比如,Map<String,Integer>。

还可以做泛型的嵌套,如:Box<List<String>> b=new Box<List<String>>();

比如ArrayList<..> ,<>中指定的就是ArrayList里要存储的数据类型

如果<>中定义了类型,那么这个集合中就只能存放这种类型的数据,如果插入别类型的数据会报错

ArrayList<..> arr=new ArrayList<..>();与ArrayList<..> arr=new ArrayList();是一样的

但是泛型的参数类型是不允许多态的,ArrayList<Object> arr=new ArrayList<String>()是不对的,参数类型就是指<>里面的类型

泛型的基类型是允许有多态的,比如List<String> arr=new ArrayList<String>()是可以的,基类型就是指<>前面的类型

如果不加泛型参数,系统会默认为Object

ArrayList<String> arr=new ArrayList<String>();

ArrayList<String> arr=new ArrayList();//arr中保存String对象

ArrayList arr=new ArrayList<String>();//arr中保存Object对象

以上三种都对。

注意:此处泛型要结合集合来理解,特别是add和get方法的限制。

带通配符的参数,通配符是指“?”号

通配符:

36

上限通配符:

? extends ...

Extends 继承类或者接口都是可以的。

比如ArrayList<? extends Object> arr=new ArrayList<String>(),是合法的

上限通配符只能在参数类型那边声明 意思也就是本类及其子类

编译器并不知道arr的参数类型,只是知道它的大概范围,这是加入任何类型的元素都不能确保是安全的,以编译编译器拒绝add元素,add方法就不可以使用了!

只能用get方法

上限通配符可以通过强转将它转成确定参数的泛型:

ArrayList<? extends Object> arr=new ArrayList<String>(); ArrayList<Integer> s=(ArrayList<Integer>)arr;//String转成了Integer //这句编译器是不会报错的,也就是说泛型是个编译时概念 ? super ... 比如ArrayList<? super Integer> arr=new ArrayList<Number>(),是合法的,下限通配符 只能在参数类型那边声明,意思也就是本类及父类 下限通配符可以加入元素,使用add方法,编译器将加入的元素当下限通配符表示的父下限通配符: 类加入,所以可以使用add方法,但是是不可以使用get,因为返回的类型不确定! 只能用add方法

如果想定义一个带泛型参数的类,又不知道泛型的数据类型,那么就可以把这个数据类型写成T

方法的传入参数是泛型的时候,不可以使用上限通配符,只读不能写

方和的返回类型是泛型的时候,不可以使用下线通配符,只写不能读

泛型只是一个编译时的概念,由编译器保证,虚拟机是不知道的

泛型在一个类中,只要是用的类型的地方,都可以使用泛型的参数类型

静态属性,和静态方法中不可以是用泛型参数,因为静态方法,属性是在类加载之前加载,而泛型是在调用构造函数的时候加载!

Java.util.Properties

Properties继承自Hashtable,Properties的关键字和值都是String类型的。可以使用继承来的put(String,String)方法和setProperty(String,String)方法设置属性值,保存在Properties中,可以通过store(OutputStream,String)将Properties中的Hashtable也就是Map数据输出到OutputStream中,并且添加一个标题,就是store的第二个参数,store会在这个标题前加上#号,以及日期Date().toString方法的,日期前也加上#号。

读入时要用load(InputStream),先载入,之后使用getProperty(String key)或者继承来的get(String)方法获得。

CoreJava DAY15 异常、断言

############################################################################### ############### CoreJava DAY15(2009.05.23) ################## ############### Made by MoXiaoMing ################## ###############################################################################

第九章 异常

一、异常处理的过程:(CEO要一份财务报表)

37

CEO

|

总监

|

经理

|

职员

如果底层的职员找不到财务报表(出现异常),这时他就会把这个信息返回给经理。如果经理找不到,再将这个信息返回给总监,如果CEO再找不到,就会把信息返回给JVM。异常处理的过程是一级级的上调的。

异常处理的过程其实是过程化的。 异常处理的原则:谁知情谁处理;谁负责谁处理;谁导致谁处理。

二、异常的类继承结构:

Object

|

Throwable

| |

Error Exception

|

RuntimeException

Error:错误,比如是系统内存不足了。(系统运行时的不可恢复的错误)

Exception:运行时的异常,多半是程序员的不小心造成的(如:空指针异常)。 RuntimeException:运行时异常(未检测异常或者是不受检查异常)。

未检查异常是因为程序员没有进行必要的检查,因为他的疏忽和错误而引起的异常。一定是属于虚拟机内部的异常(比如空指针)。

其它的异常都叫已检查异常(或者是受检查异常),这些异常都是外部的客观的原因造成的。比如说:我的程序要打开一个文件,但是这个文件在系统中找不到,再比如我的程序要通过网络访问一台机器,但是这台机器没有连在网络上的。

注意:已检查异常是必须要处理的。(受编译器的检查)

三、常见的未检查异常:

算数异常:java.lang.ArithmeticException

int a=5,b=0;

int c=a/b;

空指针异常:java.lang.NullPointerException

数组下标越界:java.lang.ArrayIndexoutofBoundsException

安全性异常:java.lang.SecurityException

数组的大小为负数的异常:java.lang.NegativeArraySizeException

类型转换异常:java.lang.ClassCastException

四、异常处理:

1、try{ //捕获异常

//(1)

//(2)

//(3)

}catch(MyFirstException e){ //异常的处理方法

38

//(4)

}finally{ //最终的,不管什么情况这个都要做。(一般在这里写资源释放的代码) //(5)

}

//(6)

三种情况的执行过程(在没有return语句和System.exit(0)语句的情况下):

1.无异常抛出:

(1)(2)(3)(5)(6)

2.抛出异常并处理:

(1)(2)(4)(5)(6)

3.抛出异常,但是没有处理:

(1)(2)(5)

----------------------------------------------------------------------

2、try{

}catch(MyFirstException e1){

}catch(MySecondException e2){

}

当一个try配多个catch时,让小范围的catch放在前面,让大的范围的catch放在后面(异常的子类放在父类的前面)。单独的try是不可以存在的,但是try可以和catch一起使用,try可以和finally一起使用。try catch finally 的代码块都是独立的,在其中的定义的变量在其他地方是不可以使用的,也就是作用域的问题。

注意:try catch finally 以及try catch之外return有几个组合。

3、怎样给自己写的类加异常处理:(已检查异常)

try{

}

catch{

}

finally{

}

一般在finally中写资源释放的代码。

如果在try中有return,方法还将会执行finally段的代码。

如果在try中有System.exit(0),方法将不会在执行finally段的代码。 Try catch是可以进行嵌套的。 对于接收到的已检查异常有两种处理方式:throws 和 try方法。 throw+异常对象 放在方法体中,throws+异常类型 放在方法声明中,放在参数后。 自定义异常类。

一、第一种定义方式,继承exception类

public class myfirstexception extends exception {

public myfirstexception() {

super();

}

public myfirstexception(string msg) {

super(msg);

39

}

public myfirstexception(string msg, throwable cause) {

super(msg, cause);

}

public myfirstexception(throwable cause) {

super(cause);

}

//自定义异常类的主要作用是区分异常发生的位置,当用户遇到异常时, //根据异常名就可以知道哪里有异常,根据异常提示信息进行修改。

}

二、 第二种定义方式:继承throwable 类

public class mysecondexception extends throwable {

public mysecondexception() {

super();

}

public mysecondexception(string msg) {

super(msg);

}

public mysecondexception(string msg, throwable cause) {

super(msg, cause);

}

public mysecondexception(throwable cause) {

super(cause);

}

}

三、测试

/**

* 自定义异常类的使用

* @author new

*

*/

public class testmyexception {

public static void firstexception() throws myfirstexception{

throw new myfirstexception("\"firstexception()\" method occurs an exception!"); }

public static void secondexception() throws mysecondexception{

throw new mysecondexception("\"secondexception()\" method occurs an exception!"); }

public static void main(string[] args) {

try {

testmyexception.firstexception();

testmyexception.secondexception();

} catch (myfirstexception e1){

system.out.println("exception: " + e1.getmessage());

40

e1.printstacktrace();

} catch (mysecondexception e2){

system.out.println("exception: " + e2.getmessage());

e2.printstacktrace();

}

//当一个try块后面跟着多个catch块时,如果发生的异常匹配第一个catch块的参数,便将异常处理权利交给第一个catch块。

//如果发生的异常与第一个catch块不匹配,便看是否与第二个catch块匹配,依次下去,如果到最后依然无法匹配该异常,

//便需要在方法声明中添加一条throw语句,将该异常抛出。

//因此,在有多个catch块,而且每次处理的异常类型具有继承关系时,应该首先catch子类异常,再catch父类异常。

//比如,如果mysecondexception继承myfirstexception,那么最好将catch (mysecondexception e2)放在前面,

//把catch (myfirstexception e1)放在后面。

}

五、断言

断言技术(Assertion)://(java 的异常处理机制)

assert boolean-typed expression: (如果返回值为真,则继续执行。

如果为假,则抛出一个异常)

assert boolean-typed expression:string (如果返回值为假,则抛出这个异常的信息 后面的string值,让程序员处理)

message to assertion facility:

如果返回值为假(false),将抛出一个(java.lang.AssertionError)的断言错误。 编译的时候用,javac –source 1.4 AsserttionTest.java 断言的测试

默认情况下assert是禁止的,所以在运行时要用java –enableassertions myApp或java –ea myApp

CoreJava DAY16 反射、注释

############################################################################### ############### CoreJava DAY16(2009.05.24) ################## ############### Made by MoXiaoMing ################## ###############################################################################

第十章、REFLECTION AND ANNOTATION

反射 和 注释(标注)

---注意:这里的注释要区别与以前的注释。这里的注释是有意义的。他使程序能够更好的执行。

一、Reflection:

1、反射,Java的基因技术。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息。

Relfection是java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs驱动如何一个已知名称的class的内部信息,包括其modifiers,superclass,interfaces,也包含fields和methodsde的所有信息,并可于运行时改变feilds内容或唤起methods.

2、java.lang.Class:用来描述某种数据类型。

41

怎样获得某个类的Class对象:(三种方法)

--通过调用Class.forName("类名")。 这里的类名包括:类、界面、Enum、Exception Class.forName()不能是基本类型,数组,void。

--类型名.Class 如:Animal.Class int.Class

注意:类名一定是太的全限定名,包名加类名。

--对象名.getClass(); 如:Animal a=new Bird(); a.getClass();

注意:getClass()方法也是Object类的方法,但是这个方法和前面讲的五个方法不一样。这个方法是final型的。不能被覆盖。前面的方法都是要程序员自己覆盖的。

3、

数据类型

|

--------------------------------------------------------

| | |

8种基本 引用类型(类) void

|

------------------------------------

| | | | |

类 接口 枚举 数组 Annotation

--Class.forName("类型名"): 类,接口,枚举,Annotation

--类型名.Class:

--Obj.getClass(): (全部)或者(Integer.TYPE) 实现类

虚拟机为每个类型管理一个Class类,所以可以用==号比较。

4、package day15(包名);

public final(修饰符) class Student(类名) extends Person(父类)

implements Compareble,Cloneable(实现的接口){

private(修饰符) String(属性类型) name(属性名);

public(修饰符) Student (String(参数类型) name){ (构造方法的代码--反编译技术) ……

}

public(修饰符) final(修饰符) void(返回值类型) study(方法)(String(参数类型) conuse){

……

}

}

以上所有注释的东西都可以用Class探查出来

5、看类的构造方法参见java.lang.reflect.Constructor类

反射需要用到的类:java.lang.Class java.lang.Package java.lang.relect.Modifies java.lang.reflect.Mothed

package day15;

import java.lang.reflect.*;

public class ReflectionTest {

public static void main(String[] args) { Class c = null; try { 42

c = Class.forName(args[0]);

//包名

System.out.println("package " + c.getPackage().getName() + ";"); //类声明

System.out.print(Modifier.toString(c.getModifiers()) + " class " + c.getSimpleName());

if (c.getSuperclass() != Object.class) {

System.out.println(" extends " + c.getSuperclass().getName()); }

Class[] inter = c.getInterfaces();

if (inter == null) {

System.out.println("{");

} else {

System.out.print(" implements ");

for (int i = 0; i < inter.length; i++) {

System.out.print(inter[i].getSimpleName());

if (i != inter.length - 1) {

System.out.print(",");

}

}

}

System.out.println("{");

//属性

for (Field f : c.getDeclaredFields()) {

System.out.println("\t" + Modifier.toString(f.getModifiers())

+ " " + f.getType().getSimpleName() + " " + f.getName() + ";");

}

System.out.println();

//构造方法

Constructor[] con = c.getConstructors();

for (int i = 0; i < con.length; i++) {

System.out.print("\t"

+ Modifier.toString(con[i].getModifiers()) + " " + c.getSimpleName() + "(");

Class[] pc = con[i].getParameterTypes();

for (int j = 0; j < pc.length; j++) {

System.out.print(pc[j].getSimpleName());

if (j < pc.length - 1) {

System.out.print(",");

}

}

//抛异常

43

Class[] e = con[i].getExceptionTypes();

if (e.length!=0) {

System.out.print(" throws ");

for (int j = 0; j < e.length; j++) {

System.out.print(e[j].getSimpleName()); if (j < e.length - 1) {

System.out.print(",");

}

}

}

System.out.println("){\n\t......\n\t}");

}

System.out.println();

//方法

for (Method m : c.getMethods()) {

System.out.print("\t" + Modifier.toString(m.getModifiers()) + " " + m.getReturnType().getSimpleName() + " " + m.getName() + "(");

Class[] cp = m.getParameterTypes();

for (int i = 0; i < cp.length; i++) {

System.out.print(cp[i].getSimpleName());

if (i != cp.length - 1) {

System.out.print(",");

}

}

System.out.print(")");

//方法的抛异常

Class[] e = m.getExceptionTypes();

if (e.length!=0) {

System.out.print(" throws ");

for (int j = 0; j < e.length; j++) {

System.out.print(e[j].getSimpleName()); if (j < e.length - 1) {

System.out.print(",");

}

}

}

System.out.println("{\n\t........\n\t}");

}

System.out.println("}");

} catch (ClassNotFoundException e) {

e.printStackTrace();

}

44

}

}

一、反射的第二个用法,动态调用

1、获得一个类的Class对象的方法:Class c=Class.forName("类全名");

2、获得一个类的实例的方法:Object o=c.newInstance();

运行时动态生成,反射可以通过参数将类名传入程序,而在程序中不需要出现具体的类,一切都是在运行时决定的。

field是该类某属性的对象

3、通过属性名获得一个对象中属性的值方法:Object o=field.get(属性所在对象);

4、给属性赋值field.set(属性所在对象,属性值)

method是该类中某方法的对象

5、调用此方法method.invoke(方法所在对象,参数...);

import java.lang.reflect.*;

public class ReflectionTest2 {

} @SuppressWarnings("unchecked") public static void main(String[] args) { } Class c = null; try { c = Class.forName(args[0]); Constructor con=c.getConstructor(String.class);//调用有参构造方法 @SuppressWarnings("unused") Object obj2=con.newInstance("lisi"); Object obj = c.newInstance();//调用无参的构造方法 Field f = c.getDeclaredField(args[1]); f.setAccessible(true);//设置访问权限 @SuppressWarnings("unused") Object name = f.get(obj); f.set(obj, "zhangsan"); Method m = c.getDeclaredMethod(args[2], String.class); m.invoke(obj, "corejava"); } catch (Exception e) { } e.printStackTrace();

====================================================================== import java.io.FileInputStream;

import java.lang.reflect.*;

import java.util.*;

public class ReflectionTest3 {

@SuppressWarnings("unchecked") public static void main(String[] args) { Properties pro = new Properties(); 45

} } Class c = null; try { pro.load(new FileInputStream("src\\day16\\config.txt"));//"\\"和”/"都是可以的 c = Class.forName(pro.getProperty("ClassName")); Object obj = c.newInstance(); Field f = c.getDeclaredField(pro.getProperty("FieldName")); f.setAccessible(true); f.set(obj, pro.getProperty("FieldValue")); Method m = c.getDeclaredMethod(pro.getProperty("MethodName"), Class .forName(pro.getProperty("MethodParameterType"))); m.invoke(obj,pro.getProperty("MethodParemeterValue")); } catch (Exception e) { } e.printStackTrace();

二、Annotation,标注

与以前使用的标注不同的地方在于,这种标注是让虚拟机去识别的,原来的标注是不被虚拟机读取的,标注和注释一样,不会影响程序代码的执行,但是这种标注可以被编译器和虚拟机读取。

1、JDK中已经定义好的一些标注

--@Deprecated:标注一个方法的话表示这个方法是个过期的方法

--@Override:标注一个方法的话表示这个方法一定是覆盖父类的一个方法,如果这个方法不是覆盖的父类的方法而被此标注注释了,那么编译器就会报错,所以此标注可以判断方法的覆盖是否正确。

以上两种标注是属于标记标注,只起标记的作用。

需要一个参数值的就是单值标注,需要多个参数的就是多值标注。

--@SuppressWarnings:这个标注修饰方法的话就是忽略方法中的警告,也就是被注释的方法里不再有警告,但是标注的的时候要传个参数,参数是个String[]对象,此数组的每个元素就是要忽略的类型的警告,这些警告类型的元素在dos命令提示符下用javac -X命令可以查出,如果你要忽略哪个类型抛出的警告,那么就可以把这些警告类型封装到String数组中传给标注,比如:

@SuppressWarnings({"deprecation","unchecked"})

......//方法

deprecation是忽略调用过期方法的警告

unchecked是忽略安全检查的警告,就像声明集合没带泛型...

此标注意思就是说忽略被注释方法中的调用过期方法和安全检查的警告

all,cast,deprecation,divzero,empty,unchecked,fallthrough,path,serial,finally,overrides all是所有的警告。一共是1+10个警告。

2、自己定义的标注

--语法:

46

定义

修饰符 @interface 标注名{

}

比如

public @interface Author{}

--标注体里定义参数

String value();

上面是单值标注,定义了一个String类型的参数,参数名是value,前面也可以加上访问控制修饰符,单值标注的参数名必须是value,多值标注可以写其他的名字。 import java.lang.annotation.*;

@Documented

@Inherited

@Retention(RetentionPolicy.RUNTIME)

@Target( { ElementType.TYPE, ElementType.METHOD })

public @interface Author {

public String name();

public String date();

}

--元标注

用来标注标注的标注:标注自己定义标注的一些特征

JDK中有四种元标注,在java.lang.annotation包中,使用的话要导入包,写在自己声明的标注之上,

--@Documented:表示标注的信息可以被javadoc这些工具提取出来

--@Inherited:表示此标注可自动被继承,也就是标注了一个类,那这个类的子类也会被自动标注以上两个元标注是标记标注

--@Retention:用来指定这个标注在多长时间内是有效的,是单值标注,参数类型是RetentionPolicy:

SOURCE

public static final RetentionPolicy SOURCE

编译器要丢弃的注释。

CLASS

public static final RetentionPolicy CLASS

编译器将把注释记录在类文件中,但在运行时 VM 不需要保留注释。这是默认的行为。 RUNTIME

public static final RetentionPolicy RUNTIME

编译器将把注释记录在类文件中,在运行时 VM 将保留注释,因此可以反射性地读取。

枚举,

--@Target:指定此标注能够用来标注什么程序元素

3、标注的解析

--所有标注默认的父接口是Annotation

47

--获得某元素标注的方法,比如获得方法的指定标注就是method.getAnnotation(指定标注的Class对象)

--获得标注对象后就课直接调用标注内的属性来返回属性值

使用标注的意义:

标注是为了让别的程序可以读取。此标注是给编译器看的。

CoreJava DAY17 GUI

############################################################################### ############### CoreJava DAY17(2009.05.30) ################## ############### Made by ZhuChuanGang ################## ############################################################################### Java.awt

Javax.swing

Javax表示扩展包。

图形界面优先选用swing

创建GUI的步骤:

选择一个容器

选择一个布局管理器

添加组建到容器

创建事件句柄

Component

|

————————

| |

Container 单一组建

Component | Container

|

————————————————

| | |

JComponent Window Panel

| | |

JPanel _____ Applet

| | |

Frame Dialog Japplet

| |

JFrame JDialog

JComponent及其子类和Panel及其子类的默认布局管理器是FlowLayout。

Window及其子类的默认布局管理是BorderLayout。

Window是顶层容器,可以没有有边框和标题栏。

Frame一定是有边框和标题栏顶层容器,可以独立存在。

Dialog不能独立存在,依赖于另一个容器存在,有边框有标题栏。

Frame和Dialog定义在java.awt包中

Jframe和JDialog定义在Javax.swing包中

48

但是它们是有继承关系的

以J开头的组件一般是swing包的组件,awt中可能会有个不含J的原型组件。 Panel不可以作为顶层容器。

Applet用的很少了,java有两种运行的方法Java Application和Applet,Application是有主方法的程序,Applet是覆盖Applet提供的程序生命周期的类,将它装入另外一个程序中,让另外一个程序调用Applet。

顶层容器:JFrame,JWindow and JDialog

一般容器:JPanel,JScrollPane,JToolBar,JSplitPane,JTabbedPane

JFrame中有个ContentPane,内容面板。

容器的方法:

Add() :向容器中添加组件。

setLayout() :设置布局管理器

getLayout() :获取布局管理器

getCommponent() :

remove and remove() :删除组件

布局管理器:

FlowLayout :流动布局

BorderLayout :边框布局,很多顶层容器的默认布局

BoxLayout :盒式布局swing包中

GridLayout :网格布局

CardLayout :卡片布局

GridBagLayout :不严格的网状布局

只有BoxLayout在swing包下,其他的布局都在awt包下。

重点掌握FlowLayout,BorderLayout,GridLayout

FlowLayout :

public class FlowLayoutTest {

public static void main(String[] args) {

JFrame frame = new JFrame("FlowLayout Test"); frame.setLayout(new FlowLayout()); for(int i=0;i<10;i++){ // frame.add(new JButton("Button"+i)); frame.getContentPane().add(new JButton("Button"+i));getContentPane()是取得 //frame的内容面板,JDK1.5后,可以省略去这一步

}

} } frame.setBounds(100,100,200,300); frame.setDefaultCloseOpeation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true);

BorderLayout:

import java.awt.*;

import javax.swing.*;

public class BorderLayoutTest {

public static void main(String[] args) {

49

} } JFrame frame = new JFrame("BorderLayout Test"); frame.setLayout(new BorderLayout()); frame.add(new JButton("east"),BorderLayout.EAST); frame.add(new JButton("west"),BorderLayout.WEST); frame.add(new JButton("north"),BorderLayout.NORTH); frame.add(new JButton("south"),BorderLayout.SOUTH); frame.add(new JButton("center"),BorderLayout.CENTER); frame.setBounds(100,100,500,300); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true);

GridLayout:

import java.awt.*;

import javax.swing.*;

public class GirdLayoutTest {

public static void main(String[] args) { JFrame frame = new JFrame("GirdLayout Test"); frame.setLayout(new GridLayout(3, 5,10,10)); for(int i=0;i<15;i++){ frame.add(new JButton("Button"+(i+1))); } frame.setBounds(100,100,500,200); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true);

}

}

JAVA图形界面

一、开发工具包

1、java.awt包

2、在1.3以后有了javax.swing包,是对awt的重写和扩展,现在基本上都在swing的基础上做开发

二、图形界面的开发过程

1、选择一个容器 Container

2、选择一个布局管理器:排列方式

3、在容器中加入图形组件【容器(复合组件)或单一组件】

4、给界面设置事件处理的代码

四、布局管理器

1、FlowLayout 流动布局

--容器中的组件的排列位置会按容器的大小或者边框大小的改变而自动改变

2、BorderLayout 边框布局

--按东南西北中划分5个方位存放组件,每个组件占据一个方位

3、BoxLayout 盒子布局

--显示的容器是一层层的

50

4、Gird Layout 网格布局

--按网格形式划分的

5、Card Layout 卡片布局

--不管有多少组件,只能一次看到一个组件,是层叠在一起的,必须设置事 件触发来翻页查看其他组件

6、GirdBag Layout

--不规则的排列可以用这个,把容器划分成N个同等大小的单元格,一个单元格 中最多有一个组件,把每个单元格都标上号,然后指定组件所占单元格的号就 可以了

五、具体用法

--new一个窗体

JFrame frame=new JFrame("FlowLayout Test");//构造方法的参数是窗体的标题, //还有两种构造方法参见API --设置布局管理器

frame.setLayout(new FlowLayout());//设置为流布局

--增加组件

frame.add(new JButton("button"));//增加了一个按钮

在1.5之前要

--设置窗体大小

frame.setSize(400, 300);//长400,高300

--设置窗体位置

frame.setLocation(200, 300);//左上角的坐标离屏幕边框水平是200,数值是300 --设置窗体的可见性

frame.setVisible(true);//设置为true是可见的,不进行这一步此窗体只是内存中的一个对象

//是不可见的

--设置关闭窗口后程序运行情况

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//关闭窗口后程序关闭

//不设置的话默认为隐藏 --文本框JTextField

设置字体setFont(Font f);

--设置背景颜色setBackground(Color c)和前景颜色setForeground(Color c)

六、按钮

--JButton

--JCheckBox

--JRadioButton 多选一的话把这些对象都放到ButtonGroup里就可以了,ButtonGroup可以使按钮相互排斥。

七、文本框

--JTextField 普通文本框,可以指定整数,表示显示文本长度,可以使用文档对象构造 --JPasswordField 密码框,显示的是*,可以设置回显字符,getPassword()返回字符数组 --JTextArea 多行文本框,可以设定显示的行数列数

--JEditorPane 可以显示图标和文字

--JTextPane 可以显示图标和文字,可以使用文档对象构造

--JLabel 不可编辑文本,只是拿来看的

51

--JToolTip 小标签,不可编辑

--JProgressBar 进度条

八、菜单和菜单项

--JMenu 在JFrame中的

--JPopupMenu 弹出式菜单

--JTable 表格

--JTree 树状层次结构

九、文件选择器

--JFileChooser

退出窗口的三种方法:

System.exit(0); 结束一个 JVM 进程和该进程创建的所有线程,包括用户线程和守护线程

dispose(); 从内存中消除一个窗体对象。

setVisible(false); 隐藏一个窗体。但该窗体并没有消失,可以用 setVisible(true); 再次把它显示出来。如果一个窗体确实不需要了,可以调用 dispose(); 把它清除掉。 ++ Swing读书笔记

1-3:版面管理器(Layout Menager)

|BorderLayout

|FlowLayout

|GridLayout

AWT----|CardLayout

|GridBagLayout

Swing--|BoxLayout

1-3-1:BorderLayout的使用:

BorderLayout的类层次结构图:

java.lang.Object

--java.awt.BorderLayout

构造函数:BorderLayout()建立一个没有间距的border layout

BorderLayout(int hgap,int vgap)建立一个组件间有间距的border layout BorderLayout将版面划分为东、西、南、北、中

例子:BorderLayoutDemo.java

import java.awt.*;

import java.awt.event.*;

import javax.swing.*;

public class BorderLayoutDemo{

public BorderLayoutDemo(){

JFrame f=new JFrame();

Container contentPane=f.getContentPane();

contentPane.setLayout(new BorderLayout());

contentPane.add(new JButton("EAST"),BorderLayout.EAST);

contentPane.add(new JButton("WEST"),BorderLayout.WEST);

contentPane.add(new JButton("SOUTH"),BorderLayout.SOUTH);

contentPane.add(new JButton("NORTH"),BorderLayout.NORTH);

52

contentPane.add(new JLabel("CENTER",JLabel.CENTER),BorderLayout.CENTER);

终止。 f.setTitle("BorderLayout"); f.pack(); f.setVisible(true); /***read**/ /*处理关闭窗口的操作,若你没写这一段,就算你已经关闭窗口了,但程序并不会

*/

f.addWindowListener(

new WindowAdapter(){

public void windowClosing(WindowEvent e){

System.exit(0);

}

}

);

/***read**/

}

public static void main(String[] args){

BorderLayoutDemo b=new BorderLayoutDemo();

}

}

设置组件的间距,你可以使用有间距参数的BorderLayout构造函数,也可以利用BorderLayout的setHgap(int hgap)与

setVgap(int vgap)两个方法来达成。

1-3-2:FlowLayout的使用:

FlowLayout的类层次结构图:

java.lang.Object

--java.awt.FlowLayout

构造函数:FlowLayout()建立一个新的Flow Layout,此FlowLayout默认值是居中对齐,组件彼此有5单位的水平与垂直间距。

FlowLayout(int align)建立一个新的Flow Layout,此FlowLayout可设置排列方式,组件彼此有5单位的水平与垂直

间距。

FlowLayout(int align,int hgap,int vgap)建立一个新的Flow Layout,此FlowLayout可设置排列方式与组件间距。

FlowLayoutDemo.java

import java.awt.*;

import java.awt.event.*;

import javax.swing.*;

public class FlowLayoutDemo{

public FlowLayoutDemo(){

JFrame f=new JFrame();

Container contentPane=f.getContentPane();

/*你可以使用有间距的FlowLayout构造函数,使FlowLayout的排列具有间距, 53

*并可利用排列方向参数来指定靠什么方向排列,FlowLayout共有五种排列方式,

*依次是CENTER(默认值),LEFT,RIGHT,LEADING,TRAILING,若我们将下面程

序第13

*行改成contentPane.setLayout(new FlowLayout(FlowLayout.LEFT)); */

contentPane.setLayout(new FlowLayout());

contentPane.add(new JButton("first"));

contentPane.add(new JButton("second"));

contentPane.add(new JButton("third"));

contentPane.add(new JButton("fourth"));

contentPane.add(new JButton("fifth"));

contentPane.add(new JButton("Last"));

f.setTitle("FlowLayout");

//f.pack();//必须将f.pach()去掉,否则setSize功能将没有作用

f.setSize(400,220);

f.setVisible(true);

f.addWindowListener(

new WindowAdapter(){

public void windowClosing(WindowEvent e){

System.exit(0);

}

}

);

}

public static void main(String[] args){

FlowLayoutDemo b=new FlowLayoutDemo();

}

}

1-3-3:GridLayout的使用:

GridLayout的类层次结构图:

java.lang.Object

--java.awt.GridLayout

GridLayout比FlowLayout多了行和列的设置,也就是说你要先设置GridLayout共有几

行几列,就如同二维平面一般,然后你加

进去的组件会先填第一行的格子,然后再从第二行开始填,依此类扒,就像是一个个的格子

一般。而且GridLayout会将所填进去组

件的大小设为一样。

构造函数:GridLayout()建立一个新的GridLayout,默认值是1行1列。

GridLayout(int rows,int cols)建立一个几行几列的GridLayout.

GridLayout(int rows,int cols, int hgap,int vgap)建立一个几行几列的GridLayout,并

设置组件的间距。

例子:GridLayoutDemo.java

54

import java.awt.*;

import java.awt.event.*;

import javax.swing.*;

public class CardLayoutDemo implements ActionListener{

JPanel p1,p2,p3,p4;

int i=1;

JFrame f;

public CardLayoutDemo(){

f=new JFrame();//当做top-level组件

Container contentPane=f.getContentPane();

contentPane.setLayout(new GridLayout(2,1));

p1=new JPanel();

Button b=new Button("Change Card");

b.addActionListener(this);//当按下"Change Card"时,进行事件监听,将会有系统操作产生。

p1.add(b); //处理操作在52-64行.

contentPane.add(p1);

p2=new JPanel();

p2.setLayout(new FlowLayout());

p2.add(new JButton("first"));

p2.add(new JButton("second"));

p2.add(new JButton("third"));

p3=new JPanel();

p3.setLayout(new GridLayout(3,1));

p3.add(new JButton("fourth"));

p3.add(new JButton("fifth"));

p3.add(new JButton("This is the last button"));

p4=new JPanel();

p4.setLayout(new CardLayout());

p4.add("one",p2);

p4.add("two",p3);

/*要显示CardLayout的卡片,除了用show(Container parent,String name)这个方法外 *,也可试试first(Container),next(Container),previous(Container),last(Container)这 *四个方法,一样可以达到显示效果。

*/

((CardLayout)p4.getLayout()).show(p4,"one");

contentPane.add(p4);

f.setTitle("CardLayout");

f.pack();

55

f.setVisible(true);

f.addWindowListener(

new WindowAdapter(){

public void windowClosing(WindowEvent e){

System.exit(0);

}

}

);

}

public void actionPerformed(ActionEvent event){

switch(i){

case 1:

((CardLayout)p4.getLayout()).show(p4,"two");

break;

case 2:

((CardLayout)p4.getLayout()).show(p4,"one");

break;

}

i++;

if (i==3) i=1;

f.validate();

}

public static void main(String[] args){

new CardLayoutDemo();

}

}

1-3-5:GridBagLayout的使用:是java中最有弹性但也是最复杂的一种版面管理器。它只有一种构造函数,但必须配合GridBagConstraints才能达到设置的效果。

GridBagLayout的类层次结构图:

java.lang.Object

--java.awt.GridBagLayout

构造函数:

GirdBagLayout()建立一个新的GridBagLayout管理器。

GridBagConstraints()建立一个新的GridBagConstraints对象。

GridBagConstraints(int gridx,int gridy,int gridwidth,int gridheight,double weightx,double weighty,int anchor,int fill, Insets insets,int ipadx,int ipady)建立一个新的GridBagConstraints对象,并指定其参数的值。

参数说明:

gridx,gridy:设置组件的位置,gridx设置为GridBagConstraints.RELATIVE代表此组件位于之前所加入组件的右边。若将gridy设置为GridBagConstraints.RELATIVE代表此组件位于以前所加入组件的下面。建议定义出gridx,gridy的位置,以便以后维护程序。表示放在几行几列,gridx=0,gridy=0时放在0行0列。

56

gridwidth,gridheight:用来设置组件所占的单位长度与高度,默认值皆为1。你可以使用GridBagConstraints.REMAINDER常量,代表此组件为此行或此列的最后一个组件,而且会占据所有剩余的空间。

fill:当组件的显示区域大于它所请求的显示区域的大小时使用此字段。它可以确定是否调整组件大小,以及在需要的时候如何进行调整。

weightx,weighty:用来设置窗口变大时,各组件跟着变大的比例,当数字越大,表示组件能得到更多的空间,默认值皆为0。

anchor:当组件空间大于组件本身时,要将组件置于何处,有CENTER(默认值)、NORTH、NORTHEAST、EAST、SOUTHEAST、WEST、NORTHWEST可供选择。

insets:设置组件之间彼此的间距,它有四个参数,分别是上,左,下,右,默认为(0,0,0,0).

ipadx,ipady:此字段指定组件的内部填充,即给组件的最小宽度(高度)添加多大的空间,默认值为0。

我们以前提过,GridBagLayout里的各种设置都必须通过GridBagConstraints,因此当我们将GridBagConstraints的参数都设置好了之后,必须new一个GridBagConstraints的对象出来,以便GridBagLayout使用。

例子:

GridBagLayoutDemo.java

import java.awt.*;

import java.awt.event.*;

import javax.swing.*;

public class GridBagLayoutDemo{

public GridBagLayoutDemo(){

JButton b;

GridBagConstraints c;

int gridx,gridy,gridwidth,gridheight,anchor,fill,ipadx,ipady;

double weightx,weighty;

Insets inset;

JFrame f=new JFrame();

GridBagLayout gridbag=new GridBagLayout();

Container contentPane=f.getContentPane();

contentPane.setLayout(gridbag);

b=new JButton("first");

gridx=0;

57

gridy=0;

gridwidth=1;

gridheight=1;

weightx=10;

weighty=1;

anchor=GridBagConstraints.CENTER;

fill=GridBagConstraints.HORIZONTAL;

inset=new Insets(0,0,0,0);

ipadx=0;

ipady=0;

c=new GridBagConstraints(gridx,gridy,gridwidth,gridheight,weightx,weighty,anchor, fill,inset,ipadx,ipady);

gridbag.setConstraints(b,c);

contentPane.add(b);

b=new JButton("second");

gridx=1;

gridy=0;

gridwidth=2;

gridheight=1;

weightx=1;

weighty=1;

anchor=GridBagConstraints.CENTER;

fill=GridBagConstraints.HORIZONTAL;

inset=new Insets(0,0,0,0);

ipadx=50;

ipady=0;

c=new GridBagConstraints(gridx,gridy,gridwidth,gridheight,weightx,weighty,anchor, fill,inset,ipadx,ipady);

gridbag.setConstraints(b,c);

contentPane.add(b);

b=new JButton("third");

gridx=0;

gridy=1;

gridwidth=1;

gridheight=1;

weightx=1;

weighty=1;

anchor=GridBagConstraints.CENTER;

fill=GridBagConstraints.HORIZONTAL;

inset=new Insets(0,0,0,0);

ipadx=0;

58

ipady=50;

c=new GridBagConstraints(gridx,gridy,gridwidth,gridheight,weightx,weighty,anchor, fill,inset,ipadx,ipady);

gridbag.setConstraints(b,c);

contentPane.add(b);

b=new JButton("fourth");

gridx=1;

gridy=1;

gridwidth=1;

gridheight=1;

weightx=1;

weighty=1;

anchor=GridBagConstraints.CENTER;

fill=GridBagConstraints.HORIZONTAL;

inset=new Insets(0,0,0,0);

ipadx=0;

ipady=0;

c=new GridBagConstraints(gridx,gridy,gridwidth,gridheight,weightx,weighty,anchor, fill,inset,ipadx,ipady);

gridbag.setConstraints(b,c);

contentPane.add(b);

b=new JButton("This is the last button");

gridx=2;

gridy=1;

gridwidth=1;

gridheight=2;

weightx=1;

weighty=1;

anchor=GridBagConstraints.CENTER;

fill=GridBagConstraints.HORIZONTAL;

inset=new Insets(0,0,0,0);

ipadx=0;

ipady=50;

c=new GridBagConstraints(gridx,gridy,gridwidth,gridheight,weightx,weighty,anchor, fill,inset,ipadx,ipady);

gridbag.setConstraints(b,c);

contentPane.add(b);

f.setTitle("GridBagLayout");

f.pack();

f.setVisible(true);

f.addWindowListener(

59

new WindowAdapter(){

public void windowClosing(WindowEvent e){

System.exit(0);

}

}

);

}

public static void main(String[] args){

new GridBagLayoutDemo();

}

}

1-3-5:BoxLayout的使用:

BoxLayout的类层次结构图:

java.lang.Object

--java.awt.BoxLayout

BoxLayout提供了两个常数X_AXIS,Y_AXIS来表示水平或垂直排列。若放进去的组件不等高,则系统将会使所有的组件与最高组件等高,还有,若你将组件都摆在同一行时,系统不因组件宽度在于Container的宽度,而使组件自动摆在下一行,你必须自行处理换 行的操作。

构造函数:

BoxLayout(Container targe,int axis)建立一个水平或垂直的BoxLayout.

讲到BoxLayout,我们就不得不提到Box这个Container,Box这个Container默认的Layout为BoxLayout,而它只能使用这个Layout,否则编译时会有Error产生,如同前面所讲的,BoxLayout是以水平或垂直方式排列,因此,当我们要产生一个Box Container时, 就必须指定它的排列方式,下面为Box的构造函数:

Box(int axis) 建立一个Box Container,并指定组件的排列方式是水平或垂直。

上面的axis参数,我们可以使用BoxLayout.X_AXIS或BoxLayout.Y_AXIS来指定。或是利用Box类所提供的两个方法:

createHorizontalBox()与createVerticalBox(),来建立BoxContainer.

Box类提供4种透明的组件来做更方便的版面管理。分别是glue、strut、rigid、filler: 下面以两个相连的按钮当例子,起始状态如下:

B1.java

1 import java.awt.*;

2 import java.awt.event.*;

3 import javax.swing.*;

4 public class B1{

5 public B1(){

6 JFrame f=new JFrame();

7 Container contentPane=f.getContentPane();

8 Box baseBox=Box.createHorizontalBox();

9 contentPane.add(baseBox);

10 baseBox.add(new JButton("A"));

60

11 baseBox.add(new JButton("B"));

12 f.setTitle("BoxLayout");

13 f.setSize(new Dimension(200,50));

14 f.setVisible(true);

15 f.addWindowListener(

16 new WindowAdapter(){

17 public void windowClosing(WindowEvent e){

18 System.exit(0);

19 }

20 }

21 );

22 }

public static void main(String[] args){

B1 b=new B1();

}

}

Glue:当glue插入在两组件间时,它会将两组件挤到最左与最右(或最上与最下),透明的glue将会占满整个中间的空间。

例:

在10与11行间加入下面一行程序:

baseBox.add(Box.createHorizontalGlue());

Strut:当你不想将A与B按钮挤到最旁边时,你可以使用Strut组件,来设置所需要的大小,但仅能限定一维的大小,例如限定

水平或垂直高度。

例:在10与11行间加入下面一行程序:

baseBox.add(Box.createHorizontalStrut(50));//A,B之间间隔50个像素。

Rigid:这个透明组件跟Strut很像,但它可以设置二维的限制,也就是可以设置水平与垂直的限制宽度。

例:在10与11行间加入下面一行程序:

baseBox.add(Box.createRigidArea(new Dimension(50,50)));

为了将Rigid的高度功能显示出来,因此以pack()方法代替setSize()方法,11行替换为:f.pack();

若我们将高度再拉长,例如baseBox.add(Box.createRigidArea(new Dimension(50,50)));的Dimension改成(50,100),则两

组件的上下空白将会增大,因为透明的Rigid组件高度增高了。

Filler:Filler是Box的inner class,它的功能跟Rigid很像,都可以指定长宽的大小限制,且Filler可以指定最大、较佳、最小的长

宽大小,以下是Filler的构造函数:

Box.Filler(Dimension min,Dimension pref Dimension max)建立一个指定大小的Filler对象。

参数min表示最小的显示区域大小,如同上面的例子所示,若所设置最小区域的高度 61

大于按钮A与B的高度,则按钮A与B的上方

与下方将有空白出现。

pref表示较佳的显示区域大小。max表示最大的显示区域大小。

例:在10与11行间加入下面一行程序:

baseBox.add(new Box.Filler(new Dimension(50,50),

new Dimension(100,50),

new Dimension(200,50)));

Box类所提供的方法:

Static Component createGlue()构造一个Glue组件可向水平与垂直方向延伸 Static Box createHorizontalBox()构造一个水平排列的Box组件 Static Component createHorizontalGlue()构造一个水平的Glue组件

Static Component createHorizontalStrut(int width)构造一个水平的Strut组件 Static Component createRigidArea(Dimension d)构造一个Rigid组件

Static Box createVerticalBox()构造一个垂直排列的Box组件

Static Component createVerticalGlue()构造一个垂直的Glue组件

Static Component createVerticalStrut(int height)构造一个垂直的Strut组件

AccessibleContext getAccessibleContext()取得与JComponent相关边的AccessibleContext

Void setLayout(LayoutManager l)丢出AWTError,因为Box只能使用BoxLayout

例子:BoxLayoutDemo.java

import java.awt.*;

import java.awt.event.*;

import javax.swing.*;

public class BoxLayoutDemo{

public BoxLayoutDemo(){

JFrame f=new JFrame();

Container contentPane=f.getContentPane();

Box baseBox=Box.createHorizontalBox();//先产生水平排列方式的Box组件,当作基底容器(BaseBox)

contentPane.add(baseBox);

/*产生垂直排列方式的Box组件来安置第一与第三个按钮

*/

Box vBox=Box.createVerticalBox();

JButton b=new JButton("first");

vBox.add(b);

b=new JButton("third");

b.setMaximumSize(new Dimension(100,150));

vBox.add(b);

baseBox.add(vBox);

/*产生垂直排列方式的Box组件来安置第二与另一个水平排列方式的Box组件

62

*/

Box vBox1=Box.createVerticalBox();

baseBox.add(vBox1);

b=new JButton("second");

b.setAlignmentX(Component.CENTER_ALIGNMENT); b.setMaximumSize(new Dimension(300,50));

vBox1.add(b);

Box hBox=Box.createHorizontalBox();

vBox1.add(hBox);

/*将第四与最后一个按钮加入水平排列方式的Box组件中 */

Box vBox2=Box.createVerticalBox();

vBox2.add(Box.createVerticalStrut(50));

vBox2.add(new JButton("fourth"));

vBox2.add(Box.createVerticalStrut(50));

hBox.add(vBox2);

Box vBox3=Box.createVerticalBox();

vBox3.add(Box.createVerticalGlue());

vBox3.add(new JButton("THis is the last button")); hBox.add(vBox3);

f.setTitle("BoxLayout");

f.pack();

f.setVisible(true);

f.addWindowListener(

new WindowAdapter(){

public void windowClosing(WindowEvent e){ System.exit(0);

}

}

);

}

public static void main(String[] args){

BoxLayoutDemo b=new BoxLayoutDemo();

}

}

63

Made by e-Stack Room

CoreJava DAY18 awt event

事件模型中,包括事件源对象,事件处理者(事件监听者对象),事件对象。

事件源和事件处理者之间建立了授权注册关系,也就是在事件源类中有一个事件处理者的对象作为属性,也可能是一个事件处理者的集合。

事件对象

事件源————————〉事件处理者

这就是事件模型的机制,也就是由事件源对象发送一个消息(事件对象),然后事件处理者调用相应的方法处理事件。

在事件监听器接口中定义的方法,都要以事件对象为参数。

*** 一个事件源可以注册多个同类型的监听器,也可以注册多种多个事件监听器, 一个事件监听器也可以为多个事件源服务。

事件对象继承自EventObject类,并可以通过getSource()方法获得事件源对象,当然需要在构造事件对象时将事件源对象传入,来区分是哪个事件源发出的事件,所以要用事件对象作为参数。

事件源,事件对象,监听接口,在java.awt包中提供了很多已经定义好的,只需要实现监听接口就好了。

什么是发消息:

A,B,C三个类,分别作为事件源,事件处理者,事件对象。

在A类中有一个B类的属性或者是一个内容为B类对象的集合,也就是事件源和事件处理者之间的建立了授权关系,在B类需要实现一个自定义的接口,这个自定义的接口继承了EventListener,EventListener接口中没有定义任何方法,这只是一个标记接口。 实现在自定义接口中定义好的用于事件处理的方法,C类要继承EventObject类。

这些方法是以事件对象为参数的b(C c),而后在A类a(C c)方法中使用B类的对象调用B类中的b(C c)方法,并把事件对象作为参数,并在main方法中用A类的对象调用了a(c)方法,这也就叫做A类对象给B类发送了消息。

也就是说事件源对象间接调用了事件监听器的方法,并以事件对象为实参传到事件监听器的方法中,要就叫事件源给事件监听器的方法发了一个消息(事件对象)。

①写一个相应的监听器接口的实现类,实现接口中的方法

②把这个实现类的对象添加为某个组件的监听器

监听器实现3种方法:

64

内部类

匿名内部类

实现实际监听接口

例子如下:

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){

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());

65

}

}

/*

* 事件对象类

* 事件对象类中要封装事件源对象

*/

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(); c1.setMessage("Test"); a1.addB(b1);//注册监听器 a1.fire();//发送事件

}

}

以上代码只是事例,在引入包之后可以运行。

在Java的图形编程中,所有动作(事件)都已经提供了相应的事件对象和事件监听接口,例如:实现窗口的关闭按钮,点击关闭按钮会发出相应的事件对象,相应的调用监听器中实现好的方法。

相应的方法清参阅Java2 SE API帮助文档。

缺省适配模式,通过一个抽象类实现接口,抽象类中的接口方法实现,都是一个无意义的空实现,可以继承这个抽象类,只覆盖想覆盖的方法就可以了。

在java.awt.event包中,会有一些适配类,也就是把相应的XXXListener,换成XXXAdapter就是适配类。

在java.awt.event包中的ActionEvent类,在以下操作中会发送这个事件,

1,JButton组件,按钮被点击

2,JTextField组件,在单行文本域中按Enter键。

3,JCheckBox组件,选中了复选框。

4,JRadioButton组件,选中了单选按钮。

5,JMenu组件,选中菜单项。

所有的按钮类都可以添加发出ActionEvent事件。

66

在Java的图形编程中,所有动作(事件)都已经提供了相应的事件对象和事件监听接口, 例如:实现窗口的关闭按钮,点击关闭按钮会发出相应的事件对象,相应的调用监听器中实现好的方法。

相应的方法清参阅Java2 SE API帮助文档。

缺省适配模式,通过一个抽象类实现接口,抽象类中的接口方法实现,都是一个无意义的空实现,可以继承这个抽象类,只覆盖向覆盖的方法就可以了。

在java.awt.event包中,会有一些适配类,也就是把相应的XXXListener,换成XXXAdapter就是适配类。

适配类是抽象类,其中对接口XXXListener中的方法进行了空实现,实现这个类,覆盖对自己有用的方法

在java.awt.event包中的ActionEvent类,在以下操作中会发送这个事件,

1,JButton组件,按钮被点击

2,JTextField组件,在单行文本域中按Enter键。

3,JCheckBox组件,选中了复选框。

4,JRadioButton组件,选中了单选按钮。

5,JMenu组件,选中菜单项。

Text发出Test事件

JTest发出Document事件

添加事件监听:

1、实现监听接口

2、将监听器对象注册在组件(事件源)中

ActionEvent

事件源 --- 组件 JButton 按钮 点击触发ActionEvent

JTextField 单行文本域 输入内容以后回车触发ActionEvent jtf.getText(); //得到文本域中的内容

CoreJava DAY19-20 多线程

C++的多进程是OS系统并发的一个任务

Java中没有多进程,一个JVM就是一个进程

==========================================

JVM Thread 对象

类似于代理模式,通过操作Thread 间接访问线程。

==========================================

OS 线程

==========================================

线程是在进程中并发的一个顺序的执行流程

多进程:划分时间片,宏观上并行,微观上串行

多线程:cpu在进程内部再划分时间片

67

CPU ,代码 ,数据

进程:进程间数据独立

线程:数据空间共享,堆空间的共享(堆空间中存放的是对象),栈空间是独立的 所以线程间切换容易,称为轻量级进程

一个线程对象代表了一个线程,并非就是一个线程

线程是操作系统中负责维护的资源

java.lang.Thread类的一个对象就代表一个线程

线程是底层OS维护的资源,JVM跑在OS上,在JVM中创建一个Thread对象,调用其start()方法,底层OS会申请一个线程资源,线程对象可到底层管理一个线程创建好线程之后,把要让线程执行的代码封装到线程对象中(覆盖run()方法)

实现线程代码的方式:

1、继承Thread 类,覆盖run()方法

去底层申请线程并运行,对线程对象调start()方法,main方法是一个主线程

宏观并行,微观串行

2、实现Runnable接口

使用多态获得Runnable对象,成为目标对象

再利用目标对象构造线程对象 Thread t = new Thread(target);//target为Runnable接口类型

四、多线程的状态转换图(7状态图)

见另一文件,名为Thread.pdf

作业:

用两种方式实现两个线程,一个线程负责打印1-2600,另一个线程打印A-Z,反复打印100遍 是一样的。

线程优先级

Java线程优先级是从0~10的,JVM会自动映射为系统的优先级,所以有时Java不同的优先级,系统优先级

13.1

■ 阻塞状态

▲ 初始状态 ▲阻塞状态 ▲终止状态

\ / ^ 1 ^

\ / \ 2sleep /

\start / \ 3join /stop

\ / \ /

V V \ /

▲ 可运行状态 _ _ _ _ OS选中 _ _ _ _\ ▲运行状态

(只缺CPU) \ CPU到期或调用yield

下面为线程中的7中非常重要的状态:(有的书上也只有认为前五种状态:而将“锁池”和“等待池”都看成是“阻塞”状态的特殊情况:这种认识也是正确的,但是将“锁池”和“等待池”单独分离出来有利于对程序的理解)

1,初始状态,线程创建,线程对象调用start()方法。

2,可运行状态,也就是等待Cpu资源,等待运行的状态。

3,运行状态,获得了cpu资源,正在运行状态。

4,阻塞状态,也就是让出cpu资源,进入一种等待状态,而且不是可运行状态,有三种情况会进入阻塞状态。

68

1)如等待数据输入(输入设备进行处理,而CPU不处理),则放入阻塞,直到输入完毕,阻塞结束后会进入可运行状态。

2)线程休眠,线程对象调用sleep()方法,阻塞结束后会进入可运行状态。 public static void sleep(long millis)

throws InterruptedException

括号中以毫秒为单位, 使线程停止一段时间,间隔期满后,线程不一定立即恢复执行。

当main()运行完毕,即使在结束时时间片还没有用完,CPU也放弃此时间片,继续运行其他程序。

try{ Thread.sleep(1000); }catch(InterruptedException e){

e.printStackTrace(e);

}

线程中有异常,只能trycatch,子类中不能抛出比父类更多的异常,父类run方法没有抛出异常。

3)线程对象2调用线程对象1的join()方法,那么线程对象2进入阻塞状态,直到线程对象1中止。

public final void join() throws InterruptedException 表示其他运行线程放弃执行权,进入阻塞状态,直到调用线程结束。 实际上是把并发的线程变为串行运行。 t1 num t2 char if(c=='m') -> t1.join() //t2对t1调用join,t2进入了阻塞状态 //当条件成立时,t1加入打印数字,一直到打印完,此时t2继续运行 5,中止状态,也就是执行结束。

6,锁池状态

7,等待队列

13.2 共享数据的并发处理

13.2.1

■ 数据的错误发生

多线程并发访问同一个对象(临界资源)

破坏了原子操作,就会发生数据不一致的情况

13.2.2 共享数据的并发处理

■ 多线程同时并发访问的资源叫做临界资源。

多个线程同时访问对象并要求操作相同资源时分割了原子操作就会出现问题。(原子操作,不可再分的操作)会出现数据的不一致或数据不完整,为避免这种现象采用对访问的线程做限制的方法。

■ 互斥锁机制,利用每个对象都有一个monitor(锁标记),当线程拥有这个锁标记时才能访问这个资源,没有锁标记便进入锁池。任何一个对象系统都会为其创建一个互斥锁,这个琐是为了分配给线程的,防止打断原子操作。每个对象的锁只能分配给一个线程。 ■ Synchronized用法

1.Synchronized修饰代码块(同步代码块),

public void push(char c){ 69

synchronized(this)//只有持有当前对象锁标记的线程才能访问这个代码块 {

...

}

}

Synchronized(),也可以锁对象

对括号内的对象加锁,只有拿到锁标记的对象才能执行该代码块

2.Synchronized修饰方法

public synchronized void push(char c) {

...

}

在整个方法里,对当前对象的加锁,只有拿到锁标记的对象才能执行该方法。默认锁住的对象就是this。

▲ 初始状态 ▲阻塞状态 ▲终止状态

\ / ┍ 1IO ┓

\ / \ 2sleep /

\start / \ 3join /stop

\ / \ /

┙ ┕ \ /

▲ 可运行状态 _ _ _ OS选中 _ _ _\ ▲运行状态

(只缺CPU) \ CPU到期或调用yield

┍ /

\ /

\ Synchronized/

\ /

\ ┕

▲ 锁池状态

锁池:一个空间,每个对象都有一个,用来存放等待锁标记的线程

当一个对象中有了锁标记,不会释放其它对象的锁标记。

当t1线程正在访问对象O的同步方法时,别的线程t2不能访问O的任何同步方法,但还是可以访问其它的非同步方法

■ ArrayList Vector

list

△ △

/ \

/ \

/ \

ArrayList Vector(所有方法都做成了同步)

■ 构造方法 ×对象没有完全构造好了,没有当前对象概念

抽象方法 ×抽象方法没有代码块,没用方法体

静态方法 √是对类对象的加锁

☆注意:构造方法不能Synchronized修饰

静态方法可以用Synchronized修饰(是对类对象加锁(类锁该类的Class对象的锁标记, 70

该对象在虚拟机中是唯一的),类对象会在反射时讲到)

抽象方法不能用Synchronized修饰,不影响子类覆盖,子类在覆盖这个方法是可以加Synchronized,也可以不加Synchronized,所以根据Java不允许写废代码的特点是不能写在一起。

■ 练习:

1、用数组实现个栈;一个线程负责入栈一个线程负责出栈;长度为6

char[6],

T1, Push A~Z

T2, Pop

长度为6,并且不允许扩充

-----------------

注意:对当前对象加锁,一个代码块或者方法是同步的(Synchronized),当前对象的锁标记没有分配出去时,有一个线程来访问这个代码块时,就会的到这个对象的锁标记,直到这个线程结束才会释放着个锁标记,其他想访问这个代码块或者是方法线程就会进入这个对象锁池,如果没有得到当前对象的锁标记,就不能访问这个代码块或者是方法。当一个线程想要获得某个对象锁标记而进入锁池,这个线程又持有其他对象的锁标记,那么这个线程也不会释放持有的锁标记。

注:方法的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 , 锁的是类对象。(称为类锁,锁的是Class类的对象。)但是Vector 是 jdk 1.0 的 ArrayList 是 jdk1.2 所以实际应用还是使用ArrayList。

注意:内同步,外同步,内同步,即,类内的方法加同步(synchronized)修饰,外同步即,在需要控制只能由一个线程进行访问时,把需要控制的方法写在同步代码块里。

14.1 多线程的通信

■ 因为线程的死锁,从而引发要多线程的通信

死锁:每个线程不释放自己拥有的资源,却申请别的线程拥有的资源,会造成死锁问题 71

■ 线程间的通信:等待通知机制

■ 每一个对象都有一个等待队列。

线程t1对O调用wait方法,△必须是在对O加锁的同步代码块中。

结果:1、线程t1会释放它拥有的所有的锁标记

2、会进入O的等待队列,开始阻塞

wait用法:

①让当前正在执行的线程对象释放掉锁,②让当前正在执行的线程对象去等待

线程t2对o调用notify/notifyAll方法时,也必须是在对o加锁的同步代码块中。结果:会从o的等待队列中释放一个/全部线程

Wait到notify后获得锁,之间会有时间差的。

▲ 初始状态 ▲阻塞状态 ▲终止状态

\ / ┍ 1 ┓

\ / \ 2sleep /

\start / \ 3join /stop

\ / \ /

┙ ┕ \ /

▲ 可运行状态 _ _ _ OS选中 _ _ _\ ▲运行状态

(只缺CPU) \ CPU到期或调用yield

┍ / \

\ / \wait(释放锁)

\ Synchronized/ \

\ / \

\ / \

\ / \

\ ┕ ┙

▲ 锁池状态 <------ ▲等待队列

notify/notifyall

Thread类的静态方法:currentThread获得正在运行的当前线程

Sleep

Yield

Thread类的非静态方法:

Set/getName

setDeamon() 设置后台进程

线程的几种情况:①代码和数据都不共享。②代码共享,数据不共享。③数据共享。

Java.util.concurrent.locks中的Lock接口,有多个实现类,调用lock和unlock方法,实现和synchronized一样的功能;ReadWriteLock接口,有两个获得锁的方法,读锁和写锁。 重点语句:

Public String get(String key){

R.lock();try{return m.getKey(key);}finally{r.unlock();};

}

使用Lock接口的lock和unlock方法,锁住的代码如果抛出异常,unlock就无法执行,所有需要用try、finally,在finally代码开中解开锁。

72

读写锁特征:

①如果读锁被一个线程锁住了,则其他线程可以再锁读锁,但不允许写锁

一个线程读操作,也允许其他线程做读操作,但不允许做写操作

②如果写锁被一个线程锁住了,则其他线程读锁和写锁都不可以锁锁

一个线程写操作,其他线程读写操作都不可以

对集合类线程安全的包装:

①使用Collections中的SynchronizedMap/List的静态方法包装一下

②使用Lock实现类给集合添加锁P269

关键字:

Volatile

Java.util.concurrent包中的Executor和ExectorService提供了线程和业务逻辑分离的方法。 线程的概念:

线程指进程中的一个执行流程,一个进程可以包含多个线程。

每一个进程都独享一块内存空间。每个进程都需要操作系统为其分配独立的内存地址,而同一进程中的多个线程在同一块地址空间工作,他们共享一块内存和资源。

java中有两中方法创建一个多线程类:

1、继承java.lang.Thread类,覆盖Thread类的run()方法

2、实现Runnable接口,实现Runnable接口的run()方法。推荐使用第二种,因为第二种更加的灵活。

每次调用java.exe的时候操作系统都会启动一个JVM进程,当启动JVM的时候,JVM都会创建一个主线程,改线程从程序入口main方法开始执行,这个线程的名字就叫main,可以在main方法中打印线程名:

System.out.println( Thread.currentThread().getName())来测试。

注意:每次程序运行的时候除了自定义的线程外还有一个main线程。

线程的调度

sleep(xxx),指当前运行的线程睡眠xxx秒,睡眠的时候当前线程会交出CPU,但是不会交出对象的锁!

yield(),指当前运行的线程交出CPU,给其他线程运行的机会。

join(),指将CPU交给调用join()方法的线程对象,直到该线程运行结束。

线程的各种状态

新建状态(new) //线程刚被创建出来

Runnable r = new ThreadTest2();

Thread t1 = new Thread(r,"t1");//创建线程t1 线程处在new状态

就绪状态(Runnable)

t1.start();//启动线程t1,这时候他处在Runnable状态,等待CPU的调度。 运行状态(Running)

如果处在Runnable状态的线程,被调度获得cpu,那么他就处在Running状态 阻塞状态(Blocked)

如果Running中的线程调用sleep(),yield()或者程序运行到等待输入的方法时,他就处在阻塞状态。

如果执行到了wait()语句,释放锁标记,并进入等待池中。直到某个线程调用notifyAll()方法将其从对象的等待池转进锁池,等待锁标记!

死亡状态(Dead)

线程执行完毕,就处于死亡状态。

73

线程安全的控制

关键就是使用:synchronized 、 wait() 和 notifyAll()

当多个线程试图同时修改某个实例的内容时,就由有可能会造成冲突。

为了解决这种冲突,使用synchronized关键字来对该共同访问的实例“加锁”。对同一个实例来说,任意时刻只能有一个synchronized方法在执行。当一个方法正在执行某个synchronized方法时,其他线程如果想要执行这个实例的任意一个synchronized方法,都必须等待当前执行synchronized方法的线程退出此方法后,才能依次执行。

注意!非synchronized方法不受影响,不管当前有没有执行synchronized方法,非synchronized方法都可以被多个线程同时执行。

每一个对象都有一个锁标记,它标记是否有线程在使用该对象。对象有一个等待池,一个锁池。

对同一个对象的不同方法使用synchronized,他们判断的是同一个锁标记,就是对象的本身(this)的锁标记。

一个线程占用了对象的锁标记,其余的线程就得在该对象锁池中等待当前线程释放对象的锁。

Object的方法;wait()和notify()/notifyAll()实现线程之间的通讯。

wait()会使线程对象放弃CPU,并释放对象的锁。JVM会将该线程放到该对象的等待池中,等待其他线程将其唤醒this.notifyAll(),这时所有等待池中的线程都进入对象的锁池,等候锁标记。

wait()产生的效果:

1.让当前正在执行的线程释放掉a的锁标记。

2.让当前正在执行的线程进入a对象的等待池等待。

notify()会唤醒在对象的等待池中等待的一个线程,JVM从对象等待池中随机选择一个线程,把他转换到对象的锁池中,所以一般都用notifyAll()把等待池中所有的线程对象都转入到对象的锁池中。

调用wait()时,该线程必须占用了某个锁标记。也就是必须出现在某一个synchronized的代码块中,并且调用wait()方法的对象必须和synchronized中声明的对象是同一个对象。 例如:

//synchronized修饰的方法就表示使用当前对象的锁标记

public synchronized void f(){

this.wait();

}

public class ThreadTestA {

public static void main(String[] args) {

} ExecutorService e = Executors.newCachedThreadPool(); e.execute(new MyRunnableA()); e.execute(new MyRunnableB()); e.shutdown();

}

class MyRunnableA implements Runnable {

@Override

74

public void run() {

for (int i = 1; i <= 20; i++) {

for (int j = 0; j < 1000000; j++)

;

System.out.println("i=" + i);

}

}

}

class MyRunnableB implements Runnable{

public void run(){

for (char i = 'A'; i <= 'Z'; i++) {

for (int j = 0; j < 1000000; j++)

;

System.out.println("i=" + i);

}

}

}

多线程相关的一些类:

Java.util.concurrent:

import java.util.concurrent.Callable;

import java.util.concurrent.ExecutionException;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.Future;

CoreJava DAY21-22 IO

File类中的方法:

canExecute();

createTempFile();

deleteOnExit();

exists();

getAbsoluteFile();

getAbsolutePath();

getParent();

getPanentFile();

isAbsolute();

length();

File类中的四个静态常量,表示路径分隔符和文件分隔符。跨平台可以使用。File类的对象不新建一个文件,只代表一个文件或目录,存不存在还不知道。输出流是可以新建一个文件的。

流的三种分类:

①按流的方向分类:

输入流 输出流

②按流的输出输入最小单位分类:

75

字节流 字符流

③按层次分类:

结点流 包装流(处理流)

节点流:可以从一个特定数据源(节点)读取数据(如,文件,内存等),构造方法是需 要传参数的。

InputStream OutputStream

输入 输出

字节 字节

它们其子类有结点流也有包装流。

Reader

输入

字节 Writer 输出 字节

它们其子类有结点流也有包装流。

1.stream代表的是任何有能力产出数据的数据源,或是任何有能力接收数据的接收源。 在Java的IO中,所有的stream(包括InputStream和Out stream)都包括两种类型:

1.1 以字节为导向的stream

以字节为导向的stream,表示以字节为单位从stream中读取或往stream中写入信息。以字节为导向的stream包括下面几种类型:

1 input stream:

1) ByteArrayInputStream:把内存中的一个缓冲区作为InputStream使用

2) StringBufferInputStream:把一个String对象作为InputStream

3) FileInputStream:把一个文件作为InputStream,实现对文件的读取操作

4) PipedInputStream:实现了pipe的概念,主要在线程中使用

5) SequenceInputStream:把多个InputStream合并为一个InputStream

2 Out stream

1) ByteArrayOutputStream:把信息存入内存中的一个缓冲区中

2) FileOutputStream:把信息存入文件中

3) PipedOutputStream:实现了pipe的概念,主要在线程中使用

4) SequenceOutputStream:把多个OutStream合并为一个OutStream

1.2 以Unicode字符为导向的stream

以Unicode字符为导向的stream,表示以Unicode字符为单位从stream中读取或往stream中写入信息。以Unicode字符为导向的stream包括下面几种类型:

1 Input Stream

1) CharArrayReader:与ByteArrayInputStream对应

2) StringReader:与StringBufferInputStream对应

3) FileReader:与FileInputStream对应

4) PipedReader:与PipedInputStream对应

2 Out Stream

1) CharArrayWrite:与ByteArrayOutputStream对应

2) StringWrite:无与之对应的以字节为导向的stream

3) FileWrite:与FileOutputStream对应

4) PipedWrite:与PipedOutputStream对应

以字符为导向的stream基本上对有与之相对应的以字节为导向的stream。两个对应类实现的功能相同,字是在操作时的导向不同。如CharArrayReader:和ByteArrayInputStream的作 76

用都是把内存中的一个缓冲区作为InputStream使用,所不同的是前者每次从内存中读取一个字节的信息,而后者每次从内存中读取一个字符。

1.3 两种不现导向的stream之间的转换

InputStreamReader和OutputStreamReader:把一个以字节为导向的stream转换成一个以字符为导向的stream。

处理流:连接已存在的流(节点流或处理流)上,通过对数据的处理为程序通过更强大的读写功能。

2. stream添加属性

2.1 “为stream添加属性”的作用

运用上面介绍的Java中操作IO的API,我们就可完成我们想完成的任何操作了。但通过FilterInputStream和FilterOutStream的子类,我们可以为stream添加属性。下面以一个 例子来说明这种功能的作用。(filter过滤)

如果我们要往一个文件中写入数据,我们可以这样操作:

FileOutStream fs = new FileOutStream(“test.txt”);

然后就可以通过产生的fs对象调用write()函数来往test.txt文件中写入数据了。但是,如果我们想实现“先把要写入文件的数据先缓存到内存中,再把缓存中的数据写入文件中”的功能时,上面的API就没有一个能满足我们的需求了。但是通过FilterInputStream和FilterOutStream的子类,为FileOutStream添加我们所需要的功能。

2.2 FilterInputStream的各种类型

2.2.1 用于封装以字节为导向的InputStream

1) DataInputStream:从stream中读取基本类型(int、char等)数据。

2) BufferedInputStream:使用缓冲区

3) LineNumberInputStream:会记录input stream内的行数,然后可以调用getLineNumber()和setLineNumber(int)

4) PushbackInputStream:很少用到,一般用于编译器开发

2.2.2 用于封装以字符为导向的InputStream

1) 没有与DataInputStream对应的类。除非在要使用readLine()时改用BufferedReader,否则使用DataInputStream

2) BufferedReader:与BufferedInputStream对应

3) LineNumberReader:与LineNumberInputStream对应

4) PushBackReader:与PushbackInputStream对应

2.3 FilterOutStream的各种类型

2.2.3 用于封装以字节为导向的OutputStream

1) DataOutputStream:往stream中输出基本类型(int、char等)数据。

2) BufferedOutputStream:使用缓冲区

3) PrintStream:产生格式化输出

2.2.4 用于封装以字符为导向的OutputStream

1) BufferedWrite:与对应

2) PrintWrite:与对应

IOException是IO包中所有异常的父类。

14.2 IO流

14.2.1 java.io Class File

■ 一个File对象代表了一个文件或目录

File f=new File("1.txt");//在堆里申请了个File对象的空间

77

f.createNewFile();//创建了个文件对象,不会产生文件,只有操作File对去创建文件

f.delete(); f.mkdir(); System.out.println(f.getName());//相对路径 System.out.println(f.getAbsolutePath());//绝对路径

■ File[] listFiles(FileFilter filter)

返回表示此抽象路径名所表示目录中的文件和目录的抽象路径名数组,这些路径名满足特定过滤器。

java.io

接口 FileFilter

accept

boolean accept(File pathname)

File pathname是指被遍历目录中所有文件和目录

作业:打印目录下所有的.java文件,包括子目录(提示:递归)

14.2.2

■ io流是用于JVM和数据源之间交换数据

| | | |

| | | |

| | | |

| --------------- DB |

| JVM 流 net |

| --------------- file|

| | | |

| | | |

■ 一个流也是个对象

流的分类:输入流、输出流

字节流、字符流

节点流、过滤流 (功能,过滤流是给其它增加个功能,本身不传输数据) ■ 装饰模式

武器

/ \

/ \

枪(节点流) 零件

/|\ \

/ | \ \ \ \

瞄 消 M P S L

(过滤流)

14.2.3.1 字节输入流

java.io

类 InputStream

字节输入流的所有类的超类

78

■ java.io

类 FileInputStream

public FileInputStream(String name)

throws FileNotFoundException//文件不存在会抛异常

FileInputStream(File file)

FileInputStream(FileDescriptor fdObj)

■ FileInputStream中方法介绍

void close()

关闭此文件输入流并释放与此流有关的所有系统资源

int read()

从此输入流中读取一个数据字节。

返回下一个数据字节;如果已到达文件末尾,则返回 -1。

int read(byte[] b)

从此输入流中将最多 b.length 个字节的数据读入一个字节数组中。

返回:读入缓冲区的字节总数,如果因为已经到达文件末尾而没有更多的数据,则返回 -1。

int read(byte[] b, int off, int len)

从此输入流中将最多 len 个字节的数据读入一个字节数组中。

CoreJava Day15

15

15.1.1 DataInputStream/DataOutputStream增加读写

关流只关最外层的过滤流就行了\

15.1.2 BufferedInputStream/BufferedOutputStream增加缓冲区

void flush()刷新此缓冲的输出流。

在官方的API帮助文档中,对于readlimit这个参数的解释是:

readlimit - the maximum limit of bytes that can be read before the mark position becomes invalid.

其实,这里的最大字节数(the maximum limit of bytes)是指调用reset()方法之后,读取超过readlimit指定的字节数,标记维(the mark position)会失效,如果这时再次调用reset()方法,会出现Resetting to invalid mark异常。

在mark(int readlimit)方法的代码中,readlimit的值会赋给数据域marklimit,如果marklimit的值大于缓冲区的值BufferedInputStream会对缓冲区的大小进行调整,调整为marklimit的值。

mark 和 reset 一起使用,mark标记读取字符的位置,reset表示重置到mark的位置。 15.1.3 管道流(和UnixC++中的FIFO相同)

■ PipedInputStream和PipedOutputStream (字节流)

这两个是节点流,注意,用来在线程间通信。

所有输入流读方法都是阻塞的。

PipedOutputStream pos=new PipedOutputStream();

PipedInputStream pis=new PipedInputStream(); try { pos.connect(pis); new Producer(pos).start();//线程类对象,在构造时,使用管道流通信 79

new Consumer(pis).start();//线程类对象,在构造时,使用管道流通信 } catch(Exception e) { e.printStackTrace();

}

管道中写入数据的时候应该flush(),否则接收端可能没有数据的。

15.1.4 随机存取文件 (重点)

RondomAccessFile类允许随机访问文件,这个类也是支持直接输出输入各种数据类型。 GetFilepoint()可以知道文件中的指针位置,使用seek()定位。

Mode(“r”:随机读;”w”:随机写;”rw”:随机读写)

1) 实现了二个接口:DataInput和DataOutput;

2) 只要文件能打开就能读写;

3) 通过文件指针能读写文件指定位置;

4) 可以访问在DataInputStream和DataOutputStream中所有的read()和write()操作;

5) 在文件中移动方法:

a. long getFilePointer(): 返回文件指针的当前位置。

b. void seek(long pos): 设置文件指针到给定的绝对位置。

c. long length(): 返回文件的长度。

15.2 字符流

■ 字符流可以解决编程中字符的编码问题。从字符到整数,对字符集和整数集建立一一对应的关系,就算叫做编码,从整数映射到字符,就叫做解码。

■ 编码问题:

字节流的字符编码:

字符编码把字符转换成数字存储到计算机中,按ASCii将字母映射为整数。 把数字从计算机转换成相应的字符的过程称为解码。

编码的方式:

每个字符对应一个整数。不同的国家有不同的编码,

当编码方式和解码方式不统一时,产生乱码。因为美国最早发展软件,所以每种的编码都向上兼容ASCII 所以英文没有乱码。

ASCII(数字、英文)1个字符占一个字节(所有的编码集都兼容ASCII)

ISO8859-1(欧洲) 1个字符占一个字节

GB-2312/GBK 1个字符占两个字节

Unicode 1个字符占两个字节(网络传输速度慢)

UTF-8 变长字节,对于英文一个字节,对于汉字两个或三个字节。 ■ InputStreamReader和OutputStreamWriter(字节流转化成字符流的桥转换器)

这两个类不是用于直接输入输出的,他是将字节流转换成字符流的桥转换器,并可以指定编解码方式。

Reader和Writer (字符流类,所有字符流的父类型)

1) Java技术使用Unicode来表示字符串和字符,而且提供16位版本的流,以便用类似的方法处理字符。

2) InputStreamReader和OutputStreamWriter作为字节流与字符流中的接口。

3) 如果构造了一个连接到流的Reader和Writer,转换规则会在使用缺省平台所定义的字节编码和Unicode之间切换。

80

BufferedReader/(BufferedWriter,不常用)(这两个类需要桥转换)

PrintWriter(带缓存的字符输出流,不需要桥转换)

常用输入输出类型,不需要桥接,其中其它方法请参看API文档。

以上两个都是过滤流,需要用其他的节点流来作参数构造对象。

BufferedReader的方法:readLine():String ,当他的返回值是null时,就表示读取完毕了。要注意,再写入时要注意写换行符,否则会出现阻塞。

BufferedWriter的方法:newLine() ,这个方法会写出一个换行符。

PrintWriter的方法:println(?.String,Object等等)和write(),println(...)这个方法就不必再写换行符了,在使用时会自动换行。

注意:在使用带有缓冲区的流时,在输入之后就要flush()方法,把缓冲区数据发出去。 原则:保证编解码方式的统一,才能不至于出现错误。

java.io包的InputStreamread输入流的从字节流到字符流的桥转换类。这个类可以设定字符转换方式。

OutputStreamred:输出流的字节流桥转换成字符流

Bufferred有readline()使得字符输入更加方便。

在I/O流中,所有输入方法都是阻塞方法。

Bufferwrite给输出字符加缓冲,因为它的方法很少,所以使用父类PrintWrite,它可以使用字节流对象,而且方法很多。

15.3 StringTokenizer

java.util

类 StringTokenizer

15.4 对象序列化

■ 把对象放在IO流上

ObjectInputStream和ObjectOutputStream(对象流)

对象流是过滤流,需要节点流作参数来构造对象。用于直接把对象写入文件和从文件读取对象。

只有实现了Serializable接口的类型的对象才可以被读写,Serializable接口是个标记接口,其中没有定义方法。对象会序列化成一个二进制代码。

writeObject(o),readObject()这两个是对象读写操作时用的方法。

对象的写入叫做对象的序列号,对象的读取叫做对象的反序列化。

readObject()方法是通过反射的方式读取并新建对象的。因为是新建的对象,所以和原来的是不同的对象,只是对象中的数据相同,对象地址不同,是两个对象。(和对象的拷贝一样的!属于深拷贝!)

对象的序列化同样也可以实现深拷贝,同覆盖clone()方法是一样的。可以把对象的序列号输入到内存数组中,用于深拷贝。

Class c=Class.forName("Stduent");

Object obj=c.newInstance();

Field f1=c.getDeclearedField();

Field f2=c.getDeclearedField();

f1.set(obj,***);

f2.set(obj,***);

***是在保存对象的文件中读取的参数。

Object o = new Object(); FileOutputStream fos=new FileOutputStream("Object.obj"); 81

ObjectOutputStream oos=new ObjectOutputStream(fos); oos.writeObject(o); oos.close(); FileInputStream fis =new FileInputStream(“Object.obj”); ObjectInputStream ois =new ObjectInputStream(fis); Object o = (Object)Ois.readObject();

ois.close();

对象流读取结束返回 EOFException异常对象。

一个类中有其他类型的对象,那么,这个类实现了Serializable接口,在对象序列化时,也同样要求这个类中属性都能够对象序列化(基本类型除外)。

对象的序列化会有漏洞,比如保存对象的类不存在了,或者发生更改。

所以需要serialVersionUID(序列化版本唯一标示),如果serialVersionUID发生更改,不管类本身的代码是否更改,程序都认为类发生更改,会抛异常;如果seriaVersionUID一直没变,那么就算类的代码更改,程序也认为类没有发生更改,不会抛异常;但是如果类发生更改,比如属性类型更改了,读回来的数据由于数据类型不匹配,可能被赋值为0或null等。 如果serialVersionUID不一样了,会抛出InvildClassException异常。

注意:对于对象流的操作,在写对象时要一次写入完毕,如果使用追加模式写入,只会读取到上一次写入的对象,使用对象流写入时,会先写入一个头部,然后写入数据,最后加上结束符号,如果使用追加方式写入的话,那就会在结束符号继续向下写入,但是在读取时只会读到结束符为止,以后再次写入的数据就会丢失。

注意:在使用对象流写入对象时要一次向文件写入,不能够采用追加方式。

serialver命令判断是否一个属性或对象可序列化,

serialver TestObject(TestObject必须为已经编译,也就是.class)

执行结果:如果不可序列化;则出现不可序列化的提示。如果可以序列化,那么就会出现序列化的ID:UID。

Externalizable这是Serializable的子接口,他可以让用户自定义如何序列化对象。

readExternal(ObjectInput in),writeExternal(ObjectOutput out)这是这个接口中的两个方法,通过这两个方法可以定制序列化过程。这个方法不安全,可以调用以上两个方法改变对象的状态。

对象中的static和transient属性不会被写入ObjectOutputStream,自然也不会被ObjectInputStream读入。

transient只能用来修饰属性。表示这个属性在对象序列化时将被忽略。

transient int num;

表示当我们对属性序列化时忽略这个属性(即忽略不使之持久化)。所有属性必须都是可序列化的,特别是当有些属性本身也是对象的时候,要尤其注意这一点。

java.util.StringTokenizer类,这个类是用于字符串截取的。

StringTokenizer(参数1,参数2)按某种符号隔开文件

StringTokenizer(s,”:”) 用“:”隔开字符,s为对象。

补充:字节流结束返回-1,字符流结束返回null,对象流结束返回 EOFException 引申---------〉异常经常被用在流程控制, 异常也是方法的一种返回形式。

IO也可以用来做文件加密,对文件重新编码,建立文件。

CoreJava DAY23 网络编程

网络编程

网络基础知识

82

网络编程的目的就是指直接或间接地通过网络协议与其他计算机进行通讯。

计算机网络形式多样,内容繁杂。网络上的计算机要互相通信,必须遵循一定的协议。目前使用最广泛的网络协议是Internet上所使用的TCP/IP协议。

IP地址:计算机在网络中唯一标识,相对于internet,IP为逻辑地址。

IP地址分类:

A类地址

A类地址第1字节为网络地址,其它3个字节为主机地址。另外第1个字节的最高位固定为0。

A类地址范围:1.0.0.1到126.155.255.254。

A类地址中的私有地址和保留地址:

10.0.0.0到10.255.255.255是私有地址(所谓的私有地址就是在互联网上不使用,而被用在局域网络中的地址)。

127.0.0.0到127.255.255.255是保留地址,用做循环测试用的。

B类地址

B类地址第1字节和第2字节为网络地址,其它2个字节为主机地址。另外第1个字节的前两位固定为10。

B类地址范围:128.0.0.1到191.255.255.254。

B类地址的私有地址和保留地址

172.16.0.0到172.31.255.255是私有地址

169.254.0.0到169.254.255.255是保留地址。如果你的IP地址是自动获取IP地址,而你在网络上又没有找到可用的DHCP服务器,这时你将会从169.254.0.0到169.254.255.255中临得获得一个IP地址。

C类地址

C类地址第1字节、第2字节和第3个字节为网络地址,第4个个字节为主机地址。另外第1个字节的前三位固定为110。

C类地址范围:192.0.0.1到223.255.255.254。

C类地址中的私有地址:

192.168.0.0到192.168.255.255是私有地址。

D类地址

D类地址不分网络地址和主机地址,它的第1个字节的前四位固定为1110。

D类地址范围:224.0.0.1到239.255.255.254

Mac地址:每个网卡专用地址,也是唯一的。

端口(port):应用程序(进程)的标识(网络通信程序)OS中可以有65536(2^16)个端口,进程通过端口交换数据。连线的时候需要输入IP也需要输入端口信息。

计算机通信实际上的主机之间的进程通信,进程的通信就需要在端口进行联系。 192.168.0.23:21

协议:为了进行网络中的数据交换(通信)而建立的规则、标准或约定,协议是为了保证通信的安全。

不同层的协议是完全不同的。

OSI网络参考模型(理论性较强的模型)

七层,应用层、表示层、会话层、传输层、网络层、数据链路层、物理层:

网络层:寻址、路由(指如何到达地址的过程)

传输层:端口连接

TCP模型:应用层/传输层/网络层/网络接口

83

层与层之间是单向依赖关系,上层依赖于下层,下层不依赖于上层,层与层之间的连接是虚连接。对等层之间建立协议。

端口是一种抽象的软件结构,与协议相关:TCP23端口和UDT23端口为两个不同的概念。 端口应该用1024以上的端口,以下的端口都已经设定功能。

TCP/IP模型

Application

(FTP,HTTP,TELNET,POP3,SMPT)

Transport

(TCP,UDP)

Network

(IP,ICMP,ARP,RARP)

Link

(Device driver,….)

注:

IP:寻址和路由

ARP(Address Resolution Protocol)地址解析协议:将IP地址转换成Mac地址

RARP(Reflect Address Resolution Protocol)反相地址解析协议:与上相反

ICMP(Internet Control Message Protocol)检测链路连接状况。利用此协议的工具:ping , traceroute

TCP Socket

TCP是Tranfer Control Protocol的简称,是一种面向连接的保证可靠传输的协议。通过TCP协议传输,得到的是一个顺序的无差错的数据流。发送方和接收方的成对的两个socket之间必须建立连接,以便在TCP协议的基础上进行通信,当一个socket(通常都是server socket)等待建立连接时,另一个socket可以要求进行连接,一旦这两个socket连接起来,它们就可以进行双向数据传输,双方都可以进行发送或接收操作。

1) 服务器分配一个端口号,服务器使用accept()方法等待客户端的信号,信号一到打开socket连接,从socket中取得OutputStream和InputStream。

2) 客户端提供主机地址和端口号使用socket端口建立连接,得到OutputStream和InputStream。

TCP/IP的传输层协议

建立TCP服务器端

一般,我们把服务器端写成是分发Socket的,也就是总是在运行,

创建一个TCP服务器端程序的步骤:

1). 创建一个ServerSocket

2). 从ServerSocket接受客户连接请求

3). 创建一个服务线程处理新的连接

4). 在服务线程中,从socket中获得I/O流

5). 对I/O流进行读写操作,完成与客户的交互

6). 关闭I/O流

7). 关闭Socket

建立一个客服部门,为客服部门配置一部电话,分配分机号,等待客户打来的电话,获得通话,通话完毕完毕通话,挂掉电话。

输入输出流必须flush()。

84

ServerSocket server = new ServerSocket(post)

Socket connection = server.accept();

ObjectInputStream put=new ObjectInputStream(connection.getInputStream());

ObjectOutputStreamo put=newObjectOutputStream(connection.getOutputStream()); 处理输入和输出流;

关闭流和socket。

典型的服务器端。

public class Server1 {

public static void main(String[] args) throws Exception {

ServerSocket ss=new ServerSocket(9000);

while(true){

Socket s=ss.accept();//获得一个Socket对象。

Thread t=new Thread1(s);//分发Socket。

t.start();

}

}

}

class Thread1 extends Thread{

Socket s;

public Thread1(Socket s){

this.s=s;

}

public void run(){

try {

OutputStream o=s.getOutputStream();

PrintWriter out=new PrintWriter(o);

out.println("Hello Client");

out.flush();

s.close();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

建立TCP客户端

创建一个TCP客户端程序的步骤:

1).创建Socket

2). 获得I/O流

3). 对I/O流进行读写操作

4). 关闭I/O流

5). 关闭Socket

Socket connection = new Socket(127.0.0.1, 7777);

ObjectInputStream input=new ObjectInputStream(connection.getInputStream());

85

ObjectOutputStream utput=new ObjectOutputStream(connection.getOutputStream()); 处理输入和输出流;

关闭流和socket。

练习:

实现一个网络应用,客户端会给服务器发送一个字符串,服务器会把这个字符串转换成大写形式发回给客户端并有客户端显示,同时,服务器会告知客户端,他是第几个客户端UDP socket 这种信息传输方式相当于传真,信息打包,在接受端准备纸。先由客户端给服务器发消息。以告诉服务器客户端的地址。

特点:

1) 基于UDP无连接协议

2) 不保证消息的可靠传输

3) 它们由Java技术中的DatagramSocket和DatagramPacket类支持

DatagramSocket(邮递员):对应数据报的Socket概念,不需要创建两个socket,不可使用输入输出流。

DatagramPacket(信件):数据包,是UDP下进行传输数据的单位,数据存放在字节数组中,其中包括了目标地址和端口以及传送的信息(所以不用建立点对点的连接)。

DatagramPacket的分类:

用于接收:DatagramPacket(byte[] buf,int length)

DatagramPacket(byte[] buf,int offset,int length)

用于发送:DatagramPacket(byte[] buf,int length, InetAddress address,int port )

DatagramPacket(byte[] buf,int offset,int length,InetAddress address,int port) 注:InetAddress类网址用于封装IP地址

没有构造方法,通过

InetAddress.getByAddress(byte[] addr):InetAddress

InetAddress.getByName(String host):InetAddress

等。

建立UDP 发送端

创建一个UDP的客户端的程序的步骤:

1). 创建一个DatagramPacket,其中包含发送的数据和接收方的IP地址和端口 号。

2). 创建一个DatagramSocket,其中包含了发送方的IP地址和端口号。

3). 发送数据

4). 关闭DatagramSocket

byte[] buf = new byte[1024];

DatagramSocket datagramSocket = new DatagramSocket(13);// set port

DatagramPackage intputPackage = new DatagramPackage(buf,buf.length);

datagramSocket.receive(inputPackage);

DatagramPackage outputPackage = new DatagramPackage(buf,0,buf.length,inetAddress,port); datagramSocket.send(outputPackage); //客户端向服务器发信的过程

没建立流所以不用断开。

建立UDP 接受端

创建一个UDP的服务器端的程序的步骤:

1). 创建一个DatagramPacket,用于存储发送方发送的数据及发送方的IP地址和端口号。

2). 创建一个DatagramSocket,其中指定了接收方的IP地址和端口号。

86

3). 接收数据

4). 关闭DatagramSocket

byte[] buf = new byte[1024];

DatagramSocket datagramSocket = new DatagramSocket();//不用设端口,因为发送的包中端口 DatagramPackage outputPackage=new DatagramPackage(Buf,buf.length,serverAddress,serverPort);

DatagramPackage inputPackage=new DatagramPackage(buf,0,buf.length); //收信之前要准备一封空信

datagramSocket.receive(inputPackage);

UDP处理多客户端,不必多线程,回信可以一封一封的回

在收发信设置为死循环

java.net.URL 统一资源定位器

定位在internet上的某一资源

更高层的网络传输

常用格式

协议名://主机名:端口号/定位寻找主机内部的某一资源

.cn:80/bin/index.html

作用:

1、必须完成

网络聊天室,以广播的形式传输数据

2、QQ聊天室

实现点对点的数据传输

3、统计一个目录下的所有“.java”文件及子目录下的".java"文件总共多少行

87

更多相关推荐:
就业感言

态度决定一切努力铸就成功就业感言在不知不觉中我们已经完成了四个月的培训在还没有褪去记忆里相逢的色彩耳边却已响起了离别的歌谣四个月的时间虽然短暂但在我心里却如曲水流长婉转脑海中留下的点滴痕迹也似萤火中般醒目难忘来...

大学生就业感想(北京达内)

培训感想通过在北京达内公司4个月的艰苦培训我有幸进入航天恒星有限公司在公司遥感部门实习的这半年里学到了很多我的人生翻开了新的一页作为503所的一员我们与企业是鱼和水的关系我们是离不开企业的并且感到自豪因为这是一...

(JSD120xx2王虎)就业感言

尊敬的青岛达内的老师们首先先对你们说声你们辛苦了经过在达内的四个月的学习我现在已经成功就业于东营汉威石油技术开发有限公司我想说的是到达内学习最重要的是坚持无论遇到什么样的困难都要克服它坚持四个月努力学习最后一定...

就业感言

就业感言我作为一名应届毕业生在前途渺茫的时候选择跟学校合作的企业去实训我选择了达内根据达内的教学方式我觉得我能够学到东西揣着不是很确切的心来到北京在达内的学习期间从早到晚的学习氛围会感染很多人在这里总想着一定要...

就业感言

就业感言好像有一句话是这样说的人生不是赢在起点而是转折点这个转折点就是改变在来达内培训之前我也是一个公司小小的主管可是自己在不停的出差做售后的工作中发现自己还是对软件开发更有兴趣并且会当作自己一个可以长期坚持下...

深圳达内学习感想及就业心得

一点都不晚现在就是人生的最好时机达内学习感想及就业心得每个人都有自己的理想每个人都希望朝着自己理想的方向奋勇前进而我正是因为在自己前进道路上的需要而选择了达内在大学毕业后的两年当中我与许多初入社会的年轻人一样有...

邱纯就业感言

就业感言20xx年11月份我踏上了去昆明的火车一段难忘的时光就结束了离开了学校离开了熟悉的环境和亲爱的同学们心里满是悲伤又充满对IT的向往在老师和同学的帮助下我慢慢的进入了状态在此期间我从学生蜕变成一个职业人这...

应聘达内科技公司咨询顾问感言

应聘达内科技公司咨询顾问感言首先很荣幸今天能够去到达内公司应聘老实说在我原先的生活状态中对软件应用这块接触的比较多对软件开发接触甚少加上本身也不是学习这个出身再去公司之前对软件开发只当是茶余饭后的一种八卦闲聊对...

太原达内--事实胜于雄辩 就业说明一切

大家好我是曹云锋于20xx年7月到当年11月在太原达内集团学习我的大学是山西大同大学在大学期间是计算机专业的相信很多在校学生都会有这样的感觉大学期间所学到的东西可能不是很充实自我感觉可能满足不了公司对人才的需求...

达内科技浅谈php行业发展前景以及就业

浅谈PHP发展前景及就业PHP发展前景好吗这是很多想要学习PHP开发的朋友所关注的问题有的人会说IT一直以来都是PHP和net的天下PHP发展前景远没有这两个好但是软件培训网却不敢苟同XKK软件培训网PHP和n...

兄妹两人先后通过青岛达内实现理想就业

记者刚刚从青岛达内软件人才中心获悉今年青岛达内学员整体就业情况非常好每周都有青岛达内学员批量高薪入职知名企业的捷报良好的就业质量赢得了口碑传播在青岛达内中心每天都会迎来通过亲友师哥师姐推荐来到青岛达内学习的新学...

深圳达内为你介绍JAVA就业前景

深圳达内为你介绍JAVA就业前景深圳达内宝安校区cn是隶属于北京达内培训机构10年的老校区致力于3GAndroidJAVA工程师和软件测试工程师的培训目前世界上最流行的计算机编程语言是JAVA20xx年9月达内...

达内就业感言(17篇)