java学习笔记-反射(1)-Class

慢慢来比较快,虚心学技术

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

同文链接:https://www.jianshu.com/p/9a456d5b2b79 

 反射

反射的概念(是什么):

java中的反射------相当于对象的镜子,对象在照镜子时可以获取自身的信息,比如:属性,方法和构造器,实现接口等,而且这面镜子还可以直接调用执行java对象的方法

反射的用处(有什么用):

1.当接收到别人传过来的类时,可以进行解析

2.当只有类名时,可以获取到对象的完整信息,从而执行相应处理

多用于可配置和动态代理

java反射涉及的几个类:

java.lang. Class :反射的核心类,可以获取类的属性,方法等信息

java.lang.ClassLoader:类的加载器,用来把类(class)装载进 JVM 

java.lang.reflect.Field :类的成员变量,用来获取和设置类的属性

java.lang.reflect.Method:类的方法,用来获取类中方法的信息或调用类的方法

java.lang.reflect.Modifier:类的修饰符工具,可以用来判断类中属性或者方法的修饰级别

 

为方便后续学习,事先创建一个基本类

public class BaseEntity {

    private String name;

    private Integer age;
    
    public BaseEntity(){
        super();
    }


    public BaseEntity(String name,Integer age){
        super();
        this.name = name;
        this.age = age;
    }

    private void addAge(String name,Integer age){
        if(this.name.equals(name)){
            this.age+=age;
        }else{
            System.out.println("名称不符,请核验");
        }
    }

}

Class类

class是一个用来描述类的类,封装了当前对象所对应的类信息,我们可以通过该类获取目标对象的属性,方法等信息,还可以根据class类创建目标对象实例

获取Class类 

1.通过类名获取 : 类名.class

Class clazz = BaseEntity.class;

2. 通过类全类名获取:Class.forName(全类名)--这种方式一般在开发中用的比较多,多为配置项获取实例,如最简单的JDBC获取驱动方式

Class clazz =Class.forName("com.java.entity.BaseEntity");

3.通过对象实例获取

BaseEntity baseEntity = new BaseEntity("test",50);

Class clazz = baseEntity.getClass();

获取父类Class

Class clazz = Class.forName("com.java.entity.BaseEntity");

Class personClazz = sonClazz.getSuperclass();

 创建目标对象实例

Object newObject = clazz.newInstance();

类的字段Field

通过class类获取目标对象的字段对象,获取到字段对象后可以对具体对象的属性值进行读取和设置操作

获取字段列表:

//获取基本公共字段(无法获取保护字段和父类字段)
Field[] fields = clazz.getFields();  //结果是null,因为BaseEntity没有public字段

 //获取所有字段(无法获取父类字段)
fields = clazz.getDeclaredFields();  //结果是name和age的对应字段对象

 获取指定字段

一般使用getDeclaredField方法获取,两种方法找不到对应字段时都会抛NoSuchFieldException异常

方法结构如下:

Field getField(字段名);

Field getDeclaredField(字段名) ;

//getField()---只能获取到公共字段
Field field = clazz.getField("name");

//getDeclaredField()----可以获取到指定字段,不管是否保护字段
Field field = clazz.getDeclaredField("name");

 设置对象对应字段的值field.set(Object obj,Object value)

 方法结构如下:

void set(实例对象,字段值)

如果是保护字段,无论读取还是修改属性内容,都需要先setAccessible(true)方可操作

//如果是保护字段,无论读取还是修改属性内容,都需要先setAccessible(true)方可操作
field.setAccessible(true);

//设置属性值
field.set(baseEntity,"base");

 获取对象对应字段的值field.get(Object obj)

//如果是保护字段,无论读取还是修改属性内容,都需要先setAccessible(true)方可操作
field.setAccessible(true);

//获取实例baseEntity对应属性的属性值(此处获取的是name的值)
field.get(baseEntity);        //-----------得到结果为base

类的方法Method

通过class类获取目标对象的方法对象,获取到方法对象后可以对具体对象的方法进行调用和方法

获取方法列表

两种方法获取都不能够获取到父类的方法,只能通过获取父类Class来简介获取父类方法

//获取公共方法列表,无法获取保护方法
Method[] methods = clazz.getMethods();

//获取全部方法列表
Method[] methods = clazz.getDeclaredMethods();

获取指定方法 

两种方法的区别和获取指定对象的区别一致,方法内的参数结构如下:

Method getMethod("方法名",方法参数类型列表)

