IO 流--网络编程--反射

110 阅读20分钟

IO 流

文件流

文件在程序中是以流的形式来操作的

流:数据在数据源(文件)和程序(内存)之间经历的路径

输入流:数据从数据源(文件)到程序(内存)的路径

输出流:数据从程序(内存)到数据源(文件)的路径

常用的文件操作

创建文件对象相关构造器和方法

相关方法

new File(String pathname) //根据路径构建一个File对象

new File(File parent,String child) /根据父目录文件+子路径构建

new File(String parent,String child) /根据父目录+子路径构建createNewFile 创建新文件

获取文件的相关信息

  1. getName文件名字、
  2. getAbsolutePath文件绝对路径
  3. getParent文件父级目录
  4. length文件大小(字节)
  5. exists文件是否存在
  6. isFile是不是一个文件
  7. isFileisDirectory是不是一个目录

目录的操作和文件删除

IO 流原理及流的分类

Java IO 流原理

  1. I/O是Input/Output的缩写,1/0技术是非常实用的技术,用于处理数据传输。如读/写文件,网络通讯等。
  2. Java程序中,对于数据的输入/输出操作以”流(stream)”的方式进行
  3. java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过方法输入或输出数据
  4. 输入input:读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中。
  5. 输出output:将程序(内存)数据输出到磁盘、光盘等存储设备中

流的分类

按操作数据单位不同分为:

字节流(8bit),二进制文件,字符流(按字符)

文本文件按数据流的流向不同分为:

输入流,输出流

按流的角色的不同分为:

节点流,   处理流/包装流

1)Java的IO流共涉及40多个类,实际上非常规则,都是从如上4个抽象基类派生的

2)由这四个类派生出来的子类名称都是以其父类名作为子类名后缀

IO 流体系图-常用的类

文件 VS 流

就像物流一样需要有一个中间商来两头走

FileInputStream 介绍

从该输入流读取一个字节的数据。 如果没有输入可用,此方法将阻止。 //如果返回-1 , 表示读取完

while ((readData = fileInputStream.read()) != -1)

 { System.out.print((char)readData);}//转成 char 显示 }

FileOutputStream 介绍

1.  new FileOutputStream(filePath) 创建方式,当写入内容是,会覆盖原来的内容

2.  new FileOutputStream(filePath, true) 创建方式,当写入内容是,是追加到文件后面

3. 写入一个字节 fileOutputStream.write('H');

4. 写入字符串 String str = "world!";

str.getBytes() 可以把 字符串-> 字节数组

fileOutputStream.write(str.getBytes());

write(byte[] b, int off, int len) 将 len 字节从位于偏移量 off 的指定字节数组写入此文件输出流            fileOutputStream.write(str.getBytes(), 0, 3);

FileReader 和 FileWriter 介绍

 

FileReader相关方法:

  1. new FileReader(File/String)
  2. read:每次读取单个字符,返回该字符,如果到文件末尾返回-1
  3. read(char[]):批量读取多个字符到数组,返回读取到的字符数,如果到文件末尾返回-1相关API
  4. new String(char[]):将char[]转换成String
  5. new String(char[],off,len):将char[]的指定部分转换成String

FileWriter常法

  1. new FileWriter(File/String):覆盖模式,相当于流的指针在首端
  2. new FileWriter(File/String,true):追加模式,相当于流的指针在尾端
  3. write(int):写入单个字符
  4. write(char[]):写入指定数组
  5. write(char[],off,len):写入指定数组的指定部分
  6. write(string):写入整个字符
  7. write(string,off,len):写入字符串的指定部分

相关API:String类:toCharArray:将String转换成char[]

>注意:

FileWriter使用后,必须要关闭(close)或刷新(flush),否则写入不到指定的文件!

节点流和处理流

基本介绍

节点流

节点流可以从一个特定的数据源读写数据,如FileReader、FileWriter

处理流

