文章目录
day13
对象流
对象序列化机制就是把内存中的Java对象转成与平台无关的二进制文件,从而可以进行持久化储存或者通过网络传输。
序列化:用ObjectOutputStream完成对象的保存
反序列化:用ObjectInputStream完成对象的读取
序列化的过程就是将java对象保存到硬盘中或者通过网络传输
//序列化
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream("object.dat"));
oos.writeObject("我爱北京天安门");
oos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(oos != null)
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
反序列的过程,将硬盘中或者通过网络传输获取到的对象转化为java对象
//反序列化
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream("object.dat"));
Object obj = ois.readObject();
String str = (String)obj;
System.out.println(str);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if(ois != null) {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
自定义序列化需要:
- 实现Serializable接口
- 当前类提供一个全局的常量:SerialVesionUID常量。 不给也行,接口会自动给一个常量,但反序列的时候可能会出错。
- 出来当前类需要实现Serializable接口外,其内部的属性 需要支持序列化
static和transient修饰的成员变量不能被序列化
RandomAccessFile类,既可以做输出流,又可以做输入流,因为实现了DateInput接口和DataOutput接口
创建实例的时候需要指定mode类型
r: 以只读方式打开
rw: 读取和写入
rwd:读取和写入,同步文件内容的更新
rws:打开以便读取和写入,同步文件内容和元文件的更新
NIO
NIO和IO有同样的作用和目的,不同的是NIO是面向缓冲区(IO是面向流),基于通道的IO操作,NIO能以更高效的方式进行文件的读写操作
socket进行网络通信
public void client(){
Socket socket = null;
OutputStream outputStream = null;
try {
//创建socket 指明ip和端口号
InetAddress inet = InetAddress.getByName("127.0.0.1");
socket = new Socket(inet,9090);
//获取输出流
outputStream = socket.getOutputStream();
outputStream.write("我是客户端".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
if(outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public void server(){
Socket socket = null;
InputStream is = null;
ByteArrayOutputStream bos = null;
try {
//创建Socket服务器端,只需要指定端口号
ServerSocket serverSocket = new ServerSocket(9090);
//accept()接受来自客户端socket
socket = serverSocket.accept();
//获取到输入流
is = socket.getInputStream();
//读取输入流的信息
bos = new ByteArrayOutputStream();
byte[] buff = new byte[5];
int len;
while((len = is.read(buff)) != -1){
bos.write(buff,0,len);
}
System.out.println(bos.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
if(is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(bos != null) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
反射
Reflection(反射)是被视为动态语言的关键。
在加载完类后,堆内存的方法区中就产生了一个class类型的对象,这个对象就包含了类的完整结构,我们可以通过这个对象看到类的结构。这个对象就一面镜子,透过镜子看到类的结构,所以,我们形象的称为:反射。
通过反射,可以调用类的私有结构:如私有构造器、方法、属性。
Class Constructor Method Filed
获取Class实例的方式
Class实例对应着加载到内存中的一个运行时类。
//方式一:调用运行时类的属性: .class
Class clazz1 = Person.class;
System.out.println(clazz1);
//方式二:通过运行时类的对象,调用getClass()
Person p1 = new Person();
Class clazz2 = p1.getClass();
System.out.println(clazz2);
//方式三:调用Class的静态方法:forName(String classPath)
Class clazz3 = Class.forName("com.atguigu.java.Person");
System.out.println(clazz3);
//方式四:使用类的加载器:ClassLoader
ClassLoader classLoader = ReflectionTest.class.getClassLoader();
Class clazz4 = classLoader.loadClass("com.atguigu.java.Person");
System.out.println(clazz4);
ClassLoader获取properties
//通过ClassLoader类加载器获取properties配置文件里的内容
Properties pro = new Properties();
ClassLoader classLoader = ReflectionTest.class.getClassLoader();
InputStream in = classLoader.getResourceAsStream("jdbc.properties");
pro.load(in);
String user = pro.getProperty("user");
String password = pro.getProperty("password");
System.out.println("user=" + user + ",password=" + password);
创建运行时类的对象
//创建运行时类的对象
Class clazz = Class.forName("com.atguigu.java.Person");
//Object obj = clazz.newInstance();
Person obj = (Person)clazz.newInstance();
System.out.println(obj);
如何操作运行类中的指定的属性
//如何操作运行类中的指定的属性
Class clazz = Person.class;
//创建类的运行时类的对象
Person p = (Person) clazz.newInstance();
//getDeclaredField()获取运行时类中指定的属性
Field name = clazz.getDeclaredField("name");
//保证当前属性是可以访问的
name.setAccessible(true);
//获取、设置指定对象属性的值
name.set(p, "Tom");
System.out.println(name.get(p));//Tom
如何操作运行类中的指定的方法
//如何操作运行类中的指定的方法
Class clazz = Person.class;
Person p = (Person)clazz.newInstance();
//getDeclaredMethod():参数1:方法的名称,参数2:方法的形参列表
Method show = clazz.getDeclaredMethod("show", String.class);
show.setAccessible(true);
//invoke():参数1:方法的调用者,参数2:给方法形参赋值的实参
//invoke()方法的返回值即为对应类中方法的返回值
show.invoke(p, "hahahha");