反射
1. 序列化和反序列化
对象流:
ObjectOutputStream:内存中的对象-----转化为---->存储中的文件、通过网络传输出去:序列化
ObjectInputStream:存储中的文件、通过网络接收过来-----还原为---->内存中的对象:反序列化
对象的序列化机制:
序列化:内存中的Java对象转换成二进制流,把二进制流持久地保存在磁盘上,通过网络将二进制流传输到另一个网络节点。
反序列化:当其它程序获取到了这种二进制流,可以恢复成原来的Java对象。
2. 反射(动态性)
- Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于
Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。 - 加载完类之后,在堆内存的方法区中就产生了一个
Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射。 - 类的加载过程:javac.exe命令后,生成一个或多个字节码文件(.class结尾),使用java.exe对某个字节码文件进行解释运行,加载到内存中。
- Class的实例就对应着一个运行时的类

(1)反射机制的功能:
-
在运行时判断任意一个对象所属的类
-
在运行时构造任意一个类的对象
-
在运行时判断任意一个类所具有的成员变量和方法
-
在运行时获取泛型信息
-
在运行时调用任意一个对象的成员变量和方法
-
在运行时处理注解
-
生成动态代理
(2)获取Class的实例方法
1)已知具体的类,通过类的 class 属性获取,该方法最为安全可靠,程序性能最高 实例:Class clazz = String.class;
2)已知某个类的实例,调用该实例的 getclass() 方法获取 Class 对象 实例:Class clazz=person.getclass();
3)已知一个类的全类名,且该类在类路径下,可通过 Class 类的静态方法 forName() 获取,可能抛出 ClassNotFoundException(比较常用)
实例:Class clazz = Class.forName(String classPath)
4)通过类加载器 ClassLoader cl = this.getclass().getClassLoader(); Class clazz = cl.loadClass("类的全类名");
public class Person {
private String name;
public int age;
public Person(){ }
private Person(String name) {
this.name = name;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public void show(){
System.out.println("it is my show time");
}
private String myNation(String nation){
System.out.println("祖国"+nation);
return nation;
}
}
Reflection测试
public class ReflectTest {
static void test01(){//反射前对实例对象的操作
Person person = new Person("张三",8);
person.show();
person.age = 12;
System.out.println(person.toString());
}
static void test02() { //反射方法
//获取Class的实例的方式
//方式1:调用运行时类的属性
Class clazz = Person.class; //Class<Person> clazz = Person.class;
System.out.println(clazz);
//方式2:通过运行时类的对象获取
Person person = new Person();
Class clazz1 = person.getClass();
System.out.println(clazz1);
//方式3:调用Class的静态方法:forName(String classPath)
Class clazz2 = null;
try {
clazz2 = Class.forName("Person");
System.out.println(clazz2);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//方式4:使用类的加载器:ClassLoader
ClassLoader classLoader = ReflectTest.class.getClassLoader();
try {
Class clazz3 = classLoader.loadClass("Person");
System.out.println(clazz3);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
test01();
test02();
}
}
(3)除了类之外哪些结构可以作为Class的实例?
1)class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类
2)interface:接口
3)[]:数组
4)enum:枚举
5)annotation:注解@interface
6)primitive type:基本数据类型
7)void:无返回值
(4)读取配置文件的方式
1)使用IO流读取
Properties pros = new Properties();
// //读取配置文件的方式一:
// //此时的文件默认在当前的module下。
// FileInputStream fis = new FileInputStream("src\\jdbc1.properties");
// pros.load(fis);
//读取配置文件的方式二:使用ClassLoader
//配置文件默认识别为:当前module的src下
ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
InputStream is = classLoader.getResourceAsStream("jdbc1.properties");
try {
pros.load(is);
} catch (IOException e) {
e.printStackTrace();
}
String user = pros.getProperty("user");
String password = pros.getProperty("password");
System.out.println("user = " + user + " password =" + password);
(5)创建运行时类的对象
反射具有动态性,要创建对象时,不知道具体哪个对象,不能使用new,只能使用newInstance()。
Class<Person> clazz = Person.class;
Person obj = clazz.newInstance(); //调用运行时类的无参的构造方法
(6)反射可以取得的结构:
-
实现的全部接口:
public Class<?>[] getInterfaces()确定此对象所表示的类或接口实现的接口。 -
所继承的父类:
public Class<? Super T> getSuperclass()返回表示此Class所表示的实体(类、接口、基本类型)的父类的Class。 -
全部的构造器:
public Constructor<T>[] getConstructors()返回此
Class对象所表示的类的所有public构造方法。public Constructor<T>[] getDeclaredConstructors()返回此Class对象表示的类声明的所有构造方法。
在Constructor类中:
- 取得修饰符:
public int getModifiers(); - 取得方法名称:
public String getName(); - 取得参数的类型:
public Class<?> getParameterTypes();
- 取得修饰符:
-
全部的方法:
public Method[] getDeclaredMethods()返回此Class对象所表示的类或接口的全部方法
public Method[] getMethods()返回此
Class对象所表示的类或接口的public的方法Method类中:public Class<?> getReturnType():取得全部的返回值public Class<?>[] getParameterTypes():取得全部的参数public int getModifiers():取得修饰符public Class<?> [] getEXceptionTypes():取得异常信息
-
全部的
Field:public Field[] getFields()返回此
Class对象所表示的类或接口的public的Field。public Field[] getDeclaredFields()返回此
Class对象所表示的类或接口的全部FieldField方法中public int getModifiers():以整数形式返回此Field的修饰符public Class<?> getType():得到Field的属性类型public String getName():返回Field的名称。
-
Annotation相关get Annotation(Class<T> annotationClass)getDeclaredAnnotations() -
泛型相关
获取父类泛型类型:
Type getGenericSuperclass()泛型类型:
ParameterizedType获取实际的泛型类型参数数组:
getActualTypeArguments() -
类所在的包
Package getPackage()
获取运行时类的属性filed:
getFields():获取当前运行时类及其父类中声明为public访问权限的属性
getDeclaredFields():获取当前运行时类中声明的所有属性。(不包含父类中声明的属性)
getType():数据类型
public class FiledTest {
@Test
public void test1() {
Class clazz = Person.class;
//获取属性结构
//getFields():获取当前运行时类及其父类中声明为public访问权限的属性
Field[] fields = clazz.getFields();
for (Field f :
fields) {
System.out.println(f);
}
System.out.println();
//getDeclaredFields():获取当前运行时类中声明的所有属性。(不包含父类中声明的属性)
Field[] declaredFields = clazz.getDeclaredFields();
for (Field f :
declaredFields) {
System.out.println(f);
}
}
//权限修饰符 数据类型 变量名
@Test
public void test2() throws ClassNotFoundException {
Class clazz = Class.forName("Person");
Field[] declaredFields = clazz.getDeclaredFields();
for (Field f :
declaredFields) {
//1.权限修饰符
int modifiers = f.getModifiers();
System.out.print(Modifier.toString(modifiers)+"\t");
//2.数据类型
Class<?> type = f.getType();
System.out.print(type.getName()+"\t");
//3.变量名
String fName = f.getName();
System.out.print(fName);
System.out.println();
}
}
}
获取运行时类的方法Methods:
getMethods():获取当前运行时类及其所有父类中声明为public权限的方法
getDeclaredMethods():获取当前运行时类中声明的所有方法。(不包含父类中声明的方法)
getAnnotations():获取方法声明的注解
getModifiers():权限修饰符
getReturnType():返回值类型
getName():方法名
getParameterTypes():形参类型
getExceptionTypes():抛出的异常
public class MethodTest {
@Test
public void test1() {
Class<Person> clazz = Person.class;
//getMethods():获取当前运行时类及其所有父类中声明为public权限的方法
Method[] methods = clazz.getMethods();
for (Method m :
methods) {
System.out.println(m);
}
System.out.println("============");
//getDeclaredMethods():获取当前运行时类中声明的所有方法。(不包含父类中声明的方法)
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method m :
declaredMethods) {
System.out.println(m);
}
}
/*
@Xxxx
权限修饰符 返回值类型 方法名(参数类型1 形参名1,...) throws XxxException{}
*/
@Test
public void test2() throws ClassNotFoundException {
Class<?> clazz = Class.forName("Person");
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method m :
declaredMethods) {
//1.获取方法声明的注解
Annotation[] annos = m.getAnnotations();
for (Annotation a :
annos) {
System.out.println(a);
}
//2.权限修饰符
System.out.print(Modifier.toString(m.getModifiers())+"\t");
//3.返回值类型
System.out.print(m.getReturnType().getName() + "\t");
//4.方法名
System.out.print(m.getName());
System.out.print("(");
//5.形参列表
Class<?>[] parameterTypes = m.getParameterTypes();
if (!(parameterTypes == null && parameterTypes.length == 0)) {
for (int i = 0; i < parameterTypes.length; i++) {
if (i == parameterTypes.length - 1) {
System.out.print(parameterTypes[i].getName() + " args_" + i);
break;
}
System.out.print(parameterTypes[i].getName() + "args_" + i + ",");
}
}
System.out.print(")");
//6.抛出的异常
Class<?>[] exceptionTypes = m.getExceptionTypes();
if (exceptionTypes.length > 0){
System.out.print("throws ");
for (int i = 0; i < exceptionTypes.length; i++) {
if (i==exceptionTypes.length -1){
System.out.print(exceptionTypes[i].getName());
break;
}
System.out.print(exceptionTypes[i].getName()+",");
}
System.out.println();
}
}
}
}
获取构造器结构
getConstructors():获取当前运行时类中声明为public的构造器
getDeclaredConstructors():获取当前运行时类中声明的所有的构造器
获取运行时类的父类:getSuperclass()
获取运行时类的带泛型的父类:getGenericSuperclass()
获取运行时类的带泛型的父类的泛型:(ParameterizedType :所带的参数类型)
调用运行时类中指定的属性:
调用运行时类中指定的方法:

