Android 注解和反射原理和实现学习(下)

本文详细介绍如何使用Java反射机制调用类中的private方法及属性,包括创建类实例、执行方法及读写属性的具体步骤。同时提供了阻止通过按钮关闭对话框的实际案例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如何调用类中的private方法

1.创建一个类的实例
在得到一个类的Class对象之后,我们可以利用类Constructor去实例化该对象。Constructor支持泛型,也就是它本身应该是Constructor<T>。这个类有一个public成员函数:T newInstance(Object... args),其中args为对应的参数,我们通过Constructor的这个方法来创建类的对象实例。实例Class类的方法有两种,一种是利用Constructor类调用newInstance()方法,另一种就是利用Class类本身的newInstance()方法创建一个实例,构造函数无参数两种方法实现的效果是一样的。如果构造函数有多个,那就不一样了,不同的构造函数创建的对象不一样。

// 加载指定的类
Class<?> clazz = Class.forName(cName);          
// 利用newInstance()方法,获取构造方法的实例
// Class的newInstance方法只提供默认无参构造实例
// Constructor的newInstance方法提供带参的构造实例
Constructor<?> constructor = clazz.getConstructor();
Object obj = constructor.newInstance();    
//如果是无参数的构造函数创建实例,用这个方法简单一些
//Object obj = clazz.newInstance();

2.行为(执行)
Method类中包含着类的成员方法的信息。在Method类中有一个public成员函数:Object invoke(Object receiver, Object... args),参数receiver指明了调用对象,参数args指明了该方法所需要接收的参数。由于我们是在运行时动态的调用类的方法,无法提前知道该类的参数类型和返回值类型,所以传入的参数的类型是Object,返回的类型也是Object。如果某一个方法是Java类的静态方法,那么Object receiver参数可以传入null,因为静态方法从不属于对象。

3.属性
对类的成员变量进行读写,在Field类中有两个public方法:Object get(Object object),该方法可用于获取某成员变量的值;Void set(Object object, Object value),该方法设置某成员变量的值。其中,Object参数是需要传入的对象;如果成员变量是静态属性,在object可传入null。
 //获取和设置属性值
 Field field = clazz.getField("i");
 field.setAccessible(true);
 Object obj = clazz.newInstance();
 Object valuen = field.get(obj);
 field.set(obj,2);
整个的代码

 //获取Class对象
 String className = "com.kayak.annotationdemo.E";
 Class<?> clazz = Class.forName(className); 
 //获取到无参数的构造方法
 Constructor<?> constructor = clazz.getConstructor();
 //创建实例
 Object object = constructor.newInstance();
 Class<?>[] parameterTypes = new Class<?>[]{String.class,Context.class};
 //获取指定的方法
 Method method = clazz.getDeclaredMethod("mtest",parameterTypes);
 method.setAccessible(true);
 Object[] values = new Object[]{"md",this};
 method.invoke(object,values);

LoadMethod.java的优化处理代码

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class LoadMethodEx {

    /**
     * 在运行时加载指定的类,并调用指定的方法
     * @param cName       Java的类名
     * @param MethodName  方法名
     * @param params      方法的参数值
     * @return
     */
    public Object Load(String cName, String MethodName, Object[] params) {
        Object retObject = null;
        try {
            // 加载指定的类
            Class<?> clazz = Class.forName(cName);            
            // 利用newInstance()方法,获取构造方法的实例
            // Class的newInstance方法只提供默认无参构造实例
            // Constructor的newInstance方法提供带参的构造实例
            Constructor<?> ct = clazz.getConstructor();
            Object obj = ct.newInstance();
            // 根据方法名获取指定方法的参数类型列表
            Class<?> paramTypes[] = this.getParamTypes(clazz, MethodName);
            // 获取指定方法
            Method meth = clazz.getMethod(MethodName, paramTypes);
            meth.setAccessible(true);
            // 调用指定的方法并获取返回值为Object类型
            retObject = meth.invoke(obj, params); 
        } catch (Exception e) {
            System.err.println(e);
        }        
        return retObject;
    }
    
    /***获取参数类型,返回值保存在Class[]中*/
    private Class<?>[] getParamTypes(Class<?> cls, String mName) {
    	Class<?>[] clazz = null;       
        /**Note: 由于我们一般通过反射机制调用的方法,是非public方法
         * 所以在此处使用了getDeclaredMethods()方法*/
        Method[] mtd = cls.getDeclaredMethods();    
        for (int i = 0; i < mtd.length; i++) {
            if (!mtd[i].getName().equals(mName)) {
            	// 不是我们需要的参数,则进入下一次循环
                continue;
            }   
            clazz = mtd[i].getParameterTypes();
        }
        return clazz;
    }
}