处理流(也叫包装流)是“连接”在已存在的流(节点流或处理流)之上,为程序提供更为强大的读写功能,也更加灵活,如BufferedReader、BufferedWriter

节点流和处理流一览图

节点流和处理流的区别和联系

  1. 节点流是底层流/低级流,直接跟数据源相接。
  2. 处理流(包装流)包装节点流,既可以消除不同节点流的实现差异,也可以提供更方便的方法来完成输入输出
  3. 处理流(也叫包装流)对节点流进行包装,使用了修饰器设计模式,不会直接与数据源相连[模拟修饰器设计模式]

处理流的功能主要体现在以下两个方面:

  1. 性能的提高:主要以增加缓冲的方式来提高输入输出的效率。
  2. 操作的便捷:处理流可能提供了一系列便捷的方法来一次输入输出大批量的数据,使用更加灵活方便

处理流-BufferedReader 和BufferedWriter

>BufferedReader和BufferedWriter属于字符流,是按照字符来读取数据的>关闭时处理流,只需要关闭外层流即可

处理流-BufferedInputStream 和 BufferedOutputStream

介绍BufferedInputStream

BufferedInputStream是字节流,在创建BufferedInputStream时,会创建一个内部缓冲区数组

介绍 BufferedOutputStream

BufferedOutputStream是字节流,实现缓冲的输出流,可以将多个字节写入底层输出流中,而不必对每次字节写入调用底层系统

对象流-ObjectInputStream 和 ObjectOutputStream

>序列化和反序列化

  1. 序列化就是在保存数据时,保存数据的值和数据类型
  2. 反序列化就是在恢复数据时,恢复数据的值和数据类型
  3. 需要让某个对象支持序列化机制,则必须让其类是可序列化的,为了让某个类是可序列化的,该类必须实现如下两个接口之一:Serializable  //这是一个标记接口,没有方法

Externalizable

Externalizable //该接口有方法需要实现,因此我们一般实现上面的Serializable接口

  1. 将文件保存的数据(值和数据类型)重新恢复成对象就称为反序列化
  2. 将值和数据类型保存到文件称为序列化

对象流介绍

ObjectOutputStream 提供 ****序列化功能

序列化数据到 e:\data.dat

oos.writeInt(100);//int -> Integer (实现了 Serializable)

oos.writeBoolean(true);// boolean -> Boolean (实现了 Serializable)

oos.writeChar('a');// char -> Character (实现了 Serializable)

oos.writeDouble(9.5);// double -> Double (实现了 Serializable)

oos.writeUTF("123");//String

oos.writeObject(new Dog("旺财", 20, "白色”))    //保存一个 dog 对

ObjectInputStream 提供 ****反序列化功能

2.读取, 注意顺序

System.out.println(ois.readInt());

System.out.println(ois.readBoolean());

System.out.println(ois.readChar());

System.out.println(ois.readDouble());

System.out.println(ois.readUTF());

System.out.println(ois.readObject());

System.out.println(ois.readObject());

System.out.println(ois.readObject());

注意细节和要素

>注意事项和细节说明

  1. 读写顺序要一致
  2. 要求序列化或反序列化对象,需要实现Serializable
  3. 序列化的类中建议添加SerialVersionUID,为了提高版本的兼容性
  4. 序列化对象时默认将里面所有属性都进行序列化,但除了static或transient修饰的成员
  5. 序列化对象时,要求里面属性的类型也需要实现序列化接口
  6. 序列化具备可继承性,也就是如果某类已经实现了序列化,则它的所有子类也已经默认实现了序列化

标准输入输出流

转换流-InputStreamReader 和 OutputStreamWrite

>介绍

InputStreamReader:Reader的子类,可以将InputStream(字节流)

包装成(转换)Reader(字符流)

OutputStreamWriter:Writer的子类,实现将OutputStream(字节流)

包装成(转换)Writer(字符流)

当处理纯文本数据时,如果使用字符流效率更高,并且可以有效解决中文问题,所以建议将字节流转换成字符流

可以在使用时指定编码格式(比如 utf-8,gbk,gb2312, ISO8859-1等)

BufferedReaderbr=newBufferedReader(newInputStreamReader(new FileInputStream(filePath), "gbk"));

打印流-PrintStream 和 PrintWriter

PrintStream out = System.out;

在默认情况下,PrintStream 输出数据的位置是 标准输出,即显示器

因为 print 底层使用的是 write , 所以我们可以直接调用 write 进行打印/输出

out.write("望城,你好".getBytes());

输出修改成到 "e:\\f1.txt

System.setOut(new PrintStream("e:\\f1.txt"));

System.out.println("hello, 望城,你好~");

Properties 类

读取 mysql.properties 文件,并得到 ip, user 和 pwd

BufferedReader br = new BufferedReader(new FileReader("src\\mysql.properties"));

String line = " ";   

while ((line = br.readLine()) != null) { //循环读取

String[] split = line.split("=");

if("ip".equals(split[0])) {     //如果我们要求指定的 ip值

 System.out.println(split[0] + "值是: " + split[1]); }}

基本介绍

1)专门用于读写配置文件的集合类

配置文件的格式:

键=值

键=值

2)注意:键值对不需要有空格,值不需要用引号一起来。默认类型是String3)

