精华内容
下载资源
问答
  • 如何选择走过你生命中的100女孩

    千次阅读 多人点赞 2013-10-22 15:14:41
    如何让我们不光有最大的概率遇到最好的那一个,而是让我们遇到尽可能高质量的女孩儿呢? 笔者将带层层剖析问题,联系现实,并用程序模拟情景,得到让惊讶的数据,也是能指引一生的泡妞计划的数据。 亲爱的程序...

    文章是作者原创,转载请标明出处

    1.    现状

            有一个有意思的问题,假如一个男性,TOM,一生中会遇到100个女孩儿,当他遇到某个女孩儿的时候必须立即决定是否要和她永结同心,那么TOM该如何选择人生中的最佳伴侣呢?

    2.    37%解决方案

            笔者看过有一篇文章从数学的角度,从选择到最好的女孩的角度分析了这个问题。下面是这篇文章所讲述的

           为了便于我们分析,让我们把生活中各种复杂纠纷的恋爱故事抽象成一个简单的数学过程。假设根据过去的经验,这个男性,TOM,可以确定出今后将会遇到的mm个数,比如说 15 个、30 个或者 50 个。不妨把女生的总人数设为 n。这 nmm将会以一个随机的顺序排着队依次前来表白。每次被表白后,TOM都只有两种选择:接受这个mm,结束这场征婚游戏,和她永远幸福地生活在一起;或者拒绝这个mm,继续考虑下一个表白者。我们不考虑TOM脚踏两只船的情况,也不考虑和被拒mm破镜重圆的可能。最后,mm有高质量有低质量,我们不妨假设TOM心里会给mm们的优劣排出个名次来。

            聪明的TOM会想到一个好办法:先和前面几个mm玩玩,试试水深;大致摸清了mm们的底细后,再开始认真考虑,和第一个比之前所有人都要好的mm发展关系。从数学模型上说,就是先拒掉前面 k mm,不管这些mm有多好;然后从第 k+1mm开始,一旦看到比之前所有人都要好的mm,就毫不犹豫地选择她。不难看出,k的取值很讲究,太小了达不到试的效果,太大了又会导致真正可选的余地不多了。这就变成了一个纯数学问题:在mm总数 n已知的情况下,当 k等于何值时,按上述策略选中最佳mm的概率最大?

    对于某个固定的 k,如果最适合的mm出现在了第 i个位置(k < i ≤ n),要想让mm有幸正好被 TOM选中,就必须得满足前 i-1个人中的最好的人在前 k个人里,这有 k/(i-1)的可能。考虑所有可能的 i,我们便得到了试探前 k个mm之后能选中最佳mm的总概率 P(k)


    x 来表示 k/n 的值,并且假设 n充分大,则上述公式可以写成:


    -x · ln x求导,并令这个导数为 0,可以解出 x的最优值,它就是欧拉研究的神秘常数的倒数—— 1/e

    也就是说,如果你预计求爱者有 n个人,你应该先拒绝掉前 n/e个人,静候下一个比这些人都好的人。假设你一共会遇到大概 30个求爱者,就应该拒绝掉前 30/e ≈ 30/2.718 ≈ 11个求爱者,然后从第 12个求爱者开始,一旦发现比前面 11个求爱者都好的人,就果断接受他。由于 1/e大约等于 37%,因此这条爱情大法也叫做 37%法则。

    此方案参考了http://songshuhui.net/archives/57722

    3.    37%的不合理之处

            但是,37%法则有一个小问题:如果最佳人选本来就在这 37%的人里面,错过这 37%的人之后,TOM就再也碰不上更好的了。但在游戏过程中,TOM并不知道最佳人选已经被拒,因此TOM会一直痴痴地等待。也就是说,TOM将会有 37%的概率失败退场,或者以被迫选择最后一名求爱者的结局而告终。从我们的人生角度考虑的话,这样的风险是不是就太大了???而且我们仔细看看这样的计算的条件,我们算出的37%假设的隐含前提是,我们只对最好的那个mm有兴趣,对其他的mm没有任何兴趣。而现实中,很多人只要能得到一个中上的mm就心满意足了,同时他们很害怕一辈子都找不到妹子(最好的mm如果在37%中,TOM就会一辈子找不到老婆了。。。)。所以,这个问题更现实的版本是,怎样让TOM找到尽可能好的mm?(而不是有最大的概率,找到最好的那个妹子)。

    4.    更好的的解决方案

            所以我们现在就变成了要让TOM找到mm的质量的权值最大。于是在此,我们假设100个女孩儿的质量已经有标明,从1-100(只是TOM不知道)。我们可以同样设之前作为比较对象的是,前k个女孩儿。在我们现在的问题中,大家可以预想这样的情况,如果质量为100mm出现在了前K个里边,可怜的TOM就只能孤老一生了,所以这样的情况下的权值为零。Tom孤老终生的概率为,K/100Tom老婆的质量高于99的概率(就是质量99的出现在k里而100的没有出现在k里)是:(100-k/100 * k/99Tom老婆的质量为98的概率是:(100-k/100 * 99-k/99 * k/98。最倒霉的情况就是命中质量为K+1mm了,这样的情况只有之前遇到的kmm的质量正好是1k时才会发生。这个的概率就是,质量排在前面99-k个的mm都不中的概率,乘以剩下最差的的k个中命中质量为1mm的概率:(100-k/100 * 99-k/99 *98-k/98 *……(102-2k)/(102-k) * 1/(k+1)。于是我们可以列出表达式,TOM找到的老婆的质量的权值为:

            k/100 * 0 + (100-k)/100 * k/99 * 100 +100-k/100 *100-k/99 * k/98 * 99 +…………

    5.    程序模拟

            好了,我们有了数学算式,理论上完全能知道怎么帮助无奈的桃花运超好的TOM同学了。只需要求和,求导,就行了。但是这个式子实在难以计算,所以笔者采取了用程序模拟的方法,让计算机帮我们算出结果。

            我还是假设100个女孩儿的质量从1100,申明一个大小为k的数组保存之前的kmm的质量情况。我们用随机数往里边不重复地填1-100的数字就行了。然后我们就能知道这前k个女孩儿的最好的一个的质量是多少。假设这个最好的女孩儿质量为q,则q越大肯定TOM实际选择到的老婆的质量也越高,所以我们只需要看我们选择到的k个女孩儿中最好的质量为多少,即可作为TOM老婆的质量的等价标准。

    6.    简陋的代码

            我在程序中做了一百万次实验取平均值,让结果相当精确。代码不怎么样,不过确实能达到目的,不喜勿喷(*^__^*)

    public class BestGirl {

     public static void main(String[] args) {

              int num = 20;//玩过的女孩数量,就是上面的k

          int life = 1000000;//模拟TOM一百万个一辈子的情况

          int total = 5;

          for(int j = 1;j < total;j++){

                double ave = 0;

                num = j;

              for(int i = 0;i < life;i++){

                  int[] girl = find(num,total);

                  ave = ave + max(girl)%total;

              }

              System.out.println(j+"  "+ave/life);

          }

     }

     public static int[] find(int num,int total){

          int[] girl = new int[num];//记录玩过的女孩的质量

          for(int i = 0;i < num;i++){

                int temp = (int)(Math.random()*total);

                int judge = 0;//判断模拟生成的女孩质量指数是否重复

                for(int j = 0;j < i;j++){

                     if(temp == girl[j]){i--;judge = 1;}//模拟生成的女孩质量指数已经存在过了,重新生成

                }

                if(judge == 0)girl[i] = temp;

          }

          return girl;

     }

     public static int max(int[] girl){

          int max = 0;

          for(int i = 0;i < girl.length;i++){

                if(girl[i] > max)max = girl[i];

          return max+1;

     }

    }

    7.    结果

            实验的结果表明,如果TOM一生中会和100mm擦肩而过的话,那只需要把前9mm作为样本就行了!!!!!

    下面是k1-50时的权值:

    49.463756          65.321506          72.745243             76.795228

    79.187116          80.569507          7  81.379381            8  81.791246

    81.912999          10 81.855833       11 81.60609           12 81.228624

    13  80.825338        14  80.282171        15  79.748856         16  79.074186

    17  78.395126        18 77.682471        19 76.886801         20 76.252873

    21  75.512409        22  74.583178        23  73.800195          24 72.956599

    25  72.122719        26  71.25072          27  70.393686         28  69.543246

    29  68.594598        30 67.757399        31 66.836978          32  65.984432

    33  65.09203          34 64.180472        35 63.264061          36  62.313682

    37  61.279555       38  60.482462         39 59.48373            40  58.512363

    41  57.550438       42  56.729568         43 55.903816           44 54.681889

    45  53.83102         46  52.900635          47  51.926824          48 51.005697           

    49  49.961179       50 49.024802

     

    8.    更接近我们的人生

            实际上很多人一辈子不可能遇到100个可能结为连理的mm,这个数字大多数人都是个位数。所以我们把实验数据调整一下,看看当TOM一辈子只有10mm的时候的情况。

            1000000次的数据表明,TOM在一生只和10mm有可能结为夫妻的情况下,需要把前2mm作为参考标准,能让TOM有尽可能的风险的同时得到最美丽贴心的夫人。不过让人惊异的是,当TOM一生的邂逅mm数缩减到6个的时候,实验证明他还是需要把前2mm作为标准。。。当基数减到5个时,我们只需要把第一个作为参考标准了。所以这个数据并不是100个就选10个,10个就选一个这样等比例增减的。

    9.    回到现实的世界

            在真实的世界中,我们还可以有更多的方式来优化上面的9/100,2/10,2/6,1/5,算法,比如用统计学的分布来检验我们得到的前k个女孩的质量。因为前k个女孩的质量分布也能影响我们的决策,比如前k个女孩的质量分布相当均衡的情况和前k个女孩中有一个女孩儿的质量异常高的情况下,我们在后面的决策是不一样的。比如在后者的情况下,我们在k个之后的女孩中即使遇到了接近但是小于那个异常高质量的女孩的数值的mm时,也完全可以考虑。或者,当我们本来打算前k个都观望的,但是其中某一个女孩异常优秀,远好于k个中其他的,我们也可以考虑直接上了。

            另外,在现实的选择中,我们还需要注意的是,当100个女孩儿选了80个了还没有高于前k个的时候,我们应该把我们的标准放低,以减小零收益的风险。所以我们可以预测到一种更好的选择女孩儿的算法,可以把100分成,比如五个阶段,0-20,21-4041-60,61-80,81-100,不同阶段,根据当前阶段的所有数据采取不同的策略能够更好地选择到更优秀的女孩儿。

    10. 尾声

            广大男同胞们,我只能帮你们到这了……最佳选择策略告诉大家了,但是基数是多少就只能看你们自己了。另外,1/5,2/62/10,9/100这样的数据确实能指导我们的人生,但是笔者提醒大家,数字毕竟只能指引我们,但不能主导我们。我们都是有血有肉有思想有情感的爷们儿,而不是机器人。智商足够高的终结者会完全按照他的算法来选取配偶(如果他需要的话(*^__^*))而我们的生活要由我们自己掌控,对象的选择不能光顾质量和自己一时爽,还要照顾对方的情感,负起责任,并且良好的感情是用时间的耐心慢慢磨合慢慢培养出来的。

            笔者觉得,内外皆佳最好的mm不是天生的,而是由我们培养的。珍惜现在,投入感情,互相理解包容才是恋爱,婚姻的实质。最后祝广大男程序员同胞们都能有情人终成眷属,都能抱得美人归!!!

    展开全文
  • 科学本质上是一种经验主义的认识论,属于哲学的一个分支。量子理论,要通过哲学语言,量子属于形而上看不到、摸不着的东西。元气的基本五行,是世界万物的行成与演变的方式。 生命的本质是化学,化学的本质是物理,...

    AGI:走向通用人工智能的【生命学&哲学&科学】第一篇——生命、意识、五行、易经、量子

    导读
    经典的物理统一在原子上,量子的物理统一在量子上,化学统一在元素上,而生命统一在DNA上,DNA本身拆干了,其实就是一群元素,按照经典物理和量子物理所进行的组合。
    科学本质上是一种经验主义的认识论,属于哲学的一个分支量子理论,要通过哲学语言,量子属于形而上看不到、摸不着的东西。元气的基本五行,是世界万物的行成与演变的方式。
    生命的本质是化学,化学的本质是物理,物理的本质用数学描述,数学的本质是由我们的某种语言写出来的。
    薛定谔的《生命是什么》指出,生命是一个负熵的过程,万物归于虚无,要一直做功。通过大分子的有序性,来克服小分子和原子的无序性,所构成的一个系统就是生命。

     

    目录

    生命

    1、关于《生命是什么》

    五行

    1、五行起源

    2、阴阳五行 VS 量子理论

    易经

    0、易经中难字的读音

    1、易经是什么?

    2、易经的核心是什么?

    3、易经的表达方式是八卦,而八卦又延伸为六十四卦

    4、易经有何作用?

    5、易经的辨证法则是什么?

    量子理论

    1、量子理论概念

    2、量子理论发展史

    3、量子理论影响

    4、什么是量子理论?

    5、量子理论的解释

    6、量子力学VS经典力学

    物理界最豪华聚会高清大合照


     

     

     

    相关文章
    AGI:走向通用人工智能的【生命学&哲学&科学】第一篇——生命、意识、五行、易经、量子
    AGI:走向通用人工智能的【生命学&哲学&科学】第二篇——思维、生命科学、客观世界

     

    生命

            薛定谔的《生命是什么》指出,生命是一个负熵的过程,万物归于虚无,要一直做功。通过大分子的有序性,来克服小分子和原子的无序性,所构成的一个系统就是生命。
           七十年代,数论还是一个离散体系(有范围的)。生命的本质是化学,化学的本质是物理,物理的本质用数学描述,数学的本质是由我们的某种语言写出来的。

    1、关于《生命是什么》

            诺贝尔奖得主、奥地利物理学家薛定谔在其1944年的著作《生命是什么?》(What Is Life? )中,提出了一个更加具体但同书名一样发人深省的问题:“是什么让生命系统似乎与已知的物理学定律相悖?”薛定谔当时给出的答案现在看来颇具预见性。他指出,生命的特征在于“密码本”,这个密码本不但可以指导细胞组织和遗传,还能让有机体摆脱热力学第二定律。
           在这本书中,薛定谔提出了生命密码和生命过程负熵的概念,并特别强调用物理和化学的方法研究生命现象的重要性。 本书原来只是一系列通俗科学演讲的结集, 没想到这本为非专家所写的书,最后却成为发现DNA结构并导致分子生物学诞生的关键著作。他的思想影响了一代生物学家,开创了信息生物学研究之先河,对20世纪的生物学革命起到了不可估量的作用。薛定谔以一种令人放松和愉悦的文笔引领读者探索生命这一令人望而生畏的主题,内容深刻而有趣,极具启发性于希望了解生命起源理论的读者来说,本书无疑是最好的选择之一。
            薛定谔关于生命熵平衡的思想可以被看作是研究生物特权,如复制、记忆、衰老、表观遗传修饰和自我调节,如何被理解为不可忽视环境的非平衡复杂性过程的先驱。令人感兴趣的是,环境和偶然性的类似考虑现在被认为是量子力学的核心,其思想是纠缠、退相干和语境。这是否不仅仅是巧合,我们还不能说。                                                         ----转自网络

     

    五行

    1、五行起源

             阴阳本于易经,而五行出于八卦,都基于河图数理。
             五行是中国古代道教哲学的一种系统观,广泛用于中医、堪舆、命理、相术和占卜等方面。五行的意义包涵借着阴阳演变过程的五种基本动态:水(代表润下)、火(代表炎上)、金(代表收敛)、木(代表伸展)、土(代表中和)。中国古代哲学家用五行理论来说明世界万物的形成及其相互关系。它强调整体,旨在描述事物的运动形式以及转化关系。阴阳是古代的对立统一学说,五行是原始的系统论。

                                                          五行相生:木→火→土→金→水
                                                          五行相克:金→木→土→水→火
             相生,是指两类属性不同的事物之间存在相互帮助,相互促进的关系;具体是:木生火,火生土,土生金,金生水,水生木。
             相克,则与相生相反,是指两类不同五行属性事物之间关系是相互克制的;具体是:木克土,土克水,水克火、火克金、金克木。

    2、阴阳五行 VS 量子理论

          量子理论,只有通过哲学语言,量子属于形而上看不到、摸不着的东西。元气的基本五行,世界万物的行成与演变的方式。

     

     

    易经

             《易经》指《连山》、《归藏》、《周易》三部易书。其中《连山》和《归藏》已经失传,现存于世的只有《周易》。从本质上来讲,《易经》是阐述关于变化之书,是博大精深的辩证法哲学书。《易经》被誉为“诸经之首大道之源”,是中华传统文化的总纲领,蕴涵含着朴素深刻的自然法则和和谐辨证思想,是中华民族万千年智慧的结晶。
            《易经》长期被用作“卜筮”。“卜筮”就是对未来事态的发展进行预测,而《易经》便是总结这些预测的规律理论的书。《易经》含盖万有,纲纪群伦,是中华文化的杰出代表;广大精微,包罗万象,亦是中华文明的源头活水。其内容涉及哲学、政治、生活、文学、艺术、科学等诸多领域,是群经之首,儒家、道家共同的经典。

    0、易经中难字的读音

    • 爻:音 yáo ,2声。组成八卦中每一卦的长短横道:爻象。
    • 兑:音 dui,4声。兑卦喜悦可见,快乐照临人。
    • 夬:音 guai,4声。决也,刚决桑也。
    • 彖:音 tuan,4声。本义为“猪跑脱”。篆为从彖声之字。
    • 贞:即祯,“贞”为动词,卜问的意思,“祯”为形容词吉祥的意思。
    • 筮:音 shì。占吉凶,如筮短龟长。



    1、易经是什么?

    • (1)、严格说来《易经》和《易传》构成了《周易》;而《周易》、《连山》、《归藏》又构成了《三易》。《连山》是夏代的易学,《归藏》是殷代的易学,《周易》是周代的易学。可惜,《连山》、《归藏》已失传。
    • (2)、《易经》又称本经,简称《易》,成书于西周初至晚周,距今约三千年前。《易经》由卦辞及爻辞组成共有六十四卦每卦有六爻,共三百八十四爻。而《易传》有十翼即:彖上、彖下、象上、象下、文言、系辞上、系辞下、说卦、序卦、杂卦十篇。《易传》成书于春秋至战国中期,是对易经的注释和发挥。
    • (3)、史学界认为《周易》为伏羲、文王、周公、孔子四圣合著,即伏羲画八卦,文王作卦辞,周公著爻辞,孔子撰《易传》。

     

    2、易经的核心是什么?

             易经的核心就是著名的“三易说”,即:简易、变易、不易。

    • (1)、简易:是指世界上的事物再复杂再深奥,一旦人类的智慧达到,就可以把它们转换成人们容易理解和处理的问题。
    • (2)、变易:是指世界上的万事万物每时每刻都在变化发展着,没有一样东西是不变的,如果离开这种变化,宇宙万物就难以形成。
    • (3)、不易:是指在宇宙间万物皆变的前提下,还有唯一不变的东西存在,就是能变出万象之物的东西不变;即是说万物皆变的规律是永远不变的。

             所谓"不易",就是基本平衡;"变易"就是发展变化,就是不平衡;"简易"就是世界上所有最复杂的事物可以用最简单的符号来概括。发展变化、不平衡是绝对的、永恒的,平衡是相对的、暂时的。

     

    3、易经的表达方式是八卦,而八卦又延伸为六十四卦

    • (1)、八卦是由:乾、兑、离、震、巽、坎、艮、坤八个单卦组成。知道了八卦就可以推出六十四卦。  乾: 天;坤: 地;兑: 水;离: 火;震: 雷;坎: 水;艮: 山;巽: 风 。
    • (2)、在《易经》经文中,用"-"表示阳爻,用"--"表示阴爻。阴阳爻就组成了卦。  
    • (3)、具体说,每一个卦有六个爻,或者是由三个阳爻或三个阴爻组成;或者是由一个阴爻与两个阳爻;或是由一个阳爻与两个阴爻组成。八卦就是八个单卦。再由八个单卦互相重合,组成六十四卦。
    • (4)、“易有太极,是生两仪,两仪生四象,四象生八卦”。阴阳的变化由太极开始,由太极产生出两仪即阴阳。即有阴阳,使相互感应,阳育阴,阴含阳,于是阴中有阳,阳中有阴,所以阴阳二气,又分为四,名曰四象。四象现在一般是指少阳、老阳、少阴、老阴。

     

    4、易经有何作用?

             易经是中国儒家千年总结的哲理和经验,它包罗万象涉及的范围很广,几乎所有的知识都包括在内的一部百科全书。易经给人类带来三把金钥匙。

    • (1)、第一把金钥匙是“阴阳”,世上任何事情阴阳平衡就达到了和谐,和谐就能发展进步。
    • (2)、第二把金钥匙是“五行”,万事万物都离不开五行的身影,风水的命理学和位理学都从它而起。
    • (3)、第三把金钥匙是“八卦”,由八卦延伸为“文王六十四卦”。他告诉我们宇宙的六十四个密码,大千世界都逃脱不了这个秘密。

     

    5、易经的辨证法则是什么?

         "易,穷则变,变则通,通则久。"这是《系辞》中说的,也是《易经》中的一个重要的辨证法则:通变致久。

    • (1)、天道运行的规律:[唯变所适]。事物有变就有常,有常就有变。《易经》就在这种[变动不居]中、显示了[恒常通久]的不变法则,又在这种“恒常通久”中、表现了“唯变所适”的可变规律。这种规律就是所谓的[天行],即天道运行的规律。
    • (2)、事物变化遵循天道运行的规律。世间万物都是变化着的,只有天道规律本身不变,所以事物变化必须遵循天道运行的规律。
    • (3)、所以《易经》认为既然世间万物都是变化着的,只有天道规律本身不变,那么人就应该效法天道,不违天逆常,顺时适变,如此才可以保持长久。
    • (4)、《易经》的两个指导人行为的概念,即[时]与[中]:中]指中庸之道:在天地自然之道正中运行,既不太过,又不不及。[时]指与时势一致:也就是说和谐、与时俱进。



     

     

    量子理论

    1、量子理论概念

             量子(quantum)是现代物理的重要概念。最早是由德国物理学家M·普朗克在1900年提出的。他假设黑体辐射中的辐射能量是不连续的,只能取能量基本单位整数倍,从而很好地解释了黑体辐射的实验现象。
             后来的研究表明,不但能量表现出这种不连续的分离化性质,其他物理量诸如角动量自旋、电荷等也都表现出这种不连续的量子化现象。这同以牛顿力学为代表的经典物理有根本的区别。量子化现象主要表现在微观物理世界。描写微观物理世界的物理理论是量子力学
             量子一词来自拉丁语quantus,意为“有多少”,代表“相当数量的某物质”。自从普朗克提出量子这一概念以来,经爱因斯坦玻尔、德布罗意、海森伯、薛定谔、狄拉克、玻恩等人的完善,在20世纪的前半期,初步建立了完整的量子力学理论。绝大多数物理学家将量子力学视为理解和描述自然的基本理论。

     

    2、量子理论发展史

             在经典物理学中,根据能量均分定理:能量是连续变化的,可以取任意值。19世纪后期,科学家们发现很多物理现象无法用经典理论解释。当时德国物理界聚焦于黑体辐射问题的研究。1900年左右,M·普朗克试图解决黑体辐射问题,他大胆提出量子假设,并得出了普朗克辐射定律,沿用至今。普朗克提出:像原子作为一切物质的构成单位一样,“能量子”(量子)是能量的最小单位。物体吸收或发射电磁辐射,只能以能量量子的方式进行。普朗克在1900年12月14日的德国物理学学会会议中第一次发表能量量子化数值、一个分子摩尔(mol)的数值及基本电荷等。其数值比以前更准确,提出的理论也成功解决了黑体辐射的问题,标志着量子力学的诞生。
             1905年,德国物理学家爱因斯坦把量子概念引进光的传播过程,提出“光量子”(光子)的概念,并提出光同时具有波动和粒子的性质,即光的“波粒二象性”。
             20世纪20年代,法国物理学家德布罗意提出“物质波”概念,即一切物质粒子均具备波粒二象性;德国物理学家海森伯等人建立了量子矩阵力学;奥地利物理学家薛定谔建立了量子波动力学。量子理论的发展进入了量子力学阶段。
             1928年,英国物理学家狄拉克完成了矩阵力学和波动力学之间的数学等价证明,对量子力学理论进行了系统的总结,并将两大理论体系——相对论和量子力学成功地结合起来,揭开了量子场论的序幕。量子理论是现代物理学的两大基石之一,从微观层面理解宏观现象提供了理论基础。

     

    3、量子理论影响

             量子假设的提出有力地冲击经典物理学,促进物理学进入微观层面,奠基现代物理学。但直到现在,物理学家关于量子力学的一些假设仍然不能被充分地证明,仍有很多需要研究的地方。
             经典的物理统一在原子上,量子的物理统一在量子上,化学统一在元素上,而生命统一在DNA上,DNA本身拆干了,其实就是一群元素,按照经典物理和量子物理所进行的组合。

     

    4、什么是量子理论?

             经过几千年的争论,我们现在终于知道了,物质追根究底是由像电子、夸克这样的微观粒子组成的。这些小家伙像乐高积木一样组合在一起,形成了原子和分子,而原子和分子又是拼成宏观世界的“乐高积木”。
             为了描述微观世界是如何运作的,科学家发展出一套叫量子力学的理论。这个理论做出的预言虽然非常古怪(例如,粒子可以同时出现在两个地方),但它是目前物理学中最精确的理论,在过去近百年里经受住了严格的检验。没有量子理论,我们周围的许多技术,包括电脑和智能手机里的芯片,都是不可想象的。
             量子理论很古怪,但它的正确性不容怀疑。科学家们所争论的,仅仅是如何解释它。

     

    5、量子理论的解释

    • 哥本哈根学派的解释:在我们测量之前,确定的现实是不存在的。只有我们在观察的那一刻,观察的行为导致波函数“塌缩”,一种确定的现实才呈现出来。哥本哈根诠释归纳起来有三个核心:玻恩的概率解释、海森堡的不确定性原理、玻尔的互补原理这三大核心原理合力摧毁了我们对世界的认知:前两者合力摧毁了经典世界的因果性,后两者合力捣毁了世界的客观性。
       

      (1)、用一个简单硬币现象来理解哥本哈根诠释        
              一个硬币一般情况下它的状态,我们认为它要么是正面,要么是反面,这是很明确的。但是,有一种情况,它的状态是不明确的,这种情况就是当它在旋转的时候,我们是不知道它是正面还是反面的。我们认为它是量子状态(我们用硬币代替粒子,实际上在宏观世界这不是量子态)。这时,可以用一个波函数来描述它的状态,也即用这个波函数来描述硬币在旋转时正面和反面的概率
               但是,当我们想去测量清楚它到底是正面还是反面时,我们就必须将硬币摁倒,这就破坏了硬币正在旋转的这种量子态,也就是它的波函数坍缩了。而在硬币旋转的时候,硬币就处于正面和反面的叠加态,或者说它即表现出是正面,又表现出是反面,这就类似于量子表现出波动性和粒子性一样。

    • 多世界解释:每一次对量子的测量都将触发无数平行宇宙的诞生,叠加态中的每一个可能性,分别都在每一个新生的宇宙中成为了现实。你之所以观察到薛定谔猫还活着,仅仅因为这个“你”碰巧跟那只活的猫处于同一个新生宇宙中而已。
    • 德布罗意的导波解释:微观粒子的行为跟经典粒子差不多,只是你要把它们想象成像冲浪者一样骑在所谓的导波上。粒子产生波,而波又引导粒子运动,如此反复。

     

    6、量子力学VS经典力学

             说实话,统治我们熟悉的“经典”世界的规则在微观世界基本上都失效了。只有少数几个硕果仅存,像能量守恒、电荷守恒等等。
             “经典”是物理学家用于描述“日常感觉”的术语——当事物的表现不超出你日常经验的范围,我们就说它是“经典”的。但这并不意味着,微观和宏观世界的规律完全“老死不相往来”。作为物理规律,量子规律无疑更基本,但是当很多粒子聚集在一起时,其整体行为就非常趋近于经典物体的行为了,这时你就可以用经典规律来描述。

     

     

    物理界最豪华聚会高清大合照

    送上1927年第五届索尔维会议合影,物理界最豪华聚会高清大合照

     

     

     

     

    参考文章
    薛定谔《生命是什么?》出版75周年纪念
    人人都能懂的量子理论 
    九个问题告诉你,《易经》讲什么?

     

    展开全文
  • Springbean的生命周期(最详细)

    万次阅读 多人点赞 2020-02-24 14:09:35
    Spring Bean的生命周期指的是从一个普通的Java类变成Bean的过程,深知Spring源码的都知道这个给面试官将的话大可将30分钟以上,如果不知道源码,那么Aware接口和调用init方法这样的,所以这个问题即考察对Spring...

           Spring Bean的生命周期是Spring面试热点问题。Spring Bean的生命周期指的是从一个普通的Java类变成Bean的过程,深知Spring源码的人都知道这个给面试官将的话大可讲30分钟以上,如果你不没有学习过Spring的源码,可能就知道Aware接口和调用init方法这样的生命周期,所以这个问题即考察对Spring的微观了解,又考察对Spring的宏观认识,想要答好并不容易!本文希望能够从源码角度入手,帮助面试者彻底搞定Spring Bean的生命周期。

    总体的创建过程

          首先你要明白一点,Spring Bean总体的创建过程如下:

                                      

            以注解类变成Spring Bean为例,Spring会扫描指定包下面的Java类,然后将其变成beanDefinition对象,然后Spring会根据beanDefinition来创建bean,特别要记住一点,Spring是根据beanDefinition来创建Spring bean的,关于beanDefinition下文会进行分析。

    beanDefinition

                                        

            上图就是beanDefinition所包含的内容,看到这些属性如果对Spring有所了解都应该知道几个,如lazyInit懒加载,在Spring中有一个@Lazy注解,用来标识其这个bean是否为懒加载的,scope属性,相应的也有@scope注解来标识这个bean其作用域,是单例还是多例,beanClass属性,在对象实例化时,会根据beanClass来创建对象、又比如autowireMode注入模型这个属性,这个属性用于记录使用怎样的注入模型,注入模型常用的有根据名称和根据类型、不注入三种注入模型。

            autowireMode虽然看似我们没有使用到过,但是知道这个对于查看Spring和其他框架整合的时候很有帮助,如果我们在beanDefinition指定其根据类型进行属性注入,那么在创建这个bean时,会将其beanClass中的所有属性都拿到,然后排出调基本属性(如类型String、Double、Boolean、Object),然后对于剩下的进行属性注入,记住一点,在beanDefinition指定其根据类型进行属性注入,即使不在属性上面使用@Autowired注解也会对其进行属性注入。在我们写注解类的时候为什么不使用@Autowired时,其属性就注入不进来呢?那是因为注解类在变成beanDefinition时,其注入类型是不注入,所以此时只有使用@Autowired注解进行标记的属性,才会完成依赖注入。

          说了这么多,总之大家要记住Spring会根据beanDefinition来完成bean的创建,为什么不直接使用对象的class对象来创建bean呢?因为在class对象仅仅能描述一个对象的创建,它不足以用来描述一个Spring bean,而对于是否为懒加载、是否是首要的、初始化方法是哪个、销毁方法是哪个,这个Spring中特有的属性在class对象中并没有,所有Spring就定义了beanDefinition来完成bean的创建。

    java类 -> beanDefinition对象

            所以说如果要说Bean的生命周期,你不能不说Java类是在那一步变成beanDefinition的,我们先来看一下Spring中AbstractApplicationContext类中的refresh方法,这个方法就可以总结上面的图。

    @Override
    	public void refresh() throws BeansException, IllegalStateException {
    		synchronized (this.startupShutdownMonitor) {
    			// Prepare this context for refreshing.
    			准备工作包括设置启动时间,是否激活标识位,
    			// 初始化属性源(property source)配置
    			prepareRefresh();
    
    			// Tell the subclass to refresh the internal bean factory.
    			//返回一个factory 为什么需要返回一个工厂
    			//因为要对工厂进行初始化
    			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
    			// Prepare the bean factory for use in this context.
    			//准备工厂
    			prepareBeanFactory(beanFactory);
    
    			try {
    				// Allows post-processing of the bean factory in context subclasses.
    				//这个方法在当前版本的spring是没用任何代码的
    				//可能spring期待在后面的版本中去扩展吧
    				postProcessBeanFactory(beanFactory);
    
    				// Invoke factory processors registered as beans in the context.
    				//在spring的环境中去执行已经被注册的 factory processors
    				//设置执行自定义的ProcessBeanFactory 和spring内部自己定义的
    				invokeBeanFactoryPostProcessors(beanFactory);
    
    				// Register bean processors that intercept bean creation.
    				//注册beanPostProcessor
    				registerBeanPostProcessors(beanFactory);
    
    				// Initialize message source for this context.
    				initMessageSource();
    
    				// Initialize event multicaster for this context.
    				//初始化应用事件广播器
    				initApplicationEventMulticaster();
    
    				// Initialize other special beans in specific context subclasses.
    				onRefresh();
    
    				// Check for listener beans and register them.
    				registerListeners();
    
    				// Instantiate all remaining (non-lazy-init) singletons.
    				finishBeanFactoryInitialization(beanFactory);
    
    				// Last step: publish corresponding event.
    				finishRefresh();
    			}
    
    			catch (BeansException ex) {
    				if (logger.isWarnEnabled()) {
    					logger.warn("Exception encountered during context initialization - " +
    							"cancelling refresh attempt: " + ex);
    				}
    
    				// Destroy already created singletons to avoid dangling resources.
    				destroyBeans();
    
    				// Reset 'active' flag.
    				cancelRefresh(ex);
    
    				// Propagate exception to caller.
    				throw ex;
    			}
    
    			finally {
    				// Reset common introspection caches in Spring's core, since we
    				// might not ever need metadata for singleton beans anymore...
    				resetCommonCaches();
    			}
    		}
    	}

           有关Spring Bean生命周期最主要的方法有三个invokeBeanFactoryPostProcessors、registerBeanPostProcessors和finishBeanFactoryInitialization。

           其中invokeBeanFactoryPostProcessors方法会执行BeanFactoryPostProcessors后置处理器及其子接口BeanDefinitionRegistryPostProcessor,执行顺序先是执行BeanDefinitionRegistryPostProcessor接口的postProcessBeanDefinitionRegistry方法,然后执行BeanFactoryPostProcessor接口的postProcessBeanFactory方法。

          对于BeanDefinitionRegistryPostProcessor接口的postProcessBeanDefinitionRegistry方法,该步骤会扫描到指定包下面的标有注解的类,然后将其变成BeanDefinition对象,然后放到一个Spring中的Map中,用于下面创建Spring bean的时候使用这个BeanDefinition

           其中registerBeanPostProcessors方法根据实现了PriorityOrdered、Ordered接口,排序后注册所有的BeanPostProcessor后置处理器,主要用于Spring Bean创建时,执行这些后置处理器的方法,这也是Spring中提供的扩展点,让我们能够插手Spring bean创建过程。

    beanDefinition对象 -> Spring中的bean

            finishBeanFactoryInitialization是完成非懒加载的Spring bean的创建的工作,你要想说Spring的生命周期,不要整其他没用的,直接告诉他在该步骤中会有8个后置处理的方法4个后置处理器的类贯穿在对象的实例化、赋值、初始化、和销毁的过程中,这4个后置处理器出现的地方分别为:

     

       关于每个后置处理的作用如下:

                   

             首先看一下继承关系,InstantiationAwareBeanPostProcessor、SmartInstantiationAwareBeanPostProcessor、MergedBeanDefinitionPostProcessor直接或间接的继承BeanPostProcessor,而SmartInitializingSingleton则是单独的一个接口。

    一、InstantiationAwareBeanPostProcessor

    InstantiationAwareBeanPostProcessor接口继承BeanPostProcessor接口,它内部提供了3个方法,再加上BeanPostProcessor接口内部的2个方法,所以实现这个接口需要实现5个方法。InstantiationAwareBeanPostProcessor接口的主要作用在于目标对象的实例化过程中需要处理的事情,包括实例化对象的前后过程以及实例的属性设置

    在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean()方法的Object bean = resolveBeforeInstantiation(beanName, mbdToUse);方法里面执行了这个后置处理器

    二、SmartInstantiationAwareBeanPostProcessor

    智能实例化Bean后置处理器(继承InstantiationAwareBeanPostProcessor)

    三、MergedBeanDefinitionPostProcessor

    四、SmartInitializingSingleton

    智能初始化Singleton,该接口只有一个方法,是在所有的非懒加载单实例bean都成功创建并且放到Spring IOC容器之后进行执行的。

    下面按照图中的顺序进行说明每个后置处理的作用:

    1、InstantiationAwareBeanPostProcessor# postProcessBeforeInstantiation

    在目标对象实例化之前调用,方法的返回值类型是Object,我们可以返回任何类型的值。由于这个时候目标对象还未实例化,所以这个返回值可以用来代替原本该生成的目标对象的实例(一般都是代理对象)。如果该方法的返回值代替原本该生成的目标对象,后续只有postProcessAfterInitialization方法会调用,其它方法不再调用;否则按照正常的流程走

    2、SmartInstantiationAwareBeanPostProcessor# determineCandidateConstructors

    检测Bean的构造器,可以检测出多个候选构造器

    3、MergedBeanDefinitionPostProcessor# postProcessMergedBeanDefinition

    缓存bean的注入信息的后置处理器,仅仅是缓存或者干脆叫做查找更加合适,没有完成注入,注入是另外一个后置处理器的作用

    4、SmartInstantiationAwareBeanPostProcessor# getEarlyBeanReference

    循环引用的后置处理器,这个东西比较复杂, 获得提前暴露的bean引用。主要用于解决循环引用的问题,只有单例对象才会调用此方法,以后如果有时间,我会写一篇关于Spring是怎么处理循环依赖的,会将这个,现在你就只需要知道他能提前暴露bean就行了。

    5、InstantiationAwareBeanPostProcessor# postProcessAfterInstantiation

    方法在目标对象实例化之后调用,这个时候对象已经被实例化,但是该实例的属性还未被设置,都是null。如果该方法返回false,会忽略属性值的设置;如果返回true,会按照正常流程设置属性值。方法不管postProcessBeforeInstantiation方法的返回值是什么都会执行

    6、InstantiationAwareBeanPostProcessor# postProcessPropertie

    方法对属性值进行修改(这个时候属性值还未被设置,但是我们可以修改原本该设置进去的属性值)。如果postProcessAfterInstantiation方法返回false,该方法不会被调用。可以在该方法内完成对属性的自动注入(注意:在Spring5.1之前,完成属性自动注入的方法是postProcessPropertyValues方法,在5.1就开始使用postProcessPropertie方法了,如果发现不同也不必惊慌,就是改了一下方法名,内部逻辑一样的)(在这一步,会完成标注了@Autowired、@Resource注解的自动装配,如果有兴趣的同学可以看一下:Spring源码分析@Autowired、@Resource注解的区别,是从源码角度分析他们之间装配的不同,不过需要一点Spring的功底

    调用invokeInitMethods方法 

         先看代码invokeInitMethods方法的代码

    private void invokeAwareMethods(final String beanName, final Object bean) {
    		if (bean instanceof Aware) {
    			if (bean instanceof BeanNameAware) {
    				((BeanNameAware) bean).setBeanName(beanName);
    			}
    			if (bean instanceof BeanClassLoaderAware) {
    				ClassLoader bcl = getBeanClassLoader();
    				if (bcl != null) {
    					((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
    				}
    			}
    			if (bean instanceof BeanFactoryAware) {
    				((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
    			}
    		}
    	}

        该方法就是查看这个bean是否实现应该的Aware接口,如果实现了,则调用相应的接口。 

    7.BeanPostProcessor# postProcessBeforeInitialization

    该方法会在初始化之前进行执行,其中有一个实现类比较重要ApplicationContextAwareProcessor,该后置处理的一个作用就是当应用程序定义的Bean实现ApplicationContextAware接口时注入ApplicationContext对象:

    class ApplicationContextAwareProcessor implements BeanPostProcessor {
    
    	private final ConfigurableApplicationContext applicationContext;
    
    	private final StringValueResolver embeddedValueResolver;
    
    
    	/**
    	 * Create a new ApplicationContextAwareProcessor for the given context.
    	 */
    	public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
    		this.applicationContext = applicationContext;
    		this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());
    	}
    
    
    	@Override
    	@Nullable
    	public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
    		AccessControlContext acc = null;
    
    		if (System.getSecurityManager() != null &&
    				(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
    						bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
    						bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
    			acc = this.applicationContext.getBeanFactory().getAccessControlContext();
    		}
    
    		if (acc != null) {
    			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
    				invokeAwareInterfaces(bean);
    				return null;
    			}, acc);
    		}
    		else {
    			invokeAwareInterfaces(bean);
    		}
    
    		return bean;
    	}
    
    	private void invokeAwareInterfaces(Object bean) {
    		if (bean instanceof Aware) {  //判断该类是否是Aware的子类
    			if (bean instanceof EnvironmentAware) {
    
    				((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
    			}
    			if (bean instanceof EmbeddedValueResolverAware) {
    				((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
    			}
    			if (bean instanceof ResourceLoaderAware) {
    				((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
    			}
    			if (bean instanceof ApplicationEventPublisherAware) {
    				((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
    			}
    			if (bean instanceof MessageSourceAware) {
    				((MessageSourceAware) bean).setMessageSource(this.applicationContext);
    			}
    			//spring帮你set一个applicationContext对象
    			//所以当我们自己的一个对象实现了ApplicationContextAware对象只需要提供setter就能得到applicationContext对象
    			//此处应该有点赞加收藏
    			if (bean instanceof ApplicationContextAware) {
    				if (!bean.getClass().getSimpleName().equals("IndexDao"))
    				((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
    			}
    		}
    	}
    
    	@Override
    	public Object postProcessAfterInitialization(Object bean, String beanName) {
    		return bean;
    	}
    
    }
    

           看到这里你可能恍然大悟,原来调用BeanFactoryAware和ApplicationContextAware时,相应的处理是不同的,这个你可能看别人写的博客时,完全就没有介绍,,所以,你如果把这个不同点说出来,那么面试官就会认为你是看过源码的人。ApplicationContextAware是在一个BeanPostProcessor后置处理器的postProcessBeforeInitialization方法中进行执行的。

          回调执行bean的声明周期回调中的init方法,该步骤不做介绍,就是执行bean的init方法

          8.BeanPostProcessor# postProcessAfterInitialization

          该后置处理器的执行是在调用init方法后面进行执行,主要是判断该bean是否需要被AOP代理增强,如果需要的话,则会在该步骤返回一个代理对象。

         9.SmartInitializingSingleton# afterSingletonsInstantiated

          该方法会在所有的非懒加载单实例bean都成功创建并且放到Spring IOC容器之后,依次遍历所有的bean,如果当前这个bean是SmartInitializingSingleton的子类,那么就强转成SmartInitializingSingleton类,然后调用SmartInitializingSingleton的afterSingletonsInstantiated方法。

        查看一下DefaultListableBeanFactory#preInstantiateSingletons方法

    public void preInstantiateSingletons() throws BeansException {
    		// Iterate over a copy to allow for init methods which in turn register new bean definitions.
    		// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
    		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
    
    		// Trigger initialization of all non-lazy singleton beans...
            //1.遍历所有的beanDefinition对象,然后根据beanDefinition去创建对象,此步骤会完成当前
            //Spring容器中所有的bean,getBean方法会查看容器中是否有该bean,如果没有则去创建
    		for (String beanName : beanNames) {
    			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
    			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
    				if (isFactoryBean(beanName)) {
    					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
    					if (bean instanceof FactoryBean) {
    						final FactoryBean<?> factory = (FactoryBean<?>) bean;
    						boolean isEagerInit;
    						if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
    							isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
    											((SmartFactoryBean<?>) factory)::isEagerInit,
    									getAccessControlContext());
    						}
    						else {
    							isEagerInit = (factory instanceof SmartFactoryBean &&
    									((SmartFactoryBean<?>) factory).isEagerInit());
    						}
    						if (isEagerInit) {
    							getBean(beanName);
    						}
    					}
    				}
    				else {
    					getBean(beanName);
    				}
    			}
    		}
    
    		// Trigger post-initialization callback for all applicable beans...
                    //2.走到这里的时候,说明所有的bean都已经被成功创建,依次遍历所有的bean
    		for (String beanName : beanNames) {
    			Object singletonInstance = getSingleton(beanName);
                          //3.判断该bean是否为SmartInitializingSingleton接口的子类,如果是,则执行afterSingletonsInstantiated方法
    			if (singletonInstance instanceof SmartInitializingSingleton) {
    				final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
    				if (System.getSecurityManager() != null) {
    					AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
    						smartSingleton.afterSingletonsInstantiated();
    						return null;
    					}, getAccessControlContext());
    				}
    				else {
    					smartSingleton.afterSingletonsInstantiated();
    				}
    			}
    		}
    	}

           对于SmartInitializingSingleton# afterSingletonsInstantiated方法,是在所有的bean完成之后进行调用的,这个扩展点可以让我们自己很轻松的自定义注解,完成我们想要实现的逻辑,比如使用@EventListener注解实现事件监听,其底层就是童年各国SmartInitializingSingleton# afterSingletonsInstantiated来实现的,关于@EventListener可以自行百度,以后有时间再进行分析,而且我在看公司内部基于Spring开发的框架时,也用到了SmartInitializingSingleton进行定义注解,实现自己的逻辑,对于Spring提供的这么多扩展点,感觉就这个我能用到一点(还是太辣鸡o(╥﹏╥)o),所以对于这个重点说一下。

         此时,Spring Bean的生命周期就算说完了,如果你能把上面的步骤将给面试官听,那么保证是没有问题的,在回答这个问题的时候可以从下面几个点思考:

         1.普通Java类是在哪一步变成beanDefinition的

         2.有8个后置处理器方法4个后置处理器,贯穿了对象的创建->属性赋值->初始化->销毁

         3.然后再说处理器方法执行的时机和作用

         4.invokeInitMethods执行的Aware和BeanPostProcessor# postProcessBeforeInitialization方法执行的aware

    总结

    Spring Bean的生命周期分为四个阶段多个扩展点。扩展点又可以分为影响多个Bean影响单个Bean。整理如下:
    四个阶段

    • 实例化 Instantiation
    • 属性赋值 Populate
    • 初始化 Initialization
    • 销毁 Destruction

    多个扩展点

    • 影响多个Bean
      • BeanPostProcessor 
      1. postProcessBeforeInitialization
      2. postProcessAfterInitialization
      • InstantiationAwareBeanPostProcessor
      1. postProcessBeforeInstantiation
      2. postProcessAfterInstantiation
      3. postProcessPropertyValues
      • MergedBeanDefinitionPostProcessor
      1. postProcessMergedBeanDefinition
      • SmartInstantiationAwareBeanPostProcessor
      1. determineCandidateConstructors
      2. getEarlyBeanReference
    • 影响单个Bean
      • Aware
        • Aware Group1(调用invokeInitMethods方法
          • BeanNameAware
          • BeanClassLoaderAware
          • BeanFactoryAware
        • Aware Group2(调用Aware和BeanPostProcessor# postProcessBeforeInitialization方法
          • EnvironmentAware
          • EmbeddedValueResolverAware
          • ApplicationContextAware(ResourceLoaderAware\ApplicationEventPublisherAware\MessageSourceAware)
      • 生命周期
        • InitializingBean
        • DisposableBean

    最后建议:

       其实想要清楚Spring Bean的周期,那么还是要看一下Spring的源码,看过源码后你会知道Spring中是怎么解决属性的循环依赖的(现在好多博客都说过循环依赖,基本都是你抄我,我抄你,没有领悟循环依赖的精髓,只知道Spring使用3个集合来解决,却不知道为啥是3个,为啥不能是2个)、@Configuration实现的原理等等,这些问题只有真正看多Spring源码的人才能很好的回答,所以建议大家还是需要看看Spring源码的。

    展开全文
  • 博主声明: 转载请开头附加本文链接及作者信息,并标记为转载。... 学习 Android 时候,通常一开始学习的都是它的生命周期,谁让我们第一个创建的就是 MainActivity 类呢。学习 Activity 就要从它...

    博主声明:

    转载请在开头附加本文链接及作者信息,并标记为转载。本文由博主 威威喵 原创,请多支持与指教。

    本文首发于此   博主威威喵  |  博客主页https://blog.csdn.net/smile_running

        在学习 Android 时候,通常一开始学习的都是它的生命周期,谁让我们第一个创建的就是 MainActivity 类呢。学习 Activity 就要从它的生命周期入手,这是我们了解它最快的一种方式,了解它的生命周期,大概就可以知道它的工作时间。比如,我们创建应该 MainActivity 就要重写它的 onCreate 方法,在 onCreate 中通过 setContentView 设置布局文件才能够真正的感受到 Activity 的存在,如果没有 setContentView 就是灰白灰白的,空空如也。

        这次呢。我们先不去管它 setContentView 干了哪些事情,先来把 Activity 的几种生命周期及情境搞明白。百度偷了一张图过来,自己懒得画了,将就看吧:

         这张图,从上到下罗列了 Activity 的几种生命周期,它的几种生命周期分为四中状态,如下图:

    下面是一些概念性的描述,蛮看吧,反正也记不住!

    onCreate : 该方法是在Activity被创建时回调,它是生命周期第一个调用的方法,我们在创建Activity时一般都需要重写该方法,然后在该方法中做一些初始化的操作,如通过setContentView设置界面布局的资源,初始化所需要的组件信息等。 


    onStart : 此方法被回调时表示Activity正在启动,此时Activity已处于可见状态,只是还没有在前台显示,因此无法与用户进行交互。可以简单理解为Activity已显示而我们无法看见摆了。 


    onResume : 当此方法回调时,则说明Activity已在前台可见,可与用户交互了(处于前面所说的Active/Running形态),onResume方法与onStart的相同点是两者都表示Activity可见,只不过onStart回调时Activity还是后台无法与用户交互,而onResume则已显示在前台,可与用户交互。当然从流程图,我们也可以看出当Activity停止后(onPause方法和onStop方法被调用),重新回到前台时也会调用onResume方法,因此我们也可以在onResume方法中初始化一些资源,比如重新初始化在onPause或者onStop方法中释放的资源。 


    onPause : 此方法被回调时则表示Activity正在停止(Paused形态),一般情况下onStop方法会紧接着被回调。但通过流程图我们还可以看到一种情况是onPause方法执行后直接执行了onResume方法,这属于比较极端的现象了,这可能是用户操作使当前Activity退居后台后又迅速地再回到到当前的Activity,此时onResume方法就会被回调。当然,在onPause方法中我们可以做一些数据存储或者动画停止或者资源回收的操作,但是不能太耗时,因为这可能会影响到新的Activity的显示——onPause方法执行完成后,新Activity的onResume方法才会被执行。 


    onStop : 一般在onPause方法执行完成直接执行,表示Activity即将停止或者完全被覆盖(Stopped形态),此时Activity不可见,仅在后台运行。同样地,在onStop方法可以做一些资源释放的操作(不能太耗时)。 


    onRestart :表示Activity正在重新启动,当Activity由不可见变为可见状态时,该方法被回调。这种情况一般是用户打开了一个新的Activity时,当前的Activity就会被暂停(onPause和onStop被执行了),接着又回到当前Activity页面时,onRestart方法就会被回调。 


    onDestroy :此时Activity正在被销毁,也是生命周期最后一个执行的方法,一般我们可以在此方法中做一些回收工作和最终的资源释放。 

    其实,说白了就对应几种状态(创建和销毁状态、可见与不可见状态、是不是可操作状态),如下图:

         每一种生命周期都两两相对,除了 onRestart 比较特殊,单身狗,被孤立了。反正,这样看是很难记住的,太过于概念化的东西容易忘记,必须手动操作一波,记得更牢固。

        来吧,实际操作一下。书本上的老套路,一个 MainActivity,一个 SecondActivity,也许有人会觉得能比书上详细吗?这我不敢说,但是我看的基本入门书,好多都没讲到,也就是介绍一下生命周期而已,一些情境都没涉及到,如果你看下去,就会知道有哪些区别了。

        首先,我们启动一个 Activity 时,第一个启动的是 Application,毫无疑问,Application 的生命周期是最长的,也就是你点开那个桌面小图标时,它就已经启动了。于此同时,Application 就会寻找它下面一级带有 LAUNCHER 的过滤器,然后启动的就是这个 Activity,参考下面的 manifest 代码:

        <application
            android:name=".App"
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme"
            tools:ignore="AllowBackup,GoogleAppIndexingWarning">
            
            <activity android:name=".MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
            <activity android:name=".SecondActivity" />
            
        </application>

        这里就解释了,Activity 并不是平白无故的启动,只有在清单文件中注册过的才能启动,当然,一个程序是可以不用任何 Activity 的。

        Application 的启动,通常就只有 onCreate 是它的生命周期,在低内存下还会执行其他的方法。Application onCreate 之后,就轮到 MainActivity 的 onCreate,下面来看这一段截图:

     1、当一个 Activity 启动完成时,它的生命周期如上图所示

     onCreate -> onStart 从不可见 到 可见 -> onResume 从不可交互 到 可交互。

    2、点击 helloword 启动了 SecondActivity ,生命周期的变化如下:

         MainActivity 没有执行 finish() 方法, 变成了 onStop 停止状态,意味着不可见,不可交互。启动 SecondActivity 生命周期是一样,不再说了。 

    3、当点击 back 时,生命周期变化如下:

        首先,它执行的是 SecondActivity 的 onBackPressed 的方法返回。可以看到,MainActivity 在前面执行到 onStop,当按下 back 时,它执行的是 onRestart -> onStart -> onResume

        而 SecondActivity 执行了 onStop -> onDestroy ,表示由停止状态 被 摧毁了。

    4、当在 MainActivity 里面执行了 finish() 方法,将 MainActivity 关闭了,又会怎么样呢?

     可以看到,MainActivity finish 后,不仅执行了 onStop,还执行了 onDestroy,彻底的把 MainActivity 给摧毁了。

    5、MainActivity 被摧毁了,这时再按 back 会怎么样呢?

     显然 MainActivity 已经没了,两个 Activity 都被摧毁了,最后也只能回到桌面上了。

    6、这个时候,再此点击桌面图片,会再次创建 Application 吗?

     答案是不会的,因为我们的 Application 并没有被杀死,所以这里的 App 的 onCreate 就不会再执行了。

    7、那如何保证彻底退出应用程序呢,保证杀死 app 呢?

    我们通过 SecondActivity 的 onBackPressed() 方法内加入: System.exit(0) ,表示杀死当前应用,彻底退出程序,看看效果:

     点击 back,再次点击桌面图片,发现 App 的 onCreate 执行了,表明我们刚刚成功的杀死这个进程了。

    8、切换任务管理快捷键时,生命周期会有什么变化?

    9、按下 home 有什么变化呢?

     原来是这样的,是不是发现了什么规律呢?

    如果没有执行 finish,那么 Activity 就不会 onDestroy,而按下 back 时,相当于 finish 了,必定执行 onDestroy

    当按下 home 和 任务管理 时,这时 Activity 处于不可见状态,但又没有被 finish,所以它只会到 onStop,然后等待被 onReStart,如果这个期间被结束任务了,那它会执行 onDestroy 吗?

     答案是不会的,看上面一个图,从任务里面杀死了 app,并不会执行 onDestroy。

        WTF,写到最后,才发现我前面漏掉了一个 onPause 生命周期方法。由于图太多了,懒得重新弄了。onPause 是会在 onStop 之前执行的,如果 onStop 执行了,那么必定会执行 onPause,自己试一试吧,多的不说了。Activity 息息相关的也就这几种场景的生命周期,属于正常的生命周期。

        还有就是 System.exit(0) 强行把 app 杀死了,这样的话,就会导致 onPause、onStop 、onDestroy 等生命周期没办法执行,如果要保存 Activity 一些数据的话,这样没法从  onPause、onStop 、onDestroy 中获取数据。

        System.exit(0)也是会有问题的,比如在开启 SecondActivity 时,没有把 MainActivity 给 finish 调,这时它又会启动一个新的 MainActivity ,比如出现这样的情况:

     这中情况发生的概率也很高,如果对 System.exit(0) 不了解的话,就会出现问题。解决的方式就是最好新建一个管理所以 Activity 的工具类,在真正需要退出 app 的地方,把 Activity 全部都 finish 掉,然后再 System.exit(0) 就不会有问题了。

    还有一种是 ANR 的情况发生,如果等待能完成到还好,如果完成不了,那么这种情况下也不会执行 onPause、onStop 、onDestroy,比如用户在输入完成后提交发生了 ANR,那么这些刚刚填的信息应该如何保证能够保存呢?

     当然,我们可以通过监听控件的事件来保存,这是一种办法。

    展开全文
  • 六、生命游戏 原文:Chapter 6 Game of Life 译者:飞龙 协议:CC BY-NC-SA 4.0... 像上的一些 CA 一样,GoL 遵循简单的规则并产生令惊讶的复杂行为。 就像沃尔夫勒姆的规则 110 一样,事实证明 Go...
  • 一、数据科学的生命周期 原文:DS-100/textbook/notebooks/ch01 译者:飞龙 协议:CC BY-NC-SA 4.0 自豪地采用谷歌翻译 ...数据科学,我们使用大量不同的数据集来对世界...提出一个问题 获取和清理数据...
  • 一个认真生活过的。自称“职业病人”的他,坦然接受命运的不公,微笑面对人生的愁苦,他说道:“消除痛苦的唯一办法就是找到自己的救赎之路。”而他那些充当救赎之路的文字,有着踏过痛苦后贴近大地的力量。...
  • 12-15 14:20 主持:非常感谢各位百忙当中来到图书馆这地方参加柴静新书首发式,当我接到她电话的时候也特别高兴,我突然有种被看得起的感觉,好久没有这样的感觉,我心里此时此刻虽然激动不
  • 生命有什么可能 读书笔记

    千次阅读 2015-08-02 23:43:39
    1.人生的三种策略:遇见、定位和创造Chapter1 人生金三角:热爱的领域努力地玩1.生涯管理要素:兴趣、能力、价值观兴趣:提升兴趣让我们持续发现新的事物,给...三叶草Chapter2 只要下定决心,任何人都能活得有趣1.
  • Android开发艺术探索——第章:Activity的生命周期和启动模式 怀着无比崇敬的心情翻开了这本书,路漫漫其修远兮,程序人生,为自己加油! .序 作为这本书的第章,主席还是把Activity搬上来了,也确实,和...
  • 另外,我平时也无开发过程也会发现,每个人选择的那个生命周期阶段去异步请求数据总会不一样,因此引发思考,到底哪个阶段更适合异步请求数据呢?产品设计和用户体验方面又会有哪些影响?本篇记录就是为了解决...
  • 【转】以太坊交易的生命周期

    千次阅读 2019-05-12 07:56:39
    你有没有想过要了解当你在以太坊执行交易之时到底发生了什么?让我们通过则交易例子来解答这问题。本文包括如下内容。 以太坊交易的端到端遍历,即从你的浏览器/控制台出发进入以太坊网络,然后再回到你的...
  • 新的生命周期函数getDerivedStateFromProps...React16.4包含一个关于getDerivedStateFromProps的bugfix,可以让React组件的一些现有bug以更一致的方式重现。如果这次变动导致了您的应用程序使用了反模式,并且出现...
  • 所以,无论一个精神病人的逻辑多么严密,思维多么清晰,也不要太过吃惊。” 我是一个精神鉴定医师,上面这段话是我毕业时导师对我的叮嘱,也一直是我的座右铭。但,每个都有自己不足为外人道的小小阴暗面,我的...
  • 迷茫,仿佛就是一团乌云,笼罩一个心中怀有抱负的的头上。每当夜深人静,思绪归于对自己人生未来的严肃思考,不知去往何处的苦闷,再加之不断迫近的升学/就业选择的压力,尤其是一些看似周密的计划,由于想把...
  • android Activity 的7个生命周期

    万次阅读 2012-12-04 09:45:13
    循环 提供两关于Activity的生命周期模型图示帮助理解:     图1      图2 从图2所示的Activity生命周期不难看出,
  • jvm的生命周期和java类的生命周期

    千次阅读 2018-06-14 00:01:33
    1.jvm的生命周期一个运行时的的java虚拟机实例的天职就是运行一个java程序。1.1.JVM实例的诞生 当一个程序启动,伴随的就是一个jvm实例的诞生,当这个程序关闭退出,这个jvm实例就随之消亡。如果同一台机器上运行...
  • 程序员,一个刚刚诞生不过三四十年的职业,很多眼里一个象征着白领高薪的行业,却没有多少知道,程序员又是一个高危行业,又是一个每日与深夜凌晨约会的行业  从过了年初八开始回到学校,开始跟着老师做某市...
  • 这里有一道经典的面试题:“一个线程两次调用start()方法会出现什么情况?谈谈线程的生命周期和状态转移。” 我们就以这道题目为切入点深入聊聊线程吧。 典型回答 Java的线程是不允许启动两次的,第二次调用必然会...
  • Java 类的生命周期详解

    千次阅读 2012-05-05 08:40:21
    、 引 言 最近有位细心的朋友阅读笔者的文章时,对java类的生命周期问题有一些疑惑,笔者打开百度搜了一下相关的问题,看到网上的资料很少有把这问题讲明白的,主要是因为目前国内java方面的教材大多只是告诉...
  • Activity的生命周期模型Google提供的官方文档上有比较详细的一个图示   public class HelloActivity extends Activity { public static final String TAG = "HelloActivity"; /** * 第一个被运行...
  • Java 对象生命周期和类生命周期

    万次阅读 2015-04-21 16:57:30
    JVM运行空间,对象的整个生命周期大致可以分为7阶段:创建阶段(Creation)、应用阶段(Using)、不可视阶段(Invisible)、不可到达阶段(Unreachable)、可收集阶段(Collected)、终结阶段(Finalized)与...
  • 你在寻找什么

    万次阅读 2007-08-16 21:01:00
    annajully (星语心雨), 信区: Girls标 题: [合集]校园恋爱学分[转载]发信站: 南京大学小百合站 (Fri Jan 25 16:14:55 2002), 站内信件iceleaf (请赐予我offer吧) 于Fri Jan 25 13:09:43 2002)提到:你在寻找什么 ...
  • 大家好,我是 Oracle首席工程师...今天我要问的问题是,一个线程两次调用start()方法会出现什么情况?谈谈线程的生命周期和状态转移。   典型回答 Java的线程是不允许启动两次的,第二次调用必然会抛出Illeg...
  • C语言的作用域和生命周期

    万次阅读 2010-10-25 15:37:00
    C语言的作用域和生存周期Author:天之枫 ...这里涉及到返回值的问题,至于是返回值传递完成之后销毁呢,还是将返回值拷贝到一个临时变量,销毁全部的局部变量,再将临时变量返回呢,这是由编译器的设计者所
  • bpmn定义之camunda bpm生命周期

    万次阅读 2020-06-02 13:31:26
    然而,您可能还注意到流程建模并不是camunda bpm生命周期一个阶段。这是因为流程建模是一种影响所有阶段的方法,尤其是流程文档和流程设计。作为顾问,我们经常遇到这样的,他们试图将流程建模作为一个阶段...
  • 生命与未来

    千次阅读 2009-02-01 21:56:00
    生命与未来作者: 董逋 整理: 邦畿千里前 言 “生命”是一个不变的话题,而这个话题就我们身上。我们之所以快乐,因为我们拥有生命,即使是痛苦,那也是生命的证实。生命很近,也很远。我们都有生命,可生命对...
  • 如何让机器自动针对问题...本文介绍了种利用人工生命和遗传算法自动发现深度学习神经网络最优结构的方法,实验结果表明,这种方法通过少量计算可以自动发现和人类手工设计出较好的神经网络结构相近性能的神经网络。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 173,101
精华内容 69,240
关键字:

任何一个出现在你生命中的人