Java常用的API
Api:应用程序接口,指的是系统中提供的大量的类及方法。
StringBuffer:
回顾:String类的对象一旦声明则不可以改变。
String对象不适合于以下情况。
public class APIDemo01
{
public static void main(String args[])
{
String str = \"\" ;
for(int i=0;i<20;i++)
{
str += i ;
}
System.out.println(str) ;
}
};
StringBuffer也是一个字符串对象,但是,此对象种的内容可以改变。只是代码的形式不同,StringBuffer必须先实例化。
StringBuffer可以改变,String不可以改变。
包装类:
IO操作时字符串变为整型:Integer。
在java中提倡一种思想,一切皆对象,java中有八种数据类型。
此处以前讲过。
Runtime类
运行时类—使用此类可以调用本机上的程序。
Runtime类中没有任何一个构造方法,则外部无法实例化。
因为在类中将构造方法私有化了。
Random类
表示一个随机数的类,例如,产生一个不大于100的10个随机数。位于java.util包下。
取得时间的类
Date、Calendar(此类可以将时间精确到毫秒)
Calendar是一个抽象类,要想实例化此类则需要子类在jdk中已经明确给出了操作此类的方法。
有时候希望可以对格式进行转换
原格式1:2009-11-17 16:19:33
转换的格式:2009年11月17日16时19分33秒
应该用几步完成以上操作呢?
1、 从原格式中丢弃格式取出具体的时间数字。
2、 准备一个新的格式。
3、 将原格式中的时间数字放到新的格式中去。
SimpleDateFormat类,此类在java.text包下。
以上介绍的只是一些基本的常用类。
Jdk开发中经常要使用到的一些小功能或小工具。
Java高级特性
今天的任务
1、 hashCode方法作用介绍。
2、 对象克隆。
3、 比较器。
4、 Class类。
hashCode—哈希玛。
Map—hashtable,hashMap。
实际上每一个对象都有一个hashCode。
如果只复写hashCode方法根本不会起作用,还需要同时复写equals方法。
对象克隆
就是对象的复制。
IO序列化:Serializable—可以序列化。
要完成克隆的类必须具备以下2种条件:
1、 类必须实现Cloneable接口,表示可以被克隆。
2、 类必须复写Object类中的clone方法。
比较器
Arrays—专门用于数组排序。
可以对任意数据类型排序。
例题:给出一个Person类里面包含姓名、年龄、成绩,声明5个Person对象的对象数组,要求对数组中的内容进行排序,排序规则如下:按成绩由高到低排序,如果成绩一样,就按照年龄由高到低排序。
比较器除了在Arrays类的排序外还可以用在TreeSet上,实际上TreeSet也需要比较器支持。
Class类
类—对象。
我们希望由对象能够知道其所属的类是哪个。
Class能够动态的为类实例化。
Class类本身没有任何构造方法。
总结出Java中对象实例化的途径:
1、 直接用new,代码比较直观,但是程序会出现耦合度。
2、 程序出现了接口,如果一个接口的子类直接通过new实例化会造成程序的耦合,所以,使用工厂进行解耦和操作。
3、 对象的克隆,将对象拷贝一份,但是,此种方法需要在子类中复写clone方法。
4、 Class类,通过Class类来实例化一个对象,通过字符串操作完成。
关于Class类只需要重点掌握实例化对象的操作。
Java网络编程
Java网络编程
C/S程序应用:客户/服务器;msn,一个客户端,客户端打开之后连接到服务器上。
B/S程序应用:浏览器/服务器;所有的代码直接放在服务期上即可—jsp。
程序分为2种:
基于tcp协议:Socket,可靠的服务:a—b;
基于udp协议:不可靠,短信功能。
如果要编写一个tcp程序需要java的2个包支持。
Java.net.*:主要提供网络支持。
|-ServerSocket类:主要用来写服务器端程序。
|-Socket类:客户端程序。
Java.io.*:传递信息流。
客户端就2个功能
1、 建立Socket。
2、 接收输入的命令(输入流)—网络上传输的程序靠的是字节流。
在jdk中也准备了2个专门用于实现udp的类:
DatagramSocket 和DatagramPacket。
Java多线程
中断线程的运行:当一个线程运行时候,另一个线程可以调用对应的Thread对象的Interrupt()方法来中断它。
Public void interrupt();
查看线程的中断状态:可以在Thread对象上调用isInterrupted方法来检查任何线程的中断状态。
Public Boolean isInterrupted()
线程如果中断之后再休眠,则会清除中断标志。
多线程问题—资源的协调
对共享对象的访问必须同步,叫做条件变量。Java语言可以通过监视器使用条件变量实现线程的同步。
监视器阻止2个线程同时访问同一个条件变量,它的作用如同锁一样作用在数据上。
线程1进入卖票方法,获得监视器,也就是加锁;当线程1的方法执行完毕返回时,
释放监视器,也就是开锁。线程2的卖票方法才能进入。
用Synchronized来标识的区域或方法即为监视器监视的部分。
一个类或一个对象由一个监视器,如果某一个程序中有2个方法使用了Synchronized标识,则它们一直在一个监视器管理之下。
一般情况下,只在方法的层次上使用关键区,也就是Synchronized关键字。
同步操作就是在方法之中加入了一个Synchronized关键字,表示此方法为同步方法。
提供了Synchronized关键字之外的第二种使用,同步代码块
同步代码块就是使用了Synchronized关键字括起来的代码表示同步代码块,同步代码块需要一个同步对象,实际上就是用{}括起来的代码。
同步代码块—在java中使用Synchronized关键字进行同步
Synchronized (对象)
{
同步代码
}
应该是对当前操作的线程进行同步,所以此操作应该使用 this,为this进行同步。
上次回顾:多线程同步问题(synchronized)
在多个线程中操作同一个资源的时候产生的问题
同步可以通过两种方式实现
同步方法
同步代码块
同步会产生一个问题—死锁。
死锁就是在多线程编程中由于处理不当而造成程序停止运行的一种状态。
同步的问题—线程死锁的问题
死锁一般而言,是在程序运行中发生的一种状态,所以此处只是简单模拟一下。
此处有2个线程—线程1是笔记本,线程2是钢笔。
线程1执行—把钢笔给我,我才能给你笔记本。
线程2执行—把笔记本给我,我才能把钢笔给你。
死锁大家只需要了解其产生的根本原因即可。
同步有一个经典的范例—生产者和消费者
线程之间通信
一个线程向数据存储空间添加数据(生产者),另一个线程从数据存储空间中取走数据(消费者)。
这个程序有2种例外需要考虑:
1、 假设生产者线程刚向数据存储空间添加了一个人的姓名,还没有加入这个人的性别,cpu就切换到消费者线程,消费者线程把这个人的姓名和上一个人的性别联系到了一起。
2、 生产者放了若干次的数据,消费者才开始取数据,或者是,消费者取完一个数据后,还没等到生产者放入新的数据,又重复取出已取过的数据。
可能会出现的2个问题:
1、 生产者比消费者快时,消费者会漏掉一些数据没有取到。
2、 消费者比生产者快时,消费者取相同的数据。
工厂模式综合讲解
工厂设计模式
Class类的反射。
IO操作。
回顾一下到底什么是工厂设计及好处?
1、 对于刚才的工厂设计存在以下问题
如果现在客户main要求既可以使用Apple对象,也可以使用Orange对象,则无法通过工厂完成。
2、 对于第二种实现存在以下问题
a) 如果输入参数错误,则会出现空指向异常。
b) 如果在子类中扩充了一个子类,则要修改工厂(工厂中如果没有子类的判断,则无法使用这个子类)。
3、 通过第三种实现去解决第二种实现中修改工厂的操作。
解决了工厂由于增加了子类需要修改的问题。
一个新的问题产生了,在项目中可能有几十个类同时实现了同一个接口,那么此时用户如何知道已有的接口子类呢?
代号—子类的包.类名称(key--value)。
要有一个文件列表,给用户列出全部的代码—子类的映射。
4、 第四种实现解决了用户无法知道全部子类的问题,同时通过了Properties保存了全部的子类信息,之后通过代码进行操作。
程序中依然存在问题,如果程序现在扩充了一个子类,则需要修改设置的属性。
解决的方法:通过文件保存Properties中的内容,以后,修改文件即可,而不用去修改类本身。
总结:
可能有大部分人认为工厂设计过于复杂,而且没有用处,具体的用法需要通过大量的训练才能够彻底掌握工厂设计模式的好处。
如果一个接口需要一个工厂的话,那么如果有100个接口,则会出现100个工厂,程序的维护又会很困难。
Java接口与类集综合应用
接口与类集综合应用
List、Set、Map。
看以下一种情况。
图书大厦里可以放很多种的书。
儿童书。
电脑书。
建筑书。
要求实现以下一种功能:
模拟图书大厦,图书大厦里可以存放多种书目,而且可以进行添加操作、删除操作、查询操作。
一个类集中可以加入多个对象,对应于儿童书、电脑书。
图书大厦-->List-->书的接口<--各种书。
Java类集应用
类集应用
例如:以下一种关系,一个人拥有多个Email。
分析:
1、 完成此功能需要多少个类?
a) 人—类;
b) Email—类;
c) 多个?如何体现?在Person类中加入一个集合,此集合中保存多个Email地址。
一对多的关系,一个人拥有多个Email,是数据库中一种一对多的关系。
多对多的关系,一个学生可以选多门课程,一个课程可同时被多个学生选择。
文件操作
文件操作
本章目标
1、掌握文件类(File类)的使用
2、掌握IO包中流的基本应用
3、了解字符编码问题
4、掌握对象序列化
文件类分为三大类
1、 file类,文件操作类
2、 字节操作类
3、 字符操作类
File类:File类是io包中唯一代表磁盘文件本身的对象,File类定义了一些与平台无关的方法来操作文件,通过调用File类提供的各种方法,能够创建、删除、重命名文件,判断文件的读写权限是否存在,设置和查询文件的最近修改时间。
直接与文件操作有关的类。
在f盘上创建一个demo.txt文件。
Import java.io.*;
Public class IODemo01
{
public static void main(String args[])
{
File f = new File(“f:\\\\ demo.txt”);
Try
{
f.createNewFile();
}
Catch(Exception e)
{
System.out.println(e);
}
}
}
文件操作时会进行判断,如果文件已经存在,则不会重新创建。
能不能通过程序直接判断文件是否存在呢?/是可以的
Import java.io.*;
Public class IODemo02
{
Public static void main(String args[])
{
File f = new File(f:\\\\ demo.txt);
If(f.exists())
{
System.out.println(“文件已经存在”);
}
Else
{
System.out.println(“文件不存在”);
}
}
}
操作:能否完成以下操作
如果文件存在则删除,如果文件不存在则创建。
Import java.io.*;
Public class IODemo03
{
Public static void main(String args[])
{
File f = new File(f:\\\\ demo.txt);
If(f.exists())
{
f.delete();
}
Else
{
f.createNewFile();
}
}
}
已经明确知道了可以通过File类找到全部文件
问题:能不能使用File类去取出d盘下的全部文件呢?是可以的
递归:一个方法自己调用自己的情况。
Import java.io.*;
Public class IODemo04
{
Public static void main(String args[])
{
Loop(“d:\\\\”);
}
Public static void loop(String dir)
{
File f = new File(dir);
String str[] = null;
If(f.isDirectory())
{
Str = f.list();
For(int i=0;i Loop(dir+”\\\\”+str[i]); } } Else { System.out.println(dir); } } } 下面我们讲解输入输出方法 什么是数据流? 数据流是指所有的数据通信管道。 在java中有关流的操作使用java.io.*. 出于安全的考虑,小应用不能实现文件io流。 读写过程 读:打开一个流,如果有信息,则读入,最后,关闭流。 写:打开一个流,如果有信息,则写入,最后,关闭流。 打个比方:读一本书的过程 1、 要找到这本书。 2、 要从书中读取文字过渡到大脑之中。 3、 书读完之后要将书放下 下面我们讲解RandomAccessFile 1、RandomAccessFile类支持”随机访问”方式,可以跳转到文件的任意位置处读写数据。 2、RandomAccessFile对象类有个位置指示器,指向当前读写处的位置,当读写了n个字节后,文件指示器指向这n个字节的下一个字节处,该类仅限于操作文件。 3、new RandomAccessFile(f,”rw”);//读写方式 4、new RandomAccessFile(f,”r”);//只读方式 5、当程序需要以读写的方式打开一个文件时,如果这个文件不存在,程序会创建。 6、支持随机文件操作的方法。 7、readXXX()或writeXXX()。 8、skipBytes()将指针向下移动若干字节。 9、seek()将指针调到所需的位置。 10、getFilePointer()返回指针当前位置。 11、length()返回文件长度。 12、利用seek(long pos)方法查找随机文件中的信息,例,把若干个32位的整数写到一个名为temp.dat的文件中,然后利用seek方法,以相反的顺序再读取这些数据。 Import java.io.*; Public class IODemo07 { Public static void main(String args[]) { //随机读取 RandomAccessFile raf1 = new RandomAccessFile(“f:\\\\demo.txt”,”rw”); //随机读取有一个限制,就是说如果要进行操作,则必须指定好数据的存取长度 //保存姓名(8位字符串)和年龄(int 4) String name = “zhangsan”; Int age = 20; Raf1.write(name.getBytes()); Raf1.writeInt(age); Name = “lisi”; Age = 30; Raf1.write(name.getBytes()); Raf1.writeInt(age); Name = “wangwu”: Age = 33; Raf1.write(name.getBytes()); Raf1.writeInt(age); Raf1.close(); RandomAccessFile raf2 = new RandomAccessFile(“f:\\\\demo.txt”,”r”); //读取第二个人的数据。 raf2.skipBytes(12); byte b[] = new byte[8]; raf2.read(b); int age2 = raf2.readInt(); System.out.println(new String(b)+”-->”+age2); } } File与文件有关 RandomAccessFile类与文件内容有关,但是,此类有一个缺点,就是说如果要跳转,则需要数据的保存长度。 字节流与字符流 输入字节流:InputStream 输入字符流:Reader 输出字节流:OutputStream 输入字符流:Writer 我们以OutputStream类来讲解 OutputStream类是一个抽象类,在java中上述的四种类都是抽象类。 抽象类必须通过子类来实例化。 举例:现在希望向文件中打印一句话:”hello,verybody” FileOutputStream为OutputStream实例化 InputStream与OutputStream InputStream与OutputStream主要用来对字节流进行操作。 主要操作方式: 1、 用File类找到一个文件。 2、 用File类的对象去实例化InputStream或OutputStream的子类对象。 3、 对文件进行读/写操作。 4、 关闭文件。 既然可以从程序中向文件中写入内容,那能否从文件中读出内容呢?肯定是可以滴 InputStream-->FileInputStream InputStream与OutputStream所操作的都是字节操作-->所有的数据都要通过byte数组操作。 在java中提供了另外的两套类,此类用于操作字符:Reader,Writer。 字符流输出时如果不关闭则无法将内容写入到文件。 根本原因是如果字符流不关闭,则内存中的数据不会强制性的输出到文件,即,字符流操作中使用了缓存,在关闭时会强制性的情况缓存,也可以使用flush方法手工清空缓存。 字符流用到了缓存,而字节流没有用到缓存。 管道流:线程间的通信可以用管道流。 import java.io.* ; // 定义一个发送者 class SendDemo implements Runnable { private PipedOutputStream out ; public SendDemo() { out = new PipedOutputStream() ; } public PipedOutputStream getOut() { return this.out ; } public void run() { String str = \"Hello LuoHui\" ; try { out.write(str.getBytes()) ; out.close() ; } catch (Exception e) { } System.out.println(\"SendDemo --> 发送的内容:\"+str) ; } }; class ReceDemo implements Runnable { private PipedInputStream in = null ; public ReceDemo() { in = new PipedInputStream() ; } public PipedInputStream getIn() { return this.in ; } public void run() { byte b[] = new byte[1024] ; int len = 0 ; try { len = in.read(b) ; in.close() ; } catch (Exception e) { System.out.println(e) ; } System.out.println(\"ReceDemo --> 收到的内容是:\"+new String(b,0,len)) ; } }; public class IODemo12 { public static void main(String args[]) { SendDemo sd = new SendDemo() ; ReceDemo rd = new ReceDemo() ; Thread send = new Thread(sd) ; Thread rece = new Thread(rd) ; // 将两个线程进行连接 PipedOutputStream out = sd.getOut() ; PipedInputStream in = rd.getIn() ; // 将输出连接到输入 try { out.connect(in) ; } catch (Exception e) { } send.start() ; rece.start() ; } }; ByteArrayInputStream ByteArrayInputStream是输入流的一种实现,它有2个构造函数,每个构造函数都需要一个字节数组来作为数据源; ByteArrayInputStream(byte[] buf) ByteArrayInputStream(byte[] buf,int offset,int length) ByteArrayInputStream() ByteArrayInputStream(int) 如果程序在运行过程中要产生一些零时文件,可以采用虚拟文件方式实现,jdk中,提供了ByteArrayInputStream和ByteArrayOutputStream两个类可以实现虚拟内存虚拟文件的功能。 注意全部是在内存中实现的。 输入输出方法: System类管理标准输入输出流和错误流。 System.out:把输出送到缺省的显示(通常是显示器)。 System.in:从标准输入获取输入(通常是键盘)。 System.err:把错误信息送到缺省的显示。 每当main方法被执行时,就自动生成上述三个对象。 System.out.println();向屏幕上打印信息。 PrintStream/PrintWriter:实际上是一个打印流,打印流比普通的OutputStream/Writer提供了更多的打印数据的方法。 OutputStream String-->byte[]; System.in:是一个专门用于键盘输入数据的文件流。 使用System.in为InputStream实例化之后,内容确实可以输入了,但是,程序存在以下2个问题: 1、 输入的内容长度受限制。 2、 如果输入的中文超过了容量,则可能出现乱码。 实际上在输入数据的时候,更希望将全部的数据一次性的取进来,如果一次性读取,则肯定不会出现乱码问题。 要想实现上述功能,则需要将输入的数据放到一个缓存之中,BufferReader。 此类在实例化时需要接受一个reader的子类对象。 System.in-->inputStream类型的-->字符类型。 字节流于字符流的转换 inputStreamReader和outputStreamWriter这2个类是字节流和字符流之间转换的类,inputStreamReader可以将一个字节流中的字节解码生成字符。 outputStreamWriter将写入的字符编码成字节后写入一个字符流。 inputStreamReader:是将输入的内容由字节变为字符。 outputStreamWriter:是将输出的内容由字符转化为字节。 文件(字节)-->内存-->字符。 上次回顾: File类直接与文件本身有关系。 字节流:OutputStream和InputStream。 字符流:Writer和Reader。 存放在文件中的都是字节,而读到内存中才是字符。 打印流:PrintString/PrintWriter提供了各种打印功能,可以输出任意的内容。根据实例化对象的不同输出的位置也不同。 System.in:键盘输入流;System.out:屏幕输出流; 输入数据的一个基本格式:BufferedReader。 字符集 GBK、GB2312、ISO8859-1。 设置系统编码字符集:System.getProperties().put(“file.encoding”,”iso8859-1”); 列出系统的全部设置属性: System.getProperties().list(System.out); 转换编码:String类中的: getBytes()方法。 文件保存时所使用的编码。 GBK:包含了繁体和简体的字符集。 GB2312:主要是指简体中文。 ISO8859-1:是国际通用编码。 File.encoding= GBK,jvm中默认的文件编码为GBK。 假设在程序中将编码变为ISO8859-1,则会如何呢? 实际上如果两个的编码不匹配,则在文件保存时会出现乱码。 乱码产生的根本原因:就是两个操作间的字符集没有统一起来。 SequenceInputStream类 SequenceInputStream用来合并文件。 用于合并2个文件的内容 Public SequenceInputStream(InputStream s1,InputStream s2) 接收2个InputStream对象,这就意味着程序需要先使用InputStream找到2个文件。 import java.io.* ; public class IODemo25 { public static void main(String args[]) throws Exception { InputStream in1 = null ; InputStream in2 = null ; // 建立一个输出流 OutputStream out = null ; in1 = new FileInputStream(new File(\"f:\\\\luohui1.txt\")) ; in2 = new FileInputStream(new File(\"f:\\\\luohui2.txt\")) ; out = new FileOutputStream(new File(\"f:\\\\luohuinew.txt\")) ; // 此处相当于将两个文件合并了 SequenceInputStream seq = null ; seq = new SequenceInputStream(in1,in2) ; // 文件合并之后输出到:luohuinew.txt文件之中 int c = 0 ; while((c=seq.read())!=-1) { out.write(c) ; } in1.close() ; in2.close() ; out.close() ; seq.close() ; } }; 后面的内容为java,甚至是j2ee都占有很大比重的部分—序列化 对象序列化 1、 对象序列化是指把对象写到流中,对象的反序列化是指从流中恢复对象。 2、 对象序列化的优点在于即使程序运行结束,对象仍然可以被保存下来。 3、 对象所在的类必须实现Serializable接口,才能被序列化。 对象序列化的步骤 1、 创建一个对象输出流,它可以连接到一个其他的流,比如文件输出流。 ObjectOutputStream out = new ObjectOutputStream(new fileOutputStream(“c:\\\\objectFile.obj”)); 2、 通过对象输出流的writeObject方法写序列化对象。 Out.writeObject(“hello”); Out.writeObject(new Date()); Out.writeObject(serialObject); 如果需要将对象变为byte流,则需要将对象进行转化,ObjectOutputStream,此种做法类似PrintWriter/PrintStream,谁为objectOutputStream提供实例化,就向哪里输出。 对象反序列化的步骤: 1、 创建一个对象输入流,它可以连接到一个其他的流,比如文件输入流。 ObjectInputStream out = new ObjectInputStream(new fileInputStream(“c:\\\\objectFile.obj”)); 2、通过对象输入流的readObject方法写序列化对象 Out. readObject(“hello”); Out. readObject(new Date()); Out. readObject(serialObject); 必须明确告诉ObjectInputStream从哪里读内容。 一个序列化的核心部分:Serializable。 问题: 在Person类中没有覆写接口中的任何一个方法。此接口只是一个声明性接口,表示实现此接口的类可以被序列化。 问题: 现在在程序中姓名和年龄都被序列化,现在不希望年龄被序列化? Transient关键字:当不希望类中 的某个字段被序列化的时候,应用Transien表示这个字段是不能被序列化的。 课后练习题:设计一程序,可以实现文件的拷贝操作。 1、 要求:模仿dos的copy命令,输入两路经名。 2、 提示:可以使用File、FileInputStream、FileOutputStream实现。 3、 执行如下:java copy c:\\\\1.txt d:\\\\2.txt 合stem.outam InputStream 因篇幅问题不能全部显示,请点此查看更多更全内容