Properties常见方法

  1. load:加载配置文件的键值对到Properties对象
  2. list:将数据显示到指定设备
  3. getProperty(key):根据键获取值
  4. setProperty(key,value):设置键值对到Properties对象
  5. store:将Properties中的键值对存储到配置文件,在idea中,保存信息到配置文件,如果含有中文,会存储为unicode码

网络编程

网络通信

网络

ip 地址

1.概念:用于唯一标识网络中的每台计算机/主机

2.查看ip地址:ipconfig

3.ip地址的表示形式:点分十进制XX.XX.XX.XX

4.每一个十进制数的范围:0~255

5.ip地址的组成=网络地址+主机地址,比如:192.168.16.69

6.ilPv6是互联网工程任务组设计的用于替代lPv4的下一代IP协议,其地址数量号称可以为全世界的每一粒沙子编上一个地址。

7.由于IPv4最大的问题在于网络地址资源有限,严重制约了互联网的应用和发展。IPv6的使用,不仅能解决网络地址资源数量的问题,而且也解决了多种接入设备连入互联网的障碍

ipv4 地址分类

域名

1. www.baidu.com

2.好处:为了方便记忆,解决记ip的困难

3.概念:将ip地址映射成域名,这里怎么映射上,HTTP协议

端口号

1.概念:用于标识计算机上某个特定的网络程序

2.表示形式:以整数形式,端口范围0~65535[2个字节表示端口0~2^16-1]

3. 0~1024已经被占用,比如 ssh 22, ftp'21, smtp 25 http 80

4.常见的网络程序端口号:

  • .tomcat : 8080
  • mysql:3306
  • oracle:1521
  • sqlserver:1433

网络通信协议

协议(tcp/ip)

TCP/IP (Transmission Control

Protocol/Internet Protocol)的简写中文译名为传输控制协议/因特网互联协议,又叫网络通讯协议,这个协议是Internet最基本的协议、Internet国际互联网络的基础,简单地说,就是由网络层的IP协议和传输层的TCP协议组成的。

网络通信协议

TCP 和 UDP

√TCP协议:传输控制协议

  1. 使用TCP协议前,须先建立TCP连接,形成传输数据通道2.传输前,采用三次握手"方式,是可靠的
  2. TCP协议进行通信的两个应用进程:客户端、服务端
  3. 在连接中可进行大数据量的传输
  4. 传输完毕,需释放已建立的连接,效率低

√UDP协议:用户数据协议

  1. 将数据、源、目的封装成数据包,不需要建立连接
  2. 每个数据报的大小限制在64K内,不适合传输大量数据
  3. 因无需连接,故是不可靠的
  4. 发送数据结束时无需释放资源(因为不是面向连接的),速度快

