Lusir Sha

Core Java

引言:

1、why:

Core Java是整个Java体系的基础和核心,其他Java技术均是构建在Core Java基础之上的。

2、What:

java语法基础:字符集,条件语句,循环语句

java面向对象编程:特征,高级特性,面向对象编程思想

java IO流(输入输出)和文件操作

多线程编程

图形用户界面(GUI)编程

Java 网络编程:Socket编程

3、How:

Thinking+Coding+Testing;

ch01 java入门

1、Java起源与发展

java起源于SUN公司的Green项目----》Oak

 

SUN公司在推出java语言的同时,也推出了一系列开发工具,如:JDK(java Development Kit)java开发工具包

时间 版本 类库数量 描述

1996 JDK1.0 250 Applet

1997 JDK1.1 500 图形用户界面编程

1998 JDK1.2(java2.0) 2300 全面支持企业及开发

2000 JDK1.3(java2.0)

2002 JDK1.4(java2.0)

2004 JDK1.5(java5.0) 3500 对语言本身做了重大改变,更稳定、更高效、更安全;---Tiger

2005 JDK1.6(java6.0)

补充内容:

java的应用版本:

JavaSE:java标准版本,基础和核心,主要用来做java小程序,桌面程序;

JavaME:java微型版本,主要用来做移动开发,游戏开发;

JavaEE:java企业版本,主要用来做企业级开发;

JDK(java Development Kit)包括:

java虚拟机JVM:编译、运行java程序,JVM可以运行在任何平台上;

java API(java/JDK类库):别人开发好的可以直接使用的类。提供一些最基础和实用的java类,例如java.lang,java.util,java.sql包中的类都处于java API中;

开发工具:这些开发工具都是可执行文件

javac.exe 编译java源程序

java.exe 运行java程序

javadoc.exe 生成java说明文档

jar.exe 打包工具

2、设置java开发环境

1)获取J2SDK

2)安装J2SDK

JDK安装目录下的文件夹简介:

bin:表示java的可执行命令/文件

demo:java的一些基本例子

include:一些c程序,主要是和其它语言集成

jre:java的运行环境,jdk必须有jre,java程序才能被处理

lib:放置库函数,也称之为第三方文件

sample:java的实例程序

src.zip:java类库源代码

 

3)设置环境变量

JAVA_HOME:设置为java安装目录,设置目的是简化其他环境变量的设置;该变量可设可不设;

path:设置java命令(工具)的路径范围,保证在操作系统的任何位置调用java命令;该变量必须设置;%JAVA_HOME%\bin;

classpath:设置java源文件的二进制文件的存储位置,一般设定为当前路径,默认为当前路径。该变量可设可不设;

3、java是什么?

java是编程语言、开发环境、应用环境、部署环境。

制订了规则并予以实现(JDK);

 

4、java的特点

1)简单功能强大的:语法类似于C、C++;废弃了指针操作,自动内存管理;Java提供了大量类库;

2)安全的:无指针操作;严格的代码校验(校验器可以发现操作数栈的溢出,非法类型转化等错误);

3)健壮的:致力检查编译和运行时错误;强类型语言;自动垃圾内存回收;

4)纯面向对象的

面向对象是java语言最重要的特征,具有封装、继承、多态等特征;java语言只支持面向对象编程,不支持类似于C那样的面向过程编程;C++既支持面向对象编程,也支持面向过程编程;

5)解释的:java源程序先编译成结构中立的字节码文件,然后解释执行;C和C++是编译执行的,先编译成本地机器码文件,然后执行;

6)跨平台的(可移植的):即“一次编译,处处执行”,通过JVM虚拟机实现的,其原理是为不同的OS提供不同JVM,但其编译生成字节码文件的规格相同;

java作为一门网络编程语言,编译生成结构中立的字节码文件,该文件可以运行在任意一个具有java运行环境的机器上。

注意:java语言的跨平台是通过JVM实现的,但是JVM本身并不跨平台;

7)多线程的:java是一个从语言级支持多线程程序设计的编程语言,也就是可以直接通过java编程实现多线程。

多线程编程的简单性是Java成为流行的服务器端开发语言的主要原因之一

8)自动垃圾内存回收

垃圾:无用对象占用的内存

垃圾回收:无用对象占用的内存的回收过程

C和C++要通过编程者自身通过编程实现内存的分配和回收,如果内存分配和回收不平衡时,将造成系统资源耗尽或者内存溢出而导致程序异常终止,从而发生错误;

java中垃圾内存是由垃圾回收器线程在适当的时候自动回收。

当系统内存紧张时,回收;否则不回收;

编程者也可以手动回收垃圾内存:java.lang.System.gc()/java.lang.Runtime.gc();

5、JVM(java virtual machine)java虚拟机:利用软件来模拟一个虚拟的环境;

6、垃圾回收

7、java代码安全

8、第一个java程序

1)源文件:包含java代码(符合java语言规则编写的内容)的文件;

特征:以.java为后缀名;可以包含多个类或者接口;文件名与类名或者接口(只包含一个类或者接口)或者与public修饰的类或者接口(包含多个类或者接口)同名;

结构:

包声明:可有可无,如果有只能有一行并且必须处于第一行(注释除外);

 

import语句:可有可无,可有多行,紧跟包声明语句;

类的声明语句;

2)类:java代码的组织单位,java代码就是由一个个类组织的,java编程就是编写一个个的java类;

3)方法、main方法

4)剖析类

package:

将类放入某一特定的包中,便于类的组织、权限访问和区分名字相同的类;

可以定义多级包,中间用“.”分开,包名.包名....

引入包名后,类的名字为:包名+类名;

java中包层次和文件系统中的目录/文件夹结构类似;

import:

导入一个或者多个与本类不在同一包层次下的类文件;

import java.io.File;

import java.io.*;导入java.io包下的所有类,但是不包括其中子包下的类;

java.lang包下的类默认导入;

9、常用的包:

java.lang:包含一些Java语言的基本类与核心类,如String、Math、Integer、System和Runtime,提供常用的功能,这个包中的所有类是被隐式导入的;

java.awt/javax.swing/java.awt.event:包含编写与平台无关的图形界面(GUI)应用程序的类;

java.io:包含一些用作输入输出(I/O)处理的类,主要包括流的类;

java.net:包含用于建立网络连接的类,与java.io同时使用完成与网络有关的读写;

java.util:包含一些实用工具类和数据结构类。像集合类、日期类等。

10、Java API:Java Application Programming Interface,java开发者预先定义好的供编程者直接使用的类库;

ch02 java语法基础

1、程序注释

为了增强程序代码的可读性,在java源文件中的任意位置均可以加入程序注释。

程序中加入注释语句,在java程序编译时会被编译器忽略,无论在程序注释中添加任何东西,编译后程序不受任何影响。

单行注释://注释内容;

利用单行注释,从符号//开始至换行之间的内容会被认为是注释内容编译时编译器会忽略;

例如:int age;//age表示年龄

多行注释:/*.........*/,“/*”,“*/”之间为注释内容,必须成对出现,注释内容可以换行;

例如:/*注释内容*/

或者

/*

注释内容

*/

为了美观可以写成:

/*

*注释内容

*/

文档注释:和多行注释相似,任何声明之前均可加入文档注释,注释内容可被JavaDoc工具读取作为JavaDoc文档内容,文档是对代码结构和功能的描述;

/**

*注释内容

*/

2、java代码编写基本规则

java语句以英文分号结束,为了程序代码的可读性最好占一行;

java代码块放在一对大括号之间;java允许一组语句放在一起用大括号括起来形成代码;例如:循环体,语句块,类体,方法体;语句块可嵌套;

程序忽略空格、制表符、空行、续行符;

3、标识符

java中用来为类、方法、变量等所起的名字叫标识符;

规则:标识符以字母、“_”、“$”开头,后可跟字母、“_”、“$”或者数字,无长度限制,大小写敏感,不能使用java的关键字、预留关键字以及有特殊用途的符号作为标识符;

有效:abc $qw $$$ q1 _$ $_

无效:1q #qw class true

注意:goto和const虽然目前不是java的关键字,但是被作为预留关键字保留;

true,false,null具有特殊用途,不能用做标识符;

Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。

命名规范:类和接口的名字首字母要大写;方法名和变量名第一个单词字首字母要小写,其他首字母要大写;包名要小写;常量名要大写;所有的命名最好不要用中文以及英文之外的其他语言;

4、数据类型:一组性质相同的值的集合以及定义在该值集合上一组操作的总称;

程序的基本功能就是处理数据,程序中用变量来表示数据,变量一定要先定义在使用;

常用的数据类型:整型,浮点型,字符型,字符串型,逻辑型

java中的数据类型分为基本数据类型和引用类型;

引用类型:类类型,数组类型,接口类型等;

基本数据类型:

数值型:整型(字节型byte,short短整型,int整型,long长整型),浮点型(float单精度型,双精度型double)

逻辑型boolean:只能代表两种状态逻辑真或者假,用于判断现实中条件的成立与否,常用来进行逻辑运算和程序的流程控制;

在java中boolean型只能取true或者false,不能像C语言中那样用0和非0的整数来代表true或者false;

字符型char:2个字节,16位,无符号,用“'”括起来;

char a='a';

char a='\u0061';

char a=ox0061;

char a=97;

转义字符:以反斜杠开头

\n 换行符,将光标定位当下一行的开头;

\t 垂直制表符,将光标定位到下一个制表符位置;

\r 回车,将光标定位到当前行开始处,并不移到下一行;

\\ 反斜杠

\' 单引号

5、变量:

变量是用来记录值可以发生改变的数据的标识符,同样那么常量就是用来记录值不可以发生改变的数据的标识符;

在计算机技术中,变量包括变量名和变量值,变量名标示一段特定的存储空间,变量值就是存放在该空间中的二进制数据,可以被修改和访问;

变量的分类:

按照存储数据的数据类型分:基本数据类型和引用类型;

按照声明的位置分:局部变量和成员变量(又称为实例变量);

局部变量:声明在方法

内部或者代码块内;

成员变量:声明在类的内部,方法的外部;

在java中变量在声明和初始化后才能使用

成员变量定义在类的内部,在使用类创建对象时同时创建成员变量,进行系统默认初始化和显示初始化;

方法形参局部变量,在调用方式进行隐式初始化;

变量的作用域和生命周期:

成员变量的作用和其所属对象相同,生命周期随着对象的创建而创建,随着对象的销毁而销毁;

局部变量的作用域为其所在的方法内部或者代码块内部,生命周期就是方法或者代码块的一次执行期间;

6、内存的逻辑分区

栈内存:特定程序专用,先进后出的分配原则,存储空间分配连续,存储容量小速度快。通常存放局部变量;

堆内存:所用应用程序公用,存储空间分配不连续,存储容量大速度慢。通常存放成员变量、对象;

代码区:专门存放方法、代码块;

静态、常量存储区:存放静态变量、常量;

7、理解对象

面向对象的开发方法把软件系统看成各种对象的集合,对象就是最小的子系统,一组相关的对象能够组合成更复杂的子系统。面向对象的开发方法将软件系统看成各种对象的集合,接近人的自然思维方式。

对象是对问题领域中实体、事件的抽象。对象具有以下特性:

1) 万物皆为对象。问题领域中的实体和概念都可以抽象为对象。例如学生,成绩单、教师、课和教室。

2) 每个对象都是惟一的。正如世界上不存在一模一样的叶子。

3) 对象具有属性和行为。

例如小张,性别女,年龄22,身高1.6m, 体重40kg, 能够学习,唱歌。小张的属性包括姓名、性别、年龄、身高和体重,行为包括学习、唱歌。

例如一部手机,牌子是诺基亚、价格是2000元,银白色,能够拍照、打电话和收发短信等。这部手机的属性包括品牌类型type、价格price和颜色color,行为包括拍照takePhoto(),打电话call(),收发短信receiveMessage()和发短信sendMessage().

4) 对象具有状态。状态是指某个瞬间对象的各个属性的取值。对象的某些行为会改变对象自身的状态,即属性的取值。

例如小张本来体重为40kg,经为减肥后,体重减到45kg.

肥胖状态: 40kg

|

| 减肥行为

|

肥胖状态: 35kg

 

5) 每个对象都是某个类的实例。小张和小王都属于学生类、中国和美国都属于国家类、中文和英文都属于语言类。类是具有相同属性和行为的对象的集合。

同一个类的所有实例都有相同属性,但属性取值不一定相同,也就是它们的状态不一定相同。例如小张和小王都属于学生类,都有姓名、性别、年龄、身高和体重这些属性,但是他们的属性取值不同。

同一个类的所有实例都有相同行为,意味着它们具有一些相同的功能。

8、类

类创建对象的模板,创建类语法为:

[<modifiers>] class <class_name>[extends superclass][implements interface a,....]{

[<attribute_declarations>]

[<constructor_declarations>]

[<method_declarations>]

}

修饰符 + 返回类型 +methodName(参数列表){

方法体;

}

void

9、实例化对象

new + 构造方法

引用变量名.属性名或者方法名;

类创建好之后,通过new关键字创建具体对象。它有以下作用:

. 为对象分配内存空间,将对象的实例变量自动初始化为其变量类型的默认值;(Java对象的默认初始化规则:数值型:0或者0.0;字符型:"\u0000";逻辑型:false;引用类型:null;)

. 如实例变量显示初始化,将初始化值赋给实例变量;

. 调用构造方法;

. 返回对象的引用;

注:结合实例,并画内存分配图讲解。

10. 基本类型和引用类型的区别

1) 基本类型代表简单的数据类型,比如整数和字符。

引用类型代表复杂数据类型,引用类型所引用的实例包括操纵这种数据类型的行为。通过"."运算符,就能访问引用变量所引用的实例的方法.

2) 基本类型Java虚拟机会为其分配数据类型实际占用的内存空间;

引用类型仅是一个指向堆区中某个实例的指针。

例:public class Counter {

int count = 13;

}

Counter counter = new Counter();

counter引用变量-------------> Counter实例

count变量(占4个字节,值为13)

counter引用变量的取值为Counter实例的内存地址。

counter引用变量本身也占一定的内存空间,到底占用多少内存空间取决于Java虚拟机的实现,这对Java程序是透明的。

注:counter引用变量到底位于Java虚拟机的运行时数据区的哪个区?取决于counter变量的作用域,如果是局部变量,则位于Java栈区;静态成员变量,则位于方法区;实例成员变量,则位于堆区;

要求:

写一个Teacher类,属性:name,age,gender,salary

对于属性赋值和取值并打印本对象信息

对老师的salary做操作--->写方法,给每个老师加薪,减薪

写一个测试类测试所写的方法

ch03 表达式、运算符、流程控制

1、运算符

算术运算符:+ - * / % ++ --;

自增自减符号:可以放在变量的前面也可以放在后面,放在后面表示先取变量值再自增或者自减1,放在变量前面先自增或者自减1再取变量值;

比较运算符:> >= < <= == != instanceof

引用名 instanceof 类型名;

判断引用是否指向某一类型或者其子类型的实例;

逻辑运算符: && || ! & | ^

语法:进行逻辑运算的逻辑值或者逻辑表达式

短路与:&&

A && B:只有当A的值为true才会考虑B,A,B都为true时返回true,否则false;

短路或:||

A || B 只有当A为false时才考虑B,A,B都为false时返回false,否则返回true;

位运算符:& | ^ ~

移位运算符:<< >> >>>

对整数的二进制数进行移位处理;

a<<b 左移:将二进制形式的a左移b位,最高位b为抛弃,低位(右侧)空出的b位补0;

a>>b 带符号右移:将二进制形式的a右移b位,最右侧的b为抛弃,最高位空出的b位补原来的符号位;

a>>>b 无符号右移:将二进制形式的a右移b位,最右侧的b为抛弃,最高位空出的b位补0;

int a=5;

00000000 00000000 00000000 00000101

a<<2 00 00000000 00000000 00000000 00010100

a>>2 00000000 00000000 00000000 00000001 01

a>>>2 00000000 00000000 00000000 00000001 01

int a=-5

10000000 00000000 00000000 00000101

11111111 11111111 11111111 11111010

11111111 11111111 11111111 11111011

a<<2 11 11111111 11111111 11111111 11101100

a>>2 11111111 11111111 11111111 11111110 11

a>>>2 00111111 11111111 11111111 11111110 11

赋值运算符:=

赋值运算符的左边必须是已经声明过的变量,不能是常量或者复合表达式;

运算符左右两边必须是相同的数据类型,可以进行类型自动转换的除外;

a E=b;

a=a E b;

条件运算符: ? :

(条件表达式)?(值1):(值2);

字符串连接符:+

2、表达式:符合一定语法规则的运算符和操作数组成的序列;

3、类型转换

基本数据类型转换和引用类型转换

基本数据类型转换:

隐式转换(自动转换):从窄精度类型向宽精度类型转换;int b=3;long d=b;

显示转换(强制类型转换):从宽精度类型向窄精度类型转换;

long d=234;int a=(int)d;

byte-->short-->int-->long-->float-->double

char-->int

引用类型转换:

隐式转换(自动转换):让父类型的引用指向子类型实例(对象);

Object object=new String("abc");

显示转换(强制类型转换):让子类型引用转换为父类型;

String str=(String)object;

4、流程控制语句

顺序结构:最简单的基本结构,按照语句顺序执行;

选择(分支)结构:按照给定条件判断,条件为true执行一个分支,为false执行另一个分支;

包括if选择结构和switch分支结构:

if选择结构:

b代表一个逻辑表达式

if(b){

statement or block;

}

if(b){

statement or block;

}else{

statement or block;

}

if(b){

statement or block;

}else if(b){

statement or block;

}else if(b){

statement or block;

}

.....

[else{

statement or block;

}]

if选择结构可以嵌套;

switch选择结构:

switch(expression){

case(常量1):{

statement or block;

break;

}

case(常量2):{

statement or block;

break;

}

......

[dafault:{

statement or block;

break;

}]

}

expression值的类型只能是int,byte,short,char,枚举,类类型之一;

break使得执行完一个分支后跳出switch语句,从语法上来讲可以没有break,但是不合语

意;

default语句可以放在switch结构的任何位置;

循环结构:按照需要使得重复执行一行或者多行代码;

for循环:用于循环次数已知的情况;

while循环:又称为当型循环或者前测试循环,该循环有可能一次都不执行;

do...while循环:又称为直到型循环或者后测试循环,该循环至少执行一次;

for each循环:

*

***

*****

*******

*********

***********

i为行标

每行*的个数为2i-1个;

每行要打印n-i个空格;

break语句:用于终止所在的switch语句或者循环语句;用于终止循环时终止的是所在单层循环;

continue语句:用于结束所在循环的本次执行,即跳过剩余循环语句,开始下一次循环;

ch04 数组

1、概念:一组相同数据类型的数据组成的有序集合;

数组是引用类型,数组型数据是一个对象,数组中元素相当于数组的属性;

数组中存放的元素可以是任意类型,基本数据类型和引用类型;

2、一维数组的声明,初始化,使用

声明:

int[] a;//规范,推荐使用

int a[];

Person[] ps;

Person ps[];

注意:数组在声明时不能指定长度(即元素个数);

例如:int[5] a;//不合法

创建数组

new int[3];

new Person[3];

数组是引用类型,数组的元素相当于对象的成员变量,在数组创建时各元素像对象的成员变量一样将根据元素类型进行默认(隐式)初始化;

数组初始化:

动态初始化:数组的声明、创建和初始化分开进行;

int[] a;

a=new int[3];

