Rxjava链式调用解析

本文以下面代码为例逐步解析

Observable.just("数据源").map(new Function<String, Integer>() {@Overridepublic Integer apply(String s) throws Exception {return 1;}}).filter(integer -> {return integer == 1;}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<Object>() {@Overridepublic void onSubscribe(Disposable d) {}@Overridepublic void onNext(Object o) {}@Overridepublic void onError(Throwable e) {}@Overridepublic void onComplete() {}});}

从just开始

 public static <T> Observable<T> just(T item) {ObjectHelper.requireNonNull(item, "item is null");return RxJavaPlugins.onAssembly(new ObservableJust<T>(item));}

返回了一个将传入的参数封装成了一个 ObservableJust对象
其他的Rxjava创建操作符类似:比如create(), just(),fromArray(),fromIterable(),timer(),interval()等

ObservableJust类


public final class ObservableJust<T> extends Observable<T> implements ScalarCallable<T> {private final T value;public ObservableJust(final T value) {  //将传入的参数赋值给valuethis.value = value;}//重点方法  稍后看@Overrideprotected void subscribeActual(Observer<? super T> observer) {ScalarDisposable<T> sd = new ScalarDisposable<T>(observer, value);observer.onSubscribe(sd);sd.run();}@Overridepublic T call() {return value;}
}

map方法

由于just方法返回了一个ObservableJust对象,所以调用链的map方法调用的ObservableJust对象的map方法
但是我们看到ObservableJust类中并没有map方法,所以去看他的父类Observable

    public final <R> Observable<R> map(Function<? super T, ? extends R> mapper) {ObjectHelper.requireNonNull(mapper, "mapper is null");return RxJavaPlugins.onAssembly(new ObservableMap<T, R>(this, mapper));}

在他的父类Observable中看到,map()依然是返回了一个ObservableMap对象,这个对象将当前对象(也就是上一步的ObservableJust对象)和map()传入的参数一起封装了起来 从上面的调用链来看就是这一段代码:

ObservableMap类

public final class ObservableMap<T, U> extends AbstractObservableWithUpstream<T, U> {final Function<? super T, ? extends U> function;public ObservableMap(ObservableSource<T> source, Function<? super T, ? extends U> function) {super(source); //这里的source也就是上一步的ObservableJust对象this.function = function; //这里的function就是map就是map()传入的参数}//这个方法一样待会分析@Overridepublic void subscribeActual(Observer<? super U> t) {source.subscribe(new MapObserver<T, U>(t, function));}@Overridepublic void onNext(T t) {if (done) {return;}if (sourceMode != NONE) {downstream.onNext(null);return;}U v;try {v = ObjectHelper.requireNonNull(mapper.apply(t), "The mapper function returned a null value.");} catch (Throwable ex) {fail(ex);return;}downstream.onNext(v);}}这时候发现ObservableMap和上面的ObservableJust类一样,都实现了subscribeActual()

filter方法

接着继续分析调用链上的方法filter,一样我们去ObservableMap父类里去找这个方法,他的父类AbstractObservableWithUpstream里面没有这个方法,但是AbstractObservableWithUpstream跟ObservableJust一样继承自Observable

public final Observable<T> filter(Predicate<? super T> predicate) {ObjectHelper.requireNonNull(predicate, "predicate is null");return RxJavaPlugins.onAssembly(new ObservableFilter<T>(this, predicate));}看到没 filter和前两个方法还是一样的套路,返回了一个ObservableFilter对象,不出意外这个ObservableFilter里面肯定也有一个subscribeActual方法,并且也是直接或者间接继承自Observable
public final class ObservableFilter<T> extends AbstractObservableWithUpstream<T, T> {final Predicate<? super T> predicate;public ObservableFilter(ObservableSource<T> source, Predicate<? super T> predicate) {super(source); this.predicate = predicate;}@Overridepublic void subscribeActual(Observer<? super T> observer) {source.subscribe(new FilterObserver<T>(observer, predicate));}static final class FilterObserver<T> extends BasicFuseableObserver<T, T> {final Predicate<? super T> filter;FilterObserver(Observer<? super T> actual, Predicate<? super T> filter) {super(actual);this.filter = filter;}@Overridepublic void onNext(T t) {if (sourceMode == NONE) {boolean b;try {b = filter.test(t);} catch (Throwable e) {fail(e);return;}if (b) {downstream.onNext(t);}} else {downstream.onNext(null);}}
}
一模一样的套路

subscribeOn

