当前位置:网络安全 > Java反射学习笔记

Java反射学习笔记

  • 发布:2023-09-26 05:19

前言

  • Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
  • 加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射。

补充:动态语言和静态语言

1、 动态语言

  1. 是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至 代码可以被引进,已有的函数可以被删除或是其他结构上的变化。通俗点说 就是在运行时代码可以根据某些条件改变自身结构。
  2. 主要动态语言:Object-C、C#、JavaScript、PHP、Python、Erlang。

2、静态语言

  1. 与动态语言相对应的,运行时结构不可变的语言就是静态语言。如Java、C、C++。
  2. Java不是动态语言,但Java可以称之为“准动态语言”。即Java有一定的动态性,我们可以利用反射机制、字节码操作获得类似动态语言的特性。 Java的动态性让编程的时候更加灵活

Java反射机制提供的功能

  • 在运行时判断任意一个对象所属的类
  • 在运行时构造任意一个类的对象
  • 在运行时判断任意一个类所具有的成员变量和方法
  • 在运行时获取泛型信息
  • 在运行时调用任意一个对象的成员变量和方法
  • 在运行时处理注解
  • 生成动态

反射相关的API

  • java.lang.Class:代表一个类
  • java.lang.reflect.Method:代表类的方法
  • java.lang.reflect.Field:代表类的成员变量
  • java.lang.reflect.Constructor:代表类的构造器

反射获取和修改某一对象

User类

public class User implements Comparable<User> {private String name;public int age;public User(String name, int age) {this.name = name;this.age = age;}private User(String name) {this.name = name;}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;}public void show() {System.out.println("调用了show方法");}private void pri(String str){System.out.println("z这是一个私有方法"+str);}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic int compareTo(User o) {return -this.name.compareTo(o.name);}
}

