反射和动态代理在Java中是如何实现和应用的?

2026-04-29 20:322阅读0评论SEO教程
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1809个文字,预计阅读时间需要8分钟。

反射和动态代理在Java中是如何实现和应用的?

反射允许对成员变量、方法和构造方法的信息进行编程访问。以下是通过反射获取Class对象的三种方式:

1. `Class.forName(全类名)`:在源代码阶段使用。

2.`Class.forName(类名.class)`:在源代码阶段使用。

反射和动态代理在Java中是如何实现和应用的?

3.`Class.forName(类名)`:在运行时使用。

反射允许对成员变量,成员方法和构造方法的信息进行编程访问。

1、获取Class对象(字节码文件对象)的三种方式

①、Class.forName(“全类名”) (在源代码阶段使用)

②、类名.class (在加载阶段中使用)

③、对象.getClass() (在运行阶段使用)

public class Test { public static void main(String[] args) throws ClassNotFoundException { //最为常用 final Class<?> aClass = Class.forName("Test05.Student"); System.out.println(aClass); //一般更多的时当做参数进行传递 final Class<Student> studentClass = Student.class; System.out.println(studentClass); //需要有对象才可以使用 Student s = new Student(); final Class<? extends Student> aClass1 = s.getClass(); System.out.println(aClass1 == aClass); //true System.out.println(aClass == studentClass); true } }

2、反射获取构造方法

如果要获取指定的构造方法,可以给方法中添加和构造相同的参数,如下所示:

import java.lang.reflect.Constructor; public class Test1 { public static void main(String[] args) throws NoSuchMethodException { //获取Student的字节对象 final Class<Student> studentClass = Student.class; //获取指定参数的构造方法 final Constructor<Student> declaredConstructor = studentClass.getDeclaredConstructor(String.class); //int类型的形参 studentClass.getDeclaredConstructor(int.class); System.out.println(declaredConstructor); } }

3、利用反射获取成员方法

4、利用反射获取成员方法

import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class Test1 { public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { //创建调用方法的对象 Student stu = new Student(); //获取字节码对象 final Class<Student> clazz = Student.class; //获取方法:第一个参数为方法名,第二个参数为方法中的形参 final Method method1 = clazz.getDeclaredMethod("show", String.class); //参数一:表示调用方法的对象 //参数二:表示给调用方法中传递的形参 method1.invoke(stu,"是酋长呀!"); } }

5、反射的作用

①、获取一个类里面所有的信息,获取到了之后,再执行其它的业务逻辑。

②、结合配置文件,动态的创建对象并调用方法。

5.1、案例一:对于任意一个对象,都可以把对象所有的字段名和值保存到文件中。

import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import java.lang.reflect.Field; public class Test1 { public static void main(String[] args) { Student stu = new Student("张三", 121); try { saveObject(stu); } catch (IOException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } //封装成一个方法 public static void saveObject(Object obj) throws IOException, IllegalAccessException { //获取字节码对象 final Class<?> clazz = obj.getClass(); //创建io流 BufferedWriter bw = new BufferedWriter(new FileWriter("F:\\Java基础\\Test02\\bb\\Information.txt")); //获取所有的成员变量 final Field[] fields = clazz.getDeclaredFields(); //遍历上面的成员变量 for (Field field : fields) { //先暂时取消访问权限 field.setAccessible(true); //获取成员变量的名称 final String name = field.getName(); //获取成员变量的值,参数为一个对象 final Object value = field.get(obj); //写出数据 bw.write(name + " = " + value); //换行 bw.newLine(); } //关闭io流的资源 bw.close(); } }

5.2、案例二:反射可以跟配置文件(后缀为properties的文件)结合的方式,动态的创建对象,并调用方法。

配置文件:

import java.io.FileInputStream; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Properties; public class Test1 { public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { //读取配置文件的信息 Properties prop = new Properties(); //创建io流 FileInputStream fis = new FileInputStream("F:\\Java基础\\Test02\\prop.properties"); //加载 prop.load(fis); //关闭资源 fis.close(); //获取全类名和方法 final String className = (String) prop.get("classname"); final String methodName = (String) prop.get("method"); //利用反射创建对象并且运行方法 final Class<?> clazz = Class.forName(className); //获取构造方法 final Constructor<?> con = clazz.getDeclaredConstructor(); //通过构造方法创建对象 final Object o = con.newInstance(); //获取成员方法并运行 final Method method = clazz.getDeclaredMethod(methodName); //设置临时访问权限 method.setAccessible(true); //调用方法,对象为上面通过构造方法创建的那个 method.invoke(o); } }

6、动态代理

步骤一:创建类

public class BigStar implements Star { private String name; private int age; //实现唱歌的方法 @Override public void sing(String name) { System.out.println(this.name + "正在唱" + name); } //实现跳舞的方法 @Override public void dance() { System.out.println(this.name + "正在跳舞"); } public BigStar() { } public BigStar(String name, int age) { this.name = name; this.age = age; } /** * 获取 * * @return name */ public String getName() { return name; } /** * 设置 * * @param name */ public void setName(String name) { this.name = name; } /** * 获取 * * @return age */ public int getAge() { return age; } /** * 设置 * * @param age */ public void setAge(int age) { this.age = age; } public String toString() { return "BigStar{name = " + name + ", age = " + age + "}"; } }

步骤二:把类中需要代理的方法添加封装成一个接口,所以类中需要实现接口中的抽象方法。

/** * 定义接口 * */ public interface Star { //唱歌的抽象方法 void sing(String name); //跳舞的抽象方法 void dance(); }

步骤三:封装生成代理的类

import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyUtil { //私有化构造方法 private ProxyUtil() { } //产生代理 public static Star creatProxy(BigStar bigStar) { Star star = (Star) Proxy.newProxyInstance( ProxyUtil.class.getClassLoader(), //参数一:用于指定用那个类加载器,去加载生成的代理类 new Class[]{Star.class}, //参数二:指定接口,这些接口用于指定生成的代理长什么样,也就是有那些方法,这里是数组的形式,可以添加多个接口,但是多个接口都需要被实现 //参数三:用来指定生成的代理对象要做什么事情 new InvocationHandler() { @Override /** * 参数一:代理的对象,一般不用管 * 参数二:要运行的方法 * 参数三:调用要运行的方法时传递的实参 * */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if ("sing".equals(method.getName())) { System.out.println("准备话筒,布置舞台!"); } else if ("dance".equals(method.getName())) { System.out.println("准备舞伴,布置舞台!"); } //利用反射调用BigStar中的方法 return method.invoke(bigStar, args); } } ); return star; } }

步骤四:通过生成代理的类生成一个代理对象,然后通过这个对象调用相应的方法

public class Test { public static void main(String[] args) { //创建对象 BigStar bigStar = new BigStar("邓紫棋", 28); //获取代理的对象 final Star star = ProxyUtil.creatProxy(bigStar); //通过代理调用里面的方法 star.sing("倒数"); star.dance(); } }

最后输出结果:

准备话筒,布置舞台! 邓紫棋正在唱倒数 准备舞伴,布置舞台! 邓紫棋正在跳舞

本文共计1809个文字,预计阅读时间需要8分钟。

反射和动态代理在Java中是如何实现和应用的?

反射允许对成员变量、方法和构造方法的信息进行编程访问。以下是通过反射获取Class对象的三种方式:

1. `Class.forName(全类名)`:在源代码阶段使用。

2.`Class.forName(类名.class)`:在源代码阶段使用。

反射和动态代理在Java中是如何实现和应用的?

3.`Class.forName(类名)`:在运行时使用。

反射允许对成员变量,成员方法和构造方法的信息进行编程访问。

1、获取Class对象(字节码文件对象)的三种方式

①、Class.forName(“全类名”) (在源代码阶段使用)

②、类名.class (在加载阶段中使用)

③、对象.getClass() (在运行阶段使用)

public class Test { public static void main(String[] args) throws ClassNotFoundException { //最为常用 final Class<?> aClass = Class.forName("Test05.Student"); System.out.println(aClass); //一般更多的时当做参数进行传递 final Class<Student> studentClass = Student.class; System.out.println(studentClass); //需要有对象才可以使用 Student s = new Student(); final Class<? extends Student> aClass1 = s.getClass(); System.out.println(aClass1 == aClass); //true System.out.println(aClass == studentClass); true } }

2、反射获取构造方法

如果要获取指定的构造方法,可以给方法中添加和构造相同的参数,如下所示:

import java.lang.reflect.Constructor; public class Test1 { public static void main(String[] args) throws NoSuchMethodException { //获取Student的字节对象 final Class<Student> studentClass = Student.class; //获取指定参数的构造方法 final Constructor<Student> declaredConstructor = studentClass.getDeclaredConstructor(String.class); //int类型的形参 studentClass.getDeclaredConstructor(int.class); System.out.println(declaredConstructor); } }

3、利用反射获取成员方法

4、利用反射获取成员方法

import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class Test1 { public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { //创建调用方法的对象 Student stu = new Student(); //获取字节码对象 final Class<Student> clazz = Student.class; //获取方法:第一个参数为方法名,第二个参数为方法中的形参 final Method method1 = clazz.getDeclaredMethod("show", String.class); //参数一:表示调用方法的对象 //参数二:表示给调用方法中传递的形参 method1.invoke(stu,"是酋长呀!"); } }

5、反射的作用

①、获取一个类里面所有的信息,获取到了之后,再执行其它的业务逻辑。

②、结合配置文件,动态的创建对象并调用方法。

5.1、案例一:对于任意一个对象,都可以把对象所有的字段名和值保存到文件中。

import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import java.lang.reflect.Field; public class Test1 { public static void main(String[] args) { Student stu = new Student("张三", 121); try { saveObject(stu); } catch (IOException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } //封装成一个方法 public static void saveObject(Object obj) throws IOException, IllegalAccessException { //获取字节码对象 final Class<?> clazz = obj.getClass(); //创建io流 BufferedWriter bw = new BufferedWriter(new FileWriter("F:\\Java基础\\Test02\\bb\\Information.txt")); //获取所有的成员变量 final Field[] fields = clazz.getDeclaredFields(); //遍历上面的成员变量 for (Field field : fields) { //先暂时取消访问权限 field.setAccessible(true); //获取成员变量的名称 final String name = field.getName(); //获取成员变量的值,参数为一个对象 final Object value = field.get(obj); //写出数据 bw.write(name + " = " + value); //换行 bw.newLine(); } //关闭io流的资源 bw.close(); } }

5.2、案例二:反射可以跟配置文件(后缀为properties的文件)结合的方式,动态的创建对象,并调用方法。

配置文件:

import java.io.FileInputStream; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Properties; public class Test1 { public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { //读取配置文件的信息 Properties prop = new Properties(); //创建io流 FileInputStream fis = new FileInputStream("F:\\Java基础\\Test02\\prop.properties"); //加载 prop.load(fis); //关闭资源 fis.close(); //获取全类名和方法 final String className = (String) prop.get("classname"); final String methodName = (String) prop.get("method"); //利用反射创建对象并且运行方法 final Class<?> clazz = Class.forName(className); //获取构造方法 final Constructor<?> con = clazz.getDeclaredConstructor(); //通过构造方法创建对象 final Object o = con.newInstance(); //获取成员方法并运行 final Method method = clazz.getDeclaredMethod(methodName); //设置临时访问权限 method.setAccessible(true); //调用方法,对象为上面通过构造方法创建的那个 method.invoke(o); } }

6、动态代理

步骤一:创建类

public class BigStar implements Star { private String name; private int age; //实现唱歌的方法 @Override public void sing(String name) { System.out.println(this.name + "正在唱" + name); } //实现跳舞的方法 @Override public void dance() { System.out.println(this.name + "正在跳舞"); } public BigStar() { } public BigStar(String name, int age) { this.name = name; this.age = age; } /** * 获取 * * @return name */ public String getName() { return name; } /** * 设置 * * @param name */ public void setName(String name) { this.name = name; } /** * 获取 * * @return age */ public int getAge() { return age; } /** * 设置 * * @param age */ public void setAge(int age) { this.age = age; } public String toString() { return "BigStar{name = " + name + ", age = " + age + "}"; } }

步骤二:把类中需要代理的方法添加封装成一个接口,所以类中需要实现接口中的抽象方法。

/** * 定义接口 * */ public interface Star { //唱歌的抽象方法 void sing(String name); //跳舞的抽象方法 void dance(); }

步骤三:封装生成代理的类

import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyUtil { //私有化构造方法 private ProxyUtil() { } //产生代理 public static Star creatProxy(BigStar bigStar) { Star star = (Star) Proxy.newProxyInstance( ProxyUtil.class.getClassLoader(), //参数一:用于指定用那个类加载器,去加载生成的代理类 new Class[]{Star.class}, //参数二:指定接口,这些接口用于指定生成的代理长什么样,也就是有那些方法,这里是数组的形式,可以添加多个接口,但是多个接口都需要被实现 //参数三:用来指定生成的代理对象要做什么事情 new InvocationHandler() { @Override /** * 参数一:代理的对象,一般不用管 * 参数二:要运行的方法 * 参数三:调用要运行的方法时传递的实参 * */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if ("sing".equals(method.getName())) { System.out.println("准备话筒,布置舞台!"); } else if ("dance".equals(method.getName())) { System.out.println("准备舞伴,布置舞台!"); } //利用反射调用BigStar中的方法 return method.invoke(bigStar, args); } } ); return star; } }

步骤四:通过生成代理的类生成一个代理对象,然后通过这个对象调用相应的方法

public class Test { public static void main(String[] args) { //创建对象 BigStar bigStar = new BigStar("邓紫棋", 28); //获取代理的对象 final Star star = ProxyUtil.creatProxy(bigStar); //通过代理调用里面的方法 star.sing("倒数"); star.dance(); } }

最后输出结果:

准备话筒,布置舞台! 邓紫棋正在唱倒数 准备舞伴,布置舞台! 邓紫棋正在跳舞