TIII-Android技术篇之反射

对于一个类来说,最重要的是什么?

构造+属性+方法+访问权限
待测试的类
/**
 * 作者:张风捷特烈
 * 时间:2018/5/6:10:40
 * 邮箱:1981462002@qq.com
 * 说明:反射测试类
 */
public class Person {
    private int age;
    private String name;
    private boolean isMan;
    public String address="beijing";

    public Person() {
        System.out.println("空参构造执行...");
    }

    public Person( String name, int age,boolean isMan) {
        this.age = age;
        this.name = name;
        this.isMan = isMan;
        System.out.println("三参构造执行...");

    }

    public void publicShow() {
        System.out.println("I am " + name + ",I " + age + "years");
    }

    public static void staticShow() {
        System.out.println("staticShow");
    }


    private void privateShow() {
        System.out.println("I am " + name + ",I " + age + "years");
    }

    public void paramShow(String str,int num) {
        System.out.println("I am " + str + ",I " + num + "years");
    }
}

一、拿到Class对象

Class对象是什么?

Class是一个类,而且它只有一个私有的构造函数,说明它不能通过new来获取对象,构造函数传入一个ClassLoader。
每个类被加载进入内存之后,系统就会为该类生成一个对应的java.lang.Class对象,
通过该Class对象就可以访问到JVM中的这个类,就可以获取某类的一切

private Class(ClassLoader loader) {
    // Initialize final field for classLoader.  The initialization value of non-null
    // prevents future JIT optimizations from assuming this final field is null.
    classLoader = loader;
}
1.对象.getClass()获取Class对象

前提:已存在对象,未知该类全貌,可以使用此方法获取Class对象来探测该类

Object类中有一个native方法获取Class
public final native Class<?> getClass();
    public static void getClass_1() {
        Person person = new Person();
        Class<? extends Person> personClass = person.getClass();
    }
2.类名.class获取Class对象

前提:需要已知类名

public static void getClass_2() {
    Class<Person> personClass = Person.class;
}
3.通过指定字符串:获取Class对象

前提:需已知全类名

