美文网首页
Java反射

Java反射

作者: 事多店 | 来源:发表于2018-05-05 22:19 被阅读34次

getXXX & getDeclaredXXX

getFields() 方法只能获得某个类及其父类中的所有的 public 字段,而 getDeclaredFields() 方法却能获得某个类(不包括父类)的所有字段(包括 public、private、proteced )等。
同样类似的还有 getConstructors() 和 getDeclaredConstructors()、getMethods() 和 getDeclaredMethods() 方法对。

测试类

public class ReflectClass {

    public static final Integer FINAL_INTEGER = 1000;
    public static final int FINAL_INT = 1000;
    public static final String FINAL_STRING = "1000";

    private int mCount;
    private String mText;

    ReflectClass() {
        mCount = 1000;
        mText = "reflect without param";
    }

    private ReflectClass(int count, String text) {
        mCount = count;
        mText = text;
    }

    private void printText(String text) {
        Log.d("ReflectClass", text);
    }

    public int getCount() {
        return mCount;
    }

    public String getText() {
        return mText;
    }
}

反射构造函数

private void testReflectConstructor() {
    try {
        Class reflectClass = Class.forName("com.example.javaproject.reflect.ReflectClass");

        // 反射获取默认构造函数
        Constructor constructor = reflectClass.getDeclaredConstructor();
        // 获取对象实例
        ReflectClass reflectObject = (ReflectClass) constructor.newInstance();

        Log.d(TAG, "testReflectConstructor, count is " + reflectObject.getCount() + ", text is " + reflectObject.getText());

        // 反射获取带参数构造函数
        constructor = reflectClass.getDeclaredConstructor(int.class, String.class);
        // 由于带参数的构造函数是private的,所以需要设置为accessible的
        constructor.setAccessible(true);
        reflectObject = (ReflectClass) constructor.newInstance(1001, "reflect with param");

        Log.d(TAG, "testReflectConstructor, count is " + reflectObject.getCount() + ", text is " + reflectObject.getText());

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

打印结果为:

testReflectConstructor, count is 1000, text is reflect without param
testReflectConstructor, count is 1001, text is reflect with param

反射方法

private void testReflectMethod() {
    Class reflectClass = ReflectClass.class;

    try {
        Method method = reflectClass.getDeclaredMethod("printText", String.class);
        method.setAccessible(true);

        // 反射获取对象实例
        ReflectClass reflectObject = (ReflectClass) reflectClass.newInstance();

        method.invoke(reflectObject, "Hello, reflect method.");
    } catch (Exception e) {
        e.printStackTrace();
    }
}

打印结果为:

Hello, reflect method.

反射字段

private void testReflectField() {
    Class reflectClass = ReflectClass.class;

    try {
        ReflectClass reflectObject = (ReflectClass) reflectClass.newInstance();
        Log.d(TAG, "testReflectField: before modify, mCount = " + reflectObject.getCount());
        
        // 反射获取字段
        Field field = reflectClass.getDeclaredField("mCount");
        field.setAccessible(true);
        
        // 修改值
        field.set(reflectObject, 2000);
        Log.d(TAG, "testReflectField: after modify, mCount = " + reflectObject.getCount());
    } catch (Exception e) {
        e.printStackTrace();
    }
}

打印结果为:

testReflectField: before modify, mCount = 1000
testReflectField: after modify, mCount = 2000

反射常量字段

private void testConstantField() {
    Class reflectClass = ReflectClass.class;

    try {
        Field fieldInteger = reflectClass.getDeclaredField("FINAL_INTEGER");

        // 无法直接修改一个final的常量
        // fieldInteger.set(null, 2000);

        // 修改final常量的方法,去掉final限定符
        Field modifiersField = Field.class.getDeclaredField("accessFlags");
        modifiersField.setAccessible(true);
        modifiersField.setInt(fieldInteger, fieldInteger.getModifiers() & ~Modifier.FINAL);
        fieldInteger.set(null, 2000);
        Integer modified_integer = (Integer) fieldInteger.get(null);

        Log.d(TAG, "testConstantField: FINAL_INTEGER = " + ReflectClass.FINAL_INTEGER + ", modified_integer = " + modified_integer);

        Field fieldInt = reflectClass.getDeclaredField("FINAL_INT");
        modifiersField.setInt(fieldInt, fieldInt.getModifiers() & ~Modifier.FINAL);
        fieldInt.set(null, 2000);
        int modified_int = (int) fieldInt.get(null);
        Log.d(TAG, "testConstantField: FINAL_INT = " + ReflectClass.FINAL_INT + ", modified_int = " + modified_int);

        Field fieldString = reflectClass.getDeclaredField("FINAL_STRING");
        modifiersField.setInt(fieldString, fieldString.getModifiers() & ~Modifier.FINAL);
        fieldString.set(null, "2000");
        String modified_string = (String) fieldString.get(null);
        Log.d(TAG, "testConstantField: FINAL_STRING = " + ReflectClass.FINAL_STRING + ", modified_string = " + modified_string);

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

打印结果为:

testConstantField: FINAL_INTEGER = 2000, modified_integer = 2000
testConstantField: FINAL_INT = 1000, modified_int = 2000
testConstantField: FINAL_STRING = 1000, modified_string = 2000

从结果上来看,我们的反射修改都成功了,但是ReflectClass这个类里面只有FINAL_INTEGER真正被修改了。原因是当我们定义基本类型的 final 常量或者 String 类型的 final 常量时(只要为 final,不限制有无 static),如果在编译时能确定其确切值则编译器会将其用到的地方用其实际值进行替换,所以即便运行时反射成功也没有任何意义,因为相关值已经在编译时被替换为了常量,而对于包装类型则没事。

测试内部类

public class OuterClass {

    private Runnable mRunnable = new Runnable() {
        @Override
        public void run() {
            Log.d("AnonymousInnerClass", "I'm anonymous InnerClass");
        }
    };

    private static class StaticInnerClass {
        private String mText;

        public StaticInnerClass(String text) {
            mText = text;
        }

        public void print() {
            Log.d("StaticInnerClass", "print: " + mText);
        }
    }

    private class NormalInnerClass {
        private String mText;

        public NormalInnerClass(String text) {
            mText = text;
        }

        public void print() {
            Log.d("NormalInnerClass", "print: " + mText);
        }
    }
}

反射静态内部类

private void testStaticInnerClass() {
    try {
        Class innerClass = Class.forName("com.example.javaproject.reflect.OuterClass$StaticInnerClass");
        Method printMethod = innerClass.getDeclaredMethod("print");

        Object innerClassObject = innerClass.getDeclaredConstructor(String.class).newInstance("I'm static InnerClass");

        printMethod.invoke(innerClassObject);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

打印结果为:

StaticInnerClass: print: I'm static InnerClass

反射内部类

private void testNormalInnerClass() {
    try {
        Class innerClass = Class.forName("com.example.javaproject.reflect.OuterClass$NormalInnerClass");
        Method printMethod = innerClass.getDeclaredMethod("print");

        OuterClass outerObject = OuterClass.class.newInstance();
        // 构造函数的第一个参数要传入外部类对象
        Object innerClassObject = innerClass.getDeclaredConstructor(OuterClass.class, String.class).newInstance(outerObject, "I'm normal InnerClass");

        printMethod.invoke(innerClassObject);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

非静态内部类会隐式持有外部类的引用,就是在构造函数中引入的,所以反射非静态内部的时候需要将外部类对象作为第一个参数,否则会报NoSuchMethodException的异常。相反,静态内部类不持有外部类的引用,所以构造函数不需要传入外部类对象。非静态内部类隐式持有外部类也是Android经常发生内存泄漏的原因之一。

反射匿名内部类

// 匿名内部类直接当成外部类的成员变量去反射就好了
private void testAnonymousInnerClass() {
    try {
        Class outerClass = OuterClass.class;
        Field field = outerClass.getDeclaredField("mRunnable");
        field.setAccessible(true);

        Runnable runnable = (Runnable) field.get(outerClass.newInstance());

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

打印结果为:

AnonymousInnerClass: I'm anonymous InnerClass

参考资料

反射之基本数据类型相关踩坑笔试题
Java 反射常量时一道非常经典有名的面试题
Java 反射内部类相关问题解析

相关文章

  • 博客地址

    java注解-01、java注解-02、Git面试资源java反射-01、java反射-02、java反射-03为...

  • Java反射机制入门

    Java反射机制入门 一、什么是反射 JAVA反射机制(The JAVA reflection mechanism...

  • Java基础之反射

    Java基础之—反射(非常重要)Java中反射机制详解Java进阶之reflection(反射机制)——反射概念与...

  • 反射之一

    总结内容源自一下文章粗浅看java反射机制反射机制应用实践谈谈java反射机制Java Reflection(反射...

  • 反射之二

    总结内容源自一下文章粗浅看java反射机制反射机制应用实践谈谈java反射机制Java Reflection(反射...

  • Java基础之反射

    Java基础之反射 反射基本介绍 反射的使用通过反射调用属性和方法通过反射获取配置文件 反射基本介绍 Java反射...

  • Java 反射机制

    Java 反射机制 什么是反射 Java 反射是Java语言的一个很重要的特征,它使得Java具体了“动态性”。 ...

  • 一探究竟:Java反射效率低的原因到底在哪?

    预备知识 了解 Java 反射基本用法 看完本文可以达到什么程度 了解 Java 反射原理及 Java 反射效率低...

  • 面试官说:大家都说 Java 反射效率低,你知道原因在哪里么

    预备知识 了解 Java 反射基本用法 看完本文可以达到什么程度 了解 Java 反射原理及 Java 反射效率低...

  • Java面试题之JavaSE高级

    一、Java中的反射 1.说说你对Java中反射的理解 java中的反射首先是能够获取到Java...

网友评论

      本文标题:Java反射

      本文链接:https://www.haomeiwen.com/subject/rvzerftx.html