Java学习笔记之:对反射的理解与代码试验

反射:

Java的反射机制就是,在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;

这种动态获取信息以及动态调用对象方法的功能成为Java的反射机制。

对反射机制的一点小小的测试

首先定义一个类People,这个类主要用于测试反射的各种功能,因此特别分别声明了一些private和public的属性与方法。

class People{
    public int ID;
    private String name;
    public People(int ID,String name){
        this.ID = ID;
        this.name = name;
    }
    public People(String name){
        this.ID = 0;
        this.name = name;
    }
    public void setName(String name){
        this.name = name;
    }
    public String getName(){
        return this.name;
    }
    private void amethod(){
        System.out.println("a private method invoked");
    }
}

接下来,定义一个testReflect类来测试反射机制的应用:

public class testReflect {
    public static void main(String[] args) {
        try{
            Class<?> c = Class.forName("People");
            People p = (People)c.getDeclaredConstructor(new Class<?>[]{int.class,String.class}).newInstance(1,"lwx");

            Method[] methods = c.getDeclaredMethods();
            System.out.println("Methods:");
            for(Method method:methods){
                System.out.println(method.getName());
            }
            Method m = c.getDeclaredMethod("setName",String.class);
            m.invoke(p,"zz");

            Method m1 = c.getDeclaredMethod("getName");
            System.out.println("name is:"+m1.invoke(p));

            Method m2 = c.getDeclaredMethod("amethod");
            m2.setAccessible(true);
            m2.invoke(p);
            
            Field[] fields = c.getDeclaredFields();
            System.out.println("Fields:");
            for(Field f:fields){
                System.out.println(f.getName());
            }

            Field f = c.getDeclaredField("name");
            f.setAccessible(true);
            f.set(p,"hh");
            
            System.out.println("now name is:"+m1.invoke(p));
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

分段来慢慢研究这个测试类运行的结果:

Class<?> c = Class.forName("People");
People p = (People)c.getDeclaredConstructor(new Class<?>[]{int.class,String.class}).newInstance(1,"lwx");

首先用Class.forName方法,传入类的路径来加载People类,这里由于我的People类与TestReflect类在同一个文件里,因此直接将People作为参数就能找到这个类并加载。
然后,通过反射机制,使用getDeclaredConstructor方法,找到People类指定参数的构造方法,并使用.newInstance()方法构建一个新的实例。

这里比较有趣的一点是,由于我指定的构造方法有一个参数是intint类型作为基础类型应该是没有对应的类的。但是,在使用getDeclaredConstructor方法时需要传递指定构造函数的参数的类。然后,就发现还真可以传一个int.class作为参数,这是咋回事呢。
上网查了一下,大概是这么一回事:

有9个预先定义好的Class对象代表8个基本类型和void,它们被java虚拟机创建,和基本类型有相同的名字boolean, byte, char,short,int, long, float, double.
这8个基本类型的Class对象可以通过java.lang.Boolean.TYPE,java.lang.Integer.TYPE等来访问,同样可以通过int.class,boolean.class等来访问.

也就是说,int.class是虚拟机运行时加载到方法区里的,所以我们编写程序的时候是找不到这么一个类的。同时,此处也可以用Integer.TYPE来代替int.cass,即可以这样写:
People p = (People)c.getDeclaredConstructor(new Class<?>[]{Integer.TYPE,String.class}).newInstance(1,"lwx");

接着看代码:

 Method[] methods = c.getDeclaredMethods();
 System.out.println("Methods:");
 for(Method method:methods){
     System.out.println(method.getName());
 }

这里通过调用getDeclaredMethods函数,获取刚刚创建的People类声明的所有方法的列表,然后将其打印出来,结果如下:
在这里插入图片描述
然后,试试用反射来调用这些方法:

Method m = c.getDeclaredMethod("setName",String.class);
m.invoke(p,"zz");

Method m1 = c.getDeclaredMethod("getName");
System.out.println("name is:"+m1.invoke(p));

Method m2 = c.getDeclaredMethod("amethod");
m2.setAccessible(true);
m2.invoke(p);

我们首先通过反射找到了名为setName的方法,生成了一个特殊的Method对象,然后通过该对象的invoke方法,来调用这个方法。值得注意的是,这个方法的第一个参数,正是一个People类的对象,也就是说这个invoke方法可以理解为p对象传入参数"zz"来调用了方法setName

然后,再用同样的方法调用getName方法,可以看到p对象的name已经被修改为了“zz”。

最后,再试试调用p对象的私有方法。这里稍微不同的是,要调用private方法必须先将该方法设置为可访问,即setAccessible(true),这样才能成功执行,否则会抛出异常IllegalAccessEsxception·

这段程序运行的结果如下:
在这里插入图片描述
最后,试试用反射来查询和访问类的属性:

 Field[] fields = c.getDeclaredFields();
 System.out.println("Fields:");
 for(Field f:fields){
     System.out.println(f.getName());
 }

 Field f = c.getDeclaredField("name");
 f.setAccessible(true);
 f.set(p,"hh");
 
 System.out.println("now name is:"+m1.invoke(p));

总得来说,和上面访问Method的方法类似,此处也用到了一个特殊的类Field。反射机制是通过该类的实例来访问People类的属性的。
这段程序运行的结果如下:
在这里插入图片描述

总结

反射就是将Java类中的方法和属性映射为一个个对象,如同Method对象将类的方法映射为一个方法对象,Field对象将类的属性映射为属性对象,Class对象为类对象。

反射的优点:

1.反射提高的Java程序的灵活性和拓展性,降低了耦合性。它允许程序创建和控制任何类的对象,无需提前硬编码目标类;

2,反射是其他一些常用语言都不具备的。

3.反射技术的应用领域很广,大多数流行的开源框架在实现过程中都应用了反射。

反射的缺点:

1.性能问题:使用反射基本是一种解释性的操作,要远慢于直接代码。因此反射主要应用在对灵活性和拓展性要求很高的系统框架上,普通程序不建议使用。

2.逻辑问题:使用反射会模糊程序内部的逻辑,反射技术绕过了源代码,从而会带来维护的问题。

3。使用反射的代码一般会比直接的代码更加复杂。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值