欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

反射学习笔记

程序员文章站 2024-03-23 14:16:52
...

title: 反射学习笔记
date: 2020-01-01 12:08:14
tags:
categories:


概述

定义

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

功能

  1. 运行时判断任意一个对象所属的类

  2. 运行时构造任一个类的对象

  3. 运行时判断任意一个类的成员变量和方法

  4. 运行时调用任意一个对象的成员变量和方法

  5. 动态代理(反射的关键应用)

主要API

类名 用途
Class类 代表类的实体,在运行的Java应用程序中表示类和接口
Field类 代表类的成员变量(成员变量也称为类的属性)
Method类 代表类的方法
Constructor类 代表类的构造的构造方法

Class类

在Object类中定义了getClass()方法,这个方法被所有子类继承

public final Class getClass()

实例化Class类对象的四种方法

  1. 通过类名创建
 Class clazz = String.class;
  1. 通过实例创建
  Class clazz = "www.xyz.com".getClass(); //通过String对象创建
  1. 通过类的全类名创建
 Class clazz = Class.forName("java.lang.String");
  1. 通过类加载器创建
   ClassLoader cl = this.getClass().getClassLoader();
   Class clazz = cl.loadClass("全类名");

Class对象的常见方法

类相关:

方法 用途
getName() 获得类的完整路径名字
getSimpleName() 获得类的名字
getSuperclass() 获得当前类继承的父类的名字
getInterfaces() 获得当前类实现的类或是接口
newInstance() 创建类的实例,无参,返回Object,需要强转

如果需要创建一个有参实例,先获取有参的构造函数,在通过newIntsance()创建;

构造器相关:

方法 用途
getConstructors() 获得该类的所有公有构造方法
getConstructor(Class…<?> parameterTypes) 获得该类中与参数类型匹配的公有构造方法
getDeclaredConstructors() 获得该类所有构造方法
getDeclaredConstructor(Class…<?> parameterTypes) 获得该类中与参数类型匹配的构造方法

通过反射机制,强制调用私有构造函数创建对象

Constructor c = clazz.getDeclaredConstructors(String.class);
c.setAccessible(true);//解除私有封装
Object ob = c.newInstance("Hello");

方法相关:

方法 用途
getDeclaredMethods() 返回此Class对象所表示的类或接口的全部方法
getMethods() 返回此Class对象所表示的类或接口的public方法

通过反射调用特定方法

Method m = clazz.getMethod(name,params);
m.invoke(obj,args);//obj是实例化的对象,args是实参

如果需要调用一个私有方法需要加上

m.setAccessible(true);

调用有返回值的方法

Method m = clazz.getMethod(name,params);
Object c =m.invoke(obj,args);

属性相关:

方法 用途
getFields() 返回此Class对象所表示的类或接口的public属性
getDelcaredFields() 返回此Class对象所表示的类或接口的全部Field

通过反射调用属性

Constructor con = clazz.getConstructor();
Student stu = (Student)con.newInstance();
Field f = clazz.getField("school");
f.set(stu,"第一中学"); //设置属性
String school = (String)f.get(stu); //获取属性

通过反射调用私有属性

Field f = clazz.getDeclaredField("privateField");
f.setAccessible(true); //解除私有封装
f.set(stu,"私有属性");
String field = (String)f.get(stu);

Constructor类

文档

Method类

文档

Field类

文档

public int getModifiers() 以整数形式返回此Field的修饰符

public Class<?> getType() 得到Field的属性类型

public String getName() 返回Field的名称

动态代理

考虑下需求:

某一开发人员,假设它会java和C++两种语言,但是由于这两种语言难度不同,所以他掉的头发也会不同。所以在他写代码之前,他都会祈祷让自己的头发少掉一点,所以如何在真正写代码前完成这样一个祈祷并告知发量的程序呢,利用动态代理即可。

先定义一个Java接口,表示码农

public interface Coder {
    void codeJava();
    void codeCPlusPlus();
}

然后写出该接口的一个实现类,表示某一个具体的码农

public class Developer implements Coder {
    @Override
    public void codeJava() {
        System.out.println("System.out.println(\"Hello,World\");");
    }

    @Override
    public void codeCPlusPlus() {
        System.out.println("cout << \"Hello, world!\";");
    }
}

然后插入动态代理,在执行方法前,完成告知发量状况

public class Coding {
    public static void main(String[] args) {
        Developer zhong = new Developer();

        /**
         * 匿名类实现
         */
        Coder zhongProxy = (Coder)Proxy.newProxyInstance(zhong.getClass().getClassLoader(),zhong.getClass().getInterfaces(),
                ((proxy, method, args1) -> {
                    if(method.getName().equals("codeJava")){
                        System.out.println("coding Java...Hair reduce 30%");
                    }else if (method.getName().equals("codeCPlusPlus")){
                        System.out.println("coding C++...Hair reduce 60%");
                    }
                    Object result = method.invoke(zhong, args);
                    System.out.println("coding done!");
                    return result;
                }));
        zhongProxy.codeJava();

        System.out.println("=========================================================================");

}

执行结果:

coding Java...Hair reduce 30%
System.out.println("Hello,World");
coding done!

上述这种方式采用了匿名类实现,更加简洁,如果喜欢麻烦,可以使用下面这种方式

创建码农代理类

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

public class DevelopProxy implements InvocationHandler {

    private Object object;

    public DevelopProxy(Object object){
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if(method.getName().equals("codeJava")){
            System.out.println("coding Java...Hair reduce 30%");
        }
        if(method.getName().equals("codeCPlusPlus")){
            System.out.println("coding C++...Hair reduce 60%");
        }
        Object result = method.invoke(object, args);
        System.out.println("coding done!");
        return result;
    }
}

同样,在main方法中调用Proxy.newInstance即可

public class Coding {
    public static void main(String[] args) {
        Developer zhong = new Developer();
        /**
         * 老老实实写接口类实现
         */

        zhongProxy = (Coder)Proxy.newProxyInstance(zhong.getClass().getClassLoader(),zhong.getClass().getInterfaces(),new DevelopProxy(zhong));
        zhongProxy.codeCPlusPlus();
    }

}

执行结果:

coding C++…Hair reduce 60%
cout << “Hello, world!”;
coding done!

相关标签: JAVA