core java的课程体系

 Java语法基础
 Java面向对象的编程
 Java的高级编程接口:4个专题

 Java图形GUI编程

 多线程编程
 I/O编程
 网络编程

Java语言的知识体系结构图
The Java Programming Language Basics
Identifiers,
Identifiers,
Keywords,
Keywords,and
and Types
Types

Getting
Getting Started
Started

Expressions
Expressions and
and
Flow
Flow Control
Control

Arrays
Arrays

Object-Oriented Programming
Objects
Objects
and
and Classes
Classes

Advanced
Advanced
Language
Language Features
Features

Exception Handling
Exceptions
Exceptions

Developing Graphical User
Building
Building GUIs
GUIs

The
The AWT
AWT
Event
Event Model
Model

lnterfaces

The
The AWT
AWT
Component
Component Library
Library

Applets
Introduction
Introduction
to
to Java
Java Applets
Applets

Multithreading
Threads
Threads

Communications
Stream
Stream I/O
I/O
and
and Files
Files

Networking
Networking

Java
Java Foundation
Foundation
Classes
Classes

java语法基础
Day01-Day03

Day01
 了解java的产生与发展
 理解java语言的特性
 理解java虚拟机jvm的特性和功能
 理解字节码和垃圾收集的概念
 列举出在java平台上实现代码安全的方法
 知道在java中定义类,包,applets和applications
 掌握编码,编译,运行java应用程序的步骤
 安装,搭建java开发运行环境

 第一个java程序
 带包的java程序

 JVM搜索类的顺序和类加载
 CLASSPATH的应用
 常用的java命令

Java的产生与发展
Java的产生

Sun公司的Green项目

基于c++开发的Oak语言

Mosaic和Netscape到JavaHot浏览器

Internet的蓬勃发展推动了java的发展(Applet)

Java(爪哇) 名字的由来
Java的发展

Java的现状
 纯面向对象的语言
 平台无关性,一次编写,到处运行
 适合于基于Internet应用程序开发

Java的地位确立
 IT产业很多大公司购买了java的许可证
 众多软件开发商已支持java软件产品
 Intranet是企业信息系统最佳的解决方案,java发挥了不可替代的
作用

Java的发展与其分支
 95.5.23 Oak改名为java
 98.12. java1.2,后来改名为java2
 陆续出现了java1.3,java1.4
 2004.12 java1.5版本推出 命名为java5.0
 后来陆续出现java6.0,java7.0

Java的产生与发展

 Java的发展与其分支

 java在今天已形成了庞大的体系,经过十年发展,已有了3个平台标准
 三大技术平台都提供了相应的开发工具包(SDK:SoftWare
Development Kits)
 java SE --标准版应用平台

 java EE--企业级应用平台
 java ME—微型版应用平台:应用在存储,运算很小的受限的平台

Java语言的特性

什么是java?

程序设计语言;开发环境;应用环境;部署环境
Java的特性

提供更简单的方式写程序
 无指针,无需做内存管理
 提供庞大的类库,纯粹面向对象设计
 支持静态和动态的代码继承和重用

提供一个可解释执行的环境
 支持任何开发平台
 只写一次,到处使用
 支持多线程
 支持动态升级

以上特性如何实现
 Java虚拟机:JVM
 垃圾收集:Garbage Collection
 代码安全:Code Security
 字节码文件:Verifying

Java语言的特性  JVM与跨平台性:  一次编写,到处运行:不同操作系统.不同的服务器 编译器  数据类型也可以实现跨平台 可执行的机  Java虚拟机的作用 源文件 器码文件  程序的开发及运行方式 解释器 边解释  Java的工作方式:先编译后解释 源文件 边执行 Java是先编译后解释执行 .不同数据库.

他们之间有很好的接 口 JVM存在的意义实际上就是屏蔽掉底层平台的差异,为上层结构中立 的字节码统一运行的环境,而JVM会将字节码转化成相应的底层平台 的机器码执行 java解释器功能是用JVM来实现的,java的解释器是在jvm中运行的 JVM的作用:   对下是屏蔽掉了底层平台的差异,对于上层的字节码而言不需要关心它运 行在什么平台上,由JVM去把底层平台的差异屏蔽掉 对上为结构中立的字节码提供了统一的运行环境,实现了字节码的跨平台 Bytecode JVM CPU .Java语言的特性        Java源文件先通过编译生成一个字节码文件bytecode 字节码不与当前OS相关,结构中立的,是二进制文件。任何平台编译 生成的字节码都是一样的。 字节码文件不能直接执行,必须需要JVM的支撑才能运行 JVM是sun开发的,字节码的结构也是sun定义的.

System.lang.Java语言的特性   Java的垃圾收集器 Java的垃圾收集解除了程序员分配存储器的责任,它提供了一种系统级线 程以便跟踪每一存储器的分配情况。在Java虚拟机的空闲周期,垃圾收 集线程检查并释放那些可被释放的存储器。  内存泄漏  垃圾收集线程  垃圾收集调用的方法:java.gc()/java.lang.gc() Java代码的安全性 .Runtime.

sun.com  不同系统平台,JDK不一样,选择适合于自己平台的JDK  JDK的安装  Windows直接安装运行jdk的可执行exe文件  Linux系统将JDK文件压缩包解压后放入opt目录,配置初始化文件的 环境变量  Windows下JDK安装后,会有2个文件夹生成  JDK:java开发工具软件包,它包含了java的编译,调试,运行 整个环境和包含了整个类库的软件包  JRE:java运行环境  JDK.Java语言的特性   字节码的作用  字节码的结构是JVM特定指定的  字节码不会破坏,篡改系统  禁止运行时堆栈溢出 防止蠕虫病毒袭击  参数类型正确  类型转换正确 安装,搭建java开发运行环境  官方网站下载JDK  官方网站:http://java.JRE和JVM .

bat文件;使用对话框(右击我的电脑/属性 /高级/环境变量/系统或用户的环境变量)操作  Unix平台需要分shell:csh $HOME/.profile  环境变量:  JAVA_HOME:保存jdk的安装目录  windows : set JAVA_HOME=c:\programfiles\java\jdk1.连接库文件,编译器等等  编译一个java文件:javac;运行一个字节码文件:java  jre目录:jdk中自带的jre  src压缩文件:放置的是jdk类库的源码文件,按包结构组织的  demo::java代码的演示实例文件  include:用于编译本地方法的文件  docs:html格式的类库文档  lib:类库文件  Java程序开发环境配置  在windows平台:autoexec.安装.cshrc bsh/ksh $HOME/.0_09 . exe文件.5.搭建java开发运行环境  JDK,JRE和JVM  jre是jdk的子集,在一套完整的jdk中就包含了jre  jre只负责运行一个编译好的java程序(字节码文件bytecode)  jdk它可以去编译,调试,运行整个操作过程都支持  在jre内部有一个软件组件jvm就是java虚拟机  JDK的结构简介  bin目录:java开发调试的命令.

class)文件的搜索路径。 设置系统在查找字节码文件时,它的搜索路径。  windows: set CLASSPATH=.5.… Linux:$PATH:…  windows: set PATH=%PATH%.jar.jar  bsh/ksh: CLASSPATH=.5.java public class HelloWorld{ public static void main(String[] args){ String str=―Hello World!‖.jar  PATH:设置命令的搜索路径,在执行命令时,操作系统就会在 PATH设置的路径去查找命令的可执行文件。  设置path不能覆盖原有的,可以使用特殊符号 windows:%PATH%.:$JAVA_HOME/jre/lib/rt. %JAVA_HOME%\jre\lib\rt.:$JAVA_HOME/jre/lib/rt.%JAVA_HOME%\bin. .0_09  CLASSPATH:系统搜索字节码(类文件.  csh: setenv CLASSPATH .Java程序开发环境配置   csh: setenv JAVA_HOME /opt/jdk1.  csh: setenv PATH $PATH:$JAVA_HOME/bin  bsh/ksh: PATH=$PATH:$JAVA_HOME/bin  Linux系统使用bsh/ksh时则需要export JAVA_HOME CLASSPATH PATH 将环境变量设置为全局的 编辑,编译,调试,运行一个java程序  写第一个java程序:HelloWorld..0_09  bsh/ksh: JAVA_HOME=/opt/jdk1.

println(―The String is::”+str).编辑,编译,调试,运行一个java程序 System.otu. 再次编译一下,查看错误提示,必须要会读错误提示  分析错误提示,排除错误是基本的能力 .out. } }  通过这个程序掌握以下概念  一个java源文件中可以定义多个类,但最多只能有一个类用public来修 饰,而且该public修饰的类名要与java源文件名一样。  一个java应用程序应该包含一个主方法,而且主方法的签名是固定不 变的。主方法定义在哪个类中并不做固定安排。  定义的所有的代码中,只看到类的定义。在类中去封装其他变量或方 法。  编译HelloWorld.java程序  开始\运行\cmd进入dos.println(―The String is: "+str).class文件得 出有效结论  编译报错则根据错误提示找出错误位置然后修改程序重新编译  举例来演示学习错误提示 假如将String的S写为小写 :string str=―HelloWorld!".out. System.java命令编译  编译成功后,到day01程序目录下查看,发现有2个.修改当前目录为d:\javacode\day01  使用javac HelloWorld. 假如将out写为out:System.println("MyAge is: "+age).

sun/com.java程序  使用包结构 package com.  编译程序:javac –d .shunshi.day01  使用包后,如何编译  写MySecondJava.java .shunshi这个是软件公司网址的url,可以区分确认哪个公司开 发的软件产品 com.没有包含主方法的类是不能运行的  开始\运行\cmd进入dos.包的命名也有企业规范的如:com.abs.ibm,这样包名不会产生冲突  abs是项目名,model是项目中的模块/子模块名  写MySecondJava. MySecondJava.来隔开每一部分,每一部分都是包结构  com.shunshi.day01.java,使用包声明: package corejava.model  .使用cd d:\javacode\day01进入程序目录  使用 java HelloWorld(包含有主方法的类的类名)来运行  使用java Student就会报告错误提示没有主方法   要求学员做HelloWorld程序并操作演示几种错误情况和调错 带包的java程序  包的声明:package day01 package是关键字 day01是包名  包的概念和含义  包名的命名符合标识符命名规则即可  企业项目开发中.corejava.包的概念,含义和使用  运行HelloWorld程序:  包含有主方法的程序才可以运行.

MySecondJava  如何运行?类加载  演示错误情况的发生  直接使用 java MySecondJava 则报告找不到这个类的定义 的错误提示  为什么找不到?从系统如何去找类来说,与jvm在查找类时 的搜索顺序有关系  直接进入包结构目录cd corejava\day01.day01.JVM搜索类的顺序与类加载  -d选项的作用:   把编译好的字节码放在你指定的目录下,所以需要指定目录  如果源文件声明了包结构,那么在给定的目录位置下会按照 包结构自动创建目录结构,编译好的字节码文件是放在最终 的子目录下  为什么使用包?  企业项目开发中方便管理不同的类  用包来分门别类地组织不同模块功能的类  使用包的好处:举例:航班机票预定项目 JVM搜索类的顺序与类加载  使用包结构编译后,如何运行?  使用java,注意:java corejava.使用java MySecondJava运行,则报告找不到类的定义同时给出错误 原因(找到的类与要运行的类不一致) .

java生成文档注释  在MySecondJava.但可以嵌套单行注释  文档注释 /**注释内容*/ 出现在类的定义,方法的定义,属性的 定义之前,用来说明类的含义,方法的含义,属性的含义  使用javadoc命令给MySecondJava.java中,类前,主方法前写一些文档注释  使用javadoc命令将文件MySecondJava.java .java中的文档注释抽取出 来生成程序文档。javadoc –d .\doc MySecondJava.Java 常用命令   为什么不一致呢?找到的是带包的,运行的是不带包的  CLASSPATH的应用  深刻理解java技术体系  如何使用第三方的java技术 常用命令  javac 选项 源文件名 编译java 源文件  -d  查看javac命令到底有哪些选项,直接使用javac/javac -help命令回车  java 选项 类名 [参数] 运行java程序  jdb 选项 类名 [参数] 进行debug调试的命令  javadoc 选项 包名 源文件名 生成jdk的api形式的程序文档  在java源文件中允许使用文档形式的注释  单行注释 //注释内容  多行注释 /*注释内容*/ 多行注释不能嵌套.

java程序 .class文件打包成一个jar文 件  jar -cvf first.jar .class)给第三个程序 MyThirdJava使用。 写MyThirdJava.Java 常用命令  分析程序文档结构和理解jdk的API文档  jar {ctxu}[vfm0Mi] [jar-file] [manifest-file] [-C directory] files 创建/展开/更 新一个jar文件  jar文件:sun公司定义的一种文件格式,与zip格式相同,可以用普通 的解压缩工具解开。jar文件压缩的一般是java的字节码文件.\corejava 不与源文件放在一起 c 代表创建jar文件 v 是可视化即可以看见创建过程和创建详细清单 f 代表可在后面指定jar文件名  解压生成后jar文件,有corejava和META-INF2个文件夹  jar文件有什么作用? 将开发的类打包jar文件给客户,客户得到后只需要设置classpath后 就可以用了 开发一个中间件,将中间件的程序打包成jar  打包day01.class文件。  创建jar文件: 将d:\corejava\day01中的1个.按照包结 构组织好的.jar(corejava\day01中的.

class移走 将javacode\day01下的MySecondJava.java移走 编译运行MyThirdJava来演示自定义jar文件的使用 思考问题  找不到MySecondJava,没有给包结构名 修改为corejava.类名来引入使用的类  要引入某包下的所有类则 import 包结构名.*.day01.day01.java中自定义一个String class String{}则会报错 与JVM搜索类的顺序有关,先搜索当前包下的String,它无构造方法  简便引入某包下的类  直接使用包名+类名的形式,程序太烦琐了  在程序的开头使用import 包结构名.jar路径给CLASSPATH,也不需要使用包结 构名+类名 因为它是lang包下的类  若在MyThirdJava.      .MySecondJava().  String的使用不需要rt.Jar文件和import的使用 将day01.MySecondJava msj=new corejava.jar路径设置给CLASSPATH 将day01包下的MySecondJava.

awt/javax.awt.net:用来做网络开发的类和接口  java.util:java工具包,包含java开发常用的工具类, java的时间日期,java的数据结构,随机数发生等。 .event:做java的图形开 发使用的包,包含有图形组件,用来构建和管理应用 程序的图形用户界面。  java.io:包含了java所有做输入输出的类和接口,包含 处理I/O文件的类  java.JDK的常用包  java.applet:用来开发java小程序的类和接口,包含了 可执行applet特殊行为的类。  java.swing/java.lang:JAVA语言包,核心的类和接口,无需导入 可直接使用。如String、Math、Integer和Thread。  java.

Day02     知道java的特殊符号 熟悉java的标识符 掌握java的关键字的使用 理解java各数据类型的存储和使用  原始数据类型  基本数据类型的转换  定义类,对象,成员变量和引用变量  类的声明  类变量与类成员变量  创建类的对象实例和使用默认值  描述引用变量与类对象的关系  掌握表达式和运算符的使用 .

java.Java中的特殊符号  注释  单行注释://  多行注释:/*….执行后,会在当前目录 下生成一个doc目录,里面文件就可查看注释了。  其他符号  .*/ 这两种注释只能通过打开源文件来查看,写程序一定 要写注释。注释与程序应是2:1  多行注释:/**……*/ 这个注释可以不打开源文件来查看,java中有一个 javadoc工具,它的作用是将源文件中的/**. Hello.*/注释单独抽 出来放在另一个文件中。 例如: javadoc –d .回车.. 一个语句的结束  { } 一个语句块  空白字符 空格,tab..换行等 .

A# ×.顺时 √  Java开发的命名习惯  所有的命名要望文生义,这样才具有良好的可读性  Total,Sum,ShunshiStudent,  类名,接口名:每个单词的首字母大写,其他字母小写 如类MyFirstJava, Player,Teacher  属性,方法.字母开头; 只含有_.$. 没有长度限制,不能有空格; 不能使用java的关键字或保留字 大小写敏感 例如:_abc √.shunshi. $ABC √.,局部变量名:第一个单词全小写,从第二个单词开始以后每 个单词首字母大写,其他字母小写 如方法 getName() setDoctorBirthday()  常量:每个单词所有字母全部大写,单词之间用_来连接 java中使用final 修饰 final int MARK_GREED=22.2A ×.corejava.Java标识符  标识符:程序中的组件名字,包括类名,方法的参数名,变量名,方法名,包 名等  定义标识符的规则: 以_ .For√.字母,数字.  包名:所有字母全部小写 如package com.$.day01 .

 Java关键字 关键字:对Java技术编译器有特殊的含义,可以被编译器识别执行  abstract do implements private throw boolean double import protected  throws  break else instanceof public transient byte extends int return true  case false interface short try catch final long static void  char finally native super volatile class float new switch while  continue for null synchronized default if package this Java关键字特点  java关键字与c++很多相似,只要与c++一样的,它的含义都与c++中的相 同  有些关键字c++有,而java没有  sizeof求出某种类型的变量的占内存的大小  为什么c++有sizeof?  因为不同机器内存占用空间大小不一样 16,32,64位,取决于操 作系统平台。  为什么Java不需要?  因为有JVM。  java中的关键字都是小写的  true、false和null为小写,而不是象在C++语言中那样为大写。 严格地讲,它们不是关键字。 .

Java关键字  有些关键字java没有取消保留下来,但它自己也不用它也不给程序员用      goto和const不是Java编程语言中使用的关键字,而是保留字。 什么是保留字? 为什么保留下来但不能用? 在java中final替代const goto在c++代表无条件跳转,功能很好,但不能经常用,要谨慎。  很多建议去掉goto关键字,没有理解goto真正含义。  为什么c++到现在都没有删除掉goto?它有一个特殊使命  Java中使用break代替goto  跳出一层循环 :break  跳出多层循环:break out out是一个标号,可以跳到out标识处  break避免滥用goto,把goto功能削弱了,只能跳到外层循环  java中加入新的关键字enum assert  enum:枚举  assert:断言 .

Java的原始数据类型         boolean true/false byte 8位整型 1个字节 short 16位整型 2个字节 int 32位整型 4个字节 long 64位整型 8个字节 char 16位 unicode 字符 2个字节 double 64位浮点数字型 8个字节 float 32位浮点数字型 4个字节 .

0代表false.非0代表true  boolean与int通用好还是不好呢?不好  举例说明 c++中的boolean与int通用  int a=1.  Java中的boolean类型的取值只能是true.  if(0<a<2) cout<<a<<endl.false  Java中的boolean类型不能与int通用,而在c++中可以  C++中. .boolean类型  Java中定义boolean类型  boolean b=true.

int.short. Integer 数据类型— byte.long Java中的4种整型类型 byte: 1个字节 –128(-27)-127(27-1) Integer short: 2个字节 –32768(-215)-32767(215-1) int: 4个字节 –2147483648 (-231) -2147483647 (-231-1) long: 8个字节 –263-263-1 Java的不同整型占用内存空间的大小不一样  Java中整型的存储规则与c++一样, 但java整型没有无符号和有符号的区分,这 与c++不一样。Java中所有整型都是有符号的,这样就可以求出每个整型能表示的 范围。 以byte为例说明 Byte是8位整型 1个字节 最多可表示28=256个数 从(-27)-128到127(27-1) 为什么是-128-127而不是-127-128呢?与整型数据在内存的存储规则有关 整型数据在内存空间中的存储方式 正整数(最高位为0)在内存中是存储原码 负整数(最高位为1)在内存中是存储其补码 补码是不考虑符号情况下 原码取反后末位加1。以-5来分析补码 分析一些特殊数字:8位全为1则是数字-1,8位全为0则是数字0 不考虑符号位最大的数是01111111表示数字127,最小的数10000000表示数字-128  .

 boolean bl1=false.√  byte e=2. if(bl1==false) System.  boolean bl2=true.√ short s2=40000.√  Long la=1234567l.×//超出范围  写TestIntBool.Integer 数据类型在内存的存储方式    为什么用补码存储负数?方便二进制计算,例如-128+127=-1 其他类型的整型在内存的存储方式与byte相同,只是空间更大。其他类型的整型 表示数的范围如前面 整型数据表示  long类型使用 l或L来表示  int的不同进制:十六进制用0x或H表示 8进制用0或O表示 10进制用D或 10表示  默认类型为int 整型定义  short s1=10000.out.java程序  byte a=1.√  int ia=0x2aff. System.× 超出范围  long l=40000L.× e+=2.println(bl2). if(bl2==1) System.out. byte bb=(byte)ia. b=2. √//十六进制  int ib=011. byte c=a+b.√  int ia=0x55.e=e+2.println(bl1).× int d=a+b.out. .println(bb).√//8进制  byte bb=0x771.

√ char uchar1=‗\u61‘.√ char enchar1=97.char数据类型 char类型  char 字符型为16位, 2个字节,与c++不一样.采用的是unicode编码 ,unicode编码是统一编码,可包含字母,数字,符号,中文文字等  unicode码是采用16进制表示的 如‘\u0061‘  2个字节的unicode编码可以表示216个字符,字符使用单引号‘’来表示  127个ASCII码全可表示 英文字符,控制字符,数字,标点符  表示其他语言的字符:中文,德语,法语,阿拉伯等  一个char类型本质上是一个整型  char与short都是16位的,他们的差别?  通过查询unicode编码集可以获取一个整型值对应的unicode字符  unicode编码集包含了ASCII码集的  在0-127内unicode编码值与ASCII码值一样,表示的字符也一样  常见的ASCII码值 :A:65 a:97 0:48  通过unicode码得到码值可以将16进制转换为10进制 char zhchar=‗中’.√在java中, int 与char 是可以互相转换的  char ucchar=‗\u0061‘.java .√ char enchar=‗a‘.×因为unicode是16进制的, 2个字节则需要16位,需要4个16进制数 下面写一组char与int的定义,TestChar.

println(ia+ib+s1). int ib=4.  char charAt(int):返回参数int指示位置上的字符  System.println(str1.  String可做什么操作  使用+号来连接字符串  String s1=―12‖. String str2=new String(― World!‖).  String concat(String):将当前String与参数String连接起来返回新串  System.concat(str2)).  System.out.out.println(s1+ia+ib). int ia=3. System.out. .println(str1.String类型简介  Java中的转义字符   \‘ :‘ 单引号 \‖ : “双引号 \\ :\顺斜杠 \n:换行 \t:tab制表 符  \b:退格 \0:‘\u0000‘ unicode码值为0的空字符 String类型  String类型:字符串类型,它不是java的8种基本类型,是类的类型  String是java的一个类,这个类的实例叫做String对象  Java中字符串用””双引号来引用  Java中的字符串类不是以‘\0‘结尾  String类是Java中使用最多的类,它有很多有用的方法,查看jdk的api文档  获得String类的对象变量  String str1=―Hello‖.out.charAt(0)).

out.out.String类型简介  boolean contains(charSequence s):判断一个字符串中是否包含参数的 子串  String str3=―Hello World!‖.out. System. System.不忽略大小写  String s2=―Hello‖.println(s4.java,演示上面String的功能 .equals(s3)).println(str3.  写TestString. String s3=―Hello‖.out.  boolean equalsIgnoreCase(String):比较2个字符串内容是否相等,忽略 大小写  String s4=―heLLo‖. System.indexOf(‗o‘)).  boolean equals(String):比较2个字符串内容是否相等.contains(str1)).equals(s3)). System.println(str3.println(str3.println(str3.  length():获得字符串的长度  System.out.println(s2.equalsIgnoreCase(s3)).length()).indexOf(―Wor‖)).out.  int indexOf(String/char):获得参数字符/字符串在改字符串中的第一次出 现的位置索引,假如找不到则返回-1  System.out.println(s4. System.

0.45e301.out.println(d).4.浮点型数据类型    浮点数据类型:2种  float:单精度,32位 4个字节 使用f或者F表示  double:双精度 64位 8个字节 默认类型 使用d或者D表示 浮点数举例  float fa=123. double dc=123.b=1.out.5E301.c=0.91.0.println(―ok‖).√ float fb=123. √  double da=123D.0/0.5E300F.456d.√ float fd=(float)12.× 默认是double double直接赋给float精 度丢失  float fc=12. System. double db=123. 浮点数据类型的存储方式  整型存储方式是精确存储  浮点存储方式是近似存储:实数范围太大了,实数太多了,无法在内存中 对应每一个实数的状态  浮点数的近似存储在程序中的问题:写TestFloat.  结果输出”on ok‖。实型数值直接比较相等不安全,不要直接比较相 等,但可以比较大小。 .else System.编译正确  double a=2.pringln(―no ok‖).4f.out.java  实型值分母可为0,double d=0.09.  if(a-b==c) System.

sin().sqrt(9)  Math.tan().  Math类  lang包下的类,它里面定义了很多方法来实现常用的数学运算  Math类中的方法都是静态的  Math类中的方法:  abs():求绝对值     sqrt():求平方根 pow():求乘方 cos().abs(-5)  Math.random()*100:获得0-100之间的随机数 .println(―ok‖).pow(2.浮点型数据类型  假如一定想要2个实型数值比较是否相等,可以考虑比较2个实型数的 差是否在一个非常小的范围内  想要输出“ok‖,则if(Math.ctan():数学的三角函数运算 random():获得0-1之间的随机数  在TestFloat.3)  Math.out.java中测试使用Math类中的方法  Math.abs(a-b-c)<(1e-6)) System.

b为-1  强制转换的原理:从最低位开始取到目标类型长度为止  整型之间的强转是保留二进制低位,去掉高位,需要考虑在内存中 如何存储  实型强转整型是保留整数,去掉小数,不考虑实型在内存中的如何 存储  写一个DataTypeTest.数据类型之间的转换  数据类型之间的转换分为2种  自动类型转换  a类型转换为b类型时,a的取值范围是b的取值范围的完全子集 这就是自 动类型转换  在java的8种基本类型中,除boolean以外,其他7种类型都是可以相互转 换的。  7种原始类型之间可自动转换结构图  byte→short→int→long→float→double char  顺着箭头方向可自动转换;逆着箭头方向则是强制转换  强制类型转换:只要不能自动转换的,则只能是强制转换  整型数据之间的强转:改变数据的符号;改变数值  int a=0x2aff. byte b=(byte)a.java程序演示数据类型转换 .

println(5/2).out.out. int iic=c1.out.  char c2=99.byte a3=a1+a2.56f.System.  默认整型为int. System.out.  char与int的转换  char c1=‗A‘.println(ff).out.System. System. double de=fe.  System.println(ia).out.int,long提升为float有精度丢失  float fa=37. System.println(b).  long lb=(long)fb.println(de). System.out. System.a2=2.println(fa).System. c=c+3.out.println(c2).  float转换为double会有精度丢失  float fe=1234. System.println(lb).println((float)5/2). System.println(fb).println(iic).out.out. byte b=(byte)a.out.  long la=0xffffffffffL.  float ff=(float)de.数据类型之间的转换  byte+byte会自动提升为int  byte a1=1. c+=3. .println(c).  int ia=(int)fa.  整型之间的强转  int a=0x2aff.out.×(精度丢失)  +=不进行类型提升  byte c=3.  整型除法  System.float fb=la.

要记录 两个生日. int yourBirthDay. year. yourBirthMonth. 则要使用 int myBirthDay. myBirthYear. myBirthMonth. month.Java中的特殊类型——对象  为什么会有对象?  早些时候的编程语言和初级程序员将每个变量看作相互无关的实体。例如, 如 果 一 个 程 序 需 处 理 某 个 日 期 , 则 要 声 明 三 个 单 独 的 整 数 : int day.  尽管这种作法很容易理解,但它存在两个重大缺陷  名称太多,会引起混乱  忽略了各个变量之间的联系  例如:若程序需同时记录几个日期,则需要三个不同的声明. 忽视了日、月和年之间的联系并把每个变量都作为一个独立的值,每 个变量都是一个独立单元(在本例中为date)的一部分并被相应地处理 Java的对象类型  为克服上述两种缺陷,Java编程语言使用类来表示这种新类型  Java除了8中基本类型,还有一种类类型或者叫做对象类型(或是一个类,或 是一个接口)  Java的类类型不是表达一个简单的数据,而是表达一个较复杂的数据(复合数 据)   . yourBirthYear.

private int age. } . this. private boolean sex.int age. this.boolean sex. private String major. public Student(String name.sex=sex.sex=sex.Java中的特殊类型——对象  例如:描述一个学生,定义一个学生类,它包含学生的相关信息:姓名,性 别,年龄,专业  创建一个学生类 class Student{ private String name.age=age. this. } public void setSex(boolean sex){ this.major=major. } public void setName(String name){ this.String major){ this.year=year.name=name.

age.float等一样可以用来定义变量 例如:Student stu.Java中的特殊类型——对象 public void setAge(int age){ this. } public String getMajor(){ return major. } public String getName(){ return name.major称为stu的成员变 .sex.major也都隐含声明了,name.age=age. } public void setMajor(String major){ this.major=major. } } Student就是一个新的类型,就像int. } public boolean getSex(){ return sex. 声明一个Student的变量stu,则它里面的 name.sex. } public int getAge(){ return age.age.

Java中的特殊类型——对象  类类型/对象类型的数据的存储方式与基本类型数据存储方式的差别  类型创建一个Student对象:  Student stu.‖computer‖). float y=9.22.9f.x=7.true. x=7. 基本类型声明变量时就已经创建了变量并分配空间,无论它是 否已经赋值,赋值只是将值放入已分配的空间  Student stu. stu=new Student(―LiDW‘.时,在内存空间也给stu分配了空间。  那分配了多少空间?Student中所有成员变量的空间大小和吗?  不是取决于Student的大小,与Student的大小无关  那stu是什么?在java中把stu叫做引用,这个引用与c++中的引用完全不一 样  Java中的引用与c++的指针相似,java中没有指针,只有引用,它保存的 也是一个地址值(内存空间中的Student对象的地址)  Java中的引用与c++的指针有差别  C++中指针可被程序员操作:int* p. p++.--等操作,所以java语言更安全。 .  把类看作一个类型的话,它的使用其实和基本类型int等一样,只不过赋值是 赋的一个复杂的复合类型数据,是new出的对象  存储形式的差别  int x.p--.  原始类型的声明 int x.对象类型声明Student stu.*p等等,所以很危险, 不安全  Java中不允许程序员对引用做操作,只能通过引用访问对象,但不能 对引用进行++.

 Student stu2=stu1.true.22.‖computer‖).stu1保存的是相同的地址值,stu2.stu1指向同一个对象  通过stu1修改了对象Student的数据值后,通过stu2访问的对象也 就改了 .Java中的特殊类型——对象  Java的引用需要多少个字节呢?  引用无论什么类型都保存的是内存中的地址值  地址值常见的是4个字节,相对来讲很固定的值  地址值的长度严格来讲也取决于不同的机器平台,由机器的寻址空间 决定的。例如常用的是32位机器,所以4个字节  那么stu=new Student(―LiWD‖.  stu2.true.‖computer‖)又干什么?  在内存空间中又开辟了一个区域专门用来保存该Student对象的数据  赋值语句将开辟的对象空间的地址赋给stu,stu就指向这个对象 综上所述,对象类型的存储方式即需要两个空间:引用空间,对象空间  Java中的对象与引用的关系:可以打个比方来看看  对象可以看作是充满氢气的气球,气球中的空气就是对象中的数据,气球 我们无法直接拿到  任何时候我们拿到气球都必须通过连接它的一根绳子,这跟绳子就可以看 作是引用  深入理解对象与引用的关系  同一个气球可不可以有多根绳子连着它?可以 就像双胞胎牵同一个 气球  Student stu1=new Student(―LiWD‖.22.

Java中的特殊类型——对象  可不可能一根绳子同时栓着多个气球?不能  如果一根绳子没有连任何气球,那么对于这个引用的访问有意义吗? 没有意义  Student stu3=null.‖computer‖).lang. stu4=null.System.22.gc()来告诉JVM做垃圾回收。程序员建议后,也 不一定就回收。 .定义了一个空引用,没有指向任何对象  假如使用stu3去访问name.  Java的垃圾回收机制  Java不让程序员管理内存  一个系统级线程专门扫描内存,回收垃圾  垃圾回收是自动进行的,程序员可以建议但不能控制,程序员调用 java.age等会报告空指针异常 NullPointerException  如果某一个气球没有任何绳子栓着,那它怎么办?飞走了  这个气球就无法访问了,变成垃圾。(垃圾占用空间,但我们 无法访问)  Student stu4=new Student(―LiWD‖.true.

对象彼此联系.Java中的特殊类型——对象  一般java.对象有属性.对象有方法 There are students and a teacher in classroom .gc()语句放在前面程序已释放了很多垃圾后,  则调用该语句执行的可能性大  Java的垃圾回收并不是马上回收,jvm有一套算法来确定什么时候进 行垃圾回收  Java垃圾回收与c++内存释放的比较差异:打个比方  C++内存释放:相当于学校食堂吃饭,吃饭后要将餐盘送到回收处, 若你不做则大家会鄙视你。若大家都不做,则长时间就没有餐盘了。  Java垃圾回收:相当于餐馆中吃饭,吃完了,只结帐就走了。餐馆 自然有人来回收。无需自己把餐盘送到后台。 理解对象  对象无处不在.System.lang.

× 比较运算符  >,>=,<,<=./.instanceof(比较类型),= =,!=  Java的数据类型中哪些是可用比较运算符来连接的 > >= < <= instanceof 布尔型 != √ √ 整型 √ √ √ √ √ √ 实型 √ √ √ √ √ √ √ √ 对象类型  == 算术运算符  +.√ b1=b1+2.*.Java的运算符   赋值运算符:一个简单的赋值=和11个复合赋值  =,*=,/=,%=,+=,-=,<<=(左移位),>>=(右移位),>>>=,&=(按位与), ^=(按位异或),|=(按位或)  复合赋值运算不会产生自动类型的提升 byte b1=2. b1+=2.%  5/2, (float)5/2 √ .-.

out. -10 System. int b=0x7332.out. 10  int in2=-20.out.左移一位等于乘2),>>>(无符号右移)  有符号的右移:则移走后最左边高位填补为原来的符号位  有符号的左移:则移出去的不管,移进来用0来填补  无符号右移:则移出去的不管,移进来都用0填补  int a=68.println(in1>>>1). a&b a|b a^b  位运算符什么时候用?用来干什么?  例:int a=0x8a3d. 很大的数 位运算符  &(按位与),|(按位或),~(按位求反),^(按位异或)  例: int a=0x5a2b.out.System.Java的运算符   移位运算符  所有的移位运算只能针对整型数据操作  >>(右移.println(in1>>1).println(a). . System. 超出了范围,移出后全为0?实 际上不是这样的。a<<34等价于a<<(34%32)  int in1=20. 10 System.System. a=a<<34.println(in2>>>1).println(in2>>1).右移一位等于除2),<<(左移.out.

 操作数只能是布尔表达式  在java中, &,|也代表逻辑与,逻辑或。与c++不一样  C++中位运算符是不能做逻辑运算的,因为c++中的布尔型与整型可以 通用,那么无法判断&,|两边到底是什么类型数据  在java中. !false=true. &,|是位运算符又代表逻辑运算那如何区分呢?  判断运算符两边是否是布尔表达式,布尔值,关系表达式;若是则代表 逻辑运算;若是整数则代表位运算       .Java的运算符 想要a高8位不变,低8位全变0 a&0xff00 想要a高8位不变,低8为全变1 a|0x00ff 想要a高8位不变,低8位求反 a^0x00ff 想要a高8位求反,低8位全为0 (a^0xff00)&0xff00 想要a的1,3,5,7位取反,2,4,6,8位不变  01010101值为85 所以 a^85 逻辑运算符  && 两边的布尔表达式都为true则结果才为true  || 两边的布尔表达式只要有一个为true则结果为true  ! 对布尔表达式结果取反 !true=false.

println(in3). if((2>3)&&((in3=2)>3)) System.  if((2>3) & ((in3=2)>3)) System.out.Java的运算符  &&.out.||与&.println(in3). .三目运算符. 条件运算符:布尔表达式? 真:..|的区别  && ,||支持短路运算  &&: 若左边的运算结果为假,则右边不做运算了 ||:若左  边的运算结果为真,则右边不做运算了  &,|不支持短路运算:运算符两边都要运算  int in3=1.

Java的运算符  运算符的优先级  运算符时很重要的问题就是运算符的优先级  一个表达式有多个运算符,若不清楚优先级则最好使用括号() .

Day03             知道java的变量的声明和常量声明 理解java中变量和常量的特点及其使用方法 掌握java中局部变量的特点和作用域 理解重合范围的局部变量和局部变量的使用 掌握函数的作用和函数声明 掌握调用函数和函数参数的传递 知道如何使用命令行参数 理解java中函数的重载和重载条件 理解控制语句的工作流程 理解循环结构设计和边界问题处理 理解java中数组的存储方式 掌握java中数组的使用 .

065√ 0895×  十六进制以0x或0X开头,由0-9. Java的常量 Java中的常量  什么是常量  常量是程序里持续不变的值,也称为字面量,是不能改变的数据  常量的分类  整型常量,浮点型常量,字符型常量,字符串型常量,布尔型常量.022e+23f √,6.4√ 023×  八进制以0开头,由0-7数字组成.3.453.4f.空 值常量null  整型常量:分为byte,int,short,long,可用用十进制,八进制,十 六进制来表示  十进制不能以0开头, 由0-9的数字组成,如223.84d.‘\t‘.如023.‘\u0027‘.6D  布尔型常量:true,false  字符型常量:由英文字母,数字,转义序列,特殊字符等字符表示  它的值就是字符本身,字符常量由‘’括起来表示  java中的字符占2个字节,由unicode码表示的,也可以以\u开头的 unicode码表示字符。如 ‘a‘.0f..final char c=‘2‘.99L;整型默认类型为int  浮点类型常量:分为float(32位)和double(64位)型  float:以f或F结束.√.如 2ef.A-F组成,如0xff.‘dd‘× .5.7e+34×  double:以d或D结束.0X97a√ 0xeg9× 长整型则以L结束,如0xffL.如3.

‖33‖. Java中的变量  什么是变量  系统为程序分配的内存单元,存储数据的,用一个标识符来表示,其中 的数据值是可以改变的,所以叫变量  变量名与变量值 X0Y3  定义变量的标识符叫变量名  内存所装载的数据值叫变量值 0+3=3 例如 int x=0.解释其在内存中的实现原理  变量的类型  八种基本类型:boolean,byte,short,int,long,char,float,double  对象类型:类,接口,数组  不同类型变量的取值范围:变量的使用特别要注意的就是数据长度。   .Java中的变量  字符串常量:由双引号“”括起来表示。.y. y=x+3. final 类型 常量名=常量值.如“hello‖.‖\t\u0024‖  空值常量:null表示空值。 常量的声明: final 类型 常量名.

Java的变量 .

//程序会将b的结果自动转换为int型  强制类型转换:显示类型  转换当两种类型不一致,不兼容  目标类型的取值范围小于源类型时则就需要进行强制转换  转换方法:目标类型 变量=(目标类型)值  例:int x.Java的变量   基本类型变量之间的数据转换  自动类型转换:也叫隐式类型转换  转换的两种类型之间要兼容  目标类型的取值范围要大于源类型  如例:byte b=3.  强制转换是将x的值转换后赋给b,而变量x本身的类型不变  强制转换会丢失数据 表达式的数据类型自动提升  表达式在计算值时也会自动进行数据类型提升 . byte b=(byte)x. int t=b.

Java的变量   变量的声明:类型 变量名; 类型 变量名=变量值.. …. }  作用域:变量的作用域是从定义变量开始一直到定义它的代码块结束。 作用域决定了变量的可见性和存在时长 局部变量   代码块的使用:一个代码块由若干个语句组成,一个代码块可嵌套在 另一个代码块  例 :{int t. {int m … } } . 变量的作用域  代码块:在程序中一对花括号{}之间部分为代码块  代码块的作用:代码块决定了在其中定义变量的作用域  例 :{int t.. ….

局部变量的使用 什么是局部变量  定义在方法中的变量  局部变量与实例变量的特点  局部变量的初始化:通过TestLocal.语句已经在定义int a.println(a).java来演示重合范围的局 部变量的使用  在同一重合范围中不允许有2个局部变量同名  Java局部变量的使用  局部变量必须先赋值再使用  局部变量的作用域是从定义它开始到定义它的代码块结束  在同一重合范围内不允许有2个同名局部变量出现  .out.0 boolean false 对象类型 null  在主方法中使用实例变量/类变量则必须将其声明为static  局部变量的作用域 :通过TestLocal1.0 double 0.java来演示局部变量的初始化  java中局部变量没有初始化则不能使用;局部变量必须先赋值 再使用。  实例变量/类变量支持不初始化就可以使用;  实例变量/类变量若不初始化,则系统会自动初始化。初始化的值 取决于它的类型:int 0 char ‗\0‘ float 0.的块外  ;表示一个语句结束,{}表示语句块  重合范围的局部变量的使用:修改TestLocal1.java来演示作用域  局部变量的作用域是从开始定义该变量到定义它的代码块结束,在 作用域外使用它是不允许的。  System.

java  不用函数,则对于只是矩形的高和宽不一样的矩形也需要重复写很多 相同功能的代码。程序复杂,繁琐。 使用函数:写PrintRectangle1.Java中的函数  函数      什么是函数:能完成一定功能的独立的子程序,在java中这个子程序就称 为函数。 使用函数的好处:使程序模块化,简单化;程序结构清晰,任务单一,程 序清晰易懂,易读,易维护。 函数举例:用*实现打印三个不同长和宽的矩形  不使用函数:写PrintRectangle.int y)  对于调用者而言,只关心函数的声明即可 分析函数  printRect中的代码段称为函数体  代码段需要一个名字标记,该标记称为函数名.java  对于相同功能的代码,将其独立出来写成一个函数printRect(int x.如printRect  函数名和函数体共同构成了函数  printRect函数接受了两个数,一个是矩形高,一个是矩形宽;这两个 数称为参数列表 .

参数类型 形参变量2…. }  不需要返回任何东西的函数,其返回类型为void  函数调用  如果函数无返回值或调用者不关心返回值:函数名(参数1,参数2…)..println(函数名(参数1.).  在程序中直接打印返回值: System.){ 函数体…… return 返回值..参数2.  如果调用者需要返回值:类型 变量=函数名(参数1.参数2.java程序来演示变量和函数的应用  本程序要来实现从键盘输入2个整数,将他们进行相加后返回结果和  变量和函数使用的规则  在static方法中只能访问static类变量,只能调用static的函数  在类的多个方法使用同一变量,那么这个变量要定义在类中且在任何方 法之外,这样的变量叫类变量或实例变量 .)).…. java中变量和函数的应用  通过写一个TestArgument.Java中的函数  有时函数还需要返回一个结果,比如CRS民航订票系统,计算机票价格  函数的声明定义:一个函数的定义由三部分组成:返回类型,函数名,参 数列表  返回类型 函数名(参数类型 形参变量1.out.

b就是命令行参数,  主方法的参数String[] args就是用来接收命令行参数的  Java中的命令行参数是不包括命令名.parseInt(String)方法来转化 . args[0]就是指的第一个参 数  命令行参数接收后都是字符串的,若想要得到相应类型的数字则 需要使用包装类的方法来转化。如整型数据 int则使用 Integer.类名 a b回车,其中a.Java中的命令行参数的使用  Java中主方法main()是程序入口.程序从主方法开始执行  在非static方法中可以使用static变量,非static变量  Java的命令行参数的使用  什么是命令行参数  位于java 命令行最后的信息  如 运行 java 包名.

函数的参数传递 函数的参数传递原理 函数的重载 什么是函数重载: 在同一个类中允许同时存在多个名字相同的方法或函数,只要它们的参数 类型和参数个数等不同,这样的情况就叫函数重载(overloaded)。 函数重载的条件:一定要参数列表不同,函数名相同,但返回值没有条件要求 .

函数的重载  函数的重载   参数类型不同  参数个数不同  参数的顺序不同 举例说明:写OverLoad.java来实现函数重载,本程序的功能就是求两个数 的和,两个数的可以是基本类型中所有的数字类型  若是三个数求和呢? .

执行语句块1. } } 真 条件1 语句块1 假 真 条件2 语句块2 假 条件n 真 语句块3 . } if(布尔表达式){ 真 }else if(…){ 语句块2 假 条件 真 语句块1 执行语句块. Java的流程控制语句 程序的流程控制  从结构化设计角度来看,我们的程序结构分为三种:顺序结构,选择结 构,循环结构  顺序结构:程序从上到下一行一行执行,中间没有任何跳转或判断,直 到程序结束 if(布尔表达式){ 选择结构: 执行语句块. }… }else { 执行语句块2. else{ 执行语句块. if(布尔表达式){ 执行语句块; 条件 语句块 }else if(布尔表达式){ 执行语句块.

middle) 写TestSwitch. case 取值n: 执行语句块2 break.short.char.exit(0).println(d)  选择结构 switch(变量/表达式){ case 取值1: 执行语句块1 break.else的使用  if(a>b)  if(c>b) d=10. 真 case1 假 真 case2 假 真 casen 假 真 defaultn 语句块1 语句块2 语句块n 语句块 .Java的流程控制语句  写TestIfElse.case后面的常量/常量表达式 值必须是唯一的,不能相同.  else d=20.java,并分析程序和if.  System.枚举类型中任意一种 •无论有多少case.top.int. } •switch的括号中变量或表达是值只能是 byte.java来演示,已 知学生课程成绩(百分制), 将其转化为等级值。规定90 以上为A,80-89为B,70-79 为C,60-69为D,60以下为E (注意无效数据的检查;演示 不用break语句带来的后果) 当检查出了无效数据则需要 退出当前程序线程调用 System. ……. •每个case中都要写break来跳出分支 •default分支可放在任何一个分支前后 (end . default: 执行语句块2 break.out.

i<=10.i++),第一部分:初始化语句;第二部分:循环条 件;第三部分:修改表达式  第一部分只执行一次  第二,三部分,循环体会循环执行 直到循环条件不满足跳出循环  while循环 while(布尔表达式){ 假 条件 循环体语句. }while(布尔表达式) 循环体 真 条件 假 . Java的流程控制语句 程序的流程控制  练习:使用switch实现打印星期的程序.测试不加break语句的执行结果  循环结构  for循环  for循环的括号中无论多么复杂则必定有2个分号,将其分为三个部分  如for(int i=0. 真 } 循环体  先判断条件是否满足,满足则执行循环体,再判断条件,满足再执行 循环体,直到判断条件不满足则跳出循环  do-while循环 do{ 循环体语句.

Java的流程控制语句  先执行一次循环体,再判断条件是否满足,满足则再执行循环体,  否则跳出循环 程序的流程控制  3种循环结构如何选择,要考虑几个因素  首先分析业务问题是否是用循环来实现  分析业务问题判断我们是否已经预先知道循环次数  如果预先知道循环次数:用for循环  如果预先不知道次数:用while循环  若至少要执行一次循环:用do.直到输入的信息的首字符不是数字 .while循环  3种不同的循环结构其实可以相互转化,按照上面的规则来选择可以简 化编程  举例来说明如何选择不同结构的循环  求 1-1/3+1/5-1/7+1/9-1/11+……的前50项的和  选择循环,知道循环次数50则选用for循环  求1-1/3+1/5-1/7+1/9-1/11+……+1/n.. 直到|1/n|满足<1e-5的和  选择循环,不知道次数则选用while循环  分析循环体设计问题和循环的边界问题  实现一个程序对输入的姓名进行循环判断,如果首字符是数字则要 求重新输入.

if (number<=0){ System.则可以到170! 所以写一个程序要考虑:数据类型的范围. Scanner sc=new Scanner(System.util.  课堂练习:通过键盘输入一个参数为整数n.Scanner Scanner sc=new Scanner(System.输入参数的合理性 public class TestFact{ public static void main(String[] args){ int number=0. } double result=1.exit(0).println("Error!"). 测试: 若输出int.next().则只能到20!.Java的流程控制语句  java. } System.nextInt() sSc.in).println(―请输入一个整数:”); number=sc. System.nextLine().out.in).i++){ result*=i.则只能到15!.nextDouble().out. 若输出为long. for(int i=1.nextInt(). sc.println(number+"!="+result).out.输出该整数的阶乘值. System.i<=number. }} .注释添加. 若输出为float则只能到34! 若输出为double.

跳出out指示的那一层循环的当次循环,进入那一层循环的下 次循环  break.Java的流程控制语句  程序流程控制语句  break .j++){  for(int k=0.语句:跳出其所在的循环  break out.  }}}}  } . 跳出out指示的那一层循环  continue.m<k.i++){  for(int j=0.i<=9.  break out.m++){  if(i+k+j+m==24){  System.java演示break out的使用  public static void main(String[] args){  out:for(int i=1.k++){  for(int m=0.j<i.k<j.continue加标号的怎么用?什么时候用?即各个控制结构语句是可以 嵌套的  写TestBreak.println(i*1000+j*100+k*10+m).out. 跳出当次循环的剩余部分,直接进入下一次循环  continue out.

length.//会输出0表示,整型数组没有初始化时 系统默认会给它赋值为0  } System.println().0  char:‘\u0000‘,boolean:false .out.java来打印数组元素和测试数组的初始化  for(int i=0.i<a.a--操作  a.i++){//使用length可通用化,因为数组大小有可能 发生变化  System.Java的数组   java的数组  在内存中是连续空间  数组用来一次定义相同类型的多个变量  数组也是一个对象,可以有属性,但没有方法的  如 一维数组:int[] a.print(a[i]+‖ ‖).length的值是数组的长度,length是数组的属性 数组的初始化  写TestArray.才会分配空间。  数组名a是一个地址,是数组的引用,但绝不能执行a++.  其他基本类型的数组没有初始化则系统也会赋值为相应类型的默认值  Long:0L,float:0.0f,double:0. 声明一个数组变量,可以不给数组长度,此时还不会 给数组分配空间。当a=new int[10].out.

5}.8. .1.24.32}.0.  数组的显示初始化:写入TestArray.System. } int[] a=new int[10].7.length.1}.6.√在定义数组a时就分配空间并初始化  int[] b=new int[]{4.√ 第二个[]中间必须为空,后面才能用{}来 初始化;这里产生了2个对象(数组对象,数组名引用)  int[] b1=new int[4]{8.out.//定义一个数组 a=new int[10].54.//为数组分配空间 for(int i=0.i<a.print(str[i]+‖ ‖).println("a["+i+"]="+a[i]).4.Java的数组  对象类型的数组没有初始化则系统默认会赋值为null  String[] str=new String[10].3.i++){ System.out.java中测试  int[] a={3.×第二个[]中间有值则后面不能使用{}来 初始化  public class TestArray1{        public static void main(String[] args){ int[] a.98.

print(a).//显式初始化 for(int i=0.7.i++){ System.Java的数组      int[] a={1.out.out.println().2.out.8}.print(m[i]+"\t").i++){ System.length.2.6}.9}.6.println("a["+i+"]="+a[i]). } System. } static void print(int[] m){ for(int i=0.3.i<a.i<m.4.//error!            int[] a={2.6.7.5.5.4. } //int[] b=new int[10]{3.4.length. } .

n.  }   } .java来演示实现数组的增长  Static int[] expand(int[] m){  int[] n=new int[m.0.  return n.m.  for(int j=0.j++){  n[j]=m[j]. }  }  static int[] expand(int[] m){  int[] n=new int[m.  System.length*2].length).Java的数组  数组的增长原理  Java中数组是一个类,它的增长原理:重新分配空间,将原来的数 组数据拷贝到新空间中,并让数组名指向新的数组首址  写ExpandArray.length*2].j<m.0.length.arraycopy(m.

i++){  for(int j=0.j++){  System.b[2],这三个又分别是一维数 组.0.out. i<b.8}.length  写一个打印二维数组b元素的程序TestTwoArray.Java的数组  特别注意:如果是一个java程序员不应该这样来实现数组拷贝,  java是一个纯面向对象的语言,java中全部是类,所以作为java程 序员首先想到的是有没有现成的类可以实现拷贝功能而不是自己 去写怎么实现。  使用System.8}.m.0.length. ×a2 a2 a22 a23 0 1 int[3][] d=new int[][]{{4.{7.j<b[i].out.4}.5}.2.length为3.{5.2}}.a=new int[3][4].length==b[1].{9.6.8}}.5}.{9.b[1].2}}.可直接实现数组拷贝 a0 a0 a02 a03 Java的二维数组 0 1  一维数组相当于一条线,二维数组相当于一个平面 a1 a11a12 a13 int[][] a=new int[3][4].printArray(d).10.5}.b[0].println().12}}. √会分配空间 0 int[][] c1=new int[][3].//空指针异常  Java的二维数组本质上是一维数组的一维数组  b是一个二维数组,如果看成一维数组的一维数组,则b用三个元素, b.8}.arraycopy(m.print(b[i][j]+‖ ‖).× int[3][] d=new int[3][]{{4.length.length==b[2]. √ int[][] d=new int[3][]. √ int[][] a. × int[][] b={{1.  b的三个元素分别为b[0].{9.}}  System.7.n. .11.{7.√显示初始化数组 int[][] c=new int[][]{{4.{7.java  for(int i=0.3.length).

out.{5.6.Java的数组                    public class TestTwoArray{ public static void main(String[] args){ int[][] a=new int[3][].{9.//Error!!!! //int[][] a={{1.println().length).12}}.length. System. System.10.length).8}.out.print(a[i][j]+"\t"). System.length.println(a.length).i++){ for(int j=0.out.j++){ System. a[2]=new int[3]. } System.println(a[1].7.length).println(a[2].3. a[1]=new int[4].out.j<a[i]. for(int i=0.11.out.println(a[0].out.4}. //int[][] a=new int[][3]. } .2.i<a. System. a[0]=new int[2].

7.Java的数组   } }  课堂练习:编写一个简单的数组访问程序ArrayAccess.length.8.9.5.3.java,要求有插入一 个元素,删除一个元素,显示所有元素的功能  解题思路:  定义数组 static int[] data={3.  编写一个insert函数 static void insert(int pos.int val),pos是位置,val 是插入的数字(考虑位置的几种情况)  若len==data.6.  定义一个整型变量len来存储当前数组data的有效元素len=data.4}.length表示数组满了,空间不够,则要考虑重新分配 新空间  考虑写一个expand方法来增长空间  (pos<0 || pos>len) 则越界了  pos==len 则刚刚在数组尾插入元素  pos在数组头或数组中间插入则需要移动元素  编写一个Delete函数 static void delete(int pos) pos删除某位置上的元素  (pos<0 || pos>len) 则越界了  pos==len 则刚刚在数组尾插入元素  pos在数组头或数组中间删除,则需要移动元素  编写显示数组所有元素的函数static void disp() .2.

 for(int i=pos.  }  } .3.  static int index=8.  }  data[pos]=value.  index++.6.  }  static void delete(int pos){  index--.5.4}.i--){  data[i]=data[i-1].i<index.8.int value){  if (index==data.i>pos. static void insert(int pos. for(int i=index.Java的数组  public class TestInsertDelete{  static int[] data={2.9.i++){  data[i]=data[i+1].length) expand().7.

请按照指定算法打印每轮的对阵形势 . // 2 1 7 6 3 8 9 4  print().i<index.  delete(1).// 2 5 1 7 6 3 8 9 4  print().  System.0.Java的数组  static void expand(){  int[] a=new int[data.0.  }  public static void main(String[] args){  insert(2.data.println().length*2].  }  static void print(){  for(int i=0.1).  data=a.print(data[i]+" ").  }  } 练习:有偶数支足球队进行单循环比赛.length).arraycopy(data.a.out.out.  }  System.i++){  System.

java面向对象的编程 Day04-Day09 .

Day04          了解和使用常见的IDE-Eclipse 如何使用面向对象的思想解决问题 理解抽象对象和抽象对象的特点 了解面向对象与非面向对象的区别 理解类和对象的概念及其关系 掌握定义,使用类和对象的方法 理解java方法的重载特性 掌握构造对象的过程和构造方法特点 掌握java中方法参数传递规则与特性 .

util.sort(数组名)来实现。  调用的java类的方法都是经过测试的,sun公司不断更新的方法,肯定是最 好的,所以一定要学会运用不同类的不同方法。 .Arrays.java分析java的面向对象  传统的程序员写排序代码则一般都会思考怎么排序,用什么循环,如何移用 元素等,自己写代码实现排序功能  作为一个java程序员,java是纯粹的面向对象的编程语言,则无需自己写代 码实现,一定要转变思想,当java程序员遇到一个问题,要实现一个功能时, 则不要一味地想到自己怎么解决问题,而是先想想java中有没有现成的哪个 类的哪个方法可以实现和解决问题。这就是面向对象的思想,也就是java的 程序设计思想  Java语言其实就是由很多的类组成,每个类有不同的对象,每个对象又有很 多方法,所以我们解决问题,编写程序就是调用这些方法来解决问题。排序 数组可使用java.  面向对象的编程思想 非面向对象与面向对象的区别  非面向对象的数据不能隐藏,而且数据与方法不够紧密  面向对象的思想  面向对象是一种思想,是指用什么样的思路去写程序,做软件。  真正的面向对象是指用面向对象的思想去在现实生活中解决问题,将现 实中解决问题的思想与计算机思想更好地统一起来,能够让计算机模拟 现实生活中解决问题的办法。  通过语言来编写程序,模拟人类解决问题的方法思路,而解决问题的最 好思想就是在现实中已形成的思想,计算机就是要解决现实中的问题, 把现实的问题迁移到计算机中解决。 面向对象解决问题的方法思想 举例说明:写一个数组排序程序ArraySort.

面向对象的编程思想   类与对象  什么是对象  对象是现实世界中客观存在的,是类的实例,万事万物皆是一个对象。  任何一个对象都有2种特性:特征和行为  一个对象它具有什么特征,我们称它具有什么属性,用属性表示  一个对象它有自己的行为,它具有什么行为,我们称它具有什么方 法,用方法表示  任何一个对象都是有属性,有方法的。  什么是类  类是同一类型事物数据的抽象,是对象共性的抽象,是客观对象在人脑 中的主观反映  例如:Student 学生 是类还是实例对象 Dog 狗 是类还是实例对象  java中的类与对象的使用  在java中,我们一定是写类,因为对象太多,无法写,只能写一个类来 代表所有对象  在java中,我们一定是使用对象,因为类是一个抽象,没有实现,在现 实生活中只有具体的对象,所以我们一定是用对象 对象之间的联系在现实中的表现  现实世界万事万物都是对象  现实世界都是由对象之间彼此联系,彼此配合形成的  对象是简单的,但由简单的对象可拼装成复杂的系统 .

试卷分 析  将传统的文档形式的学生评教做成学生评教系统,自动完成总分,数据分析  以学生考试系统为例:首先从这个现实问题中抽象出可以用计算机模拟的对 象 .统分.面向对象的编程思想  例如:一个人要从北京到南京,怎么解决? 人 北京 南京 自行车 三轮车 汽车 火车 飞机 轮船 坦克 火箭 神州  人这个对象 调用自己的骑车方法可以到达 调用汽车的运行方法也可以达到 调用其他交通工具的对象的方法来达到 所以在现实世界中的对象是彼此联系的,通过对 象之间的方法相互调用来解决问题。 面向对象的思想如何将现实问题迁移到计算机中?  将传统的试卷形式的学生考试做成学生考试系统,自动完成考试.

面向对象的编程思想  学生类 Student:Student类可以有答题方法,而答题方法操作的是试卷  试卷类 Paper:Paper类对象可以作为答题方法的参数 Student 答题方法(试卷) Paper  将现实世界的学生抽象成计算机可以模拟的Student类,这个过程就是抽象  抽象就是将要使用的对象抽取出来  抽象对象的特点  简单性  保持对象的简单性,使其各司其职,各进所长;所谓术业有专攻  弱耦合性  对象之间,对象与系统之间要具有弱耦合性;即抽象的对象之间,对象 与系统之间的联系尽量弱  举例说明——计算机硬盘  计算机硬盘坏了,可以接上任何一个硬盘继续工作,不影响计算机 正常工作  所有硬盘都遵守同一个标准,所以可以任意更换  可重用性  抽象的对象是可以重用的 .

所以我们调用的方法都是最新的,最好的 .面向对象的编程思想  举例说明——课件  课件是抽取出重难点知识点做成的,课件并非教材  课件就是一个标准,它是老师与学生之间的标准;它定义了老师要 讲什么,定义了学生要学什么  任何一个老师来讲都用这个课件,它具有重用性  有了课件,学生获得了标准信息,老师也知道要讲的主要内容,至 于怎么讲则形式都无关紧要 老师 学生 课件  可扩展性   抽象的对象是可以扩展的  举例说明  一个完成的工行系统可以进行扩展后给建行使用  一个普通汽车通过扩展改装成赛车 面向对象与面向过程  面向过程:先想到算法,在想到用什么数据结构  面向对象:关注对象有什么属性,方法;即先有(数据结构)对象,再有算法, 而这个算法不是自己去写,而是要学会如何在对象之间调用合适的方法  java进行程序设计就是要学会调用java已经设计好的各种类,对象的各种方 法,因为这些方法经过严格测试,而且一旦某个方法有更好的实现,则sun 公司会有专业人员马上更新方法.

 构造没有现实意义,只是得到对象的,它是为计算机语言服务的 类的结构与定义  类的结构:从oop角度,类包含了属性,方法,构造三部分  类的定义:从java代码角度,定义一个类 .Java中类与对象的设计      类与对象  对象:现实世界任何万物都是对象,对象不一定要是看得见,摸得着的。错 误也是一个对象;对象是类的实例,是客观存在的。 例如:狗是一个从很多具体的狗抽象出的一个类,世界人没有一个人看见了狗, 而我们能看见的都是狗类的某一个对象实例。像小白,旺财,美美等  类:同一类型事物的共性抽象 类(主观) 对象(客观存在) 抽象出共同特性 怎么写类,类包含什么  每一类事物都有它的特征,也都有它的行为  例如:学生类 Student 姓名,性别,年龄等为学生的特征;吃,睡,学习等 为学生的行为  在java中,特征是用属性来表现,行为使用方法来表现 对象的特征,行为与类的特征,行为的区别  对象是有特征的,也是有行为的  对象的特征,行为是具体的,具有个体性;而类的特征,行为是抽象的,没 有实现的 构造  想要从类得到具体的实例对象需要构造 如 String str=new String(“123”).

6.0.classpath都要配置;但在5.  在一个源文件中,package语句出现的次数为0-1次  包名规范:全部小写,分目录的结构  import 引入某包下的类库  同一个包是不需要导入的,导入其他包类库是从 classpath指示的位 置导入  以前jdk版本path.}  public是可选的,在一个java源文件中,只能有一个public的类,其 他的类可以有n个  class是关键字,表明定义的类;写类必须要有class,类名,类体 括号{};若没有类体括号{}则不为类  类名的规范是每个单词首字母大写,单词之间无空格  类体中包含什么  public class 类名{  属性  构造方法  方法  语句块{…}  内部类 } .Java中类与对象的设计  package 包结构名.0版本中只配path 即可  import在一个源文件中出现的次数为0-n次  (public) class 类名{…类体...

属性名首单 词字母全小写,其他单词首字母大写  实例变量没有初始化也可使用,系统会默认初始化为相应类型的 默认值  实例变量的访问范围是整个类中,在本类中可直接使用变量名访 问,在其他类的方法中则只能通过对象来访问;因为实例变量即 属性是属于对象的,有了对象,属性才存在  一个类中允许实例变量和局部变量同名,但在方法中访问同名变 量时,则访问的是局部变量;按照就近优先原则来访问  局部变量是定义在方法内的变量,它必须先赋值才能使用,与实 例变量不同,它不属于对象,方法调用完了则局部变量就消失了  想要通过方法访问实例变量,我们可以写get方法来返回实例变量  方法  方法即是表现对象的行为,方法的定义如下 .  public int age.  private int age.Java中类与对象的设计  举例说明类体中各部分——写一个学生类并测试  属性  属性在类里用实例变量来体现,在一个类里,属性可以出现0-n个  实例变量是定义在类里且在任何方法外的变量,可以使用三种访 问修饰符定义  int age.  定义属性的语法规范:修饰符 类型 属性名(=初始值).

Java中类与对象的设计  private void method(){….}  java中方法的定义指明方法能做什么,方法的实现是指明怎么做  在一个类中,方法可以出现0-n次,方法名的首单词全小写,其他 单词的首字母大写  方法的定义规范  方法的修饰符 方法的返回类型 方法名(方法的参数) 方法 抛出的异常{…return 返回值}  方法修饰符可以是0个或多个,修饰符位置可以交换  方法的返回值是返回给调用者  方法名指明方法能做什么  方法的参数可选,是方法需要操作的数据  方法若无返回值则返回类型为void;若有返回值则在方法中使用 return 返回值来返回  常见的主方法的定义:public static void main(String[] args){…….}  public int getAge(){….}  java中的方法重载  java中可以实现方法重载,方法重载叫做overload  方法重载的条件是方法名相同,但参数列表不一样,参数列表不 一样主要指参数个数不同,参数类型不同,参数顺序不同,但是 返回类型不做要求  对于java方法重载,在调用时,不同参数选择哪一个方法来调用, 是在编译时就确定了,与jvm无关,称为编译时多态。 .

Java的方法重载  在java中有很多方法重载的现象,这种思想很重要,java就要学习 这种思想  例如:java中的打印输出方法 System.out.System.java来演示测试  方法重载,参数按照就近原则,向上匹配  java中类的构造方法  在一个类中,构造可以出现0-n个  构造方法的语法规范  如 public Student(String name.boolean sex){….pri ntln(1).out.println(―abc‖).out.  方法重载的好处,为什么要重载  举例说明:人类对象的吃方法  人 吃(食物food):吃(药),吃(糖),吃(饭);若允许 重载,存在重载,虽然有很多不同方法,但调用者只管给不同 食物,统一调用吃方法则实现吃不同食物,至于具体调用哪个 方法来实现吃不同食物,则调用者不同关心,也不需要关心  人 吃 吃药(),吃糖(),吃饭();若不存在重载,则 方法很多,而且方法名不同,那么在调用方法时,则调用者就 要关心应用调用什么方法,需要判断调用哪个方法?而调用者 往往不知道类中有多少个方法,这样的设计不好  方法重载可以屏蔽一个对象同一类方法,由于参数不同所造成 的差异,这个屏蔽是对调用方法,使用方法者屏蔽。  方法重载的特性  举例:写程序OverLoad.int age.println().println()方法  System.} .out.System.

Java中类的构造方法  修饰符 类名([参数列表])[抛出的异常]{…构造体…}  构造方法命名必须与本类的类名相同  当没有定义构造方法时,系统会提供一个默认的无参构造,所以一 个编译生成的.  在构造方法中初始化:public TestInit(int m){data=m.java程序  执行new语句会创建对象,创建对象首先会分配空间  分配堆空间后,接着初始化属性,有2种方法  在定义属性时就初始化: private int data=1.}  修改代码,增加初始化语句块 .class文件中,构造可以出现1-n个  当定义了构造方法时,系统就不会提供默认的无参构造了  构造方法是可以重载的,只要在类中定义了2个及其以上的构造则 一定自动构成构造重载  定义类一定要写一个无参构造,因为这个无参构造会给子类用的, 本类不一定要用,但子类要用  构造方法创建对象的过程  创建对象分为三个步骤  申请分配堆空间:为对象的属性分配空间,是在jvm的堆空间 中  初始化属性:对对象的属性进行初始化,有2种初始化方法  执行构造方法:构造不能手工调用,只能系统调用  举例说明创建对象的过程及属性初始化 写TestInit.

char c=―s‖.2 8个字节  对象变量:先构造的对象引用,再构造对象;对象引用是在栈中,对象 是在堆中  首先看如何构造对象:Student s.  Student s. double dd=1. s=new Student().Java构造对象的过程   初始化代码块是定义在类体括号中的,使用{}来定义  初始化代码块的语句代码在初始化属性时执行,在构造之前执 行  构造对象的完成过程  申请分配堆空间  初始化属性  初始化语句块  执行构造 java中的简单变量和对象变量  构造简单变量与对象变量的区别  简单变量:直接在栈空间中分配一个变量空间,将内容放入空间中,空 间用变量名来表示  如 int a=10.2 a 10 4个字节 c s 2个字节 dd 1. 在java中只是定义一个变量,而没有生成对象,是在 栈空间定义一个变量s,只是类型为Student .

 当通过引用访问属性时,实际上是访问引用指向的对象的属性, 如s.study().java程序来演示对象与引用 .在java中才是生成对象,在堆空间分配生成 了一个对象空间存对象内容,然后将对象空间的地址赋给s,所以 s指向该对象空间。如下图: 1A2B S:1A2B  new Student() 对象与对象引用  如 Student s=new Student()  s是该对象的引用,s中存的是这个对象空间的首址,s指向该对象  当通过对象引用调用对象方法时,实际上是调用引用所指向的对 象的方法 如 s.Java中的简单变量与对象变量  s=new Student().age  引用类型与对象类型可以不一致  举例:写TestRef.

java来演示参数传递  不同方法测试结果分析与画出内存图  Java中,简单变量作参数是值传递,对象变量作参数是引用传递  Java中对象的特殊引用this  this的应用之一就是区分局部变量与实例变量  举例:写TestThis.out.out.} }  在无参构造中调用本类的有参构造  使用this(参数列表)来调用 .Java中的简单变量与对象变量  简单变量与对象变量作参数传递的区别  举例:写程序TestParameter.println(―ClassA(String)‖).System.} public ClassA(String s){ this().println(―ClassA()‖).java程序来演示  this代表当前对象  使用this访问实例变量 this.属性名  this的应用之二是在构造方法中调用其它的本类构造  在有参构造中调用本类的无参构造  使用 this()来调用  this()语句一定要放在有参构造的第一句,最先调用  如 class ClassA{ public ClassA(){System.

out.Java中的简单变量与对象变量  this(参数列表)一定要放在无参构造中的第一句,最先调用  如 class ClassA{ public ClassA(){ this(―abc‖).println(―ClassA(String)‖).} public ClassA(String s){ System.参数是double型的金额  构造方法:有参和无参.有参构造方法用于设置必要的属性 .参数是double型的金额;withdraw:取款 方法.println(―ClassA()‖).System.}   } Java类的特点  Java中类的声明与类的实现必须同时进行,不能分开;即java中写类一定 要写类体括号{},{}代表类的实现。  类中,构造方法与方法的区别在于构造方法无返回,方法有返回,即使无 返回值也返回void 作业:开发一个基于c/s结构的银行帐户管理软件:项目作业1—写一个账户类 (Account)  属性:id:账户号码 长整数;password:账户密码;name:真实姓名; personId:身份证号码 字符串类型;email:客户的电子邮箱; balance:账户余额  方法:deposit: 存款方法.out.

Day05             了解面向对象的三大特性——封装,继承,多态 理解封装的概念和表现 掌握如何实现封装和封装的好处 理解java中继承的概念和java的单继承 理解继承中的属性,方法继承特点——属性遮盖和方法覆 盖 掌握继承中的属性,方法的访问权限及常见的访问修饰符 使用 掌握继承中的子类的构造过程和构造特性 掌握继承复用和组合/聚合复用 理解java中多态的概念和多态的表现 掌握多态的实现和实现条件 掌握多态的作用和广泛应用 理解为什么要有多态和要用多态 .

set方 法;修改TestCreditCard.set方法来访问 封装的实现和封装的好处  写程序TestCreditCard.get.set+属性名(属性名首字母大写).set组件;get, set组件的规范是 get.java程序,在set密码的方法中设置密码要求6位  如果对于数据要求是只读的,那么则给类提供get方法  完全封装对象:如果把对象的所有属性都设置成私有的,我们常常称这样 的对象为完全封装对象;写CreditCard类为完全封装的对象  完全封装的对象写成类都要具备java beans的规范。java beans是java中的 一种组件,也是一种规范,在java beans中,必须要写get.属性名来访问,而要通 过提供的一些get.set是设置和获得 属性的 .面向对象的三大特性     面向对象的三大特性:封装,继承,多态 面向对象语言的特征  一个语言是否是面向对象的,就是看它是否有多态,有些语言也有对象, 也有封装,比如javascript,但它没有继承,没有多态,所以javascript不是 面向对象的语言 封装的概念和表现  封装  写程序TestEncapsulation.java来演示封装的实现和好处  对于封装,属性都是应该隐藏起来做成私有  为了保证可以访问属性,我们需要提供公开的访问方法,在这些方法中可 以判定数据的有效性,这样保证数据的访问安全,这些方法就是get.java来演示封装  对象属性的封装隐藏,方法的公开;即该隐藏的隐藏,该公开的公开  属性私有化后,则其他类不能直接使用对象名.

因为调用者只需要知道方法的声明就可以调 用了  举例说明  求一个数的2倍 public int doubleNumber(int a){ return a*2. } . //return a<<1.否则其他类随意调用则会是空间无限增长  私有方法与公开方法的设计原则  给别人调用的方法要是公开的方法  给自己调用的方法要是私有的方法  方法的公开和隐藏  方法的公开不是完全公开;公开方法是公开方法的声明,而隐藏方法的 实现  例如:TV电视机;银行ATM自动取款机  为什么要隐藏方法的实现  隐藏方法的实现使得方法实现的改变对程序架构的影响最小  这里的隐藏是系统自动实现的,我们只需写公有的方法。它的实现 对调用者不需要关心.面向对象的三大特性—封装  对于封装,方法都常常公开;一般情况下,方法的声明是公开的,但也有 私有方法的情况  比如: 人的走路,骑车方法是公开的,人的消化方法是私有的  又比如:可变长的数组类.增长空间的方法expand()则不能设置为公有 方法.

seatClass.rate){ ……………………… ………………rate……… result=票价.//获得票价 } 2000年,民航总局要求每张机票增加机场建设费,50元;result= 票价+50; 2003年,民航总局取消机场建设费,改为收取机场建设税,50元 ;这样设计不变。 2004年又要求扩展,税率要变,这样就需要再添加一个税率参数 ,此时方法声明就要变了。于是全国各地的订票机构,机票代理 商,它们都要调用这个方法来计算票价,那这些机构都要重新修 改调用的方法。这样带来了颠覆的影响。  方法的声明很重要的,不能随便修改的,一旦改动会给软件带来颠 覆的影响;在大型项目中,一个方法很可能有很多参数,有些可能 用到,但有些是用不到的,是为以后扩展使用的 .psrClass.面向对象的三大特性—封装  CRS民航订座系统,其中一个运价组件是完成计算一张民航机 票的价格,获得一张客票价格。这个组件中有一个方法专门计 算票价。 int getPrice(fltNo. return result.

有参构造方法用于设置必要的属性  练习2:(封装)  将Account类作成完全封装 .参数是double型的金额  构造方法:  有参和无参.面向对象的三大特性—封装  练习作业:开发一个C/S结构的银行帐户管理系统  项目名称:Bank Account Management System 银行账户管理系统 简称BAM  项目描述:这是一个基于C/S结构的银行账户在线管理系统.用户可以通过ATM终端 界面来操作自己的银行账户.  练习1:(面向对象基础语法)—写一个账户类(Account)  属性:  id:账户号码 长整数  password:账户密码  name:真实姓名  personId:身份证号码 字符串类型  email:客户的电子邮箱  balance:账户余额  方法:  deposit: 存款方法.参数是double型的金额  withdraw:取款方法.

则这个 类就是那多个类的父类.面向对象的三大特性—继承  继承的概念和java的单继承 将现实生活中的 对象 如:学生 计算机中的那块 学生数据 计算机中的那块 教师数据 面向对 象思想 抽象 抽象 计算机中的一块 数据来模拟学生 class Student{ 对象共性的抽象 } class Teacher{ 对象共性的抽象 } 除了可以从具体的对象抽象成类之 外.还有一种抽象就是将多个类抽取 出它们共性.又做成一个类.而那几个类 就是就是这个类的子类。 class Person{ 多个类的共性的抽象 } 父类:Animal 子类:Cat 又如:狗和猫都是动物,也可以抽象出共性 子类:Dog  泛化:把多个类的共性抽取出来,做成父类,这个过程叫做泛化  泛化和继承一定要具备逻辑上是is-a的关系。  如 Dog is a Animal Student is a Person  又比如 电脑和主机,他们不是is-a关系,他们是has-a关系,他们不能做 成父子类来继承  继承关系中一定有父类和子类,子类is a 父类  继承的好处  子类可以重用父类的代码  继承是类多态的前提条件 .

面向对象的三大特性—继承  定义一个类继承另一个类的方法  class 子类名 extends 父类名{…}  Java中只存在单继承  一个类最多只有一个直接父类,因为可能存在很多间接父类  如:Student-Person-Animal-生物;Person是Student的直接父类, 其他都是Student的间接父类  为什么java中类与类的继承只有单继承  一个人只有一个亲生父亲,如果一个类只有一个父类的话,那么该 父子类放在一起就会形成一棵树,是树状结构,方便遍历访问  中国传统的家谱就是以树的结构来谱写的,家谱上只有父亲的名字 没有母亲的名字,否则就会形成网状结构,不能遍历访问  特化:将某一个类按照特征,功能归到某一个大类中,这个过程叫特化  例如:车 车 自 行 车 三 轮 车 摩 托 车 电 动 车 .

java来演示  修改程序演示不同修饰符的作用 .面向对象的三大特性—继承  Java中多继承的实现  在现实生活中,很多地方都存在多继承的,如机器人Robot,它既要继承  人的特性,也要继承机器的特性  java中只有单继承,多继承如何实现:使用类和接口来实现 继承中属性和方法的继承特点  一个类的哪些部分可以被继承,哪些不能被继承  一个类一般都有属性,方法,构造  属性,方法是可以被继承的  构造是一定不能被继承的  为什么能继承父类的内容  创建子类过程是先创建父类再创建子类  一个子类对象中会包含父类对象  父类对象的私有属性和方法,子类可以继承但无法访问  Java的访问修饰符  四种常见的访问修饰符:private (default) protected public  四种访问修饰符的作用  修饰属性:写程序TestAccessProperties.

Java的访问修饰符  访问修饰符的访问范围 修饰符 范围 备注 private 本类内部 私有的 default 本类+同包的类 若不写修饰符时则是默认的 default;但default 不能显式地修饰成员,只能采用不写的方式 protected 本类+同包+不同 包的子类 受保护的 public 公开的所有的类 公开的  修饰符修饰方法  方法的访问权限,范围与属性一样的,不同修饰符权限不一样, 权限范围与上面的属性访问范围相同 public都能访问;private不能访问;default一般不用来修饰方法 重点学习 protected修饰方法:写程序TestAccessMethod.java来 演示 protected修饰的方法是同包可访问,但同包指的是与方法所在的 类同包  修饰符的访问权限和继承特性  在java中,常常是以父类的属性,方法是否可以被子类访问来判 定是否可以被继承,按照此标准来判定如下的继承特性 .

java演示方法覆盖与方法重载  举例:写程序TestOverride2.java测试演示返回类型不同的覆盖  Jdk5.0以后,当返回类型不同时,父子类方法覆盖则必须返回类型也是父 子类关系,也可覆盖 .继承中的方法覆盖 访问权限和继承特性 Java的访问修饰符从严到宽 范围 继承描述  修饰符 备注 private 本类内部 一定不能继承 其实是继承了,但不能访问 default 本类+同包的类 不一定能继承 若父子类同包则能继承 若父子类不同包则不能继承 protected 本类+同包+不同 包的子类 一定能继承 同包,不同包的父子类都能 继承 public 公开的所有的类 一定能继承  继承中的方法覆盖  只有有了继承,在父子类之间才会存在方法覆盖  方法覆盖的条件是父子类方法名,参数表,返回类型全部相同才能覆盖  举例:写程序TestOverride.java程序演示测试方法覆盖  什么是方法覆盖:父子类的方法覆盖是指当父类引用指向子类对象时,会 执行子类的覆盖方法  举例:写程序TestOverride1.

另一个是子类自己的a=10。当我们使 用this.属性名来访问  访问父类继承的方法而非子类覆盖的方法也用super.java来测试演示属性遮盖 super this ClassA a=20 ClassB a=10 局部a=30 创建子类对象 ClassB cb=new ClassB(),会先创建父类 ClassA对象,子类对象创建后,则必然有2个实例变量a, 一个是父类的a=20.继承中的属性遮盖  修改程序代码TestOverride2.方法名来调用  super指当前对象的父类对象  继承中子类的构造特点和过程  子类构造特点  在创建子类对象时,一定是先构造父类对象,再构造子类对象  如 A←B←C←D,构造D对象时,则一定先构造A对象,接着构造B对象, 然后构造C对象,最后才构造D类对象 B C D .a访问时却访问的是子类自己的实例变量a=10,这 就是子类属性遮盖了父类属性  当子类中的属性与父类属性同名时,则子类属性会遮盖父类属性  一定想要在子类中访问继承父类的同名属性,使用super.java改变父子类方法的修饰符  子类方法修饰符的范围要比父类的宽才能覆盖  子类方法抛出的异常不能超过父类的异常才能覆盖  继承中的属性遮盖  写程序TestSxZg.

}}  我们可以使用super().java来演示继承中子类与父类的构造特性  写一个类一定要写一个无参构造,可能自己不用,但可能某个子类用  在调用父类构造时,若不显式地调用则系统会默认地调用父类的无参构造  如:class A{public A(){.子类的构造特点和过程  举例:写程序TestConstructor.一层一层地 构造父类对象,直到构造Object对象为止  Object类是所有类的默认父类,若一个类不写extends时,则该类就是Object 的子类。所以不写extends等同于extends Object(但不能直接写出extends Object) ...super(参数)来显式地指明调用父类的哪个构造,并且 该语句必须只能放在子类构造的第一句,最先调用  调用构造方法,一般有三种形式,这三种形式都必须放在第一句,所以他们 不能同时出现,只可能一个嵌入另一个  super()—调用父类的无参构造  super(参数)—调用父类的有参构造  this(参数)—调用本类的有参构造  子类构造过程  当子类有很多的间接父类时,则构造子类会递归地构造父类对象.}} class B extends A{} 这段代码隐含了很多代 码  隐含代码:class B extends A{public B(){super()..

printMoney()来实现;这样同包的ZhangJS就可以 调用该方法了 .java来演示构造子类的过程  构造子类的过程是先递归地构造父类对象,一层一层地构造每一个类的 对象,在构造每一个类的对象时分四步执行:  分配本类的空间  初始化本类的属性  调用本类的初始化代码块  调用本类的构造 最后才构造子类对象 继承复用和组合/聚合复用  继承复用  程序TestAccessMethod.java程序,ZhangJC自定义printMoney 的方法,使用super.java来演示继承Object类  再次修改程序TestInhericeObject.java,引入初始化代码块演示  在构造方法执行时,先找this,再找super;若都没有则直接默认找 super()  创建对象时,先执行初始化语句块再执行构造,但构造中this,super不  受语句块的限制,会先执行  写程序TestConstructorSub.子类的构造特点和过程  写程序TestInhericeObject.java中,ZhangJC可以调用printMoney方法就 是继承复用父类HuZG的代码  修改前面的TestAccessMethod.

继承复用和组合/聚合复用  组合/聚合复用  写程序TestCARP.java来演示分析继承复用  如果想要一个类也具有另一个类的方法功能时,早期一般情况会采用将 这个类去继承另一个类,这就是继承复用  继承复用有设计问题  继承一定是从一般到特殊的关系,父子类之间一定要是is-a的关系。 而程序中的两个类不是/不一定是is-a的关系,不能直接设计为继承 关系  如果被继承的另一个类中有protected属性,那么在子类中就可以随 意访问和修改,数据不安全,继承复用破坏了封装  对于被继承的另一个类中有些方法,子类不想要,但因继承却不得 不要,破坏了子类的设计要求  修改程序TestCARP.java的代码将其变为组合/聚合复用  组合/聚合复用不使用extends,而是在一个类中维护另一个类的对 象作为属性,然后在自己的方法中不写自己实现,而去调用属性指 示的另一个类的对象方法来实现自己的方法。  组合/聚合复用的好处  不破坏封装  不需要继承不想要的方法  可以复用别的类的方法来实现自己的方法 复用代码一定尽可能使用组合/聚合复用,在工程上几乎不采用继承复用,会给设计 带来重大问题。 继承复用也称白盒复用 要破坏封装 组合/聚合复用也称黑盒复用,不破坏封装 .

因为是用引用去调用方法操作对象.java来分析多态的实现和实现条件  对象类型是客观不变的  当父类引用指向子类对象时,对一个对象只能调用父类引用类型中定义的方 法.java,演示将父类引用赋给子类引用  一个父类引用不能赋给子类引用,因为父类引用还可能指向其他子类对象, 若一定要这样做,则只能强转类型 .所以只知道父类方法  运行时.会在运行时对调用子类的覆盖方 法.对象类型是客观存在 的类型,也叫客观类型  引用类型:指把对象当作什么类型来看待.会根据对象类型找覆盖之后的方法.引用类型是一种主观的反映,也叫 主观类型  引用类型和对象类型  引用类型与对象类型可以不一致,但不一样时则只能是引用类型是父类, 对象类型是子类;若不是则出错  多态表现:当父类引用指向子类对象时,运行时,会根据对象类型找子类的 覆盖方法,调用子类的覆盖方法,这就是多态 多态的实现及实现条件  举例写程序TestPolymorphism.面向对象的三大特性—多态   多态的概念和表现  对象类型:一个对象都有它自己的类型称为对象类型.这就是运行时多态  修改程序TestPolymorphism.

则就允许我们实现通用编程.调用者无需关心 多态的应用  多态常常用在参数上  直接使用父类引用指向子类对象来引用多态在项目中是很少的  多态常常用在参数上:将子类对象作为参数传给父类引用,然后调 用引用类型的方法时会执行子类覆盖的方法。所以我们看到一个方 法的参数是对象类型时,则就要知道可以传一个该类对象,也可以 传一个该类的子类对象  写程序TestPolymorphism1.避免造成转换异常 多态的作用  有了多态.它只要知道可用这些父类方法.可以 屏蔽不同子类的差异.面向对象的三大特性—多态  父类引用不能随便强转为子类类型,因为强转类型不一定正确  想要正确地使用父类引用强转为子类类型,则先使用instanceof来判断   父类是否可以转为子类  父类引用 instanceof 子类名 来判断该引用所指向的子类对象是否 与当前比较的类兼容  该判断若返回true则兼容可转;返回false则不可转.java来演示多态做参数的应用 .至于 这个引用调用的方法是哪个子类的.父类引用指向不同子类对象.  该判断常常用在强制类型转换之前.对调用者来说.

java来演示多态在方法的返回类型上 的应用  为什么要用多态和多态使用的注意问题  为什么要使用多态  有了多态,那么父类引用指向子类对象,运行时调用的方法是子类覆盖 的方法。这个特性可以实现通用编程。对于调用者而言,不关心方法的 实现是父类的还是哪个子类的,他只管知道可以调用哪个方法就OK了  多态屏蔽了不同子类的差异,可以扩展程序  多态使用的注意问题  多态只在访问方法上有.而不会发生在访问属性上.面向对象的三大特性—多态  多态常常用在返回类型上  多态在返回类型应用对软件的扩展带来极大的方便;所以我们看到一个 方法的返回类型是对象类型时;则就要想到它可以返回父类对象,也可 能返回子类对象  举例:写程序TestPolymorphism2.java来测试方法重载中是否有多态 .属性是没有多态的; 即父类引用不会根据子类对象找子类属性的  多态是指运行时多态,是在运行时才创建子类对象,调用子类的覆盖方 法  请问方法重载中是否有多态?  写程序TestOverLoadDT.

方法:求周长和求面积 形状类的子类:Rect(矩形).Rect类的子类:Square(正方形).在编译时.HourlyEmployee:Employee的子类,按小时拿工资的员工,每月工作超出 160小时的部分按照1.分别打印出每个对象的周长和面积  2.放在Shape 类型的数组里.子类对象没有创建  练习作业:  1.创建三个不同的形状对象.Circle(圆形).某公司的雇员分为以下若干类: Employee:这是所有员工总的父类,属性:员工的姓名.员工的生日月份。方 法:getSalary(int month) 根据参数月份来确定工资,如果该月员工过生日, 则公司会额外奖励100元。 SalariedEmployee:Employee的子类,拿固定工资的员工。属性:月 薪. 不同的 子类会有不同的计算周长和面积的方法.5倍工资发放。属性:每小时的工资、每月工作的小时数 SalesEmployee:Employee的子类,销售人员,工资由月销售额和提成率决 定。属性:月销售额、提成率 BasedPlusSalesEmployee:SalesEmployee的子类,有固定底薪的销售人员, 工资由底薪加上销售提成部分。属性:底薪 .方法重载—编译时多态  多态是运行时多态,方法重载是编译时语法,方法重载中不能实现 运行时多态,也不会实现运行时多态  方法重载是编译时多态,编译时就决定了选择什么方法,而多态是 在运行时才能获得子类对象.设计一个形状类Shape.

Day06         掌握static修饰符的作用和使用方法 理解static修饰符的特性和应用 理解和掌握单例模式的设计 理解类加载过程和继承中的加载顺序 理解final修饰符的作用和使用方法 掌握final的特性和应用 理解java中真正的常量及其使用 理解abstract修饰符的作用和使用方 法  掌握abstract修饰符的特性和应用 .

protected.static class Inner{…}}  static修饰属性  静态属性:static修饰的属性为静态属性  静态属性的特点:静态属性是全类共有的属性.public.是该类所有对象共有的  写TestStatic.修饰内部类  修饰属性:static int age.修饰方法.修饰初始化代码块.  修饰方法:static int method(){…}  修饰代码块:static{…}  修饰内部类:class Outer{….java来演示 .public能修饰什么,static?  static的修饰作用:修饰属性. 它是在类加载时就被初始化了。  写一个计数器对象TestCount.java来测试演示静态属性与非静态属性  实例变量:每个实例对象都有自己一份  静态变量:是本类所有对象共有的,所以也叫类变量。类变量就是 该类所有实例共有的变量。  类变量可以用类名直接访问,类变量在对象不存在时就已经存在了.protected一样都是java中的修饰符  分析private.修饰符static  static修饰符  什么是static?与private.

修饰符static  static在现实中的情况  static属性存储在哪里?计数器程序的内存图  static修饰属性的特性  静态属性(类变量)可以直接使用类名访问  静态属性不是实例对象中的数据,它与类相关,只要类加载了就存  在了  静态属性是在类加载时就申请空间并初始化,而且静态属性是存储 在jvm的静态池里  静态属性可在任意的方法中使用,可称为全局变量 什么是类加载呢? 在执行new Student()这个语句时,jvm在执行这句时,它怎么知道student是一 个类呢?一个类是由student.就分配静态变量的空间.class。student.class文 件存储的就是类的信息。所以jvm执行new Student(),就首先找student.初始化静态变量  实例变量是创建对象时才创建 .class, 接着使用输入流将它读入到jvm并保存,此时jvm才知道Student类,才创建对象; 若第二次再new student(),就不用再类加载了也知道这个Student类了。这个过 程就是类加载。  静态变量在类加载时.java经过编译得到student.

java来测试static在父子类之间的覆盖与多态  java中的main方法为什么一定要是static  Java是一个纯面向对象的语言,而main也是在一个类里,若不是静态的 .但只能用子类的静态 方法去覆盖.修饰符static  static修饰方法  什么是static方法?用static修饰的方法为静态方法  静态方法的特性  static方法可以用类名直接调用,无需使用对象来访问,非static的方法只 能使用对象调用  static方法只能直接访问类的静态成员(静态方法,静态属性)  static方法不能直接访问非静态成员  static方法子类可以继承.不能用子类的非静态方法去覆盖,静态方法覆盖后不能实现多 态  static方法中不允许出现this,super关键字  静态方法与非静态方法  非静态方法可以访问静态成员  对象可调用静态方法 修改程序MyClass类来演示学习static修饰属性和方法 修改程序TestCount.java,演示测试静态方法与this,super 写一个TestStaticFGDT.而且子类可以覆盖静态方法.

}  }  栈里:p1.}  public class TestClassLoad{  public static void main(String[] args)  Person p1=new Person().修饰符static  ,则在没有对象时,main是不能调用的,这样以来程序就没有入口了, 所以main方法一定要是静态的,而对象的创建必须是jvm执行主方法后 才创建,而main就是主方法,只有main执行了才开始创建对象。main   是静态方法是由java的纯面向对象和jvm机制决定的。 static修饰语句块  什么是静态语句块?用static修饰的语句块或代码块 static{….  Person p2=new Person().p2;堆里:2个new Person();静态池里:name  new对象时就类加载,所以将静态属性放入静态池里 什么时候进行类加载?(类加载时机) .}  类加载主要对static修饰的内容做了什么?  写TestClassLoad.java来看看类加载在内存的操作  class Person{static String name.

java中代码演示声明一个类的引用的类加载情况  声明一个类的引用时,不会进行类加载的,而且也不会执行构造 在class Person中增加一个静态属性age,在TestStaticInitBlock主方法中访问 测试类加载  访问一个类的静态成员时,一定会类加载 修改TestStaticInitBlock.java,修改class Person中代码块为静态static语句块  执行本类的主方法一定会先加载本类,类加载时一定先执行static语句块  static语句块是在类加载时执行 将本类主方法中的代码拷贝到其他类TestStaticInitBlock.java,构造2个对象,测试初始化代码块的执行次数  只要构造对象就会执行初始化代码块,构造几次就执行几次代码块 修改TestClassLoad.修饰符static  代码块:{}括起来的代码叫代码块,它是直接定义在类体括号内但在任何方 法外的,即在类的属性的位置上。  一个类的加载情况 修改TestClassLoad.java程序,修改class Person来演示代码块  声明一个对象引用不会创建对象也就不会执行初始化代码块  代码块的执行时间:在初始化属性时执行,这样的代码块叫初始化代码块。构造 对象时,先初始化属性再执行构造方法。 修改TestClassLoad.java的主方法中再运行  执行其他类的主方法一定会先加载他类,所以本类加载是在new对象前发生,类 加载一定会执行本类的static代码块 修改TestStaticInitBlock.java,进行new2个对象,测试类加载  类加载只加载一次,类加载时执行static语句块 .

方法)时,要类加载,且只执行一次  当声明一个类的引用时,不会类加载  创建子类对象时,先加载父类,再加载子类(只要第一次需要加载子类 时,一定会先加载父类,且执行各一次)  如果子类没有覆盖父类的静态方法,那么子类直接调用父类继承的静态 方法m()时.java演示类加载  类加载时机总结  第一次创建对象时,要类加载,且只执行一次  第一次访问静态成员(属性.只会加载父类  如果子类覆盖了父类的静态方法,那么子类直接调用静态方法时,则先  加载父类,再加载子类,并且调用的是子类的静态方法 static的应用:设计模式-单例模式 .修饰符static  小结  一个类在构造对象时先初始化属性,执行初始化语句块,语句块与属性 的执行顺序由他们的声明定义顺序决定  static语句块会在类加载时就执行  一个类只会进行类加载一次  在执行一个类主方法时,一定会加载该主方法所在的本类  只声明一个类的引用不会类加载  访问类的静态成员会类加载  继承关系中父子类的类加载  写测试程序TestClassLoad1.

包括语法.不会反复创建 . public Person(){} }  然后将属性设为static.则就只会在类加载时创建一次.设计原则等  设计模式种类:四人帮设计模式提出了23种设计模式  单例模式——Singleton  在现实生活中存在单例的情况  提出怎样让一个类从头到尾,无论什么时候new创建都只能创建一个对 象,无论创建多少次也只返回同一个对象,即在堆里只new一次?  首先写一个类允许它的属性也是本类类型:在现实中存在这样的情 况,一个人,它有一个父亲属性,它的父亲也是一个人 class Person{Person father.}  接着将其构造方法私有,只能让它自己能new对象,创建自己,创 建后给一个属性来保存;如果不私有则会发生堆栈溢出,而且不能 保证只new一次 class Person{ private Person p=new Person().修饰符static  什么是设计模式?面向对象的思想中,设计模式很重要,它是前人总结出的 编程思路或套路,就像企业应用中也有一套规范.

private Person(){} public static Person getPerson(){return p.java 单例模式的实现有2种  饿汉式  懒汉式 单例模式实现的内存存储  栈里有hs1,它指向静态池里的实例instance;  静态池里有实例instance,它指向堆里的new对象  堆里对象有属性,它指向静态池里的静态属性(虚指向) 单例模式的应用很广  比如我们银行帐户管理,对所有的帐户应该只有一个银行来管理  银行也需要作成单例 .} } 例如:韦小宝就是八妻一夫,韦小宝只有一个。写一个单例模式的韦小宝 程序TestSingleton. private Person(){} }  到目前为止已经保证一个类只能创建自己一次,但创建后别的类如何 获得它呢?提供一个公有的方法返回它自己这个属性,以便别的类可 以使用它 class Person{ private static Person p=new Person().修饰符static     class Person{ private static Person p=new Person().

private Bank(){} public static Bank getBank(){return bk.java,给final属性分别在声明时和构造时赋值  final属性可以在声明时就赋值,也可以在构造方法中赋值 修改程序TestFinal.java,创建不同对象时为其final属性赋值  final修饰的属性不一定是常量,final只是不可二次赋值,但不一定是常 量  常量要使用static final同时修饰 如:static final int a=10.修饰类.修饰方法.}} final修饰符  什么是final?final也是修饰符,类似于c++中的const,代表不可改变,所有 被final修饰的则都不可改变  final能修饰什么?修饰属性.修饰符final   class Bank{ private static Bank bk=new Bank().java程序测试演示final修饰简单变量  final修饰属性必须且只能赋一次值才能使用,赋了值后则不能改变 修改程序TestFinal.修饰局部变量 final修饰属性  final修饰简单变量,则该简单变量就为常量,值不能改变 举例说明:写TestFinal.  对于static final的属性,什么时候初始化? .

java测试常量的使用  final属性与static final属性  当仅用final修饰属性final int b=20.  在构造方法中不能给static final属性赋值初始化  在static初始化代码块中可以初始化static final属性  static final int a.,b是一个属性,所以创建一个对象就 有一个b,而且若在声明时就初始化赋值,则每一个对象的b值不能变, 都一样,这样就太浪费空间了;final很少单独使用  如果想要每个对象都有b且b的值固定不变,则只需要一个b就够了,使 用static final来同时修饰b;static final使用地更多  final属性会影响类加载  举例说明:写TestFinal.修饰符final  在定义属性时初始化,如 static final int a=10.}  修改TestFinal.java,增加代码  static final修饰的属性值若可以在编译时就确定,则访问它时就不会类 加载  static final修饰的属性值若可以在编译时不确定,则访问它时就会类加 载  final修饰属性的特性  final修饰的简单变量值不可改变  final修饰的对象引用只能固定地指向某个对象,但对象中的内容可变 . static{…a=10.

修饰符final  final修饰的变量仅只能赋一次值,可以在声明定义时赋值,也可在构造 中赋值  final修饰的变量会浪费空间,在实际开发中使用很少  final修饰的变量若没有赋值,则不能直接使用  static final同时修饰变量是常量,在实际开发中用得很多,它的赋值可  以在声明中定义,也可以在静态代码块中赋值  static final修饰变量时,可能会不执行类加载  当修饰变量的值是可在编译时确定的则就不进行类加载  当修饰变量的值是不能在编译时确定的则就会进行类加载 final修饰方法  final修饰方法特点:  final修饰的方法可以被子类继承  final修饰的方法不能覆盖  非final方法的覆盖会受到修饰符的影响,子类的修饰符要比父类的宽才能覆盖  举例说明:在TestFinal.java中增加代码测试final修饰方法的覆盖特点  final修饰类 .

a=a. final修饰类的特点:  修饰符final  final修饰的类叫不变类  final修饰的类不能被继承,它没有子类  一个final类中的所有方法都是final的方法 final的应用:设计模式-不变模式  不变模式:定义一个类中的所有属性都为final.int b){this.b=b.} }  一个不变的类创建两个对象,则他们的属性都不能改变;  不变的类创建每一个对象都是一样的,这样就浪费空间  jdk中的不变类(final类)  String类就是一个典型的final类  String类是一个不变类,即String类的字面值是不能改变的  举例说明String的使用:写TestString. private final int b.则这个类是一个不变的类  举例说明不变类 final class C{ private final int a. public C(int a.this.java .

String s4=new String(―456‖). s3与s4指向 的地址不同,每new一次都会在堆里重新分配空间 s2 堆 456 s4 456 .final类String的使用  String类  String的字符串字面常量存储在串池里,里面的值不能改变 String s1=―123‖. s1与s2指向的地址相同,都在串池里 s1 串池 123 s3  new String对象是在堆里创建一个对象,每new一个对象则都会重新 分配空间 String s3=new String(―456‖). String s2=―123‖.

使用+号很浪费空间(每连接一个字符串就会重新申请空间 )  例如: String s=―A‖.使用+号运算符可以连接字符串的.java测试intern()方法的作用  intern()方法的作用是返回该字符串在串池中的位置,前提是在串池 中有该字符串  String s=―123‖. s2=s2+‖9‖.final类String的使用  intern()方法的使用  修改TestString. s=―456‖的内存存储  String s2=―678‖. .然而String类是 不变类.s=s+‖B‖+‖C‖+‖D‖+‖E‖.的内存存储 01dc ―123‖ S:01dc 01dd 02dc S2:02dc  ―456‖ S:01dd 03dc ―678‖ S2:03dc ―6789‖ String的+号连接字符串  对于String类.

final类String的使用 写TestStringLJ.是可变的.toString().  写TestStringBufferLJ.最好不用String.效率低  StringBuffer是字符缓冲类.java来连接前面的字符 String与StringBuffer比较  String是不变类,想要连接多个字符串时.java程序来测试String.  StringBuffer如何转换为String  String s=sb.StringBuffer的连接效 率    . StringBuffer sb=new StringBuffer(s).用它来连接多个字符串效率高  写TestStringBuffer.lang包下的类,是字符串缓冲类  StringBuffer是一个可变的类,调用其对象的append(字符串),则 可以直接在后面连接字符串,不需要也不会创建新的空间  String如何转换为StringBuffer  String s=―A‖.java来连接前面的字符  String是一个不变类,它的值不能改变,使用+号连接字符串则 每次都需要重新分配空间,之前分配的空间就变为垃圾,这样很 浪费空间和制造大量垃圾的。  在大量连接字符串时选择使用StringBuffer类 StringBuffer类  StringBuffer是java.

abstract修饰类  写程序TestAbstractClass.修饰符abstract    abstract修饰符  什么是abstract?abstract是修饰符,代表抽象  abstract能修饰什么?修饰类,修饰方法.java测试抽象类的使用和抽象类的特性  abstract类的特性  使用abstract修饰的类为抽象类,抽象类是用来被继承,子类去实现 的  抽象类就像一张图纸,实现后的子类则就像根据图纸生产的产品  abstract与多态密不可分的  抽象类可以声明一个引用  抽象类不能创建对象  抽象类可以调用静态方法,不能调用非静态方法  一个抽象类可以被子类继承,子类也可以是抽象类  一个类中有抽象方法,则这个类必须是抽象类  一个抽象类中不一定要有抽象方法  子类Sub并不是一个抽象类,可以创建对象 abstract修饰方法 .

java程序来演示抽象方法的使用  父类是抽象类时,构造子类也会调用父类的构造  abstract方法与多态是紧密联系的  在现实世界中,某类事物能做什么是可以确定的,所以现实中的类常常都 是抽象类,它的抽象方法的定义与实现分开的  abstract类与abstract方法的特性和作用  抽象类就是用来定义一类事物能做什么,而子类可以实现抽象类的部 分抽象方法  抽象类对象是不能独立存在的,但若创建子类时候,先构造父类对象 则是可以的 .修饰符abstract  什么是抽象方法?用abstract修饰的方法为抽象方法  抽象方法的特点  抽象方法只有声明,没有实现,用.结束 如 abstract void method().  非abstract子类继承有abstract方法的父类,则一定要实现从父类继承  下来的abstract方法  abstract子类继承有abstract方法的父类,则可以不实现从父类继承下 来的abstract方法 abstract类与abstract方法的应用  abstract类是一种很有用的语法,在实际开发中,它主要用来抽象出一些 子类的共性,在抽象类中只声明方法,表示出方法能做什么,但因不同子 类可能方法的实现不一样,所以方法实现就是个性  写TestAbstractMethod.

修饰符abstract   抽象类是有无参构造的,是留给子类使用的  抽象类就是用来定义一个标准,定义某类事物的方法标准,而让其被 不同子类继承,去覆盖实现这些方法  对于调用者而言,只需知道抽象类的方法定义,则就可以调用不同子 类的实现  抽象类屏蔽了不同子类的方法对调用者的差异 三个修饰符的共同特性和使用  三个修饰符的共同特点  三个修饰符都可以修饰方法  三个修饰符都不能修饰构造方法  static绝不能修饰构造方法,因为构造方法是创建对象的,而 static是在对象不存在时就存在  final不能修饰构造方法,构造方法不能被继承的,当然就不能覆 盖,所以无需用final。  abstract也不能修饰构造方法,因为abstract就是用来继承的,用 来实现被覆盖的,构造方法本来就不能继承,覆盖。  三个修饰符组合使用规范  static不能与abstract合用  final不能与abstract合用  private不能与abstract合用 .

三个修饰符组合使用的规范  static不能与abstract合用  abstract方法是为了子类覆盖该方法而实现多态,但static方法是找 引用类型的方法,没有多态。  没有多态则调用的是父类的方法,父类方法又没有实现  final不能与abstract合用  abstract修饰的类,方法是能继承的,能覆盖的,但final修饰的类 是不能被继承的,final修饰的方法不能被覆盖  private不能与abstract合用  private方法是不能被继承的,当然就不能覆盖,而abstract是要求 子类继承并覆盖  写程序TestModifier.java测试三个修饰符的组合使用 .

Day07         理解接口的概念 掌握接口的特点及定义一个接口 理解接口与抽象类的联系 掌握接口的继承与实现 理解接口的思想和使用 掌握接口的应用和接口回调 理解和掌握Object类及其常用方法 理解包装类和掌握包装类,基本类型,String的转 换  理解基本类型与包装类的自动封箱,自动解箱  掌握String的常用方法使用  理解StringBuffer.StringBuilder的区别及使用 .

接口与抽象类  接口  什么是接口?接口也是一个特殊的抽象类  接口的特点及定义接口  写TestInterface. void m1().java程序来演示测试接口特点  接口特点  所有属性是公开静态的常量  所有方法是公开的抽象方法  接口中没有构造方法 public class TestInterface{ public static void main(String[] args){ } } abstract class ClassA{ public static final int a=10. void m2().PI. public static final double b=Math.PI. public abstract void m1(). double b=Math. } . public abstract void m2(). } Interface IA{ int a=10.

接口与抽象类
 定义接口
 一个抽象类的所有方法全是公开抽象,属性是公开静态常量,则这个
抽象类就可以一定为接口
 使用interface来定义接口,如 interface 接口名{接口体}
 编译前面的代码发现,编译后接口也会生成一个IA.class文件,所
以接口也是一个抽象类
 接口与抽象类
 在java的一个文件中,只允许一个public的class,可以有多个class;
在java的接口文件中,也只能有一个public的接口,可以写多个接口,
编译后生成的.class文件名与接口名一样
 抽象类与接口在逻辑上是相等的,但有一点不同,抽象类是有构造方法
的,可以自定义构造,而接口是没有构造方法的
修改前面的TestInterface.java,测试使用多个public接口和在接口,抽象
类中构造
 接口是一个特殊的抽象类,抽象类可继承,接口也可以继承,但是接口

继承后的子接口可以不实现父接口的抽象方法
 接口的继承与实现
 接口与接口之间可以是多继承
在TestInterface.java中增加代码测试接口继承
 接口是抽象类,不能new接口对象,只能new实现了接口方法的子类对

接口的继承与实现
在TestInterface.java中测试new接口对象
 接口可以声明引用,这个引用可以指向实现接口的类的对象
在TestInterface.java中测试接口声明引用
 接口与接口之间继承,而接口与类之间则可以有实现,接口是抽象类,
可以被一个类继承,当一个类继承接口时则称这个类实现接口,用
implements关键字来表现
在TestInterface.java中增加代码演示接口的实现
 实现接口的子类中方法一定要加全修饰符
写程序TestIn.java来测试演示如何访问接口的静态成员
 可以访问接口中的静态成员,使用接口名.属性名来访问
 一个类在继承一个类的同时,还可以实现多个接口
在TestInterface.java中增加代码测试一个类继承一个类同时实现多个接口
 小结——接口的特性
 接口也是一个抽象类
 接口也可以继承
 在一个接口文件中:只能有一个公开的接口,可以写多个接口,编译生成
的.class文件名与接口名一样.
 继承接口后的子接口是抽象类,无需实现

接口的使用

 接口之间可以实现多继承的.
 接口不能new对象,但可以声明引用
 接口可以被一个类继承,类继承接口时用implements
 一个类在继承一个类的同时,还可以实现多个接口.
 接口的使用
在TestInterface.java中增加代码测试接口引用调用不同的接口方法
 当多个父接口(直接,间接)指向接口同一个实现类的对象时,则各个接口
引用能调用的方法是该接口引用中的方法
 实现了子接口的类也可以调用间接父接口的方法,因为一个类实现了子
接口,也就是实现了父接口
在TestInterface.java中测试实现类的类型与各个接口类型的比较
 接口的思想
 接口的作用是实现多继承,这只是接口的一部分功能
 举例说明
存储设备
输入设备

光盘

USB设备

硬盘
移动硬盘

U盘

这三个对象我们第一想到它们
是存储设备,将存储设备作成
父类

鼠标

键盘

这两个对象我们第一想到它们
是输入设备,将输入设备作成
父类

接口的思想
接口是一个类的附加信息,接口的多继承是不会破坏类的单继承的
一个类的父类与该类实现的接口并不在同一个层次上,一个类实现的接口

,往往是对多个类的共性再做一个抽象
接口是对事物的共性再抽象
任何一个对象都是多继承的,不可能是单个类型的,但对象的多个
类型之间有一个主次关系。主要的做成类:存储设备,输入设备;
次要的就做成接口:usb设备,也称副类型
练习作业
将前面我们写的Shape作成接口
在原有的雇员练习上修改代码,公司会给SalariedEmployee每月
另外发放2000元加班费,给BasePlusSalesEmployee发放1000元加
班费,改写原有代码,加入以上的逻辑,并写一个方法,打印出本
月公司总共发放了多少加班费。(提示:这2类员工开加班费,利
用接口实现,抽取出这2个类的共性写一个接口,提供一个加班
费的抽象方法,让这2个类实现接口。最后还要求计算总的加班
费,通过判断类型是否为接口类?是则加上加班费)
接口是提供了一个标准,它使得方法的使用者与实现者之间是弱耦合关
系;因为接口中都是抽象方法所以接口是一个解耦合工具。
接口的作用
举例说明:java使用驱动Driver访问不同数据库的原理
java
Driver
DB 软件 OS
硬件

接口的作用
 首先驱动只能由各个数据库厂商来写
 为了避免不同厂商的驱动差异,则sun公司就要求制定一种标准,

所有厂商都按照统一标准来写,这样java就可以用统一标准的方法,
这样以后使用java,则会附带使用各个数据库,也提高了数据库的
使用
 Java中只定义了访问数据库的标准方法的定义,但方法的实现只能
由各个数据库厂商来实现。这样所有主流DB厂商都按标准来实现,
访问DB驱动,这样java就可以使用标准定义访问各个DB
 写TestJDBC.java程序来测试演示不同数据库的访问
 在主方法中实现各个不同数据库的访问,只需要改变不同的驱
动对象,对于调用者调用的方法则不变
 若没有标准,则不同数据库不同实现,则对数据库做一些应用
时,只能不同DB的应用也不同。对于调用者使用也就不同。
 有了标准则可以通过标准去访问标准的实现,因为有了标准,
既可访问实现1,也可以访问实现2,不同数据厂商提供不同的
实现。如下图
实现1
使用者


实现2

实现3

接口的应用

使用者都是通过标准来访问不同实现,所以接口可以实现多态。
把接口的各种实现都当作标准接口来看,来屏蔽了不同的实现对使用者的差异。
接口就是实现了接口的使用者与接口的实现者的弱耦合性
例如:不同厂商的灯泡是遵循同一标准,不同灯座(灯罩)也是遵循同一标准,所
以不同厂商的灯座(灯罩)都可以使用不同厂商的灯泡。
有了标准,则APP应用对Driver的实现并不关心,只需要调用标准的方法则会有不
同的实现
 接口的应用
 接口用作形式参数
 排序算法有很多种,作为面向对象编程的程序员要考虑排序不依赖
与具体算法,而是依赖于接口。
 将排序方法的实现定义一个标准接口,接口中定义一个排序方法
 采用多个不同实现来实现接口,在使用者处提供一个方法专门负责
排序,将接口作为参数传入
 只要将不同排序的实现类对象以参数传入给调用者的排序方法,则
就可以排序
 这样使得某个具体的排序与要排序的数组之间实现了弱耦合关系
 举例:使用接口实现排序数组元素的程序TestArraySort.java
 接口用作返回类型
 修改之前的TestJDBC.java程序,使得连接数据库的实现类对象可通
过参数来获得,使得程序延展性更好,扩展性更好!
 使用接口类型来做返回类型,可使得连接数据库的实现可动态获得

接口的应用
 将对象作成接口
 若我们要想实现一个对象的某个方法,而此时该对象还来不及创建
出来,这时我们就可以将这个对象先作成接口。
 定义了接口,就可以使得原本要调用这个对象的调用者可以在对象
还没有创建出来之前,使用接口来代替,一样可以编译成功,等到
以后有了该接口的实现了,则将实现类的对象传给这个接口的引用
即可实现
 有了接口,至于标准的使用者先有,还是标准的实现者先有,哪个
先有都无所谓了。
 有了接口标准,那么调用对象的方法时,可以使得在对象还没有创
建出来时,使用接口引用来代替调用。这样调用者就不依赖与对象
的实现,所以接口就像定义了一个标准,标准的使用者和实现者可
以分开实现,无论谁先谁后都可以。
 例如:有了灯泡和灯座(灯罩)的标准后,则无论先买灯泡,还是
灯座(灯罩)都是一样的。
写一个灯泡与灯座的程序TestCallback.java演示对象作成接口和接口
回调
 接口回调
 把接口的实现者对象传给接口的使用者,再由接口的使用者通过接口去调

用接口的实现者的方法,这个叫做接口回调
 在灯泡和灯座的程序中,我们很清楚地知道回调了接口的方法,这是因为
程序很小,接口的定义,实现和调用者都是一个人写的。

接口回调  在大型工程项目中,不可能由一个人完成接口的定义,接口的实 现和调用者的程序。往往都是告诉你如何定义接口,要求你实现 接口的方法,但这些接口会被其他人写的程序调用,但是你看不 到别人回调你的接口方法,你也不知道别人什么时候回调,什么 地方回调,怎么回调。  在大型工程开发中,往往都是只给你一些.class文件,而你看不 到源码,不清楚别人在什么时候调用你的方法,而且也会给你一 个帮助文档,里面会告诉你要定义的接口及接口的方法,要求你 实现并测试 利用接口回调完成作业:完成剪刀,石头,布的游戏(提供帮助文档 给你,告诉你接口和接口的方法要求你实现)  Object类  java的类之间一定是树状关系,所以每个类都有自己的父类,任何一个类 若无自定义父类,则它默认的父类是Object  类Object是任何一个自定义类的直接父类或间接父类  Object类的所有方法可以被其他类调用,Object的引用可以指向任何一个 类的对象。  Object类的常见方法  Object类的finalize()方法:  finalize()这个方法是在对象被回收时才调用  finalize()方法中若定义了释放资源的功能代码则可以在对象被回 收时释放资源  finalize()方法与c++析构不同,java中没有析构,c++中析构是用 .

java程序来测试clone  先拷贝对象变量,则原始变量与拷贝变量引用同一对象, 那么他们的改变会相互影响  要想实现拷贝与原来的互不影响,是2个独立的对象,有各 自的空间,则需要使用clone方法 .java来演示finalize()方法  Object的clone()方法  写一个TestClone.类Object 来释放资源的,一般将释放资源的代码写在析构中。但finalize()方 法中一般不写释放资源的代码,虽然这个方法可以写释放资源 的代码,它在对象被回收时会被调用释放资源,但这样做并不 能有效的释放资源,因为java虚拟机回收垃圾时机是标准的,不 同对象的回收时机也不一样。  java的垃圾回收时机  在java中,回收垃圾是java虚拟机的工作,jvm回收垃圾是 一个标准,它是在垃圾不得不回收时才回收垃圾,而回收 垃圾时会调用finalize()方法。  不同类型的对象,垃圾回收时机也不一样,不同对象的垃 圾回收也要求不一样,程序无法控制垃圾对象的回收时间 的。  当一个对象没有任何引用指向它,它成为垃圾,但这也不 代表jvm就将其马上回收,到回收还需要一段时间。  在finalize()方法中写资源释放代码则要等到垃圾回收时才调 用,所以这样时间该对象占用的资源就浪费了  在项目中,我们绝不会将有用的代码,释放资源的代码放 在finalize()方法中。 写一个程序TestFinalize.

clone()来调用,为什么?子类不是可以访问父类受保护的方 法的吗!每个类都是Object的子类的吗!  clone()方法比较特殊,子类只能调用clone()方法来克隆自己, 而Object的clone是克隆Object,所以必须在子类中重新定义自 己的clone()方法,将其声明为public。  子类要覆盖重写clone方法,而且要使得clone方法能实现克隆则 子类还必须要实现Cloneable接口,实现这个接口的唯一目的是 可以使用instanceof来对一个类检查它是否可以克隆。  Cloneable接口在java中是一个标记接口,在该接口中没有任何 接口方法。这个接口只是作为一个标记,并不是为了实现某些方 法,它只是表明类设计者知道要进行克隆处理。  如果一个类没有实现Cloneable接口,则该类对象调用覆盖的 clone方法时就会抛出CloneNotSupportedException异常。所以 覆盖的clone方法要抛异常,测试主方法也抛异常。 修改class Employee,让其实现Cloneable接口,覆盖clone方法, 在覆盖的clone方法中调用父类的clone方法,测试clone的作用  clone()方法的作用:克隆一个对象,创建一个对象的副本,在java运 行时系统为新的实例分配存储空间,并将当前的对象复制到新分配的 对象空间中。 修改class Employee,增加一个对象域Salary salary,再次演示浅拷贝  浅拷贝:但是在子类覆盖的clone方法中,如果我们直接使用 .类Object  在Object类中,clone方法是protected,因此无法直接使用对 象.

类Object super.clone()调用父类Object的clone方法则克隆不是那么简单,因 为Object对具体子类对象一无所知,所以Object克隆也只是将子类 各个属性域进行简单拷贝,age是基本类型,这样简单拷贝则没有 问题,但是如果域是对象类型则进行简单拷贝则就有问题,出现2个 引用指向同一个域对象,相互修改就会影响,就没有实现真正的拷 贝,这就是浅拷贝。  在实际开发中,我们必须避免浅拷贝,所以使用深拷贝。深拷贝就 是让所有非Object的类都重新定义clone方法,在方法中自定义实 现对象内容的拷贝,这就是深拷贝。 修改class Salary,使其也实现Cloneable接口,在Employee的覆盖 clone方法中实现内容拷贝,并演示测试深拷贝  clone方法的特性和使用  默认的克隆操作是“浅拷贝”,它并没有克隆包含在对象中的 内部对象  浅拷贝带来的问题就是内部对象并没有克隆,会产生原对象与 克隆对象共享,如何解决这个问题,只有使用深拷贝  深拷贝:让所有非Object的类都实现Cloneable接口,重新定 义clone方法,在方法中自定义实现对象内容的拷贝。  clone的使用需要对每一个类做出判断 默认的clone()方法是否能满足要求 默认的clone()方法是否能够通过调用可变子对象的clone()方 法的到弥补 是否不应该使用clone() .

类Object  想要覆盖clone()方法则必须实现Cloneable接口,使用public修饰 符来重新定义clone()方法,这样其他类才可以调用  Cloneable接口是一个标记接口,该接口中没有任何方法,使用它 的唯一目的就是可以使用instanceof来对一个类进行检查它是否可 以克隆。  如果一个类使用浅拷贝可以满足克隆要求则也要定义该类实现 Cloneable接口,但可以不重写clone方法。  如果一个类不实现Cloneable接口,则覆盖clone方法后,也不能使 用clone方法克隆,执行时会抛CloneNotSupportedException异常  在Employee中,Stirng也是对象类型,而我们并没有去让String实 现Cloneable接口,也没有在String中去覆盖clone方法,为什么 String使用浅拷贝时则可以实现真正克隆?因为String是一个不变 类,它的内部对象都是不变的,这样原始对象与克隆对象共享的内 部是不变的,既没有要更改它的方法,也没有创建对它引用的方法, 所以不会产生问题。  相反一个类中如果包含了一些没有实现Cloneable接口的域则就不 能保证内部子类实现clone一定正确了。  对于clone方法,我们建议少用,避免使用,在jdk类库中,不到 5%的类实现了Cloneable接口,所以很容易克隆出错。 .

getName() + '@' + Integer.equals比较为true Student的==比较为false. }  举例演示:写TestToString.toHexString(hashCode()).类Object  Object的toString()方法  Object的toString()方法:public String toString(){return getClass().java程序,实现覆盖toString()方法演示打印结果  toString()方法返回的是对象的字符串形式。  如果一个自定义类没有覆盖toString()方法,那么打印该类对象时,就 会打印出对象的地址  如果一个类覆盖了toString()方法,在覆盖方法中输出对象内容,那么 打印该类对象时就会打印对象的信息而非地址。  Object的equals()方法:比较两个对象是否相等  Object的euqals()方法的实现:public boolean equals(Object o){return this==o.equals比较也为false .}这是Object的equals()方法,是比较的两个对象的引用。  举例说明 :String类的对象比较和其他自定义类的对象的比较,写 TestEquals.java程序来演示测试  程序结果:String的==比较为false.java程序测试toString()的作用  直接打印一个String对象可以打印出字符串内容  Student也是一个类,可以直接打印,但打印的不是Student的内 容信息而是对象在内存中的地址  打印一个对象引用和打印一个对象的toString方法的返回值一样, 都默认是对象地址  所以一个类覆盖Object的toString()方法,则就可以实现打印对象 内容 修改TestToString.

97;91与94是同一个等级,94与97是同一个等级, 然而91与97却不是同一个等级;这就说明每隔5分为一个等级这个标准不具 有传递性,不满足equals方法的要求。我们就不能在equals中用这个标准 .26).equals(s3)也为true.则 s1.equals(s1)永远为true. 类Object Student类的对象可以调用equals方法,因为equals方法是Object类 的方法  Student对象调用Object的equals方法得到false结果,因为Object的 equals方法的实现是比较两个对象的引用。  String对象调用equals方法得到true结果,因为String类覆盖了Object 的equals方法,实现的是内容比较  如果写自定义类我们也覆盖equals方法,在该方法中可以实现自定义 类的对象的内容比较则就可以实现对象内容比较  Object类的equals为什么不直接实现内容比较?因为不同对象的内容 不同,是否一样的比较标准也不一样,而这个比较标准是由具体的 对象来确定的,Object不知道具体对象的内容比较标准  覆盖Object的equals方法是有一定要求的:  自反性: 若Student s1=new Student(―wj‖.94.equals(s3) 也为true. 自己与自己比较,则永远为true  对称性: 若s1.equals(s2)为true. 例如:学生类中考试成绩比较,假设我们制定判断标准为每5分为 一个等级,那么对于91. s2.则s2.equals(s2)为true.  传递性: 若s1.equals(s1)也为true.那么s1.

类Object
 如何覆写equals方法:在自定义类中写覆盖方法时就要从这个特性上

入手,在Student类中写一个equals()方法
public boolean equals(Object o){
if(o==this) return true;//先判断自反性,判断是否就是当前对象,自己
则返回true
if(o==null) return false;//判断o是否为空,若为空,而当前对象肯定存
在,则返回false
if(!(o instanceof Student)) return false;//判断2个比较对象的类型是否
是同一类型,若不是同一类型则没有可比性,返回false
上面判断类型的操作不够严密,如果o是Student的子类呢?则以上条
件是可以比较的,但在实际情况中,o是Student子类,它是不能与
Student比较的,因为他们是不同类型,而且子类很可能有其他成员,
所以我们使用下面的判断来实现,直接判断类型
if(this.getClass()!==o.getClass())return false;//getClass()方法是返回
当前对象的类型
以上判断都不满足,则说明这2个对象是同一类型而且可以比较
Student st=(Student)o;//首先将o转化为Student类型
if(st.getAge()==this.getAge() &&
st.getName().equals(this.getName()))
{
return true;
}else{ return false;}
}
 作业:写一个雇员类Employee,属性有name,age,salary;给这个雇员类写
toString(),equals(),clone()方法

Java的包装类

java的包装类
 Java所有基本类型都有相应的类,这些类我们称为包装类
 可以将简单类型变量转化为相应的对象类型,如int转为Integer,char转为
Character,byte转为Byte等
 除了int,char与对应的类名相差较大以外,其他简单类型相对应的类的类名
就是将简单类型名的第一个字母大写
int→Integer char→Character byte→Byte float→Float double →Double
boolean →Boolean long →Long short →Short
 简单类型,包装类,String的互相转换
 写程序TestWraper.java来演示各种类型的转换
 基本类型与包装类型的转换
 基本类型转换为相应的包装类对象:直接使用new对象
如int i=10; Integer ii=new Integer(i);
 包装类型对象转换为相应的基本类型:调用方法—包装类的对象.类
型名Value();
如 Integer ii=10; int i=ii.intValue();
 基本类型,包装类型与String的转换
 基本类型转换为String
 使用+号连接一个空串:如int i=10; i+‖‖; 一般不这样做
 调用包装类型的toString(基本类型)方法:如double d=3.2;
String str1=Double.toString(d);
 String转换为基本类型:包装类型调用parse基本类型()方法;如
String str2=―32‖; int i=Integer.parseInt(str2);

Java的包装类
 包装类型转换为String:直接调用toString()方法 如 Integer

ii=34;String str3=ii.toString();
 String转换为包装类型:直接new对象 如 String str4=―33.33‖;
Double dd=new Double(str4);
Integer i1=new Integer(2); Integer i2=new Integer(―2‖);
System.out.println(i1==i2);System.out.println(i1.equals(i2));
int temp=Integer.parseInt(―24‖);System.out.println(temp);
 基本类型,包装类型,String的相互转换图
 这三种类型的转换非常重要,因为我们开发的项目都是基于客户端,
服务端的,客户端传送到服务端的都是字符串,所以需要转换
 类型转换图
Integer

右图为转换图,
Integer可以转换为其
他的包装类,方法都
类似的。将Integer转
换为Double,将int转
换为double

Integer.toString(int)

int

String .valueof(int)

Integer.parseInt(String)

String

String,StringBuffer,StringBuilder的使用
 对于基本类型和包装类型之间的转换到了jdk5.0以后就支持自动转

换了,我们称为自动封箱和自动解箱。
 在程序中增加自动封箱和解箱的代码演示自动转换
String,StringBuffer,StringBuilder的使用
 String的使用
 拆分字符串——split(…) 返回类型为拆分后的字符串数组,方法参数可
以是一个符号,也可以是一个正则表达式;写TestSplit.java程序演示
 去掉字符串的空格——trim() 去掉字符串的前导和尾部空格,返回去掉
空格后的字符串;在TestSplit.java程序写代码演示
 求子串的位置——indexOf(String) 返回参数String第一次在本String中
出现的位置索引int类型;写程序TestIndexOf.java来实现在一个字符串
中找出出现子串的所有位置索引。
 字符串池的测试,写程序TestPool.java来演示串池与String对象的使用
 替换字符串——replace(…,…)/replaceAll(…,…) 返回替换后的字符串,
第一个参数是被替换的字符串,第二个参数是替换的字符串;写程序
TestReplace.java来演示替换操作
 字符串的匹配——matches(),判断字符串是否匹配一个正则表达式;
写程序TestZz.java来演示

String,StringBuffer,StringBuilder的使
StringBuffer与StringBuilder 用

 StringBuffer与StringBuilder都是可变字符串,它们的API有很多相同的
方法,StringBuilder是jdk5.0后才有的,它与StringBuffer不同在安全和
效率方面
 StringBuffer的效率较低,支持同步,可在多线程环境中使用,很安

 StringBuilder的效率较高,不支持不同,只能在单线程环境中使用,
不安全
 写程序TestStringBuiler.java来演示StringBuilder的使用
作业与练习
 写一个雇员类Employee,属性String name,int age,double salary,给这个类
写clone(),finalize(),toString(),equalse()方法
 哥德巴赫猜想:大于6的偶数都可以拆分成2个质数之和,要求验证哥德巴赫

猜想;写出一个接口实现拆分,从命令行输入偶数,然后输出所有的质数之
和的组合
 解题思路:首先写一个判断质数的方法,实现有很多,采用接口;接着
写一个拆分偶数的方法,实现有很多,也采用接口,在这个方法中需要
调用判断质数的方法,所以需要用一个参数来传递质数接口的引用
 将前面的形状作业Shape做成接口来实现
 将前面的公司雇员程序改做成接口来实现,增加功能如:公司给
SalariedEmployee,HourlyEmployee这2类员工开加班费,利用接口实现
 解题思路:抽取出2种类的共性做成接口,提供一个加班费的抽象方法,
让这2个类实现接口,最后还要求计算出总的加班费,通过判断类型是
否是接口类型来统计加班费

Day08








理解什么是内部类
理解内部类存在的问题和好处
掌握内部类的特性与分类
掌握4种不同内部类的实现与使用
理解java中异常的概念和分类
掌握异常的产生和传递
掌握异常的处理
理解和掌握自定义异常的使用
断言的使用和作用

内部类

什么是内部类?
 定义在一个类的内部的类,就叫内部类
 举例:
class Outer{

class Inner{
….
}
}
class Outer1{}
这个Inner1不是Outer1的内部类,不在Outer1的类体括号

class Innter1{
……
}
Class Outer2{Inner2虽然是在Outer2的方法内,但还是在Outer2的类体括号内,
是内部类
……
public void test(){
class Inner2{
….
}
}
}

java来测试成员内部类  在成员变量的位置上定义的类称为成员内部类  成员内部类与成员变量相似,一个成员变量的修饰符有多种,这些修饰 符也可以修饰成员内部类 .内部类    内部类有什么问题和好处  问题:外部类不使用或不创建外部类对象,就不能直接创建内部类对象  好处:外部类的私有属性,内部类可使用,而且不破坏封装,这也是为什么 内部类存在的重要原因 内部类的特性与分类  内部类的特性  内部类的特征与变量概念特性很相似  内部类的位置与变量位置相似  变量可分为实例变量(成员变量),局部变量,静态变量  内部类与变量相似,也可分为四种  内部类的分类  静态内部类,成员内部类,局部内部类,匿名内部类 不同内部类的实现和使用  成员内部类——MemberInner  举例:写程序MemberInner.

class文件,一个是 MemberInner.变量名则访问外部类的成员 .class文件,它与外部类文件之间相互 独立。  在本类中和其它类TestMemberInner.成员内部类  内部类是一个编译时语法,编译后生成2个.java中分别写主方法测试运行程序分析 内部类的特点和使用  使用成员内部类就象使用成员变量一样,在本类的主方法中则直接使用 成员内部类,不用加上外部类的名字来访问。但在其他类的主方法中要 使用成员内部类则就需要使用外部类.this.class,另一个上MemberInner$Inner.变量名则访问内部类的成员  使用外部类名.内部类来访问。  使用外部类名来访问内部类还因为一个内部类可能有不同的外部类  创建一个成员内部类对象必须先创建外部类的对象,因为成员内部类要 访问外部类的成员  成员内部类可以访问外部类的所有属性  成员内部类中不能定义有静态属性  当外部类的成员与内部类成员,内部类中局部变量同名时,则使用三种 不同方式访问  直接使用变量名则访问局部变量  使用this.class,这2个类文 件是相互独立的,运行时,这2个类是完全独立的2个类。  内部类也是一个类,也有自己的.

属性名/方法名访问,但是在本类中可不用类名.java中分别写主方法测试运行程序分析内 部类的特点和使用  静态内部类与静态方法,静态属性相似,访问静态方法,静态属性用类 名.静态内部类  静态内部类——StaticInner  举例:写StaticInner.java来演示测试局部内部类的使用  局部内部类的作用范围是从定义它开始到定义它的代码块结束  局部内部类若没有定义在本类的主方法中,则不能在本类的主方法使用 .java来测试静态内部类的实现  在成员位置上定义为static的内部类,称为静态内部类  静态内部类类似于静态变量,修饰静态变量的修饰符也可以修饰静态内 部类  在本类中和其它类TestStaticInner.内部类名来访问。  静态内部类中只能访问外部类的静态成员和本内部类的成员  静态内部类中不能访问外部类的非静态成员  局部内部类  定义在一段代码块中或一个方法中的类,称为局部内部类  局部内部类与局部变量相似,不能用访问修饰符修饰,作用范围为定义 它开始到定义它的代码块结束  举例:写程序LocalInner.来访问。静态内部类 也一样,在本类方法中访问则不用加上外部类名来访问,若在其他类的 方法中则要加外部类名.

java中分别写主方法测试运行程序分析内 部类的特点和使用  局部内部类可以访问外部类的成员属性,静态属性  局部内部类可以访问外部类中的final型的局部变量,但不能访问外部类 的非final型的局部变量  main方法中不能直接访问非main方法中定义的局部内部类  虽然在main方法中,无法直接使用局部内部类,但我们可以在主方法 中创建外部类对象,用外部类对象调用包含有内部类的方法来使用局部 内部类。  局部内部类的应用  应用举例:分析和模拟大学安排课程老师的案例  写老师接口 interface JavaTeacher{void teachJava().}  不同老师实现接口  写一个大学类class University来安排课程的老师  写一个测试类来模拟大学安排课程老师  程序有问题,可以不通过大学来获得老师,而在主方法中自己new 老师对象,改进程序,将不同老师实现接口的类放入大学类的方法 中,用局部内部类实现  再思考安排课程老师业务的实现,引入将局部内部类转变为匿名内 部类  匿名内部类  修改前面的大学安排课程老师的程序,改用匿名内部类,演示它的使用 和实现 .局部内部类  在本类中和其它类TestLocalInner.

java来演示和测试主方法中的匿名内部 类使用  匿名内部类的应用  一个类可以继承另一个类,同时实现多个接口  分析下面2段代码—写TestInAbstract.java中分别写主方法测试运行程序分 析内部类的特点和使用  因为只new一次创建一个对象,只有一个对象生成,所以对象名无意义, 则就可以直接将实现写在创建对象处。  匿名内部类不能定义构造方法,因为匿名内部类是一个特殊局部内部类, 它没有类名。  匿名内部类可以访问外部类的局部变量,但也要求外部类的局部变量是 final型的才能访问  匿名内部类可以访问外部类的属性  匿名内部类可以在一个类的方法中创建,同样可以在一个类的主方法中 实现。  写程序TestMainAnymousInner.java .匿名内部类  匿名内部类是一种特殊的局部内部类,局部内部类可以转化为匿名内部 类  局部内部类要转化为匿名内部类必须具备3个条件  首先是一个局部内部类,也是一个私有的内部类  该局部内部类实现一个接口或继承一个父类  局部内部类只new一次创建一个对象  匿名内部类就是无显式地声明某个类名来实现接口,而直接实现接口的 方法的类  在本类中和其它类TestAnymousInner.

java来实现  人Person设计为抽象类  机器设计为接口  机器人实现接口做成匿名内部类 异常的概念和分类  异常是什么  在java中,异常也是一个对象,不同异常则是不同对象;它是程序中出现 的一些意外错误的情况  异常的作用  异常的作用是在程序发生错误时,将损失减少到最小,当然有些错误是不 可避免的,所以异常是为了提高程序的容错性  异常的分类 .匿名内部类  当继承的父类中抽象方法与实现的接口中方法同名,同参数列表,同  返回类型,则子类只写一个方法实现就可以了  当继承的父类中抽象方法与实现的接口中的方法同名,但返回类型不 同,则子类就必须写出每个方法,但这样的方法集同名,返回类型不 一样则认为是同一方法,又不能构成重载,则就会编译出错  利用上面的原则,来分析一个实例机器人问题  利用匿名内部类分析和解决机器人的问题:写程序TestRobot.

cause) cause是异常的原因信息 非RuntimeException CheckedException 非RuntimeException:已检查异常,是不可 避免的,必须处理,若不处理则编译通不过。只 要不是RuntimeException.异常的概念和分类  在java中,对于很多不同的异常都抽象出他们的共性做成为一个 Throwable类  Java中的异常非得是Throwable类的对象,Throwable类是所有异常的 父类,它含有很多的异常子类 exception:是异常,但是可以处理,可以挽  异常的分类结构图 回部分损失的。Exception有几个构造方法。 error:代表的是特 别严重的底层错误, 不能修复,不可避 免。如java虚拟机 崩溃等,这类错误 是不能处理的。error Throwable Exception().Exception(message) message是异常的描述信息 Exception RuntimeException UncheckedException RuntimeException:运行时异常(未检查异 常),它是由于程序员未检查,程序员的疏忽而 导致的异常。这类异常是可以避免的,可以处 理的。当然是可以不处理,即使不处理也可以 编译通过,它并非是编译错误(如少一个分号, 则是编译错误)。对于运行时异常,我们首先考 虑的是避免它,而非处理它。 如:人为火灾—运行时异常 常用方法: 不常用的方法: Exception(cause) Exception(message.则都是非 RuntimeException。 .

异常的产生与传递  异常的产生和传递  举例说明:写程序TestFirstException.java,增加数组访问代码演示异常  IndexOutOfBoundException .java来演示异常  整除除数为0,则抛出一个数学异常  举例加薪申请类比异常处理过程  程序运行一个数学异常抛出,若产生该异常的方法test中没有处理异常, 则异常就会向该方法的上一层main即调用该方法的main方法传递异常, 若主方法也没有处理异常则jvm就中止程序运行  异常的产生和处理  当程序出现错误情况时,会产生一个异常对象;若不处理则异常就会往 上层一个方法一个方法地向上抛,直到main方法,若main方法也不处 理则jvm就中止程序  常见的异常及异常信息  分析刚才除数为0的异常信息分为2部分  说明异常情况:异常出现在第几行,2个位置都有说明了异常的传 递  指出异常对象:指明产生的异常对象的名称 ArithmeticException算 术异常  算术异常——ArithmeticException  数组下标访问越界  修改程序TestFirstException.

java程序,增加类型转换代码演示异常  ClassCastException  数字格式化异常  修改TestFirstException.常见的运行时异常的处理  对象空指针异常  修改TestFirstException.java程序,增加数字格式化代码演示异常  NumberFormatException  常见的运行时异常的处理  运行时异常常见的就是前面的五种,这些异常在Eclipse中编译时不会报 出红色错误提示,没有红色提示错误异常也产生了,这样的异常就叫运  行时异常(未检查异常)。有红色提示错误的异常就是已检查异常  运行时异常因编译通过,没有任何红色提示,在程序中很危险,很容易 造成程序中止  运行时异常很多是由于程序员的疏忽引起的,它们是可以避免的;所以 对于运行时异常,程序员要尽可能地避免而不是出现异常后去处理,避 免比处理效率高。  修改TestFirstException.java程序,增加空指针访问代码演示异常  NullPointerException  对象类型转换异常  修改TestFirstException.java程序,将五种常见的运行时异常处理了 异常对象的创建与传递: .

EOFException是非 RuntimeException,必须处理,否则编译通不过 异常的处理  异常的处理,在java中有2种方式 .EOFException),发现程序报错  NullPointerException是RuntimeException,可以不处理,也能编译通过  FileNotFoundException.java的NullPointerException的传递过程是: mc→mb→ma→main→jvm  Java中的异常必须是Throwable类或其子类类型,但不能是简单类型或 String  修改程序TestException.java来演示      在方法mc中生成异常对象 new 异常类名().  在mc方法中抛出异常使用throws 异常对象的创建  异常也是一个对象,使用new 异常名()来生成异常对象 异常的抛出  在程序中,程序员抛出一个对象使用 throw new 异常类名().异常对象的创建与传递  写程序TestException.SQLException.SQLException.  使用throw来抛出一个异常则程序就会返回一个异常对象 异常的传递  异常的传递是沿着方法调用链返向传递的  程序TestException.java,增加其他三个异常 (FileNotFoundException.

SQLException  main方法使用throws throws Exception .SQLException  ma方法使用throws throws IOException.将异常向上抛  throws 处理异常  throws异常处理也称消极处理,实质上没有做处理  它将产生的异常向上抛出,自己并不做实质的异常处理,但这种向上 层抛出异常的在java中被认为是处理了异常,所以编译可通过。特别 是已检查异常,必须处理,采用throws也算处理了已检查异常,程序 编译就可通过  修改刚才出错的TestException.Java异常的处理  捕获处理:一种积极的处理——try{…} catch(Exception e){…}  矛盾转移:一种消极的处理——throws Exception名.EOFException.SQLException  mb方法使用throws throws FileNotException.EOFException.java使用throws处理三个已检查异常  每个方法声明的第五部分就是抛出异常,本方法出现了异常,而本方 法不处理,将它传递给上层,这就是java处理异常的一种方式  mc方法使用throws throws FileNotFoundException.

Java的异常处理  对于运行时异常可以不使用throws处理,系统也会自动向上层抛的。 比如程序中throws异常处理并没有处理NullPointerException  未检查异常(运行时异常)可以不使用throws/try-catch处理,系统 会自动向上抛出的  已检查异常则必须处理,可以使用throws向上抛来处理,也可以 使用try-catch来处理  throws向上抛出异常是可以实现多态的,抛出父类异常  比如程序中ma方法抛出IOException.java来演示throws的使用 .EOFException.是 FileNotFoundException.SQLException的父类异 常;main抛出Exception是其他所有异常的父类异常  throws处理其实所有方法都没有做实质的异常处理,但在java中认为 处理了,可以编译通过,但运行结果与先前没有处理异常一样,这是 一种消极地处理方式。  为什么要用throws?  throws具备try-catch不具备的特性和功能  举例:电子商务系统的会员注册模块和商品购买模块,都会有 SQLException,但处理方式不一样  在java的jdk中大部分的异常都是采用throws的方式向上抛出,抛 给上层用户处理  写程序TestThrows.

}catch(Exception e){.}finally{.Java的异常处理  try-catch处理  一种积极处理方式,叫做捕获异常  try-catch处理异常都使用异常处理块  try{.java程序,分析异常的try-catch处理  分别分析有异常和无异常发生时的程序运行情况  catch捕获异常是从上到下匹配的,而且catch只能捕获一次,捕 获后处理完就不再调用其他的catch子句,而执行catch后的代码  在catch捕获异常时,是允许catch捕获多个异常子类,也允许捕 获父类异常来代替多个捕获子类异常 .java来演示try-catch-finally的异常处理  try-catch-finally的异常处理机制  首先执行try块中的程序代码,当出现异常时,会中断执行异常 后面的代码,转入到catch块中执行处理异常的代码,异常处理 完后再执行finally块中的程序代码  异常的处理可以分支处理 无异常发生时,则执行try-finally块 有异常发生时,则执行try-catch-finally块  修改TestException...}  try块中写可能出现异常的程序代码  catch块中写异常处理代码  finally块中写一定要执行的代码  在异常处理块中,try出现1次,catch出现0-n次,finally出现0-1次  当catch块为0次时,finally块必须出现1次  写程序TestTry..

Java的异常处理  允许同时捕获父子类异常,同时捕获父子类异常时,则必须将子 类异常放在父类异常的前面,否则会编译出错  修改程序TestTry.在catch执行return 之前一定会执行finally块的代码  在catch块中使用异常对象的printStackTrace()方法可以打印抛出 异常对象的堆栈信息,它包含了异常的详细信息  修改程序代码,增加捕获空指针异常 在捕获Exception之前捕获NullPointerException,编译允许 在多个catch中的异常变量可以同名,因为他们是局部变量e 编译运行时不会捕获空指针异常,因程序不会发生该异常 catch是从上到下捕获的,一旦捕获就不会再捕获了,只捕获 一次 在捕获Exception之后捕获NullPointerException,编译不允许 NullPointerException在Exception就永远不会执行了,java中 不允许出现这样的情况,所以异常捕获一定要先父后子  修改程序代码,将catch中的代码全部注释了,发现编译并不出错, 但这样不合理,异常捕获了就要处理,否则不如不捕获  再次修改程序代码,只留下捕获空指针异常,发现编译通过但运 行时异常并没有被捕获,还是给了jvm,jvm将程序中止了。  异常捕获是要匹配catch后的异常类型,不符合类型则无法捕获 .java演示异常处理  Try块中若需要返回值,则try-catch2个语句块都需要返回值  运行程序发现,不发生异常时执行try块中的return之前一定会执 行finally块的代码  发生异常时,执行try块到异常处,执行catch.

} 并没有catch捕 …. 获,所以还可 catch(异常){ }catch(异常){ }catch(异常){ } 以throws将异 …. 第三种形式中 try{ try{ try{ try{….catch中的return  若return后面跟的是一个方法,则会先调用方法再return方法的返回值  当try块中没有发生异常时,执行完try块,再执行finally块  当try块中有异常发生时,则执行到发生异常处,跳转到catch处理, catch执行完了后,才执行finally块  finally块中的代码一般都写释放资源的代码,因为无论是否正常执行, 都要释放资源。 这三种形式可 try{ 以嵌套的,而  try-catch-finally异常处理的形式 ….Java异常处理的finally块  try-catch异常处理的finally块  写程序TestFinally. 在返回前则要 }catch(异常){…} 先执行finally代 finally{….} } 码再返回停止。 . …. …. finally{ 常向上抛,但 } } } ….java来演示分析finally的使用  finally{}块的代码必须写在所有catch子句的后面  finally{}块中代码会在return之前执行,而且一定会执行  若finally中有return语句,则会屏蔽掉try. …. ….

java,在mc方法中给异常封装异常信息  throw new NullPointerException(―空指针异常”) .Java异常处理的finally块  写程序TestFinally1.catch中的return  修改程序TestFinally1.来构造,设置父类Throwable的message  一般使用throw创建异常对象时,会传一个字符串参数来描述异常信息  修改程序TestException.java来演示finally的作用  测试程序,当不同的a值,则运行结果不一样  执行return之前一定会执行finally块  finally中的return会屏蔽掉try.java,在finally块中添加打印语句  运行程序发现finally中的打印语句一定会执行  调换finally块中代码顺序,发现打印语句不一定执行了,如何解 决这样的问题——使用嵌套的try-catch-finally块  异常描述信息  在Throwable类中有一个String message属性,任何一个异常都有String message的属性  message属性是表示该异常的描述信息。在很多Exception的子类的构造 方法中都有message参数,所以这个异常描述信息message可以通过构 造方法将信息作为参数传给异常构造方法构造异常;而这个参数在本类 构造中是没有用的,是将这个参数传给父类的构造方法使用,所以采用 super(message).

getMessage()).  异常的printStackTrace()方法可以打印出异常的堆栈的详细跟踪信息,可 以指出异常的产生位置,异常类型,第一次上传处,第二次上传处等等  有异常的方法覆盖  写程序TestExceptionOverride.Java异常描述信息  throw new FileNotFoundException(―文件没找到异常”)  throw new EOFException(―文件结束异常”)  throw new MyException(―我自己定义的异常”)  在Throwable中,有一个方法getMessage(),该方法就是获得异常描述 信息message的,在catch中,要打印出异常的message,则使用 System.println(e.out.java来演示有异常的方法覆盖  修改程序以不同情况出现,则方法覆盖情况也不一样  抛异常方法的覆盖要求子类抛出的异常范围不能比父类抛异常的范围宽  父类抛什么,子类抛什么  允许父类抛,子类不抛  允许父类抛的多,子类抛的少  不允许父类不抛,子类抛  不允许子类抛一个父类没有抛的异常  自定义异常 .

} } class MyException extends RuntimeException{ public MyException(){super().} } .Java的自定义异常  什么是自定义异常  程序员自己定义的一个异常类,而非java中的异常类  如何进行自定义异常  写一个类继承异常父类  若是一个已检查异常则继承Exception  若是一个未检查异常则继承RuntimeException  在自定义异常类中提供2个构造方法  无参构造  有参构造:有message参数的构造 class MyException extends Exception{ public MyException(){super().} public MyException(String message){super(message).} public MyException(String message){super(message).

java来演示自定义异常的使用,实现Person 的age属性在设置时控制年龄范围在0-130之间,若没有在这个年龄范围 则抛出AgeException异常  第一次抛出异常的组件或方法一定会用throws来将异常抛给调用者,由 调用者来处理  抛出异常尽量抛具体异常也是为了以后可以覆盖或重写  虽然自定义异常不常用,但这个思想很有用,有助于学习后面的课程  异常使用的思想  怎么控制try中的代码行  举例说明try中代码的要求  在try块中放一些关联语句操作  throws什么时候用?try-catch什么时候用?  throws和try-catch配合使用,通过throws将异常传递到应该处理的 地方使用try-catch来处理  产生异常的方法不能用try-catch来自己捕获,不合逻辑  当自己不能处理时,则throws向上抛,当能处理时则应该处理,用 try-catch捕获处理  有些异常是必须要处理的,若无法处理则再throws向上抛 .Java的自定义异常  在适当的时候,需要用throws来抛出一个异常对象  写程序TestAgeException.

则会抛出这个异常  以上四个异常类有一个共同的父类 BusinessException并妥善的处理这些异常 .例如密码两 次输入不一致等情况  LoginException:用户登录异常的情况.自定义异常的应用  作业:为BAM添加几个异常类  BalanceNotEnoughException :用于取钱的时候余额 不足的情况(包括账户余额超过透支额的情况)  BalanceSmalerZeroException:用于存取钱为负数的情 况  RegisterException:用于开户异常的情况.如果用户试图将贷 款额置为负数.例如id错误.密码 错误  LoanException:贷款额不能为负数.

Java中断言的使用  断言的使用  写程序TestAssert.4 文件名.java 来编译断言  断言的运行使用 java –enableassertions(-ea) 类名来运行断言  断言的应用  有了断言,在程序开发中主要用断言调试程序的,调试完后是要将断言 语句删除的 .java来测试断言的使用  什么是断言  断言是java1.4以前不支持  断言的程序使用 javac –source 1.4后才支持,1.4新加入的,断言可以用来调试程序,调试程序时用断言, 而调试完了则将断言删掉  怎么使用断言  assert 布尔表达式 : String字符串  布尔表达式成立则断言自动执行  布尔表达式不成立则断言会抛出一个错误AssertionError  若要给断言添加描述信息,则在冒号后面加上:断言描述信息字符串  当断言不成立时则会现实断言的描述信息  使用断言修改程序  在打印语句前增加代码: assert a%2==0 : ―a必须为偶数”  断言如何编译和运行  断言的程序是jdk1.

Day09  理解java集合的选择和作用  掌握java中集合框架体系结构  掌握不同集合的特性和实现原理  List的三种实现及特性  Set的实现及特性  Map的实现和特性  掌握不同集合的使用和应用  List的常用方法和应用  Set的常用方法和应用  Map的常用方法和应用 .

集合的作用和选择   什么是集合和集合作用  集合也是对象,可以用来管理,存储其他对象,作用类似于数组,类似于c++ 中的容器,也相当于一种数据结构  在java中,集合就是采用封装数组的方式,将常用的数据结构,方法封装成不 同的子类,并封装好这些类的方法,程序员使用时就可直接封装好的类来操作, 简化编程,非常方便  为了更好地应用这些类,又将这些封装好的类的共性抽象出来作成一系列的类, 接口;这些类,接口统称为集合框架;集合框架是管理其他多个对象的对象 集合的选择  集合框架有很多不同的集合,集合是用来存储管理对象的,那么根据存储对象 的特性则选择的集合也不一样,集合的选择也是一门学问  如:存储年龄 int基本类型 用int[]数组;存储同学 对象类型 不重复 用Set存  如:存储上网注册用户 需要发送序号与学生键值对 用Map存储  如:存储姓名 可以重复 用List存  如:从DB中读出学生信息,则不需要将其与序号对应,不用Map,可以用 List/Set存储,List是有序的,Set是无序的  集合框架体系  集合框架体系包含有很多的集合接口和实现子类 .

5.key是无序的,且不重复.value存储 Object.1.3.而且单词是按字 实现类:TreeMap 母顺序排序的。 又如:新华字典 字是按照汉字拼音排序的 接口:Map . List:是Collection的子接 元素可能是无序的。 接口:Collection 口,它管理多个对象时, Set:是Collection的子接口, 多个对象是有序的,这里 它类似于数学上集合概念, 的有序最初是指插入顺序,子接口:List 子接口:Set 元素是无序的,元素不可重 元素可以重复 复的,所以Set是无下标的, 实现类:HashSet 遍历时则不能用下标来操作 如等比数列:1,2,4, LinkedHashSet 8,16….排序可以有排序规则的。 例如词典 单词与解释就是键值对.元素位置是不 子接口:SortedSet SortedSet:是Set的 能随便更换的。 子接口,是排序Set 实现类:ArrayList 又如纳波约契数列: 实现类:TreeSet 接口,实现它可以按 Vector 1.value可重复 子接口:SortedMap SortedMap:是Map的子接口,是排序Map接口, 对key排序的Map.8…元素可以 照一定标准来排序与 LinkedList 重复 插入顺序无关 实现类:HashMap LinkedHashMap Map:Map接口用来存储具有键值对特性的数据keyvalue;比如英文词典,单词为 key,解释为value; 实现类:HashTable key可存贮Object.集合框架体系  集合是存储对象的,它也有像数组一样的操作对象的方法,这些方法与DB操 作相同,有增,删,查,改等方法 Collection:每个元素都是Object..2.

集合框架体系  集合的实现类有很多是Linked的,加了Linked的实现类,比如:LinkedList,  LinkedHashSet,LinkedHashMap  加了Linked的实现类的底层是用链表来实现的,链表的特性是增删快,查询慢, 在内存中链表是一块一块的不连续的空间。在项目中对于遇到增删频繁,查找 少的情况,则选用加了Linked的实现类操作。  举例说明:比如银行管理系统的日志管理,每个用户操作后都会生成日志,无 论用户是否打印凭条,日志都会产生,但是真正去查看日志的用户很少。所以 是增删多,查询少的情况,使用加了Linked的实现类。  除了Linked以外的实现类之间的区别  List的实现类ArrayList和Vector的区别  ArrayList:高效,不安全,不能支持并发 它是jdk1.value都不允许null 不同集合的特性,实现和使用  List接口及其实现类  List接口  查看API,查看List常用的方法 .3之前,使用Vector,很多老 的java用户则使用它  Map的实现类HashMap和HashTable的区别  HashMap:高效,不能支持并发,key.3推出的,尽可能 使用它代替Vector  Vector:低效,安全,支持并发 在jdk1.value都允许null  HashTable:低效,支持并发,key.

object)在index位置插入元素,List是有序的,可有以 索引位置记录元素在List中的位置,索引是从0开始的 addAll(集合)增加一个集合所有元素到本集合中  删除 clear()清除集合的所有元素,即全删 remove(Object)删除最后一个元素 remove(index)删除index索引位置上的元素  查询 contains(元素)判断集合中是否包含该元素(该方法要正常实现则 元素类型需要符合equals方法指明相等判断的标准,才能判断是 否包含) get(index)取出index指定位置上的元素 indexOf(元素)返回参数元素在集合中的索引位置 isEmpty()判断集合是否为空  修改:set(index.List接口的特性,实现和使用  增加 add(object)在最后追加元素 add(index.object)将原有元素替换覆盖了  查看API,List的简介 .

add(3)实际上加入的是new Integer(3)对象,这里是一个自 动封箱特性  集合list的元素的下标是从0开始的  调用get方法是调用的实现子类ArrayList的get方法,这是一个 多态特性  打印obj会自动调用obj的toString()方法来打印其返回值  打印obj时有多态,实际上打印的是String.Integer的toString方 法的返回值 .而非元素重写;hashCode是否重写由不同集合实 现类决定List接口继承了Iterable接口,Iterable接口是可迭代接 口,实现了可迭代接口的类则可以通过迭代器来迭代访问元素。  List中的iterator()方法则是获得集合的迭代器;size()方法是求 集合中元素个数  List接口中的方法中的E代表是泛型,这里可以理解为Object类 型  List的第一种实现——ArrayList类  ArrayList实现了List接口,则就实现了List的方法,我们可以使用这 些方法  举例:写程序TestList.List接口的实现类ArrayList  List接口重写了equals和hashCode方法;equals重写是指集合 实现类重写.java来演示ArrayList的使用;程序中的几个注 意问题  接口=new 实现子类对象 这里是一个多态特点  list.

List接口的实现类ArrayList  集合使用泛型  想要集合专门存储特定类型的数据则可以使用泛型  泛型是jdk5.0之后才支持  修改TestList.java程序代码,使用泛型 将list修改为只能存储String类型的元素:List<String> list=new ArrayList<String> ().RandomAccess接口 1、ArrayList实现了Iterable接口,则表明ArrayList对象可以使用 迭代器来迭代访问 Iterator接口是迭代器接口,迭代器有3个方法来进行迭代 (1)hasNext():返回集合中是否还有元素可迭代;返 回true则可迭代,返回false则不可迭代 (2)next():返回当前迭代指针指向的元素 (3)remove():删除迭代器指针指示的最后元素 .不需要使用Object  在项目中很多情况是需要使用泛型指定元素类型的;比如从DB 中把学生表的信息读取出来,放入ArrayList中,那么学生表里都 是学生对象数据,没有其他类型,此时写代码时最好使用泛型: List<Student> list=new ArrayList<Student>().0推出的,只有jdk5.add(3)报错,因为3不是String,将该语句注释 取元素时则可将代码改为String str=list.Collection.get(i).  API中的ArrayList类的介绍  ArrayList实现了List,Serializable(对象序列化),Cloneable, Iterable. 修改后发现:list.

length) 来 拷贝旧数组内容到新数组 .)方法, 在ArrayList中的add.java来迭代访问元素.elementData.List接口的实现类ArrayList 写程序TestArrayListIterator.5的实现是2步,先new一个新数组给elementData, 再 使 System.)方法实现,按新的 容 量创建新数组,再将原数组中的东西拷贝到新数组 jdk1.6的实现:使用Arrays.copy(oldData.oldData.0..在程序中方法参 数为Collection类型,这是一个多态特性 2、ArrayList实现了Cloneable接口,表明ArrayList可以克隆,在 ArrayList中有一个clone()方法,该方法只是在当前层上的克隆 3、ArrayList实现了RandomAccess接口,RandomAccess是随机 访问接口,正是因为实现了该接口,所以ArrayList可以使用get()来 取得任意位置上的元素。  ArrayList的构造方法与增长实现 1、ArrayList()默认构造10个元素的容量 2、放入第11个元素时,不会有问题,ArrayList会自动增加容量的 3、ArrayList为什么会自动增容?得分析ArrayList的源码文件 (1)ArrayList的底层实现是用Object数组实现的,所以 ArrayList只能放Object类型,不能放其他基本类型,而且 是有序的,因为数组元素排列有序的。 (2)数组是定长的,默认情况10的容量是由有参,无参构造 实 现的 (3)数组是定长的,实现增容是调用ensureCapacity(.addAll()等都调用了ensureCapacity() 方 法来增容 (4)ensureCapacity方法的实现 jdk1.arrays.copyOf(.0..

List接口的实现类ArrayList 4、ArrayList的增容效率低,尽量少增容 在写程序/应用时,要尽量少使用ArrayList去增容,因为增容 很耗资源,效率低;如果能确认一个应用的ArrayList的容量则在 构造时就一次分配足够的空间,无需以后再增容 举例:写程序TestCapacity.方法是获得毫秒数,该毫秒数是 指系统当前时间距离1970年1月1日 0小时0分0秒0毫秒的毫秒差  List中元素的排序 1、举例:写程序TestListSort.java来测试使用无参和有参构造 的ArrayList对象存储10万个对象的效率对比 System.java程序代码,给list添加4个Integer的对象, 同样使用Collections的sort来排序 3、Collections的sort方法的排序实现原理 修改程序TestListSort.sort(集合)来排序 2、Collections是集合的工具类,在这个工具类中所有方法是静态 的,这些方法可以直接用类名调用 Collections的sort(list)方法是实现对List的元素排序 修改TestListSort.Integer类的对象可以排序是因为他们的比较规则 已定义好了,他们可以比较 .java来演示List的排序 使用Collections.java代码,给list添加4个Student对象, 发现使用sort并没有实现排序学生对象的功能,为什么呢? (1)排序一定要做比较操作,比较2个对象,如果是自定义 类型,那么要比较自定义对象,而自定义对象如何比较,比较规 则标准,Collections并不知道;因比较规则是由自己来决定的 (2)String.currentTimeMillis().

消耗资源多.java 中 的 Student 类 , 增 加 实 现 Comparable接口的compareTo方法;实现以下几种排序: 以年龄升序排序;以年龄降序排序;以姓名升序/降序排序;先 以年龄升序排序,年龄相同以姓名升序排序  List的另一种实现——Vector  Vector也是实现了List接口,所以无需关心Vector的方法,只要知道了 List接口定义的方法即知道了Vector的方法  ArrayList 也 是实 现 了 List 接 口 , 知道 了 ArrayList 的 方 法也 就 知道 了 Vector的方法,这就是学习java的面向对象的思想  Vector与ArrayList的异同  相同点:采用数组来实现,有序的  不同点: Vector:重量级.访问速度慢.但线程安全.支持并发 ArrayList:轻量级,消耗资源少,访问速度快,线程不安全,不 支持并发 .List接口的实现类ArrayList (3)比较规则如何实现呢? 实现Comparable接口的compareTo的方法,在compareTo方 法中规定了比较规则; Collections的sort方法是采用接口回调方式来排序的,sort方 法中会调了一个标准接口Compare中compareTo方法来比较元素 要想能排序自定义类的对象,则我们要在自定义类实现 Comparable接口并实现compareTo方法来指定比较规则;当实现 了该接口的该方法则sort排序自定义对象时会回调compareTo方 法来比较自定义对象 修 改 程 序 TestListSort.

List的第三种实现类LinkedList  什么是线程安全与不安全? 当多个线程并发地去访问ArrayList或Vector中的元素时, ArrayList可能会出错,而Vector则不会出错  List的第三种实现——LinkedList  LinkedList的实现原理  LinkedList的底层是采用的链表实现,更准确地说是采用双向循 环链表实现  LinkedList实现了List接口,所以对于它的方法我们也无需关心, 只要知道List的方法就可以了  LinkedList与ArrayList的比较 1、LinkedList:用链表实现,链表的结构实现插入,删除是比较 快的,而查询是比较慢的,因为只知道链表头,所以每次查询只 能从头开始找,LinkedList更适合用在增删多,查询少的情况 举例:Stack栈只有一个出入口即栈顶,他就是只有增删操作而 无查询操作,因为对于栈只能在栈顶操作。Stack就最好采用 LinkedList来实现 2、ArrayList:用数组实现,数组在内存中是一片连续的空间, 对于数组,查询非常快,直接使用下标就可以访问,但数组的插 入,删除很麻烦,需要移动大量元素,很慢。所以需要大量地移 动元素更适合用在频繁地查询,很少地增删情况 .

java来演示如何实现栈  Set的实现和应用  Set接口介绍  Set接口是继承Collection接口的,所以只要知道Collection接口的方 法,则就可以知道Set的方法 .List的第三种实现类-LinkedList 举例:管理一个班的学员信息,更多地时候是查询,而插班生, 转班生是比较少的情况,这样就可采用ArrayList来管理  想要实现栈Stack,常见的方式有三种:数组,ArrayList,LinkedList, Stack,哪种实现最好?  数组,ArrayList:增删慢,效率低,一般都不用数组; 很多研究生会选数组,研究生的项目一般是研究性项目,而非应 用性项目,所以不考虑效率,一般就用数组实现,但在企业中不 是这样的  Stack:java中的一个封装好的线程栈类 Stack类的底层实现也是采用数组来实现的,第一,Stack类是 Vector 的子类,Vector用数组实现效率低;第二,Vector类中的有些方法 是不能应用在栈中的,而Stack是继承了Vector,所以它会无条件 地 全部继承复用Vector中所有方法,这样Stack就有了很多不应该有 的 方法,这非常不合理,这是sun公司中的组合/聚合复用的一大反 例。 实现栈不用java封装的Stack线程栈类  LinkedList:采用它是实现栈是最好的,效率高。那如何实现呢? 使用LinkedList来封装一个MyStack类,在类中维护一个 LinkedList对象作为属性,采用组合/聚合原则实现复用,不要继 承复用来实现。写程序TestMyStack.

java来测试演示Set的的无序和不重复  举例:写程序TestSet2.Java的Set接口  Set接口的实现类有HashSet,LinkedHashSet,Set有一个子接口 SortedSet,SortedSet接口的实现类为TreeSet。  Set接口的方法  增加  add(E) 在集合的最后添加元素  addAll(Collection) 将另一个集合的所有元素添加到本集合中  删除  clear()清除集合中所有元素  remove(Object)删除集合中的Object元素  removeAll(Collection)删除集合中另一个集合元素组  其他常用方法  isEmpty()判断查询是否为空  equals()判断2个对象是否内容相等  hashCode()求一个对象的hash码值  Set中没有查找方法,这是与Set的特性有关的  Set的特性  Set存储元素是无序的,无法直接获取指定元素,要取得Set中的元素必须 要使用迭代器,像List的迭代一样  Set中的元素是不允许重复的,这里的不重复是指元素的内容不重复  举例:写程序TestSet1.java来演示泛型在Set的应用 .

Set的实现类——HashSet  Set的迭代不像List既可以用for循环+get(),又可以用迭代实现,Set是 无序的,只能使用迭代,迭代比较麻烦,代码繁琐。有没有更好地办 法解决呢?使用jdk5.java,将迭代代码改变为使用foreach循环  for(String ss: s)System.75=12个;存储到12个则就到加载因子指示的位 置了,存放第13个时就增容了,本来要存16个,但现在打折了存 12个就要增容了。  HashSet的有参构造可以自定义设置初识容量和加载因子的  HashSet达到了加载因子指示的位置后如何扩容呢?它是以2倍的容量 扩容的。  HashSet如何过滤重复元素? .  foreach循环支持所有集合,所有数组,他们都可以用foreach来访问  foreach的语法格式:for(元素类型 元素变量名:集合/数组名)  Set的实现之一——HashSet:我们查看api文档来分析HashSet  HashSet并没有实现RandomAccess接口,所以它不能随意访问,没 有get方法  HashSet的底层实现是由HashMap来实现的  HashSet的无参构造初识容量为16,即可存储16个元素;后面给出了 一个加载因子说明,加载因子为0.println(ss).0之后都不支持  修改程序TestSet2.out.75  加载因子的概念是什么?类似于商品的打折意思,只要HashSet 存储元素个数超了加载因子指示的位置则就增容了。比如初识容 量16,那么16*0.0之前,5.0使用, 5.0的新特性——foreach循环  foreach循环其实它的底层也是用迭代器来实现的,这个特性只能在 jdk5.

equals方法 3、equals()方法是用在判断对象内容是否相等,不一定一定是在 Hash算法中 4、Hash算法判断元素重复的步骤 调用元素的hashCode() 比较哈希码 哈希码无重复则直接存入 获得哈希码 比较哈希码 判断内容是否相等 哈希码重复 则调用equals()方法 判断内容是否相等 内容相等则不存入丢弃掉 内容不相等则另外再次 计算hashCode再存入 .HashSet如何过滤重复元素  HashSet是基于Hash算法(哈希算法)来判断,保证元素不重复。 Hash算法在低层仍然是采用数组实现的  HashSet的Hash算法实现原理 Hash算法的原理首先对每个对象调用hashCode()方法,这个方 法是Object的方法,该方法的返回值为哈希码;然后由哈希码根 据数组长度取模来得到该元素放在数组中的位置。 举例说明:将s1-s6放入6个元素的Set,分析存放过程 1、在HashSet中,判断元素是否重复要使用hashCode().equals() 方法 2、只要使用Hash算法,无论是否是HashSet,则都要用 hashCode.

equals方法。 并且实现时要保证内容相同的2个对象的Hash码一样。 8、HashSet保证元素内容不重复,必须按下面要求设计 (1)覆盖hashCode()方法,保证内容相同的对象返回 相同的hashCode码,这样才回再调用equals方法 (2)覆盖equals()方法,保证内容相同对象调用equals() 方法返回true .s3.equals() 方法,因为在项目中常用 HashSet,所以写一个类一般 都要覆盖Object的 hashCode().s1等,看 似有序,但这个有序是指在底层数组中的位置,但这个数组中存 放元素的顺序是由哈希码决定的,是随机不定的,它与插入的元 素顺序是不一样的,我们说是无序的 7、对于Hash算法而言,不是一定要调用equals方法来判 断对象内容是否相同,是有前提条件的,条件就是当2个 对象的哈希码相同时,才会调用equals方法来比较2个对 象内容是否一样。所以若使得2个内容相同对象的 hashCode不一样,则就它们可以插入到hashSet中,这样 就出现了2个内容相同的对象在一个hashSet中,那么如何 解决?要求我们在自定义类中覆盖hashCode.equals方 法,再次运行发现不能放入重复元素 6、从以上的Hash算法原理可以看出,底层也是数组实现 的,所以遍历时以这个数组从上往下遍历,得到s2.java,添加Student对象给set,发现可 以 重复,然后再修改Student类,增加hashCode.Hash算法的特点和实现原理 5、有了Hash算法,我们写一个类,如果需要将其对象放 入HashSet中,则一定要覆写Object的hashCode().equals()方法。 修改程序TestSet1.

java来演示hashCode().java程序,增加String存入HashSet的代码测试  写程序TestPerson.}则对于其他 内容不同,而年龄相同的对象而言,也会调用equals方法来比较, 这样也降低了效率,所以尽量不要这样做 10、使用String作为HashSet元素时,并没有覆写 hashCode.Hash算法的特点和实现原理 (3)内容不同的对象允许返回相同的哈希码,这样的 情况是存在的; 例如:哈希码是int型的,它的范围是-2147483648到 2147483647,若现在有4294967296个对象,则肯定 有2个对象的哈希码一样; 又如:13个人中肯定有2个人的生日月份一样;3个 人中肯定有2个人的性别相同 (4)当对象数量已超过哈希码的范围时则不同内容的对 象允许返回相同的哈希码 9、尽量是内容不相同的对象的hashCode不同,这样就避免了 equals比较,提高了效率 例如:有s1-s4的4个对象,他们内容相同,若覆写hashCode方法 int hashCode(){return 0.equals()方法的使用情 况 .equals方法,也实现了保证元素不重复,这是因为java 中jdk的很多类已经覆写了hashCode(),equals()方法。 修改TestSet1.}则每个对象调用都返回0,于是每次每个 对象都会调用equals()方法来比较对象内容,对于内容不同的对象 也比较,所以这样效率很低 又如实现hashCode方法:int hashCode(){return age.

out.out. 运行后发现 先打印”ccc‖再打印”Hash Code id‖,这说明HashSet在存放元 素时才会调用hashCode()方法 .setId(4),运行结果”equals id‖并没有打印,说明 在hashCode不同情况下equals方法不会调用;这里”Hash Code id‖打印了2遍,为什么?是因为打印hashSet时会打印元素的16进 制的hash码,所以又调用了一遍hashCode方法 2、在set.println(―equals ‖+id).println(―ccc‖).out.equals()方法何时调 用,调用多少次? 在hashCode方法中增加第一句:System.add(s1)之前加入System. 修改TestPerson.Hash算法的特点和实现原理 写class Person类(id,name属性);写TestPerson类,用 HashSet来存储 1、第一次Person覆盖hashCode方法直接返回id值作为哈希码, equals方法只用id来判断,id是判断条件,观察运行结果;发现打 印set则打印出元素,这说明HashSet覆盖了toString()方法 2、第二次Person覆盖hashCode方法,使方法始终返回9, equals方法不变,观察运行结果 3、第三次在第二次基础上,只修改equals方法,使得equals方法 永远返回true,观察运行结果 4、第四次使得hashCode返回id值为哈希码,equals方法仍然为 第三次的equals,观察运行结果  修改程序TestPerson. 在equals方法中增加第一句:System.java的程序代码: 1、修改为p4.java来演示hashCode().println(―Hash Code ‖+id).

equals会调多少次 第一个元素放入时,调用1次hashCode;第二个元素放入时调1 次hashCode,调1次equals;第三个元素放入时调1次hashCode, 调1次equals;第四个元素放入时,调1次hashCode,调1次 equals 再修改程序,将equals方法还原为比较id,hashCode仍可以返回 9为准,运行结果是:放入p1时则调1次hashCode;放入p2时调1 次hashCode,调1次equals;放入p3时则调1次hashCode.调2次 equals;放入p4时则调1次hashCode,调3次equals 4、只要HashSet调用add则会执行hashCode方法,所以HashSet执 行add的次数则为执行hashCode次数;调用equals的次数则变化 较多,但原则是每放入一个元素,若需调用equals则必须与集合 中已有的每个元素都要比较 p1-p4对象的产生new Person()得到的,他们是在堆空间分配了4 个Person空间,与hashCode无关;只是放入HashSet时会与 hashCode有关,那么放入Set时放入的是指针而非真正的对象。 因为对象在堆空间,所以指针放入的位置是由hash算法来计算, 那么我们要弄清楚对象,HashSet,引用之间的关系,我们需要 画一个内存的结构图 .Hash算法的特点和实现原理 3、HashSet已覆盖了toString(),所以打印HashSet则就是打印其 元素,而元素对象没有覆盖toString()方法,打印元素为“类型@ 地址”,地址在java中是16进制的hash码,那么要取得hash码则 必须调用hashCode()方法 修改程序,将hashCode()方法设置为都返回9,equals方法始终 返回true,那么调用hashCode.

java程序中,我们曾设定 p4.setId(3),hashCode返回 id,equals返回false的情况。 6、当hash值一样,equals方法返回true,那么该元素是丢弃还是替 换?HashSet是丢弃,hashMap是替换。 修改程序,hashCode返回id,equals以id作为比较条件,设置 p4.HashSet的内存结构图 5、HashSet的内存结构图:以TestPerson.setId(1);在程序中使用foreach循环打印发现运行后打印出了 ZhangJC,这说明打印的是p1而非p4,p4被丢弃了 .java为例 栈 set p1 p2 p3 p4 堆 指针1 指针2 指针3 指针4 new Person() new Person() new Person() new Person() new HashSet() 指针中存放的引用p1-p4的地址,具体存放 哪个地址引用地址由hash算法决定。在 TestPerson.setId(3),hashCode返回id,所以p4 与p3的hash值一样,调用equals;若 equals方法返回true则p4丢弃,若 equals方法返回false,则还会重新计算 hash码,在set中找一个位置放p4。我们 演示一下,p4.

java来演示TreeSet的使用 运行程序后发现打印出的元素已经排序了 .SortedSet的实现类-TreeSet  Set的子接口SortedSet及其实现TreeSet  SortedSet接口——Set的子接口  SortedSet是Set的子接口,它是可排序接口,实现SortedSet接口 的Set是可排序的  SortedSet的可排序不代表是add加入顺序;它可以按照某个属性 来排序,但并不代表是放入顺序 例如:全班每个人有学号,已经按学号编排好了位置,早上来时, 就直接按编好的位置入座,但是早上来的顺序不是按学号来  SortedSet是Set的子接口,必然SortedSet也要保证元素不重复  SortedSet的实现类——TreeSet  TreeSet是基于二叉树算法来存储的  TreeSet实现SortedSet接口,那么TreeSet是可排序的,所以 TreeSet是基于排序二叉树的算法来存放元素并且排序元素的  TreeSet的二叉树排序存储是如何实现的呢? 以1作为根 这个二叉树 不平衡,每 放入一个元 素后比较次 数较多 例如 3 2 4 1 5五个数,用二叉树来存放并排序,如何做? 1 3 以中间值作为根, 以3作为根 2 4 然后每一点从根 这个是平衡二 2 3 叉树,每放入 1 开始比较,根据 5 4 一个元素后比 大小放入二叉树 较次数较少, 5 中 效率高  写程序TestTreeSet1.

add(14),来演示 TreeSet不允许重复元素 运行后,发现打印出只有一个14,则没有出现重复元素 1、TreeSet存储元素要排序,排序会发生比较,它一定会回调 元素的compareTo方法 2、任何一个类型的对象要想用TreeSet存储排序,则必须要实 现Comparable接口的compareTo方法,来指定比较规则 3、java中常见的类Integer,String等,我们并没有实现 Comparable接口的compareTo方法,他们也能自动放入 TreeSet并排序是因为他们本身已经实现了Comparable接口的 compareTo方法 修改程序TestTreeSet1.java的s4.SortedSet的实现类-TreeSet  修改程序TestTreeSet1.java来演示测试 运行程序后发现4个学生按学号排列出来,而且打印了id这说明 TreeSet存储元素回调了compareTo方法;使用TreeSet存储自 定义对象,则自定义类一定要实现Comparable接口的 compareTo方法  修改程序的TestTreeSet2.java,在程序中增加ts.java,增加存放String的代码,运行发 现按拼音顺序排列的 举例说明:实现将全班同学按学号排列出来,无论哪个同学先 加入,哪个同学后加入,最后排序出来是按学号排列的。 解题思路:使用TreeSet来存储,在学生类中用一个方法 compareTo方法来通知TreeSet按学号排列即可。写程序 TestTreeSet2.setId(1),运行发现只有3个 学生信息,而且打印了s1的”zhang‖,这说明有重复元素时, 重复元素丢弃而不是替换。 .

equals方法,但TreeSet还是保 证元素不重复 (1)TreeSet实现元素不重复是靠comparable接口的 compareTo方法的返回值决定的,compareTo返回值0则它认 为是重复的,不再加入;compareTo返回值非0则它认为不重 复,允许加入 (2)TreeSet实现元素不重复与hashCode().hashCode()则就不用再覆写equals()方法 了,在该方法中打印一句话,运行程序发现没有打印这句话这 说明TreeSet存储元素不会回调hashCode()方法,与hash码无 关 (3)对于TreeSet而言,要保证它的元素不重复,自定义对象 类一定要实现Comparable接口的compareTo方法 .SortedSet的实现类-TreeSet 修改程序的TestTreeSet2.java的Student类的compareTo方法, 使用name来比较判断,运行程序发现4个学生都加入了 TreeSet,而且s1与s4的id相同也加入了TreeSet。所以 TreeSet是靠compareTo方法的返回值来过滤重复元素的。  TreeSet是如何过滤重复元素的? 当compareTo方法比较id时,s4与s1的id相同,compareTo返 回0则s4没有加入TreeSet 当compareTo方法比较name时,s4与s1的id相同, compareTo返回非0,则s4加入了TreeSet 总上所述:TreeSet在过滤重复元素时,与HashSet不一样, Student并没有覆盖hashCode.equals()方法无关, 使用TreeSet存储自定义类的对象,自定义类无需覆写 hashCode(),equals()方法也可以保证不重复。 修改程序TestTreeSet2.java,在Student中覆写hashCode()方 法,使其返回super.

Set的排序实现 (4)TreeSet存储元素就要保证不重复,因为它是Set的子接口 SortedSet的实现类;要保证不重复就一定要实现Comparable 接口的compareTo方法,所以若没有实现Comparable接口的类, 则该类对象是不能存入TreeSet中的 修改Student类,使其不实现Comparable接口的compareTo方 法,发现ts.java来演示两种不同方式的排序  使用addAll(Collection)方法来二次封装HashSet  作业  使用集合实现一个栈  改写银行帐户管理系统的Bank类,采用集合来实现管理多个帐户对象,并添 加一个方法打印所有用户的资产排名(提示:一个用户可能有多个帐户,以身 份证号为准,总资产指多个帐户余额的总和,不考虑贷款帐户的贷款额)  定义一个Employee类,属性name:String;age:int;salary:double;把 若干Employee对象放入List中,排序并遍历;排序规则:salary高则在前面, salary相同时age大则在前面,age相同时按照name升序排列  把若干个Employee放入HashSet中并遍历,要求没有重复元素 .add报错  Set的排序  因为已经明白了TreeSet排序的原理和ArrayList排序的原理,所以 Set的排序就可以很简单了,可以利用上面2种结构来排序  Set的HashSet实现类实现排序有2种方式实现  将HashSet封装成一个TreeSet  将HashSet封装成一个ArrayList  写程序TestSetSort.

Java的高级编程之 Java图形GUI编程 Day10-Day12 .

Day10           理解Map接口及其子接口的特点和作用 掌握Map及其子接口的使用 掌握Map的实现类及实现原理 掌握Map的实现类的遍历和应用 了解GUI概述,作用和重要性 理解awt和swing的特点和由来 掌握构建图形界面的三大要素:容器,组件,布局管理器 掌握awt包下的常用组件类库及其使用 掌握swing包下的常用组件类及其使用 掌握常见的图形用户编程的步骤和方法 .

Map接口    Map接口的特点  Map接口是存储的键值对,Map的键为key,Map的值为value  Map的key和value都是Object的,key是不能重复的,value是可重复的  Map支持泛型,Map的支持泛型是key.value都支持泛型 Map的作用  Map的特点是存储键值对,对于要存储键值对的情况,我们就要使用Map  例如:英文词典 单词←→一条解释;新华字典 拼音←→字 Map及其子接口的使用  Map结构 接口:Map 实现类:HashMap List 装 set 装 实现类:HashTable List Map 装 装 子接口:SortedMap set List 对于集合框架,元素都是对象,而集合本身对象, 所以集合也可以相互嵌套 实现类:TreeMap sortedMap: 对key排序 TreeMap:要 对key排序, 不允许key为 null .

轻量级,消耗资源少,速度快,但线程不安全, 不支持并发;允许key.value设为null  写程序TestMap1.value设为null  HashTable相当于Vector.java来演示HashMap的使用和特点  使用put(key.然后迭代key来获得 value  key重复时,后加入的元素会覆盖先前加入的元素  Map的key是不允许重复 .  Map的常用方法与实现类 Map的常用方法  containsKey(Object key)判断Map中是否包含参数key对象  get(Object key)通过Map的key取得相对应的value  keySet()获取Map所有的key组成的set  put(Object key.Object value)给Map添加一个元素  remove(key)按key将其对应的value删掉  clear()删掉Map中所有的键值对元素  size()取得Map中元素的个数 Map的实现类及其实现原理  Map的实现类  Map的实现类有2个,一个是HashMap,另一个是HashTable  HashMap与HashTable的区别  HashMap相当于ArrayList.null)  要想输出key.value则可先使用keySet()方法获得key.value都可以为null,所以可添加put(null.value)方法来添加元素  Map的key.重量级,消耗资源多,速度慢,线程安全,支持 并发,不允许key.

Map的常用方法与实现类

 Map的key,value都支持泛型,修改程序将key,value都使用泛型
 Map的key是不允许重复的,与HashSet一样,key的不重复是由Hash算法
来计算的,所以是通过hashCode(),equals()2个方法来判断的,而String本
本身就是jdk的类,它已经实现覆盖了这2个方法,所以我们无需再自己覆
写,那如果是自定义类则就需要自己覆写hashCode(),equals()方法
修改程序TestMap1.java,增加自定义类Person,分别实现覆盖前后的效果
 Map的子接口——SortedMap的实现类
 SortedMap接口是可排序的,该可排序的是对key排序而非对value
 SortedMap的实现类是TreeMap,因为TreeMap要对key排序,所以
TreeMap不允许key为null
Map的遍历和应用
 Map中添加元素及其特点
 在Map中添加元素,使用put(key,value)方法
 Map中的key是不重复的,那么是如何实现的?
 对于HashMap,与HashSet相似,也是依靠hashCode(),equals()方法
来保证key不重复的,由hash算法来保证的
 对于自定义类,我们也要在该类中实现hashCode(),equals()方法这样
HashMap在存储时,才能保证key不重复
 Map的key一般是很少使用自定义类的对象,而常常使用String,8种

包装类型,如Integer,Double,而对于这些类型,已经是sun公司封装
好的,本身已经覆盖了hashCode,equals方法所以不用我们覆写了。
 Map的key重复时,使用put(key,value)添加元素,后加入的元素会覆盖先
前加入的元素;而put方法的返回值是为原来旧的被覆盖的键值对的value。

Map的遍历和应用
 Map的遍历

 Map并非是Collection,不能直接用迭代器Iterator来遍历
 Map接口中,提供了3个方法实现遍历
 若想遍历value对象,则用Map中的values()方法,这个方法返回的
是Map中所有的value组成的集合Collection,而集合Collection是可
以通过Iterator来迭代遍历的。
写程序TestMap2.java来遍历Map的值对象集合
 若想遍历key对象,则用Map中的keySet()方法,这个方法返回的是
Map中所有的key组成的集合Collection,而集合Collection是可以通
过迭代器来遍历的,那么有了key又可以通过Map的get(key)方法来
获得value,所以就可以遍历出每个键值对。
 若想要遍历Map的键值对元素,则可以用entrySet();

修改程序TestMap2.java,使用keySet()来遍历Map的键值对集合
 Map子接口——SortedMap及其实现类TreeMap
 SortedMap:Map的子接口,它是可排序的接口,它是对key排序
 SortedMap的实现类是TreeMap,它因为要对key排序,所以
TreeMap的key不能为null
 TreeMap要对key排序,排序就要比较,所以TreeMap存储自定义
类的对象作为key时,则自定义类一定要实现Comparable接口的
compareTo方法,实现compareTo方法来指明比较规则
 客户化排序可以使得客户自定义排序,无需依赖要排序的自定义类
实现Comparable接口。

Map的遍历和应用
 客户化排序是使用Compatator接口,自定义一个类实现
Comparator接口来作为比较器。
 实现了Comparator接口则就要实现compare(Type x,Type y)
方法,Type是要比较的类型
 写程序TestTreeMap.java来演示客户化排序和TreeMap的使

GUI概述
 什么是GUI
 GUI是图形用户接口,可以用它来构建图形用户界面
 GUI的作用
 用来构建图形用户界面,应用于人机对话,提供丰富的客户端界面
 GUI的重要性
 学好web,GUI图形化用户接口,对于开发c/s结构的程序非常重要

数据
client

数据

c/s结构:将程序的一部分逻辑放在服务器上完成,现在很多应用
软件都是c/s结构,如QQ,MSN,杀毒软件,它们都需要下载一个
server 客户端软件安装才能使用,由这个客户端软件帮助你建立连接,
连接到服务器上操作;c/s结构的程序需要不断更新客户端的应用
软件,更新后客户又需要下载新的来安装,很不方便。

GUI概述
http request
browers

server
Html response

b/s结构:无需用java来写界面,对客户端无要求,只要有
浏览器即可。客户端发送http请求,浏览器得到html响应,
html在浏览器被解释为一个网页,也是一个界面。例如:
访问新浪网,若采用c/s结构,则需要安装一个图形界面的
客户端软件才能上网,非常麻烦。b/s结构不存在这样的问

Java的优势在于开发server应用程序,而java的图形界面设计相对效率较低,而且
图形界面100%跨平台是很难的,不同操作系统图形组件库是不一样的。所以我们
说GUI很有用,但在找工作中并不重要
 Java的图形设计包
 Java类库的功能非常强大,在java中有2个包是图形设计包,一个是
java.awt,另一个是javax.swing。
 awt和swing的特点和由来
 java.awt是sun公司开发推出的,这个包是java的抽象窗口工具包;该
包的功能不强大,推出的组件很少,而且不适合商用,它们做界面非
常难看。它们对图片,2D,3D,二维表不支持。
 javax.swing是在awt推出不久,IBM与另一个公司借用awt思想共同推
出了另一套组件-JFC,它比awt强大,支持图片,二维表,2D,3D,
树结构等,组件很多适用商用。Sun公司将JFC的核心包和组件拿过
来在jdk1.3时取名为swing纳入了java的jdk,这就是swing。
 awt不适合商用,我们学习其思想,swing是商用组件,我们使用它

构建图形用户界面

 用户界面三大要素
 容器:它像集合,集合是对象的容器,容器是用户界面组件的容器,也是一种组
件;如窗口是容器也是组件,它会采用什么方法来存储组件呢?add,set
 组件:如计算器有按钮,文本框,窗口所有这些我们都叫组件;窗口组件可以存
放其它组件,它也是容器,所以容器也是一种组件
 布局管理器:用来负责控制组件在容器的大小和位置的。
 GUI三大要素中,除了布局管理器都是组件,容器也是组件的特例,可以存放其
他组件;awt是抽象窗口工具集,提供了构建图形用户界面的类库,但我们都使
用商用swing类库。
 awt和swing的API
 java.awt包下的类库
 BorderLayout/CardLayout/FlowLayout布局管理器,CheckBox复选框,
CheckBoxGroup复选框的分组组件,TextField文本框,Frame窗口,Color
颜色,Font字体,Graphics图形,Button按钮,Label标签
 javax.swing包下的类库
 swing是对awt的功能的增强版,awt中有Button,swing也有Button的增强版
 awt中95%的都在swing有,只是swing中将其名字改变了,名称前面多加了
J(J+类名)
 常见的swing组件
 JButton按钮,JLabel标签,JFrame窗口,JTextField文本框,
JMenuBar菜单栏,JMenuItem菜单项,JMenu菜单,JSlider滑动条,
JTextArea文本域等

构建图形用户界面
 swing比awt增强哪些功能
 swing支持3D,2D,支持二维表,支持拖拽;awt都不支持
 swing中提供了JTable,JTree等类,awt没有,做不了
 swing中所有组件类的父类都是JComponent,它又是awt的Component
的子类
 awt与swing的比较
组件包

缺点

优点

几乎被淘汰不用了,不能100%跨平台,部分功能依赖
速度稍快
OS,第三方厂商不支持,功能有限
直接支持Applet
swing 1.4jdk的swing速度慢,5.0以后swing速度加快了,不 100%跨平台,第三方厂商都支
直接支持Applet,需要安装插件才能使用,耗内存 持,开发功能更强大,轻量级组
件,资源消耗不大,风格更统一
awt

 swing是从awt发展过来的,他们发展结构图:
 java.awt
Component
 javax.swing
JComponent
 Component是所有swing组件的父类

构建图形界面应用的步骤
 选择容器和组件;容器是装组件的,一个界面就是一个容器,窗口就是容器
 选择和设置布局管理器;根据组件在容器中的位置来选择配置
 添加组件;将组件添加到容器中

swing的常用基本组件
 添加事件处理;比如一个按钮,点击了它可以起到作用完成某个操作,功能,不

加入事件处理,则它是一个死按钮
 swing的常用基本组件——JFrame,JButton,JPanel
 JFrame,JButton的API
 JFrame的继承关系很复杂,它有很多父类,方法相当多,属性也有很多,
其中常量是大写
 JFrame的无参构造,带title参数的构造;title是指窗口的标题栏,JFrame的
其他构造很少用
 JFrame的构造方法构造出来的对象默认是不可见的,需要使用JFrame的
setVisible()方法来设置可见
 JFrame的add(组件)方法是向容器JFrame中添加组件的,setLayout()是用来
设 置 布 局 的 , setCursor() 设 置 游 标 的 , setMenuBar() 设 置 菜 单 栏 的 ,
setTitle()设置标题栏,setVisible()设置可见性,setState()设置状态栏等
 写程序FirstFrame.java
 运行后发现不可见,窗口大小看不见
 修改程序使得窗口有大小,可见,运行后发现窗口的关闭功能无法实现
 修改程序实现窗口的关闭按钮功能
 JPanel面板
 JPanel特性
 JPanel是透明的面板,也是一个容器,但它不能像JFrame一样作为顶
层容器,它里面也可以放其他组件,它自己也可放在容器中,实现小容
器放到大容器中。

getContentPanel().b三个颜色值的有参构造Color(r.b),可构造出一种颜色; 除此之外,Color还有其他加亮,加暗,透明设置等方法  程序注意问题  设置容器的大小和可见性必须同时放在给容器添加组件之后, 否则若在设置了可见性,大小之后添加组件,这些组件也是看 不见的。  修改程序FirstFrame.4及其之前版本,给窗体添加组件不是直接给窗体添加,而是 给窗体的内容面板添加组件;所以添加组件代码并非jf.add(jp),而 是首先获得窗体的内容面板,再添加组件 jf.add(jp)  修改程序FirstFrame.java增加JPanel的使用  相关组件的API  JPanel是一个组件,无参构造可构建一个面板,有参构造(布局 管理器)也可构建一个带布局的面板,这2个构造常用  JPanel的setSize(长,宽)设置面板大小;setBackground(背景 色)设置它的背景色;除此之外,JPanel有很多的父类,继承了 很多父类方法,大部分与JFrame相同  使用JPanel的setBackground时用到颜色类Color.java来演示内容面板的使用 .java演示可见性和大小放在添加组件之前  添加组件特性  在jdk1.Color类中有 很多静态属性表示不同颜色,可以直接用类名使用;Color还有 带r.g.swing的常用基本组件  修改程序FirstFrame.g.

awt包 .JPanel 可选 Panel→JPanel 面板:不能独立存在,也要依赖于窗口或对话框 不同容器都有容器的特性,有相同/类似的方法,只需要知道了JFrame常用方法就 容器的方法 知道其他容器的方法了。JFrame常用方法:add有很多重载方法(添加组件), setVisible.setSize(设置可见,大小),remove()(删除组件),setLocation(设置窗口位 置)。FirstFrame程序运行后默认窗口出现的位置是左上角,可以使用setLocation()方 法来改变默认出现的位置  布局管理器的种类  窗体,面板上可以添加组件,那么这些组件添加到窗体,面板上后,要怎 么摆放组件呢?这就是布局管理器。  在java中,LayoutManager为布局管理器—专门管理容器中的组件的布局  常见的布局管理器  常见的布局管理器都来自于java.布局管理器  布局管理器  布局管理器是对容器作用的,只有容器才有布局,布局管理器是用来负责控制 布局,控制容器中组件的大小和位置的  容器的setLayout(布局管理器对象)方法是设置容器的布局的  java中的容器 容器的分类 Frame→JFrame 窗口:通常意义上的窗口,只有它们能做顶层容器 一个图形程序 JFrame必须有, Dialog→JDialog 对话框:有了窗口才会有对话框,它依赖于窗口 JDialog.

vgap)可指定对齐,水平间距,垂直间距; 一般都使用无参构造就可以了  其他方法:设置对齐方式setAlign(),设置间距setHgap(),setVgap()  使用FlowLayout来管理多个按钮和1个文本框:写程序TestFlow.hgap.流式布局FlowLayout  包括BorderLayout边框布局,FlowLayout流式布局,CardLayout卡片布局, GridLayout网格布局,GridBagLayout增强网格布局  其中JFrame默认的布局是BorderLayout布局;JPanel默认的布局是 FlowLayout  一个容器只能有一个布局管理器,不能同时有2个布局  FlowLayout—— 流式布局  流式布局的特点  保持组件的原始大小  像word打字一样,流式布局中,组件从左向右一直放,当放到窗体 最右边上则自动换行再放  当容器大小改变后,则组件相对位置也会随着变化  水平方向有左,右,居中对齐;垂直方向有居中,上,下对齐;默认 都是居中对齐  FlowLayout的API使用  3个构造:无参构造(),默认居中对齐;有参构造(int align)可指定对 齐;有参构造(align.java  运行程序后发现组件之间没有间隔,如何解决? .

边框布局BorderLayout  修改程序创建布局时用newFlowLayout(FlowLayout.30是指定间距的;LEFT是FlowLayout的静态属性指定对齐方 式的,LEFT左对齐,RIGHT右对齐,CENTER居中对齐  BorderLayout——边框局部  BorderLayout的特点  BorderLayout布局很有意思,它将容器分为东,西,南,北,中5个窗 格,每个窗格用常量表示,东-EAST、西-WEST、南-SOUTH、北NORTH NORTH、中-CENTER W E S T CENTER E A S T SOUTH  南北占整行,只支持 垂直扩展;东西不占整列,只支持水平扩展,中 间可双向扩展  BorderLayout布局是JFrame.LEFT.30)  20.20.JDialog默认的布局管理器,它不保持组 件的原始大小,组件会自动填满区域窗格,添加组件时若不指明哪个 区域窗格则默认放到CENTER区域中  每个窗格默认只能放一个组件。若想一个窗格中放多个组件则需要使 用JPanel;先放一个JPanel面板,在JPanel面板上可以放多个组件  BorderLayout的API  BorderLayout中有很多静态常量属性,其中CENTER-指示中间区域, EAST-东边区域,WEST-西边区域,NORTH-北边区域,SOUTH-南边 区域 .

网格布局GridLayout  BorderLayout有2个构造,无参构造是很常用的,构造一个没有组件间 距的布局;有参构造,参数是水平间距和垂直间距  BorderLayout的其他方法,取得水平间距,垂直间距;设置水平间距, 垂直间距;  使用BorderLayout布局实现东西南北中五个按钮分布于各区域  5个按钮的文字“东,西,南,北,中”为了使得按钮通用,我们考虑 使用String[]数组来实现  5个按钮对象同时也考虑按钮数组实现,使用for循环对5个按钮初始化  JFrame的add方法,使用有参add(组件名,区域名字)  写TestBorderLayout程序演示边框布局  GridLayout——网格布局  GridLayout的特点  网格布局的功能很好,很强大;因为它是以网状方式排列,像表格一样。 它将容器分为指定的网格数。几行×几列  在每个网格中默认只能放在一个组件,每个网格的大小一样;若要想在 一个网格中放多个组件,则需要JPanel面板组件,再JPanel上可放多个 组件 Btn1 Btn2  GridLayout布局分布如图: Btn3 Btn5 Btn4 .

awt包的类,Font是字体类,Color是颜色类  Font类中有很多静态常量非常有用,这些静态常量用来设置字形, 字体,字的大小,字的样式等  Font类的构造方法Font(字体名,字的样式,字的大小)非常有用, 创建某种特定的字体  Font类中还有一些获得字体名,字体逻辑名,字的大小的方法; 还有检查字体,判断样式的方法等  Color前面已经讲过,就不再重复了;主要就是静态常量代表各 种颜色,构造方法的参数指定r.Color都是java.java来演示网格布局  CardLayout——卡片布局  CardLayout的特点 .获得列数getColumns(), 获得组件的水平间距getHgap().Color的api  Font.卡片布局CardLayout  GridLayout布局不保持组件的原始大小,允许网格中不放组件;若想 要放则是从左向右,从上向下顺序地一个网格放一个组件  GridLayout的API  GridLayout有3个构造,无参构造,则布局占据一行一列,一般不使 用无参构造;2个参数的构造指定生成的布局的行数和列数,这个有 参构造非常有用;4个参数构造指定行数,列数,水平间距,垂直间 距,不常用该构造  GridLayout的其他方法:获得行数getRows().获得组件的垂直间距getVgap()  实现一个颜色交替的按钮网络  首先该程序需要设置颜色,字体,所以先看看Font.b值。  写程序TestGridLayout.g.

卡片布局CardLayout  卡片布局就像一叠叠扑克牌,每一时间只能看见最上面的一张,支持 上翻,下翻;也像bbs中的分页概念,有首页,上一页,下一页,末 页的功能  卡片布局将容器布局分为一张张卡片,第一次运行只能看见最前面的 卡片,想要看见后面的需要翻卡片。在现实中,这种布局用得非常多, 如图片浏览器就是一张张地翻图片;安装软件过程界面也是卡片式, 每次单击next按钮,就显示下一步骤的界面  其他的布局管理器,我们都不太关心方法,但对于卡片布局,我们则 需要关注它的方法  CardLayout卡片布局的API  CardLayout的构造:无参构造 是构造一个间隙为0的布局 很常用; 有参构造,参数是组件的水平间距,垂直间距;也很常用  CardLayout的常用方法:first(容器名)—翻到某容器的第一张卡片; last(容器名)—翻到某容器的最后一张卡片;next(容器名)—翻到某容 器的当前卡片的下一张卡片;previous(容器名)—翻到某容器的当前 卡片的上一张卡片;show(容器名,组件标识)—翻到指定容器的指定 组件标识的卡片(组件标识是指组件加入容器时的名字标识);  上面的5个方法都有容器名参数,为什么?  一个窗口可能有多个子容器,每个容器中可能都有卡片布局;因 此需要使用容器名指定是窗口中哪个容器中的卡片布局  show方法的参数,除了容器名,还有一个name名称,这个 name从哪里来呢?name是何时给到容器的卡片布局的呢? 卡片布局中每个组件加入容器时,必须要提供一个name标识, 这就是为了show方法准备的;只有加入组件时给了name名字标 识,组件才可能被show调用显示出来 .

JLabel放入卡片布局,实现翻页功能,每翻一次则是 不同颜色的不同的数字  本程序整体布局是BorderLayout,卡片部分放入JPanel,布局为卡片 布局;按钮部分放入JPanel,布局为FlowLayout布局  一个容器只有一个布局,所以这个程序需要3个容器:1个JFrame.2 个JPanel。  写程序TestCardLayout.复杂网格布局GridBagLayout  实现一个类似于图片浏览器的程序  提供4个按钮分别实现卡片布局的first.last.next.java来演示卡片布局  GridBagLayout:复杂的网格布局  GridBayLayout布局的特点  这是一种复杂的网格布局,它能具备很强的特性,这种布局允许某一 个组件跨越多行,多列。这样的布局使用GridLayout无法实现,但使 用GridBagLayout则可以实现;  它的结构如图: .JPanel.previous的功能;按 钮标签由String[]实现,按钮有按钮数组实现,使用for循环初始化  提供1-6数字放入JLabel组件,并且每个JLabel的文字颜色不同  将按钮.

gridwidth/gridheight:指定组件的显示区域中行, 列中的单元数,默认值为1  GridBagConstraints.gridy=0  GridBagConstraints.REMAINDER指定组件的显示区域为从gridx到 该行中最后一个单元格或从gridy到该列中最后一个单元格 .复杂网格布局GridBagLayout  GridBagLayout的API  功能简单的则一个类来实现就可以;功能复杂的则可能用多个类来 实现;GridBagLayout是由GridBagConstraint来管理的  setConstraints(组件,GridBayConstraints)用来设置将指定组件加 入布局时,给组件设定加入的约束条件  GridBagConstraints的fill指示组件在放入布局网格时,若网格大于组 件,是否将组件扩大来填充网格;HORIZONTAL表示在水平方向填 充,VERTICAL表示在垂直方向上填充,BOTH表示在2个方向上填 充  GridBagConstraints.girdx/gridy:指定包含组件显示区域的前导角的 单元,在此显示区域中位于网格原点的单元,地址是 gridx=0.weightx/weighty:用来指定在行,列上的组件 的权重,至少要指示一个组件,否则所有组件都会放到容器的中央。 权重其实指示的是所占的单元格基数  GridBagConstraints.

+,-,*,/,=,.复杂网格布局GridBagLayout  GridBagConstraints.java  程序运行的结果如下图 Button1 Button2 Button3 Button4 Button5 Button6 Button7 Button9 Button8 Button10 作业 队列是一种常用的数据结构,它采用先进先出的方式来存储数据的,要求 写一个类模拟队列数据结构类型,要求底层采用List来实现,并且让这一类型 实现Iterator接口,使之成为可循环遍历的类 顺时希望在毕业时统计学生的各科成绩并进行排名,要用集合来管理学生 的各科成绩,将多个Student对象放入集中并进行按照总成绩来排名 写一个计算器的程序界面,包含0-9.RELATIVE指定组件的显示区域为从gridx到其所 在的行的倒数第二个单元格或从gridy到其所在的列的倒数第二个单元 格  写API中的GridBagLayout的程序TestGridBagLayout.,Backspace,C,CE, +/-按钮和文本框 写一个图形浏览器实现图片翻动和播放图片的功能 .

Day11         理解java事件模型的概念和事件模型的特点 掌握java事件模型的实现和应用 理解AWT事件模型的概念和特点 理解AWT事件模型与java事件模型的关系 掌握AWT事件模型的实现和应用 理解观察者设计模式特性 掌握观察者设计模式的实现和应用 使用AWT事件模型完成计算器,图片浏览器 .

 Java事件模型 Java事件模型的概念,特点和组成  java中有java事件模型和awt事件模型;awt事件模型是java事件模型的应用  java事件模型的概念和组成  java事件模型是一种观察者模式,它不仅仅用在图形组件上  Java事件模型由3部分组成  事件源EventSource  产生事件的对象,即事件的发起者  一个事件源可以产生多个事件  例如:点击按钮的事件源是按钮(注意:这里是指JVM控制的只 有按钮,而非人)  事件对象EventObject  它是指事件本身,事件也是一个对象,它用于描述发生什么事情  在某些组件上进行地某种操作  例如:点击按钮的事件对象是什么?如何描述?描述就是要让 JVM知道“点击哪个按钮”  事件监听EventListener  针对某个组件上的某些操作所采取引发的处理行为  JVM接收事件就要进行处理,JVM让事件监听来处理 .

Java事件模型的规范和特点  事件源是事件的发起者,事件对象是事件的描述者,事件监听是 事件处理者  例如:高中课上看小说被老师逮着了,这句话里能不能体现出事 件模型三要素 事件源:小说;事件对象:上课看小说;事件监听:监听到看小 说后采取的处理行动  基于现实实例,我们都可以用事件模型来体现,java事件模型的 应用很广,java事件模型是为awt事件模型准备的  java事件模型的规范和特点  事件模型三要素的设计规范  事件源 因为无法确切保证将来谁可以做事件源,所以没有设计规范要求; 既然没有规范则无需用接口,应该使用类;事件源是一个类, sun公司将其设计为EventSource类  事件对象 因为事件对象是用来描述事件的,那么在描述时在需要设计出一 个规范标准来描述,所以事件对象需要设计规范。每个不同事件 有各自的特点,所以事件对象应该既可以是类也可以是接口.sun 公司将其设计为EventObject类  事件监听 因为事件监听要对事件做处理,不同事件处理也不一样,所以 对不同事件都具有各自规范的,正因为监听有很强的规范,所以 事件监听应该使用接口;sun公司将其设计为EventListener .

util.util中,EventObject事件对象类是所有事件对象的父类, 事件对象要继承它;一个事件对象中会封装事件源对象。如 EventObject(source)事件对象的构造中有source事件源; EventObject还有一个getSource()方法获得事件源  Java事件模型的实现和应用  实现java事件模型的步骤  写一个类继承EventObject作事件  写一个类事件EventListener接口,并作监听  在其他类/监听类中发起事件,然后交给监听去处理  写事件源类继承EventSource,注册监听器  Java事件模型的特点 .EventObject是所有事件对象的根  java.util包中,EventObject 不是很常用但又是一个工具;sun公司将事件源EventSource放 入java.EventListener是所有事件监听的根,它是一个标记接口, 在该接口中无方法  标记接口:标记接口代表一种标识,标识着一个事件监听对象。 在java中还有Cloneable接口,它也是一个标记接口,它代表一 个类可克隆  事件源与事件监听是2个不同的对象,但两者之间是一种授权注 册关系,2者之间就某个事件达成约定,事件源产生的该事件会 给事件监听者处理。如事件源(产生事件)→事件监听  在java.event包;sun公司将事件监听放入java.util包中  事件模型三要素的特性  java.awt.util.事件模型三要素的特性  Sun公司将事件对象EventObject放入java.

java事件模型的实现和应用   EventSource:用来做事件源,负责事件的生成,事件对象可以 注册监听  一个监听者是监听某一个事件发生,然后处理事件  监听者通过事件来联系事件源  一个监听者可以监听多个事件源  一个事件源的事件也可由多个监听者来监听  事件源发生事件给监听处理  Java事件模型的应用  实现一个Fall in love的事件模型,写程序TestEventModel.java AWT事件模型的概念和特点  AWT事件模型的概念  awt事件模型是java事件模型的应用,是由sun公司设计定义的,同样包含 三要素:事件源,事件对象,事件监听  awt事件模型是根据java事件模型设计的,awt事件模型是java的GUI的组 件的事件模型。GUI提供了很多的图形组件,基于这些图形组件sun设计了 awt事件模型。  awt设计了很多组件,不同组件会有不同的事件发生,设计了不同的事件, 不同的事件也就有不同的监听器来处理  AWT事件模型的事件和事件监听 .

util.util.util.AWTEvent Java中最基本,最常用的事件;比如双击list组件,点按钮,点菜 单,文本框回车,qq.msn的ctrl+enter就发生该事件 AdjustmentEvent 调整数值事件,基本上很少用 ActionEvent ComponentEvent 组件事件,包括很多种类 ItemEvent 单选/复选/下拉选框的选项变化发生该事件 TextEvent 文本框/文本域/其他文字组件的文字变化发生该事件 ContainerEvent ComponentEvent 容器事件,往容器中加/删一个组件时发生该事件 FocusEvent 光标事件,获得光标焦点/失去光标焦点时发生该事件 InputEvent 输入事件,分为键盘输入/鼠标输入 WindowEvent KeyEvent MouseEvent 窗口事件,比如关闭,打开,最小化窗口等  awt的事件监听:它们都是以接口形式体现的 监听是处理事件的,监听是接口,它要提供一个方法来处理事件,不同事 件的监听不同,不同监听处理不同事件的方法也不一样。Awt中提供了 不同监听的不同方法来监听各种事件 awt事件模型的事件监听 .AWTEvent是EventObject的子类 awt事件模型的事件结构 java.AWT Event事件模型  awt的事件类型:java.EventObject java.

AWT Event事件模型的事件和事件监听 监听接口 监听方法 监听事件类型 ActionListener actionPerformed(ActionEvent e) ActionEvent ItemListener itemStateChange(ItemEvent e) ItemEvent选项状态改变时处 理 MouseMotionListen er mouseDragged(MouseMotionEvent e) mouseMoved(MouseMotionEvent e) MouseMotionEvent 鼠标拖拽时处理 鼠标移动时处理 MouseListener mousePressed(MouseEvent e) mouseReleased(MouseEvent e) mouseEntered(MouseEvent e) mouseExited(MouseEvent e) mouseClicked(MouseEvent e) MouseEvent 鼠标按下时处理 鼠标释放时处理 鼠标进入某区域时处理 鼠标移出某区域时处理 鼠标点击时处理 KeyListener keyPressed(KeyEvent e) keyReleased(KeyEvent e) keyTyped(KeyEvent e) KeyEvent 键盘按下时处理 键盘松开时处理 键盘打字时处理 FocusListener focusGained(FocusEvent e) focusLost(FocusEvent e) FocusEvent 获取光标焦点时处理 失去光标焦点时处理 .

AWT Event事件模型的事件和事件监听 监听接口 ComponentListen er 监听方法 componentMoved(ComponentEvent e) componentHidden(ComponentEvent e) componentResized(ComponentEvent e) componentShow(ComponentEvent e) 监听事件类型 ComponentEvent 组件移动时处理 组件隐藏时处理 组件大小发生变化时处理 组件显示出来时处理 AdjustmentListene adjustmentValueChanged(AdjustmentEve r nt e) AdjustmentEvent 滑块,滚动条改变值时处理 WindowListener windowClosing(WindowEvent e) windowOpened(WindowEvent e) windowIconified(WindowEvent e) windowDeiconified(WindowEvent e) windowCloased(WindowEvent e) windowActivated(WindowEvent e) windowDeactivated(WindowEvent e) MouseMotionEvent 鼠标拖拽时处理 鼠标移动时处理 ContainerListener componentAdded(ContainerEvent e) componentRemoved(ContainerEvent e) ContainerEvent 向容器添加组件时处理 从容器删除组件时处理 TextListener textValueChanged(TextEvent e) .

AWT Event事件模型  AWT事件模型的特点  事件源与事件监听先进行授权注册,当事件条件满足时,事件源会给注册 的监听器发送一个事件对象,由事件监听器作出相应的处理  一个事件源可以是多个事件的事件源  一个事件源就同一类事件可以注册多个监听器  一个监听器可以同时注册在多个事件源当中  事件源与监听器是独立的,弱耦合的,是各司其职的  事件对象中会封装事件源对象,事件监听接口中的每一个方法都要以事件 对象作为参数  事件源给事件监听器发送事件对象,事件源以事件对象作参数,调用监听 器的相应方法  若事件源注册了多个监听器,那么调用监听方法时,就要遍历监听器集合, 给每个监听器发送事件对象;每个监听器都要调用处理方法,事件源以事 件对象作为参数,调用监听器的处理方法  添加事件监听,实现监听接口,将监听器对象注册在组件(事件源)中  awt事件模型三要素规范和设计  事件源:awt中有很多图形组件  事件监听:图形组件中封装了多个不同的监听器集合,可以有多个不 同的监听器来处理同一事件  添加监听:在组件中维护不同的所有支持的事件监听器集合,我们要 调用组件的addxxxListener(xxx监听器对象)来添加监听器实现对象  图形组件的API中,我们能找到addxxxListener,其中xxx是事件名, 该图形组件就是xxx事件的事件源,xxxEvent就是事件对象, xxxListener就是该事件监听器 .

AWT Event事件模型的实现和应用  图形组件的API中,我们能找到addxxxListener,其中xxx是事件名,  该图形组件就是xxx事件的事件源,xxxEvent就是事件对象, xxxListener就是该事件监听器  当事件发生时,只要图形组件注册添加了该事件的监听器,则组件会 自动调用监听器的处理方法来响应事件。对于awt的事件模型,要实 现事件处理只需要实现事件监听器接口中的方法,则事件源就会自动 调用我们实现的方法,这就是一个接口回调  图形组件也可以添加多个监听,通过事件对象也可以获得事件源图形 组件的信息(通过调用getSource()方法),使用addxxxListener()方 法,当把多个监听器添加给一个事件源时,则事件发生时,多个监听 器会同时处理事件 AWT事件模型的实现  AWT事件模型的实现  写一个简易计算器来实现点击按钮则在文本框显示该按钮的文字内容;写 程序TestAWTEvent.java程序  分析程序的布局界面,写界面布局代码  实现点击按钮功能的步骤  写一个监听器类是ActionListener接口的实现类,点击按钮事件是 ActionEvent,它的监听器接口就是ActionListener。实现 ActionListener接口则就要实现actionPerformed方法来处理事件, 即在该方法中写显示标签文字到文本框的代码  写了监听,要使得监听可以监听按钮的事件,还需要把监听器注 册给按钮,所以给每个按钮调用addActionListener(监听器实现类 对象)  修改程序TestAWTEvent来实现事件监听 .

AWT Event事件模型的实现和应用  AWT事件模型的应用  实现一个计数器来记录点击次数,单击+号按钮则数字加1,单击-号按钮则数字减1  选容器,选组件:1个JFrame,1个JPanel,2个JButton,1个 JLabel  选布局:JFrame用BorderLayout.java来实现  实现类似图片浏览器的按钮动作实现 数字  实现图片浏览器的first.next.previous.JPanel用FlowLayout  加入组件:JFrame加入JLabel,JPanel;JPanel加入2个JButton  加入监听:点击按钮是ActionEvent,实现ActionListener接口,重 写actionPerformed方法给按钮组件添加监听器  写程序Counter.last四个按钮的动作  观察者设计模式—Observer  观察者模式的特征和概念  观察者模式类似于事件处理方式,事件处理方式是事件源发起事件,监听 者来处理。发起事件的对象和处理事件的对象不是同一个对象,这就是一 种观察者模式,监听观察事件源的事件,一旦发生则就处理  在java中,如果a发生变化,b采取行动,这就是观察者模式  在现实生活中,观察者设计模式的情况有吗?即当我的状态发生改变,则 你们采取行动。现实中这样的情况太多了  天安门广场便衣非常多,一旦有人靠近国旗台并大声喊,便衣就马上 拥上来抓人了。人们进行某种行动,便衣马上采取处理,这就是一个 观察者模式 .

Observable,它是发生变化的类,单词Observable代 表可以被观察  Observable类的方法 构造方法: Observable()构造一个带有0个观察者的变化类对 象Observale  其他方法: addObserver(观察者) 将观察者添加给变化类 deleteObserver(观察者)将观察者从变化类中删除 setChanged()测试变化类对象是否改变,若不调用此方法,观 察者不认为变化类已改变 .a变化则b就行动,那么每次行动处理不一样,所以b 设计为接口,每次实现方法也不一样。  Java中观察者模式的API  观察者模式包含变化类,处理接口  在java中设计观察者模式:包含的要素是变化类和处理接  类:java.观察者设计模式Observer  天安门广场便衣非常多,一旦有人靠近国旗台并大声喊,便衣就马 上拥上来抓人了。人们进行某种行动,便衣马上采取处理,这就是 一个观察者模式  在电子商务平台,网上卖东西,商品a价格调价了,那么b马上更新 页面,否则就会造成网页显示价与实际价不一样,a(商品价格)变化, 则生成页面的b要处理,这也是一个观察者模式  观察者模式的组成,特点:观察者模式包含有a类—变化类,b类—行动 处理类,这2个类也是有规范的,将它们收录到java类库中,a是变化的 类,将其设计为类.util.

java来演示实现前面的天安门便衣抓人过程  作业  使用awt事件模型实现完成计算器的真正计算功能  搭建程序框架,写一个Computer类实现ActionListener接口,在构造方法 构建程序图形界面  20个按钮放入JPanel,采用GridLayout布局;文本框与JPanel是 BorderLayout布局,放入JFrame  20个按钮的标签采用String[]数组,按钮采用JButton[]数组 .观察者设计模式Observer notifyObserver()通知观察者变化类已经变化,使其采取行动;若变 化类已改变,也调用了setChanged();但没有调用 notifyObsever(…)方法则观察者也不知道要采取处理行动  接口:java.Observer观察者,监听事件发生则采取处理接口  Observer接口的方法 update(被观察的Observable对象o.Object arg) 当变化类发生变 化时,则观察者调用update来采取行动 update方法的参数Object arg是被观察对象的参数,这个参数可 以被这里的观察者获得;这个参数是由变化类的 notifyObserver(参数arg)方法的参数而来的  观察者设计模式的实现  写程序TestObserver.util.

将文本框中数字取反  . 将文本框中数字加上小数点  计算器工作特点的程序描述  当判断到点击的是数字按钮时,还需要判断状态append是追加还是替 换  上一次点击数字则append一定为true.计算器功能实现的程序分析  添加监听:分析20个按钮的处理方式将其分组  0-9数字组 处理方式相同,它们处理最关键 第一次点击数字时则之前的0被覆盖了; 第二次单击数字时则是追加数字; 若是点击+-*/后再点击数字则就是替换数字 那么如何标识数字是追加还是替换呢?使用一个boolean变量append 来表示,true代表追加,false代表替换.上一次点击+-*/+/-则append一定 为false .初始时append为fasle, append要在多个方法中使用,所以将其作为属性 对于数字按钮0-9,之前判断采用equals方法,这样判断很繁琐,可以 考虑使用String的match来判断 match(―\\d‖) \d代表数字  C/CE 文本框清0 append为false  Backspace 文本框中数字退掉一位,可使用取子串来实现  +-*/ 文本框数字是替换  = 计算结果并将结果显示在文本框  +/.

JTable.Day12            掌握实现计算器的方法和步骤 掌握浮点数的精确处理方法 理解java中的JFC和常用组件的特性 掌握JFC中常用组件的使用 理解java中awt的适配器及其特点 掌握适配器设计模式的特点和应用 掌握swing扩展的组件 ColorChooser.JTree的使用 掌握定时器Timer的使用 理解和掌握鼠标事件的应用 理解java应用程序与Applet 掌握java的JApplet的应用 .

;若有则不进行任何操作,若 没有则直接将.将文本框中数字符号取反  .计算器的分析  计算器的实现  计算器分析  搭建程序框架,写一个Computer类实现ActionListener接口,在构造方法构 建程序图形界面  20个按钮放入JPanel,采用GridLayout布局;文本框与JPanel是 BorderLayout布局,放入JFrame  20个按钮的标签采用String[]数组,按钮采用JButton[]数组  添加按钮事件监听:分析20个按钮的处理方式将其分组  0-9数字组 :点击后要么追加,要么替换,用append布尔变量标识  C/CE 文本框清0,如setText(―0‖) append变为false  Backspace 文本框中数字退掉一位,可用取子串subString()来实现  +-*/ 点击后append变为false是替换,用变量operator来记录运算符  = 根据记录的运算符来计算结果并将结果显示在文本框  +/.追加到文本框的数字之后  计算器使用操作步骤  先按数字按钮,接着按运算符,再按第2个数字再按=就计算结果  第一次点击数字时则文本框是替换原有的0;第二次单击数字时则 文本框是要追加数字;点击运算符后再点击数字则是替换原有数字 那么如何标识数字是追加还是替换呢?使用一个boolean变量 append来表示,true代表追加,false代表替换 . 点击后,判断文本框数组是否已有.

),-:subtract(.math包下的类,它可用于精确运算浮点数,以后都使用 它做精确运算,专门用于解决浮点精确的问题  BigDecimal的API分析  BigDecimal的构造  常用的构造方法2个,一个是double型数据做参数,另一个是String数 据参数  BigDecimal(double),BigDecimal(String)  BigDecimal的其他方法  +:add(.),/:divide(.) ..java来实现计算器  运行程序,实现计算器功能,我们操作后发现进行浮点运算时结果并不准 确;如`-0..上一次点击+-*/+/-则append 一定为false  写程序Computer.),*:multiply(.5900001,这样情况是不对的;  如何能精确处理浮点数据?得使用java的BigDecimal类 浮点数的精确处理—BigDecimal  BigDecimal类是java.计算器的实现   在初始时append为false,append要在多个方法中使用,所以将 其设置为属性  对于数字按钮0-9,之前判断采用equals方法,这样判断很繁琐, 可以考虑使用String的match来判断 match(―\\d‖) \d代表数字  当判断到点击的是数字按钮时,还需要判断状态append是追加还 是替换  上一次点击数字则append一定为true...41=0..

浮点数的精确处理—BigDecimal  BigDecimal的使用  写程序TestBigDecimal.java来演示BigDecimal的使用  直接使用double型数据封装BigDecimal对象进行计算结果精度仍然存 在问题  使用String封装BigDecimal对象来进行运算则精度问题就解决了  直接使用BigDecimal的divide方法不能处理结果为无限循环小数的情 况,想要处理无限循环小数的情况我们要在调用divide方法时使用 BigDecimal的舍入模式,ROUND_HALF_UP就是四舍五入模式  BigDecimal对于超过数据类型表示范围的数据用String来表示封装仍 然可以进行正常地运算得到正确的结果  Java中的JFC和常用组件  JFC是什么  JFC是从Netscape学来的,由IBM和灯塔公司共同研发的一套图形用户接 口类库;JFC创建的GUI比awt功能强大  swing是什么  swing是JFC中的核心组件,sun公司见JFC应用很广,将其核心组件纳入 java中作为swing,它支持2D,3D,拖拽等功能  swing组件的架构 .

Frame. ScrollBar… Font Frame AWT Event Graphics Tool kit Dialog Color Java 2D Drag and Drop Accessibility AWT JFC  常用组件  由awt继承发展的 AbstractButton JComboBox下拉列表 JButton JMenuItem JLabel标签 JList列表 JComponent JMenuBar菜单栏 JPanel面板 JPopupMenu快捷菜单 JScrollBar滚动条 JScrollPane滚动面板 JTextComponent JToggleButton JCheckBoxMenuItem 复选菜单项 菜单 JMenu JRadioButtonMenuItem 单选菜单项 JCheckBox JRadioButton JEditorPane 编辑面板 JTextArea 文本域 JTextField 文本框 JPasswordField 密码域 复选按钮 单选按钮 JTextPane .Java中的JFC和常用组件 Your Application swing AWT Component Window Button.

Java中的JFC和常用组件  扩展的非awt继承的组件 颜色选择器 文件选择器 JColorChooser JFileChooser JInternalFrame JComponent JLayeredPane JDesktopPane JOptionPane 带确定按钮的对话框 进度条 JProgressBar JRootPane JPopupMenuSeparator 快捷菜单的分隔条 JToolBarSeparator 工具栏分隔条 滑动条 JSeparator JSlider JSplitPane JTabledPane 二维表 JTable JToolBar JTree 工具栏 树状结构 JToolTip JViewPort JInternalFrame JDesktopIcon .

常用组件的使用  常用组件的使用  菜单的制作  菜单的组成  菜单包括菜单栏,菜单,菜单项  菜单项→菜单→菜单栏→窗口  在java中的组件中,JMenuItem——菜单项,JMenu——菜单, JMenuBar——菜单栏 窗口  菜单组件的API  JMenuBar  无参构造 构造一个菜单栏  add(菜单)方法可以实现给菜单栏添加菜单  JMenuBar无需事件,因为它不执行任何具体的操作处理  JMenu  JMenu的父类是JMenuItem,这是为什么? 因为菜单中也有子菜单作菜单项,比如文件/新建/很多子菜单项, 新建是菜单项,但它也是一个菜单 这样来设置的好处是JMenu.add(JMenuItem ji)方法添加菜单项时, 使用父类参数JMenuItem类型的,这样在添加时既可以传子类类 型,也可以传父类类型,所以JMenu的父类是JMenuItem  JMenu的String有参构造 JMenu(String 菜单名) 可以构造一个带 有菜单名的菜单  Add(菜单项)方法可以实现添加菜单项  JMenu无需事件,因为单击只是显示菜单项,无需进行具体操作 .

菜单组件的使用和制作菜单  JMenuItem  有参构造3个方法 JMenuItem(String 文字)构造一个只有文字的菜单项 JMenuItem(Icon 图标) 构造一个只有图标的菜单项 JMenuItem(String 文字,Icon 图标) 构造一个带有文字,图标 的菜单项  对于JMenuItem,我们更需要关注菜单项能处理什么,它可以 加哪些监听,点击菜单是ActionEvent事件,需要加 ActionListener来监听。  菜单的实现  生成JMenuItem 将其加入JMenu;生成JMenu 将其加入JMenuBar; 生成JMenuBar 将其加入JFrame  JFrame使用setJMenuBar()方法来加入菜单栏  菜单中很多地方需要有分隔线,菜单的分隔线怎么处理呢?使用 JMenu的addSeparator()方法来加入分隔线  实现一个程序带多个菜单,带分隔线,带多个菜单项的菜单  1个JMenuBar,n个JMenu,n个JMenuItem  JMenu考虑用String[]数组来管理JMenu的名称,使用JMenu[] 数组来管理多个菜单组件  JMenuItem考虑也用数组,每个菜单都对应一组菜单项,所以 考虑用二维数组来管理,使用String[][]来管理菜单项名,使用 JMenuItem[][]来管理菜单项  写程序TestMenu.java来生成菜单 .

java为GUIUtil.java,将生成菜单做成一个可 重用的工具类  窗口的关闭  窗口关闭的特性  窗口的关闭其实也是一个事件,这个事件的类型是窗口事件 WindowEvent,要想处理WindowEvent则就需要添加 WindowListener窗口监听  有了WindowListener就可以自己写关闭代码,自己决定关闭窗口时做 什么处理操作,可以不用JFrame的setDefaultCloseOperation()来直 接关闭  WindowListener的API .图形工具类与窗口的关闭  运行程序后生成了一个菜单,这个程序已经是一个成品了,若想 要生成其他菜单只需要修改2个String数组的名称即可  对于这样的通用代码在开发中常常要积累起来做成工具类中的工 具方法来专门负责生成菜单以便以后直接使用  实现工具类  工具类一般取名为xxxUtil,工具类中作为工具方法的一般为静态 方法,所以设计静态方法  菜单的2个String数组是变化的,所以作为方法的参数  最后希望获得菜单栏,所以返回值为菜单栏JMenuBar  修改程序TextMenu.

窗口事件与窗口关闭  WindowListener是窗体事件监听器,它是一个接口,这个接口中有7  个方法,我们需要写一个类实现接口,则就要实现这7个方法,其中 有一个方法windowClosing方法是我们这里窗口关闭需要的;我们在 这个方法中写代码,就可以实现在关闭时做一些其他操作,而对于其 他方法我们就采用{}来实现即可  实现在窗口关闭时在控制台打印一句“GoodBye‖  写程序TestWindowListener.java来实现  给窗口添加WindowListener对象时不能直接使用this而要new一 个对象,因为这是窗口监听  运行程序后功能正常实现,但有缺陷,就是实现WindowListener 接口则就要实现这个接口的7个方法,然而另外6个方法都是不需 要的,这样代码占用空间,代码冗余,效率极低,所以采用另外 的方法来解决——这就是适配器类 awt的适配器类及其使用  什么是适配器类  前面的程序我们实现接口则需要重写很多不需要的方法,要解决这个问题, 其实就是希望有一个现存的类已经实现了接口,它的实现也是空实现,而 我们程序写类只需要继承这个现存的类,类是没有强制子类的特性,继承 这个类后在则只需要重写需要的方法就OK了,其他方法现存类已经实现 则无需实现也不会报错,那么该现存的类在java中已经写好了,他们的名 字是事件类别+Adapter组成,这些现存的类就是适配器类 .

同时还实现设置窗 口的标题栏  因为适配器类做成了匿名内部类,所以窗口对象需要设置为 final才能被访问调用方法 .java来实现窗口的关闭  程序中除了实现在控制台打印”GoodBye‖.适配器类及其使用  在java中,只要监听接口有多于一个方法的,该监听接口都有一个 对应的适配器类  一个适配器类可以实现多个监听接口  适配器类也有弊端,使用它重写方法时,无法判断出是否已经重写 了足够的方法,因为即使重写方法不够程序也不会报错,所以无法 辨别  使用适配器类来解决窗口的关闭  写一个类继承适配器类,覆写一个windowClosing方法  适配器类一般不放在组件外面,因为它常常访问组件的成员,所以 常常将适配器类放在方法中,做成一个局部内部类,要在局部内部 类中访问组件局部变量,那么该局部变量必须要设置为final型的  因为监听实现类对象一般只new一次,所以可以直接将该局部内部 类做成匿名内部类  与WindowListener接口相对应的适配器类是WindowAdapter  写程序TestWindowAdapter.

适配器模式及其使用  适配器模式及其使用  适配器模式  我们知道做软件时,客户需求是会改变的,客户需求一旦改变,对开发团 队来讲,最担心的就是前面所做的开发无法再用,这样就要修改前期所开 发的代码,这样的修改是非常危险的,有可能造成整个程序项目面目全非, 比如String改变了,那整个项目程序就无用了  为了适应改变,使得程序的扩展性更好,减少风险,于是java就由适配器 特点设计一个适配器设计模式,这个模式就是用来适应不同变化而使得程 序更健壮。  适配器模式只是适应改变的一种方法,java中还有其他方式也可以适应改 变  适配器的使用  举例:现在客户要求建一个米店卖米,建一个肉店卖肉;不过程序写好后 客户要求改变了,客户觉得肉店太远了买肉不方便,要求米店也可以买到 肉  正常情况下,米店卖米,肉店卖肉;先写2个类分别是米类,肉类,在2个 类中提供卖米,卖肉方法  增加需求后,大部分的客户还是在米店买米,所以不能直接删除卖米方法, 不能直接修改米类;但有一个大客户需要在米店买到肉,那么如何实现不 直接修改原有的类但又能实现修改米类的功能呢?考虑重新写一个类继承 米类,并覆写卖米方法使其实现卖肉功能即可,要实现卖肉功能则新类中 需要维护一个肉店,即维护一个卖肉的对象;这个新类就是适配器类 .

java来实现一个带图标的按钮  JTextArea与JTextField组件的使用  JTextArea与JTextField的介绍  JTextArea是文本域,在很多电子商务的表单中使用,一般都带有滚动条 .bmp  Icon的实现:写程序TestIcon.常用组件—Icon  写一个类MiAdapter继承Mi类,并覆写其卖米方法sellMi实现卖肉  适配器模式的好处   使用适配器类最大的好处是在于可以使得原有程序和结构不改动,不受任 何影响,而进行新程序功能的扩展。  适配器模式可以混合任意2个不相关的类,这个设计对项目设计非常重要, 这个模式就是适配器模式,在这个模式中有重写,继承,关联很多概念, 所以可以看出我们前面讲的基础概念在设计模式中很有用的,很适用的  有了适配器模式,我们可以实现人发出狗叫,狗说人话了 常用组件的使用  Icon图标组件的使用  Icon的介绍  Icon是一个接口,不是真正的Icon组件,我们必须找到它的子类来使 用,ImageIcon类是Icon的一个实现子类  ImageIcon的构造方法很多,其中有一个构造是ImageIcon(String 图 形文件的路径)  按钮是可以带图片的,在JButton的构造中,有一个JButton(Icon icon) 带图标参数的  图标文件的格式可以是jpg.gif.

JTextField  JTextArea的构造中常用的是JTextArea(行数,列数),因为JFrame的 默认布局BorderLayout,不保持原始大小,所以JTextArea一般都要 设置其行数与列数  JTextArea是带滚动条的,在java中使用JScrollPane来封装实现  JTextField是文本框,很常用,它的构造JTextField(显示字符个数), 在JTextField中回车则触发ActionEvent,所以可以使用 ActionListener来监听  实现一个简易聊天客户端  在qq聊天时,我们知道在下面文字区中出入文字内容发送后,则显示 在上面的文字区,那么我们现在就实现这样一个功能  聊天客户端界面如图  在JTextField中输入文本回车则将JTextField文本发 送显示在JTextArea中  JTextArea中的文本只能来自于JTextField发送的, JTextArea 而不能自己编辑  JTextArea的setEditable(false)方法可以设置 JTextField JTextArea不可编辑  JTextField回车是ActionEvent,要进行回车后处理, 则给JTextField添加监听ActionListener  写程序ChatClient.java来实现 .常用组件—JTextArea.

swing包中的,Timer是计时器,它可以在指定的时间 延迟后激发一个动作,有了它图片自动播放很简单了。  例如有很多看图软件像ACDSee软件都会有一个播放功能,这个播放 功能就要实现每相隔多少秒就切换图片  Timer的构造  Timer(int delay,监听器)方法,delay以毫秒为单位,若要想每 隔1秒就自动激发调用一次则delay为1000ms。监听器是每隔 delay要执行一次监听处理  Timer的方法  start()方法启动计时器,计时器构造若不启动则并没有开始计时, 不会工作  stop()方法停止计时器,计时器停止工作计时  Timer的实现应用:写程序TestTimer.常用组件——定时器Timer  Timer定时器的使用  动画形成原理  动画是n张画每隔一小段时间就换一张这样就形成动画  例如:小时候,找一把折扇,一面画鸟,一面画笼子,然后将扇子快 速旋转则就会看见鸟在笼子里了,这就是动画  图片的自动播放  图片要自动播放,则也就要每隔一小段时间自动翻换;要实现这个功 能我们必须要使用swing中的定时器组件Timer  Timer的API  Timer类是java.java来实现  实现每隔1秒在控制台打印“Hello‖字符串,点击start按钮则启动计时, 点击stop按钮则停止计时 .

int max)创建一个滑动条,滑动的值范围为最小值 min,最大值max  JSlider的方法  getValue()返回当前滑动条上滑块指示位置的值  滑动条滑块滑动是ChangeEvent,由ChangeListener来监听,所以给 R: G: B: 确定 滑动条添加ChangeListener  我们做一个颜色选择器,界面如下  使用3个滑动条组件来调整颜色,JTextArea用 来显示颜色,滑块滑动时JTextArea中颜色发生 JTextArea 变化 显示颜色  点击取消按钮则关闭窗口,点击确定按钮则确 定选择的颜色  写程序ColorChooser.JSlider  颜色选择器—JColorChooser和滑动条—JSlider  JColorChooser是一个提供用于允许用户操作和选择颜色的控制器窗格  JColorChooser提供三个级别的API  显示有模式颜色选取器对话框并返回用户所选颜色的静态便捷方法  创建颜色选取器对话框的静态便捷方法,可以指定用户按下其中一个 对话框按钮时要调用的ActionListener  (在任何容器中)直接创建JColorChooser窗格实例的能力,可以添加 PropertyChange侦听器,以检测何时当前”颜色”属性发生改变  这里我们采用选择第3种方式来实现和使用JColorChooser  JSlider的构造  JSlider(int min.java来实现程序 取消 .常用组件——JColorChooser.

java描述学生信息  写一个子类继承AbstractTableModel类,覆写相应的方法,封装二维 表的数据结构  利用写好的二维表数据结构来实现生成二维表  鼠标事件 .java来实现  首先写一个学生类Student.常用组件——JTable  JTable组件的使用  JTable组件是一个二维表组件,二维表存储的数据是二维表的数据,这样 的数据在java中要用JTable来存储,则需要符合JTable的规范  JTable用来显示和编辑规则的二维单元表,设计使用JTable的应用程序时, 要严格注意用来表示表数据的数据结构  表数据的数据结构要么用AbstractTableModel类,写一个子类继承该类, 重写它里面的方法;要么用DefaultTableModel接口,写实现类实现其中的 方法  我们这里采用AbstractTableModel类,写一个子类继承它,重写 getColumnCount()获得表格列数,getRowCount()获得行数, getValueAt(行,列)获得在某行某列上的对象,getColumnName()获得表 格每列列名  实现一个学生信息表,将存储在集合中学生信息用表格显示出来,写程序 TestJTable.

getY()方法可以获得鼠标当前的位置值 .常用的鼠标事件和鼠标事件监听器  我们知道点按钮是ActionEvent, ActionEvent是高级事件,支持很多事 件触发,如点按钮,点菜单,文本框回车等;这些操作中有鼠标操作, 也有键盘操作。  ActionEvent发生时,会触发ActionListener处理;ActionListener接口中 只有一个方法,无需要有一个适配器类,在java中ActionListener没有对     应的适配器类 ActionEvent是高级事件,它指示所有事件,包括键盘,鼠标事件; 键盘事件也同时也包括很多地操作,有更详细的事件来支持,键盘事件 对应keyBoardListener监听来处理;同理鼠标操作本身也包括很多,有 对应的MouseListener监听来处理 MouseListener:鼠标事件监听器接口用来处理鼠标各种操作的即 MouseEvent,包括的操作有  mouseClicked:鼠标点击  mouseEntered:鼠标进入  mouseExited:鼠标离开  mousePressed:鼠标按下  mouseReleased:鼠标弹起 写程序MouseEventTest.java来演示鼠标操作  MouseEvent对象的getX().

.常用组件——JTree  树状结构——JTree组件  JTree是用来建立类似目录树结构的组件,在程序中使用很广,如资源管理 器,聊天工具qq.value对象  一个树,我们知道有根节点,父节点,子节点一层层的;Hashtable结 构正好适合建立一棵树,它的每个key可作为root节点,它的value可作 每个key根的子节点或子树  我们要建立一棵树,可以先用Hashtable来封装数据,再用Hashtable来 生成树。  实现一个使用Hashtable来生成树的程序  写程序TestTree.msn等  JTree的API  JTree的构造:  最常用的JTree(Hashtable对象),Hashtable我们知道它是Map的实现类,  有key.java来实现 Applet及其使用  Applet是什么?  Applet是一种特殊的java程序,它可以通过网络下载,然后在支持java的浏 览器上运行  Applet也是能够嵌入到一个HTML页面中,且可通过Web浏览器下载和执行 的一种Java类 .

class文件会从Web服务器端被下载到浏览器 端,浏览器启动一个Java虚拟机来运行Applet。如下图: 客户机器 Web服务器 支持Applet的浏览器 启动 下载 .class文件和JVM进程位 加载 于同一台机器上。如图 .class  Applet的运行机制  当Applet作为小应用程序时,JVM不会找Applet的main方法,而是通过 Applet默认构造方法创建一个实例,然后调用它的初始化方法init()来执行  Applet的运行机制如下图: .class文件 JVM解析,执行.Java中的Applet  它是Java技术容器(container)的一种特定类型,其执行方式不同于应用 程序。  Applet与独立的应用程序Application的差异?  java application和applet都是java程序,他们都可以运行,但他们有差别  一个应用程序application有主方法main,程序是从它的main()方法开始执行的, 它是独立的应用程序;在这种运行模式中,java类的.class文件 JVM  一个Applet没有主方法main,它的运行必须要依赖于支持java程序的浏览器, 它是小应用程序。它的运行模式是当前浏览器访问Web服务器中一个嵌入了 Applet的网页时,这个Applet的.

.Java中的Applet的运行机制 1.

Java中的Applet  对于用户自定义的Applet,也必须提供默认构造方法,否则JVM在创建它的 实例时会抛出NoSuchMethodErrorApplet异常  Java中Applet类继承关系和API Window←Frame←JFrame  Java的Applet的继承关系  Object←Component←Container← Panel←Applet←JApplet  Applet是awt包下的,商用的是swing的JApplet  Applet 没 有 直 接 继 承 Component , 而 是 Panel , Applet 类 , 这 说 明 JApplet是一种容器类,但它又不是继承Window,它不能做顶层容器  由JApplet的继承关系得到JApplet的特点  如果JApplet位于独立应用程序中,它不能单独存在,因为它不能 做顶层容器,与Panel一样,必须加入到其他容器  不能直接向JApplet中加入组件,而必须先获得它的内容面板,然 后向内容面板中加入组件,内容面板的默认布局管理器是 BorderLayout  JApplet及它的父类Applet可作为小应用程序在浏览器中运行  Applet的API  Applet的构造方法  无参构造Applet() 构造一个新的Applet实例对象  Applet的生命周期  Applet的生命周期是指从一个Applet实例被创建到这个实例所占 的资源被回收之间的过程 .

class文件的URL,它通常与 html网页的URL相同,但并不一定是这样  getImage(URL base,String target):从Web服务器端下载一 个图标,存放在Image对象中 .Java中的Applet  Applet之所以可以没有主方法也能运行,就是因为它的生命周 期的方法可以被JVM回调来运行,运行完后也可销毁它  Applet的生命周期方法  init():初始化Applet方法,Applet对象创建后,就会自动调用 此方法,由init()方法特性,这个方法我们可以用来初始化成员 变量,装载所需要的图片及获取参数等。init()方法只在Applet 首次加载入浏览器时被调用,并且在调用start()方法之前执行 结束  start():Applet被初始化后,当浏览器在页面上显示Applet时调 用此方法;start()方法可以被调用多次。比如:当浏览器由最 小化变恢复时;当浏览器在链接到另一个URL后又返回到当前 Applet页面时。  stop():在Applet成为不可见时被调用,比如浏览器被最小化; 链接到另一个URL;stop方法也可以调用多次  destroy():当浏览器被关闭时,Applet结束生命周期时执行, 该方法可以用来释放Applet对象占用的资源  Applet的其他方法  getDocumentBase():返回Applet所在的html网页的URL  getCodeBase():返回Applet 的.

java  使用javac编译该程序  在程序文件的当前目录建立一个HelloWorldApplet.html命令来测试运行Applet  查看applet的步骤 编译java源文件,生成类.String target):从Web服务器下载一段声 音存放在AudioClip对象中  getParameter(String name):返回在html网页中名称为name的参 数值  实现一个最简单的Applet程序  直接使用编辑器  使用记事本写程序HelloWorldApplet.Java中的Applet  getAudioClip(URL base.html网页文件,名字 与类名相同  在网页中使用<applet>标记来引入Applet类  直接使用IE查看html网页文件则就可以运行Applet了  想要在运行前测试Applet类的运行可以使用java中的applet查看器  使用appletviewer HelloWorldApplet.class‖ width=―300‖ height=―300‖></applet> code是用来指定Applet类文件的路径的,width指定在网页中applet 程序的宽;height用来指定Applet在网页中的高 .class文件 创建html,告诉浏览器首先加载哪个类文件以及如何设定它的大小; 比如在html中使用<applet>标记来标识 <applet code=―HelloWorldApplet.

Java中的Applet
 使用Eclipse工具
 使用Eclipse写程序HelloWorldApplet.java
 使用Run/Run as/Java Applet菜单命令运行Applet就OK了
 使用Eclipse测试运行Applet其实就是使用applet查看器来运行的
 修改代码增加测试Applet的生命周期的方法
 向Applet传递参数
 在网页上要想传递参数,则<applet>标记中可以嵌入一个<param></param>
标记,在<param>标记中嵌入参数名name和参数值value
 有了参数在Applet类中,我们可以通过getParameter(name参数名)来获得参
数值
 修改程序使得JLabel的文字内容由网页中参数指定
 如何将现有的应用程序application转换为Applet
 将一个图形应用程序转化为applet的步骤
 创建一个Html页面,并用适当的标记加载applet代码
 创建一个JApplet子类,设置该类为public,否则不能被JVM加载
 删除原应用程序中的main方法,因为Applet没有主方法,applet在浏览
器中运行的
 将所有初始化代码拷贝到applet的init方法中,applet可以不写构造,浏
览器会调用默认构造实例话applet对象
 删除时原来窗口的setSize方法,applet的大小是在网页中用applet标记
的width,height指定的

Java中的Applet
 删除setTitle方法调用,applet没有窗口JFrame,不用设置其标题栏
 不要调用setVisible方法,applet会在浏览器中自动显示出来

 实现将一个计时器应用转换为Applet
Applet的安全限制
由于通过网络装载,Applet的代码具有一种内在的危险性。如果有人编写了一个
恶意的类来读取你的密码文件,并把它通过Internet传送,会产生怎样的后果呢
 所能够控制的安全程度是在浏览器层次上实现的。大多数浏览器(包括
Netscape Nevigator)缺省地禁止以下操作
 运行时执行另一程序
 任何文件的输入/输出
 调用任何本地方法
 尝试打开除提供Applet的主机之外的任何系统的Socket
 这些限制的关键在于,通过限制Applet对系统文件的存取来阻止它侵犯一个
远程系统的隐私或破坏该系统。
 禁止执行另一程序和不允许调用本地方法限制了Applet启动未经JVM检查
的代码。
 对Socket的限制则禁止了与另一个可能有危害性的程序的通信。

Java的高级编程之
Java多线程编程
Day13-Day14

Day13







理解多进程及其进程实现原理
理解多线程的概念和java的多线程实现原理
掌握建立,启动一个线程的二种方式
理解和掌握线埕的各种状态和状态之间的转换
掌握线程的调度原理和特点
理解和掌握精灵线程特点,原理和使用
理解和掌握线程的让位处理与优先级
理解和掌握线程的阻塞和阻塞方法

进程与线程

进程与线程
 进程
 什么是进程
 一个进程就是OS并发执行的一个程序任务。
 在c++中我们可以开多个进程并发运行
 在java中运行中没有进程,因为java程序是在jvm中运行的,一个
jvm就是一个进程,在进程中不能再有进程,所以java中无多进程
是指一个jvm中无多进程
 不在一个jvm时,java也存在多进程,进程在java中有一个类
java.lang.Process;我们可以去研究
 在java中支持本地进程,在主流的OS中同时可以开多少个程序即
同时支持多少个进程。进程就相当于OS中的一个程序,现在主流
的OS都支持n个进程,它们是多进程的OS
 多进程的优势
 多进程与单进程相比,它的优势就在于并行,我们使用windows时,
之所以既可以上网,又可以聊天,还可以听歌,就是因为并行;否
则我们每次只能单独做一件事情,等做完一件后再做另一件事情。
很明显并行效率高,速度快。多进程是对OS的优化,否则很不方
便
 多进程的特点和查看
 多进程的特点就是并行
 在Window中,我们使用ctrl+alt+delete打开任务管理器来查看进程
 在Linux中,我们使用ps –aux查看多个进程

进程与线程
 线程

 java的多线程
 java是在jvm上运行的,jvm在OS中就是一个进程,多个进程就必须

(x1,y1)

y

有多个jvm;在一个jvm进程中并发执行的流程,这些流程就叫线程
 例如:在安装软件过程中,我们就需要2个子程序流同时运行,
一个是进行文件的复制写入硬盘,另一个是安装软件的进度条;
这2个子程序是在同时执行的2个任务;但是这2个任务它们各自
不能单独存在作为进程,他们必须是一体的,是一个安装程序的
2个执行流程,所以它们的组合才是一个进程,他们需要并行,
他们就叫做线程
 又例如QQ,QQ是一个程序窗口,它是一个进程,但可以和多个
x 人同时聊天,同时聊天以线程方式存在
 又比如一个小球在窗口中不停地移动(运行程序小球移动)
(x2,y2)
一个小球就是一个对象,通过for循环不断地修改小球坐标来实现
小球移动,从这个程序分析可以得出小球移动需要4个步骤
1、在x1,y1处画一个小球
2、修改x,y坐标值为x2,y2
3、在修改后的x2,y2位置处画一个小球
4、在原来的位置使用背景色画一个小球
如果将小球移动程序作为一个进程的话,则这4个操作步骤就是在
该进程中并发执行的4个线程

进程与线程
 前面讲到说OS使用进程来优化,提高效能;那进程也需要优化,它就

用线程来优化
 进程与线程的相互影响问题
 例如:在Window系统中,边听歌边看小说;如果听歌程序关掉了,
还可以继续看小说;它们互不影响(蓝屏,黑屏不算)
 进程之间运行是互不影响的,因为它们堆,栈内存是独立的,一个程
序死了,其他不受影响
 例如:在QQ聊天时,与张三说话同时又与李四说话;如果都正常运
行,他们的说话是互不影响的;但如果与张三说话死了,则会导致与
李四说话也可能死了
 线程之间运行是有可能互相影响的,因为他们的栈内存独立,堆内存
共享,一个线程死了,有可能影响其他线程的
 什么是线程?
 所谓线程实际上就是进程中的子程序流,java中的jvm是一个进程,在
jdk文件中有一个javaw.exe文件,它就是jvm进程;在jvm中运行代码
程序都是线程,main方法也是一个线程,它叫主线程
 线程的特点
 线程是一个程序中的单独的顺序流,线程同时运行,它们不依赖于其
它线程但有可能相互影响其它线程;在java中,有一个类是线程类,
它就是java.lang.Thread
 进程与线程的实现原理和比较

Y 坐标值 修改处 在原处画背 画小球 景色小球  因此假如有多个小球同时运动则小球之间的距离就会缩短  进程和线程的构建  进程和线程的三要素 .进程与线程的实现原理  进程在进程中并行的原理  在os中,多进程并行执行是将一个cpu的时间分为时间片,在不同的 时间片上执行不同程序。例如:winamp.QQ.IE同时运行,它们的时 间片分配;在宏观上它们是并发执行,cpu时间片轮换;微观上串行 一个cpu的时间 winamp QQ IE winamp QQ IE  线程在OS中的实现原理  线程的并发执行是将一个进程所拥有的cpu时间片再分成更小的cpu 时间片,每个小时间片上只执行一个操作流程(线程),这就是线程并 发。线程多了,每个线程执行的时间就少,执行速度就慢了。  例如:小球移动的线程并发的时间片分配如下: 一个进程的cpu时间 画小球 修改X.

线程 Thread都包括三要素 1、cpu:首要因素是CPU,因为正常情况下是1个cpu,如何 让多个进程,线程并发使用?Sun公司推出了虚拟cpu概念, 即前面讲的时间片原理,每个时间片就是一个虚拟cpu;除此 之外,我们知道内存,硬盘大小没有问题 2、代码:它是告诉cpu执行什么操作,它是第二要素 3、数据:代码所要操作的属性等,数据是存储在内存中的, 它是第三要素 无论是进程还是线程,这三个要素都是必备的,必不可少的。 它们构成了进程空间/线程空间,代码和数据是可见的。 数  进程和线程三要素特点 cpu 据  每个进程,线程空间都包括cpu、代码、数据;如图: 代码  对于进程而言,每个进程之间的数据空间是独立的  对于线程而言,同一个进程中的线程之间的数据空间是可以共 享的。如下图:共享的空间为堆空间 cpu 代码 数 据 数 据 代码 cpu .进程与线程的三要素  进程和线程要正常执行,必须具备三要素,sun公司作为一个 知名IT公司,它不会让我们自己构建进程,线程,我们也没有 那个水平和能力;在java中sun构建的进程Process.

进程与线程的执行顺序  java虚拟机空间分为堆,栈,静态池。进程堆,栈空间都独立; 线程栈独立,堆共享  进程空间独立,所以切换进程就既要切换堆又要切换栈;而进程 中线程切换则只切换栈,无需切换堆,这样线程比进程的切换速 度快,运行速度也快  进程与线程的比较  进程是由虚拟内存,代码,数据,系统资源的集合构成;支撑它 独立运行的都具备了;进程之间内存独立;一个进程中总是至少 有一个线程在运行,该线程就是主线程  线程相当于进程中的子程序流,进程运行了,线程才能运行  一个进程中只允许有一个主线程,但可以有多个非主线程,其他 线程与主线程是平级的,它们不一定依赖于主线程,但可能影响 主线程  主线程结束了,其他线程可能继续运行,不一定结束  Jvm结束了,则所有线程都结束了,进程是线程的支撑者  进程和线程的执行顺序  进程的执行顺序  我们知道多个进程并发执行时,是由分配cpu时间片来决定的,那么 到底由谁来分配时间片给不同进程呢?这是OS来决定的,由系统内 .

start()/Runtime.exec()  ProcessBuilder是进程构建类,它里面的静态方法start()就可以创建 一个进程对象  Runtime是什么呢? .Process类,这个类 是进程类;这个类是与进程打交道的  Process类是一个抽象类,所以它不能直接用new来构造进程对象, 那么进程对象如何获得呢?在API中,我们看到了很高兴事情,就是 有另外2种方法可获得进程对象。方法是: ProcessBuilder.lang.lang包下,是java.进程与线程的API 核来管理分配的,由OS来决定将cpu时间分为多少个时间片,并将不 同时间片给给不同进程,让它们在不同时间点运行  线程的执行顺序  线程是在一个进程中的并发流程,所以线程的执行顺序与进程同理; 多个线程并发执行时间是由一个进程的cpu时间片来决定的,那么到 底谁有权决定哪个时间片给哪个线程呢?这也是OS来管理,来决定 的;OS中有一个线程调度专门用来管理调度线程的,决定执行哪个 线程  java中进程与线程的API  进程的API  在java中有一个类在java.

lang包下。所以只要将 Runnable.Thread结合起来则线程就可实现并运行 .lang包下  Runnable接口中有一个run()方法,专门处理代码,数据的。有了 代码,数据,还缺少三要素的虚拟cpu;虚拟cpu在java中是由 Thread类来提供的,Thread类也在java.进程与线程的API  Runtime是运行环境,它虽不是抽象类,但它的构造是不公开 的,我们只可以通过它的一个静态方法getRuntime()方法来获 得Runtime对象。Runtime的这些特点说明它就是一个典型的 单例模式;有了Runtime对象,再调用其exec(…)方法可以获 得进程;所以想要调什么进程程序,就要看exec()方法;  进程注意问题:进程是与OS相关的,所以用了命令exec方法来调 用程序,则java就不跨平台了,  例如:在程序中使用exec方法调用记事本,浏览器,exel等都 可以运行,但该程序换到非window系统下则程序的exec就不 能使用了  线程也依赖于进程才能运行,进程与OS有很深的关系,所以线程 也不能完全跨平台;在Linux下线程调用代码与window下线程代码 是不一样的;在window下写的线程调用代码放到Linux下不一定能 运行  线程的API  在java中对线程定义规范的,规范就是以一个接口形式存在的,这 个接口就是在java中是Runnable接口,它代表可运行的,它在 java.

进程与线程的API  Sun公司针对线程特点,它又做了一件很有意思的事情,它把  Thread类做了特殊处理,我们一起来看看Runnable接口和Thread 的API  Runnable接口中有run方法,这个方法是无参的,也是无返回的, 而且这个方法不能抛异常,所以这个方法很单薄,功能也单一。 run方法将来实现线程是要 被重写的;所以子类重写run方法时, 也不能抛异常,不能传参,也不能返回,这就意味着子类的run方 法中有异常则必须在方法中捕获处理,而且这个方法就相当于无输 入,无输出,异常也不能向上抛。  Runnable是接口,它本身无构造,必须要有实现子类,run方法的 功能单一,但线程要执行的代码只能放在run方法中,run方法提供 了线程的代码,而实现子类的属性可以提供数据,缺cpu由Thread 提供  Thread类很特殊,它实现了Runnable接口,它作为Runnable的一 个实现子类,它当然可以提供数据,代码,具备Runnable特性。 所以Thread类除了有自己的特性外还具备了Rnnable特性。我们要 写一个线程则只需要写一个类继承Thread类就可以了,无需再实 现Rnnable接口了 建立、启动、运行线程  直接继承Thread类创建线程 .

直接继承Thread类创建线程  线程与线程对象  线程对象  在java中,Thread是线程类,Thread类的对象就代表一个线程, 只是代表,而不等于是;表示一个线程的对象叫线程对象,一个 Thread类的对象就线程对象  线程  线程是OS中维护的资源,线程对象是在java的jvm的堆空间中的 一块数据;所以线程对象不是线程,只是可代表一个线程  写线程程序TestThread.java来演示线程的创建和使用  分析程序运行结果 JVM Thread对象 OS 线程 start() 线程对象与线程关系: 每次程序运行不一定都是这个结果,不同机器运行也不一定一样 这个打印结果体现了并发特点,但不明显  修改程序代码使得并发结果更明显  再次修改程序实现2个线程1对1打印显示  分析程序得出结论 线程为什么能并发执行  线程的并行执行是无规律的,乱序运行的;所以线程之间是并行 的,但同时也是乱序的  一个线程内部的代码是顺序执行的,不会乱序;所以同一个线程 内部的程序代码是顺序执行的 .

 课堂练习 线程调度  写一个程序并发执行,实现$$$1000个和###1000个交替打印  线程的调度  线程调度是OS中专门负责分配时间片和调度线程的。线程调度是 由jvm来管理,它的作用就是分配时间片,它会随机地挑选一个线 程来运行  cpu除了被系统占用的时间之外,还有其他很多的空闲时间;当有 了线程,就将这些空闲时间分成时间片分配给线程来使用,主线程 不用管由jvm负责  线程调度负责给线程分配好时间片,分配好了,不一定线程就马上 执行,因为主线程的时间片不一定执行完了,要看主线程有没有将 时间片的权利放出来  调度可以分给多少个线程?得由线程个数和cpu空闲时间来决定, cpu没有空闲时则大家都没有机会;cpu空闲了,调度器就随机选 一个来执行。比如选择线程1,cpu又有空闲则运行线程1了  调度分配的时间片是极短的,我们根本感觉不出来,所以我们感觉 运行起来是并行的  当一个线程运行后时间片完了,但该线程并没有执行完,则线程调 度可能再分配时间片但不会马上分配的等待一会儿,下次分配 举例说明:假如一个cpu时间为0.1s(0.1s*60%=60ms用来分配,若有三个 线程,那么每个线程的机会均等,运行20ms可以做很多事情。 .1s为视觉停留的时间),有 60%的空闲用来分配;那么0.

线程调度  从线程的执行原理上看,我们知道在微观上看一个时间点的话, 则只有一个线程可运行,多个线程之间是串行的;从宏观上看, 一个时间段中是多个线程并行的其实所谓多进程,多线程在时 间点上都是单的  直接调用run()方法,则在os中不会生成线程,线程对象只作为 普通对象。run方法是进程方法跟其他普通方法一样顺序执行, 调用run方法不会过线程调度  若采用start()方法,则在os中就会生成线程,start()是线程方法, 是要过线程调度,有了线程调度,线程会自动由调度管理调用 run方法运行线程代码  Runnable与Thread结合  分析Runnable与Thread  在java.java程序再增加打印1000 个@@@,使用Runnable接口实现 线程的状态转换及其状态转换图  状态转换 .lang包中有一个接口Runnable,实现该接口对象虽然不是线 程对象,但可以用来构造线程对象。  Runnable的run方法可以提供代码,数据;现在只缺虚拟机cpu,所 以要结合Thread来生成线程对象,Thread可提供虚拟cpu  实现Runnable接口的对象称为目标对象,目标对象可用来创建线程 对象  写程序TestRunnable.java来测试演示Runnable的使用  课堂练习:将先前的线程练习TestThreadExec.

start();这3个线程 都只是在可运行状态,因为它们在主线程中,说明主线程在运 行状态,所以t1.t3仍存在; 那么它们什么时候退出呢?当jvm一个进程中的所有线程都终 止了,则这个进程就会终止 .t3都在可运行状态,到底谁先获得时间片进入运行状 new 线程对象 态呢?这个不一定,因为谁先获得时间片,由操作系统决定, 不同系统可能不一样。在window.Linux中是按先start则先进入 调用start()方法,OS才 start() 创建一个线程,但该 运行状态 线程并没有马上执行, 只是处于可运行状态, 等待时间片 可运行状态 被OS调度选 中分得时间片 运行状态 以前我们执行程序都知道main方法执行完了就完了;所以本来 主线程执行完了退出,则程序就执行完了,但因为有了线程 t1.t3就只能等待; 初始状态 那么t1.t2.t3.t2.start().t2.t2.线程状态转换及其状态转换图  有了线程对象还不一定在OS中就有线程,要start后才会申请调度生成一个 线程,所以线程的状态是在变化的  当有了线程对象还并没有在OS中产生线程,这种状态是线程初始化状态  调用了线程对象的start()方法则线程产生,此时线程会等待分时间片,并 不会马上执行,这种状态是线程的可运行状态  当线程获得了时间片就可以执行了,此时线程状态就是运行状态  状态转换图 例:分析ThreadExec2.t3;t1.java程序中,各个线程的状态;在主线程 中,有三个线程t1.t2.start().t3,所以主方法执行完了程序并不会退出。t1.t2.

gc(). 精灵线程 精灵线程  精灵线程特性  精灵线程也叫守护线程,它要依赖于其他非精灵线程而存在  守护线程的生命周期依赖于其他非守护线程的  线程的生命周期就是线程从无到有,再从有到无的过程  例如:在现实中也存在生命周期概念的,比如 花 种子→骨朵→花→ 果实→凋谢→死亡  一旦其它非守护线程执行完毕,则守护线程也就必须跟着结束  非守护线程不一定只是主线程  精灵线程的作用  在java中精灵线程非常有用,在jvm中就有一个守护线程,它就是垃圾回 收线程  Jvm的垃圾回收机制就是采用一个垃圾收集精灵线程实现的  Jvm的垃圾回收简称为gc,全名为garbageCollection;它指的是内存 垃圾的回收,它本质上是一个守护线程回收内存中的无用内存  对于程序员是没办法去要求jvm的垃圾回收马上回收垃圾内存,但程 序是可以建议或干预jvm回收;程序员可使用System.来建议jvm 去回收,但不一定马上被jvm采纳  实现精灵线程  想要一个线程成为精灵线程,我们要使用setDaemon(true/false)方法, true代表将该线程对象所代表的线程作成精灵线程 .

java来演示精灵线程的使用  分析程序运行结果  线程只能启动一次  为什么守护线程可以跟随非守护线程结束而结束 守护线程之所以可以随着非守护线程结束而结束,是通过线程调 度来实现的 首先线程调度去检测OS中有无守护线程,如果都是守护线程了, 则调度不会再分配时间片了给守护线程了。守护线程执行完当前 的时间片就结束终止了 线程的让位处理与优先级  线程的让位处理  线程的执行顺序可以通过让位处理来控制和干预,在线程中,线程的让位 处理可以有2种办法,一种是线程的休眠,另一种就是线程的让位  线程的休眠——sleep  线程休眠使用sleep(时间毫秒)方法,它可以使得当前线程睡觉,让出 指定的cpu时间,这个方法是有参数的,参数是用来指定时间数,单 位为ms;这个方法会抛一个异常InterruptException,调用该方法本线 程一定会让出cpu时间暂停运行  线程让位——yield  线程让位是使用yield()方法实现的,yield()方法是无参的,调用方法使 得本线程让出cpu时间给其他线程使用运行;yield()方法不是所有线程 都让位的,它只让给优先级比自己高或与自己平等的线程  sleep与yield的区别 .线程的让位处理与优先级   写程序TestDaemon.

yield();再次运行程序结果仍 然是2个线程交替执行,为什么?  因在主线程中生成的2个线程并没有设置优先级,所以它们是平 级的。调用yield()方法,tsy1与tsy2平级,他们都会让出cpu时间 给平级的,所以同样是交替执行  那如何才能明显地看见yield的让位功能呢?我们需要修改优先级 在tsy1.setPriority(8);再次运行程序发 现先执行tsy1的打印,在执行tsy2的打印;这就是因为tsy1的优 先级高,所以tsy2每次会让位给tsy1,而tsy1不会让位给tsy2  线程的优先级  线程的优先级的设置使用setPriority(1-10),数字越大优先级越高 .start()之前增加代码tsy1.java来演示让位处理  首先使用sleep(100),程序运行结果是2个线程交替执行,每个线程 执行一定的代码又睡觉,睡醒了又恢复运行  修改代码Thread.线程的让位处理与优先级  sleep与优先级无关,只要sleep则就一定让出cpu,所以sleep是雷锋 方法,它有参数,参数指定让出cpu时间,时间到了还会恢复运行  yield与优先级有关,yield只让给优先级比自己高或与自己相等的线程, 它不是让出指定时间,它是欺软怕硬的;调用它相当于自己还是要参 与运行权利的争夺;如果争夺到了时间片则运行;若没有获得时间片 饿让位  写程序TestSleepYield.sleep(100)为Thread.

线程的优先级  线程的优先级的设置使用setPriority(1-10),数字越大优先级越高  不设置线程的优先级时,线程也有默认的优先级,默认的优先级的 数字是5  线程的优先级与sleep无关,与yield有关;yield会让给比本线程优先 级高或平级的线程  当没有sleep/yield时的一般情况下,优先级高的线程则先进入运行 状态,但这也决不是绝对的,不同系统,可能不一样  有些系统认为优先级高的则就先进入运行状态,这样的系统成 为独占式系统  有些系统是非独占式系统,是共享式系统,它就不会认优先级, 每个可运行状态的线程都有可能进入运行状态的  优先级并不是很重要,要使某个线程先运行则不能用优先级来 控制,这不是绝对的  垃圾回收线程的优先级最低,所以在其他线程运行时,垃圾回 收线程是不能运行的  在独占式系统中,高优先级线程调用yield()等于没调为什么? 例如:可运行状态 WeiJ优先级最高 Huzg Zjc WeiJ Hiloo Liucy 运行状态 WeiJ 当WeiJ调用了yield()方法后,WeiJ就回到 可运行状态,此时OS又开始挑选,谁先 进入运行状态,因为独占式系统,所以优 先级高的先进入.则WeiJ运行 .

java来实现 线程的阻塞  阻塞线程的特性  处于阻塞状态的线程是给它cpu,它也用不了  如何使得线程变为阻塞线程  等待数据输入  数据的输入,但数据的输入并非一定是用户输入,也有从文件,网络 输入,只要没有读到数据则会阻塞  像c++中的cin>>i;运行到这里就会阻塞,等待用户输入;又如 c++的System(read)也是阻塞方法,要求从文件读入数据,若没 有文件则会阻塞  若有一个方法要求等待输入数据,则这个方法就会产生阻塞,这 样的方法成为阻塞方法  对于等待数据输入的阻塞,当读入了数据后则该线程就会由阻塞 状态变为可运行状态,但不会直接进入运行状态 .线程的阻塞  Linux系统不支持优先级  虽然yield()方法是让位给优先级高的,但有时Thread -1 0也能打印出  来,这是什么原因?因为Thread-0 1的时间片用完了,所以Thread1也就打印出来了  课堂练习  用2种方式实现2个线程,一个线程负责打印1-26个数,另一个线程负 责打印A-Z字符,他们交替执行实现1对1打印;写程序 NumberChar.

线程的阻塞  线程休眠——Thread.join()则t2阻塞,t1运行,直到t1运行完了,t2 才运行  join 方法还有几个重载的方法,重载方法有参数,参数是设置毫 秒数的 如果有2个线程a和b,b运行时,调用a.sleep(毫秒数)  线程休眠也可以使得线程变为阻塞状态,当休眠时间完了则又回到可 运行状态。前面我们已经讲解了sleep方法,我们知道采用sleep可用 来控制2个线程交替执行run方法。Sleep抛异常,所以在run方法中必 须对其进行捕获处理因为父类Thread的run方法没有也不能抛异常的, 所以自定义Thread的子类的run方法也不能抛异常  一个线程调用另一个线程的join方法  join 方法的特点  在线程t2中调用t1.join()/a.join(ms)结果是b 中止运行,b中止的时间由join方法决定,有2种情况 1、join()无参方法则b中止运行,让a运行,直到a运行完毕后, b才恢复运行 2、join(ms)有参方法则b中止运行的时间由参数指定的毫秒数 决定,这段时间a运行,时间到了b又恢复运行  在现实中,存在需要join的情况,比如“交通管制”,在北京会 经常看到,也非常熟悉这四个字。 例如:布什总统的车队要来,那么那天就会很早出发,否则就会 遇上交通管制堵上了。这个过程是暂时的,是要恢复的 判断是否是领导的车队,若不是则畅通走;若是领导的车队则实 施管制不能畅通 .

线程的阻塞 当所有领导的车队都走了则也不必再管制了,可以直接走了  写程序TestJoin.java来演示join的使用  写一个类TestJoin继承Thread类,重写run方法,在main中创建 2个线程,启动2个线程,然后将用其中1个线程的join的方法  分析程序运行结果和运行机制  join方法能干什么  由join的特点,我们可以看出join很有用,用在什么地方呢? 假如以后有这样的情况,做一件事情有5个步骤1().join(),以此类推;  课堂练习  前面我们写过一个NumberChar.5(); 如果前一个步骤的结果是下一个步骤的条件,则我们就可以将5 个步骤作成5个线程;在2()中调用1.java程序,实现2个线程,t1为 数字线程,t2为字母线程;t1与t2交替执行;若现在要求实现打 印了’M‘字母后,则一直打印数字直到26,打印完数字在打印 剩下的字母。 进一步增加线程状态转换图 .4().3().2().

状态转换图及作业 初始状态 new 线程对象 阻塞状态 线程只能在运行状态 时才能进入阻塞状态 1、等待数据输入 2、sleep 3、一个线程调用另 一个线程的join方法 OS分配的时间片执行完/ 调用yield()让位方法 调用start()方法,OS才 start() 创建一个线程,但该 线程并没有马上执行, 只是处于可运行状态, 可运行状态 等待时间片 被OS调度选中分得时间片  终止状态 本线程的代 码执行完毕 主线程退出 Jvm关闭退出 运行状态 作业  实现2个线程,一个线程打印1-52,另一个线程打印A-Z,要求输出结果如 右:1 2 A 3 4 B 5 6 C 7 8 D 9 10 11 12…..52 E F G H I J K … Z .

Day14           理解java多线程通信的特点和问题 掌握多线程的同步和通信 理解和掌握多线程的死锁问题及死锁特性 理解和掌握同步中的生产者与消费者问题 理解和掌握java的File类的使用 掌握常见的文件操作和目录迭代的实现 理解java的I/O的概念和实现原理 掌握java的I/O的流的概念和分类 理解各类I/O流的作用和特点 理解和掌握java的装饰设计模式 .

多线程的同步和通信  多线程的同步和通信  写程序TestStack.java来分析多线程的同步与通信  分析程序运行结果和问题  程序运行结果是:A‖ ‖C,不符合栈的特点,造成数据不一致,这样的 问题成为临界问题  程序问题原因  这里会出现数据不一致的原因是在入栈线程中,将字符C入栈后, 没有及时将index加1,而去睡觉了,使得出栈线程抢占执行。  得出结论就是入栈操作和索引递增操作一定要么一起执行成功,要 么一起执行失败,这样的操作叫做原子操作  实际上在OS中,即使入栈线程没有睡觉,也不一定就能保证数据正 确,因为很有可能该线程执行完入栈操作,还没有执行索引递增操 作时间片就执行完了,也会造成数据不一致问题,所以多个线程访 问同一个对象时,一定要处理数据一致性的问题。  这里的sleep睡觉代码只是将原子操作可能被打断变为了肯定被打断  什么情况下,原子操作被打断才会发生以及如何解决  多个线程并发访问同一个对象时,这个对象叫做临界资源;若不加 同步则就可能会破坏原子操作,而造成临界资源数据不一致的错误  要解决这个问题,就是要让多个线程同步执行并发访问同一临界资 源  举例说明:2个人去修电线 .

先将闸拉下.因为不知道Liucy在修电 线.这 种情况下电闸就是一个临界资源.Liucy修理完了. 所以谁拉电闸.则下来将电闸门打开.一声惨叫.而将闸拉下.Liucy被电死.则就谁推上电闸.Liucy去修电线时.Huxz 来了后.然后上电线杆去修电 线.将闸推上去.Huxz因为没电.去电闸处.上电线杆修电线.这就是数据不一致情 况.发现电闸门锁上的.多线程的同步和通信 Liucy去修电线.将闸拉下同时 将电闸门锁上. Liucy 电闸 .就避免事故发 生. 如何解决? 采用给电闸加一个锁.从高处落下.钥匙放在包里.则无法操作.

多线程的同步和通信  临界资源及其同步实现  在java中解决数据不一致问题与检修电线同理,当一个线程在执行访 问临界资源时,将原子操作部分加锁,只有拿到锁的线程才能执行 原子操作,等到原子操作执行完了才释放锁,另一个线程才可能获 得锁进入原子操作执行  Java中任何对象都有可能成为临界资源,所以在创建对象时,系统 都会自动给对象创建一把互斥锁标记,每个对象都有自己的锁标记, 这个互斥锁标记是专门分配给线程使用的  在java中是采用关键字synchronized来将原子操作定义为同步代码块, 同步代码块的代码只有线程拿到了对象的锁标记才能执行。  定义同步代码块的语法:synchronized(o){原子操作作同步代码},o 是对象,是临界资源,只有拿到了o的锁标记的线程才能进入这段代 码块执行。synchronized修饰的代码块叫同步代码块;进一步用举 例图示说明。  Synchronized同步代码块对临界资源同步,在同步代码块中的代码 就是不可分割的原子操作  使用同步代码块来解决栈的数据不一致问题(修改栈的代码)  同步代码块的应用  银行帐户系统存取钱操作  分析需求 .

.}  对于同步方法只有拿到了该方法所在的类的当前对象的锁标记的 线程才能调用同步方法;所以synchronized修饰的方法就是给当 前对象加锁,相当于synchronized(this){.多线程的同步和通信  需要一个Account类;又因为模拟2个人同时操作,所以须要个线 程;Account需要设计为一个线程,实现Runnable接口好一些  银行处理余额都不是在本地处理,而是要操作远端DB,所以需要 连接DB,会有延迟,用sleep来模拟。  本来正常情况取了2次钱后结果应该是剩下400,但运行后结果是 2000,为什么?这就是多线程造成的数据不一致问题。  这个问题就要采取同步机制来解决,在线程方法中将读余额,操 作余额,写余额作为原子操作,用synchronized来将其作为同步 代码块。  写程序Account.pop方法设置为同步方法  同步代码块 .}  有了同步方法,前面的栈程序还可以使用同步方法来解决。在栈 的代码中将push.java来演示帐户余额的同步操作  synchronized的用法和锁池  同步方法  synchronized可以用来修饰方法,synchronized修饰的方法成为 同步方法  synchronized修饰方法时,它是放在方法签名的返回类型之前; 如public synchronized void m(){..

}当线程还没有 拿到对象o的锁标记时,则就会被阻塞在对象o的锁池里等待; 当另一个线程释放了该对象o的锁标记后,则在锁池中的很多线 程会去争拿锁标记,其中只有一个线程可以拿到锁标记,进入 运行状态。那么在锁池中的其他多个线程到底谁先拿到锁标记 呢?这是由操作系统决定的,随机的。  在java中,一个线程可以同时拿到多个对象的锁标记,所以同 步代码块是可以嵌套的。如: synchronized(o1){.} o为Object对象  This代表当前对象,只有拿到当前对象或对象o的锁标记的线程 才能进入同步代码块执行  锁池  线程想要调用同步方法或进入同步代码块执行,必须要拿到对 象的锁标记,如果拿不到对象的锁标记则现程就会被堵住暂停, 那么这些被堵住的线程在哪里呢?他们会在对象的锁池里  锁池是一个空间,每个对象都有,存放等待该对象锁标记的线 程  对象o有一个同步代码块,如synchronized(o){..多线程的同步和通信  synchronized也可以修饰语句块,synchronized修饰的语句块 称为同步代码块。  synchronized修饰同步代码块时,必要要对某一个对象加锁才 能同步,所以需要一个对象;如synchronized(this){..}或 synchronized(o){.synchronized(o2){…}..} ...

} .java演示 死锁的产生、原因和特性  什么是死锁  死锁是线程同步的一个特殊情况而已  分析死锁情况  例如:t1线程准备进入 synchronized(o1){…synchronized(o2){….}….set需要加同步; 读方法不会改变状态,则不加同步;但是若是一写多读情况 时都需要加同步,否则一个写另一个读,读出错误结果  synchronized修饰符可以修饰哪些方法 可以修饰静态方法;可以修饰非静态方法;不能修饰构造方 法;不能修饰抽象方法;写代码来T.死锁的产生、原因和特性   在一个线程进入锁池后不会释放任何它已拥有的锁标记,正 是因为这样,才会有死锁产生  同步的使用和特性  当一个线程正在访问对象o的同步方法时,则另一个线程无法 访问该对象的同步方法,但可以访问该对象的非同步方法  自定义的类,对象是要被多个线程访问时则一定要考虑同步 问题  我们在设计对象的方法时,若方法要改变对象的状态则方法 就要加同步,若不改变对象的状态则一般不加同步  一般情况,写方法会改变对象状态,所以add..

}…..t2就都在各自的锁池里,而且也永远不会拿到各自 需要的锁标记,这种情况就叫死锁  死锁产生的条件和应用  条件  首先得有2个临界资源,接着有2个线程都各自拥有一个临界资源的 锁标记,然而这2个线程都不释放自己已拥有的资源的锁标记,却 又互相申请对方已拥有的锁标记。 .} t1线程想进入o1的同步代码块,则必须拿到o1的锁标记,假如t1已拿 到了o1的锁标记,进入了o1同步代码块中;此时t1还想进入o2同步 代码块 t2线程想进入o2的同步代码块,则必须拿到o2的锁标记,假如t2已拿 到了o2的锁标记,进入了o2同步代码块中;此时t2还想进入o1同步 代码块 t1想要进入o2的同步代码块则就还要拿到o2的锁标记,但是o2的锁标 记还在t2那里,所以t1进入o2的锁池等待但同时它又不会释放它已 有的o1的锁标记 t2想要进入o1的同步代码块则就还要拿到o1的锁标记,但是o1的锁标 记还在t1那里,所以t2进入o1的锁池等待但同时它又不会释放它已 有的o2的锁标记 于是这两个线程t1.死锁的产生、原因和特性 t2线程准备进入 synchronized(o2){….synchronized(o1){…..

死锁的产生、原因和特性  应用  在OS中,多线程多资源的死锁问题经常需要控制和处理,哲学家 进餐问题就是一个典型的死锁问题  每一个为哲学家,只有一根筷子,每个哲学家都不可能进餐,因为 他们分别都拿着自己的一根筷子不肯放下借给别人用但自己又因为 缺少筷子无法进餐,这就是死锁。  有锁池的线程状态图 初始状态 new 线程对象 调用start()方法,OS才 创建一个线程,但该 线程并没有马上执行, 只是处于可运行状态, 等待时间片 阻塞状态 线程只能在运行状态 时才能进入阻塞状态 1、等待数据输入 2、sleep 3、一个线程调用另 一个线程的join方法 OS分配的时间片执行完/ 调用yield()让位方法 sleep执行完了 数据输入完了 start() 调用join执行完了 可运行状态 被OS调度选中分得时间片 Os选中,将锁标记交 给线程执行 synchronized代码 锁池状态 终止状态 本线程的代 码执行完毕 主线程退出 Jvm关闭退出 运行状态 运行状态的线程在同 一时刻只有一个线程 想进入同步代码块却 没有得到对象的锁标 记则进入锁池等待 .

多线程的通信  多线程的通信  举例分析多线程的通信问题——双向单行道  这是一个双向单行道,huxz从北向南到北南 北 huxz 路口,liucy从南向北到南北路口,此时他们 双 在路口相遇;因为左边是高山,右边是河, 向 所以2个人堵死,这就是一个死锁。那么怎 河 单 高山 斜坡 么解决?多线程死锁问题可以在协调下解决 行 的,协调就是沟通,也就是通信 M 道  首先,将liucy开到斜坡,则liucy将路 liucy 南 南资源让出来,然后等待;huxz先开  这个通知和到斜坡就是一种 过路南,等huxz走过了,然后huxz要 沟通机制,也就是通信,这 通知liucy,此时liucy才开到路上,开 种机制是等待机制。 走到路北。  通信机制中,开到斜坡就是让出cpu,释放资源,在java中可以采用调 用对象的wait()方法来实现线程阻塞释放资源,而通知就是唤醒其他 线程,告诉他们可以使用资源了,在java中是采用调用对象的 notify()/notifyAll()来通知唤醒其他线程。  多线程通信特点  每个对象都会成为临界资源,所以每个对象都有锁池,互斥锁标记,除 此之外,每个对象也都有一个等待队列,队列也是存放线程的; 调用对象的wait()方法的线程则会是本线程阻塞,进入对象的等待队列 .

多线程的通信 并释放资源,而调用对象的notify()/notifyAll()会唤醒其他线程;从等待队列 中出,但出来的线程不一定就能获得对象锁标记,也就不一定会进入可 运行状态。  线程调用对象的wait()方法,必须是在对该对象加锁的同步代码块中,因 为如果没有同步根本就不存在释放资源(包括锁标记);调用对象的wait() 方法后线程释放它拥有的所有锁标记,然后进入对象的等待队列开始阻 塞  线程调用对象的notify()/notifyAll()方法,必须是在对该对象加锁的同步代 码块中,因为如果没有同步根本不存在从等待队列中唤醒。调用了 notify()/notifyAll()后,对象会从等待队列中释放1个或所有的线程;但是 调用notify()/notifyAll()时,不会将线程已拥有的锁标记释放  锁池与等待队列都是存线程的,他们有什么区别  入锁池:线程是因为拿不到锁标记,而又想进入同步代码块,所以 被逼进入锁池  出锁池:是因为别的线程释放了锁标记,由OS在锁池中选中一个使 它拥有锁标记而出锁池进入可运行状态进而获得时间片进入同步代 码块  入等待队列:是线程自己调用对象的wait()自愿进入等待队列,并且 释放资源,在等待队列里的线程都是无锁标记的  出等待队列:是由别处线程调用了对象的notify()|notifyAll()才由OS .

notify().o.所以调用notify() 后被唤醒的线程是由OS决定....  } t1拿到了o的锁标记进入同步代码块,执行到调用wait()时, t1阻 塞进入 o的等待队列并释放o的锁标记,将来t1要再运行则回到wait() 语句的下一句继续执行,而这句代码也是在对象的同步代码块中,所 以t1要执行,则先拿到 o的锁标记,所以从队列中出来后时会进入锁 池的  t2:synchronized(o){  …t2…o....而调用notifyAll方法则是唤醒所有线程.  } 当t1释放了o的锁标记进入等待队列,则t2拿到了锁标记进入o的同 步代码块,执行同步代码块直到调用notify()|notifyAll(),则t1重新从 等待队列出来,但此时t2并没有释放锁标记,所以t1只能在锁池中等 待,等再次拿到锁标记再回到刚才阻塞地方wait()下一句执行。  在等待队列中可能有很多的线程在等待队列被唤醒.notifyAll()|o. 具有等待队列的线程转换图    .wait().不一定能拿到锁标记. 这些线程就都会进入锁池.多线程的通信 选中从队列中出来,线程因无锁标记会进入锁池而不会马上进入同步 代码块 举例分析多线程同步通信  t1:synchronized(o){  …t1.

多线程的通信 初始状态 new 线程对象 调用start()方法,OS才 创建一个线程,但该 线程并没有马上执行, 只是处于可运行状态, 等待时间片 阻塞状态 线程只能在运行状态 时才能进入阻塞状态 1、等待数据输入 2、sleep 3、一个线程调用另 一个线程的join方法 OS分配的时间片执行完/ 调用yield()让位方法 sleep执行完了 数据输入完了 start() 调用join执行完了 可运行状态 Os选中,将锁标记交 给线程执行 synchronized代码 被OS调度选中分得时间片 终止状态 本线程的代 码执行完毕 主线程退出 Jvm关闭退出 运行状态 运行状态的线程在同一时 刻只有一个 线程想进入同步代码块却 没有得到对象的锁标记则 进入锁池等待 锁池状态 别的线程调用同步 对象,临界资源的 notify()|notifyAll(), 由OS选中唤醒一个 线程进入锁池 线程中调用了同步 对象、临界资源的 wait方法,线程阻 塞进入等待队列并 释放资源 等待队列 .

多线程的通信  生产者与消费者问题  生产者和消费者问题就是生产者不能一直生产不检查或不考虑消费情况,这 样会出现存货滞留状态;消费者若一直消费也可能出现大量缺或情况;生产 与消费是同时进行的,所以可以采用个线程来模拟,生产和消费的货品是共 享的,可以考虑用一个仓库来存放货品。  在java中采用栈来模拟,生产者不停生产,若消费情况不好,仓库都塞满了 则生产者要暂停生产;消费者一样,若消费情况非常好,生产者来不及生产, 仓库都空了,没有货品了,则消费者也要暂停一下。  所以前面我们写的栈程序就是生产者与消费者的问题,但是我们开要考虑栈 空与栈满的问题;现在我们假设栈的长度固定为6,为了保持数据一致性, 入栈,出栈都是同步方法,2个线程同时启动,那么当栈满时则入栈线程就 不能再将元素压栈,入栈线程暂时被中止,释放锁标记,此时调用栈对象的 wait(),完后同时调用  写程序TestProducerConsumer.java来演示生产者与消费者的问题 .

txt 名”).getAbsolutePath();但是要实现过滤条件,则 必须要实现FileFilter接口中的accept()方法,这同时也说明了在 listFiles方法中会先使用过滤器接口的accept方法来完成过滤,但 过滤条件的实现是自定义的,所以我们要实现accept方法,有了 实现,则listFiles方法就会来调用实现的accept方法,这就是一个 典型的接口回调。 .java演示迭代目录操作  list()方法只能实现迭代一层目录,无法迭代多层子目录  listFiles(过滤器)方法是列出该目录下满足过滤条件的目录名、文 件名等File对象数组File[],此时若想要打印取得每个File对象的绝 对路径,调用File[i].java来演示File的使用  在本程序中createFile.createFile()方法才创建了文件  写程序TestFile.Java的I/O—File  Java的File类简介  File类在java中代表的时文件类,File的一个对象代表磁盘上的一 JVM File f 对象 个文件或目录  File的对象时“代表”文件或目录,但并不就是“是”文件或目录, createFile() File对象与磁盘文件的关系就如同线程对象与线程的关系  在java中,我们可以生成一个File对象,如:File f=new File(―文件 文件系统 1.f只是创建了一个File对象,但文件并没有创建生成。但有了 这个File对象则可以调用f.sleep方法都会有异常抛出,所以主方 法要处理异常,使用throws方式处理  File对象可以代表磁盘上的文件或目录,文件常见的操作时增删查; 目录最常见的操作就是迭代目录。在java中,使用list()方法来迭代 目录,该方法返回的时该目录下的文件名,子目录名组成的字符 串数组String[]  修改程序TestFile.

Java的I/O—I/O流  有了File的listFiles(过滤器)方法,我们就可以对任何一个目录迭代,输出该  目录及其子目录的文件名,目录名,而且还可以输出满足某个条件的文件或 目录  修改程序TestFile.java,实现列出指定目录下的所有java文件  修改程序TestFile.java.再次实现迭代指定目录及其所有子目录的所有 java文件 Java的I/O—I/O流  Java的I/O引入  以读写文件为例,java中I/O时相对于jvm的,程序于磁盘上数据文件之 间通过jvm来进行数据传输的,所以java的I/O即输入输出,是指jvm于外 部数据源之间进行数据交换。如图结构 JVM 虚拟机 输出流 管道 外部数据源 输入流  jvm和外部数据源进行数据交换是在管道中传输数据的,就像流一样, 但不像c++是以内存为主体;java中的输入,输出是相对于JVM虚拟机的, 是虚拟机与外部数据源之间的数据交换。(注:外部数据源有很多,除 了有磁盘还包括网络或另一个JVM等)  什么是流及流的用途  什么是流  在java中,流也是一个对象,流是有方向的,流的方向有2种。 .

out就是标准输出流,在显示屏幕上打印 显示的输出流;  流的分类  流在java中有很多不同功用和特点,可以按照不同的标准来分类  按JVM方向和实现功能来分  输入流:读设备的内容到JVM .in就是标准输入流即可以接收键盘输入的流;又如 显示器也是输出设备,System.Java的I/O—I/O流  例如:“HelloWorld‖是一个String,本质上是由多个byte来存储的;如 果要读的话也是以一个字符或1个byte为单位来读取,这样来读就像水流 loworld在管道中流动一样;如图: l e read() h  流的方向  Java中流是有方向的,因为数据有读写2个操作,读写方向时不同的,所 以流也就不同。Java中将从jvm到数据源的流成为输出流;将从数据源到 jvm的流称为输入流;  Java的IO其实就是输入输出的简写,I代表Input输入,O代表Output输出  Java的输入,输出不只是文件可以,还有其他的输入输出设备;比如: 键盘,鼠标。System.

Java的I/O—I/O流  按底层处理数据的方式来分  字节流:以字节1byte为单位来传输处理数据,它可以处理任何文件  字符流:以字符2byte为单位来传输处理数据,它只能处理文本文件  按流的处理的对象来分  节点流:直接跟设备打交道的,负责底层传输数据,也称低级流  过滤流(处理流):直接跟程序打交道,对节点流再进行包装,使 得节点流更好使,给节点流增强功能的,它并不直接负责传输数据, 也称高级流  程序操作处理流,处理流找节点流,节点流找设备  过滤流的设计  过滤流或处理流可以对其他节点流进行再包装,增强其功能,这样 的流在java中是采用了一种很好的模式来设计的,这个模式叫装饰 模式  举例说明:80年代有一款很流行的游戏——魂斗乐,一个小人有一 把枪,最初枪只能发射单发子弹,当这个小人吃了不同的物品后, 则枪的子弹会发生叠加变化。如图: 最初是单发子弹 枪 L 激光 .

Java的I/O—I/O流 枪 S F 多束散开的子弹或其他 M 电波 瞄准镜 P 消声器  假如小人吃了S+L则枪发射的是多条激光;小人吃了s+F则枪发射 的是多条电波  只要每吃一种物品则枪的子弹就叠加一种功能,如果要写出这些 类,应该怎么做?  分析:不论吃什么物品,都必须要有枪;所以枪是最基本的 类,不可少的,它相当于节点流;其他任何一种物品都只是 对枪的功能的加强,物品相当于处理流,所以这些物品是对 枪起了装饰作用,这就是装饰模式。我们可以设计类如下: 武器 零件相当于过滤流, 枪相当于节点流, 枪 零件 不直接负责数据传输 负责数据传输 以枪对象为主体 P 对象,以零件作 M S F L 参数构造具有各 种附加功能的枪 .

Java的高级编程之 Java的I/O编程 Day15-Day16 .

Day15  理解和掌握java中I/O流的继承关系  理解和掌握各种流的常用方法的使用  FileInputStream与FileOutputStream  DataInputStream与DataOutputStream  BufferedInputStream与BufferedOutputStream  PipedInputStream与PipedOutputStream  ByteArrayInputStream与ByteArrayOutputStream  PrintStream的使用  理解和掌握随机访问文件类RandomAccessFile的使用  理解字符编码和乱码问题的处理  理解和掌握常见的字符流的使用  InputStreamReader与OutputStreamWriter  BufferedReader与BufferedWriter .

I/O流的继承关系  I/O流的继承关系  I/O流分为输入流和输出流,输入流有相关的继承关系,输出流也同样有  输入流的根是InputStream,它是一个字节流,它是所有输入流的父类,只要研 究了InputStream的方法,则所有子类都继承它,都有相应的方法,我们就都能 使用子类的方法了。所有的I/O流都放在java.io包中。  InputStream  在java.io包中的InputStream是一个抽象类,所以不能构造对象,我们只能 用它的子类  InputStream的构造方法不能用,InputStream的方法不多  InputStream的其他方法如何使用  available()返回的是可读的字节数即文件大小,但是该方法在网络流中 返回的结果不准确,有bug  close()方法是关闭流对象  不是所有对象都能关闭的,查看InputStream的api发现它实现了 Closeable接口的;Closeable接口中只有一个close()方法; Closeable接口表示可关闭的,就像Iterable,Cloneable接口一样 表示可迭代的,可克隆的  流对象为什么要关闭? java程序是运行在jvm中的,之前写的程序是完全在jvm中运行的, 完全由jvm来管理;但I/O流jvm无法完全管理,它是设备与程 .

. 需要记录每次读文件读到哪个位置,记录文件位置的就是标记,它 就像在文件中指明位置的指针。写文件时也是同理以byte写入,那 ghijk.txt abcd.返回值表示的是每次实际读入多少个字 节数 .I/O流的继承关系 序的桥梁;程序在jvm中运行,可由jvm来管理,但设备则也需要一个 机构来管理;jvm关闭了则程序关了,但系统资源则jvm无法直接管 理,jvm也管不了。所以在jvm关闭之前,我们需要使用close()来将 与jvm联系的系统资源(设备)也关闭  mark(int.... 么写入上时也需要记录写入的文件起始位置  read方法是读文件方法,它有三种不同的形式  read()无参方法是抽象方法,由子类来实现;该方法是一次读一个 字节,基本不用  read(byte[] b)有参方法,每次读入数据放入字节数组byte[],但是 可能最后一次读入数据不会占满字节数组;该方法很常用,掌握该 方法则子类都可以使用了  read(byte[] b.int offset.int len)有参方法,每次读入数据放入数组时 从offset位置开始放入,len是指每次读入多长的数据(即读多少个字 节),该方法在实际读入时是无需设置起始位置和数据长度的,该 方法不常用  三个读方法返回类型为int.文件不是一次就可以读完,所以我们需要将文件分多次读,这样就 def.)方法是标记流数据的位置  为什么要标记?标记是什么意思? 对文件时,我们知道底层是基于字节byte为单位来读的,但是一个 文件ab.

int offset.int offset.int len)相 对应,每次将字节数组中从offset位置开始的数据写出len个字节 数据  三个写方法与三个read不同,三个写方法都无返回值;其中第2, 3个方法比较常用  java中的I/O流的继承关系架构 .I/O流的继承关系  reset()方法是将文件指针(标记)定位到前面mark指定的位置  skip(long n)方法是放弃和跳过输入流中的n个字节数据  OutputStream  OutpurStream也是抽象类,实现了Closeable接口,可关闭;而且它还实 现了Flushable接口表示可刷新。OutputStream是抽象类,不能直接构造 对象,我们只能使用子类  OutputStream的方法很多,与InputStream的方法相似,功能相似  flush()方法是刷新输出流,使得数据及时写出  close()方法是关闭输出流,调用close()方法时系统会自动先调用 flush()方法将数据写出后才关闭流,几乎所有流都很少用flush()方法  与InputStream的读方法相对应的有OutputStream的写方法write  write(int b)与read()相对应,每次写出参数int指定的字节个数的 数据,该方法基本不用  write(byte[] b)与read(byte[] b)相对应,每次将字节数组byte[] b 的数据写出  write(byte[] b.int len)与read(byte[] b.

I/O流的继承关系架构  输入流的架构 InputStream 所有字节输入流的抽象类 SequenceInputStream序列输入流 FileInputStream文件输入流 PipedInputStream管道输入流 FilterInputStream过滤输入流 DataInputStream数据输入流 ByteArrayInputStream字节数组输入流 ObjectInputStream对象输入流 PushbackInputStream后推输入流 BufferedInputStream缓冲输入流  输出流的架构 OutputStream 所有字节输出流的抽象类 FileOutputStream文件输出流 PipedOutputStream管道输出流 ByteArrayOutputStream字节数组输出流 FilterOutputStream过滤输出流 CheckedOutputStream DeflaterOutputStream DigestOutputStream ObjectOutputStream对象输出流 CipherOutputStream DataOutputStream数据输出流 PrintStream格式化输出流 BufferedOutputStream缓冲输出流 .

I/O流的继承关系架构  I/O流的继承关系中有非常多的I/O流,这些不同的I/O流有不同的作用  I/O流虽然很多,但在开发中经常使用的I/O流并不是很多,而且I/O流的使 用方法大多类似,所以我们在I/O流中主要重点掌握五对非常重要且有用 的流来学习,除此之外还会学习一些其他的流  五对I/O流  FileInputStream与FileOutputStream 文件流,用于读写文件  ObjectInputStream与ObjectOutputStream 对象流,用于读写对象  DataInputStream与DataOutputStream 数据流,用于读写基本类型和 String类型的数据  InputStreamReader与OutputStreamWriter 桥梁流,负责将字节流转 为字符流  BufferedReader与PrintWriter(BufferedWriter) 逐行字符流,负责逐行 读取  常用流的使用  文件流——FileInputStream与FileOutputStream  文件输入流的特点  FileInputStream是文件输入流,是一个节点流,也是字节流;它可用 来读写文件;FileInputStream的构造方法常用的是2个;一个是以 String参数指定文件路径名,另一个是以File对象作为指定文件  FileInputStream构造中指定的文件一定是存在的文件,若文件不存在 则会抛异常FileNotFoundException .

txt,内容为”abcdefghi‖,写程序 ReadWriteFile.java来演示读文件  read()方法读 读的结束条件是read()返回-1;读出的1个字节要转化为char;关 闭流close();处理异常FileNotFoundException,EOFException, IOException  read(byte[] b)方法读 修改程序代码,声明一个长度为6的字节数组来存储读入数据; 读入数据显示出来发现有重复;读数据的长度应使用读方法的返 回值而非数组长度  原样读出文件内容,使用String的构造将字节数组封装;建立文 件read1.txt,文件内容为“Welcome to beijing! I am very good!‖, 考虑写程序TestReadWriteFile.常用流—FileStream的使用  FileInputStream的三个读方法的功用与InputStream一样,三个读方 法都有可能抛异常EOFException,IOException;三个读方法读文件 的结束条件是读方法返回-1表示文件结束  使用FileInputStream及其方法可能会抛异常,因此在读文件时要进行 try-catch或throws的异常处理  建立一个文件read.java来实现原样读出  文件输出流的特点  FileOutputStream是文件输出流,它是一个节点流,同时也是一个字 节流;FileOutputStream的构造方法常用的就是2个;一个是以String 作为参数指定文件路径名,另一个是以File对象为参数指定文件 .

java来实现写文件,要求不使用 try-catch来处理异常,而且要实现追加文件内容  课后作业:写一个拷贝文件的程序CopyFile.java实现写文件write.true)构造,true表示追加  FileOutputStream的写方法有三个与三个read方法相对应  修改程序ReadWriteFile.java,要求源文件名由参数 传进来,目标文件自动生成,将源文件内容拷贝到目标文件  数据流——DataStream的使用  DataStream的特点  DataInputStream和DataOutputStream是处理流,也是过滤流。它们的 构造方法是以节点流为参数的,这表明真正读写数据的还是节点流  为什么要使用过滤数据流?  例如:前面我们写入一个String s=―ShunShi‖时,采用 FileInputStream,FileOutputStream,他们是节点流;写入String 数据时需要首先将String转换为byte数组,如byte[] b=s.常用流—FileStream的使用  FileOutputStream指向的文件不存在,则会自动创建输出流对象并生成 一个文件  FileOutputStream指向的文件存在,则会将原来的文件删掉再创建新的 文件;若不想创建新文件而是在原文件中追加内容则是使用new FileOutpurStream(文件名.getBytes(), 再调用write(b)方法写入  String数据可以用上面的方法实现,那如果写入一个long型数据 呢?——将long型数据转换为字节数组,怎么做? .txt  课堂练习:写程序TestReadWriteFile.

这种方法麻烦.然后将该数向右移8位 4)重复上面3)的方法.常用流—DataStream的使用 1)将long型的数据转换为一个字节数组再写入;long型的数据是 8个字节 2)可以将这8个字节与00000001该8个字节进行’与’运算,取 得第一个字节 3)将取得的该字节存储在字节数组中.)方法,readUTF(.分别取得第2-8个字节.效率不 高  采用过滤流来实现读写基本类型,String类型的数据  用过滤流封装节点流,增加节点流功能即增加8种基本类型, String类型的读写功能  write数据类型名(…)方法,read数据类型名(…)方法可用来读写 数据  writeUTF(..也将它们存放在字节 数组中 5)最后将调用write(字节数组)就可以写入..)方法可以读写String类型的数据  使用过滤流读写完成后,则关闭只需要关闭最外层的过滤流即可, 无需再关闭节点流  在读写不同类型数据时,按什么顺序写入就按什么读出,即先写 则先读  写程序TestDataStream.java来演示过滤流的使用  缓冲流——BufferedStream  什么是缓冲? .

常用流—BufferedStream的使用 早期是直接在虚拟机jvm与外部数据源之间象流一样传输数据,外 部数据源的速度很慢,所以效率低 ,读写次数很多。现在为了减少 输入/输出次数,所以在jvm与外部数据源之间增加了缓冲区,此时输 入/输出都是通过缓冲区的,当缓冲区满了时再读写到数据源  BufferedInputStream.BufferedOutputStream可以给节点流添加缓冲功能; BufferedSteam是过滤流,它的构造参数是节点流,用它封装节点流后, 输入输出就带有缓冲功能  带缓冲的流在缓冲区没满时不会马上输出的,一定要使用flush()方法将缓 冲区内容输出并清空缓冲区。  当缓冲区没有满时,关闭流文件则也会自动将当前缓冲中的内容输出并清 空缓冲区  在I/O中最容易犯的错误有2个,其中一个就是使用带缓冲区的流却没有用 flush()清空缓冲区;另一个就是在使用Bufferedwriter时没有用newLine() 来写换行符  写一个程序TestBufferedStream.java来演示缓冲流的使用  管道流——PipedStream的使用  管道流是一种节点流,它包括PipedInputStream,PipedOutputStream一 对流  管道流的读写方式是不同于FileInputStream,FileOutputStream的读写; 文件流的对写是写了再读或读了再写,是读写分离的,即使文件流增加了 过滤流功能也还是读写分离的;  管道流的读写则可以实现读写同步,管道流主要用在多线程之间通信的; 一个线程维护PipedOutputSteam,另一个线程维护PipedInputStream, 两个线程之间由PipedSteam建立了通信管道,如下图:  .

connect(in)方法使 得2个管道流建立连接  通信前,2个管道流要先连接起来,然后一个线程向管道里写,另一个线 程从管道里读,这样就完成了管道通信  管道流本身也是带缓冲功能的节点流,是线程之间交换数据的流  写程序TestPipedStream.常用流—PipedStream的使用 T1 线 程 PipedOutputStream out PipedInputStream in T2 线 程 out.java来演示管道流的作用和应用  管道流是节点流,所以用管道流来读写String时,需要用getBytes()来转换 为字节再读写  如果使用管道流来读写long型或其他8种基本类型数据,怎么办呢?  基本类型数据转化为字节数组是非常麻烦的,这里我们可考虑使用 DataStream的过滤来封装管道流,这样读写基本类型数据就简单了  修改程序TestPipedStream.java来实现读写基本类型数据  如果想要给管道流进一步增加缓冲功能则也可以用BufferedStream来封装  字节数组流——ByteArrayStream  字节数组流包括ByteArrayInputStream和ByteArrayOutputStream一对, 他们是节点流 .

ByteArrayOutputStream是节点流,若想要它读写 基本类型数据,则可以将其封装为DataStream  ByteArrayStream是节点流,可以直接读写数据,读写的数据是放在哪呢?  ByteArayStream是有内部缓冲区的,读写的数据都是在它自带的缓 冲区里的  当使用封装后的DataOutputStream写入数据后,数据是存储在 ByteArrayOutputStream的缓冲里,存储的形式是以字节形式,那么如何 能得到字节形式的数据字节数组呢?可以通过ByteArrayOutputStream的 toByteArray()方法将基本类型数据转化成字节数组  我们要写出基本类型的数据,之前使用FileStream时,因它是节点流,所 以首先要将基本类型数据转化为字节数组。对于String类型直接调用 getBytes()方法获得;但是对于其他类型如何得到其字节数组呢?可以使 用ByteArrayStream来实现  如何使用ByteArrayStream将基本类型数据转化为字节数组  首先创建ByteArrayOutputStream对象,并将其封装为 DataOutputStream  调用write数据类型名的方法写入数据到ByteArrayOutputStream 的缓冲区  调用ByteArrayOutputStream的toByteArray()方法返回刚才写入 数据的字节数组  创建ByteArrayInputStream对象,使用read(byte[])读出刚写入的 字节数组 .常用流—ByteArrayStream的使用  字节数组流包括ByteArrayInputStream和ByteArrayOutputStream一对, 他们是节点流  ByteArrayInputStream.

常用流—PrintStream的使用  写程序TestByteArrayStream.java来演示字节数组流的使用  格式化流——PrintStream类  PrintStream流是过滤流,它也可以封装节点流来写出数据  PrintStream是过滤流,像DataOutputStream一样,也能输出格式化的数 据  PrintStream在写文件时不会抛出IOException,异常情况仅设置可通过 checkError()方法测试的内部标志。即客户程序可以通过PrintStream的 checkError()方法来判断写数据是否成功,如果返回true就表示遇到了错误  PrintStream实现了Flushable接口,所以它可在写入数据后会自动调用 flush()方法,也可调用其中println()方法写入换行字符  PrintStream的写数据方法都是以”print‖开头,PrintStream有以下方法  print(int i):向输出流写入一个int型数据  print(long l):向输出流写入一个long型数据  print(float f):向输出流写入一个float型数据  print(String s):向输出流写入一个String型数据,采用本地操作系统 的默认字符编码  println(int i):向输出流写入一个int型数据和换行符  println(long l):向输出流写入一个long型数据和换行符  println(float f):向输出流写入一个float型数据和换行符  println(String s):向输出流写入一个String型数据和换行符,采用本地 操作系统的默认字符编码  PrintStream的使用注意事项 .

java来实现分别通过PrintStream, DataOutputStream想一个字节数组中写字符串“好”,由于2者采用不同 的字符编码,所以写出的数据是不一样的。 .print(―你好啊\n‖)等价  printStream.println(―你好啊”);printStream.println(String s)和DataOutputStream的writeUTF(String s)一样都能输出字符串;但他们有区别:前者采用本地操作系统默认 的字符编码,而后者采用适用于java语言的UTF-8字符编码;使用 DataOutputStream的writeUTF()方法输出的字符串,只能用 DataInputStream的readUTF()方法读取,这样才能得到正确的数据  PrintStream和BufferedOutputStream类一样,也带有缓冲区。两者 的区别在于:后者只有在缓冲区满的时候,才会自动执行物理写数据 操作;而前者可以让用户来决定缓冲区的行为。在默认情况下, PrintStream也只有在缓冲区满的时候,才会自动执行物理写数据的 操作,此外,PrintStream的一个构造方法带有autoFlush参数, autoFlush参数是用来指定刷新缓冲区的方式  若autoFlush参数为true,则表示PrintStream在以下三种情况也会自 动把缓冲区的数据写到数据源  输出一个字节数组  输出一个换行符即执行print(―\n‖)方法  执行了println()方法  写程序TestPrintStream.print(―你好啊”), printStream.println();printStream.常用流—PrintStream的使用  每个print()方法都和一个println()方法对应,例如以下三段程序代码是 等价的  printStream.

随机访问文件类——RandomAccessFile  随机访问文件类——RandomAccessFile  RandomAccessFile类它具有随机读写文件的功能  RandomAccessFile类可以随机读写文件是因为它的内部都有一个文件指针 来标识读写的起始位置,文件指针随着读写会自动地移动,从而可实现随 机访问  RandomAccessFile实现了Closeable,DataInput,DataOutput接口,所以 它可以支持关闭,而且还可以直接写基本类型数据,String类型数据,同时 也可读写字节  RandomAccessFile的构造方法中除了有File表示文件做参数,String name 作文件路径名参数,还有一个参数mode表示模式,mode模式是用来指明 文件打开方式的。mode的取值情况  ‘r‘表示只读方式;’rw‘表示读写方式;’rws‘表示读写方式同时要求 数据更新同步(包括文件和元数据);’rwd‘表示读写方式同时要求 数据更新同步(只包括文件)  RandomAccessFile在读写文件时,会抛出EOFException,IOException, 所以要处理异常  RandomAccessFile的其他常用方法  close()关闭流及其相关的系统资源  length()获得文件的长度 .

int)  支持读写基本类型.String数据:read数据类型名(),write数据类型名()  seek(long pos)方法是设置相对于文件开始的偏移量,即相对于文件 开始多少个字节,也就是设置文件指针的值,设置偏移量  getFilePointer()返回当前读写指针所出的位置  skipBytes(int n)使读写指针从当前位置开始跳过n个字节  写程序TestRandom.随机访问文件类——RandomAccessFile  以字节为单位读写方法: read(),read(byte[]),read(byte[].int.java来演示随机读写文件  作业:写一个程序实现将2个文件内容连接起来,要求使用随机读写类  字符流的使用  字符流是什么,有什么作用?  读写都是以字符形式来处理的流就是字符流;字节流也可以读写字符, 那为何还要用字符流?因为字符流可以解决编码问题  编码及编码的应用分析  我们通过DataOutputStream可以writeChar(‗A‘)写一个字符,那么这个字 符在计算机中是什么形式存放的呢?我们知道计算机是只识别二进制数的, 所以我们写的任何内容都是以二进制数形式存放在计算机的  例如:写一个’A‘到计算机中,则计算机中存的并非是1个’A‘,‘A‘ 是无法存的,计算机里‘A‘是以8位二进制数表示的,这8位二进制数 可以计算得到一个对应的十进制65,所以计算机存的是数。A→数 →int 65→01000001→65→01000001→‗A‘  任何一个内容在计算机都是以数的形式存放的 .int); write(),write(byte[]),write(byte[].int.

B3个值组成,R为0-255,B为0255,G为0-255,这三个值描述一个点的颜色  又如马赛克,我们可以将它看成是九个点排列而成,用中间点的值去 覆盖周围的8个点即可  我们现在常用的字符集是ASCII码,这个字符集是由美国标准局制定 的,这是一种编码方式。如A-65,B-66,C-67,…Z-90。这个字符 集是最早的,后来各国的编码字符集都是在此基础上发展起来的,并 保留ASCII码的对应关系,然后在ASCII码的基础上扩展形成自己的 字符集  那么字符集的编码方式由谁来决定?  字符集编码是国家制定的,国家标准局说了算。因为有了编码,则不 同国家字符集编码不一样,所以就会出现乱码问题  例如:中国人在网络上发了一句“狗”,假设狗所对应的编码的 数是1250,这是中国的编码方式,采用中国制定的编码集得到 的;将此信息发送到日本,日本接收到后则按日本的编码找对应 的字符来解码,而1250在日本对应的是“小泉”,这样就造成 了日本接收到的数据与中国发送的数据不一致,这就是乱码  乱码:编码方式与解码方式不统一造成的  常见的几种编码方式  美国的ASCII码采用8位二进制来编码,1Byte能表示28=256个数,所 以可以给256个字符编码,而常用字符最多28个,所以足够编码。这 个ASCII码是最早的编码集。其他任何一个国家的编码都是以ASCII 为基础,是在ASCII码上扩展的,所以世界上任何一种码都含有 ASCII码的部分,正因为每个国家的各自的编码集都含有ASCII码; .G.字符流和字符编码  又如:一个点在计算机中存储的是这个点的水平位置,垂直位置的值, 以及该点RGB值,这个值是由R.

常见的几种编码方式  所以英语在世界各地传输都不会出现乱码。现在使用的ASCII码是 ISO-8859-1,1个字符用1个字节表示  中国的编码是GB2312-8,GB表示国标,由国家标准总局制定,在 计算机中采用2个字节来编码汉字,可表示65535个汉字,而 GB2312中只制定了常用字的编码,有些不常用的字没有编码,所 以有些打字软件也无法打印出来;后来,从GB2312发展到GBK内 码,这个编码集包含了更多的汉字,一些生字、词都有编码。GBK 是大陆采用的编码;而港,奥,台采用Big5的编码(大五码)  Unicode编码采用的是双字节的编码方式,如:各种网络协议都是 用英文编码的,这样才能保证网络协议一致性,保证正常地传 输。”ABCD‖4个字节→8个字节;1000个字符→2000个编码  在使用DataStream收发String.采用的是 writeUTF(),readUTF(); UTF就是Unicode编码utf-8;UTF是变长的编码字节,常见的有1B.3B.4B等  写程序TestCode.java程序演示字符编码问题  常见的字符流及其使用  字符流的介绍  字符流可以帮助我们处理字符的编码,Reader/Writer是所有字符流 的父类;Reader表示字符输入流,Writer表示字符输出流  字符流的作用就是用来读写字符的,所以读写文本文件可用字符流, FileReader/FileWriter用来读写文件  Reader/Writer是所有字符流的父类,他们是抽象类,不能创建对象。 所以我们使用的字符流都是其子类 . 不常见的是2B.

String charsetName):需要 两个参数,字节流和编码方式;按照参数charsetName指定的字 符编码方式读取输入流中的字符 OutputStreamWriter(OutputStream os):需要一个字节流参数; 按照本地平台的字符编码写出到输出流的字符 OutputStreamWriter(OutputStream os.常见的字符流及其使用  Reader/Writer的子类有很多,常见的有  CharArrayReader与CharArrayWriter  BufferedReader与BufferedWriter  InputStreamReader与OutputStreamWriter  PipedReader与PipedWriter  一个字节流可以通过桥梁流来转换为字符流  字符流的使用  InputStreamReader与OutputStreamWriter  InputStreamReader与OutpurStreamWriter是桥梁流,他们都采 用适配器模式把原来的字节流InputStream/OutputStream转换为 Reader/Writer的字符流  他们的构造方法 InputStreamReader(InputStream in):需要一个字节流参数;按 照本地平台的字符编码读取输入流的字符 InputStreamReader(InputStream in.String charsetName): 需要两个参数,字节流和编码方式;按照参数charsetName指定 的字符编码方式写出到输出流中的字符  常用的方法 .

java实现读入诗文文件内容并向该文件 中追加剩下的诗句 newLine()是I/O程序中最容易犯的错误,很多情况是在写时没有 写newLine(),所以在读时readLine()就读不到换行符 字节流→字符流→加一个缓冲→带缓冲的字符流 FileReader是InputStreamReader的子类,该类只能按照本地平 台的字符编码来读取数据 .常见字符流的使用         getEncoding()返回此流中使用的字符编码的名称 常用的读写方法,以字节为单位的读写方法 InputStreamReader与OutputStreamWriter是不带缓冲功能,一 般不单独使用,而是将他们又封装为BufferedReader与 BufferedWriter字符流来增加缓冲功能。BufferedReader与 BufferedWriter在开发中是最常用的 BufferedReader中有一个很有用的方法readLine()可以读取一行, 返回值为String类型;BufferedWriter有很有用的方法write(String) 可写字符串,newLine()可写换行符 BufferedReader/BufferedWriter的构造方法需要一个 Reader/Writer的对象 采用BufferedReader/BufferedWriter时,它们不是过滤流,关闭 直接关最外层的流BufferedReader/BufferedWriter。 写程序TestReaderWriter.

Day16  理解和掌握常见的字符流的使用  PipedReader与PipedWriter  PrintWriter  掌握标准I/O的使用和重新包装后的使用  理解和掌握对象序列化与反序列化  理解和掌握带分隔符的字符串的处理—— Tokenized  理解和掌握Properties  理解网络编程的通信机制  理解网络通信的OSI网络模型和TCP/IP模型  理解和掌握TCP的Socket编程  实现TCP Socket的一次和多次交互的程序 .

字符流-PipedReader/PipedWriter的使用  常见的字符流的使用  PipedReader与PipedWriter  在字节流中,有PipedInputStream,PipedOutputStream管道流来实现 线程之间的数据通信。在字符流也有PipedReader/PipedWriter来实现管 道通信  字符流的管道通信模型 T2线程 T1线程 PipedWriter PipedReader 读 写 BufferedReader readLine() 管道 BufferedWriter write(String) newLine()  封装管道流需要缓冲字符流,要创造一个带缓冲的字符流也需要做几个 步骤非常麻烦  封装带缓冲的字符流的3个步骤  创建一个字节流  利用字节流构造字符流  用字符流再构造缓冲字符流  PrintWriter .

java使用PrintWriter来写文件 标准I/O及其重新包装  java标准I/O  标准I/O的特点  当程序读写文件时,在读写操作完毕后,就会及时关闭输入流或输 .0以后才支持  PrintWriter提供了print()方法可以输出8种基本类型的数据,println()方法 可以写换行符,也提供了write(int),write(byte[]),方法以字节为单位写,  非常方便操作  在大多数情况下,我们还是用PrintWriter,用PrintWriter写入数据后,再 读时,读完结束条件是null。使用PrintWriter写数据时,编码方式是在桥 梁转换时指定的  使用PrintWriter时关闭还是关闭最外层的流的对象即PrintWriter对象  PrintWriter中有一个方法println(Object o)是写对象的,它的本质是写对象 的toString()方法的返回值  修改程序TestReaderWriter.字符流-PrintWriter的使用  在Writer中有一个非常方便使用的PrintWriter流,它是一个自带缓冲的字 符流  PrintWriter字符流的构造可以直接使用一个字符流来封装,简单易用  PrintWriter带缓冲的字符输出流,除了可以用字节流封装,也可以直接使 用文件名来构造,直接用文件名构造是在jkd5.

out也可以封装为PrintWriter来使用 .in是InputStream类型,为了能读到格式化的数据,以及提高读数 据的效率,常常要对它进行包装  键盘输入的是字符串,为了可以从标准输入键盘按行读取输入的字符串, 则先用InputStreamReader适配器把System.in读取标准输入流的数据  System.in:它为InputStream类型,是字节流,代表标准输入流,默 认的数据源为键盘,程序可通过System.标准I/O及其重新包装 出流。这些输入流或输出流的生命周期是短暂的,不会存在于程序运 行的整个生命周期中。对于某些应用程序,需要在程序运行的整个生 命周期中,从同一个数据源读入数据,或者向同一个数据汇输出数据。 最常见的是输出一些日志信息,以便用户能够跟踪程序的运行状态  java的标准I/O流  System.out输出运行时的正 常消息  System.err输出运行时的错误消息  上面的三种标准的I/O流都是由jvm创建的,他们存在于程序运行的整个生 命周期中,这些流始终处于打开状态,除非程序显式地关闭他们。只要程 序没有关闭这些流,在程序运行的任何时候都可以通过它们来输入或输出 数据  重新包装标准输入和输出  System.in转换为Reader类型,再用 BufferedReader装饰它,同理System.out:它为PrintStream类型,是字节流,代表标准输出流, 默认的数据汇就是控制台,程序可以通过System.err:它为PrintStream类型,代表标准错误输出流,默认的数 据类汇是控制台,程序可以通过System.

5  输出:name:WeiJuan age:27 sex:female phone:80997901 greed:95.对象序列化  写程序TestStandInOut.5  若输入回车或ctrl+c组合键则就结束程序  在读写一些带有特殊字符的字符串,比如以某个符号为分隔符的字符串, 我们可以用String中split()方法来拆分,该split()方法的返回值是String[]数  组,存放拆分后的多个字符串 对象序列化  对象的读写在现实中是非常普遍的,我们打游戏时,要经常存盘、读盘,其 实在游戏时存盘就是存对象,将对象状态转换为数据保存起来。本质上存对 象就是存对象属性,同理,读对象也是读出对象对象数据转换为对象状态  我们把对象放在I/O流上传输,这个过程就叫对象序列化  如一个class Student{String name.java来实现从键盘输入以“:‖分隔的学生信息,然 后打印显示出学生信息,格式如下:  输入 WeiJuan:27:female:80997901:95.}这些属性都是基 本类型,存对象就是存属性,这3种类型我们已经知道用DataStream可以 处理,为什么还需要用对象序列化呢?因为如果一个Student中属性也是 对象怎么办呢?一个对象的属性可以是一个对象  ObjectInputStream和ObjectOutputStream  把对象存文件即可通过流来写入文件,从文件中取对象也可以通过流来读 取 .int age.double mark.

对象序列化  对写对象在java中可采用ObjectInputStream/ObjectOutputStream,它们是 自带缓冲的,它们是InputStream,OutputStream的子类,是节点流  ObjectInputStream,ObjectOutputStream既可以读写8种基本类型,String 类型,又可以读写对象类型的数据;它们的readObject(),writeObject()方 法是用来读写对象的方法;read类型名(),write类型名()是用来读写基本类 型,String类型的数据  ObjectInputStream/ObjectOutputStream的构造方法需要一个InputStream, OutputStream类型的流;它们也是字节流但一般是读写文件,所以采用      FileStream来封装构造ObjectStream 使用ObjectStream可以实现对象序列化,但不是所有对象都可以在流上传 输,可序列化。要使一个对象可以用ObjectStream序列化,该对象则必须 要实现一个接口Serializable接口,可序列化接口。一个对象只有实现了这 个接口,它才能被序列化 要实现Serializable接口,则要实现该接口中的所有方法,然而我们查看 API发现Serializable接口中并没有任何方法,这样的接口是空接口,称为 标记接口;跟Cloneable接口一样。 写程序TestObjectStream.java来实现序列化学生对象 写对象实质上是写该对象的toString()方法的返回值,而默认Object的 toString()的方法的返回值就是类名@地址。所以我们想要正确写入对象属 性,我们得让Student类实现toString()的方法去覆盖父类Object的toString() 方法。 修改程序代码,实现Student的toString()方法 .

.Teacher都要实现Serializable接口  Java中到底哪些类可以实现序列化?即在java中哪些类是实现了 Serializable接口的,则它们就能序列化  在Linux系统中的bin目录下有一个Serialver命令,该命令可查看 某类是否实现了序列化接口。 如:.对象序列化  修改程序代码,实现Student的toString()方法  现在我们序列化的Student都只包含基本类型的数据;如果Student中属性 也是对象,如何序列化?假如给Student增加一个Teacher属性,Teacher 也是一个对象,实现序列化  修改程序代码,增加Teacher类型的对象作为Student的属性实现序列化  通过前面的程序我们总结序列化对象的步骤  该对象的类必须实现java.Serializable接口  如果类的属性/属性的元素又是一个对象则属性对象的类或属性类, 属性元素类也必须要实现Serializable接口  例如:Student中有一个List ts=new new ArrayList().>Serialver Student运行此命令 若无法序列化,则说明Student没有实现Serializable接口 若显示了序列化版本号,则说明Student实现了Serializable接口  Serialver命令可以判断一个类是否实现了可序列化接口,但并不是一个对 象的所有属性都要序列化,对象的某些属性是无需序列化读写文件的  如:我们在进行连网时,ADSL连接就无需保存,因为每次连接都是 不一样的,是临时属性的,是只在本次连接操作使用的  又如:到银行要领取排队号,排队号也是一个临时属性,每次到银行 排队号是不同的,只在本次操作中用,这样的属性无需序列化的 .ts中每个元 素都是Teacher对象则要求ts.io.

java实现Student的mark属性不序列化  一个对象的静态属性是不参与序列化的;Object对象是不能序列化的,因 为Object没有实现Serializable接口  修改程序增加一个Student的属性为Object obj,运行程序发现报错不能序 列化;修改程序Student的属性obj为static,运行程序发现没有报错了,但 obj属性并没有序列化,所以静态属性不参与序列化,Object对象不能序列 化  ObjectStream在读写对象文件时,判断结束的条件是通过EOFException 来判断的;ObjectStream不是过滤流,所以在关闭直接使用他们的close() 方法就可以关闭;  通过对象文件的结束判断,总结分析不同流的读文件的结束条件  字节流:read方法返回-1表示读完了;如while((len=read(byte))!=1){..}  对象流:readObject()返回的是对象,读完了该方法并不是以-1,null 来作为结束条件 .对象序列化  如果一个对象的某些属性是不序列化的,那么如何实现?对于不序列化的 属性,我们采用transient来修饰。Transient修饰的属性是临时属性,不参 与序列化  修改程序TestObjectStream..}  字符流:readLine()方法返回null表示读完了;如 while((str=readLine())!=null){.

java来追加对象,比较追加对象和直接写出多 个对象的区别  在序列化对象时,每序列化一个对象的开始时,都会有ACED字符标识序 列化的开始。所以采用追加方式先写一个对象s1则序列化s1会增加 ACED标识,接着流关闭;再追加一个对象s2时,则又会写ACED标识。 于是追加方式的文件student1.dat比非追加方式的students.dat大  因追加方式添加对象的文件内容与直接写的方式的文件内容不一致,不 准确;所以给文件添加一个对象时,正确的方式是先将原有对象读出放 入集合中,再在集合中添加新对象,然后遍历集合所有元素对象一次性 写回文件。  写程序TestObjectAppend.java实现准确的对象序列化的追加 Tokenized——格式字符串的拆分  StringTokenizer类是允许将字符串分解成标记,它的构造方法需要一个字符 串和一个拆分标记,构造后是一个StringTokenzier对象  StringTokenizer对象是由许多标记组成,其中hasMoreTokens()方法是判断 是否还有下一个标记,可用它来迭代StringTokenizer拆分后的所有标记; nextToken()方法是返回下一标记,可以用它来获得每一个标记并输出 .对象序列化  readObject()方法它读完文件中所有的对象是抛出一个 EOFException异常的,所以我们只要对该异常捕获处理就可以知道 文件结束了。这说明对象序列化是以异常结束。在读取文件中的对 象时,需要利用EOFException来控制循环退出  对象序列化的追加  写程序TestObjectAdd.

String value)将新的键值对添加到Properties中  Load(InputStream in)将具有Properties键值对特性文件加载到输入流中, 这样就可以从输入流中读取键值对 .java实现拆分格式化的字符串  Properties的特点和使用  Properties称为属性类,是java集合中的一种Map,它存储的也是键值对  Properties存储的键和值必须是String类型,它实际上是Hashtable的子类  Properties比Hashtable功能更强大,它主要增加了将键值对进行读写到文件的 功能;有了该功能则可以将键,值写入文件,也可以从具有键值对的 properties文件中读出;  因为Properties有读写键值对文件的特性,所以我们常常使用它来做一些配置 文件;配置一些程序的属性,比如数据库的连接属性等  Properties的构造方法  无参构造:构造一个空属性列表(键值对);  有参构造:创建一个带有默认值的空属性列表  Properties的键值必须是String类型,所以读写键值的方法与Hashtable的 put.格式字符串拆分——StringTokenizer  写程序TestStringTokenizer.putAll不一样。它的方法常用的如下:  getProperties(String key)由String的key获得对应的String value  setProperties(String key.

properties文件写入ADSL客户信息  写程度读取出信息并向文件中再写入客户信息 java的网络编程  ip与端口  网络上的计算机要通信是离不开ip地址,ip地址是计算机在网络上的地址, 一般采用点分十进制表示,由4个0-255的十进制数表示  Ip是找到计算机中的唯一途径,但找到ip却不够,ip所在的计算机还需要 开一扇门才能与外部交流才行,这扇门就是端口  端口是一个数字,从0-65535,我们知道网络通信实际上是2个程序通信, 那如何识别不同的程序?就是靠端口。端口是进程在网络上的标识,网络 上2台主机通信,本质上是2个进程在通信。每个不同的数字端口能启动一 个服务或完成一个功能。如http服务端口为80,很多很安全的服务器就是 只开了80端口。黑客要攻击的基本功就是要攻击80端口  ip的分类  ip常见的分为A、B、C、D、E等几类,由4个0-255的十进制数以‘.java实现使用Properties来维护保存ADSL客户连接信息, 客户信息包括ip,sid,name,passwd,phone  首先建立一个a.网络编程   Store(OutputStream os.String)将生成好的Properties键值对写到输出流指 向的属性文件中  Properties在什么地方/情况下使用  很多应用程序都有选项设置,当我们进行了选项设置后,在程序退出时会 将这些选项值和功能存储到文件,下次在启动应用程序则要将这些选项设 置读到内存生效  写程序TestProperties.‘ 分隔组成 .

ip地址与port端口  A类:第一个数字从0-126,A类网络最大,它能连入的主机数量最多  B类:第一个数字从128-191,B类网络比较大,它能连入的主机较多  C类:第一个数字从192-223,C类网络相对较小,中国的C类地址最 多  D类:第一个数字从224开始,D类网络很少,它支持连入的主机太少 了  端口的分类:0-65535的端口根据功能分为几个部分  0-1023部分是固有端口,这些端口是对用户不开放的,我们不能用, 他们是已经定义好了分配给系统或固定程序软件使用的  1024-48xxx部分上普通端口,开放给用户使用,稳定的,其中部分端 口被一些软件厂商占用了  48xxx-65535部分是动态端口,不稳定,随时可能发生端口会被其他 程序或系统占用  固有端口:主要给系统服务用的;如ftp 21,http 80,telnet 23, echo 7  普通端口:有部分被一些软件厂商占用;如Oracle 1521,Tomcat 8080,Oracle的http服务 8080,Weblogic 7001等  动态端口:最好不用,因为有可能随时会抽出给系统或其他的程序使 用  网络通信的实质 .

ip地址与port端口 A主机 B主机 PA1听音乐 port::22 PA2打游戏 port::24 PA3下载 port::27 port::23 PB1游戏 port::25 PB2音乐 port::26 PB3下载 2个进程间通信 首先B主机开放一些端口给客户机访问使用;如 PB2 25; 接着A客户机的PA2打游戏进程在端口24,去连 接访问B主机的23端口 然后B主机24端口获得连接后就记录下A主机的 端口23 再下来2个进程就开始通信 最后通信完毕则关闭连接  ip和端口的关系  ip地址与port端口的关系就像打电话的总机和分机一样。ip地址就像 总机,端口号就像分机,先由ip地址找到通信的主机,再有端口号找 到该主机上的进程  网络模型与协议  计算机网络分层模型OSI  OSI模型是针对网络通信的实现来分为七层,它是现在网络通信的基 础。OSI网络模型的七层 .

…) Session会话层 port port port Transport传输层 TCP or UDP Transport传输层 (TCP.Telnet.RARP.ARP. Pop3.Smpt.ICMP.…) Link链路层 (Device driver…) data port# data Physical物理层  协议  网络要实现通信,通信双方为了要正常通信,得事先约定好一种规范, 一种标准,一种约定,这就是协议。  对于OSI模型的各层之间是单向以来关系,下层给上层提供服务,上 层使用下层提供的服务,每个层都要完成各自的工作。数据传输实质 上是在物理层上传输,但是在对等层上也是在虚拟传输。为什么?举 例说明  在每个对等层上要传输则都需要协议,所以在每个对等层上都有相应 的协议  例如:中国主席与美国总统之间通信 .UDP…) Network网络层 Data Link数据链路层 Network网络层 (IP.Ftp.网络模型与协议 OSI Model模型 TCP/IP Stack模型 Scenario Application应用层 Application应用层 app app app Presentation表示层 (Http.

网络模型与协议 要实现通信则要在每个 对等层上制定一些协议 文书协议 中国主席 Mic 秘书 文书记录 电码协议 翻译 中←→电代码 发报员 美国总统 Mic 秘书 文书记录 翻译 电代码←→英 发报员 在OSI模型中,要实现 通信则在每个对等层 上都有相应的协议  OSI模型中的对等层协议  应用层 http:超文本传输协议,它是互联网的基石,没有http则没有互 联网 ftp:文件传输协议,实现文件上传,下载 telnet:远程登录协议 Pop3 Smpt:电子邮件协议  传输层:主要解决数据传输问题 Tcp:传输控制协议 Udp:用户数据报协议 .

RARP是网络层协议;它将OSI模型的数据链 路层和物理层作为一层成为“链路层”,主要负责管理设备,驱动等  Socket网络编程  Socket编程是指server与client之间是基于Socket来实现通信的  Socket编程有2种方式,一种是Tcp Socket,另一种是Udp Socket  Tcp与Udp的区别  Tcp传输控制协议,它是面向连接的协议;先建立连接,确认连接连 通了,才发送,接收数据;客户端与服务器端要保持连接;Tcp能够 保证数据地正确传输,它会重发一切错误数据,但它消耗资源多,效 率低;它就像生活中的打电话 .TCP/IP模型与Socket编程  网络层:IP协议主要是解决寻址,路由问题; IP协议不是一个单一的协议,而是一个协议族; 访问网站常用域名,这个域名输入后都会到美国分ip中心将其解 析转换为ip即由域名转ip这需要ARP协议 有了ip反过来得到域名则需要RARP协议 ip寻址一定会找网卡的MAC地址,这需要ICMP协议  TCP/IP模型  它对OSI模型进行了封装;将OSI模型的应用,表示,会话三层作为 一层,称为“应用层”  TCP/IP也有很多协议支持通信,它不只是一个协议,是一个协议族  Http,Ftp,Telnet,Pop3,Smpt是应用层协议;Tcp,Udp是传输 层协议;Ip,Icmp.ARP.

net包中,既然Socket只是负责连 接,而真正交互信息的是I/O流,所以Socket一定有获得相应网络流的 方法。ServerSocket是用在服务器端,Socket是用在客户端  ServerSocket的构造  无参构造 因没有开放端口 基本不用  有一个端口参数构造 服务端需要打开一个端口给客户端访问,服 务器端不需要ip 该方法常用  有端口,最大队列两个参数 jdk1.0中该 方法有问题  有端口,最大队列,绑一个ip三个参数 该方法很少用  ServerSocket的方法 .ServerSocket与Socket  Udp用户数据报协议,它以数据包形式发收;Udp是无连接协议,无 需使客户端和服务器保持连接,所以数据包在传输中可能丢失,也可 能先发送的后到达目的地;它不会重发错误数据,Udp效率高,资源 消耗少;Udp就像生活中的写信或广播  ServerSocket与Socket:它们就要连接保持才能通信,它们是基于Tcp传 输的  Socket是套接字,即ip+端口,有了它2台机器才能实现连接和通信; ServerSocket也是Socket,只是它是用在服务端的Socket,它只负责 连接,不负责交互信息  Socket,ServerSocket都是在java.4中这个构造很有用 但5.

)方法是阻塞方法,会暂停以等待客户端连接,直到连接 上了就打破阻塞;一个服务器端可以连接的客户端数量理论上应 该是无限的,所以考虑accept(...}死循环中  Socket的构造  Socket(ip.)放入一个while(true){.port)它就与服务器的accept()方法交互,进行连 接了  Socket的方法  getInputStream().port)构造方法很常用,用在客户端,客户端要去连接 服务端,需要知道服务器的ip和服务端打开的端口。在客户端 new Socket(ip..ServerSocket与Socket  ServerSocket作为一个Socket,需要关闭,有close()方法  ServerSocket是只负责连接,不能做交互;而Socket是可以管交 互的,所以在客户端和服务器端都需要有Socket才能交互;那 ServerSocket如何连接呢?accept()方法是等待客户端连接的, 这个方法连上了就返回一个Socket,这样就使得ServerSocket转 换为了Socket,可以交互了  accept(.getOutputStream()获得网络输入,输出流,负 责真正地交互信息。想要实现客户端与服务端的交互则在客户端, 服务端需要两套网络流,而且服务器端的输入流对应客户端的输 出流;服务器端的输出流对应客户端的输入流  close()方法是关闭Socket  Tcp Socket编程  网络编程是进程间通信,所以得开2个jvm,所以我们需要写2个类,2个 主方法  Tcp Socket的编程步骤 .

close() br.getOutputStream().pw. DataInputStream dis=new DataInputStream(is).getInputStream(). 将字节流进行封装 获得信息交互的输入流is OutputStream os=s. 获得信息交互的输出流os 信息交互 获得信息交互的输入流is OutputStream os=s.close().close()关闭流 s. 信息交互 InputStreamReaer isr=new InputStreamReader(is) InputStreamReaer isr=new InputStreamReader(is) BufferedReader br=new BufferedReader(isr) BufferedReader br=new BufferedReader(isr) DataOutputStream dos=new DataOutputStream(os).getOutputStream().close()关闭ServerSocket dis. 获得信息交互的输出流os DataInputStream dis=new DataInputStream(is). InputStream is=s.port) 创建一个Socket对象,向ip指定的服 务器端的port端口发起连接 Socket s=ss. OutputStreamWriter osw=new OutputStreamWriter(os) OutputStreamWriter osw=new OutputStreamWriter(os) BufferedWriter bw=new BufferedWriter(osw) BufferedWriter bw=new BufferedWriter(osw) PrintWriter pw=new PrintWriter(os) PrintWriter pw=new PrintWriter(os) dis.close()关闭Socket .accept()调用accept方法, 在网络中进行信息交 这样客户端创建了一个Socket对象, 服务端accept()连通后又返回一个 该方法是阻塞方法它会侦听等待客户 互,字节流不能直接 端发起连接;连接上后会打破阻塞; 读写基本类型数据, Socket对象,这两个Socket对象就可以 获得I/O流来实现通信了 返回一个Socket对象;返回的Socket对 String数据;若想要读 象才真正与客户端进行通信 写这些数据,要考虑 InputStream is=s.dos.close().Tcp Socket编程 Client端 Server端 ServerSocket ss=new Socket(port) 创建一个ServerSocket对象,并让它绑 定打开一个端口,这样客户端才能向 服务端的该端口发起连接 Socket ss=new Socket(ip.dos.close()关闭流 ss.close().pw. DataOutputStream dos=new DataOutputStream(os).close() br.getInputStream().close().

java解决程序的局限性问题,使其支持 键盘连续输入直到输入“bye‖ .java.in来使其支 持键盘输入  本程序修改成支持键盘输入后,则输入交互的次数应该由client 来控制。所以考虑将读写放入循环,直到client端输入”bye‖则 退出输入  修改程序TcpServer1.TcpClient.java来演示  程序测试中的几个问题  网络程序要分别启动2个程序,先启动服务端还是客户端? 先启动服务器端;若先启动客户端会抛出一个 ConnectException异常表示connect refused连接拒绝 启动服务器后,再次启动服务器(连续启动2次服务器)则会抛异 常BindException绑定异常,表示ip地址已经被使用了;此时必 须先关闭一个启动的服务器,再启动才OK  程序的局限性  本程序客户端向服务器端发送信息,只发送一次,而且不能支 持从键盘灵活输入;所以考虑修改程序使用System.Tcp Socket编程  实现启动服务器后,每连接上一个客户端;客户端向服务器发送一个名 字字符串;接着服务器接收后就发回一条响应”Welcome login ‖+客户 端名字;接下来服务器再连续发送3个”Hello‖,客户端连续接收。写程 序TcpServer1.TcpClient2.TcpClient.java.java.java为 TcpServer2.

Tcp Socket编程  本程序已经实现了可以从键盘输入信息,并且可以与服务器 实现多次信息交互,但本程序服务端只能连上一个客户端, 为一个客户服务;如果一个服务器要为多个客户端服务,可 以有多个客户连接上来进行通信,怎么办?  作业  在网络上有很多共享软件,使用的次数是有限制的,那么如何来记录使 用次数呢?采用Properties来实现  用对象序列化把若干个Employee对象写到文件中再读取出来  用字符流把文件中唐诗排列成古文形式,格式如下: 床前明月光 凝似地上霜 举头望明月 低头思故乡 唐诗排列转 换古文排列 低举凝床 头头似前 思望地明 故明上月 乡月霜光 .

Java的高级编程之 Java网络编程 Day16-Day17 .

Day17  掌握TCP Socket多客户端与服务器交互信息的 实现  理解和掌握UDP Socket的网络通信编程  掌握UDP Socket编程步骤和方法  实现UDP Socket网络编程程序  理解统一资源定位URL的概念,特性和作用  掌握URL的作用和编程应用  分析局域网qq聊天室的架构和界面设计  理解局域网qq聊天室的实现原理和通信机制  掌握局域网qq聊天室的技术,技能要点和设计 步骤 .

hashCode()方法,这就意味着比较 InetAddress对象是否相等时不是比较对象的地址,而是比较对象中内容即 网址的值  InetAddress无构造器提供,这就说明它的构造私有了,不能用  InetAddress没有构造我们可以通过getAddress()返回ip地址,返回类型是字 节数组byte[],那么ip地址如何存储到字节数组中? .java,TcpClient3.java来实现一个服务器服务于多个客户 端  InetAddress  InetAddress类是指ip地址类;ip很重要,没有ip就没有互联网  InetAddress类实现了可序列化接口,它有2个子类,一个是4位ip的 InetAddress,另一个是6位ip的InetAddress类  InetAddress中重写了equals().TCP Socket多线程编程  Tcp Socket通信中实现一个服务器同时与多个客户端交互  之前的服务器之所以只能为一个客户端服务是因为服务器的ServerSocket只 有一次accept(),所以只能等待一个连接连通;  当有多个客户端来连接时,则考虑accept()可放入循环连接侦听,当每个客 户端与服务器连接上后,服务器都需要一个读写过程来为之服务,所以我们 可考虑使用线程来实现。即accept()反复侦听,一旦有一个客户端连接上来, 则服务器就生成一个线程来与该客户端进行通信。如:accept同时侦听到1, 2,3,4个线程的连接。  accept方法调用,线程创建都要放入循环里,在线程中维护一个accept返回 的socket来获得相应的网络流来通信  写程序TcpServer3.

java来实现打印显示本机的ip地址  UDP Socket多线程编程  UDP协议可把它看成邮局发收信件的形式,就像广播一样,无连接的  发收信件需要什么要素?信件、邮局(邮筒);发送接收双方需要2个要素。 信件对应DatagramPacket对象,邮局对应DatagramSocket对象  邮局发收信件,信件到了家,如果家里没人,邮递员是不会去寻找你的; 你的信件投错邮筒了,信件也不会重发,而且邮局不会与你保持一直联系  UDP Socket编程特性  UDP Socket就像一个邮筒,既可发送也可接收  UDP是无连接的协议,无需保证连通也可以通信,所以UDP通信比 TCP简单  UDP Socket发送数据只管发送,不需要确认对方是否接收;接收数据 也只管接收,不需要知道是否接收正确  DatagramPacket创建一个数据包以便做投递服务  UDP Socket通信是需要DatagramSocket对象 .168这两个数用 1个byte的正数无法表示的,那如何处理?可以用负数表示,因为每一 个负数都对应一个正数形式的二进制形式表示,负数值=256-正数  getAllByName(Host)按主机名取主机的InetAddress对象  getLocalHost()取本机的ip的InetAddress对象,这是一个static方法  写程序TestInetAddress.21,每个数字代表一个字 符,但是要注意1个字节能表示的数是0-127,所以192.168.UDP Socket多线程编程  Ip地址是以点分十进制形式表示如192.0.

InetAddress.offset.DatagramPacket(byte[].length).off set.length.UDP Socket多线程编程  UDP Socket通信必须是客户端先给服务器发送信息,因为只有客户端发 了,服务器才知道客户端的地址,才能回复。  TCP Socket通信则客户端与服务器谁先发数据无所谓,因为Tcp可以通过 accept()获得客户端地址与端口  查看DatagramPacket与DatagramSocket的API  DatagramSocket的构造  DatagramSocket()无参构造,最常用  DatagramSocket(DatagramImpl)该构造是受保护的,几乎不用; DatagramImpl是在底层实际干活的实现类,DatagramSocket是 一个上层类,我们不需要关心底层类,只需要关心上层类就OK  DatagramSocket(port)开放一个端口最常用  DatagramSocket(端口,InetAddress)构造Socket无需邦定ip的, 不常用  DatagramPacket的构造  DatagramPacket的构造中有2个带参SocketAddress参数的几乎 不用,因为信件只需要存储内容和指明长度  DatagramPacket(byte[].In etAddress.length.DatagramPacket(byte[].length).port)是一对;字节数组相当于信封,存储信的内容, length代表信的长度  DatagramPacket(byte[].port)是一对;offset偏移量表示信的内容 是从数组的哪个位置开始,这2个带offset的方法很少用 .

length);  DatagramSocket发送,接收  发送,接收是由邮局来做,而发送,接收的对象是信件;所以 DatagramSocket的send(DatagramPacket), receive(DatagramPacket)方法实现发送接收,参数为 DatagramPacket  作为发送者,接收者谁先启动?像广播一样,我们得先打开收音机 等待接收,所以接收方先启动。如果接收方启动了,但还没有发送 怎么办?没关系,因为接收方法receive方法是阻塞方法会一直等着 接收,直接收到才会打破阻塞  其他方法 .port)给发送还是接收方 用 作为发送邮筒而言,它无需关心发到哪里,会由机器来分,所以作 为发送者使用DatagramSocket()无参构造 作为接收邮筒而言,它想要接收则需要做好准备,开放一个端口给 外来者,所以作为接收者使用DatagramSocket(port)有参的 从信件的角度来考虑,发送信件上需要注明发到哪里才能正常发送, 所以作为发送的信件则用 DatagramPacket(byte[].length.port); 接收信件无需关心信件是从哪里来,而是关心信件内容,所以作为 接收的信件,则使用DatagramPacket(byte[].InetAddress.length), DatagramPacket(byte[].UDP Socket多线程编程  在DatagramSocket.DatagramPacket的常用4个构造中如何选择? DatagramSocket().length.InetAddress.DatagramSocket(port)给发送还是接收方用? DatagramPacket(byte[].

getAddress().length.len,serverAddress.send(dp). clientAddress.len)准备一个收信封,接收邮件信息 ds.send(dp1).getPort().receive(dp1)调用ds的receive 方法接收发回的邮件信息 ds.调用send方法发送邮件 DatagramPacket dp1= new DatagramPacket(buffer.UDP Socket多线程编程 DatagramPacket的getlength().clientPort) 准备发回到发送端的发信封 发送方 DatagramSocket ds=new DatagramSocket() 建立一个邮箱用于发送邮件 DatagramPacket dp=new DatagramPacket( buffer.close()关闭发送端的邮箱 .serverPort) 准备一个发信封,封装好邮件信息, 指定发送的服务器地址,端口 ds.length) 准备一个接收信封,准备好数据空间接收回信 ds.close()关闭接收方的邮箱 ds.receive(dp)调用ds的receive 方法接收信息到信封dp dp.调用send方法将反 馈信封信件发回给发送端 ds. 通过接收的邮件,然后调用getAddress.getOffset()方法可获得信的长度,偏移 量 UDP Socket编程步骤   接收方 DatagramSocket ds=new DatagramSocket(port) 建立一个邮箱,邦定打开端口号用于接收信息 DatagramPacket dp=new DatagramPacket( buffer.clientPort=dp. getPort方法来获得发送端的ip地址和端口 DatagramPacket dp1= new DatagramPacket(buffer.

html时文件路径和文件名  URL的构造和其他方法  URL(String)参数字符串包括了协议,主机地址,端口,文件名4个 部分,该方法最常用 .sina.html  http:协议名;www.com.cn:8080/phps/index.java来实现UDP通信  统一资源定位URL  什么是URL  URL是统一资源定位器,它是指向互联网的资源的指针,即它就是网址  URL的作用  URL主要时针对Http.UDPSend.com.sina.cn主机名或IP;8080端口; phps/index.URL  写程序UDPReceive.java.Ftp这2个协议的;Http是超文本传输协议,即URL 可以解决打开一个网页的问题;Ftp是文件传输协议,即URL可以解决文 件上传,下载问题  URL的API  URL是一个final类,它没有子类,实现了序列化接口,它可以序列化  URL对象指向互联网资源的指针,即就是一个网址;一个网址包括哪些 部分?  一个网址包括协议,主机名,端口,文件资源名组成  如:http://www.

String)4个String参数分别代表协议,主机 地址,端口,文件名,该方法几乎不用  其他构造都是拆了网址的各各部分,这些方法基本不用,只有第一 各构造最常用  URL是网址可访问一个网页文件,那如何能获得文件名呢?getFile() 获得打开的网页文件名  openStream()打开一个输入流,可读入网页的内容  URL没有提供获得输出流的方法,因为一般情况下,一个网页文件 是不允许用户随意修改的,那么网页的输出流存在吗?能打开吗? 存在,也能打开,只是URL做不到,即使输出流打开了也写不进去 内容  openConnection()方法可以由URL得到URLConnection对象(即先有 网址,才能连接)  URLConnection是URL连接类,有了它可以创建URL连接对象,连 接对象调用connect()就可以连接上URL的网址。  URLConnect对象的getInputStream(),getOutputStream()就是获得 网络输入流,输出流;这2个方法得到的是低级流,使用时可以使用 高级流封装。  从URL上读则为下载;往URL上写则为上传  使用URL实现打印显示网页源码  看一个网页源码,常用方法是右击网页/选择菜单”查看源码”  在java程序中不能用前面的方法,而在java程序中怎么做? .URL  URL(String.String.String.

URL  写程序TestURL.java来实现 .java来演示URL的使用  我们知道每一个网页资源文件,都会有一个文件头,文件头包含很 多的 字段信息;对于这些文件头信息都是指定网页特性的,文件头 有很多字段,字段包括字段名称和字段值  我们可以使用java程序来获取这些字段值,如何做?得看 URLConnection的方法  getHeaderFieldKey(int)获得文件头信息中第n个头字段的名称 (键)  getHeaderField(int)获得文件头信息中第n个字段的值  getData()返回Data头字段的值  getContentType()返回文件头中字段Content-Type的值  getExpiration()返回Expiration头字段的值  getContentLength()返回文件头中字段Content-length的值  getLastModified()返回LastModified头字段的值  getContentEncoding()返回文件投中字段content-encoding的值  要求实现从键盘输入任意一个网址(合理),然后打印出它的文件 头信息,包括打印content-type,content-length,content-encoding 字段,再读出网页的前100行的内容  写程序TestURLConnection.

Sign up to vote on this title
UsefulNot useful