InetAddress 类

相关方法

  1. 获取本机InetAddress对象 getLocalHost
  2. 根据指定主机名/域名获取ip地址对象getByName
  3. 获取InetAddress对象的主机名 getHostName
  4. 获取InetAddress对象的地址 getHostAddress

Socket

基本介绍

  1. 套接字(Socket)开发网络应用程序被广泛采用,以至于成为事实上的标准。
  2. 通信的两端都要有Socket,是两台机器间通信的端点
  3. 网络通信其实就是Socket间的通信。
  4. Socket允许程序把网络连接当成一个流,数据在两个Socket间通过IO传输
  5. 一般主动发起通信的应用程序属客户端,等待通信请求的为服务端

示意图

TCP 网络通信编程

1.基于客户端一服务端的网络通信

2.底层使用的是TCP/IP协议

3.应用场景举例:客户端发送数据,服务端接受并显示控制台

4.基于Socket的TCP编程

netstat 指令

  1. netstat-an可以查看当前主机网络情况,包括端口监听情况和网络连接情况
  2. netstat-an|more可以分显示
  3. 要求在dos控制台下执行 win+r

说明:

  • Listening表示某个端口在监听
  • 如果有一个外部程序(客户端)连接到该端口,就会显示一条连接信息
  • 可以输入ctrl+c退出指令

TCP 网络通讯

当客户端连接到服务端后,实际上客户端也是通过一个端口和服务端进行通讯的,这个端口是TCP/IP来分配的,是不确定的,是随机的

UDP 网络通信编

基本介绍

类 DatagramSocket和 DatagramPacket数据包/数据报 实现了基于 UDP协议网络程序。

UDP数据报通过数据报套接字DatagramSocket发送和接收,系统不保证

UDP数据报一定能够安全送到目的地,也不能确定什么时候可以抵达。

DatagramPacket对象封装了UDP数据报,在数据报中包含了发送端的

IP地址和端口号以及接收端的IP地址和端口号。

UDP协议中每个数据报都给出了完整的地址信息,因此无须建立发送方和接收方的连接

基本流程

1.核心的两个类/对象 DatagramSocket与DatagramPacket

2.建立发送端,接收端(没有服务端和客户端概念)

3.发送数据前,建立数据包/报DatagramPacket对象

4.调用DatagramSocket的发送、接收方法

5.关闭DatagramSocket

项目开发流程

反射(reflection)


  1. 反射机制允许程序在执行期借助于ReflectionAPI取得任何类的内部信息(比如成员变量,构造器,成员方法等等),并能操作对象的属性及方法。反射在设计模式和框架底层都会用到
  2. 加载完类之后,在堆中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象包含了类的完整结构信息。通过这个对象得到类的结构。这个Class对象就像一面镜子,透过这个镜子看到类的结构,
  3. 所以,形象的称之为:反射 p对象-》类型Person类Class对象cls->类型Class类

Java 反射机制原理示意图!!!

Java 反射机制可以完成

  1. 在运行时判断任意一个对象所属的类
  2. 在运行时构造任意一个类的对象
  3. 在运行时得到任意一个类所具有的成员变量和方法
  4. 在运行时调用任意一个对象的成员变量和方法
  5. 生成动态代理

反射相关的主要类

1.java.lang.Class:代表一个类,Class对象表示某个类加载后在堆中的对象

2. java.lang.reflect.Method:代表类的方法, Method对象表示某个类的方法

3. java.lang.reflect.Field:代表类的成员变量, Field对象表示某个类的成员变量

4. java.lang.reflect.Constructor:代表类的构造方法,Constructor对象表示构造器

这些类在 java.lang.reflection

反射优点和缺点

1.优点:可以动态的创建和使用对象(也是框架底层核心),使用灵活,没有反射机制,框架技术就失去底层支撑。

2.缺点:使用反射基本是解释执行,对执行速度有影响