参考文章:利用java反射技术阻止通过按钮关闭对话框连接: 点击打开链接

下面添上一段利用java反射技术阻止通过按钮关闭对话框的代码

package crazypebble.androidreflection;

import java.lang.reflect.Field;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity {
    /** Called when the activity is first created. */
    private static Button btnHandler = null;
    private static Button btnShowing = null;
    AlertDialog alertDialog = null;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    
        btnHandler = (Button)findViewById(R.id.btn_mHandler);
        btnHandler.setOnClickListener(new ButtonListener());
        
        btnShowing = (Button)findViewById(R.id.btn_mShowing);
        btnShowing.setOnClickListener(new ButtonListener());
        
        alertDialog = new AlertDialog.Builder(this)
                .setTitle("abc")
                .setMessage("Content")
                .setIcon(R.drawable.icon)
                .setPositiveButton("确定", new PositiveClickListener())
                .setNegativeButton("取消", new NegativeClickListener())
                .create();
    }
    
    private class ButtonListener implements OnClickListener {

        @Override
        public void onClick(View v) {
            switch (v.getId()) {
            case R.id.btn_mHandler:
                modify_mHandler();
                alertDialog.show();
                break;
            case R.id.btn_mShowing:
                alertDialog.show();
                break;
            default:
                break;
            }
        }
    }
    
    private class PositiveClickListener implements android.content.DialogInterface.OnClickListener {

        @Override
        public void onClick(DialogInterface dialog, int which) {
            // 方法二时启用
            modify_dismissDialog(false);
        }
    }
    
    private class NegativeClickListener implements android.content.DialogInterface.OnClickListener {

        @Override
        public void onClick(DialogInterface dialog, int which) {
            // 方法一时启用
            //dialog.dismiss();

            // 方法二时启用
            modify_dismissDialog(true);
        }
    }
    
    /*
     * 第一种方法:修改AlertController类的private成员变量mHandler的值
     */
    public void modify_mHandler() {
        try {
            Field field = alertDialog.getClass().getDeclaredField("mAlert");
            field.setAccessible(true);
            // 获取mAlert变量的值
            Object obj = field.get(alertDialog);
            field = obj.getClass().getDeclaredField("mHandler");
            field.setAccessible(true);
            // 修改mHandler变量的值,使用新的ButtonHandler类
            field.set(obj, new MyButtonHandler(alertDialog));
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    /*
     * 第二种方法:修改dismissDialog()方法
     */
    public void modify_dismissDialog(boolean flag) {
        try {
            Field field = alertDialog.getClass().getSuperclass().getDeclaredField("mShowing");
            field.setAccessible(true);
            // 将mShowing变量设为false,表示对话框已经关闭
            field.set(alertDialog, flag);
            alertDialog.dismiss();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

package crazypebble.androidreflection;

import java.lang.ref.WeakReference;

import android.content.DialogInterface;
import android.os.Handler;
import android.os.Message;

public class MyButtonHandler extends Handler{

    // Button clicks have Message.what as the BUTTON{1,2,3} constant
    private static final int MSG_DISMISS_DIALOG = 1;
    
    private WeakReference<DialogInterface> mDialog;

    public MyButtonHandler(DialogInterface dialog) {
        mDialog = new WeakReference<DialogInterface>(dialog);
    }

    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            
            case DialogInterface.BUTTON_POSITIVE:
            case DialogInterface.BUTTON_NEGATIVE:
            case DialogInterface.BUTTON_NEUTRAL:
                ((DialogInterface.OnClickListener) msg.obj).onClick(mDialog.get(), msg.what);
                break;
        }
    }
}

反射机制通过void setAccessible(boolean flag)方法可以得到一个类的private的方法和属性,使用这些private的方法和属性,已经可以做一些超越限制的事情了,从而也面临了一些安全性的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值