public static void getClass_3() {
    try {
        Class<?> person = Class.forName("top.toly.bean.Person");
     System.out.println(person);
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}

二、通过反射构造对象

1.获取无参构造实例化对象:clazz.newInstance()
/**
 * 通过反射建无参实例
 */
public static void createInstance() {
    //早期:new 的时候,先根据类名寻找到该类的字节码文件,并加载到内存,创建该字节码文件对象。
    // 再创建该字节码文件对相应的Person对象
    try {
        String className = "top.toly.bean.Person";
        // 寻找到该类的字节码文件,并加载到内存,创建该字节码文件对象。
        Class<?> clazz = Class.forName(className);
        Object instance = clazz.newInstance();
        System.out.println(instance instanceof Person);//true
    } catch (Exception e) {
        e.printStackTrace();
    }
2.通过反射建有参实例:clazz.getConstructor
 /**
  * 通过反射建有参实例
  */
 private static void createInstance_2() {
     try {
         String className = "top.toly.bean.Person";
         // 寻找到该类的字节码文件,并加载到内存,创建该字节码文件对象。
         Class<?> clazz = Class.forName(className);
         Constructor<?> constructor = clazz.getConstructor(String.class, int.class, boolean.class);
         Object instance = constructor.newInstance("捷特", 24, true);
         System.out.println(instance);
         //Person{age=24, name='捷特', isMan=true, address='beijing'}
     } catch (Exception e) {
         e.printStackTrace();
     }
 }
补充:XXXDeclaredXXX都是只获取本类,不包括父类
// 获得该类所有的构造器,不包括其父类的构造器
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
// 获得该类所以public构造器,包括父类 
public Constructor<T> getConstructor(Class<?>... parameterTypes)

三、通过反射获取字段

1.获取公共字段:clazz.getField
/**
 * 获取公共字段
 */
public static void getPublicField() throws Exception {
    String className = "top.toly.bean.Person";
    // 寻找到该类的字节码文件,并加载到内存,创建该字节码文件对象。
    Class<?> clazz = Class.forName(className);
    Field address = clazz.getField("address");//获取公有字段
    Object o = address.get(clazz.newInstance());
    System.out.println(o);//beijing
}
2.获取私有字段:
/**
 * 获取私有字段
 */
public static void getPrivateField() throws Exception {
    String className = "top.toly.bean.Person";
    // 寻找到该类的字节码文件,并加载到内存,创建该字节码文件对象。
    Class<?> clazz = Class.forName(className);
    Constructor<?> constructor = clazz.getConstructor(String.class, int.class, boolean.class);
    Object instance = constructor.newInstance("捷特", 24, true);
    //可以获取所有类型字段
    Field name = clazz.getDeclaredField("age");
    //想要访问私有,需要将可获取置为true
    name.setAccessible(true);
    //设置私有成员值
    name.setInt(instance,30);
    //获取私有成员值
    Object o = name.get(instance);
    System.out.println(o);//30
}

四、调用方法:

1.获取公共方法:getMethods()
/**
 * 获取公共方法
 */
public static void getPublicMethod() throws Exception {
    String className = "top.toly.bean.Person";
    // 寻找到该类的字节码文件,并加载到内存,创建该字节码文件对象。
    Class<?> clazz = Class.forName(className);
    //创建实例
    Constructor<?> constructor = clazz.getConstructor(String.class, int.class, boolean.class);
    Object instance = constructor.newInstance("捷特", 24, true);
    Method[] methods = clazz.getMethods();//只能获取公有方法,包括父类
    for (Method m : methods) {
        System.out.println(m);
    }
    //获取公共无参
    Method publicShow = clazz.getMethod("publicShow", null);
    //调用函数:invoke
    publicShow.invoke(instance, null);
    //获取公共有参
    Method paramShow = clazz.getMethod("paramShow", String.class, int.class);
    paramShow.invoke(instance, "龙少", 24);
}

clazz.getDeclaredMethod:获取指定名称和参数类型的本类中声明(访问权限不限)的方法 clazz.getDeclaredMethods(): 获取该类所有的方法,不包括父类 clazz.getMethod:获取当前类及所有继承的父类的public修饰的方法。仅包括public clazz.getMethods();获取该类所有的public方法,包括父类的

2.获取私有方法:getDeclaredMethods()
/**
 * 获取私有方法
 */
public static void getPrivateMethod() throws Exception {
    String className = "top.toly.bean.Person";
    // 寻找到该类的字节码文件,并加载到内存,创建该字节码文件对象。
    Class<?> clazz = Class.forName(className);
    Method[] declaredMethods = clazz.getDeclaredMethods();//获取该类中的所有方法
    //创建实例
    Constructor<?> constructor = clazz.getConstructor(String.class, int.class, boolean.class);
    Object instance = constructor.newInstance("捷特", 24, true);
    for (Method m : declaredMethods) {
        System.out.println(m);
    }
    Method privateShow = clazz.getDeclaredMethod("privateShow", null);
    privateShow.setAccessible(true);
    privateShow.invoke(instance,null);
}

反射差不多也就这些,理论并不难,学以致用才是关键


后记、

1.声明:

[1]本文由张风捷特烈原创,转载请注明 [2]欢迎广大编程爱好者共同交流 [3]个人能力有限,如有不正之处欢迎大家批评指证,必定虚心改正 [4]你的喜欢与支持将是我最大的动力

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏前端架构与工程

【译】《Understanding ECMAScript6》- 第五章-Class

目录 ES5中的拟Class结构 Class声明 Class表达式 存储器属性 静态成员 派生类 new.target 总结 自JavaScript面世以来,许...

24560
来自专栏陈纪庚

javascript冷知识

  如果放在数值前的话,对数值不会产生任何影响,不过放在其他的数据类型前面的话,就等于调用number()将他转为数字,布尔值false被转为0,ture被转为...

12230
来自专栏猿学

猿学-深入理解Java中的反射机制

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对...

5400
来自专栏微信公众号:Java团长

Java基础之反射(非常重要)

(使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码))

10730
来自专栏平凡文摘

深入理解Java类型信息(Class对象)与反射机制

15130
来自专栏二进制文集

Java 反射详解

反射(Reflection)能够让运行于 JVM 中的程序检测和修改运行时的行为。

12330
来自专栏Java技术分享

反射类的字段

@Test public void test6() throws Exception { Person person = new...

21860
来自专栏互扯程序

大牛:你真的懂反射吗?

现在是资源共享的时代,同样也是知识分享的时代,如果你觉得本文能学到知识,请把知识与别人分享。

14630
来自专栏柠檬先生

你不知道的javaScript笔记(3)

对象 对象可以通过两种形式定义: 声明形式和构造形式 声明形式语法: var myObj = {key:value} 构造形式语法: var myObj = n...

19350
来自专栏老马说编程

(84) 反射 / 计算机程序的思维逻辑

上节介绍完了并发,从本节开始,我们来探讨Java中的一些动态特性,包括反射、类加载器、注解和动态代理等。利用这些特性,可以以优雅的方式实现一些灵活和通用的功能,...

26280

扫码关注云+社区

领取腾讯云代金券