Java学习笔记(第五周)

一、流

1.流概述:
流是一组有序的数据序列,根据操作的类型,可分为输入流和输出流两种。I/O(Input/Output)流提供了一条通道程序,可以使用这条通道把源中的字节序列送到目的地。虽然I/O流经常与磁盘文件存取有关,但是程序的源和目的地也可以是键盘、鼠标、内存或显示器窗口等。
在这里插入图片描述
2.输入输出流:
①输入流:
InputStream类是字节输入流的抽象类,是所有字节输入流的父类。InputStream类的具体层次结构如图所示:
在这里插入图片描述
该类中所有方法遇到错误时都会引发IOException异常。下面是对该类中的一些方法的简要说明如下表所示
在这里插入图片描述
Java中的字符是Unicode编码,是双字节的。InputStream是用来处理字节的,在处理字符文本时不是很方便。Java为字符文本的输入提供了专门一套单独的类Reader,但Reader类并不是InputStream类的替换者,只是在处理字符串时简化了编程。Reader类是字符输入流的抽象类,所有字符输入流的实现都是它的子类,Reader类的具体层次结构如下图所示:
在这里插入图片描述
②输出流:
OutputStream类中的所有方法均返回void,在遇到错误时会引发IOException异常。下面对OutputStream类中的方法作一简单的介绍,如下表所示:
在这里插入图片描述
Writer类是字符输出流的抽象类,所有字符输出类的实现都是它的子类,Writer类的层次结构如下图所示:
在这里插入图片描述
3.File类
①文件的创建与删除:
可以使用File类创建一个文件对象,通常使用以下3种构造方法来创建文件对象。
File(String pathname)
File(String parent , String child)
File(File f , String child)
②获取文件信息:
File类提供了很多方法用于获取文件本身的一些信息,File类的常用方法如下表所示。
在这里插入图片描述
4.文件输入输出流:
①FileInputStream与FileOutputStream类:
FileInputStream类与FileOutputStream类都是用来操作磁盘文件。如果用户的文件读取需求比较简单,则可以使用FileInputStream类。该类继承自InputStream类。FileOutputStream类与FileInputStream类对应,提供了基本的文件写入能力。FileOutputStream类是OutoputStream类的子类。
②FileReader类和FileWriter类:
使用FileOutputStream类向文件中写入数据与使用FileInputStream类从文件中将内容读出来,存在一点不足,即这两个类都只提供了对字节或字节数组的读取方法。由于汉字在文件中占用两个字节,如果使用字节流,读取不好可能会出现乱码现象。此时采用字符流Reader或Writer类即可避免这种现象。
FileReader、FileWriter字符流对应了FileInputStream、FileOutputStream类。FileReader流顺序地读取文件,只要不关闭流,每次调用read()方法就顺序地读取源中其余的内容,直到源的末尾或流被关闭。

5.带缓存的输入输出流:
①BufferedInputStream类与BufferedOutputStream类:
BufferedInputStream类可以对任何的InputStream类进行带缓存区的包装以达到性能的优化。
使用BufferedOutputStream输出信息和往OutputStream输出信息完全一样,只不过BufferedOutputStream有一个flush()方法用来将缓存区的数据强制输出完。
在这里插入图片描述
②BufferedReader与BufferedWriter类:
BufferedReader类与BufferedWriter类分别继承Reader类与Writer类。这两个类同样具有内部缓存机制,并可以以行为单位进行输入输出。
在使用BufferedWriter类的Write()方法时,数据并没有立刻被写入至输出流中,而是首先进入缓存区中。如果想立刻将缓存区中的数据写入输出流中,一定要调用flush()方法。
在这里插入图片描述
6.数据输入输出流:
数据输入输出流(DataInputStream类与DataOutputStream类)允许应用程序以与机器无关的方式从底层输入流中读取基本Java数据类型。也就是说,当读取一个数据时,不必再关心这个数值应当是什么字节。
DataInputStream类只提供了一个readUTF()方法返回字符串。这是因为要在一个连续的字节流读取一个字符串,如果没有特殊的标记作为一个字符串的结尾,并且事先也不知道这个字符串的长度,也就无法知道读取到什么位置才是这个字符串的结束。DataOutputStream类中只有writeUTF()方法向目标设备中写入字符串的长度,所以我们也只能准确地读回写入字符串。

7.ZIP压缩输入输出流:
①压缩文件:
利用ZipOutputStream类对象,可将文件压缩为“.zip”文件。ZipOutputStream类的构造函数如下所示:
ZipOutputStream(OutputStream out);
ZipOutputStream类的常用方法如下表所示:
在这里插入图片描述
②解压缩ZIP文件:
ZipInputStream类可读取ZIP压缩格式的文件,包括对已压缩和未压缩条目的支持(entry)。ZipInputStream类的构造函数如下所示:
ZipInputStream(InputStream in)
ZipInputStream类的常用方法如下表所示:
在这里插入图片描述

二、枚举类型、泛型

1.枚举类型:
①使用枚举类型设置常量:
使用枚举类型定义常量的语法如下:
public enum Constants{
Constants_A,
Constants_B,
Constants_C
}
其中,enum是定义枚举类型关键字。当需要在程序中使用该常量时,可以使用Constants.Constants_A来表示。
②深入了解枚举类型:
枚举类型较传统定义常量的方式,除了具有参数类型检测的优势之外,还具有其他方面的优势。
用户可以将一个枚举类型看作是一个类,它继承于java.lang.Enum类,当定义一个枚举类型时,每一个枚举类型成员都可以看作是枚举类型的一个实例,这些枚举类型成员默认都被final、public、static所修饰,所以当使用枚举类型成员时直接使用枚举类型名称调用枚举类型成员即可。
③使用枚举类型的优势:
枚举类型声明提供了一种用户友好的变量定义方法,枚举了某种数据类型所有可能出现的值。总结枚举类型,它具有以下特点:
类型安全。
紧凑有效的数据定义。
可以和程序其他部分完美交互。
运行效率高。

2.泛型:
①定义泛型类:
Object类为最上层的父类,很多程序员为了使程序更为通用,设计程序时通常使传入的值与返回的值都以Object类型为主。当需要使用这些实例时,必须正确地将该实例转换为原来的类型,否则在运行时将会发生ClassCastException异常。
在JDK 1.5版本以后,提出了泛型机制。其语法如下:
类名
其中,T代表一个类型的名称。
②泛型的常规用法:
Ⅰ.定义泛型类时声明多个类型
Ⅱ.定义泛型类时声明数组类型
Ⅲ.集合类声明容器的元素
③泛型的高级用法:
Ⅰ.限制泛型可用类型
Ⅱ.使用类型通配符
Ⅲ.继承泛型类与实现泛型接口
4.泛型总结:
下面总结一下泛型的使用方法。
泛型的类型参数只能是类类型,不可以是简单类型,如A这种泛型定义就是错误的。
泛型的类型个数可以是多个。
可以使用extends关键字限制泛型的类型。
可以使用通配符限制泛型的类型。

三、线程

1.线程简介:
世间万物会同时完成很多工作,例如人体同时进行呼吸、血液循环、思考问题等活动,用户既可以使用计算机听歌,也可以使用它打印文件,而这些活动完全可以同时进行,这种思想放在Java中被称为并发,而将并发完成的每一件事情称为线程。
在人们的生活中,并发机制非常重要,但是并不是所有的程序语言都支持线程。在以往的程序中,多以一个任务完成后再进行下一个项目的模式进行开发,这样下一个任务的开始必须等待前一个任务的结束。Java语言提供并发机制,程序员可以在程序中执行多个线程,每一个线程完成一个功能,并与其他线程并发执行,这种机制被称为多线程。

2.实现线程的两种方式:
①继承Thread类:
Thread类是java.lang包中的一个类,从这个类中实例化的对象代表线程,程序员启动一个新线程需要建立Thread实例。Thread类中常用的两个构造方法如下:
public Thread(String threadName);
public Thread();
其中第一个构造方法是创建一个名称为threadName的线程对象。
继承Thread类创建一个新的线程的语法如下:
public class ThreadTest extends Thread{
//…
}
②实现Runnable接口:
到目前为止,线程都是通过扩展Thread类来创建的,如果程序员需要继承其他类(非Thread类)并使该程序可以使用线程,就需要使用Runnable接口。例如,一个扩展JFrame类的GUI程序不可能再继承Thread类,因为Java语言中不支持多继承,这时该类就需要实现Runnable接口使其具有使用线程的功能。
实现Runnable接口的语法如下:
public class Thread extends Object implements Runnable

