反射

Class类

反射的使用
package com.ReflectionTest.common;

import org.junit.Test;

import java.lang.annotation.ElementType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/** @author Chen */
public class ReflectionTest {

  // 反射之前,对Person的操作
  @Test
  public void test() {
    // 1、创建Person类的对象
    Person p1 = new Person("name", 12);
    // 2、通过对象,调用其内部的属性、方法
    p1.age = 10;
    System.out.println(p1.toString());
    p1.show();

    // 在Person类外部,不可以通过Person类的对象调用其内部私有结构
    // 比如:name、showNation()以及私有的构造器
  }

  // 反射之后,对Person的操作
  @Test
  public void test1()
      throws IllegalAccessException, InvocationTargetException, InstantiationException,
          NoSuchMethodException, NoSuchFieldException {
    Class<Person> clazz = Person.class;
    // 1、通过反射,创建Person类的对象
    // clazz.getConstructor
    Constructor<Person> constructor = clazz.getConstructor(String.class, int.class);
    Person person = constructor.newInstance("chen", 25);
    System.out.println(person);
    // 2、通过反射,调用对象指定的属性、方法
    // 调用属性:clazz.getDeclaredField
    Field age = clazz.getDeclaredField("age");
    age.set(person, 27);
    System.out.println(person.toString());
    // 调用方法:clazz.getDeclaredMethod
    Method show = clazz.getDeclaredMethod("show");
    show.invoke(person);
    System.out.println("**************");

    // 通过反射,可以调用Person类的私有结构的。比如:私有的构造器、方法、属性
    // 调用私有构造器
    Constructor<Person> declaredConstructor = clazz.getDeclaredConstructor(String.class);
    declaredConstructor.setAccessible(true);
    Person person1 = declaredConstructor.newInstance("Jerry");
    System.out.println(person1);
    // 调用私有属性
    Field name = clazz.getDeclaredField("name");
    name.setAccessible(true);
    name.set(person1, "cheng");
    System.out.println(person1);
    // 调用私有方法
    Method showNation = clazz.getDeclaredMethod("showNation", String.class);
    showNation.setAccessible(true);
    // 相当于person1,。showNation("中国")
    String nation = (String) showNation.invoke(person1, "中国");
    System.out.println(nation);
  }
  // 疑问1:通过直接new的方式或反射的方式都可以调用公共的结构,开发中到底使用哪种?
  // 建议:直接new方式
  // 什么时候会使用反射的方式。反射的特征:动态性
  // 疑问2:反射机制与面向对象中的封装性是不是矛盾?如何看待两个技术
  // 不矛盾
  /*
   关于java.lang.Class类的理解
   1.类的加载过程:
     程序经过javac.exe命令之后,会生成一个或多个字节码文件(.class结尾)
     接着我们使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件
     加载到内存中。此过程就称为类的加载。加载到内存中的类,我们就称为运行时类,
     此运行时类,就作为Class的一个实例
   2.换句话说,Class的实例就对应着一个运行时类。
   3.加载到内存中的运行时类,会缓存一定的时间。在此时间之内,我们可以通过不同的方式
     获取此运行时类。
  */

  // 获取Class的实例的方式(前三种方式需要掌握)
  @Test
  public void test2() throws ClassNotFoundException {
    // 方式一:调用运行时类的属性:.class
    Class<Person> aClass = Person.class;
    System.out.println(aClass);
    // 方式二:通过运行时类的对象
    Person p1 = new Person();
    Class<? extends Person> aClass1 = p1.getClass();
    System.out.println(aClass1);
    // 方式三:调用Class的静态方法:forName(String classPath)
    Class<?> aClass2 = Class.forName("com.ReflectionTest.common.Person");
    System.out.println(aClass2);

    System.out.println(aClass == aClass1);
    System.out.println(aClass == aClass2);

    // 方式四:使用类的加载器:ClassLoader
    ClassLoader classLoader = ReflectionTest.class.getClassLoader();
    Class<?> aClass3 = classLoader.loadClass("com.ReflectionTest.common.Person");
    System.out.println(aClass3);
    System.out.println(aClass == aClass3);
  }

  // Class实例可以是哪些结构的说明
  @Test
  public void test3() {
    Class c1 = Object.class;
    Class c2 = Comparable.class;
    Class c3 = String[].class;
    Class c4 = int[][].class;
    Class c5 = ElementType.class;
    Class c6 = Override.class;
    Class c7 = int.class;
    Class c8 = void.class;
    Class c9 = Class.class;

    int[] a = new int[10];
    int[] b = new int[100];
    Class c10 = a.getClass();
    Class c11 = b.getClass();

    // 只要数组的元素类型与维度一样,就是同一个Class
    System.out.println(c10 == c11);
  }
}


