Android 反射机制简单使用及总结

关于反射

开发过程汇总偶尔会用到反射相关的内容。每次使用到时都是在网上找Ctrl+CV,没去梳理总结过,今天正好想起来了,就做一个简单的总结,也加深一下印象。
在我的日常开发工作中,反射主要是用来调用一些被系统隐藏掉的API,以便实现某些需求。

实现反射的三种方式

  1. 使用Class类的静态方法forName(),用类的名字获取一个Class实例 ;
  2. 利用对象调用getClass()方法获取该对象的Class实例;
  3. 运用.class的方式来获取Class实例,对于基本数据类型的封装类,还可以采用.TYPE来获取相对应的基本数据类型的Class实例;

示例

Book.java

package com.example.reflect;

/**
 * @author: SuHang
 * @date: 2021/9/14
 * @desc: 示例类,含两个属性name和price,及四个对应的get/set方法,均为private类型。
 */
public class Book {
    private String name = "Hello";
    private float price;
    
    private String getName() {
        return name;
    }
    private void setName(String name) {
        this.name = name;
    }
    private float getPrice() {
        return price;
    }
    private void setPrice(float price) {
        this.price = price;
    }
}

MainActvity.java

package com.example.reflect;

import android.os.Bundle;
import android.util.Log;

import androidx.appcompat.app.AppCompatActivity;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
     
        reflect1();
    }
    
    /**
     * 使用Class类的静态方法forName(),用类的名字获取一个Class实例
     * 获取其中的成员变量及成员方法,并调用。
     */
    private void reflect1() {
        String bookName;

        try {
            //通过全路径获取Book类
            Class<?> bookClass = Class.forName("com.example.reflect.Book");
            //实例出Book类实例
            Object book = bookClass.newInstance();

            //获取全部成员变量
            Field[] fields = bookClass.getDeclaredFields();
            Log.d(TAG, "book fields size : " + fields.length);
            for (int i = 0; i < fields.length; i++) {
                Log.d(TAG, "book fields name : " + fields[i].getName());
            }

            //获取某个成员变量
            Field nameField = bookClass.getDeclaredField("name");
            /*
            调用方法前,设置访问标志。参数值为true,打开禁用访问控制检查。
            即 true 为可以访问, false 为不可以访问。
            注意:此处设为true,并非将该方法从 private 变成了 public
                 public 方法默认属性也是true
            */
            nameField.setAccessible(true);
            Log.d(TAG, "nameField: " + nameField.get(book));

            //获取全部成员方法
            Method[] methods = bookClass.getDeclaredMethods();
            Log.d(TAG, "book methods size : " + methods.length);
            for (int i = 0; i < methods.length; i++) {
                Log.d(TAG, "book methods name : " + methods[i].getName());
            }

            //获取成员方法 getName();
            Method getNameMethod = bookClass.getDeclaredMethod("getName");
            getNameMethod.setAccessible(true);
            //调用成员方法 getName();
            bookName = (String) getNameMethod.invoke(book);
            Log.d(TAG, "before bookName: " + bookName);

            //获取成员方法 setName();
            Method setNameMethod = bookClass.getDeclaredMethod("setName", String.class);//需加上参数类型,防止方法重载
            //调用成员方法 setName();
            setNameMethod.setAccessible(true);
            setNameMethod.invoke(book, "World");

            //调用成员方法 getName();
            bookName = (String) getNameMethod.invoke(book);
            Log.d(TAG, "after  bookName: " + bookName);

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }

    /**
     * 方法二
     * 利用对象调用getClass()方法获取该对象的Class实例
     */
    private void reflect2() {
        Book book = new Book();
        Class<? extends Book> bookClass = book.getClass();
        //.....
    }
    
    /**
     * 方法三
     * 运用.class的方式来获取Class实例,对于基本数据类型的封装类,还可以采用.TYPE来获取相对应的基本数据类型的Class实例
     */
    private void reflect3() {
        Class<Book> bookClass = Book.class;
        // 基本数据类型
        Class<Integer> integerClass = Integer.TYPE;
        //.....
    }
}

输出结果:

D/MainActivity: book fields size : 2
D/MainActivity: book fields name : name
D/MainActivity: book fields name : price
D/MainActivity: nameField: Hello
D/MainActivity: book methods size : 4
D/MainActivity: book methods name : getName
D/MainActivity: book methods name : getPrice
D/MainActivity: book methods name : setName
D/MainActivity: book methods name : setPrice
D/MainActivity: before bookName: Hello
D/MainActivity: after  bookName: World

关于 setAccessible(boolean b) 方法

调用方法前,设置访问标志。
参数值为true,打开禁用访问控制检查。
即 true 为可以访问, false 为不可以访问。
注意:此处设为true,并非将该方法从 private 变成了 public。public 方法默认属性也是true。

反射的一些常用方法

    public Annotation[] getAnnotations () //获取这个类中所有注解

    getClassLoader() //获取加载这个类的类加载器

    getDeclaredMethods() //获取这个类中的所有方法

    getReturnType() //获取方法的返回类型

    getParameterTypes() //获取方法的传入参数类型

    isAnnotation() //测试这类是否是一个注解类

    getDeclaredConstructors() //获取所有的构造方法

    getDeclaredMethod(String name, Class… parameterTypes)// 获取指定的构造方法(参数:参数类型.class)

    getSuperclass() //获取这个类的父类

    getInterfaces()// 获取这个类实现的所有接口

    getFields() //获取这个类中所有被public修饰的成员变量

    getField(String name) //获取指定名字的被public修饰的成员变量

    newInstance() //返回此Class所表示的类,通过调用默认的(即无参数)构造函数创建的一个新实例

其他示例

由于目前没有实际需求需要用到反射,所以找了一个网上的示例,并未验证。

需求: 蓝牙开发的时候,自动配对的一些方法在API 19以后才对外开放的,这边我们就可以使用反射来实现配对功能了

try
{
    Class<BluetoothDevice> bluetoothDeviceClass = BluetoothDevice.class;
    bluetoothDeviceClass.getMethod("setPin", byte[].class).invoke(device, "1234".getBytes());
    bluetoothDeviceClass.getMethod("createBond").invoke(device);
    bluetoothDeviceClass.getMethod("setPairingConfirmation", boolean.class).invoke(device, true);
    bluetoothDeviceClass.getMethod("cancelPairingUserInput").invoke(device);
}
catch (Exception e)
{
    e.printStackTrace();
}

未完待续

以上内容只是对反射的基础使用进行了一些总结。未来在实际开发过程中再遇到有相关内容时,再来补充。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值