a[0]=2;

a[1]=3;

a[2]=9;

Person[] ps;

ps=new Person[3];

ps[0]=new Person("zhangsan",32);

.....

静态初始化:在声明数组的同时给数组分配内存空间并赋值;

int[] a={2,4,6};

Person[] ps={new Person("zhangsan",34),new Person("lisi",87)};

数组的访问:

数组名[元素下标]

数组元素下标:0--n-1;n为元素个数(数组长度);

数组的元素个数可以通过数组的属性length获得;

数组的长度一旦确定将不可改变;

多维数组:

若干个低维数组组成的数组;

特性:多维数组的声明、初始化要从高维到低维进行;

java中的多维数组可以不是规则的矩形;

int[][] a=new int[3][];

int[][] b=new int[3][4];

int[][] c=new int[][4];//非法

int[][] a=new int[3][];

a[0]=new int[3];

a[1]=new int[2];

......

多维数组的初始化:

动态初始化:

int[][] a=new int[3][];

a[0]=new int[3];

a[1]=new int[2];

......

a[0][0]=3;

a[0][1]=4;

.....

静态初始化:

int[][] a={{1,2},{3,4},{5,6,7}};

int[3][2] a={{1,2},{3,4},{5,6}};//非法

数组的拷贝:java.lang.System.arraycopy(源数组,源数组索引位置,目标数组,目标数组索引位置,长度);

数组的排序:java.util.Arrays.sort(数组类型参数);

ch05 对象和类

1、java编程语言是面向对象的,利用java语言进行编程称为面向对象编程(oop:Object-Oriented Programming)。

java编程的基本单位是类,对象要通过类进行实例化,及创建对象。

2、理解对象:

对象的概念和特征(回顾ch02讲过的内容)引出类;

3、类是一种抽象数据类型:引用类型;

类是元数据,元数据就是表示数据的数据,数据在面向对象程序设计中以对象的形式存在,类是对对象共有属性和行为的抽象描述。

成员方法:

包括实例方法(无static修饰)和静态方法(类方法,有static修饰)

参数传递

值传递:对应参数的值拷贝过程,不能影响传入参数的值;

引用传递:不能改变引用变量本身的值,只可能改变传入引用所指向对象的值;

成员变量:

包括实例变量(无static修饰)和静态变量(类变量,有static修饰)

4、this变量:代表当前对象的引用

两种用法:

this.varName(实例变量):用来区分实例变量和局部变量

简化本类构造方法的调用:this(参数列表),在本类构造方法中调用其他构造方法必须放在第一行;

5、封装:封装就是包装,java编程的基本单位是类,也就是说java是以类为基础的,所有的数据和操作都封装到类中,封装是OOP的基本特征之一;

数据隐藏:

提供统一接口;

隐藏实现细节;

提高可维护性;

6、方法的重载 Overloading

条件:

1)方法名必须相同(在同一类中);

2)参数列表必须不同(参数个数不同,参数类型不同,参数顺序不同);

3)返回类型无关紧要(相同不相同均可);

在编译的过程中根据方法参数确定寻找相应的方法,称为编译时多态;

编译之后的方法名加上其参数类型称为唯一的名字;

7、创建和初始化对象

new的作用;

8、构造方法

构造方法是一个特殊的方法,方法名和类名相同,无返回类型;

构造方法在创建所属类型的对象时使用,作用就是创建一个对象,构造方法中的代码一般做一些初始化工作;

每个类都有一个构造方法,如果类中没有定义构造方法,那么系统将自动为其提供一个缺省的无参构造方法;

当一个类中定义了一个或者多个构造方法,那么系统将不再提供缺省的无参构造方法;

一般情况下一个类都要保证具有一个无参构造方法,否则影响操作;

java Web中的JavaBean在使用时,系统将默认调用其无参参构造方法,如果没有定义将出错;

使用:

在本类的其他构造方法中利用this变量来调用;

在当前类的子类中利用super变量来调用;

在程序中创建对象时通过new来调用;

9、继承

概念:在已有类型的基础上进行改进和扩充而得到新的类型,也就是在定义一个类时可以继承一个已有的类,目的是为了简化代码,实现代码的复用;

条件:“is a”的关系

子类,父类--超类,派生;

关键字:extends

特点:

1)Object类是所有java类的父类;

2)单继承

java类只能有一个直接父类,但可以派生出多个子类;

3)子类不能继承父类的构造方法;

4)子类可以继承父类中非private的方法和属性;

5)如果子类声明了一个与父类同名的成员变量,此时我们称子类的成员变量隐藏了父类的成员变量;

5)如果子类声明了一个与父类同名的成员方法,则此时子类不能继承父类的成员方法,此时我们称子类的成员方法覆盖(重写)了父类的成员方法

10、super变量

作用

用来调用父类中被子类隐藏的变量和被覆盖的方法;

用来在子类的构造方法中调用父类的构造方法

1)super只能用在构造方法或者实例方法中,不能用在静态方法或者静态代码块中;

2)子类构造方法一定直接或者间接地调用父类的构造方法;

3)如果子类构造方法没有显示调用父类的构造方法,也没有通过this来调用本类中其他的重载构造方法,那么将默认调用父类无参构造方法(若父类中没有则出错);

11、方法覆盖:

覆盖(重写)overriding:子类根据需要对从父类继承来的方法进行重写实现;

条件:

1)重写发生在子父类之间,同一类中的方法不能被重写只能被重载。

2)重写方法和被重写方法要保证具有相同的方法名字、参数列表、返回类型;

3)重写方法不能具有比被重写方法更严格的访问权限;

4)重写方法不能抛出比被重写方法范围更大的异常;

5)静态方法的重写:父类的静态方法可以被子类同名的静态方法重写,此时隐藏了父类的方法;父类的静态方法不能被子类非静态的方法重写(编译错误);父类非静态的方法不能被子类重写为静态方法;

12、多态

多态是发生在继承的基础上的;

父类 FatherClass 类 Son1Class Son2Class...

FatherClass fc=new Son1Class()或者new Son2Class();

父类的一个引用可以指向多种不同的子类对象;也就是引用可以有很多类型(可以是类型本身也可以强转为所指向对象的类型);

但是一个对象只有一个类型;

多态就是由于一个父类引用指向不同的子类对象所引发的现象。当一个父类引用指向不同的子类对象调用相同的方法时,表现出不同的行为;

多态不像方法重载那样发生在编译时刻,而是发生在运行时刻。

13、instanceof

用法:引用变量 instanceof 类型名

判断引用变量是否指向指定类型的对象或者指定类型的子类型对象,如果是返回true,否则返回false;

引用类型之间的转换:

显式转换:父类型--》子类型(先用instanceof进行类型判断,结果为true才可进行强转)

隐式转换:子类型--》父类型

转化原则:被转化的实际对象类型必须是转化后类型本身或者子类型;

Animal a=new Animal();

Bird b=(Bird)a;

Animal a=new Bird();

Bird b=(Bird)a;

Animal a=new Bird();

Animal aa=(Bird)a;

14、Object类,“==”和equals方法

Object类是所有java的根类;

“==”符号对于基本数据类型就是比较值是否相等,

例如a=2,b=3;a == b返回false;

如果“==”比较两个引用变量也是比较两个引用变量的值是否相等;也就是说看两个引用变量是否指向内存中同一个对象,如果指向同一个对象返回true,否则则返回false;

equals方法:比较两个对象是否相等

,即同一类型的两个对象的各属性值是否相等,如果相等返回true否则返回false;

Object类中实现的equals方法实际和“==”功能相同,所以定义类时通常重写equals方法实现对象相等的比较;

equals和toString方法重写

String类

finalize方法使用

ch06 高级特性

1、static修饰符

static修饰符可以修饰成员变量、成员方法、代码块和内部类。

用static修饰的成员变量,称为成员变量或者类变量,可以通过类名.静态变量名来访问;

用static修饰的成员方法,称为静态方法或者类方法,可以通过类名.静态方法名来访问;

用static修饰的程序代码块,称为静态代码块,在类加载时由java虚拟机执行;

用static修饰的成员变量和成员方法属于整个类公有,不依赖于类的某个实例,为类的所有实例共享;

静态变量:

成员变量分为静态变量和实例变量:

区别:

静态变量属于某个类,在内存中静态变量只存一份,为该类所有实例共享;实例变量对于该类的每一个实例在内存都存一份,互不影响;

java虚拟机在加载类时就为静态变量分配内存,实例变量是在利用类创建对象时分配内存;

静态变量存放在内存中静态变量常量区,实例变量存放在堆区;

静态变量通过类名.变量名访问(当然静态变量也可以通过实例名.变量名来访问,但是将出现警告信息),实例变量通过实例名.变量名访问;

实例一:说明内存分配;实例二:统计一个类创建实例的个数;

静态方法:

1)静态方法不能直接访问类的非静态成员(实例变量和实例方法),可以直接访问类的静态成员;

2)静态方法中不能使用this和super关键字;

3)子类中可以定义与父类同名的静态方法,这成为子类隐藏了父类的静态方法,此时也要满足覆盖条件;但是要注意:静态方法和类绑定,执行静态方法时要看该引用的实际类型,实例方法和实例绑定,执行实例方法要看引用指向对象实际类型;

4)父类中的静态方法不能被覆盖为非静态方法,反之也成立;

静态代码块:

定义在类的内部,方法外部由static修饰的代码块称为静态初始化代码块,类加载时自动执行,并且只执行一次;

非静态代码块:实例化块

非静态代码块在创建对象时自动执行;

静态代码块,非静态代码块,构造方法的执行顺序???

static应用:单例模式

设计模式:不同于语法,高于语法,是一种设计思想,是被人反复使用、多人知晓的、前人代码设计经验的总结;例如单例模式、门面模式、MVC设计模式等

单例模式--》编写一个类实现该类只能产生唯一一个实例(对象);

1)提供一个私有的构造方法;

2)提供一个本类类型的私有的static的成员变量,并使用构造方法进行初始化;

3)提供一个public的方法获得成员变量即唯一实例;

2、final修饰符

final具有最终的,不可改变的意思,final可以修饰类、变量、方法;

final修饰的类不能被继承;

final修饰的方法不能被覆盖;

final修饰的变量即常量,不能被改变只能被赋值一次;常量只能在声明的同时赋值或者在构造方法中显式赋值,赋值后才能使用;

final不能修饰构造方法,抽象类和抽象方法;

3、abstract修饰符

abstract可以用来修饰类、成员方法,称为抽象类和抽象方法;

抽象方法:

只有方法声明,没有方法实现;

public abstract void setName(String name);//抽象方法

抽象方法必须用abstract修饰;

public void setName(String name){

}//不是抽象方法,是普通方法或者说是具体方法,只是实现为空实现;

抽象类:

用abstract修饰的类称为抽象类

语法规则:

1)抽象类不能实例化对象,可以声明引用;

public abstract class A{

.........

}

A a;//合法

new A();//非法

2)包含抽象方法的类必须声明为抽象类;但抽象类可以不包含抽象方法;//??想一想如果可以实例化对象,来调用其中的抽象方法将执行什么???

3)定义抽象类主要用来定义新类时去继承它,子类继承抽象类要实现其中的所有抽象方法,否则必须也声明为抽象类;

抽象类主要作用是:规划和重用代码;由子类继承抽象类去发挥作用;

4)abstract修饰的方法、类不能有final来修饰;

4、接口interface

概念:接口本质是特殊的抽象类,比抽象类更抽象,是常量和抽象方法的集合,接口中只能包含常量和方法的定义,不能定义变量和方法的实现。

public interface Runner{

public static final int id=0;

public abstract void start();

public abstract void run();

public abstract void stop();

}

接口中的定义的属性默认就是public static final修饰的,方法默认是public abstract修饰的,所可以省略;

public interface Runner{

int id=0;

void start();

void run();

void stop();

}

接口和抽象类一样不能实例化对象,只能声明引用;

和继承相似,java类可以实现一个或者多个接口,类实现接口就必须实现所要实现接口中的所有抽象方法;

和子父类一样,接口与实现类之间也存在多态;

数据库--》任何语言数据库编程访问数据库--》导入驱动(SQL Server-微软,Oracle-oracle)

sun共制定统一接口 数据库厂商实现接口(驱动包)

接口可以继承,并且支持多继承;即定义一个接口可以继承一个或者多个已经存在的接口;

类可以在继承一个类的同时实现一个或者多个接口;

5、访问修饰符

类的修饰符

成员修饰符

6、内部类:在一个类内部再定义的一个类;

例如:

public class A{

private class B{

....

}

static class C{

....

}

接口名或抽象类 引用=new 接口名或抽象类(){

.......

};

public void test(){

class D{

...

}

if(...){

class E{

...

}

}

接口名或抽象类 引用=new 接口名或抽象类(){

.......

};

}

}

在程序中,凡是使用内部类的地方都可以使用普通类(顶层类)来替代,使用内部类可使程序更有条理性,代码更加简洁,便于划分类的层次结构和命名规范。

根据变量划分原则来划分内部类:

作用

域划分:

成员内部类:实例内部类 静态内部类

局部内部类:

另外还有一种特殊的局部内部类没有名字,称为匿名内部类;

顶层类:public default

内部类的访问修饰符:private default protected public

静态内部类:最简单一种;

用static修饰的成员内部类(定义在外部类的内部,方法的外部);

1)不能用private修饰;

2)只能访问外部类的静态成员,不能访问非静态成员;

3)创建静态内部类实例不依附于外部类的实例,可以直接通过外部类名.内部类名来创建;

new OuterClass.InnerClass();

实例内部类:没有static修饰的成员内部类;

可以访问外部类的一切成员;

创建内部类的实例要依附于外部类的实例;

例如(new Outer()).new Inner();

 

局部内部类:定义在方法体内或者代码块内;

1)局部内部类和局部变量一样不能使用public,private,protected,static修饰符;

2)局部内部类可以访问外部类的一切成员,只能使用方法体内或者代码块内final修饰的局部变量(常量);

3)局部内部类只能在所定义的方法体内或者代码块内使用;

匿名内部类:既可以定义在方法体或者代码块内,也可以定义在方法体或者代码块外,没有名字,只能在所在之处使用一次;

匿名内部类一定在new关键字的后面使用,隐含着继承一个父类或者实现一个接口,没有名字,根据多态,使用其父类名或者所实现接口名字;

父类名 引用=new 父类名{....};

接口名 引用=new 接口名{....};

应用:a.当类与接口(或者是接口与接口)发生方法命名冲突的时候,此时必须使用内部类来实现。

b.用接口不能完全地实现多继承,用接口配合内部类才能实现真正的多继承。

7、封装类:java API为每个基本数据类型提供了一个包装类;

int --- Integer:对int类型数据进行包装成为一个对象;

byte-----Byte

short----Short

char---Char

boolean----Boolean

float----Float

double----Double

long ----Long

封装类处于:java.lang包下

作用:1)用引用类型表示数值,例如表示一个缺考学生的成绩;

2)有些场合必须使用引用类型,例如:集合中只能存放引用类型;

3)用于基本数据类型间以及与字符串间的转换;

以Integer为例讲解:查阅API文档

8、集合:

引入集合:数组的缺点

集合的概念:用来存放多个对象的对象,并且只能存放对象(引用类型),这个对象可以用来维护和管理一组相同和相似的对象;

集合三要素:接口,接口的实现类,算法

集合相关的要素由java API提供,处于java.util包下

主要掌握用法;

集合框架接口层次图:

Collection:集合的根接口,

集合分为三类:

Set:不允许存放重复的元素,其中存放的元素是无序的;

List:按照一定的顺序存放元素(不是排序),可以存放重复的元素;

Map:存放键值对,不允许存放键重复的键值对,一个键只能对应一个值;

briup---02111111111

SortedSet:和Set类似,其中的元素按升序排列;

SortedMap:和Map类似,其中的键值对按键升序排列;

接口实现类:

Collection--》无直接实现类,提供了访问集合的通用方法;

List---》ArrayList,Vector,LinkedList

Set --》HashSet,LinkedHashSet

SortedSet--》TreeSet

Map---》HashMap

SortedMap---》TreeMap

ArrayList类:实现了List接口,用于表示长度可变的数组列表;在构造对象时可以指定列表长度(所能容纳元素个数),默认长度为10,不指定长度但添加对象数目超过10时,系统将自动增加列表长度;

查阅ArrayList类的API;

Vector类:与ArrayList一样也实现了List接口,表示一个可变的对象数组;

与ArrayList的差别:Vector是同步(线程安全)的,占用的资源多一些,运行效率要低一些,主要用在多线程环境下,ArrayList是不同步的,适合在单线程环境下使用;

Iterator(迭代器):Iterator描述的是使用统一方式对各种集合元素进行遍历/迭代的工具,也称为迭代器;

主要方法:

public interface Iterator{

boolean hasNext();

Object next();

void remove();

}

HashSet类:实现了Set接口,HashSet不能存放重复的元素,其中的元素是无序的;HashSet中可以存放null

HashSet在存储对象元素时,会根据对象的哈希码来计算对象的存储位置,对象的哈希码是通过Object类提供的hashCode()方法来获得,hashCode()方法返回的值是根据对象的内存地址得到哈希码,这两个对象通过new来构造的其地址不一样,那么得到的哈希码就不一样,所以HashSet认为两者是不同的对象;

hashCode返回相同值的同时必须保证对象的equals方法为真这样HashSet才认为两者为相同的对象;

结论:如将自定义类对象用hashSet来添加时,一定要覆盖hashcode()和equals()这两个方法,覆盖的原则是保证当两个对象相同时hashcode返回相同的整数,而且equals()返回的值为True。

TreeSet类:实现了Set接口,实现了排序功能的集合;

在将对象元素添加到TreeSet中时会按照一定排序规则将元素插入到有序的对象序列中,保证TreeSet中的元素组成的对象序列时刻按照“升序”排列;

向TreeSet添加的对象元素的类型必须实现Comparable接口,否则程序编译时出现java.lang.ClassCastException异常,API中String类、封装类都已实现该接口;

HashMap类:实现了Map接口,用于存放“key-value”对信息,不能存放键值重复的“键-值”对;

主要方法:

TreeMap类:使用和HashMap类似;向TreeMap添加的"键--值"对元素的键类型必须实现Comparable接口,否则程序编译时出现java.lang.ClassCastException异常,API中String类、封装类都已实现该接口,这一点和TreeSet完全一致。

反射:

1、概念

java程序在运行时可以动态加载、解析和使用编译时并不确定的类型,这种机制称为反射或者说是内省;也就是说反射机制在运行状态中,对于任意一个类可以知道它具有的属性和方法,如果是一个对象,可以调用它的任意一个方法;指的是动态地获取类型信息和动态执行对象方法的功能;

2、功能

动态加载编译时不确定的类型;

解析类型结构,获取内部信息;

操作类型及其实例,具体包括访问属性信息、执行对象方法、创建实例;

3、反射相关API

java.lang.Class:类类型,用来描述java类的抽象类型,和普通的java类一样。(类是用来描述对象的抽象类型,类的实例是一个特定的对象)

Class的实例表示运行时的java类型,例如:类、接口、注释、数组、枚举、java基本数据类型和void。

在类加载时,java虚拟机将自动创建一个相应的Class对象来描述所加载类的类型信息,即java类的成分信息(属性,构造方法,方法,所实现的接口,所继承的父类,所在包等等信息)。

java.lang.Class

java.lang.reflect.Field

java.lang.reflect.Method

java.lang.reflect.Constructor

java.lang.reflect.Modifier

4、反射编程的基本步骤:

1)获得Class实例

引用类型获取方式:

a:利用Class提供的静态方法forName:

Class c=Class.forName("类名");// 这里的类名指的是类的全名:包名+类名;

b:利用Object类提供的getClass方法:

Person p=new Person();

Class c=p.getClass();

c:利用.class表达式

Class c=类名.class;//这里的类名指的是类的全名:包名+类名;

Class c=String.class;

Class c=com.briup.Person.class;

基本数据类型和void的获取方式:

a:利用.class表达式

Class c=int.class;

Class c=void.class;

b:利用包装类的TYPE

Class c=Integer.TYPE;//表示的是int不是Integer(Integer.class);

Class c=void.TYPE;

2)利用Class对象的方法来获得类型的相关信息;

查阅java.lang.Class API;

3)访问/操作类型成员

java.lang.reflect.Field

java.lang.reflect.Method

java.lang.reflect.Constructor

java.lang.reflect.Modifier

public static final

public static void setName(int a,int b,String str){

};

ch07 异常

1、异常的基本概念:

1)异常产生的条件

或者称为异常情况。在Java代码中哪些是异常情况呢? 例如:

a. 整数相除运算中,分母为0;

b. 通过一个没有指向任何具体对象的引用去访问对象的方法;

c. 使用数组长度作为下标访问数组元素;

d. 将一个引用强制转化成不相干的对象;

..........

2)异常会改变正常程序流程;异常产生后,正常的程序流程被打破了,要么程序中止,要么程序被转向异常处理的语句;

3)当一个异常的事件发生后,该异常被虚拟机封装形成异常对象抛出。

4)用来负责处理异常的代码被称为异常处理器

5)通过异常处理器来捕获异常

6)异常分为错误(Error)和违例(Exception)两种:

错误Error是指像JVM错误,内存资源耗尽等严重情况。程序一旦发生错误是不可恢复的,只能终止程序;

违例Exception是指由于编程错误或者偶然的外在因素引发的事件导致的一般性问题,如网络连接中断、试图打开/读取不存在的文件、数组越界、空指针访问、对负数开平方等。程序发生违例Exception,可以通过适当的手段方式使得程序得以继续运行。

7)在Java中异常是特殊的运行错误对象。是面向对象规范的一部分,是异常类的对象,Java声明了很多异常类,每个异常类都代表了一种运行“错误”。每当Java程序运行过程中发生一个可识别的运行“错误”时,即该“错误”有一个异常类与之相对应时,系统都会产生一个相应的该异常类的对象,即产生一个异常。

2、java异常类层次:

Throwable

|

Error Exception

.....................

1)Error类:表示仅靠程序本身无法恢复的严重错误,比如内存空间不足,或者Java虚拟机的方法调用栈溢出。在大多数情况下,遇到这样的错误时,建议让程序终止。

2)Exception类:表示程序本身可以处理的异常。Exception还可以分为两种:运行时异常和受检查异常。

RuntimeException:运行时异常或者称为未检查异常,编译器不要求捕获、处理;

java.lang.ArithmeticException 算术异常,如除数为0

java.lang.ArrayIndexOutOfBoundsException 数组越界异常,如一个数组由3个元素,访问第4个元素;

java.lang.NullPointerException 空指针异常,没有初始化引用变量就使用

java.lang.NumberFormatException 数据格式转换异常,如Integer.parseInt("a");

java.lang.SecurityException 安全异常,一般碰不到

java.lang.NegativeArraySizeException 数组长度负数异常;

上述异常为unchecked异常,编译器不要求必须捕获,也就是说在程序中不进行异常处理编译时也不会报错,这个时候作为程序员必须考虑到这些情况,确保异常不要发生。如在做除法运算时必须确保除数不为0,通过引用变量访问对象时确保对象不为空等。

运行时异常表示无法让程序恢复运行的异常,导致这种异常的原因通常是由于执行了错误操作。一旦出现了错误操作,建议终止程序,因此Java编译器不检查这种异常。运行时异常应该尽量避免。在程序调试阶段,遇到这种异常时,正确的做法是改进程序的设计和实现方式,修改程序中的错误,从而避免这种异常。捕获它并且使程序恢复运行并不是明智的办法。

受检查异常:除了RuntimeException及其子类以外, 其他的Exception类及其子类都属于受检查异常(Checked Exception)。 这种异常的特点是Java编译器会检查它,也就是说,当程序中可能出现这类异常时,要么用try...catch语句捕获它,要么用throws子句声明抛出它,否则编译不会通过。

例如java.io.IOException,java.lang.ClassNotFoundException,java.io.FileNotFoundException;

3、异常处理

checked异常必须处理,处理有两种方式:就地处理(try-catch块,捕获)和向上抛出;向上抛出异常使用throws关键字,声明将异常抛出给方法的调用者;

异常处理宗旨

1)使得程序返回到一个安全、已知的状态;

2)能够让用户执行其他命令;

3)如果可能保存所有的工作;

4)如果有必要可以退出,以避免进一步危害;

异常处理机制

1)java程序在执行过程中如果出现异常,系统监测到并自动生成对应的异常类对象,然后将它交给运行时系统;

2)运行时系统会寻找相对应的代码来处理这一异常,如果运行时系统找不到对应的异常处理代码,则运行时系统将终止,相应的java程序也将不得不退出;

3)程序员对错误Error无能为力,可以对违例Exception进行处理。

try{

....//可能产生异常的代码

}catch(ExceptionName1 e1){

....//异常处理代码

}catch(ExceptionName2 e2){

....//异常处理代码

}[finally{

....//无条件执行的语句,一般用于资源的释放

}]

在try/catch块语句中可以有多个catch语句,但是其捕获异常类对象应从特殊到一般(从窄到宽)

如果父类中的方法抛出多个异常,则子类中的覆盖方法要么抛出相同的异常,要么抛出异常的子类,但不能抛出新的异常(注:构造方法除外);

import java.io.*;

class B{

public void b() throws Exception{

 

}

}

class C extends B{

public void b() throws FileNotFoundException,IOException{//合法

 

}

}

class C1 extends B{

public void b() throws IOException{//合法

 

}

}

异常调用栈:异常处理时所经过的一系列方法调用过程被称为异常调用栈。

1. 异常的传播:哪个调用,哪个处理;

a. 异常情况发生后,发生异常所在的方法可以处理;

b. 异常所在的方法内部没有处理,该异常将被抛给该方法调用者,调用者可以处理;

        c. 如调用者没有处理,异常将被继续抛出;如一直没有对异常处理,异常将被抛至虚拟机;

2. 如果异常没有被捕获,那么异常将使你的程序将被停止。

异常产生后,如果一直没有进行捕获处理,该异常被抛给虚拟机。程序将被终止。

3. 经常会使用的异常API

getCause():返回类型是Throwable,该方法获得Throwable的异常原因或者null。

getMessage():获得具体的异常出错信息,可能为null。

printStackTrace():打印异常在传播过程中所经过的一系列方法的信息,简称异常处理方法调用栈信息;在程序调试阶段,此方法可用于跟踪错误。

异常对象可以人为制造:

java异常对象除了当程序运行出错时有系统自动生成并抛出外,还可以人工创建异常对象并抛出;使用关键字throw

IOException e=new IOException();

throw e;

或者

throw New Exception();

在人工抛出异常时,必须是Throwable及其子类的对象,否则编译时将产生语法错误;

throw new String("aaa");//非法

throw语句后面不允许紧跟其它语句,因为这些语句永远不会被执行。

4、自定义异常

可以定义自己的异常类,继承Exception,必须人工抛出;

5、断言

JDK1.4引入,在java程序中加入检查语句,主要用于程序调试;

断言机制:

在程序中定义的boolean表达式(假定条件)不成立时(即返回false),系统将产生一个Error对象,类型为AssertionError类型;

在约定条件不成立的情况下需要终止程序操作时使用断言;

断言作为Error的一种,断言失败不必进行铺获处理或者声明抛出,一旦出现终止程序,不必进行补救和恢复。

使用断言

assert boolean表达式[:表达式]

断言用于程序调试,java运行时环境默认关闭断言功能;

开启断言功能:

java -ea classname

或者

java -enableassertions classname

关闭断言功能:

java -da classname

或者

java -disableassertions classname

ch08 GUI

1、基本概念

GUI:Graphics User Interface 图形用户界面,与用户交互的窗口;

我们以前讲的内容也可以说程序都是通过命令行窗口或者说是控制台和用户进行交互,可以通过键盘输入数据给应用程序,程序通过命令行窗口或者控制台返回程序运行后的结果数据给用户,GUI是通过图形化的方式和用户进行交互;图形用户界面更友好,和用户交互很方便;典型是Windows界面,PPT等;

AWT:Abstract Window ToolKit抽象窗口工具集

AWT是JDK的一部分,可以说是Java API的子集,其中包括组件、容器和布局管理器等要素;AWT支持Java GUI事件处理;使用AWT可以进行Java GUI的开发;

AWT构建图形用户界面的机制包括:

提供了一些容器组件(如Frame和Panel), 用来容纳其他的组件(如按钮Button、复选框Checkbox和文本框TextField)。

用布局管理器来管理组件在容器上的布局;

利用监听器来响应各种事件,实现用户与程序的交互。一个组件如果注册了某种事件的监听器,由这个组件触发的特定事件就会被监听器接收和响应;

相关软件包:

java.awt.*:GUI基本组件包;

java.awt.event.*:java GUI事件处理包(用于实现与用户交互);

javax.swing.*:图形界面升级包;

2、组件:Component

组件是图形用户界面的基本组成元素;凡是能够显示在屏幕上并且能够和用户交互的对象称为组件,例如:菜单、按钮、标签、文本框和滚动条等;

组件不能单独的显示出来,必须放在一定的容器中才能显示出来;