Method getDeclaredMethod("方法名",方法参数类型列表)

//获取BaseEntity的addAge方法对象
Method method = clazz.getMethod("addAge",String.class,Integer.class);


Method method = clazz.getDeclaredMethod("addAge",String.class,Integer.class);

执行指定方法  invoke(Object obj, Object... args)

反射执行指定方法是框架中用的比较普遍的用法,方法结构如下:

Object invoke(具体实例对象, 参数值列表)

如果是保护方法,执行方法前都需要先setAccessible(true)方可操作

method.setAccessible(true);

//执行调用baseEntity的addAge方法,传入参数name和age的值
method.invoke(baseEntity, "base", 12);

//之后再获取baseEntity的age值看一下结果:
Field field = clazz.getDeclaredField("age");

field.setAccessible(true);
field.get(baseEntity,"age");//---------------得到结果:50+12= 62,方法执行正确

类的修饰符工具Modifier

如上所述,方法和属性字段都有保护和公共之分,那么如何判断一个方法或者属性是否公共呢?java反射提供了Modifier工具类,该工具类对类和成员访问修饰符进行解码,通过判断类和成员修饰符的整数编码,判定类和成员是否保护以及修饰符类型

 Modifier类将修饰符作为整数编码代号,具体部分常量如下:

public static final int PUBLIC  = 0x00000001;
public static final int PRIVATE  = 0x00000002;
public static final int PROTECTED  = 0x00000004;
public static final int STATIC  = 0x00000008;
public static final int FINAL  = 0x00000010;
public static final int SYNCHRONIZED  = 0x00000020;

Modifier工具类提供如下静态方法判断类和成员的修饰符:

Modifier.isPublic(int mod)
Modifier.isPrivate(int mod)
Modifier.isProtected(int mod)
Modifier.isStatic(int mod)
Modifier.isFinal(int mod)
Modifier.isSynchronized(int mod)

 所以,我们可以通过调用Modifier工具类的方法来判断我们的方法或者属性字段是否公共字段/方法,其中,可以使用field.getModifiers(),method.getModifiers()获取字段或方法修饰符的对应编码值

//判断field是否公共字段
if(!Modifier.isPublic(field.getModifiers())){
     field.setAccessible(true);
}

field.set(baseEntity,50);

综合使用-动态执行方法(通过传入全类名,通过传入具体对象)

①依旧使用BaseEntity作为基本类操作

②创建ClassUtil类,作为工具类

public class ClassUtil {
    
    /**
     * 执行方法
     *
     * @param className 目标class名称
     * @param methodName 目标方法名称
     * @param args 执行目标方法所需要的参数值
     * @return java.lang.Object 执行目标方法后的返回值
     *
     * @author *** 2019/2/15
     * @version 1.0
     **/
    public static Object invoke(String className,String methodName,Object ...args){
        Class clazz = null;
        Class[] parementerType = new Class[args.length];

        try {
            //通过传入的class路径反射class
            clazz = Class.forName(className);

            for(int i=0;i

 ③综合测试

//传入全类名调用方法
ClassUtil.invoke("com.java.entity.BaseEntity","setAge",123);

//传入具体对象调用方法
BaseEntity baseEntity = new BaseEntity();
ClassUtil.invoke(baseEntity,"setAge",123);
System.out.println(baseEntity.getAge());

总结

1.java反射-对象在照镜子时可以获取自身的信息,比如:属性,方法和构造器,实现接口等,而且这面镜子还可以直接调用执行java对象的方法

2.java反射的主要类为Class,ClassLoader,Field,Method,Modifier

3.Class类是一个用来描述类的类,封装了当前对象所对应的类信息,我们可以通过该类获取目标对象的属性,方法等信息,还可以根据class类创建目标对象实例

4.Field类,通过class类获取目标对象的字段对象,获取到字段对象后可以对具体对象的属性值进行读取和设置操作。对于保护的字段的读取和更改,需要先调用setAccessible(true)方法。

5.Method类,通过class类获取目标对象的方法对象,获取到方法对象后可以对具体对象的方法进行调用和方法。对于保护的方法执行,需要先调用setAccessible(true)方法。

6.java反射提供了一个专门封装了类和类的成员修饰符的工具类Modifier,用于判断类与类的成员的修饰符。其底层使用的是修饰符整数编码,本人认为与日志级别的设计思想一致,值得学习

参考文档

【1】java编程思想

【2】https://www.cnblogs.com/tech-bird/p/3525336.html

你可能感兴趣的:(java)