Android知识点17--Java的反射

82 阅读3分钟

Java的反射机制

是指在运行时检查和操作类、方法、字段等程序组件的能力。通过反射,可以动态地获取类的信息、调用方法、访问字段,而无需在编译时知道这些信息。Java的反射机制提供了一种灵活的方式来操作类和对象,使得程序能够在运行时进行动态的操作和处理。

Java的反射机制主要基于java.lang.reflect包中的类和接口。一些常用的反射类包括:

  1. Class类:代表一个类或接口,在运行时可以用来获取类的信息,如类名、父类、实现的接口、字段、方法等。
  2. Method类:代表类的方法,可以通过Method对象调用类的方法。
  3. Field类:代表类的字段,可以通过Field对象访问和修改类的字段。
  4. Constructor类:代表类的构造函数,可以通过Constructor对象实例化类的对象。

通过这些反射类,可以实现以下功能:

  1. 动态加载类:在运行时根据类名动态加载类,创建类的实例。
  2. 调用方法:通过Method对象调用类的方法,包括公有方法、私有方法、静态方法等。
  3. 访问字段:通过Field对象访问和修改类的字段,包括公有字段、私有字段等。
  4. 处理注解:通过反射可以获取类、方法、字段上的注解信息,实现基于注解的编程。

三种获取Class对象的方式

   // 第一种, 使用ClassLoader装在类,并对类进行初始化
   Class c1= Class.forName("Test");
   Object t1 = c1.newInstance();
   System.out.println(((Test)t1).getString());

   // 第二种,返回类对象运行时真正所指的对象、所属类型的Class对象
   Class c2 = new Test().getClass();
   Object t2 = c2.newInstance();
   System.out.println(((Test)t2).getString());


   // 第三种,ClassLoader装入内存,不对类进行类的初始化
   Class c3 = Test.class;
   Object t3 = c3.newInstance();
   System.out.println(((Test)t3).getString());


   // 有参数的构造
   Constructor<?> csr = c1.getDeclaredConstructor(String.class, int.class);
   Object o1 = csr.newInstance("lpf",18);

   // 反射类中的属性
   // getField : 只能获取public的,包括从父类继承来的字段
   // getDeclaredField: 可以获取本类所有的字段,包括private以及继承来的字段
   Field field = c1.getDeclaredField("name");
   // 使用setAccessible取消Java的权限控制检查,特别是可以取消私有字段访问限制
   // public 和 private修饰的属性,默认accessible属性都为false
   field.setAccessible(true);
   field.set(t1, "lpf");
   System.out.println(((Test) t1).getName());

   // 修改属性中的修饰符
   Field field2 = c1.getDeclaredField("name");
   String priv = Modifier.toString(field2.getModifiers());
   System.out.println("打印属性修饰符" + priv);

   // 反射类中的方法
   Method m = c1.getDeclaredMethod("setName",String.class);
   m.invoke(o1, "new invoke name");
   System.out.println("打印setName后的结果"+((Test)o1).getName());

   // 反射静态方法
   Class clz = Class.forName("Test");
   Method m2 = clz.getDeclaredMethod("getStaticMethod");
   m2.invoke(null);

   // 反射泛型参数方法
   Class clzT = TestT.class;
   // 方法中有泛型参数时,编译器会自动类型向上转型,T 向上转型是Object
   Method m3 = clzT.getDeclaredMethod("test", Object.class);
   m3.setAccessible(true);
   m3.invoke(new TestT<Integer>(),1);

动态代理的作用?

在不改变代码的情况下,增加一些方法,在方法执行前后做一些事情

   
   // 定义接口
   public interface Subject {
       void doSomething();
   }

   // 具体实现类
   public class RealSubject implements Subject{
       @Override
       public void doSomething() {
           System.out.println("Real Subject do something");
       }
   }

   // 代理类
   public class ProxyHandler implements InvocationHandler {

       private Object realSubject;

       public ProxyHandler(Object realSubject) {
           this.realSubject = realSubject;
       }

       @Override
       public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

           // 在调用具体目标对象前,可以执行一些具体处理
           System.out.println("执行具体对象前...");
           Object result = method.invoke(realSubject, args);
           System.out.println("执行具体对象后...");
           return result;
       }
   }

   // 执行
    public static void main(String[] args) {
       RealSubject real = new RealSubject();
       Subject proxySubject = (Subject) Proxy.newProxyInstance(
               Subject.class.getClassLoader(),
               new Class[]{Subject.class},
               new ProxyHandler(real));
       proxySubject.doSomething();
   }