java利用反射分析类,并且创建对象

java利用反射分析类,并且创建对象,第1张

反射的定义

能够分析类能力的程序称为反射,反射的本质就是为了获取类信息。

在某些时刻,无法通过new来实例化对象,比如tomcat,这个时候就需要反射通过代码来获取类信息,并且无需new来生成对象。

反射获取类信息的三种方式

通过类:类.class

通过对象:对象.getClass();

通过路径:class.forName(里面传的是类的路径)

利用反射分析类的能力

java.lang.reflect 包中有三个类 Field、Method 和 Constructor

Field 类:----获取属性信息的类

常用的方法有四个:

getFields():获取所有公共类域---public

getDeclaredFields():忽略修饰符,获取所有类里的域

getField:获取指定名字的公共域

getDeclaredField():忽略修饰符,获取指定名字的域;

我们定义一个类:

public class Peo {
    private String name;
    protected String adeeress;
    public int age;
    public String sex;
    public String password;
    char a;
}

然后我们在测试类里尝试获取这些属性的信息,注释为输出的结果

public class TestP {
    public static void main(String[] args) throws Exception {
        Class p  = Peo.class;
        Field[] fields = p.getFields();
        for (Field f:fields){
            System.out.println(f);
        }
        //public int reflection.Peo.age
        //public java.lang.String reflection.Peo.sex
        //public java.lang.String reflection.Peo.password
        System.out.println("----------------------------------");
        Field[] fields1 = p.getDeclaredFields();
        for (Field f2 :fields1){
            System.out.println(f2);
        }
        //private java.lang.String reflection.Peo.name
        //protected java.lang.String reflection.Peo.adeeress
        //public int reflection.Peo.age
        //public java.lang.String reflection.Peo.sex
        //public java.lang.String reflection.Peo.password
        //char reflection.Peo.a        
        System.out.println("----------------------------------");
        Field age = p.getField("age");
        System.out.println(age);
        //public int reflection.Peo.age
        System.out.println("----------------------------------");
        Field name = p.getDeclaredField("name");
        System.out.println(name);
        //private java.lang.String reflection.Peo.name
    }
}

Method类-----获取类中方法信息

常用方法类似于Field也是四个,获取的权限与Field基本类似;

getMethods()

getDeclaredMethods()

getMethod(String name,args....)

getDeclaredMethod(String name,ares....)

这里需要强调一下后两个方法,我们需要显示给出方法的名字和参数的类型,比如:

public int run(int a,int b,String c){

return 2;

}//这是我们定义的方法;

Class p = Peo.class;

Method run2 = p.getMethod("run",int.class,int.class,String.class);//这是我们获取的方式

下面我们来测试一下:

首先我们在刚才定义的Peo类中添加一些方法:

public class Peo {
    private String name;
    protected String adeeress;
    public int age;
    public String sex;
    public String password;
    char a;
    public int run(){
        return 1;
    }
    public int run(int a,int b,String c){
        return 2;
    }
    private String eat(){
        return "";
    }
    protected String hh(String ss){
        return "ss";
    }

我们在主方法中进行测试:

public static void main(String[] args) throws Exception {
    Class p  = Peo.class;
    Method[] methods = p.getMethods();
    for (Method m :methods){
        System.out.println(m);
    }
    //public int reflection.Peo.run()
    //public int reflection.Peo.run(int,int,java.lang.String)
    System.out.println("-------------------------------");
    Method[] methods1 = p.getDeclaredMethods();
    for (Method m2:methods1){
        System.out.println(m2);
    }
    //private java.lang.String reflection.Peo.eat()
    //protected java.lang.String reflection.Peo.hh(java.lang.String)
    //public int reflection.Peo.run()
    //public int reflection.Peo.run(int,int,java.lang.String)
    System.out.println("----------------------------------");
    Method run1 = p.getMethod("run");
    System.out.println(run1);
    Method run2 = p.getMethod("run",int.class,int.class,String.class);
    System.out.println(run2);
    //public int reflection.Peo.run()
    //public int reflection.Peo.run(int,int,java.lang.String)
    System.out.println("-----------------------------------");
    Method eat = p.getDeclaredMethod("eat");
    Method hh = p.getDeclaredMethod("hh",String.class);
    System.out.println(eat);
    System.out.println(hh);
    //private java.lang.String reflection.Peo.eat()
    //protected java.lang.String reflection.Peo.hh(java.lang.String)
}

Constructor类

在我们已经了解过以上两个类之后,Constructor类便很容易理解了

同样有四个常用的方法:getConstructor、getConstructors、getDeclaredConstructor、getDeclaredConstructors,用法基本一致。

下面我们直接来测试。

我们定义一个私有类型的构造器

private Peo(String name){
    this.name = name;
}
Class p  = Peo.class;
Constructor c = p.getDeclaredConstructor(String.class);

//private reflection.Peo(java.lang.String)

可以看到 我们可以轻松获取构造器的信息。

以上我们了解了如何获取类的一些主要信息,我们知道了如何获取域、方法和构造器,接下来我们来介绍一下如何通过反射实例化对象,并对属性赋值。

在这里为了便于理解,我们将域和构造器稍作修改:

private String name;
protected String address;
public int age;
private Peo(String name,String address,int age){
    this.name = name;
    this.address = address;
    this.age = age;
}

首先通过类名.class来获取当前类,并用一个Class变量接收:

Class peo = Peo.class;

然后通过getDeclaredConstructor方法来获取到构造器,并用Constructor类型的变量接收,这里注意我们需要显式给出参数类型,以此来明确获取的构造器:

Constructor constructor = peo.getDeclaredConstructor(String.class,String.class,int.class);

然后我们通过newInstance方法来实例化对象:

Peo peo1 = (Peo) constructor.newInstance("张三","保定",19);

 这里会报错,原因是因为我们定义的构造器是私有类型的,直接调用newInstance是无法使用构造器的。

在实例化之前,我们需要暴力反射构造器,以此来屏蔽安全访问修饰符的检查,这里特指private

constructor.setAccessible(true);
Peo peo1 = (Peo) constructor.newInstance("张三","保定",19);

 我们可以看到,在暴力反射构造器之后,我们可以成功实例化一个Peo类型的对象了。

现在我们完成了对对象的实例化,而在我们的项目过程中,我们有时候需要修改对象的属性值。

对于非私有类型的变量,我们可以通过set方法直接对其修改,通过get方法直接获取到。

set(Object,value);

get(Object)

  而对于私有属性的变量我们是没有办法直接获取的,

看到这里的小伙伴应该也明白了,如果我们想直接拿到私有类型的属性,我们需要对其暴力反射。

上面介绍的是通过暴力反射来获取到private类型的属性,我们也可以通过更改器和访问器来获取到private类型的属性:

//请注意这里的方法我们设置为public类型

public String getName() {
    return name;
}

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

 思考:假如更改器和访问器我们也设置为私有,如何通过这两个方法来获取到私有属性值?

欢迎分享,转载请注明来源:内存溢出

原文地址: https://www.outofmemory.cn/langs/720098.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-25
下一篇 2022-04-25

发表评论

登录后才能评论

评论列表(0条)

保存