3.线程的生命周期:
线程具有生命周期,其中包含7种状态,分别为出生状态、就绪状态、运行状态、等待状态、休眠状态、阻塞状态和死亡状态。出生状态就是用户在创建线程时处于的状态,在用户使用该线程实例调用start()方法之前线程都处于出生状态;当用户调用start()方法后,线程处于就绪状态(又被称为可执行状态);当线程得到系统资源后就进入运行状态。
在这里插入图片描述
4.操作线程的方法:
①线程的休眠:
一种能控制线程行为的方法是调用sleep()方法,sleep()方法需要一个参数用于指定该线程休眠的时间,该时间使用毫秒为单位。在前面的实例中已经演示过sleep()方法,它通常是在run()方法内的循环中被使用。
sleep()方法的语法如下:
try{
Thread.sleep(2000);
}catch(InterruptedException e){
e.printStackTrace();
}
②线程的加入:
如果当前某程序为多线程程序,假如存在一个线程A,现在需要插入线程B,并要求线程B先执行完毕,然后再继续执行线程A,此时可以使用Thread类中的join()方法来完成。这就好比此时读者正在看电视,却突然有人上门收水费,读者必须付完水费后才能继续看电视。
当某个线程使用join()方法加入到另外一个线程时,另一个线程会等待该线程执行完毕再继续执行。
③线程的中断:
在以往时候会使用stop()方法停止线程,但当前版本的JDK早已废除了stop()方法,同时也不建议使用stop()方法来停止一个线程的运行。现在提倡在run()方法中使用无限循环的形式,然后使用一个布尔型标记控制循环的停止。
④线程的礼让:
Thread类中提供了一种礼让方法,使用yield()方法表示,它只是给当前正处于运行状态下的线程一个提醒,告知它可以将资源礼让给其他线程,但这仅仅是一种暗示,没有任何一种机制保证当前线程会将资源礼让。
yield()方法使具有同样优先级的线程有进入可执行状态的机会,当当前线程放弃执行权时会再度回到就绪状态。对于支持多任务的操作系统来说,不需要调用yeild()方法,因为操作系统会为线程自动分配CPU时间片来执行。

5.线程的优先级:
每个线程都具有各自的优先级,线程的优先级可以在程序中表明该线程的重要性,如果有很多线程处于就绪状态,系统会根据优先级来决定首先使哪个线程进入运行状态。但这并不意味着低优先级的线程得不到运行,而只是它运行的几率比较小,比如垃圾回收线程的优先级就较低。
Thread类中包含的成员变量代表了线程的某些优先级,比如Thread.MIN_PRIORITY(常数1)、Thread.MAX_PRIORITY(常数2)、Thread.NORM_PRIORITY(常数5)。其中每个线程的优先级都在Thread.MIN_PRIORITY~Thread.MAX_PRIORITY之间,在默认情况下其优先级都是Thread.NORM_ PRIORITY。每个新产生的线程都继承了父线程的优先级。
①线程安全:
实际开发中,使用多线程程序的情况很多,如银行排号系统、火车站售票系统等。这种多线程的程序通常会发生问题,以火车站售票系统为例,在代码中判断当前票数是否大于0,如果大于0则执行将该票出售给乘客功能,但当两个线程同时访问这段代码时(假如这时只剩下一张票),第一个线程将票售出,与此同时第二个线程也已经执行完成判断是否有票的操作,并得出结论票数大于0,于是它也执行售出操作,这样就会产生负数。所以在编写多线程程序时,应该考虑到线程安全问题。实质上线程安全问题来源于两个线程同时存取单一对象的数据。
②线程同步机制:
如何解决资源共享的问题?基本上所有解决多线程资源冲突问题都会采用给定时间只允许一个线程访问共享资源,这时就需要给共享资源上一道锁。这就好比一个人上洗手间,这个人进入洗手间后将门锁上,当他出来时再将锁打开,然后其他人才可以进入。

四、网络程序设计基础

