(31)反射

Java反射机制概念

1,什么是反射?
      Reflection(反射):是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。

2,Java 反射机制提供的功能

①,在运行时判断任意一个对象所属的类

②,在运行时构造任意一个类的对象

③,在运行时判断任意一个类所具有的成员变量和方法

④,在运行时获取泛型信息

⑤,在运行时调用任意一个对象的成员变量和方法

⑥,在运行时处理注解

⑦,生成动态代理

3,获取Class实例的三种常见方式

Class clazz1 = String.class;
Class clazz2 = person.getClass();
Class clazz3 = Class.forName(String classpath)

4,反射的使用

@Test
//反射的使用
public void test01() throws Exception {
    Class clazz = Person.class;
    //1,通过反射,创建Person类的对象
    Constructor constructor = clazz.getConstructor(String.class, int.class);
    Object object = constructor.newInstance("Tommey,222");
    Person p = (Person)object;
    System.out.println(p.toString());
    
    //2,通过反射,调用对象指定的属性,方法
    Field age = clazz.getDeclaredField("age");
    age.set(p,10);
    System.out.println(p.toString());

    //调用方法
    Method show = clazz.getDeclaredMethod("show");
    show.invoke(p);

    //通过反射,可以调用Person类的私有结构的。比如:私有的构造器,方法,属性
    //调用私有的构造器
    Constructor constructor1 = clazz.getDeclaredConstructor(String.class);
    constructor1.setAccessible(true);
    Person p1 = (Person)constructor1.newInstance("Tom");
    
    //调用私有的属性
    Field name = clazz.getDeclaredField("name");
    name.setAccessible(true);
    name.set(p1, "a");
    
    //调用私有的方法
    Method showNation = clazz.getDeclaredMethod("showNation", String.class);
    showNation.setAccessible(true);
    showNation.invoke(p1,"中国");
}

类加载和ClassLoader的理解

1,关于java.lang.Class类的理解

①,类的加载过程

       程序经过javac.exe命令以后,会生成一个或多个字节码文件(.class结尾)。接着我们使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件加载到内存中。此过程就称为类的加载。加载到内存中的类,我们就称为运行时类,此运行时类,就作为Class的一个实例。

②,换句话说,Class的实例就对应着一个运行时类

③,加载到内存中的运行时类,会缓存一定的时间,在此时间之内,我们可以通过不同的方式来获取此运行时类

2,加载配置文件的两种方式

读取配置文件的方式一:

Properties pros = new Properties();
FileInputStream fis = new FileInputStream("jdbc.properties");
pros.load(fis);

读取配置文件的方式二:ClassLoader

ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
InputStream is = classLoader.getResourceAsStream("jdbc.properties");
pros.load(fis);

获取运行时类的完整结构

1,获取运行时类,方法,接口,泛型构造器中的应用

//getFields():获取当前运行时类及其父类中声明为public访问权限的属性
Class clazz = Person.class;
Field[] fields = clazz .getFields();
//getDeclaredFields():获取当前运行时类中声明的所有属性。(不包含父类中声明的属性)
Field[] declaredFields = clazz.getDeclaredFields();
getMethods():获取当前运行时类及其所有父类中声明为public权限的方法
getDeclaredMethods():获取当前运行时类中声明的所有方法。(不包含父类中声明的方法)
Field方法中:
  public int getModifiers() 以整数形式返回此Field的修饰符 --> Modifier.toString(modifier)
  public Class<?> getType() 得到Field的属性类型
  public String getName() 返回Field的名称
全部的方法:
   public Method[] getDeclaredMethods()返回此Class对象所表示的类或接口的全部方法
   public Method[] getMethods()返回此Class对象所表示的类或接口的public的方法
Method类中:
   public Class<?> getReturnType()取得全部的返回值
   public Class<?>[] getParameterTypes()取得全部的参数
   public int getModifiers()取得修饰符
   public Class<?>[] getExceptionTypes()取得异常信息
   //获取运行时类的带泛型的父类的泛型
   Type genericSuperclass = Person.class.getGenericSuperclass();
   ParameterizedType paramType = (ParameterizedType) genericSuperclass;
   //获取泛型类型
   Type[] actualTypeArguments = paramType.getActualTypeArguments();

   //获取运行时类实现的接口
   Class[] interfaces = clazz.getInterfaces();
   //获取运行时类的父类实现的接口
   Class[] interfaces1 = clazz.getSuperclass().getInterfaces();

2,调用运行时类中指定的结构:属性,方法/font>

属性:

  //创建运行时类的对象
  Person p = (Person)clazz.newInstance();
  //1,getDeclaredField(String fieldName):获取运行时类中指定变量名的属性
  Field name = clazz.getDeclaredField("name");
  //获取指定的属性:要求运行时类中属性声明为public,不理想,要求属性权限太高
  Field id = clazz.getField("id");
  id.set(p,1000);
  //2,保证当前属性是可访问的
  name.setAccessible(true);
  //3,获取,设置指定对象的此属性值
  name.set(p, "Tommey");

方法:

  //1,获取指定的某个方法getDeclaredMethod():参数1:指明获取的方法的名称 参数2:指明获取的方法形参列表
  Method show = clazz.getDeclaredMethod("show", String.class);
  show.setAccessible(true);
  //2,调用方法invoke():参数1:方法的调用者 参数2:给方法形参赋值的实参,invoke()的返回值即为对应类中调用的方法的返回值
  Object returnValue = show.invoke(p, "CHN");
  //调用静态方法
  Method showDesc = clazz.getDeclaredMethod("showDesc");
  showDesc.setAccessible(true);
  Object returnVal = showDesc.invoke(Person.class);

反射的应用动态代理

1,代理理设计模式的原理:
      使用一个代理将对象包装起来, 然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。

2,静态代理举例:

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();
    }
}

3,动态代理举例:

要想实现动态代理需要解决的问题?

  • 问题一:如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象(通过Proxy.newProxyInstance()来实现)

  • 问题二:当通过代理类的对象调用方法时,如何动态的去调用被代理类中的同方法名(通过InvocationHandler接口的实现类及其方法invoke())

interface Human{

    String getBelief();
    void eat(String food);
}

class SuperMan implements Human{

    @Override
    public String getBelief() {
        return "他有一个喜欢的人!";
    }

    @Override
    public void eat(String food) {
        System.out.println("她喜欢吃"+food);
    }
}

class ProxyFactory{
    //调用此方法,返回一个代理类的对象。解决问题一
    public static Object getProxInstance(Object 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:被代理类的对象
        return method.invoke(obj,args);
    }
}

public class ProxyTest {

    public static void main(String[] args) {
        SuperMan superMan = new SuperMan();
        //proxyInstance:代理类的对象
        Human proxyInstance = (Human) ProxyFactory.getProxInstance(superMan);
        String belief = proxyInstance.getBelief();
        System.out.println(belief);

        proxyInstance.eat("东坡肉");
    }
}
发布了67 篇原创文章 · 获赞 19 · 访问量 9868

猜你喜欢

转载自blog.csdn.net/qq_41530004/article/details/104367122
31
31)