官方:主要指应用程序访问、检测、修改自身状态与行为的能力。JAVA反射机制是在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法
个人理解:java 反射机制知道类的结构,能够在程序运行过程中,动态地根据.class文件获取类信息的一种手段,包括类属性,方法,修饰符,接口等信息。
动态开放性质,运行时装配代码,灵活。
在运行时判断任意一个对象所属的类;
在运行时构造任意一个类的对象;
在运行时判断任意一个类所具有的成员变量和方法;
在运行时调用任意一个对象的方法;
生成动态代理。
优点:
能够运行时动态获取类的实例,大大提高系统的灵活性和扩展性。
功能强大
缺点:
性能低
安全限制
程序健壮性,破坏类的封装性
官方解释:回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。
个人理解:
这个被传入的、后又被调用的函数就称为回调函数。
简单来讲就是A类调用了B类的方法,然后再B类的方法中返回来又调用了A的方法。
灵活,易于扩展。
public class Main implements InterfaceExample{
public static void main(String[] args) {
System.out.println("------接口使用测试--------");
InterfaceTest test = new InterfaceTest();
//调用InterfaceTest的handleThings方法,并传递Main的实例
test.handleThings(new Main());
System.out.println("------异步回调测试--------");
}
@Override //重写接口方法
public void sendMessage(String string) {
System.out.println("接口回调成功,利用 " + string + " 做一些事");
}
}
//接口也可以写在一个独立的.java文件里
interface InterfaceExample {
void sendMessage(String string);
}
public class InterfaceTest {
//注意这里Main实例向上转型,接口变量引用了Main实例
public void handleThings(InterfaceExample example) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("-----做一些事------");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//回调接口方法
example.sendMessage("接口传的参数");
}
}).start();
}
}
委托是一个类型(定义了方法的类型),代表着具有相同参数列表和返回类型的方法的类型,一个委托变量可以搭载多个方法,并且可以使得委托对象所搭载的方法并不属于同一个类,当调用此变量时,可以依次调用所绑定的方法。
委托是一种引用类型,作为引用,指向特定的方法,可以用于将方法作为参数传递给其他方法。
为什么需要委托呢?为了使代码解耦,更具有扩展性,更灵活,具体体现在哪里呢?
举例:
在观察者模式中,主题对象和观察者紧密耦合。类图如下:
代码:
抽象观察者
public abstract class Observer {
public abstract void update();
}
抽象主题对象
需要知道具体观察者,并且在自己改变时通知观察者对象,让观察者执行update操作。
public class Subject {
List<Observer> observerList=new ArrayList<Observer>();
public void add(Observer observer){
observerList.add(observer);
}
public void remove(Observer observer){
observerList.remove(observer);
}
public void notify1(){
for (Observer observer:observerList) {
observer.update();
}
}
}
具体观察者,重写update操作,并且要知道具体的主题对象
public class ConcreteObserver extends Observer {
private String name;
private String observerState;
private ConcreteSubject subject;
public ConcreteObserver(String name,ConcreteSubject subject){
this.name=name;
this.subject=subject;
}
@Override
public void update() {
observerState=subject.getSubjectState();
System.out.println("观察者"+name+"状态是"+observerState);
}
}
具体主题对象
public class ConcreteSubject extends Subject {
public String getSubjectState() {
return subjectState;
}
public void setSubjectState(String subjectState) {
this.subjectState = subjectState;
}
private String subjectState;
}
通过上面的分析,虽然可以实现通知的功能,但是有以下不足:
(1)观察者需要知道抽象的通知者,和通知者之间紧密耦合,互相知道
(2)通知者是调用的都是观察者的更新操作,如果想通知的时候,让不同的观察者执行自己不同的行为操作,不能满足。
例如老师来了,一个放哨的同学发送通知说:让玩手机的同学放下手机,睡觉的同学醒来,并且让放哨的同学和睡觉玩手机的同学解耦。如何实现?
实现思路:
在观察者和通知者之间添加一个中间对象,实现通知和观察者的松耦合
观察者通知中间对象,让中间这个对象管理起来所有的观察者,然后根据不同的观察者对象,执行不同的观察者对象的方法,有没有发现就是委托呢?上面提到委托就是方法的引用,然后去执行方法,下面就分析c#版和java版如何实现。
委托在c#中是一个语言特性,但是在java中没有直接的对应。
在java中可以通过反射拿到对象方法的引用来实现委托。
需求:
热水器加热水,当水的温度达到设定的98的时候,让铃响发出通知告诉主人,并且热水器上的显示器显示水温为98度。热水器和铃,显示器解耦。
首先通知者类Notifier:
public abstract class Notifier {
private EventHandler eventHandler=new EventHandler();
public EventHandler getEventHandler() {
return eventHandler;
}
public void setEventHandler(EventHandler eventHandler) {
this.eventHandler = eventHandler;
}
/**
* 增加listener
*/
public abstract void addListener(Object o,String methodName,Object... args);
public abstract void notifyAllListeners();
}
热水器通知者HeaterNotifier:
public class HeaterNotifier extends Notifier {
private Integer temperature;
@Override
public void addListener(Object o, String methodName, Object... args) {
EventHandler eventHandler=this.getEventHandler();
eventHandler.addEvent(o,methodName,args);
}
@Override
public void notifyAllListeners() {
try {
this.getEventHandler().notifyX();
} catch (Exception e) {
e.printStackTrace();
}
}
public void boilWater(Integer warningTemperature){
for (int i = 0; i <100 ; i++) {
this.temperature=i;
if (this.temperature>warningTemperature) {
notifyAllListeners();
break;
}
}
}
}
这个通知者和我们的观察者模式的通知者是不是很像,只不过观察者模式是通知具体的观察者对象,而这里我们是交给了EventHandler来进行管理。
EventHandler类
在EventHandler中遍历每一个事件对象进行通知,类似观察者模式的通知者
public class HeaterNotifier extends Notifier {
private Integer temperature;
@Override
public void addListener(Object o, String methodName, Object... args) {
EventHandler eventHandler=this.getEventHandler();
eventHandler.addEvent(o,methodName,args);
}
@Override
public void notifyAllListeners() {
try {
this.getEventHandler().notifyX();
} catch (Exception e) {
e.printStackTrace();
}
}
public void boilWater(Integer warningTemperature){
for (int i = 0; i <100 ; i++) {
this.temperature=i;
if (this.temperature>warningTemperature) {
notifyAllListeners();
break;
}
}
}
}
接下来看Event事件。在每一个Event对象中都保存着监听者对象和方法名称。Event的invoke方法通过反射获取要执行的方法。也就是委托。
public class Event {
public Object getObject() {
return object;
}
public void setObject(Object object) {
this.object = object;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public Object[] getParams() {
return params;
}
public void setParams(Object[] params) {
this.params = params;
}
private Object object;
private String methodName;
private Object[] params;
public Class[] getParamTypes() {
return paramTypes;
}
public void setParamTypes(Class[] paramTypes) {
this.paramTypes = paramTypes;
}
private Class[] paramTypes;
public Event() {
}
public Event(Object o, String methodName, Object... args) {
this.object = o;
this.methodName = methodName;
this.params = args;
contractParamTypes(this.params);
}
private void contractParamTypes(Object[] params) {
this.paramTypes = new Class[params.length];
for (int i = 0; i < params.length; i++) {
this.paramTypes[i] = params[i].getClass();
}
}
public void invoke() throws Exception {
Method method = object.getClass().getMethod(this.getMethodName(), this.getParamTypes());
if (null == method) {
return;
}
method.invoke(this.getObject(), this.getParams());
}
}
监听者铃AlarmList
public class AlarmListener
{
public void alarm(Integer data){
System.out.println("水开了,当前温度是:"+data);
}
}
监听者显示器DisplayListener
public class DisplayListener {
public void disPlay(Integer data) {
System.out.println("主人,水开了,显示的温度是:"+data);
}
}
灵活扩展体现在了哪里?
假如我想让热水器水烧开的时候也自动关闭电源,这时候我只需要添加一个关闭电源的类,然后在客户端中把监听者添加进去即可。
添加一个TurnOffListener类
public class TurnOffListener {
public void turnOff(Integer data) {
System.out.println("水开了,自动关闭电源了,水温度是:"+data );
}
}
修改客户端:只需添加
heaterNotifier.addListener(new TurnOffListener(),"turnOff",temperature);
public class HeaterEventTest {
public static void main(String[] args) {
Integer temperature=98;
HeaterNotifier heaterNotifier=new HeaterNotifier();
heaterNotifier.addListener(new AlarmListener(),"alarm",temperature);
heaterNotifier.addListener(new DisplayListener(),"disPlay",temperature);
heaterNotifier.addListener(new TurnOffListener(),"turnOff",temperature);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
heaterNotifier.boilWater(temperature);
}
}
委托能做什么?
委托就是自己把这件事委托给别人去做。
1、通知者完全不知道坚挺着,监听者也不知道通知者,实现了完全的解耦
2,通知者和观察者之间没有依赖,扩展性好
3. 一次通知执行,可以执行不同类的不同方法。
跟购物一样,先看大家的评论以及作者的资历。
挑选出好文章之后,先全局看一遍,然后再仔细看,我觉得是需要看懂的,如果看不懂就看下一篇,效率不会太高。看懂的话,再看别的,也能去对比,看到最后其实发现大家写的意思都差不多,这样看懂了之后再去看别的就会很容易。
JAVA回调机制
JAVA回调机制(CallBack)详解
Java 利用反射实现C#的委托
C# 委托(delegate)和事件(event)详解