java 反射学习

2015/6/14 posted in  Java

概要

反射就是能够根据你给出类名实例化出一个实实在在的对象。所以,对象的实例化就不是写死的了,我们可以根据传入的类名不同,从而可以实例化出不同的对象。这种方式可以和工厂设计模式很好的结合,从而可以更加灵活的创建对象

测试用例

定义一个类

定义一个类,用反射来调用他的成员,方法,构造函数等

package com.example.xuyushi.reflecttest;

import android.util.Log;

/**
 * Created by xuyushi on 15/7/14.
 */
public class student {
    static final String TAG = "student";
    private int age;
    private String name;
    private String addresss;

    public student() {
        Log.d(TAG, "none parameter student constructor");
    }

    public student(int age, String name, String addresss) {
        this.age = age;
        this.name = name;
        this.addresss = addresss;
        Log.d(TAG, "3 parameters student constructor");

    }

    public int getAge() {
        return age;
    }

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

    public String getName() {
        return name;
    }

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

    public String getAddresss() {
        return addresss;
    }

    public void setAddresss(String addresss) {
        this.addresss = addresss;
    }

    @Override
    public String toString() {
        return super.toString();
    }

    public void printMessage(int age,String name,String adress){
        Log.d(TAG, "name=" + name + ",age=" + age + ",adress=" + adress);
    }
}

测试用例

public class MainActivity extends Activity {
    static final String TAG = "student";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        testReflect();
    }

    private void testReflect() {
        try {
            /**
             * 1 反射出无参的构造方法并得到对象
             * 注意:
             *      1 在Class.forName()中应该传入含有包名的类全名
             *      2 newInstance()方法的本质是调用类的无参Public构造方法
             */
            String className1="com.example.xuyushi.reflecttest.student";
            Class clazz1=Class.forName(className1);
            Object object1=clazz1.newInstance();


            /**
             * 2 反射出带参数的构造方法并得到对象
             */
            String className2="com.example.xuyushi.reflecttest.student";
            Class clazz2=Class.forName(className2);
            Constructor constructor1=clazz2.getConstructor(int.class,String.class,String.class);
            Object object2=constructor1.newInstance(18,"zhangsan","beijing");
            Log.d(TAG, object2.toString());
            /**
             * 3 获取类的私有字段
             * 注意:
             *      获取共有字段应调用clazz3.getField(name)方法
             */
            String className3="com.example.xuyushi.reflecttest.student";
            Class clazz3=Class.forName(className3);
            Field ageField1=clazz3.getDeclaredField("age");
            Log.d(TAG,"ageField1=" + ageField1);

            /**
             * 4 获取和更改某个对象的私有字段
             *   即模拟get()和set()方法
             */
            String className4="com.example.xuyushi.reflecttest.student";
            Class clazz4=Class.forName(className4);
            Field ageField2=clazz4.getDeclaredField("age");
            Object object4=constructor1.newInstance(19,"wangwu","shanghai");
            //取消访问私有字段的合法性检查
            ageField2.setAccessible(true);
            //获取对象的私有字段
            Object ageObject4=ageField2.get(object4);
            Log.d(TAG, "ageObject4=" + ageObject4);

            //再更改对象的私有字段的值
            ageField2.set(object4, 27);
            //重新获得
            Object ageObject5=ageField2.get(object4);
            Log.d(TAG, "ageObject5=" + ageObject5);

            /**
             * 5 调用对象的带参数的方法
             */
            String className5="com.example.xuyushi.reflecttest.student";
            Class clazz5=Class.forName(className5);
            Method method=clazz5.getMethod("printMessage",int.class,String.class,String.class);
            Object object5=clazz5.newInstance();
            method.invoke(object5,50, "lisi","hangzhou");


        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

实际用例

开关移动流量需要用到sdk中的隐藏函数,需要利用到反射机制实现

public void toggleMobileData(Context context, boolean enabled) {
        ConnectivityManager conMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);

        Class<?> conMgrClass = null; // ConnectivityManager类
        Field iConMgrField = null; // ConnectivityManager类中的字段
        Object iConMgr = null; // IConnectivityManager类的引用
        Class<?> iConMgrClass = null; // IConnectivityManager类
        Method setMobileDataEnabledMethod = null; // setMobileDataEnabled方法

        try {
            // 取得ConnectivityManager类
            conMgrClass = Class.forName(conMgr.getClass().getName());
            // 取得ConnectivityManager类中的对象mService
            iConMgrField = conMgrClass.getDeclaredField("mService");
            // 设置mService可访问
            iConMgrField.setAccessible(true);
            // 取得mService的实例化类IConnectivityManager
            iConMgr = iConMgrField.get(conMgr);
            // 取得IConnectivityManager类
            iConMgrClass = Class.forName(iConMgr.getClass().getName());
            // 取得IConnectivityManager类中的setMobileDataEnabled(boolean)方法
            setMobileDataEnabledMethod = iConMgrClass.getDeclaredMethod("setMobileDataEnabled", Boolean.TYPE);
            // 设置setMobileDataEnabled方法可访问
            setMobileDataEnabledMethod.setAccessible(true);
            // 调用setMobileDataEnabled方法
            setMobileDataEnabledMethod.invoke(iConMgr, enabled);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }