Notes Site.
post @ 2023-10-17

Java反序列化原理

Serializable 接口的使用

类需要被序列化和反序列化,需要实现接口 java.io.Serializable

Java 提供的序列化接口 Serializable ,是一个空接口,没有成员方法和变量

1
2
public interface Serializable { 
}
1
2
3
4
5
6
import java.io.Serializable;

public class Example implements Serializable{
private String name;
....
}

序列化 调用 ObjectOutputStream 类的 writeObject 方法

反序列化 调用 ObjectInputStream 类的 readObject 方法

注意:

只有实现了Serializable或者Externalizable接口的类的对象才能被序列化为字节序列,否则会抛出异常。Externalizable 接口继承自Serializable接口,实现 Externalizable接口的类完全由自身来控制序列化的行为,而仅实现 Serializable 接口的类可以采用默认的序列化方式。

  1. 它是Java 提供的序列化接口,是一个空接口,没有成员方法和变量
  2. 一个类要想序列化就必须继承java.io.Serializable接口,同时它的子类也可以序列化(不用再继承Serializable接口)
  3. 一个实现Serializable 接口的子类也是可以被序列化的。在反序列化过程中,它的父类如果没有实现序列化接口,那么父类将需要提供无参构造函数来重新创建对象,这样做的目的是重新初始化父类的属性,父类对应的属性不会被序列化
  4. 序列化只能保存对象的非静态成员变量,不能保存任何的成员方法和静态的成员变量,而且序列化保存的只是变量的值,对于变量的任何修饰符都不能保存。即序列化是保存对象的状态(对象属性)
  5. transient 标识的对象成员变量不参与序列化
  6. Serializable 在序列化和反序列化过程中大量使用了反射,因此其过程会产生的大量的内存碎片

注:JAVA会被称为八股文,原因在于它的一个小知识点里会有很多细节在里面

Person

Read More
post @ 2023-10-13

Java反射&动态代理

反射机制

Java 反射(Reflection)是一种机制,它允许 Java 程序在运行时获取和操作它本身的数据结构,比如类、方法、属性等。通过反射,我们可以动态地创建对象、调用方法、访问属性等,而无需在编译时知道这些信息。

Java 反射主要包括以下几个核心类:

  1. Class 类:表示一个类或接口,包含了获取类信息的方法,如获取类名、父类、接口、属性、方法等。
  2. Constructor 类:表示一个构造函数,包含了获取构造函数信息的方法,如获取构造函数名、参数列表等。
  3. Field 类:表示一个属性,包含了获取属性信息的方法,如获取属性名、类型、访问权限等。
  4. Method 类:表示一个方法,包含了获取方法信息的方法,如获取方法名、参数列表、返回类型等。

以下是一些 Java 反射的常见用法:

  1. 获取类信息:通过 Class.forName() 方法获取某个类的 Class 对象,然后使用 Class 对象的各种方法获取类的信息,如 getName() 获取类名,getDeclaredMethods() 获取所有方法等。
  2. 创建对象:通过 Class 对象的 getConstructor()getDeclaredConstructor() 方法获取指定构造函数的引用,然后使用 newInstance()newInstance() 方法创建对象。
  3. 访问属性:通过 Class 对象的 getDeclaredField() 方法获取指定属性的引用,然后使用 set()get() 方法设置或获取属性的值。
  4. 调用方法:通过 Class 对象的 getDeclaredMethod() 方法获取指定方法的引用,然后使用 invoke() 方法调用方法并传递参数。
  5. 动态代理:通过 Java 反射实现动态代理,可以在运行时创建一个实现了指定接口的代理类,并实现指定的方法逻辑。

Class类就是通过FieldMethod来描述类中的字段和方法

代码

Person 类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package net.Seck2y.a02;

public class Person {
private String name = "zhangsan";
private int age = 23;

public Person(){}

public Person(String name, int age) {
this.name = name;
this.age = age;
}

public void action(String string){
System.out.println(string);
}

// 重写 toString,规定打印格式,不规定会输出 类 和 地址
@Override
public String toString(){
return "Person{" +
"name: " + this.name +
", age: "+ this.age +
"}";
}
}

Reflection 类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
package net.Seck2y.a02;

import java.lang.reflect.*;

public class Reflection {
public static void main(String[] args) throws Exception {
// Class<?>
// 获取 Person 类的 Class 对象(两种形式)
// Class<?> personClass = Person.class;
Class<?> personClass = Class.forName("net.Seck2y.a02.Person"); // 完整路径


// Constructor<?>
// 获取 Person 类的构造方法
Constructor<?> constructor = personClass.getConstructor(String.class, int.class);

// 创建 Person 对象
Object person = constructor.newInstance("lisi", 24);
System.out.println(person);
// 输出 Person{name: lisi, age: 24}


// Field
// 获取成员属性的信息(无值)
Field[] personField = personClass.getDeclaredFields();
for (Field f:personField){
System.out.println(f);
}
/* 输出
private java.lang.String net.Seck2y.a02.Person.name
private int net.Seck2y.a02.Person.age
*/

// 获取成员属性的值
Field nameField = personClass.getDeclaredField("name");
Field ageField = personClass.getDeclaredField("age");
nameField.setAccessible(true); // 提权
ageField.setAccessible(true); // 提权
String name = (String) nameField.get(person); // 获取 nameField 属性的值
int age = (int) ageField.get(person); // 获取 ageField 属性的值
System.out.println(
nameField.getName() + ": " + name + ", " +
ageField.getName() + ": " + age);
// getName 获取属性的名称
// System.out.println(person); 可替换
// 输出 name: lisi, age: 24

// 修改成员属性的值
Field setName = personClass.getDeclaredField("name");
Field setAge = personClass.getDeclaredField("age");
setName.setAccessible(true);
setAge.setAccessible(true);
setName.set(person, "wangwu");
setAge.set(person, 25);
System.out.println(
setName.getName() + ": " +setName.get(person) + ", " +
setAge.getName() + ": " + setAge.get(person));
// System.out.println(person); 可替换
// 输出 name: wangwu, age: 25


// Method
// 获取方法
Method[] personMethod = personClass.getDeclaredMethods();
for (Method m: personMethod) {
System.out.println(m);
}
/* 输出
public java.lang.String net.Seck2y.a02.Person.toString()
public void net.Seck2y.a02.Person.action(java.lang.String)
*/

// 获取 Person 对象的方法信息并调用它们
Method actionMethod = personClass.getMethod("action",String.class);
actionMethod.invoke(person,"Reflection");
// 输出 Reflection
}
}

Class

Read More
⬆︎TOP