Android 反射机制的理解

作者: Lipt0n | 来源:发表于2016-08-12 19:19 被阅读9572次

之前在网上找有关反射机制的资料发现网上关于这块的资料不多,而且不太容易懂,所以试着写一篇我自己所理解的反射机制希望能多你有所帮助.


首先来看看用反射机制和用以前的方法新建对象实例有什么不同

第一步新建一个Person对象

用以前的方法是:

Person p = new Person();

在内存中新建一个Person的实例,对象p对这块内存地址进行引用

用反射机制实现 (有三种方法):

第一种:

Class<?> cls=Class.forName("com.fanshe.Person"); //forName(包名.类名)
Person p=(Person)cls.newInstance();

1.通过JVM查找并加载指定的类(上面的代码指定加载了com.fanshe包中的Person类)
2.调用newInstance()方法让加载完的类在内存中创建对应的实例,并把实例赋值给p

第二种:

Person p = new Person();
Class<?> cls=p.getClass();
Person p2=(Person)cls.newInstance();

1.在内存中新建一个Person的实例,对象p对这个内存地址进行引用
2.对象p调用getClass()返回对象p所对应的Class对象
3.调用newInstance()方法让Class对象在内存中创建对应的实例,并且让p2引用实例的内存地址

第三种:

Class<?> cls=Person.Class();
Person p=(Person)cls.newInstance();

1.获取指定类型的Class对象,这里是Person
2.调用newInstance()方法在让Class对象在内存中创建对应的实例,并且让p引用实例的内存地址

注意:
cls.newInstance()方法返回的是一个泛型T,我们要强转成Person类
cls.newInstance()默认返回的是Person类的无参数构造对象
被反射机制加载的类必须有无参数构造方法,否者运行会抛出异常


先来看看反射的好处

可能有人会有疑问,明明直接new对象就好了,为什么非要用反射呢?代码量不是反而增加了?

其实反射的初衷不是方便你去创建一个对象,而是让你在写代码的时候可以更加灵活,降低耦合,提高代码的自适应能力.

怎么样降低耦合度,提高代码的自适应能力?

通过接口实现,但是接口如果需要用到new关键字,这时候耦合问题又会出现
举个栗子:

public static void main(String[] args) {
    HeroFacrty facrty =new HeroFacrty();
    hero iroman= facrty.CreateHero("IronMan");
    iroman.attach();
}

public hero CreateHero(String name) {
    if ((name).equals("IronMan")) {
        return new IronMan();
    }
    if ((name).equals("Hulk")) {
        return new Hulk();
    }
    return null;
}

interface hero {
    public void attach();
}

class IronMan implements hero {

    @Override
    public void attach() {
        System.out.println("Laser Light");

    }
}

class Hulk implements hero {

    @Override
    public void attach() {
        System.out.println("fist");

    }
}

假设有1000个不同Hero需要创建,那你打算写1000个 if语句来返回不同的Hero对象?

如果使用反射机制呢?

public static void main(String[] args) {
        HeroFacrty facrty = new HeroFacrty();
        Hero hero=facrty.CreateHero("test.IroMan");
        hero.attack();
    }

    public Hero CreateHero(String name) {
        try {
            Class<?> cls = Class.forName(name);
            Hero hero = (Hero) cls.newInstance();
            return hero;
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;

    }

}

class IroMan implements Hero {

    @Override
    public void attack() {
        System.out.println("Laser Light");

    }
}

class Hulk implements Hero {

    @Override
    public void attack() {
        System.out.println("Fist");

    }
}

interface Hero {
    public void attack();
}

利用反射机制进行解耦的原理就是利用反射机制"动态"的创建对象:向CreateHero()方法传入Hero类的包名.类名 通过加载指定的类,然后再实例化对象.

对于反射机制举个不太严谨的栗子:

当你电脑需要使用鼠标时,你向电脑USB接口插入鼠标,鼠标向电脑发送驱动请求,驱动的型号为NFTW-2196的驱动.这时候电脑在驱动集合中查找驱动,找到后运行驱动鼠标能用了,插入键盘同理.


说完了反射机制如何生成类对象,那生成了对象以后当然要开始调用类的方法了

在调用方法前先了解Class<?> cls=Class.forName("fanshe.Person");cls内部有哪些方法供我们使用.

方法关键字 含义
getDeclareMethods() 获取所有的方法
getReturnType() 获取方法的返回值类型
getParameterTypes() 获取方法的传入参数类型
getDeclareMethod("方法名,参数类型.class,....") 获得特定的方法
-
构造方法关键字 含义
getDeclaredConstructors() 获取所有的构造方法
getDeclaredConstructors(参数类型.class,....) 获取特定的构造方法
-
成员变量 含义
getDeclaredFields 获取所有成员变量
getDeclaredField(参数类型.class,....) 获取特定的成员变量
-
父类和父接口 含义
getSuperclass() 获取某类的父类
getInterfaces() 获取某类实现的接口

以下面的Person来做讲解,稍后我们会用反射实现下面的代码:

public class fanshe03 {

    public static void main(String[] args) {
        Person person=new Person();
        person.setName("Lipt0n");
        System.out.print(person.getName);
    }
}
class Person {

    String name;
    
    public Person() {
    }

    public Person(String name) {
        super();
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

    

很简单步骤分为三步:

  1. 实例化一个Person类对象
  2. 调用Person.setName("name")设置名字
  3. 在控制台打印Person.getName()的值
现在我们用反射机制来实现上面的代码:
public static void main(String[] args) {

         try {
         Class<?> cls=Class.forName("test.Person");//加载Person类
         Object object=(Object) cls.newInstance();//实例化Person
         Method setname=cls.getDeclaredMethod("setName", String.class);//获取setName()方法
         setname.invoke(object, "Lipt0n");//设置调用setName的对象和传入setName的值
         Method getname=cls.getDeclaredMethod("getName");//获取getName方法
         System.out.print(getname.invoke(object, null));//设置调用getName方法的对象.把值打印到控制台
         
         } catch (Exception e) {
         e.printStackTrace();
         }
    }

Java程序可以加载一个运行时才得知名称的class,获悉其完整构造,并生成其对象实体、或对其成员变量赋值、或调用其方法。这种“看透class”的能力称为反射.--(摘自网上的一段话,具体出处忘记了)


</br>

写到这里反射机制的基本用法和好处都基本讲完了.以上就是我对反射机制的理解,希望写出来的东西能对你有所帮助.如果你发现文章有错误的地方希望可以指出,以免误导他人 : )

相关文章

  • Android 反射机制的理解

    之前在网上找有关反射机制的资料发现网上关于这块的资料不多,而且不太容易懂,所以试着写一篇我自己所理解的反射机制希望...

  • 插件化笔记

    看这个就够了啊,深入理解Android插件化技术 插件化技术核心 类的加载机制和反射机制。 类加载 https:/...

  • JAVA反射机制知识

    导读 移动开发知识体系总章(Java基础、Android、Flutter) 反射机制的概念 反射机制的主要功能 与...

  • 反射机制原理的深度理解2017-12-26

    首先我们编写person.java文件如下: 然后创建测试反射机制的类 原理解析: 要理解反射机制的实现过程,首先...

  • Android java层的shell

    Android学习的第一个java层的shell,理解了不少东西,主要理解了Ref反射机制。学习路径来自F8LEF...

  • 反射机制的理解

    Reflection 是 Java 程序开发语言的重要特征之一,是学习Java必须知识点。 Java反射机制主要提...

  • Android反射机制

    Android反射相关知识汇总 一、什么是反射机制? JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这...

  • Android 反射机制

    01、反射 主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。 02、反射作用 反编译:将 class ...

  • 深入理解 Android 消息机制

    原文转载:深入理解 Android 消息机制 深入理解Android消息机制 在日常的开发中,Android 的消...

  • Java 反射机制

    [1]. java反射详解[2]. Java Reflection(反射机制)详解[3]. 深入理解Java类型...

网友评论

  • 木溪bo:清晰明了,言简意赅,好文
  • 世道无情:很好,很清晰
  • 有一点小怪坏:谢谢作者
  • Lipt0n:@黑猿 文章里面的示例代码已经是完整的
  • 88f14aa4ba7d:请问 提高代码自适应能力 再使用反射机制 的那段代码有完整的吗?
  • ac9159fe991b:不错,谢谢作者,赞一个!
  • 程洛_1114:打印语句应该是这样的吧:System.out.print(getname.invoke(object, null).toString);
    Lipt0n:不是这样的
    public String getName() {
    return name;
    }
    从上面代码可以看到getName返回的已经是String了,所以.toString可以省略掉了.
  • 程洛_1114:通过反射获取到getname对象之后,getname不是一个方法,getname(object, null)是什么含义呢?
    Lipt0n:感谢提出,的确少写了应该是 getname.invoke(object, null)

    含义是这样的:
    Object object=(Object) cls.newInstance();
    .........
    Method printname=cls.getDeclaredMethod("getName");

    ----------------------------------------
    getname(object, null)传入的第一个参数是类的实例,第二个是调用getName方法传入的需要的形参
    参看invoke方法源码: public Object invoke(Object obj, Object... args) 第二参数是一个Object的可扩展数组,因为getName方法不需要传入参数,所以传null即可.
  • Shidx:写的非常好,简洁易懂:+1:
  • 7c2628f0a7b3:写的挺好,赞一个
  • 5d89ee9858c7:最后一句有问题
  • 一休日记:网上看了很多Android反射机制的文章,这篇真的看懂了入了门。
    Lipt0n:@余ni同在 能帮到你很高兴
  • and_pu:图片为什么只能看一部分
    Lipt0n:@and_pu 整篇文章都没有一张图片..
  • e758bc175f19:虽是简单,但总有人不懂,赞:kissing_heart:
    Lipt0n:@海的儿子 谢谢哈

本文标题:Android 反射机制的理解

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