1.局域网与因特网:
服务器是指提供信息的计算机或程序,客户机是指请求信息的计算机或程序,而网络用于连接服务器与客户机,实现两者相互通信。但有时在某个网络中很难将服务器与客户机区分开。我们通常所说的“局域网”(Local Area Network,LAN),就是一群通过一定形式连接起来的计算机。它可以由两台计算机组成,也可以由同一区域内的上千台计算机组成。由LAN延伸到更大的范围,这样的网络称为“广域网”(Wide Area Network,WAN)。我们熟悉的因特网(Internet),则是由无数的LAN和WAN组成。
在这里插入图片描述
2.网络协议:
网络协议规定了计算机之间连接的物理、机械(网线与网卡的连接规定)、电气(有效的电平范围)等特征以及计算机之间的相互寻址规则、数据发送冲突的解决、长的数据如何分段传送与接收等。就像不同的国家有不同的法律一样,目前网络协议也有多种,下面简单地介绍几个常用的网络协议。
IP协议
TCP与UDP协议

3.端口与套接字——端口:
一般而言,一台计算机只有单一的连到网络的“物理连接”(Physical Connection),所有的数据都通过此连接对内、对外送达特定的计算机。这就是端口。网络程序设计中的端口(port)并非真实的物理存在,而是一个假想的连接装置。端口被规定为一个在0~65535之间的整数。HTTP服务一般使用80端口,FTP服务使用21端口。假如一台计算机提供了HTTP、FTP等多种服务,那么客户机通过不同的端口来确定连接到服务器的哪项服务上,如下图所示。
在这里插入图片描述
4.端口与套接字——套接字:
网络程序中套接字(Socket)用于将应用程序与端口连接起来。套接字是一个假想的连接装置,就像插插头的设备“插座”,用于连接电器与电线,如下图所示。Java将套接字抽象化为类,程序设计者只需创建Socket类对象,即可使用套接字。
在这里插入图片描述

五、TCP程序设计基础

1.InetAddress类:
java.net包中InetAddress类是与IP地址相关的类,利用该类可以获取IP地址、主机地址等信息。InetAddress类的常用方法如下表所示。
在这里插入图片描述
2.ServerSocket类:
java.net包中ServerSocket类用于表示服务器套接字,其主要功能是等待来自网络上的“请求”,它可通过指定的端口来等待连接的套接字。服务器套接字一次可以与一个套接字连接。如果多台客户机同时提出连接请求,服务器套接字会将请求连接的客户机存入列队中,然后从中取出一个套接字,与服务器新建的套接字连接起来。若请求连接数大于最大容纳数,则多出的连接请求被拒绝。队列的默认大小是50。
ServerSocket类的构造方法都抛出IOException异常,分别有以下几种形式。
ServerSocket():创建非绑定服务器套接字。
ServerSocket(int port):创建绑定到特定端口的服务器套接字。
ServerSocket(int port, int backlog):利用指定的backlog创建服务器套接字并将其绑定到指定的本地端口号。
ServerSocket(int port, int backlog, InetAddress bindAddress):使用指定的端口、侦听backlog和要绑定到的本地IP地址创建服务器。这种情况适用于计算机上有多块网卡和多个IP的情况,我们可以明确规定ServerSocket在哪块网卡或IP地址上等待客户的连接请求。

3.TCP网络程序:
知道了TCP程序的工作过程,就可以编写TCP服务器程序了。在网络编程中如果只要求客户机向服务器发送消息,不用服务器向客户机发送消息,称为单向通信。客户机套接字和服务器套接字连接成功后,客户机通过输出流发送数据,而服务器会使用输入流接收数据。

六、UDP程序设计基础

1.DatagramPacket类:
java.net包的DatagramPacket类用来表示数据包。Datagram Packet类的构造函数有:
DatagramPacket(byte[] buf , int length)
DatagramPacket(byte[] buf , int length , InetAddress address , int port)
第一种构造函数创建DatagramPacket对象,指定了数据包的内存空间和大小。第二种构造函数不仅指定了数据包的内存空间和大小,而且指定了数据包的目标地址和端口。在发送数据时,必须指定接收方的Socket地址和端口号,因此使用第二种构造函数可创建发送数据的DatagramPacket对象。

2.DatagramSocket类:
java.net包中的DatagramSocket类用于表示发送和接收数据包的套接字。该类的构造函数有:
DatagramSocket()
DatagramSocket(int port )
DatagramSocket(int port , InetAddress addr)
第一种构造函数创建DatagramSocket对象,构造数据报套接字并将其绑定到本地主机上任何可用的端口。使用第二种构造函数创建DatagramSocket对象,创建数据报套接字并将其绑定到本地主机上的指定端口。第三种构造函数创建DatagramSocket对象,创建数据报套接字,将其绑定到指定的本地地址。第三种构造函数适用于有多块网卡和多个IP的情况。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值