创建运行时类的对象
创建运行时类的对象
package com.ReflectionTest.common;

import org.junit.Test;

import java.util.Random;

/**
 * 通过反射创建对应的运行时类的对象
 *
 * @author Chen
 */
public class NewInstanceTest {
  @Test
  public void test() throws IllegalAccessException, InstantiationException {
    Class<Person> personClass = Person.class;
    /*
       newInstance():调用此方法,创建对应的运行时类的对象。
                     内部调用了运行时类的空参的构造器
    */
    Person person = personClass.newInstance();
    System.out.println(person);
  }

  /*
   体会反射的动态性
  */
  @Test
  public void test1() {
    int num = new Random().nextInt(3); // 0,1,2
    String classPath = "";
    switch (num) {
      case 0:
        classPath = "java.util.Date";
        break;
      case 1:
        classPath = "java.lang.Object";
        break;
      default:
        classPath = "com.ReflectionTest.common.Person";
        break;
    }
    try {
      Object instance = getInstance(classPath);
      System.out.println(instance);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  /*
     创建一个指定类的对象
     classPath:指定类的全名
  */
  public Object getInstance(String classPath) throws Exception {
    Class<?> aClass = Class.forName(classPath);
    return aClass.newInstance();
  }
}


获取运行时类的完整结构
获取当前运行时类的属性结构
package com.ReflectionTest.ClassTest1;

import com.ReflectionTest.ClassTest.Person;
import org.junit.Test;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

/**
 * 获取当前运行时类的属性结构
 *
 * @author Chen
 */
public class FieldTest {
  @Test
  public void test() {
    Class<Person> personClass = Person.class;

    // 获取属性结构
    // getFields():获取当前运行时类及其父类中声明为public访问权限的属性
    Field[] fields = personClass.getFields();
    for (Field f : fields) {
      System.out.println(f);
    }

    // getDeclaredFields():获取当前运行时类中声明的所有属性
    Field[] declaredFields = personClass.getDeclaredFields();
    for (Field f : declaredFields) {
      System.out.println(f);
    }
  }

  // 权限修饰符 数据类型 变量名
  @Test
  public void test1() {
    Class<Person> personClass = Person.class;
    Field[] declaredFields = personClass.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();
    }
  }
}

获取当前运行时类的方法
package com.ReflectionTest.ClassTest1;

import com.ReflectionTest.ClassTest.Person;
import org.junit.Test;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/**
 * 获取当前运行时类的方法
 *
 * @author Chen
 */
public class MethodTest {
  @Test
  public void test() {
    Class<Person> personClass = Person.class;

    // getMethods():获取当前运行时类及其所有父类中声明为public权限的方法
    Method[] methods = personClass.getMethods();
    for (Method m : methods) {
      System.out.println(m);
    }
    System.out.println();

    // getDeclaredMethods():获取当前运行时类中声明的所有方法,不包含父类
    Method[] declaredMethods = personClass.getDeclaredMethods();
    for (Method m : declaredMethods) {
      System.out.println(m);
    }
    System.out.println();
  }

  /*
   @Xxxx
   权限修饰符 返回值类型 方法名(参数类型1 形参名1,···) throws XxxException{}
  */
  @Test
  public void test1() {
    Class<Person> personClass = Person.class;
    Method[] declaredMethods = personClass.getDeclaredMethods();
    for (Method m : declaredMethods) {
      // 1.获取方法声明的注解
      Annotation[] annotations = m.getAnnotations();
      for (Annotation a : annotations) {
        System.out.println(a);
      }

      // 2.权限修饰符
      System.out.print(Modifier.toString(m.getModifiers()) + "\t");

      // 3.返回类型
      Class<?> returnType = m.getReturnType();
      System.out.print(returnType.getName() + "\t");

      // 4.方法名
      System.out.print(m.getName() + "\t");

      // 5.形参列表
      System.out.print("(");
      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 == parameterTypes.length - 1) {
            System.out.print(exceptionTypes[i].getName());
            break;
          }
          System.out.print(exceptionTypes[i].getName() + ",");
        }
      }

      System.out.println();
    }
  }
}

输出
public	int	compareTo	(java.lang.String args_0)
public volatile	int	compareTo	(java.lang.Object args_0)
public	void	info	()
@com.ReflectionTest.ClassTest.MyAnnotation(value=nation)
private	java.lang.String	show	(java.lang.String args_0)
public	java.lang.String	display	(java.lang.String args_0,int args_1) throws java.lang.NullPointerException,java.lang.ClassCastException

Process finished with exit code 0

获取运行时类的构造器和父类
package com.ReflectionTest.ClassTest1;

