Java中的反射

反射用得最多的地方是在框架的开发中,平时项目中用得比较少。反射机制允许程序在运行时获取一个已知名称的类的内部信息,包括属性(Field)、方法(Method)、构造函数(Constructor)等,并且可以在运行时改变属性和调用方法。Java文件被编译后生成.class文件,Java虚拟机(JVM)会去解读.class文件,当某个类被使用时JVM会通过加载、连接和初始化三个步骤把.class文件解析为一个对象,这个对象就是java.lang.Class。每一个Java源文件最终都会有一个唯一的类对象(Class),这里需要注意的是:类的对象和类对象不一样,类的对象存在于堆中,可以创建多个;类对象存在于方法区中,每一个类对应唯一的一个类对象,为Class类型。而我们在使用反射时,首先最重要的就是获取到这个唯一的类对象。

获取类对象:
类对象的获取有三种方式:
1、类名.class 比如:User.class
2、类的对象.getClass 比如:new User().getClass
3、Class.forName(“全类名”) 比如:Class.forName(“com.example.amt.activitystartdemo.User”)
上面三种方式都可以获取到一个Class类型的类对象,在框架开发中最常用的是第三种方式。当我们获取到这个类对象后就可以调用对应的API操作类中的构造函数、属性、方法。下面我们来看看具体是怎么操作的,其实就是熟悉一些API。首先我们定义一个User类:其中有public的属性、有private的属性、有static属性、有构造函数、有public的方法、private的方法。

public class User {
    public String userName;
    public int userAge;
    private String userPass;
    private static String userTag = "USER";

    public User() {

    }

    public User(String userName, int userAge) {
        this.userName = userName;
        this.userAge = userAge;
        Log.i("User", "userName=" + userName + ",userAge=" + userAge);
    }

    private User(String userPass) {
        this.userPass = userPass;
        Log.i("User", "userPass=" + userPass);
    }

    public void testMethod(String name, int age) {
        Log.i("User", "testMethod name=" + name + ",age=" + age);
    }
 
    public String getUserName() {
        return userName;
    }

    private int getUserAge() {
        return userAge;
    }
    
}

操作构造函数(Constructor):

            Class c = Class.forName("com.example.amt.activitystartdemo.User");
            //获取public的构造函数
            Constructor[] publicConstructors = c.getConstructors();
            for (Constructor constructor : publicConstructors) {
                Log.i("User", "publicConstructor:" + constructor);
            }

            //获取所有的构造函数
            Constructor[] allConstructors = c.getDeclaredConstructors();
            for (Constructor constructor : allConstructors) {
                Log.i("User", "allConstructor:" + constructor);
            }

            //获取指定的public构造函数(通过构造函数中的参数来获取)
            Constructor publicC = c.getConstructor(String.class,int.class);
            Log.i("User", "constructor:" + publicC);
            //通过public构造函数生成对象
            Object obj = publicC.newInstance("LT",26);

            //获取指定的私有构造函数(通过构造函数中的参数来获取)
            Constructor privateC = c.getDeclaredConstructor(String.class);
            //所有private的构造函数、属性、方法在使用前都必须设置setAccessible为true
            privateC.setAccessible(true);
            Object o =  privateC.newInstance("123456");

其中需要注意的是我们在获取到private的构造函数后使用这个构造函数生成新对象时需要先设置setAccessible(true),否则运行会报错。这个不仅仅是在操作private的构造函数中需要这样,所有private的属性、方法在应用前都必须设置反射对象的setAccessible为true。setAccessible设置为true表示反射对象在应用时抑制Java语音访问检查,setAccessible设置为false表示反射对象在应用时强制执行Java语音访问检查。

操作属性(Field):

            //获取所有public的属性
            Field[] publicField = c.getFields();
            for (Field field : publicField) {
                Log.i("User", "publicField:" + field);
            }

            //获取所有属性
            Field[] allField = c.getDeclaredFields();
            for (Field field : allField) {
                Log.i("User", "allField:" + field);
            }

            //获取指定的public属性(通过属性名称)
            Field field = c.getField("userName");
            //设置新的值
            field.set(o, "newUser");
            //获取属性值
            Log.i("User", "userName:" + field.get(o));
            
           //获取private static的属性
            Field staticField = c.getDeclaredField("USER");
            staticField.setAccessible(true);
            Log.i("User", "staticField:" + staticField.getName());

当我们获取到了某个属性的反射对象后,如果对这个属性设置新的值,那么我们首先需要一个类的对象,就是对哪一个对象设置属性值,如上面代码中的对象o,这个对象o就是上面通过构造函数构造出来的新对象(Object o = privateC.newInstance(“123456”);),并且也需要记住的是如果操作的属性是private的需要先设置setAccessible(true)。

操作方法:

            //获取所有的public方法
            Method[] publicMethod = c.getMethods();
            for (Method method : publicMethod) {
                Log.i("User", "publicMethod:" + method);
            }

            //获取所有的方法
            Method[] allMethod = c.getDeclaredMethods();
            for (Method method : allMethod) {
                Log.i("User", "allMethod:" + method);
            }

            //获取指定方法
            //通过方法名+参数
            Method method = c.getMethod("testMethod", String.class, int.class);
            //方法调用
            //通过类的对象+参数
            method.invoke(o, "testName", 26);

            //private方法
            Field ageFiled = c.getField("userAge");
            ageFiled.set(o, 28);
            Method privateMethod = c.getDeclaredMethod("getUserAge");
            privateMethod.setAccessible(true);
            Log.i("User", "privateMethod:" + privateMethod.invoke(o));

获取某个指定的方法是需要通过方法名称+参数来获取,这里的参数是指该方法中参数的类型,比如上面的testMethod这个方法,参数的类型就是Sting.class和int.class,我们使用invoke来调用执行方法,同Field一样也需要传入一个类的对象,表示执行哪个对象的方法,invoke中除了传入类的对象外后面跟的就是具体的参数,如果这个方法没有定义参数那就只需类的对象。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值