关于回调和反射的简单分享
调用
同步调用
1 | public class Person{ |
在打印“新的一天开始了”内容时,door.open()方法已经执行结束。(可能会造成阻塞问题)
异步调用
1 | public class Person{ |
将调用放在一个新的线程中,后边的操作将不再依赖于调用方法的结束。(解决同步调用的阻塞问题)
回调
双向调用模式
A callback is a function this is passed as an argument to another function and is executed after its patent function has completed.
回调是一个函数,它作为参数传递给另一个函数,并在其父函数完成后执行
回调的思想是:一.类A的a()方法调用类B的b()方法
二.类B的b()方法执行完毕主动调用类A的callback()方法
原理:首先创建一个回调对象,然后再创建一个控制器对象,将回调对象需要被调用的方法告诉控制器对象,控制器对象负责检查某个场景是否出现或某个条件是否满足,当满足时,自动调用回调对象的方法。
例一:
情景:老板A对员工B说,我现在交给你一个任务,并且我把我的电话号码给你,你一旦完成任务就给我打电话。
1.创建一个回调接口
1 | public interface CallBack |
2.创建回调接口的实现类,即本例中的老板类
1 | public class Boss implements CallBack |
3.创建控制类,也就是本例中的员工对象
1 | public class Employee |
创建测试类
1 | public class TestMain |
在本例中,如果员工的工作结果可能不止向一类人传递,比如还会给经理、测试等人传递结果。这时我们可以将接收结果这个方法看做一种公共需求,接收到结果后后续处理操作也不一样,我们可以将这个方法定义到接口中,再在具体的类中进行实现。
例二:(安卓中的实例)
在android中回调机制被大量的使用。比如,在Activity中定义了很多生命周期的不同状态要调用的方法,这些方法都是空实现,系统框架要调用,用户也要调用来实现。
举个简单的例子就是Button的点击响应事件实现机制
1 | import android.app.Activity; |
例三:(还是安卓实例)
点击文本框弹出对话框,将输入的文字显示在文本框中。
https://github.com/liuyuxin-cloud/Android/tree/main/callbackdemo
反射
原理
(1)Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息。
(2)Java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁。
反射机制使java具有动态特性
理解
关于java.lang.Class 类的理解
将类编译生成字节码文件(.class)再用(java.exe)命令对每个字节码文件进行解释运行。相当于将某个字节码文件加载到内存中。
加载到内存中的类称为运行时类,它们是Class类的实例。
(java万物皆对象 我们的自定义类是Class类的对象)
用途
1、反编译:.class–>.java
2、通过反射机制访问java对象的属性,方法,构造方法等
3、当我们在使用IDE,比如Ecplise,IntelliJ IDEA时,当我们输入一个对象或者类,并想调用他的属性和方法是,一按点号,编译器就会自动列出他的属性或者方法,这里就是用到反射。
4、反射最重要的用途就是开发各种通用框架。比如很多框架(Spring)都是配置化的(比如通过XML文件配置Bean),为了保证框架的通用性,他们可能需要根据配置文件加载不同的类或者对象,调用不同的方法,这个时候就必须使用到反射了,运行时动态加载需要的加载的对象。
例子:
反射前对于自定义类的操作:
1.通过构造器实例化对象
2.通过对象调用内部属性、方法
3.在类外部不可以通过对象调用内部私有(private)结构(封装性的限制)
反射后:
1.通过反射创建类的对象
2.通过反射调用对象指定的属性、方法
3.通过反射可调用类的私有结构
什么时候使用反射?
1.具有动态性时
2.编译时不确定造哪个对象时
常用类
Java.lang.Class;
Java.lang.reflect.Constructor;
Java.lang.reflect.Field;
Java.lang.reflect.Method;
Java.lang.reflect.Modifier;
基本使用
1、获得Class:主要有三种方法:
(1)Object–>getClass
(2)任何数据类型(包括基本的数据类型)都有一个“静态”的class属性
(3)通过class类的静态方法:forName(String className)(最常用)
1 | //第一种方式获取Class对象 |
2、判断是否为某个类的示例:
一般的,我们使用instanceof 关键字来判断是否为某个类的实例。同时我们也可以借助反射中Class对象的isInstance()方法来判断时候为某个类的实例,他是一个native方法。
1 | public native boolean isInstance(Object obj); |
3、创建实例:通过反射来生成对象主要有两种方法:
(1)使用Class对象的newInstance()方法来创建Class对象对应类的实例。
1 | Class<?> c = String.class;Object str = c.newInstance(); |
(2)先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建对象,这种方法可以用指定的构造器构造类的实例。
1 | //获取String的Class对象 |
4、通过反射获取构造方法并使用:
(1)批量获取的方法:
public Constructor[] getConstructors():所有”公有的”构造方法
public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)
(2)单个获取的方法,并调用:
public Constructor getConstructor(Class… parameterTypes):获取单个的”公有的”构造方法:
public Constructor getDeclaredConstructor(Class… parameterTypes):获取”某个构造方法”可以是私有的,或受保护、默认、公有;