在java.awt.*包中定义了很多组件类:Button、Menu、Lable、TextField;

在java.awt.*包中有一个抽象类java.awt.Component,该类是除了Menu类之外所有组件类的功能父类,其中定义了GUI组件的基本特征,例如:尺寸、位置、颜色等;还实现了作为GUI组件应该具备的基本功能;

3、容器:Container

容器本身也是一个组件,具有组件具有的所有性质,只是容器组件可以容纳其他组件或者容器;所以Container是Component的子类;

容器具有add()方法用于添加其他组件到容器中;

容器分类:

1)java.awt.Window

可以自由停泊的顶级窗口;例如:PPT

2)java.awt.Panel

可以作为容器容纳其他组件,但是不能独立存在,必须添加到其他容器;例如:添加到Frame中;

Frame

Frame的类层次结构:java API

java.lang.Object

java.awt.Component

java.awt.Container

java.awt.Window

java.awt.Frame

1、Frame对象的显示效果是一个可以自由停泊的“顶级”窗体;带有标题和尺寸重置角标;

2、Frame默认是不可见的,可以调用Frame的setVisible(true)方法设置为可见;

3、作为容器Frame可以使用add()方法添加组件;

Panel

提供容纳组件的空间,不能独立存在,必须添加到其他容器中;

可以采用与所在容器不同的布局管理器;

组件定位:

java组件在容器中的定位由布局管理器决定;

如果人工控制组件的定位,可取消布局管理器,然后使用Component的方法:

setLocation(),setSize,setBounds()

void setBounds(int x, int y, int width, int height)

void setSize(int width, int height)

void setLocation(int x, int y)

GUI的坐标系:

4、布局管理器:LayoutManager

用来控制组件在容器中的排列风格;包括组件的位置和大小的设定;

为了使java GUI程序具有良好的平台无关性,java提供了LayoutManager来管理容器的布局,不建议直接设置组件在容器中的尺寸和位置;

每个容器都有一个默认的布局管理器,当容器需要对某一组件进行定位或者判断其大小尺寸时,就会调用对应的布局管理器;

GUI程序的开发步骤:

1、确定容器;

2、设置布局管理器

3、向容器添加组件

4、添加事件处理器

一个容器只能有一种排列风格;

例如:BorderLayout、FlowLayout、GridLayout、CardLayout、GridBagLayout等;

Window及其子类(Frame、Dialog)默认布局管理器为BorderLayout;

Panel及其子类(Applet)默认布局管理器为FlowLayout;

BorderLayout

BorderLayout布局管理器是Frame默认的布局管理器;

布局效果:

BorderLayout将容器划分为东西南北中五个区域,组件只能被添加到指定的区域;

添加组件时如果没有指定添加区域,默认添加到Center区域;

一个区域只能放一个组件,如果在一个区域添加多个组件,则先前添加的组件将作废;

组件大小被强行控制,大小与指定区域大小相同;

BorderLayout容器的缩放原则;

FlowLayout

FlowLayout是Panel容器的默认布局管理器

布局效果:

组件在容器中逐行加入,行内自左向右,排满一行后换行;

不改变组件大小,按原始大小加入;

组件在容器中默认居中对齐,也可以通过构造方法设置对齐方式,行间距,组件间距;

GridLayout

GridLayout布局效果:

将容器划分为规则的矩形网格,按照组件的加入顺序自左向右逐行加入,行间自上而下,将组件放入单元格;

组件大小被强行控制,和单元格大小相同,随着容器的大小变化,组件大小自动调整,但相对位置不变;

CardLayout

将多个组件放在容器的同一区域内交替显示,就像落在一起的扑克牌只显示最上面的一张;

CardLayout可以按照名称显示某一张卡片,或者按照顺序依次显示每一张卡片,也可以直接定位到第一张、下一张、上一张或者最后一张;

GridBagLayout

GridBagLayout是建立在GridLayout布局管理器基础上的一种极为复杂和灵活的布局管理方式。

容器嵌套

容器嵌套可以使得原本只能显示一个组件的区域可以显示多个组件;

5、GUI事件处理

引言:

图形用户界面设计并不是我们Java GUI程序设计的全部,甚至不是主要的部分,前面所讲的GUI界面不能用户交互,是静止的,这不是我们想要的。GUI程序应该能够和用户很好的交互,也就是说通过图形界面能够接收来自用户的输入,并且能够按照用户操作做出相应的响应。

Java GUI事件处理机制:

GUI事件处理机制和异常处理机制类似,JDK为GUI组件的各种可能操作预先定义了事件类,如果用户触发了组件的某一操作,组件将产生对应事件类的事件对象,此时将根据事件对象执行注册在该组件上的监听器与事件对象相对应的方法(当然前提是对于我们关心的组件事件,已经在组件上注册了对应的监听器并实现了事件处理方法)。

当用户与GUI交互,比如移动鼠标、按下鼠标键、单击Button按钮、在文本框内输入文本、选择菜单项或者关闭窗口时, GUI会接收到相应的事件,即各种可能的操作。

GUI事件处理的基本概念:

1、事件对象:事件就是描述发生了什么事,也可以说是对组件进行了什么操作,在Java中,用事件对象来描述事件,事件一旦被触发组件就产生对应的事件对象,事件对象对应的类一般均是Java API直接提供,自已很少构建事件对象类;例如:用户对按钮进行了单击操作,被单击的按钮组件将产生ActionEvent事件对象;

2、事件源:能够接收用户事件(用户操作)并产生事件对象的GUI组件都被当做事件源,事件源产生事件对象;如按钮、文本框等;

3、事件监听器:对事件进行处理的对象;该对象定义了能够接收、解析和处理事件的方法,该方法实现与用户交互;

每一种事件都对应专门的监听器中的某一方法。监听器中的方法负责接收和处理这种事件。一个事件源可以触发多种事件,如果它注册了某种事件的监听器,那么这种事件就会被接收和处理。

称为事件处理模型的三要素。

案例总结:GUI事件处理

1、定义监听器类,该类实现特定的接口中的对应抽象方法即编写自己的程序处理逻辑;

2、在相应组件上添加该监听器对象;

3、从此监听器将对该组件发生的某一操作进行监听,若发生对应事件将执行对应监听器的事件处理方法;

ActionEvent

当菜单或者按钮触发ActionEvent事件时,使用actionCommand属性来记录事件的相关指令信息;

从所讲案例中可以看出,GUI程序的运行结果作为开发者并不能控制,和用户操作有关,我们称之为事件驱动程序;

GUI事件类型层次

java.util.EventObject

ActionEvent(点击时触发) ContainerEvent

java.awt.AWTEvent AdjustmentEvent FocusEvent KeyEvent

ComponentEvent InputEvent MouseEvent

ItemEvent WindowEvent

TextEvent

ActionEvent:指鼠标在菜单、按钮进行点击等

AdjustmentEvent:组件或者容器的大小发生变化或者重置

ItemEvent:组件条目发生变化时触发,例如当列表框中条目发生变化或者被选中;

TextEvent:当文本框或者文本域中内容发生变化时触发事件;

ContainerEvent:当向容器加入组件或者从容器移除组件时触发;

FocusEvent:焦点事件,例如组件获得或者失去焦点时触发的事件;

InputEvent:是父类,当用鼠标、键盘进行输入时触发;

KeyEvent:是InputEvent的子类,当用键盘进行输入时触发;

MouseEvent:是InputEvent的子类,当用鼠标进行输入时触发;

WindowEvent:当窗口初始化、最大化、最小化、关闭或者销毁都会触发这种事件;

事件及相应的监听器接口

1)windowActivated(WindowEvent e) //激活窗口

2)windowClosed(WindowEvent e) //调用dispose方法关闭窗口后

3)windowClosing(WindowEvent e) //试图利用窗口关闭框关闭窗口

4)windowDeactivated(WindowEvent e) //本窗口成为非活动窗口

5)windowDeiconified(WindowEvent e) //窗口从最小化恢复为普通窗口

6)windowIconified(WindowEvent e) //窗口变为最小化图标

7)windowOpened(WindowEvent e) //当窗口第一次打开成为可见时

1)keyPressed(KeyEvent e) //键已被按下时调用

2)keyReleased(KeyEvent e) //键已被释放时调用

3)keyTyped(KeyEvent e) //键已被按下并释放时调用

1) componentHidden(ComponentEvent e) //组件隐藏

2) componentMoved(ComponentEvent e) //组件移动

3) componentResized(ComponentEvent e) ///组件改变大小

4) componentShown(ComponentEvent e) ///组件变为可见

1)componentAdded(ContainerEvent e) ///容器内加入组件

2)componentRemoved(ContainerEvent e) //从容器中移走组件

6、Swing组件

处于java.swing.*;

Swing与AWT的关系:

Swing是建立在java AWT的基础上的增强型组件集或者说工具集,使用轻量级组件来替代AWT中绝大多数重量级组件;

JFC:Java Foundation Classes,java基础类库和想象的不一样,JFC专指用于创建java 图形用户界面的API,具体包括Swing、AWT、Java 2D等;

重量级组件:调用操作系统底层组件完成功能,开销大效率低并且具有严重的平台相关性;

轻量级组件:通过java绘图技术实现,开销小效率高具有平台无关性;

Swing组件较AWT功能更强大,更复杂;Swing组件的根类JComponent继承自java.awt.Container;

使用JFrame和JTextField;

7、多重监听器:

通常情况下,事件源可以产生不同的事件对象,因而可以注册(触发)多种不同类型的监听器;

1、同一事件源可以注册多个监听器;

2、同一事件源的同一种事件可以注册多个监听器;

3、一个监听器可以被多个事件源注册。

8、适配器类:Adapter

Adapter是针对大部分的事件监听器接口所定义的对应的实现类,适配器类实现了相应的监听器接口中的所有方法,只不过所有的方法都是空实现即什么事情都不做。

例如:MouseMotionAdapter类的定义为:

package java.awt.event;

public abstract class MouseMotionAdapter implements MouseMotionListener{

public void mouseDragged(MouseEvent e) { }

public void mouseMoved(MouseEvent e) { }

}

为什么要有适配器类?

通过前述实例可以看出,如果要实现GUI的事件处理,要在定义监听器类时实现监听器接口,既然是实现接口必须实现其中所有的方法,在实现的方法中可能有些在程序中根本用不到,当然用不到的方法也只是空实现,尽管是这样这也是程序员十分讨厌的事情。所以出现了Adapter。

主要适配器类介绍:

适配器类 实现的接口

MouseAdapter MouseListener

MouseMotionAdapter MouseMotionListener

FocusAdapter FocusListener

WindowAdapter WindowListener

KeyAdapter KeyListener

ComponentAdapter ComponentListener

ContainerAdapter ContainerListener

两点说明:

1、在JDK中定义的适配器类都是abstract的,其实这不是必须的,只是怕程序员误用。

2、适配器类不能完全替代监听器接口。

假如一个监听器既要监听鼠标事件对象,又要监听单击事件对象应该怎么办??

9、监听器类经常使用内部类实现;

监听器类中方法所实现的功能:重用价值不大。

1、学会常用组件的使用;

2、习惯于查阅API文档;

软件工程:

计算器:

需求分析、设计、实现

利用GUI编程实现一个记事本。

ch10 线程

1、基本概念

程序:

程序是计算机指令的集合或者说一组指令序列,它以文件的形式存储在磁盘上。

进程:

进程是一个程序在其自身的地址空间中的一次执行活动,也可以说进程是运行中的程序;

进程是资源申请、调度和独立运行的单位,因此,它使用系统中的运行资源;而程序不能申请系统资源,不能被系统调度,也不能作为独立运行的单位,因此,它不占用系统的运行资源。

程序和进程是不同的概念,一个程序对应多个进程;

计算机是支持多进程的;

线程

线程是进程中的一个单一的执行流程。

进程是程序的一次执行,程序执行过程中可能有很多个执行流程,所以说:一个进程可以拥有多个线程。

在进程地址空间中,真正完成任务的是线程。

线程又称为轻量级进程,它和进程一样拥有独立的执行控制,由操作系统负责调度,区别在于线程没有独立的存储空间,而是和所属进程中的其它线程共享一个存储空间,这使得线程间的通信远较进程简单。

所以说线程依附于进程,也就是说一个线程必有一个父进程。

计算机支持多线程;

 

为什么设计多线程?

是否可以使用多进程程序替代多线程程序?

Java语言是第一个语言级支持多线程的语言。

2、java中线程的概念模型(三要素):

虚拟的CPU:由java.lang.Thread封装和模拟;

Code:CPU要处理的代码,传递给Thread对象;

Data:CPU要处理的数据,传递给Thread对象;

3、线程的创建:

1)直接继承java.lang.Thread

查看java API了解Thread中的方法;

Thread-n

2)实现Runnable接口

run方法:线程体,线程所实现的业务功能代码;

start方法:启动一个线程,执行线程的run方法;

比较两种创建线程方式:

实现Runnable接口:推荐使用

1)实现接口的同时继承一个其他的java类;

2)将CPU、代码和数据分开;

继承Thread类:

1)编写简单

2)继承Thread的同时不能继承其他类;

区分几种线程:

1)用户线程User Thread:用户创建的线程;

2)main线程:程序的入口方法,程序的主线索;

3)后台线程Daemon Thread:也叫精灵线程,在后台运行,礼让其他线程执行,在系统空闲时运行;例如:JVM中的垃圾回收线程就是一个后台线程;

4)子线程Sub Thread:定义在其他线程中的线程;

3、线程的生命周期:

1)线程的实现有两种方式,一是继承Thread类,二是实现Runnable接口,无论哪种方式,当创建了(new+构造方法)线程对象后,线程就进入了初始状态;

2)当该对象调用了start()方法,就进入可运行状态;

3)进入可运行状态后,当该对象被操作系统选中,获得CPU时间片就会进入运行状态;

4)进入运行状态后情况就比较复杂了

4.1、run()方法或main()方法结束后,线程就进入终止状态;

4.2、当线程调用了自身的sleep()方法或其他线程的join()方法或者发出了IO请求,就会进入阻塞状态(该状态既停止当前线程,但并不释放所占有的资源)。当sleep()结束或join()结束后或者IO操作结束或者调用线程的interupt方法,该线程进入可运行状态,继续等待OS分配时间;

4.3、线程调用了yield()方法或者时间片用完,意思是放弃当前获得的CPU时间片者时间片用完线程还没结束,回到可运行状态,这时与其他进程处于同等竞争状态,OS有可能会接着又让这个进程进入运行状态;

4.4、当线程刚进入可运行状态(注意,还没运行即将运行),发现将要调用的资源被synchronize(同步),获取不到锁标记,将会立即进入锁池状态,等待获取锁标记(这时的锁池里也许已经有了其他线程在等待获取锁标记,这时它们处于队列状态,既先到先得),一旦线程获得锁标记后,就转入可运行状态,等待OS分配CPU时间片;

4.5、当线程调用wait()方法后会进入等待队列(进入这个状态会释放所占有的所有资源,与阻塞状态不同),进入这个状态后,是不能自动唤醒的,必须依靠其他线程调用notify()或notifyAll()方法才能被唤醒(由于notify()只是唤醒一个线程,但我们由不能确定具体唤醒的是哪一个线程,也许我们需要唤醒的线程不能够被唤醒,因此在实际使用时,一般都用notifyAll()方法,唤醒所有线程),线程被唤醒后会进入锁池,等待获取锁标记。

线程的优先级:

1、线程的优先级用一个整数表示1-10(从高到低);

2、线程的默认优先级为5;

java没有规定优先级低的线程就一定要让优先级高的线程先运行且直到线程结束,所以开发时不能利用优先级来控制线程的执行;

相关方法:setPriority和getPriority

属性:MIN_PRIORITY,MAX_PRIORITY,NORM_PRIORITY;

线程的串行化(join方法):

实际应用广泛,多用无参方法;

join();

A B--->B.join();

利用sleep方法实现数字时钟;

yield方法使用,线程让步给其他线程进行执行,使用该方法后线程并不进入阻塞状态而直接进入就绪状态;

t.yield();

主要用于在一个线程在释放已经用完的所占资源时调用,以便其他线程获得使用资源的机会;

实现线程终止,stop方法因存在不安全因素被废弃,必须寻求替代方法;

4、线程同步:

栈的操作实例

class Stack{

int index=0;//元素个数

char[] data=new char[6];

public void push(char c){

data[index]=c;

index++;

}

public char pop(){

index--;

return data[index];

}

}

同一时刻只允许一个线程访问的资源,称为临界资源;处理临界资源的代码称为临界区。

互斥锁:

在java中为了保证共享数据操作的完整性,引入了互斥锁的概念;

java中每一个对象都有唯一一个互斥锁,一旦加上锁之后,保证了同一时刻只能有一个线程访问该对象及其所保护的临界区;

也可以理解为线程如果要访问一个对象及其所保护的临界区,首先应获得该对象的锁,获得对象锁后即获得了访问该对象及其所保护临界区的权力,在该线程没有释放对象锁之前即没有访问完该对象及其所保护临界区之前,其他线程就该对象无法访问该对象及其所保护临界区;

线程---》对象---》代码(临界)

使用关键字synchronied实现给对象加锁;

synchronized可以修饰方法也可以修饰代码块,用synchronized修饰的方法称为同步方法,用synchronized修饰的代码块称为同步代码块;

同步代码块是对this对象加锁;

5、线程死锁:

并发运行的多个线程彼此等待对方占有的资源,都无法运行的状态称为死锁;

A:x,y x

B:x,y y

String StringBuffer

String str="a"+"b"+"c";

"ab"-->"abc"

StringBuffer str="a"+"b"+"c";

"abc"

6、线程同步通信:

为了在多线程并发运行时避免死锁,在线程阻塞时应该尽可能的释放所占有的资源,使得其他线程获得运行的机会;

使用的方法wait(),notify();notifyAll();

wait():是线程本身停止执行等待,同时释放所占有资源;直到有其他线程调用notify或者notifyAll方法才有可能重新执行,否则永远不会执行;

notify:唤醒调用了wait方法而等待的线程中的某一个线程,至于是哪一个不确定;

notifyAll:唤醒调用了wait方法而等待的所有线程;

生产者消费者问题:

题意分析:作为生产者来生产产品而消费者来消费产品,当生产者生产出产品后将其放在一个仓库,然后通知消费者来拿产品并等待,等消费者拿走产品后生产者再往仓库放产品(消费者拿走产品后通知生产者继续放产品);消费者从仓库拿走产品后,通知生产者继续往仓库放产品并等待,等生产者放完产品后再来取产品(生产者放完产品后通知消费者来取产品)。

用多线程来解决这个问题:通过刚才上述对这个问题的分析,看该问题中有几个对象:生产者,消费者另外还有就是放置产品的仓库也是一个对象。仓库是用来存放产品的,以面向对象程序设计的思想,编写仓库这个类,将产品数据和操作产品的方法组织在一起,也就是说仓库类要提供放置产品和获得产品的方法。

生产者和消费者用线程来表示。

类和对象的叫法不好区分;

语境

注意:1、wait方法、notify方法放在同步块或者同步方法中,由于这是使用的是同步方法,所以我们同步的对象是this;2、调用wait方法此时将线程放入this对象的等待队列中,notify方法唤醒的也是this对象的等待队列的线程;这里我们一定要注意wait方法和notify方法一定要处于锁定同一对象的同步代码块中或者同步方法中,否则将会产一些问题。

ch11 I/O流

一、基本概念:

I/O:Input/Output,跨越了JVM边界,和外界进行数据交换;

数据源:数据的来源,一切可以提供数据的地方,例如:磁盘上的文件、键盘、网络连接等;

数据宿:数据目的地,一切可以接收数据的地方,例如:磁盘上的文件、显示器、打印机;

目前很多人将两者都称为数据源。

在java中把不同的数据源和程序间的数据传输抽象的描述成“流”(Stream),计算机中处理的数据形式为“0”或者“1”这样的二进制位,称为数据流;

java.io包中定义了很多流类来实现数据I/O功能。

二、I/O流的分类:

1、按照数据的流向(或者操作类型)分:输入流InputStream和输出流OutputStream;

对于输入流只能从中读数据,不能向其写数据;对于输出流只能向其写数据,不能从中读数据;

区分输入流和输出流的最有效办法:

以当前程序作参照,如果是读数据就用输入流,写数据用输出流;

I/O流类java.io.RandomAccessFile类是个特例,该类即是输入流又是输出流;

2、按照流的功能分:节点流和功能流(或者过滤流、处理流);

节点流只能连接数据源;功能流是对已经存在的节点流进行连接和封装,通过封装来增强流的读写功能,功能流不能数据源直接连接;

3、按照操作的数据单位分:字节流和字符流;

字节流以字节为单位进行传输(读写),字符流以字符为单位进行传输(读写);

java I/O流命名惯例:以InputStream或者OutputStream结尾的流为字节流,以Reader或者Writer结尾的流为字符流;

三、流类的体系结构

4个顶层流类:

这四个均为抽象类,其中InputStream和OutputStram是字节流,Reader和Writer是字符流,InputStream和Reader是输入流,Writer和OutputStram是输出流,均为相应流的父类。

查阅以上流类的API文档熟悉相关方法:

四、常用I/O类:

1、FileInputStream和FileOutputStream:

FileInputStream以字节为单位读取本地文件的数据;FileOutputStream以字节为单位将数据写入到文件;

2、BufferedInputStream/BufferedOutputStream

两者是为字节输入流和输出流增加功能(缓冲);

3、DataInputStream/DataOutputStream

分别实现了DataInput/DataOutput接口;

DataInputStream:允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型和String类型数据;

DataOutputStream:允许应用程序以适当方式将基本 Java 数据类型或者字符串形式写入输出流中;

数据存储格式与JVM中内存中的数据存储格式相同

4、FileReader和FileWriter

FileReader以字符为单位读取本地文件的数据,FileWriter以字符为单位将数据写入文件;

5、BufferedReader/BufferedWriter

两者是为字符输入流和输出流增加功能;

6、InputStreamReader/OutputStreamWriter

InputStreamReader实现字节流向字符流的转换,OutputStreamWriter实现字符流转换为字节流;

流操作的基本步骤:

1)创建节点流实例,和数据源相连;

2)创建功能流实例对第一步创建的节点进行封装,以增强其功能,例如:缓冲功能,操作功能等;

3)操作流,从输入流中读数据,从输出流中写数据;

4)对于具有缓冲功能的流进行刷新操作;

5)关闭流,释放流对象本身占用的资源以及其中使用的其他资源。

PrintStream、PrintWriter

System.in System.out

7、RandomAccessFile类

RandomAccessFile类同时实现了DataInput和DataOutput接口,提供了对文件随机存取的功能,利用这个类可以在文件的任何位置读取或写入数据;

RandomAccessFile类提供了一个文件指针,用来标志要进行读写操作的下一数据的位置。

8、ObjectOutputStream/ObjectInputStream

对象的序列化

1、将对象转换为字节流保存起来,并在日后还原这个对象,该机制称为对象序列化和反序列化;

2、将一个对象保存到永久存储设备上称为持久化;

3、一个对象要想能够实现序列化,必须实现Serializable接口或Externalizable接口;

4、对象的序列化可利用ObjectOutputStream中的writeObject()方法;对象的反序列化可利用ObjectInputStream中的readObject()方法;

5、当一个对象被序列化时,只保存对象的没有transient修饰的非静态成员变量,不能保存任何的成员方法和静态的成员变量;

6、如果一个对象的成员变量是一个对象,那么这个对象的数据成员也会被保存。

7、当我们利用对象的反序列化重新构建对象的时候,它并不会调用这个对象当中的任何构造器,它仅仅是根据我们先前保存对象的状态信息在内存中重新还原这个对象;

8、如果一个可序列化的对象包含对某个不可序列化的对象的引用,那么整个序列化操作将会失败,并且会抛出一个NotSerializableException。我们可以将这个引用标记为transient,那么对象仍然可以序列化。

9、PipedInputStream/PipedOutputStream

使用管道流进行线程间的数据传输;

10、Properties类的使用:

五、文件操作:

java.io.File类:

1)一个File类的对象,表示了磁盘上的文件或目录;一般情况下,File只表示文件,但在Java中它不仅表示文件而且还表示目录;

2)File类提供了与平台无关的方法来对磁盘上的文件或目录进行操作。

查阅Java API文档,熟悉File类的相关方法。

//window下路径中分隔符为“\”,Unix下为"/";/ch04/a.txt

//File.separator在window下指的是“\”,Unix下为"/"

ch12 网络编程

基本概念:

1、计算机网络

计算机网络是相互连接的独立自主的计算机的集合,最简单的网络形式由两台计算机组成。

2、网络通信

IP地址:

1)IP网络中每台主机都必须有一个惟一的IP地址;

2)IP地址是一个逻辑地址;

3)因特网上的IP地址具有全球唯一性;

4)32位,4个字节,常用点分十进制的格式表示,例如:192.168.0.16。

协议:

1)为进行网络中的数据交换(通信)而建立的规则、标准或约定;(=语义+语法+规则) ;

2)不同层具有各自不同的协议。

端口号:

端口使用一个16位的数字来表示,它的范围是0--65535,1024以下的端口号保留给预定义的服务。例如:http使用80端口。

3、OSI(Open System Interconnection)参考模型

物理层:二进制传输,确定如何在通信信道上传递比特流;

数据链路层:加强物理层的传输功能,建立一条无差错的传输线路;

网络层:在网络中数据到达目的地有很多线路,网络层就是负责找出最佳的传输线路;

传输层:传输层为源端计算机到目的端计算机提供可靠的数据传输服务,隔离网络的上下层协议,使得上层网络应用的协议与下层无关;

会话层:在两个相互通信的应用进程之间建立、组织和协调其相互之间的通信;

表示层:处理被传送数据的表示问题,也就是信息的语法和语义,如有必要将使用一种通用的格式在多种格式中进行转换;

应用层:为用户的应用程序提供网络通信服务;

OSI(Open System Interconnection)参考模型并不是物理实体上存在这七层,这只是功能的划分,是一个抽象的参考模型。进行网络通信时,每层提供本层对应的功能;

1)通信实体的对等层之间不允许直接通信,它们之间是虚拟通信,实际通信在最底层完成;

2)各层之间是严格单向依赖;

3)上层使用下层提供的服务 — Service user;

4)下层向上层提供服务 — Service provider。

5)对等层实体之间虚拟通信;

6)下层向上层提供服务,实际通信在最底层完成。

6、OSI各层所使用的协议

1)应用层:远程登录协议Telnet、文件传输协议FTP(网上下载一个软件或者资料的时候就会使用该协议)、 超文本传输协议HTTP(使用较多,通过IE浏览一个网页的时候就使用该协议)、域名服务DNS(使用较多,通过网络访问一个计算机一般不使用该主机的IP地址,而是通过该主机的域名访问)、简单邮件传输协议SMTP(通过Formail发送邮件)、邮局协议POP3等(通过Formail收邮件);

2)传输层:传输控制协议TCP、用户数据报协议UDP;

TCP:面向连接的可靠的传输协议;在利用TCP协议进行通信的时候,首先要经过三步握手建立起通信双方的连接,一旦连接建立后就可以通信了。TCP协议提供数据确认和重传的机制,保证数据一定能够到达数据接收端。像打电话。

UDP:是无连接的,不可靠的传输协议;采用UDP协议进行通信时,不需要建立连接,可以直接向一个IP地址发送数据,至于是不是能够收到不能保证,发送过程中数据有可能丢失、IP地址可能不存在、再者IP地址代表的主机没有运行等原因都可能导致不能接收到数据。

3)网络层:网际协议IP、Internet互联网控制报文协议ICMP、Internet组管理协议IGMP。

基于TCP的Socket编程步骤:

1)服务器程序编写:

①调用ServerSocket(int port)创建一个服务器端套接字,并绑定到指定端口上;

②调用accept(),监听连接请求,如果客户端请求连接,则接受连接,返回通信套接字;

③调用Socket类的getOutputStream()和getInputStream获取输出流和输入流,开始网络数据的发送和接收;

④最后关闭通信套接字。

2)客户端程序编写:

①调用Socket()创建一个流套接字,并连接到服务器端;

②调用Socket类的getOutputStream()和getInputStream获取输出流和输入流,开始网络数据的发送和接收;

③最后关闭通信套接字。

基于UDP的Socket编程步骤:

1)接收端程序编写:

①调用DatagramSocket(int port)创建一个数据报套接字,并绑定到指定端口上;

②调用DatagramPacket(byte[] buf, int length),建立一个字节数组以接收UDP包 ;

③调用DatagramSocket类的receive(),接收UDP包;

④最后关闭数据报套接字。

2)发送端程序编写:

①调用DatagramSocket()创建一个数据报套接字;

②调用DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port),建立要发送的UDP包;

③调用DatagramSocket类的send(),发送UDP包;

④最后关闭数据报套接字。

URL:

URL(Uniform Resource Locator统一资源定位器):表示Internet上资源的地址;

URL格式:<协议名><资源所在主机>[:端口号][资源名]

http://home.netscape.com/home/welcome.html

http://www.sun.com:80/

http://www.cs.tsinghua.edu.cn:8888/