 public final Observable<T> subscribeOn(Scheduler scheduler) {ObjectHelper.requireNonNull(scheduler, "scheduler is null");return RxJavaPlugins.onAssembly(new ObservableSubscribeOn<T>(this, scheduler));}public final class ObservableSubscribeOn<T> extends AbstractObservableWithUpstream<T, T> {final Scheduler scheduler;public ObservableSubscribeOn(ObservableSource<T> source, Scheduler scheduler) {super(source); this.scheduler = scheduler;}@Overridepublic void subscribeActual(final Observer<? super T> observer) {final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(observer);observer.onSubscribe(parent);parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));}static final class SubscribeOnObserver<T> extends AtomicReference<Disposable> implements Observer<T>, Disposable {private static final long serialVersionUID = 8094547886072529208L;final Observer<? super T> downstream;final AtomicReference<Disposable> upstream;SubscribeOnObserver(Observer<? super T> downstream) {this.downstream = downstream;this.upstream = new AtomicReference<Disposable>();}@Overridepublic void onSubscribe(Disposable d) {DisposableHelper.setOnce(this.upstream, d);}@Overridepublic void onNext(T t) {downstream.onNext(t);}@Overridepublic void onError(Throwable t) {downstream.onError(t);}@Overridepublic void onComplete() {downstream.onComplete();}@Overridepublic void dispose() {DisposableHelper.dispose(upstream);DisposableHelper.dispose(this);}@Overridepublic boolean isDisposed() {return DisposableHelper.isDisposed(get());}void setDisposable(Disposable d) {DisposableHelper.setOnce(this, d);}}final class SubscribeTask implements Runnable {private final SubscribeOnObserver<T> parent;SubscribeTask(SubscribeOnObserver<T> parent) {this.parent = parent;}@Overridepublic void run() {source.subscribe(parent);}}
}

这个subscribeOn用于切换上游线程:
主要是这一句parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));
scheduler就是我们传入的Schedulers.io(),上面代码可以看到SubscribeTask是一个Runnable,run()里调用的sourcesource.subscribe(parent),还记得source吗,source就是调用链上一步返回的对象,也就是上一步的
ObservableFilter;
去看看Schedulers.io()返回的是个什么类

    public static Scheduler io() {return RxJavaPlugins.onIoScheduler(IO);}看到他返回的是一个Scheduler,去Scheduler中找scheduleDirect
  @NonNullpublic Disposable scheduleDirect(@NonNull Runnable run) {return scheduleDirect(run, 0L, TimeUnit.NANOSECONDS);}public Disposable scheduleDirect(@NonNull Runnable run, long delay, @NonNull TimeUnit unit) {final Worker w = createWorker();final Runnable decoratedRun = RxJavaPlugins.onSchedule(run);DisposeTask task = new DisposeTask(decoratedRun, w);w.schedule(task, delay, unit);return task;}继续往下追踪会发现最终将这个Runable经过各种封装,最后提交到一个线程池(ScheduledExecutorService)中去执行任务,这样就实现了SubscribeOn上游数据源代码的线程切换

