JAVA-反射基础

本文详细介绍了Java反射机制的概念、Class对象的获取方式及其区别,并通过具体示例展示了如何使用反射来获取构造函数、属性和方法。

一、反射的定义

反射机制是指在程序的运行状态中,可以构造任意类的对象,了解任意对象所属的类,了解任意类的成员变量和方法,可以调用任意对象的属性和方法。

即,对类和实例化对象可以动态进行以下操作:

  • 1、通过类构造实例化对象
    2、通过类读取类包含的属性方法
    3、通过实例化对象获取类的信息
    4、通过实例化对象操作对象的所有属性和方法
    这么方便的操作,为什么在日常编码中很少直接使用呢,反射有如下问题:

1、性能差,反射是一种解释性操作,直接通知JVM进行的操作,无法进行代码优化,比直接使用类和实例化对象要慢的多。

2、安全问题,通过反射可以执行实例化对象所有的属性方法,包括private的方法,会引起一些安全错误

3、可读维护性差,使用反射相对直接调用,不能直观的看到调用的属性方法,出问题了,代码的可读、调试和维护性会很差

4、抽象性,对象改变了,通过反射逻辑可能无法感知,引起一些莫名的错误

二、Class的获取

反射的第一步需要获取Class对象,怎么获取呢

首先构建一个pojo对象Person作为例子


public class Cat {
    static {
        log.info("I am cat");
    }

    public Cat (String name){this.name=name;}
    public Cat (){}
    public int id;
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }


    public void show()
    {
        log.info("this cat show");
    }
}

1、实例化对象获取Class对象

Cat cat= new Cat ();
Class cl1 = Cat .getClass();

2、类获取Class对象

Class cl2 = cat .class;

3、使用class.forName根据类的全名获取

Class cl3 = Class.forName("");

4、使用类加载器获取

Class cl4 = ClassLoader.getSystemClassLoader().loadClass("");

forName和loadClass的区别

  • 类的加载过程包括以下步骤:加载、连接(连接过程暂不细分)、初始化

  • forName默认是进行到初始化,loadClass进行到连接这一步
    即,loadClass只把类加载到了jvm中,forName加载并完成了初始化

在Person这个类中有一块代码

static {
    System.out.println("i am Cat ");
}

这个是在初始化阶段执行的,试下两个方法是否有这个日志打印

如果forName不想走初始化过程,可以使用

public static Class<?> forName(String name, boolean initialize, ClassLoader loader) 

这个方法加载,将initialize设置为false即可

三、反射的使用

1、构造函数的获取和使用

先获取构造函数

Class cl = Cat .class;
String pStr = "";

Constructor[] cs = cl.getConstructors();
for (Constructor c : cs) {
    Parameter[] ps = c.getParameters();
    pStr = "";
    for (Parameter p : ps) {
        pStr += p.getType().getSimpleName() + " " + p.getName() + ",";
    }
    log.info(String.format("%s (%s)", c.getName(), pStr));
}

获取指定构造函数


Constructor sc = cl.getConstructor(String.class);
Parameter[] ps = sc.getParameters();
pStr = "mhf";
for (Parameter p : ps) {
    pStr += p.getType().getSimpleName() + " " + p.getName() + ",";
}
log.info(String.format("%s (%s)", sc.getName(), pStr));

使用构造函数实例化对象


Constructor sc1 = cl.getConstructor(String.class);
Person person1 = (Person) sc1.newInstance("");
log.info(person1.getName());

2、属性的获取和使用

获取属性的方法有两个getFields只能获取public修饰的属性,如下


Field[] fs = cl.getFields();
for (Field f : fs) {
    log.info(String.format("%s %s", f.getType().getSimpleName(), f.getName()));
}

获取所有属性的方法是getDeclaredFields


Field[] fs = cl.getDeclaredFields();
for(Field f : fs)
{
    log.info(String.format("%s %s",f.getType().getSimpleName(),f.getName()));
}

获取指定名称的属性


Field field = cl.getDeclaredField("name");
log.info(String.format("%s %s",field.getType().getSimpleName(),field.getName()));

获取和修改属性值


Person person1 = new Person();
person1.setName("mhf");
Field field = cl.getDeclaredField("name");
field.setAccessible(true);
log.info(field.get(person1).toString());
field.set(person1,"mg2020");
log.info(field.get(person1).toString());
注意 private的属性需要设置下field.setAccessible(true);否则抛异常。

3、方法的获取和使用

获取包括父类的所有方法


Method[] ms = cl.getMethods();
for (Method m : ms) {
    Parameter[] ps = m.getParameters();
    pStr = "";
    for (Parameter p : ps) {
        pStr += p.getType().getSimpleName() + " " + p.getName() + ",";
    }
    log.info(String.format("%s (%s)", m.getName(), pStr));
}

获取本类中定义的方法


Method[] ms = cl.getDeclaredMethods();
for (Method m : ms) {
    Parameter[] ps = m.getParameters();
    pStr = "";
    for (Parameter p : ps) {
        pStr += p.getType().getSimpleName() + " " + p.getName() + ",";
    }
    log.info(String.format("%s (%s)", m.getName(), pStr));
}

获取指定的方法


Method method = cl.getMethod("setName",String.class);
Parameter[] ps = method.getParameters();
pStr = "";
for (Parameter p : ps) {
    pStr += p.getType().getSimpleName() + " " + p.getName() + ",";
}
log.info(String.format("%s (%s)", method.getName(), pStr));

使用方法

{

    Method method = cl.getMethod("setName",String.class);
    method.invoke(cat 1,"mhf");
    log.info(cat .getName());
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值