import com.ReflectionTest.ClassTest.Person;
import org.junit.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Type;

/** @author Chen */
public class OtherTest {
  /*
     获取构造器
  */
  @Test
  public void test() {
    Class<Person> personClass = Person.class;
    // getConstructors():获取当前运行时类中声明为public的构造器
    Constructor<?>[] constructors = personClass.getConstructors();
    for (Constructor c : constructors) {
      System.out.println(c);
    }

    System.out.println();

    // getDeclaredConstructors():获取当前运行时类中声明的所有构造器
    Constructor<?>[] declaredConstructors = personClass.getDeclaredConstructors();
    for (Constructor c : declaredConstructors) {
      System.out.println(c);
    }
  }

  // 获取运行时类的父类
  @Test
  public void test1() {
    Class<Person> personClass = Person.class;
    Class<? super Person> superclass = personClass.getSuperclass();
    System.out.println(superclass);
  }

  // 获取运行时类的带泛型的父类
  @Test
  public void test2() {
    Class<Person> personClass = Person.class;
    Type genericSuperclass = personClass.getGenericSuperclass();
    System.out.println(genericSuperclass);
  }
}


调用运行时类的指定结构
调用运行时类的指定结构
package com.ReflectionTest.ClassTest1;

import com.ReflectionTest.ClassTest.Person;
import org.junit.Test;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * 调用运行时类的指定结构
 *
 * @author Chen
 */
public class ReflectionTest {
  @Test
  public void test() throws Exception {
    Class<Person> personClass = Person.class;

    // 创建运行时类的对象
    Person person = personClass.newInstance();

    // 获取指定的属性
    // 不建议此方法
    Field id = personClass.getField("id");

    // 设置当前属性的值
    id.set(person, 12345);

    // 获取当前属性的值
    int personId = (int) id.get(person);
    System.out.println(personId);
  }

  /*
   如何获取运行时类中的指定属性 ---掌握
  */
  // 建议方法
  @Test
  public void testField() throws Exception {
    Class<Person> personClass = Person.class;

    // 创建运行时类的对象
    Person person = personClass.newInstance();

    // 获取指定的属性
    // 建议此方法
    Field name = personClass.getDeclaredField("name");

    // 以上代码已经代表拿到该属性,但是该属性是private,没有权限,需要修改
    name.setAccessible(true);

    // 设置当前属性的值
    name.set(person, "chen");

    // 获取当前属性的值
    Object o = name.get(person);
    System.out.println(o);
  }

  /*
   如何获取运行时类中的指定方法 ---掌握
  */
  // 建议方法
  @Test
  public void testMethod() throws Exception {
    Class<Person> personClass = Person.class;

    // 创建运行时类的对象
    Person person = personClass.newInstance();

    // 获取指定的某个方法
    // getDeclaredMethod():参数1,方法名称  参数2,参数列表(由于重载)
    Method show = personClass.getDeclaredMethod("show", String.class);
    show.setAccessible(true);
    Object invoke = show.invoke(person, "CHN");
    // invoke的返回值即为show的返回值
    System.out.println(invoke);

    System.out.println("********如何调用静态方法********");

    // private static void showDesc()
    Method showDesc = personClass.getDeclaredMethod("showDesc");
    showDesc.setAccessible(true);
    showDesc.invoke(person);
  }
}

反射的应用:动态代理
动态代理的举例
package com.szu.java;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 动态代理的举例
 *
 * @author Chen
 */
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("我喜欢吃" + food);
  }
}

/*
   要想实现动态代理,需要解决的问题?
   问题一:如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象。
   问题二:当通过代理类的对象调用方法a时,如何动态的去调用被代理类中的同名方法a。
*/

class ProxyFactory {
  // 调用此方法,返回一个代理类的对象。解决问题一。
  public static Object getProxyInstance(Object obj) { // obj:表示 被代理类 的对象
    MyInvocationHandler handler = new MyInvocationHandler();
    handler.bind(obj);
    return Proxy.newProxyInstance(
        obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), handler);
  }
}

class MyInvocationHandler 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);
    return returnValue;
  }
}

public class ProxyTest {

  public static void main(String[] args) {
    // superMan:被代理类
    SuperMan superMan = new SuperMan();
    // proxyInstance:代理类的对象
    Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);
    // 使用代理类对象进行操作
    proxyInstance.getBelief();
    proxyInstance.eat("面包");

    System.out.println("********动态性***********");

    // 被代理类
    NikeClothFactory nikeClothFactory = new NikeClothFactory();
    // 代理类
    ClothFactory proxyClothFactory = (ClothFactory) ProxyFactory.getProxyInstance(nikeClothFactory);
    // 操作
    proxyClothFactory.produceCloth();
  }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值