至于下游代码线程切换来看ObserveOn

  public final Observable<T> observeOn(Scheduler scheduler, boolean delayError, int bufferSize) {ObjectHelper.requireNonNull(scheduler, "scheduler is null");ObjectHelper.verifyPositive(bufferSize, "bufferSize");return RxJavaPlugins.onAssembly(new ObservableObserveOn<T>(this, scheduler, delayError, bufferSize));}public final class ObservableObserveOn<T> extends AbstractObservableWithUpstream<T, T> {final Scheduler scheduler;final boolean delayError;final int bufferSize;public ObservableObserveOn(ObservableSource<T> source, Scheduler scheduler, boolean delayError, int bufferSize) {super(source);this.scheduler = scheduler;this.delayError = delayError;this.bufferSize = bufferSize;}@Overrideprotected void subscribeActual(Observer<? super T> observer) {if (scheduler instanceof TrampolineScheduler) {source.subscribe(observer);} else {Scheduler.Worker w = scheduler.createWorker();source.subscribe(new ObserveOnObserver<T>(observer, w, delayError, bufferSize));}}
}

ObserveOnObserver类:

mplements Observer<T>, Runnable {private static final long serialVersionUID = 6576896619930983584L;final Observer<? super T> downstream;final Scheduler.Worker worker;final boolean delayError;final int bufferSize;SimpleQueue<T> queue;Disposable upstream;Throwable error;volatile boolean done;volatile boolean disposed;int sourceMode;boolean outputFused;ObserveOnObserver(Observer<? super T> actual, Scheduler.Worker worker, boolean delayError, int bufferSize) {this.downstream = actual;this.worker = worker;this.delayError = delayError;this.bufferSize = bufferSize;}@Overridepublic void onSubscribe(Disposable d) {if (DisposableHelper.validate(this.upstream, d)) {this.upstream = d;if (d instanceof QueueDisposable) {@SuppressWarnings("unchecked")QueueDisposable<T> qd = (QueueDisposable<T>) d;int m = qd.requestFusion(QueueDisposable.ANY | QueueDisposable.BOUNDARY);if (m == QueueDisposable.SYNC) {sourceMode = m;queue = qd;done = true;downstream.onSubscribe(this);schedule();return;}if (m == QueueDisposable.ASYNC) {sourceMode = m;queue = qd;downstream.onSubscribe(this);return;}}queue = new SpscLinkedArrayQueue<T>(bufferSize);downstream.onSubscribe(this);}}@Overridepublic void onNext(T t) {if (done) {return;}if (sourceMode != QueueDisposable.ASYNC) {queue.offer(t);}schedule();}@Overridepublic void onError(Throwable t) {if (done) {RxJavaPlugins.onError(t);return;}error = t;done = true;schedule();}@Overridepublic void onComplete() {if (done) {return;}done = true;schedule();}@Overridepublic void dispose() {if (!disposed) {disposed = true;upstream.dispose();worker.dispose();if (!outputFused && getAndIncrement() == 0) {queue.clear();}}}@Overridepublic boolean isDisposed() {return disposed;}void schedule() {if (getAndIncrement() == 0) {worker.schedule(this);}}void drainNormal() {int missed = 1;final SimpleQueue<T> q = queue;final Observer<? super T> a = downstream;for (;;) {if (checkTerminated(done, q.isEmpty(), a)) {return;}for (;;) {boolean d = done;T v;try {v = q.poll();} catch (Throwable ex) {Exceptions.throwIfFatal(ex);disposed = true;upstream.dispose();q.clear();a.onError(ex);worker.dispose();return;}boolean empty = v == null;if (checkTerminated(d, empty, a)) {return;}if (empty) {break;}a.onNext(v);}missed = addAndGet(-missed);if (missed == 0) {break;}}}void drainFused() {int missed = 1;for (;;) {if (disposed) {return;}boolean d = done;Throwable ex = error;if (!delayError && d && ex != null) {disposed = true;downstream.onError(error);worker.dispose();return;}downstream.onNext(null);if (d) {disposed = true;ex = error;if (ex != null) {downstream.onError(ex);} else {downstream.onComplete();}worker.dispose();return;}missed = addAndGet(-missed);if (missed == 0) {break;}}}@Overridepublic void run() {if (outputFused) {drainFused();} else {drainNormal();}}boolean checkTerminated(boolean d, boolean empty, Observer<? super T> a) {if (disposed) {queue.clear();return true;}if (d) {Throwable e = error;if (delayError) {if (empty) {disposed = true;if (e != null) {a.onError(e);} else {a.onComplete();}worker.dispose();return true;}} else {if (e != null) {disposed = true;queue.clear();a.onError(e);worker.dispose();return true;} elseif (empty) {disposed = true;a.onComplete();worker.dispose();return true;}}}return false;}@Overridepublic int requestFusion(int mode) {if ((mode & ASYNC) != 0) {outputFused = true;return ASYNC;}return NONE;}@Nullable@Overridepublic T poll() throws Exception {return queue.poll();}@Overridepublic void clear() {queue.clear();}@Overridepublic boolean isEmpty() {return queue.isEmpty();}}