反射调用优化-关闭访问检查

  1. Method和Field、Constructor对象都有setAccessible()方法
  2. setAccessible作用是启动和禁用访问安全检查的开关
  3. 参数值为true表示反射的对象在使用时取消访问检查,提高反射的效率。参数值为false则表示反射的对象执行访问检查

Class 类

基本介绍

  1. Class也是类,因此也继承Object类
  2. Class类对象不是new出来的,而是系统创建的
  3. 对于某个类的Class类对象,在内存中只有一份,因为类只加载一次
  4. 每个类的实例都会记得自己是由哪个Class实例所生成
  5. 通过Class对象可以完整地得到一个类的完整结构,通过一系列API
  6. Class对象是存放在堆的
  7. 类的字节码二进制数据,是放在方法区的,有的地方称为类的元数据(包括方法代码变量名,方法名,访问权限等等)

Class 类的常用方法

获取到 Car 类 对应的 Class 对象

<?>表示不确定的 Java 类型 Class<?> cls = Class.forName(classAllPath);

输出 cls System.out.println(cls);

显示 cls 对象, 是哪个类的 Class 对象 com.wyxedu.Car System.out.println(cls.getClass());

输出 cls 运行类型 java.lang.Class

  1. 得到包名 System.out.println(cls.getPackage().getName());//包名
  2. 得到全类名 System.out.println(cls.getName());

通过cls 创建对象实例

Car car = (Car) cls.newInstance(); System.out.println(car);    //car.toString()

通过反射获取属性

brand Field brand = cls.getField("brand"); System.out.println(brand.get(car));//宝马

通过反射给属性赋值 brand.set(car, "奔驰"); System.out.println(brand.get(car));//奔驰

我希望大家可以得到所有的属性(字段)

System.out.println("====所有的字段属性====");

Field[] fields = cls.getFields(); for (Field f : fields) { System.out.println(f.getName());//名称 }

获取 Class 类对象

已知一个类的全类名

前提:已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法

forName()获取,可能抛出ClassNotFoundException,实例:

Class cls1 =Class.forName("java.lang.Cat");

应用场景:多用于配置文件,读取类全路径,加载类

已知具体的类

前提:若已知具体的类,通过类的class获取,该方式最为安全可靠,程序性能高

实例:Class cls2=Cat.class;

应用场景:多用于参数传递,比如通过反射得到对应构造器对象

某个类的实例

前提:已知某个类的实例,调用该实例的getClass()方法获取Class对象,

实例:Class clazz =对象.getClass();//运行类型

应用场景:通过创建好的对象,获取Class对象

其他方式

ClassLoader cl =对象.getClass().getClassLoader();

Class clazz4 = cl.loadClass("类的类名");

基本数据(int, char, Boolean, float, double, byte, long, short)按如下方式得到Class对象

Class cls=基本数据类型.class

基本数据类型对应的包装类,可以通过.TYPE得到Class类对象

Class cls=包.TYPE

哪些类型有 Class 对象

1.外部类,成员内部类,静态内部类,局部内部类,匿名内部类

2. interface:接口

3.数组

4.enum:举

5.annotation:注

6.基本数据类型

7. void

类加载

基本说明

反射机制是java实现动态语言的关键,也就是通过反射实现类动态加载

1.静态加载:编译时加载相关的类,在如果没有则报错,依赖性太强

2.动态加载:运行时加载需要的类,如果运行时不用该类,即使不存在该类,则不报错,降低了依赖性

类加载时机

1.当创建对象时(new) //静态加载

2.当子类被加载时 父类也加载 //静态加载

3.调用类中的静态成员时  //静态加载

4.通过反射   //动态加载

Class.forName("com.test.Cat");

类加载过程图

类加载各阶段完成任务

加载阶段

连接阶段-验证

  1. 目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。
  2. 包括:文件格式验证(是否以魔数oxcafebabe开头)、元数据验证、字节码验证和符号引用验证
  3. 可以虑使用-Xverify:none参数来关闭大部分的类验证措施,缩短虚拟机类加载的时间。

连接阶段-准备

JVM会在该阶段对静态变量,分配内存并默认初始化

(对应数据类型的默认初始值,如0、OL、null、false等)。这些变量所使用的内存都将在方法区中进行分配

连接阶段-解析

Initialization(初始化)

  1. 到初始化阶段,才真正开始执行类中定义的Java程序代码,此阶段是执行<clinit>()方法的过程。
  2. <clinit>()方法是由编译器按语句在源文件中出现的顺序,依次自动收集类中的所有静态变量的赋值动作和静态代码块中的语句,并进行合并。
  3. 虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确地加锁、同步,

如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的<clinit>()方法,其他线程都需要阻塞等待,直到活动线程执行<clinit>()方法完毕

通过反射获取类的结构信息

第一组: java.lang.Class 类

  1. getName:获取全类名
  2. getSimpleName:获取简单类名
  3. getFields:获取所有public修饰的属性,包含本类以及父类的
  4. getDeclaredFields:获取本类中所有属性
  5. getMethods:获取所有public修饰的方法,包含本类以及父类的
  6. getDeclaredMethods:获取本类中所有方法
  7. getConstructors:获取本类所有public修饰的构造器
  8. getDeclaredConstructors:获取本类中所有构造器
  9. getPackage:以Package形式返回包信息
  10. getSuperClass:以Class形式返回父类信息
  11. getlnterfaces:以Class]形式返回接口信息
  12. getAnnotations:以Annotation]形式返回注解信息