创建并获取和修改User类

   @Testpublic void fanshe() throws Exception {Class<User> userClass = User.class;Constructor<User> constructor = userClass.getDeclaredConstructor(String.class, int.class);User lihua = constructor.newInstance("lihua", 77);System.out.println(lihua);// User{name='lihua', age=77}lihua.setAge(66);System.out.println(lihua);// User{name='lihua', age=66}Field age = userClass.getDeclaredField("age");age.set(lihua, 55);System.out.println(lihua);// User{name='lihua', age=55}Method show = userClass.getDeclaredMethod("show");show.invoke(lihua);// 调用了show方法//调用私有构造器Constructor<User> constructor1 = userClass.getDeclaredConstructor(String.class);constructor1.setAccessible(true);User zhangsan = constructor1.newInstance("zhangsan");System.out.println(zhangsan);// User{name='zhangsan', age=0}// 修改私有属性Field name = userClass.getDeclaredField("name");name.setAccessible(true);name.set(zhangsan,"zhangsam1");System.out.println(zhangsan);// User{name='zhangsam1', age=0}// 调用私有方法//        Method pri = userClass.getDeclaredMethod("pri")没有参数的写法Method pri = userClass.getDeclaredMethod("pri",String.class);pri.setAccessible(true);pri.invoke(zhangsan,"dsdd");// z这是一个私有方法dsdd}

获取Class的实例方法

 @Testpublic void classget() throws ClassNotFoundException {// 第一种写法Class<User> userClass = User.class;System.out.println(userClass);// class User// 第二种写法User user = new User();Class<? extends User> aClass = user.getClass();System.out.println(aClass);// class User// 第三种写法(常用)Class<?> user1 = Class.forName("User");System.out.println(user1);// class User// 第四种(了解)test为当前类的名字ClassLoader classLoader = test.class.getClassLoader();Class<?> user2 = classLoader.loadClass("User");System.out.println(user2);// class User}

哪些类型可以有Class对象?

( 1) class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类

( 2) interface:接口

(3)[]:数组

(4) enum:攻举

(5) annotation:注解@interface

(6) primitive type:基本数据类型

( 7) void

  @Testpublic void shuzu(){int[] a = new int[10];int[] b = new int[100];int[][] c = new int[10][];Class<? extends int[]> aClass = a.getClass();Class<? extends int[]> aClass1 = b.getClass();Class<? extends int[][]> aClass2 = c.getClass();// 只要类型和维度一样就是同一个ClassSystem.out.println(aClass == aClass1);// true//        System.out.println(aClass == aClass2);报错}

使用CLassLoad加载配置文件

    @Testpublic void classLoad() throws IOException {Properties properties = new Properties();// 方式一
//        FileInputStream inputStream = new FileInputStream("src\\jdbc.properties"); 此方法路径默认在工程下// 方式二ClassLoader classLoader = test.class.getClassLoader();InputStream inputStream = classLoader.getResourceAsStream("jdbc.properties");// 此方法默认在srproperties.load(inputStream);String name = properties.getProperty("name");System.out.println(name);}

动态代理

代理设计模式的原理

使用一个代理将对象包装起来,然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。
之前的代理机制的操作,属于静态代理,特征是代理类和目标对象的类都是在编译期间确定下来,不利于程序的扩展。同时,每一个代理类只能为一个接口服务,这样一来程序开发中必然产生过多的代理。最好可以通过一个代理类完成全部的代理功能。

动态代理是指客户通过代理类来调用其它对象的方法,并且是在程序运行时根据需要动态创建目标类的代理对象。

动态代理使用场合:

  • 调试
  • 远程方法调用

JDK动态代理举例

    interface Human{String bef();void eat(String str);}class SuperMan implements Human{@Overridepublic String bef() {return "我相信光";}@Overridepublic void eat(String str) {System.out.println( "我喜欢吃"+str);}}static class ProxyFactory{public static Object getProxyFactory(Object object){MyInvocationHandler myInvocationHandler = new MyInvocationHandler();myInvocationHandler.bind(object);return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(), myInvocationHandler);}}static class MyInvocationHandler implements InvocationHandler{// 需要被代理的对象进行赋值private Object object;public void bind(Object object) {this.object = object;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("代理前所作工作");Object invoke = method.invoke(object, args);System.out.println("代理后所作工作");return invoke;}}@Testpublic void DyProxy(){SuperMan superMan = new SuperMan();Human proxyFactory = (Human) ProxyFactory.getProxyFactory(superMan);proxyFactory.bef();proxyFactory.eat("麻辣烫");}
}

CGLIB动态代理
JDK 动态代理有一个的缺陷就是其只能代理实现了接口的类。而CGLIB正好解决了这个问题,在 CGLIB 动态代理机制中 MethodInterceptor 接口和 Enhancer 类是核心

//定义被代理类
class SuperMan{public void whoAmI(){System.out.println("我是超人");}
}
// 定义代理类
class MyMethodInterceptor implements MethodInterceptor{/*o:被代理对象method:被拦截的方法objects:参数methodProxy:调用原始方法*/@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("你是谁?");// 被增强的方法Object invoke = methodProxy.invokeSuper(o, objects);System.out.println("好的,我知道了!");return invoke;}
}class CglibProxyFactory{public static Object getProxy(Class<?> clazz){// 创建增强类Enhancer enhancer = new Enhancer();// 设置被代理类enhancer.setSuperclass(clazz);// 设置类加载器enhancer.setClassLoader(clazz.getClassLoader());// 设置fenhancer.setCallback(new MyMethodInterceptor());return enhancer.create(); // 创建出代理类}
}
// 执行@Testpublic void ProxyTest(){SuperMan proxy = (SuperMan) CglibProxyFactory.getProxy(SuperMan.class);proxy.whoAmI();}
// 结果
你是谁?
我是超人
好的,我知道了!java

静态代理

特点:代理类和被代理类编译期间就确定下来了

interface clothFactory{void pro();}class proxyFactory implements clothFactory {private clothFactory clothFactory;public proxyFactory(clothFactory factory) {this.clothFactory = factory;}@Overridepublic void pro() {System.out.println("代理工厂做的前期操作");clothFactory.pro();System.out.println("代理工厂做的后期操作");}}class nike implements clothFactory{@Overridepublic void pro() {System.out.println("nike");}}@Testpublic void proxy(){nike nike = new nike();proxyFactory proxyFactory = new proxyFactory(nike);proxyFactory.pro();}

动态代理相比于静态代理的优点:

​ 抽象角色中(接口)声明的所有方法都被转移到调用处理器一个集中的方法中处理,这样,我们可以更加灵活和统一的处理众多的方法。

相关文章

热门推荐