不想看代码直接总结,从ObserveOnObserver类中发现他的onSubscribe,onNext,onError,OnNext方法都调用了schedule(),追踪schedule()发现,最终同样是把任务交给了线程池处理,在本例子中由于传递的是AndroidSchedulers.mainThread(),所以下游是切换到主线程执行,这里是用了Handler将任务提交给主线程

final class HandlerScheduler extends Scheduler {private final Handler handler;private final boolean async;HandlerScheduler(Handler handler, boolean async) {this.handler = handler;this.async = async;}@Override@SuppressLint("NewApi") // Async will only be true when the API is available to call.public Disposable scheduleDirect(Runnable run, long delay, TimeUnit unit) {if (run == null) throw new NullPointerException("run == null");if (unit == null) throw new NullPointerException("unit == null");run = RxJavaPlugins.onSchedule(run);ScheduledRunnable scheduled = new ScheduledRunnable(handler, run);Message message = Message.obtain(handler, scheduled);if (async) {message.setAsynchronous(true);}handler.sendMessageDelayed(message, unit.toMillis(delay));return scheduled;}
}

在这里插入图片描述

终于到了最后一步suscribe

这里调用的是Observable的subscribe

 public final void subscribe(Observer<? super T> observer) {ObjectHelper.requireNonNull(observer, "observer is null");try {observer = RxJavaPlugins.onSubscribe(this, observer);ObjectHelper.requireNonNull(observer, "The RxJavaPlugins.onSubscribe hook returned a null Observer. Please change the handler provided to RxJavaPlugins.setOnObservableSubscribe for invalid null returns. Further reading: https://github.com/ReactiveX/RxJava/wiki/Plugins");subscribeActual(observer);//重点看这里} catch (NullPointerException e) { // NOPMDthrow e;} catch (Throwable e) {Exceptions.throwIfFatal(e);// can't call onError because no way to know if a Disposable has been set or not// can't call onSubscribe because the call might have set a Subscription alreadyRxJavaPlugins.onError(e);NullPointerException npe = new NullPointerException("Actually not, but can't throw other exceptions due to RS");npe.initCause(e);throw npe;}}

看到subscribeActual()方法没,原来subscribe()里会调用subscribeActual;

现在往回追溯:

在subscribe方法中会调用当前对象的subscribeActual(),所以往回追溯他首先会去调ObservableObserveOn的subscribeActual(),参数就是最终传入的Observer

回忆一下ObservableObserveOn的subscribeActual()

    @Overrideprotected void subscribeActual(Observer<? super T> observer) {if (scheduler instanceof TrampolineScheduler) {source.subscribe(observer);} else {Scheduler.Worker w = scheduler.createWorker();source.subscribe(new ObserveOnObserver<T>(observer, w, delayError, bufferSize));}}

继续将Observer封装成ObserveOnObserver,然后调用source.subcribe(),source还记得吧,就是调用链上一步的返回的对象,也就是ObservableSubscribeOn,这个类没有实现subscribe,但是他的父类有这个方法,那不就是Observable的subcribe()吗?是的,也就是跟调用链最后一步调用的subcribe()是同一个方法,只不过他的参数是基于下游的参数的进一步封装,那么同样我他会调用到susscribeActual()

 @Overridepublic void subscribeActual(final Observer<? super T> observer) {  //这里的Observer就是将下游封装后的Observer//将oberser继续封装final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(observer);observer.onSubscribe(parent);//经过刚才的分析 这里是将任务交给线程池处理,所以去看SubscribeTask的run()parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));}// SubscribeTask的run()@Overridepublic void run() {source.subscribe(parent); //同样继续调用source.subscribe,那么他也是同意是调用到调用链上一步返回对象的subscribeActual(),,也就是ObservableFilter对象对象}

不出意外ObservableFilter对象里也是将Observer继续封装,然后调用source.subscribe

  @Overridepublic void subscribeActual(Observer<? super T> observer) {source.subscribe(new FilterObserver<T>(observer, predicate));}

现在来到了第一步ObservableJust的subscribeActual():

  @Overrideprotected void subscribeActual(Observer<? super T> observer) {ScalarDisposable<T> sd = new ScalarDisposable<T>(observer, value); //将Observer和value进行封装,value就是我们第一步传入的数据源了observer.onSubscribe(sd);sd.run();}//ScalarDisposable的run方法@Overridepublic void run() {if (get() == START && compareAndSet(START, ON_NEXT)) {observer.onNext(value);   //这里开始把数据源往下游传, value指数据源  observer就是下游一步一步封装的Observer啦if (get() == ON_NEXT) {lazySet(ON_COMPLETE);observer.onComplete();}}}

还记得回溯时封装的那些Observer吗?分别是MapObserver,FilterObserver,SubscribeOnObserver,ObserveOnObserver以及调用链上最后一步我们自己自定义的Observer
分别再看他们的onNext(),其他方法套路一致

MapObserver:

 @Overridepublic void onNext(T t) {if (done) {return;}if (sourceMode != NONE) {downstream.onNext(null);return;}U v;try {//处理数据源,将数据源转换成想要的类型v = ObjectHelper.requireNonNull(mapper.apply(t), "The mapper function returned a null value.");} catch (Throwable ex) {fail(ex);return;}// 继续调用下游Observer的onNextdownstream.onNext(v);}

FilterObserver

 @Overridepublic void onNext(T t) {if (sourceMode == NONE) {boolean b;try {// 数据判断b = filter.test(t);} catch (Throwable e) {fail(e);return;}//满足过滤条件继续调用下游onNextif (b) {downstream.onNext(t);}} else {downstream.onNext(null);}}

SubscribeOnObserver

由于subscribeOn只是起到切换上游线程的作用,所以对下游他不做任何操作,继续调用下游的onNext

     @Overridepublic void onNext(T t) {downstream.onNext(t);}

ObserveOnObserver:

    @Overridepublic void onNext(T t) {if (done) {return;}if (sourceMode != QueueDisposable.ASYNC) {queue.offer(t);}schedule();  //切换下游线程,将任务交给线程池或者主线程handler,然后调用下游onNext}

最终就调到我们自定义的onNext()啦,整个流程就结束了

总结一下

Rxjava的链式调用整个流程就是从下到上,由上而下
每一步的操作符都是将上游对象作为source封装成新的Observable,然后继续往下传递,直到最后的subsribe方法反向开始调用source.subscribe然后调用到每个soource对象的subscriActual(),每一步的subscribActual()又会将下游传递来的Observer一步步封装,直到传递到最上游,在最上游开始再一步步调用封装好的Observe的相关方法,这样就实现了将数据源传递到下游。

切换上游线程:
创建一个Task,继承自Runable,在Runable的run()里调用source.subscribe(),然后将这个Runable进一步封装,根据传递的参数创建对应的线程池或者主线程Handler,将Runable提交给线程池或者Handler去执行

切换下游线程:
封装的Observer的onSubscribe,onNext,onError,OnNext方法都调用了schedule(),追踪schedule()发现,最终同样是把任务交给了线程池处理,在本例子中由于传递的是AndroidSchedulers.mainThread(),所以下游是切换到主线程执行

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/630497.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

element-ui表单验证同时用change与blur一起验证

项目场景&#xff1a; 提示&#xff1a;这里简述项目相关背景&#xff1a; 当审批时不通过审批意见要必须输入&#xff0c; 1&#xff1a;如果用change验证的话删除所有内容时报错是massage的提示&#xff0c;但是在失去焦点的时候报错就成了英文&#xff0c;如下图&#xf…

SQL语句详解四-DQL(数据查询语言-多表查询一)

文章目录 表和表的关系一对一关系一对多、多对一关系多对多关系 表和表的关系 概述&#xff1a;数据库中表的关系有三种&#xff0c;一对一关系、一对多的关系、多对多的关系。 一对一关系 例如&#xff1a;一个人只能有一个身份证号&#xff0c;一个身份证号只属于一个人 示…

STM32F103标准外设库——RCC时钟(六)

个人名片&#xff1a; &#x1f981;作者简介&#xff1a;一名喜欢分享和记录学习的在校大学生 &#x1f42f;个人主页&#xff1a;妄北y &#x1f427;个人QQ&#xff1a;2061314755 &#x1f43b;个人邮箱&#xff1a;2061314755qq.com &#x1f989;个人WeChat&#xff1a;V…

PyQt5零基础入门(四)——信号与槽

信号与槽 前言信号与槽单对单直接连接使用lambda表达式 信号与槽多对多一个信号连接多个槽多个信号连接一个槽信号与信号连接 自定义信号 前言 PyQt5的信号与槽是一种对象之间的通信机制&#xff0c;允许一个QObject对象发出信号&#xff0c;与之相连接的槽函数将会自动执行。…

漏洞复现-科荣AIO UtilServlet任意命令执行漏洞(附漏洞检测脚本)

免责声明 文章中涉及的漏洞均已修复&#xff0c;敏感信息均已做打码处理&#xff0c;文章仅做经验分享用途&#xff0c;切勿当真&#xff0c;未授权的攻击属于非法行为&#xff01;文章中敏感信息均已做多层打马处理。传播、利用本文章所提供的信息而造成的任何直接或者间接的…

【MySQL】管理用户

DCL-管理用户 查询用户 use mysql; select * from user;创建用户 create user 用户名主机名 identified by 密码;修改用户密码 alter user 用户名主机名 identidied with mysql_native_password by 新密码;删除用户 drop user 用户名主机名;创建用户test&#xff0c;只能够…

地震预测系统项目实现

整个项目思路即在一组观测数据中&#xff0c;地震专家&#xff08;即用户&#xff09;输入观测窗口的最小数量和最大数量&#xff0c;进行预测峰值点 数据文件如图所示&#xff1a; #define _CRT_SECURE_NO_WARNINGS #include<fstream> #include<string> #include&…

CSS 设置背景图片

文章目录 设置背景颜色设置背景图片背景图片偏移量计算原点背景图片尺寸设置背景图片位置设置背景图片重复方式设置背景范围设置背景图片是否跟随元素移动测试背景图片 本文概念部分参考&#xff1a;CSS背景background设置 设置背景颜色 background-color 设置背景颜色 设置…

当我们谈上下文切换时我们在谈些什么

相信不少小伙伴面试时&#xff0c;都被问到过这样一个问题&#xff1a;进程和线程的区别是什么&#xff1f;大学老师会告诉我们&#xff1a;进程是资源分配的基本单位&#xff0c;线程是调度的基本单位。说到调度&#xff0c;就不得不提到CPU的上下文切换了。 何为CPU上下文切换…

香港服务器托管:你对服务器托管了解多少?

在当今数字化的时代&#xff0c;服务器托管已成为企业和网站运营的关键一环。对于许多企业来说&#xff0c;如何选择一个安全、稳定、高效的服务器托管方案&#xff0c;成为了确保业务连续性和数据安全的重要课题。那么&#xff0c;究竟什么是服务器托管&#xff0c;它又有哪些…

使用WAF防御网络上的隐蔽威胁之扫描器

在网络安全领域&#xff0c;扫描器是用于侦察和识别网络系统漏洞的工具。 它们可以帮助网络管理员识别安全漏洞&#xff0c;也可能被攻击者用来寻找攻击目标。 扫描器的基本概念 定义&#xff1a;扫描器是一种自动化工具&#xff0c;用于探测网络和服务器中的漏洞、开放端口、…

手机崩溃日志的查找与分析

手机崩溃日志的查找与分析 摘要 本文介绍了一款名为克魔助手的iOS应用日志查看工具&#xff0c;该工具可以方便地查看iPhone设备上应用和系统运行时的实时日志和崩溃日志。同时还提供了崩溃日志的分析查看模块&#xff0c;可以对苹果崩溃日志进行符号化、格式化和分析&#x…

统计学R语言 实验3 点估计

统计学R语言 实验3 点估计 一、实验目的 1. 掌握理解点估计的相关概念和方法。 2. 掌握理解点估计的估计质量好坏判断方法。 3. 熟悉R语言等语言的集成开发环境。 二、实验分析与内容 某灯泡厂从某日生产的一批灯泡中抽取10个灯泡进行寿命试验&#xff0c;得到灯泡寿命&…

leetocode 15 三数之和

题目 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请你返回所有和为 0 且不重复的三元组。 注意&#xff1a;答案中不可以包含重复的三元组。 示例…

Linux网络引导自动安装centos7

目录 一、部署PXE远程安装服务 1. 系统装机的三种引导方式 2. pxe概述 3. 实现过程 4. 搭建过程中服务介绍 4.1 TFTP服务 4.2 vsftp&#xff1a;安装系统镜像文件获取方式 4.3 syslinux 4.4 DHCP服务 5. 操作过程 二、实现Kickstart无人值守安装 1. 安装Kickstart图…

计算机三级(网络技术)——应用题

第一题 61.输出端口S0 &#xff08;直接连接&#xff09; RG的输出端口S0与RE的S1接口直接相连构成一个互联网段 对172.0.147.194和172.0.147.193 进行聚合 前三段相同&#xff0c;将第四段分别转换成二进制 11000001 11000010 前6位相同&#xff0c;加上前面三段 共30…

AI图片物体移除器:高效、便捷的AI照片物体擦除工具

在我们的日常生活中&#xff0c;照片是一种重要的记录和表达方式。然而&#xff0c;有时候我们会遇到需要将照片中的某些物体和元素去除的情况。这时候&#xff0c;传统的图像处理软件可能过于复杂&#xff0c;让人望而却步。为了解决这个问题&#xff0c;AI图片物体移除器的软…

运筹说 第104期 | 2023全球高被引科学家名单发布!

2023年11月15日&#xff0c;全球领先的专业信息服务提供商科睿唯安发布2023年度“全球高被引科学家”名单&#xff0c;遴选全球高校、研究机构和商业组织中对所在研究领域具有重大和广泛影响的顶尖科学人才。最终&#xff0c;来自全球67个国家和地区1300多个机构的6849名科学家…

Node cool 跨域问题的解决

1.问题 自己在写后端接口的时候 发现一个接口在抖音小程序上可以调用 浏览器上也可以直接打开 但是在H5 的请求中 一直就是cors error 前端报这个跨域问题 在后端 报not Found 一开始以为是找不到 经过确定 发现是跨域问题 2.解决 在全局 configuration.ts 文件里有个全局…