public void testMethod() throws Exception {
Class<Person> clazz = Person.class;
//创建运行时类的对象
Person person = clazz.newInstance();
/*
1.获取指定的某个方法
getDeclaredMethod():参数1 :指明获取的方法的名称 参数2:指明获取的方法的形参列表
*/
Method show = clazz.getDeclaredMethod("show", String.class);
//2.保证当前方法是可访问的
show.setAccessible(true);
/*
3. 调用方法的invoke():参数1:方法的调用者 参数2:给方法形参赋值的实参
invoke()的返回值即为对应类中调用的方法的返回值。
*/
Object returnValue = show.invoke(person, "CHN");
System.out.println(returnValue);
System.out.println("*************如何调用静态方法*****************");
Method showDesc = clazz.getDeclaredMethod("showDesc");
showDesc.setAccessible(true);
//如果调用的运行时类中的方法没有返回值,则此invoke()返回null
//Object returnVal = showDesc.invoke(null);
Object returnVal = showDesc.invoke(Person.class);
System.out.println(returnVal);
}
调用运行时类中指定的构造器
public void testConstructor() throws Exception {
Class clazz = Person.class;
//private Person(String name)
/*
1.获取指定的构造器
getDeclaredConstructor():参数:指明构造器的参数列表
*/
Constructor constructor = clazz.getDeclaredConstructor(String.class);
//2.保证此构造器是可访问的
constructor.setAccessible(true);
//3.调用此构造器创建运行时类的对象
Person per = (Person) constructor.newInstance("Tom");
System.out.println(per);
}
3.动态代理
使用一个代理将对象包装起来,然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。
(1)静态代理
静态代理的缺点:
① 代理类和目标对象的类都是在编译期间确定下来,不利于程序的扩展。
② 每一个代理类只能为一个接口服务,这样一来程序开发中必然产生过多的代理。
interface ClothFactory{
void produceCloth();
}
//代理类
class ProxyClothFactory implements ClothFactory{
private ClothFactory factory;//用被代理类对象进行实例化
public ProxyClothFactory(ClothFactory factory) {
this.factory = factory;
}
@Override
public void produceCloth() {
System.out.println("代理工厂做一些准备工作");
factory.produceCloth();
System.out.println("代理工厂做一些后续的收尾工作");
}
}
//被代理类
class NikeClothFactory implements ClothFactory{
@Override
public void produceCloth() {
System.out.println("Nike工厂生产了一批运动服");
}
}
//测试
public class StaticProxyTest {
public static void main(String[] args) {
//创建被代理类的对象
ClothFactory nike = new NikeClothFactory();
//创建代理类的对象
ClothFactory proxyClothFactory = new ProxyClothFactory(nike);
proxyClothFactory.produceCloth();
}
}
/*
代理工厂做一些准备工作
Nick工厂生产一批运动服
代理工厂做一些后续的收尾工作
*/
(2)动态代理
两个主要问题:
问题一:如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象。
(通过 Proxy.newProxyInstance() 实现)
问题二:当通过代理类的对象调用方法a时,如何动态的去调用被代理类中的同名方法。
(通过 InvocationHandler 接口的实现类及其方法 invoke() )
实现步骤:
-
创建一个实现接口
InvocationHandler的类,它必须实现invoke方法,以完成代理的具体操作。 -
创建被代理类以及接口
-
通过Proxy的静态方法
newProxyInstance(ClassLoader loader, Class<?>...interface, InvocationHandler h)创建一个接口代理 -
通过代理类的实例调用被代理类的方法
interface Human {
String getBelief();
void eat(String food);
}
//被代理类
class SuperMan implements Human {
@Override
public String getBelief() {
return "I believe I can fly!";
}
@Override
public void eat(String food) {
System.out.println("I like eat " + food);
}
}
/*
要想实现动态代理,需要解决的问题?
问题一:如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象。
问题二:当通过代理类的对象调用方法a时,如何动态的去调用被代理类中的同名方法a。
*/
//创建继承了InvocationHandler接口的类
class MyInvocationHanlder implements InvocationHandler {
private Object obj;//需要使用被代理类的对象进行赋值
public void bind(Object obj) {
this.obj = obj;
}
//当我们通过代理类的对象,调用方法a时,就会自动的调用如下的方法:invoke()
//将被代理类要执行的方法a的功能就声明在invoke()中
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//method:即为代理类对象调用的方法,此方法也就作为了被代理类对象要调用的方法
//obj:被代理类的对象
Object returnValue = method.invoke(obj, args);
//上述方法的返回值就作为当前类中的invoke()的返回值。
return returnValue;
}
}
class ProxyFactory {
//调用此方法,返回一个代理类的对象。解决问题一
public static Object getProxyInstance(Object obj) {
MyInvocationHanlder hanlder = new MyInvocationHanlder();
hanlder.bind(obj);
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),hanlder);
}
}
//测试动态代理
public class ProxyTest {
public static void main(String[] args) {
SuperMan superMan = new SuperMan();
//proxyInstance:代理类的对象
Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);
//当通过代理类对象调用方法时,会自动的调用被代理类中同名的方法
String belief = proxyInstance.getBelief();
System.out.println(belief);
proxyInstance.eat("火锅");
}
}
动态代理与AOP
-
使用
Proxy生成一个动态代理时,往往并不会凭空产生一个动态代理,这样没有太大的意义。通常都是为指定的目标对象生成动态代理。 -
这种动态代理在
AOP中被称为AOP代理,AOP代理可代替目标对象,AOP代理包含了目标对象的全部方法。但AOP代理中的方法与目标对象的方法存在差异: -
AOP代理里的方法可以在执行目标方法之前、之后插入一些通用处理

浙公网安备 33010602011771号