Java 开发人员必须要知道的一个知识,就是反射,在看很多底层源码的时候或多或少都会涉及一些,下面来介绍一下
Java 一种经典的面向对象开发语言,对象先声明后使用,而一个变量又分为 编译型类型 与 运行时类型
若编译时类型和运行时类型不一致,也就是我们所谓的 多态。因为子类其实是一种特殊的父类,因此java允许把一个子类对象直接赋值给一个父类引用变量,无须任何类型转换,或者被称为向上转型,由系统自动完成。引用变量在编译阶段只能调用其编译时类型所具有的方法,但运行时则执行它运行时类型所具有的方法
为方便下面的方法示例,这里做一些准备工作,新建几个类
1、新建一个类 StudyParamParentPre
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class StudyParamParentPre {
String namePrePre;
List<String> listPrePre;
List<List<String>> dListPrePre;
public void publicGetParentPre() {
}
protected void protectedGetParentPre() {
}
private void privateGetParentPre() {
}
}
2、新建一个类 StudyParamParent,其是StudyParamParentPre 的子类
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class StudyParamParent extends StudyParamParentPre{
String namePre;
List<String> listPre;
List<List<String>> dListPre;
public void publicGetParent() {
}
protected void protectedGetParent() {
}
private void privateGetParent() {
}
}
3、新建一个接口 StudyInfer
public interface StudyInfer {
public void publicGetInfer();
}
4、新建一个类 StudyParam,其是 StudyParamParent 的子类,实现了 StudyInfer
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class StudyParam extends StudyParamParent implements StudyInfer {
String name;
List<String> list;
String[] strings;
List<List<String>> dList;
public StudyParam(String namePre, List<String> listPre, List<List<String>> dListPre, String name) {
super(namePre, listPre, dListPre);
this.name = name;
}
private StudyParam(String namePre, List<String> listPre, List<List<String>> dListPre, String name, List<String> list) {
super(namePre, listPre, dListPre);
this.name = name;
this.list = list;
}
public void publicGet() {
}
protected void protectedGet() {
}
private void privateGet() {
}
@Override
public void publicGetInfer() {
}
public void getPublicHa() {
}
public void getPublicHa(String name) {
}
private void getPrivateHa() {
}
private void getPrivateHa(String name) {
}
}
反射 就是在运行状态中,能够知道任意类所有属性和方法,可调用其任意一个方法和属性,即动态获取信息及动态调用对象方法的功能叫 Java 反射
在运行状态中,反射可以做以下事情:
因为Java是面向对象编程,最基础的就是类,即 Class
面向对象编程,故基础为类,属性与方法都基于类,该类中有的方法常用的如下:
方法名称 | 用途 | 返回值 |
---|---|---|
toString toGenericString |
对象转换为String | String |
isInstance isAssignableFrom isInterface isArray isPrimitive isAnnotation isSynthetic isAnnotationPresent isAnonymousClass isLocalClass isMemberClass isEnum |
是否是某实例 是否从xx 继承/实现来的 是否是接口 是否是数组 是否是原始类型 是否是注解 是否是Synthetic 是否是注解 是否是匿名类 是否是局部变量 是否是Member 是否是枚举 |
boolean |
newInstance | 实例化对象 | T |
getName getSimpleName getTypeName getCanonicalName |
获取类的全类名 | String |
getSuperclass getGenericSuperclass |
获取父类 | Class super T> Type |
getPackage | 获取类所在的包 | Package |
getComponentType | 返回表示数组组件类型的 Class | Class> |
getClassLoader | 获取类加载器 | ClassLoader |
说明:
方法使用举例:
package com.study;
import com.study.pojo.StudyInfer;
import com.study.pojo.StudyParam;
import com.study.pojo.StudyParamParent;
import java.lang.reflect.Constructor;
import java.lang.reflect.Type;
public class Study {
public static void main(String[] args) throws IllegalAccessException, InstantiationException {
Class<StudyParam> studyParamClass = StudyParam.class;
Class<StudyParamParent> studyParamParent = StudyParamParent.class;
System.out.println("-------- class toString -------- ");
System.out.println(studyParamClass.toString());
//class com.study.pojo.StudyParam
System.out.println("-------- class toGenericString -------- ");
System.out.println(studyParamClass.toGenericString());
//public class com.study.pojo.StudyParam
System.out.println("-------- class isInstance -------- ");
System.out.println(studyParamClass.isInstance(new StudyParam()));
System.out.println(studyParamClass.isInstance(new StudyParamParent()));
//true
//false
System.out.println("-------- class isAssignableFrom -------- ");
System.out.println(studyParamClass.isAssignableFrom(StudyParamParent.class));
System.out.println(studyParamClass.isAssignableFrom(StudyInfer.class));
System.out.println(studyParamParent.isAssignableFrom(StudyParam.class));
//false
//false
//true
System.out.println("-------- class isInterface -------- ");
System.out.println(studyParamClass.isInterface());
// false
System.out.println("-------- class isArray -------- ");
System.out.println(studyParamClass.isArray());
// false
System.out.println("-------- class isPrimitive -------- ");
System.out.println(studyParamClass.isPrimitive());
// false
System.out.println("-------- class isAnnotation -------- ");
System.out.println(studyParamClass.isAnnotation());
// false
System.out.println("-------- class getName -------- ");
System.out.println(studyParamClass.getName());
// com.study.pojo.StudyParam
System.out.println("-------- class getSimpleName -------- ");
System.out.println(studyParamClass.getSimpleName());
// StudyParam
System.out.println("-------- class getCanonicalName -------- ");
System.out.println(studyParamClass.getCanonicalName());
// com.study.pojo.StudyParam
System.out.println("-------- class getTypeName -------- ");
System.out.println(studyParamClass.getTypeName());
//com.study.pojo.StudyParam
System.out.println("-------- class getInterfaces -------- ");
Class<?>[] interfaces = studyParamClass.getInterfaces();
for (Class<?> interfacess : interfaces) {
System.out.println(interfacess);
}
//interface com.study.pojo.StudyInfer
System.out.println("-------- class getSuperclass -------- ");
Class<? super StudyParam> superclass = studyParamClass.getSuperclass();
System.out.println(superclass);
// class com.study.pojo.StudyParamParent
System.out.println("-------- class getGenericSuperclass -------- ");
Type genericSuperclass = studyParamClass.getGenericSuperclass();
System.out.println(genericSuperclass.getTypeName());
// com.study.pojo.StudyParamParent
System.out.println("-------- class getPackage -------- ");
Package aPackage = studyParamClass.getPackage();
System.out.println(aPackage.getName());
// com.study.pojo
System.out.println("-------- class getComponentType -------- ");
StudyParam studyParam = studyParamClass.newInstance();
studyParam.setStrings(new String[]{"1"});
Class<?> componentType = studyParamClass.getComponentType();
Class<?> componentType1 = studyParam.getStrings().getClass().getComponentType();
System.out.println(componentType);
System.out.println(componentType1);
//null
//class java.lang.String
System.out.println("-------- class getClassLoader -------- ");
ClassLoader classLoader = studyParamClass.getClassLoader();
System.out.println(classLoader);
// sun.misc.Launcher$AppClassLoader@18b4aac2
}
}
涉及的方法如下:
方法名称 | 用途 | 返回值 |
---|---|---|
forname | 根据类全类名称获取类 | Class |
获取 Class 有四种方式:
example:
Class clazz1 = Class.forName("com.study.pojo.StudyParam");
Class clazz2 = GenericTest.class;
Class clazz3 = new GenericTest().getClass();
ClassLoader loader = null;
loader.loadClass("com.study.pojo.StudyParam");
类中有很多方法,包括:
常用获取类中方法的方式如下:
方法名称 | 用途 | 返回值 |
---|---|---|
getMethods | 或者本类以及父类或者父接口中所有的公共方法 | Method[] |
getMethod | 获取本类以及父类或者父接口中所有的公共方法指定的Method | Method |
getDeclaredMethod | 获取本类所有的方法中指定的Method,不包括继承的方法 | Method |
getDeclaredMethods() | 获取本类所有的方法,不包括继承的方法 | Method[] |
getConstructors getDeclaredConstructors |
获取所有的构造方法 getConstructors包含所有的公共构造方法 getDeclaredConstructors 包含所有的构造方法 |
Constructor[] |
getConstructor | 获取指定构造方法 | Constructor |
方法使用举例:
package com.study;
import com.study.pojo.StudyInfer;
import com.study.pojo.StudyParam;
import com.study.pojo.StudyParamParent;
import java.lang.reflect.Constructor;
import java.lang.reflect.Type;
public class Study {
public static void main(String[] args) throws NoSuchMethodException {
Class<StudyParam> studyParamClass = StudyParam.class;
System.out.println("-------- class getConstructors -------- ");
Constructor<?>[] constructors = studyParamClass.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
//public com.study.pojo.StudyParam()
//public com.study.pojo.StudyParam(java.lang.String,java.util.List,java.lang.String[],java.util.List)
//public com.study.pojo.StudyParam(java.lang.String,java.util.List,java.util.List,java.lang.String)
System.out.println("-------- class getConstructor -------- ");
Constructor<StudyParam> constructor = studyParamClass.getConstructor(String.class, List.class, List.class, String.class);
System.out.println(constructor);
//public com.study.pojo.StudyParam(java.lang.String,java.util.List,java.util.List,java.lang.String)
System.out.println("-------- class getDeclaredConstructors -------- ");
Constructor<?>[] declaredConstructors = studyParamClass.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
}
//public com.study.pojo.StudyParam()
//public com.study.pojo.StudyParam(java.lang.String,java.util.List,java.lang.String[],java.util.List)
//private com.study.pojo.StudyParam(java.lang.String,java.util.List,java.util.List,java.lang.String,java.util.List)
//public com.study.pojo.StudyParam(java.lang.String,java.util.List,java.util.List,java.lang.String)
System.out.println("-------- class getDeclaredConstructor -------- ");
Constructor<StudyParam> declaredConstructor = studyParamClass.getDeclaredConstructor(String.class, List.class, List.class, String.class, List.class);
System.out.println(declaredConstructor);
//private com.study.pojo.StudyParam(java.lang.String,java.util.List,java.util.List,java.lang.String,java.util.List)
System.out.println("-------- class getMethods -------- ");
Method[] methods = studyParamClass.getMethods();
for (Method method : methods) {
System.out.println(method);
}
//public java.lang.String com.study.pojo.StudyParam.toString()
//public java.lang.String com.study.pojo.StudyParam.getName()
//public void com.study.pojo.StudyParam.setName(java.lang.String)
//public void com.study.pojo.StudyParam.setDList(java.util.List)
//public void com.study.pojo.StudyParam.publicGetInfer()
//public java.util.List com.study.pojo.StudyParam.getList()
//public java.util.List com.study.pojo.StudyParam.getDList()
//public void com.study.pojo.StudyParam.setList(java.util.List)
//public void com.study.pojo.StudyParam.getPublicHa()
//public void com.study.pojo.StudyParam.getPublicHa(java.lang.String)
//public java.lang.String[] com.study.pojo.StudyParam.getStrings()
//public void com.study.pojo.StudyParam.setStrings(java.lang.String[])
//public void com.study.pojo.StudyParam.publicGet()
//public void com.study.pojo.StudyParamParent.setDListPre(java.util.List)
//public void com.study.pojo.StudyParamParent.publicGetParent()
//public java.util.List com.study.pojo.StudyParamParent.getListPre()
//public void com.study.pojo.StudyParamParent.setNamePre(java.lang.String)
//public void com.study.pojo.StudyParamParent.setListPre(java.util.List)
//public java.util.List com.study.pojo.StudyParamParent.getDListPre()
//public java.lang.String com.study.pojo.StudyParamParent.getNamePre()
//public void com.study.pojo.StudyParamParentPre.publicGetParentPre()
//public java.util.List com.study.pojo.StudyParamParentPre.getDListPrePre()
//public java.lang.String com.study.pojo.StudyParamParentPre.getNamePrePre()
// public void com.study.pojo.StudyParamParentPre.setDListPrePre(java.util.List)
//public void com.study.pojo.StudyParamParentPre.setListPrePre(java.util.List)
//public void com.study.pojo.StudyParamParentPre.setNamePrePre(java.lang.String)
//public java.util.List com.study.pojo.StudyParamParentPre.getListPrePre()
//public final void java.lang.Object.wait() throws java.lang.InterruptedException
//public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
//public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
//public boolean java.lang.Object.equals(java.lang.Object)
//public native int java.lang.Object.hashCode()
//public final native java.lang.Class java.lang.Object.getClass()
//public final native void java.lang.Object.notify()
//public final native void java.lang.Object.notifyAll()
System.out.println("-------- class getMethod -------- ");
Method getPublicHa = studyParamClass.getMethod("getPublicHa", String.class);
System.out.println(getPublicHa);
//public void com.study.pojo.StudyParam.getPublicHa(java.lang.String)
System.out.println("-------- class getDeclaredMethods -------- ");
Method[] declaredMethods = studyParamClass.getDeclaredMethods();
for (Method method : declaredMethods) {
System.out.println(method);
}
//public java.lang.String com.study.pojo.StudyParam.toString()
//public java.lang.String com.study.pojo.StudyParam.getName()
//public void com.study.pojo.StudyParam.setName(java.lang.String)
//public void com.study.pojo.StudyParam.setDList(java.util.List)
//public void com.study.pojo.StudyParam.publicGetInfer()
//private void com.study.pojo.StudyParam.privateGet()
//public java.util.List com.study.pojo.StudyParam.getList()
//public java.util.List com.study.pojo.StudyParam.getDList()
//public void com.study.pojo.StudyParam.setList(java.util.List)
//public void com.study.pojo.StudyParam.getPublicHa()
//public void com.study.pojo.StudyParam.getPublicHa(java.lang.String)
//public java.lang.String[] com.study.pojo.StudyParam.getStrings()
//public void com.study.pojo.StudyParam.setStrings(java.lang.String[])
//private void com.study.pojo.StudyParam.getPrivateHa(java.lang.String)
//private void com.study.pojo.StudyParam.getPrivateHa()
//public void com.study.pojo.StudyParam.publicGet()
//protected void com.study.pojo.StudyParam.protectedGet()
System.out.println("-------- class getDeclaredMethod -------- ");
Method getPrivateHa = studyParamClass.getDeclaredMethod("getPrivateHa", String.class);
System.out.println(getPrivateHa);
//private void com.study.pojo.StudyParam.getPrivateHa(java.lang.String)
}
}
类中有很多属性,包括:
常用获取类中属性的方式如下:
方法名称 | 用途 | 返回值 |
---|---|---|
getFields getDeclaredFields |
获取当前类和父类中 public 类型的 所有属性 获取当前类中的所有属性(public、protected、default、private) |
Field[] |
getField getDeclaredField |
获取当前类和父类中 public 类型的 指定属性 获取当前类中的指定属性(public、protected、default、private) |
Field |
方法使用举例:
package com.study;
import com.study.pojo.StudyInfer;
import com.study.pojo.StudyParam;
import com.study.pojo.StudyParamParent;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.List;
public class Study {
public static void getFiledInfo() throws NoSuchFieldException {
Class<StudyParam> studyParamClass = StudyParam.class;
System.out.println("-------- class getFields -------- ");
Field[] fields = studyParamClass.getFields();
for (Field field : fields) {
System.out.println(field);
}
// 无
System.out.println("-------- class getField -------- ");
Field name = studyParamClass.getField("name");
System.out.println(name);
// 无
System.out.println("-------- class getDeclaredFields -------- ");
Field[] declaredFields = studyParamClass.getDeclaredFields();
for (Field field : declaredFields) {
System.out.println(field);
}
//java.lang.String com.study.pojo.StudyParam.name
//java.util.List com.study.pojo.StudyParam.list
//java.lang.String[] com.study.pojo.StudyParam.strings
//java.util.List com.study.pojo.StudyParam.dList
System.out.println("-------- class getDeclaredField -------- ");
Field declaredField = studyParamClass.getDeclaredField("name");
System.out.println(declaredField);
//java.lang.String com.study.pojo.StudyParam.name
}
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, NoSuchFieldException {
getFiledInfo();
}
}
为了下面的示例,在上述的 StudyParam 类中新增一个方法
package com.study.pojo;
import lombok.*;
import java.util.ArrayList;
import java.util.List;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class StudyParam extends StudyParamParent implements StudyInfer {
public <T extends Throwable> List<String> getPublicHa(String name, String hhh, List<String> l, List<List<String>> ll) throws T, NullPointerException {
System.out.println("getPublicHa invoke process");
return new ArrayList<>();
}
}
类中的方法为Method,Method常用的方法如下:
方法名称 | 用途 | 返回值 |
---|---|---|
toString() toGenericString |
方法的名称字符串 | String |
isBridge isVarArgs isSynthetic isDefault |
是否是xxx,与上面的雷同 | boolean |
getReturnType getGenericReturnType |
返回方法返回值类型 | Class> Type |
getParameterTypes getGenericParameterTypes |
返回方法参数值类型 | Class>[] Type[] |
getExceptionTypes getGenericExceptionTypes |
返回方法异常抛出类型 | Class>[] Type[] |
getName | 获取方法名称 | String |
invoke | 方法执行 | |
getParameterCount | 获取方法的参数数量 | int |
getTypeParameters | 获取方法一共都用了哪些泛型参数 | TypeVariable[] |
setAccessible | 设置方法可访问 |
说明:(getGenericxxxx 这种相比较 getxxxx ,若涉及泛型会输出泛型里面参数的具体类型)
方法使用举例:
package com.study;
import com.study.pojo.StudyInfer;
import com.study.pojo.StudyParam;
import com.study.pojo.StudyParamParent;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.List;
public class Study {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, NoSuchFieldException {
method();
}
public static void method() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<StudyParam> studyParamClass = StudyParam.class;
StudyParam studyParam = new StudyParam();
Method getPublicHa = studyParamClass.getMethod("getPublicHa", String.class ,String.class ,List.class,List.class);
System.out.println("-------- method toString -------- ");
String toString = getPublicHa.toString();
System.out.println(toString);
// public java.util.List com.study.pojo.StudyParam.getPublicHa(java.lang.String,java.lang.String,java.util.List,java.util.List) throws java.lang.Throwable,java.lang.NullPointerException
System.out.println("-------- method toGenericString -------- ");
String toGenericString = getPublicHa.toGenericString();
System.out.println(toGenericString);
// public java.util.List com.study.pojo.StudyParam.getPublicHa(java.lang.String,java.lang.String,java.util.List,java.util.List>) throws T,java.lang.NullPointerException
System.out.println("-------- method isDefault -------- ");
boolean defaults = getPublicHa.isDefault();
System.out.println(defaults);
//false
System.out.println("-------- method getName -------- ");
String name = getPublicHa.getName();
System.out.println(name);
// getPublicHa
System.out.println("-------- method getParameterCount -------- ");
int parameterCount = getPublicHa.getParameterCount();
System.out.println(parameterCount);
// 4
System.out.println("-------- method getReturnType -------- ");
Class<?> returnType = getPublicHa.getReturnType();
System.out.println(returnType);
// interface java.util.List
System.out.println("-------- method getGenericReturnType -------- ");
Type genericReturnType = getPublicHa.getGenericReturnType();
System.out.println(genericReturnType);
// java.util.List
System.out.println("-------- method getParameterTypes -------- ");
Class<?>[] parameterTypes = getPublicHa.getParameterTypes();
for(Class<?> c : parameterTypes){
System.out.println(c);
}
//class java.lang.String
//class java.lang.String
//interface java.util.List
//interface java.util.List
System.out.println("-------- method getGenericParameterTypes -------- ");
Type[] genericParameterTypes = getPublicHa.getGenericParameterTypes();
for(Type t: genericParameterTypes){
System.out.println(t);
}
//class java.lang.String
//class java.lang.String
//java.util.List
//java.util.List>
System.out.println("-------- method getExceptionTypes -------- ");
Class<?>[] exceptionTypes = getPublicHa.getExceptionTypes();
for(Class<?> c : exceptionTypes){
System.out.println(c);
}
//class java.lang.Throwable
//class java.lang.NullPointerException
System.out.println("-------- method getGenericExceptionTypes -------- ");
Type[] genericExceptionTypes = getPublicHa.getGenericExceptionTypes();
for(Type t: genericExceptionTypes){
System.out.println(t);
}
// T
System.out.println("-------- method getGenericExceptionTypes -------- ");
Type[] genericExceptionTypes = getPublicHa.getGenericExceptionTypes();
for(Type t: genericExceptionTypes){
System.out.println(t);
}
// T
System.out.println("-------- method getTypeParameters -------- ");
TypeVariable<Method>[] typeParameters = getPublicHa.getTypeParameters();
for(TypeVariable<Method> typeVariable : typeParameters){
System.out.println(typeVariable);
}
// T
String invokeName = "name";
String invokeHhh = "hh";
List<String> invokeL = new ArrayList<>();
List<List<String>> invokeLl = new ArrayList<>();
getPublicHa.invoke(studyParam, invokeName , invokeHhh , invokeL , invokeLl);
// getPublicHa invoke process
}
}
本次示例使用以下构造方法:
package com.study.pojo;
import lombok.*;
import java.util.ArrayList;
import java.util.List;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class StudyParam extends StudyParamParent implements StudyInfer {
String name;
List<String> list;
String[] strings;
List<List<String>> dList;
public StudyParam(String namePre, List<String> listPre, List<List<String>> dListPre, String name) {
super(namePre, listPre, dListPre);
this.name = name;
this.list = listPre;
this.dList = dListPre;
}
}
Constructor(构造方法) 与 Method 类似,Constructor 常用的方法如下:
方法名称 | 用途 | 返回值 | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
toString() toGenericString |
方法的名称字符串 | String | ||||||||||||||||||
isVarArgs isSynthetic |
是否是xxx,与上面的雷同 | boolean | ||||||||||||||||||
getReturnType getGenericReturnType |
返回方法返回值类型 | Class> Type |
||||||||||||||||||
getParameterTypes getGenericParameterTypes |
返回方法参数值类型 | Class>[] Type[] |
||||||||||||||||||
getExceptionTypes getGenericExceptionTypes |
返回方法异常抛出类型 | Class>[] Type[] |
||||||||||||||||||
getName | 获取方法名称 | String | ||||||||||||||||||
getParameterCount | 获取方法的参数数量 | int | ||||||||||||||||||
getTypeParameters | 获取方法一共都用了哪些泛型参数 | TypeVariable 说明:(getGenericxxxx 这种相比较 getxxxx ,若涉及泛型会输出泛型里面参数的具体类型)
方法使用大多与Method相同,这里主要试 newInstance 方法来实例化类: Filed类中的属性为 Fileld,Fileld 常用的方法如下:
说明:(getGenericxxxx 这种相比较 getxxxx ,若涉及泛型会输出泛型里面参数的具体类型)
方法使用举例: 实例化类上述介绍了 反射、Class与Constructor,也介绍了其中的一些方法,此处之外,实例化类还有其他的几种方式,下面介绍一下:
注意:这里五种方法,只有 clone 对象拷贝方法 不会执行构造方法 准备: 1、正常 new 对象**(会调用构造方法)** 2、调用 Class对象 的 newInstance 方法 (会调用构造方法) 3、调用 Constructor 对象的 newInstance 方法 (会调用构造方法) 4、clone 对象拷贝方法 (不会调用构造方法) 使用这种方式,必须实现 Cloneable 接口,可自定义重写 clone 方法 调用: 5、通过 ObjectInputStream的readObject() 方法反序列化类 (会调用构造方法) 使用这种方式,必须实现 Serializable 接口 调用: |