第二组java.lang.reflect.Field类

getModifiers:以int形式返回修饰符

【说明:默认修饰符是0,public是1,private是2,protected是4static是8,final是16 】

【public(1) + static(8) =9】

  1. getType:以Class形式返回类型
  2. getName:返回属性名

第三组java.lang.reflect.Method类

getModifiers:以int形式返回修饰符

【说明:默认修饰符是0,public是1,private是2,protected是4,static是8,final是 1】

  1. getReturnType:以Class形式获取返回类型
  2. getName:返回方法名
  3. getParameterTypes:以Class[]返回参数类型数组

第四组java.lang.reflect.Constructor类

1.getModifiers:以int形式返回修饰符

2.getName:返回构造器名(全类名)

3.getParameterTypes:以Class[]返回参数类型数组

通过反射创建对象

1.方式一:调用类中的public修饰的无参构造器

2.方式二:调用类中的指定构造器

3.Class类相关方法

  1. newlnstance:调用类中的无参构造器,获取对应类的对象
  2. getConstructor(Class..clazz):根据参数列表,获取对应的public构造器对象
  3. getDecalaredConstructor(Class.clazz):根据参数列表,获取对应的所有构造器对象
  4. Constructor类相关方法
  5. setAccessible:暴破
  6. newlnstance(Object.obj):调用构器

通过反射访问类中的成员

访问属性

1. 根据属性名获取Field对象

Field f = clazz对象.getDeclaredField(属性名);

2.  暴破:

f.setAccessible(true); //f 是Field

3. 访问

f.set(o . 值);  //o表示对象

syso(f . get(o);/o表示对象

注意:如果是静态属性,则set和get中的参数o,可以写成null

访问方法

根据方法名和参数列表获取Method方法对象:

Method m= clazz.getDeclaredMethod(方法名,XX.class);匹配指定名称和参数的类的方法,此方法返回的Method对象

获的对象:

Object o=clazz.newInstance();

暴破:

m.setAccessible(true);暴破【暴力破解】 , 使用反射可以访问 private 构造器/方法/属性, 反射面前,都是纸老虎

访问:

Object returnValue = m.invoke(o,实参列表);/o就是对象

注意:

如果是静态方法,则invoke的参数o,可以写成null!


本章笔记是观看韩顺平的JAVA的视频和在网上找的资料 以及自己的理解总结出来的笔记希望可以帮助大家,感谢大家的耐心观看 如有错误请即使联系我 我会及时修正