为了保证制作简历的安全性和流畅性,建议您使用Chrome浏览器进行访问
# 先马后看
别犹豫了,马就完事了。在这里每个人都是分享者,你可以分享技能/干货/安装包/电影/图书等等宇宙内的所有资源。
···
1627人正在讨论
#
软绵绵的机器鬼
安徽大学·2022届

程序员常见智力题30道

二进制问题 金条问题 有个商人雇用了一位手艺高超的工匠了为他做一个精致产品,工作一星期七天的代价是一条金条。商人手头上有一条金条,刚好有可以付工匠一星期的工钱。但工匠要求工钱要按每天来付。虽然他并不急着用钱,每天有钱进账,老人心里总是踏实一些。但商人家中有个规矩,金条每星期只能切二刀。后来商人想出以了个切割金条的办法,满足了工匠的要求。你知道商人是怎么切割金条才能满足工匠的吗? 切成1、2、4。这三个二进制数的组合能表示0-7中的任何一个。 老鼠和毒药 实验室有100个瓶子,其中有一瓶装有慢性毒药(第3天发作),另外99瓶装有蒸馏水。请问至少需要多少只小白鼠才能在3天内找出哪一瓶是慢性毒药? 利用二进制来做,最少的老鼠数量就是计算2的多少次方大于等于瓶子数量,例如本题为7。对100瓶进行二进制编码,这样可以排列出1xxxxxx,x1xxxxxx,...,xxxxxx1这样的七组序列,如果是1xxxxxx和x1xxxxx的老鼠死了,表示1100000有毒。 水桶问题 倒水问题1 一个装了10L水的桶,一个7L的空桶,一个3L的空桶,怎样变成2个5L 初始时为10,0,0。第二步7,0,3。然后7,3,0。然后4,3,3。然后4,6,0。然后1,6,3。然后1,7,2。然后8,0,2。然后8,2,0。然后5,2,3。然后5,5,0。 倒水问题2 如果你有无穷多的水,一个3夸脱的和一个5夸脱的提桶,你如何准确称出 4夸脱的水? 初始时0,5然后3,2然后0,2然后2,0然后2,5然后1,4 舀酒问题 据说有人给酒肆的老板娘出了一个难题:此人明明知道店里只有两个舀酒的勺子,分别能舀7两和11两酒,却硬要老板娘卖给他2两酒。聪明的老板娘毫不含糊,用这两个勺子在酒缸里舀酒,并倒来倒去,居然量出了2两酒,聪明的你能做到吗? 初始0,11然后7,4然后0,4然后4,0然后4,11然后7,8然后0,8然后7,1然后0,1------然后1,11然后7,5然后0,5然后5,0然后5,11,然后7,9然后0,9然后7,2 钱问题 赚钱问题 一个人花8块钱买了一只鸡,9块钱卖掉了,然后他觉得不划算,花10块钱又买回来了,11块卖给另外一个人。问他赚了多少? -8+9-10+11=2 假钱问题 老王30买了双鞋,35卖,客人花100买,老王没零钱于是向老李换了100.补给客人后,客人走远后老李突然说是假钱,于是老王补偿给了老李,问老王一共亏了多少? 卖鞋赚了35-30=5假钱赔了100一共亏95 取硬币问题 30枚面值不全相同的硬币摆成一排,甲、乙两个人轮流选择这排硬币的其中一端,并取走最外边的那枚硬币。如果你先取硬币,能保证得到的钱不会比对手少吗? 先取者可以让自己总是取奇数位置上的硬币或者总是取偶数位置上的硬币。数一数是奇数位置上的面值总和多还是偶数位置上的面值总和多,然后总是取这些位置上的硬币就可以了。 旅馆问题 有三个人去住旅馆,住三间房,每一间房10元,于是他们一共付给老板10元,于是他们一共付给老板10元,于是他们一共付给老板30,第二天,老板觉得三间房只需要25元就够了于是叫小弟退回25元就够了于是叫小弟退回25元就够了于是叫小弟退回5给三位客人,谁知小弟贪心,只退回每人1,自己偷偷拿了1,自己偷偷拿了1,自己偷偷拿了2,这样一来便等于那三位客人每人各花了九元,于是三个人一共花了27,再加上小弟独吞了不27,再加上小弟独吞了不27,再加上小弟独吞了不2,总共是29。可是当初他们三个人一共付出29。可是当初他们三个人一共付出29。可是当初他们三个人一共付出30那么还有$1呢? 他们所消费的27元里已经包括小弟贪污的2元了,再加退还的3元=30元。:这30元现在的分布是:老板拿25元,伙计拿2元,三人各拿1元,正好! 蓝眼问题 蓝眼睛问题 有个岛上住着一群人,有一天来了个游客,定了一条奇怪的规矩:所有蓝眼睛的人都必须尽快离开这个岛。每晚8点会有一个航班离岛。每个人都看得见别人眼睛的颜色,但不知道自己的(别人也不可以告知)。此外,他们不知道岛上到底有多少人是蓝眼睛的,只知道至少有一个人的眼睛是蓝色的。所有蓝眼睛的人要花几天才能离开这个岛? 有多少个蓝眼睛的人就会花多少天。 c=1假设岛上所有人都是聪明的,蓝眼睛的人四处观察之后,发现没有人是蓝眼睛的。但他知道至少有一人是蓝眼睛的,于是就能推导出自己一定是蓝眼睛的。因此,他会搭乘当晚的飞机离开。 c=2两个蓝眼睛的人看到对方,并不确定c是1还是2,但是由上一种情况,他们知道,如果c = 1,那个蓝眼睛的人第一晚就会离岛。因此,发现另一个蓝眼睛的人仍在岛上,他一定能推断出c = 2,也就意味着他自己也是蓝眼睛的。于是,两个蓝眼睛的人都会在第二晚离岛。 c>2逐步提高c时,我们可以看出上述逻辑仍旧适用。如果c = 3,那么,这三个人会立即意识到有2到3人是蓝眼睛的。如果有两人是蓝眼睛的,那么这两人会在第二晚离岛。因此,如果过了第二晚另外两人还在岛上,每个蓝眼睛的人都能推断出c = 3,因此这三人都有蓝眼睛。他们会在第三晚离岛。 不论c为什么值,都可以套用这个模式。所以,如果有c人是蓝眼睛的,则所有蓝眼睛的人要用c晚才能离岛,且都在同一晚离开。 疯狗问题(跟蓝眼睛一样) 有50家人家,每家一条狗。有一天警察通知,50条狗当中有病狗,行为和正常狗不一样。每人只能通过观察别人家的狗来判断自己家的狗是否生病,而不能看自己家的狗,如果判断出自己家的狗病了,就必须当天一枪打死自己家的狗。结果,第一天没有***,第二天没有***,第三天开始一阵枪响,问:一共死了几条狗? 死了3条(第几天枪响就有几条)。从有一条不正常的狗开始,显然第一天将会听到一声枪响。这里的要点是你只需站在那条不正常狗的主人的角度考虑。有两条的话思路继续,只考虑有两条不正常狗的人,其余人无需考虑。通过第一天他们了解了对方的信息。第二天杀死自己的狗。换句话说每个人需要一天的时间证明自己的狗是正常的。有三条的话,同样只考虑那三个人,其中每一个人需要两天的时间证明自己的狗是正常的狗。 耳光问题(跟蓝眼睛一样) 一群人开舞会,每人头上都戴着一顶帽子。帽子只有黑白两种,黑的至少有一顶。每个人都能看到其他人帽子的颜色,却看不到自己的。主持人先让大家看看别人头上戴的是什么帽子,然后关灯,如果有人认为自己戴的是黑帽子,就打自己一个耳光。第一次关灯,没有声音。于是再开灯,大家再看一遍,关灯时仍然鸦雀无声。一直到第三次关灯,才有劈劈啪啪打耳光的声音响起。问有多少人戴着黑帽子?答案:有三个人戴黑帽。假设有N个人戴黑帽,当N=1时,戴黑帽的人看见别人都为白则能肯定自己为黑。于是第一次关灯就应该有声。可以断定N>1。对于每个戴黑帽的人来说,他能看见N-1顶黑帽,并由此假定自己为白。但等待N-1次还没有人打自己以后,每个戴黑人都能知道自己也是黑的了。所以第N次关灯就有N个人打自己。 时间问题 蜡烛燃烧问题 两根蜡烛,燃烧完都需要1小时,怎么确定15分钟是多久? 点燃第一根的一端,第二根的两端。第二根烧完代表半小时后,点燃第一根另一端,烧完代表15分钟。 重量问题 乒乓球重量 8个乒乓球,其中一个重,有一个秤,问至少几次能够找出重的那个乒乓球 2次,分成3堆,3,3,2。①称3和3,如果一样重,代表重的在2。②称2个那一堆的。①称3和3,不一样重,重的在3里面重的那堆。②3个里面随便取2个,一样重,第三个重。不一样重,重的那个就是。 盐重量问题 有7克、2克砝码各一个,天平一只,如何只用这些物品五次内将140克的盐分成50、90克各一份? 第一次:先分成70和70第二次:通过7和2砝码将70分成9和61第三次:通过9克盐和2砝码将61分成50和11 药丸问题 有20瓶药丸,其中19瓶装有1克/粒的药丸,余下一瓶装有1.1克/粒的药丸。给你一台称重精准的天平,怎么找出比较重的那瓶药丸?天平只能用一次。 从药瓶#1取出一粒药丸,从药瓶#2取出两粒,从药瓶#3取出三粒,依此类推。如果每粒药丸均重1克,则称得总重量为210克(1 + 2 + … + 20 = 20 * 21 / 2 = 210),“多出来的”重量必定来自每粒多0.1克的药丸。 药瓶的编号可由算式(weight - 210) / 0.1 得出。因此,若这堆药丸称得重量为211.3克,则药瓶#13装有较重的药丸。 药丸问题2 你有四个装药丸的罐子,每个药丸都有一定的重量,被污染的药丸是没被污染的重量+1.只称量一次,如何判断哪个罐子的药被污染了? 答:从第一盒中取出一颗,第二盒中取出2 颗,第三盒中取出三颗。 依次类推,称其总量。减去10,多的数字就是药丸罐子序号。 数学问题 概率问题1 一个家庭有两个小孩,其中有一个是女孩,问另一个也是女孩的概率(假定生男生女的概率一样) 1/3样本空间为(男男)(女女)(男女)(女男)A=(已知其中一个是女孩)=)(女女)(男女)(女男)B=(另一个也是女孩)=(女女)于是P(B/A)=P(AB)/P(A)=(1/4)/(3/4)=1/3 概率问题2 你有两个罐子,每个罐子各有若干红色弹球和蓝色弹球,两个罐子共有50个红色弹球,50个蓝色弹球,随机选出一个罐子,随机从中选取出一个弹球,要使取出的是红球的概率最大,一开始两个罐子应放几个红球,几个蓝球?在你的计划中,得到红球的准确几率是多少? 一个罐子放1红,一个罐子放49红和50蓝,这样得到红球的概率接近3/4。 扑克牌问题 54张扑克牌,其中有十张是翻过来的。现在把你的眼睛蒙上,让你把扑克牌分成两叠(两叠的多少可以不一样)。要求在两叠中翻过来的扑克牌是相等的。请问该怎么做? 第一步,你在这54张牌中任意取出10张,现在,扑克牌分成了两叠。44张和10张;第二步,44张那叠不动,将10张这叠每张都翻过来,便得到了符合条件的两叠牌。 解释:第一步之后,设44张那叠中正面牌x张,10张那叠中正面牌则为10-x张。第二步之后,44张那叠中正面牌保持x张,10张那叠反过来了:反面牌为10-x张,正面牌x张。 扔鸡蛋问题 有栋建筑物高100层。若从第N层或更高的楼层扔下来,鸡蛋就会破掉。若从第N层以下的楼层扔下来则不会破掉。给你2个鸡蛋,请找出N,并要求最差情况下扔鸡蛋的次数为最少。 14次 首先,让我们试着从10层开始扔鸡蛋,然后是20层,等等。如果鸡蛋1第一次扔下楼(10层)就破掉了,那么,最多需要扔10次。如果鸡蛋1最后一次扔下楼(100层)才破掉,那么,最多要扔19次(10、20、…、90、100层,然后是91到99层)。这么做也挺不错,但我们只考虑了绝对最差情况。我们应该进行“负载均衡”,让这两种情况下扔鸡蛋的次数更均匀。 我们的目标是设计一种扔鸡蛋的方法,使得扔鸡蛋1时,不论是在第一次还是最后一次扔下楼才破掉,次数越稳定越好。(1) 完美负载均衡的方法应该是,扔鸡蛋1的次数加上扔鸡蛋2的次数,不论什么时候都一样,不管鸡蛋1是从哪层楼扔下时破掉的。(2) 若有这种扔法,每次鸡蛋1多扔一次,鸡蛋2就可以少扔一次。(3) 因此,每丢一次鸡蛋1,就应该减少鸡蛋2可能需要扔下楼的次数。例如,如果鸡蛋1先从20层往下扔(不破),然后从30层扔下楼(破),此时鸡蛋2可能就要扔9次(从21到29 一次次试)。若鸡蛋1再扔一次,我们必须让鸡蛋2扔下楼的次数降为8次。也就是说,我们必须让鸡蛋1从39层扔下楼。(4) 由此可知,鸡蛋1必须从X层开始往下扔,然后再往上增加X-1层……直至到达100层。(5) 求解方程式X + (X-1) + (X-2) + … + 1 = 100,得到X (X + 1) / 2 = 100 → X = 14。 (直接设要X次,假如X 和X-1这两次了 则再加X-2 总共还是X次, 次数总为X)我们先从14层开始,然后是27层,接着是39层,依此类推,最差情况下鸡蛋要扔14次。 其他情况也是一样的只需要求X (X + 1) / 2 = 楼层数量的X大约值即可。 填数字 0 1 2 3 4 5 6 7 8 9_ _ _ _ _ _ _ _ _ _ 在横线上填写数字,使之符合要求。要求如下:对应的数字下填入的数,代表上面的数在下面出现的次数,比如3下面是1,代表3要在下面出现一次。 正确答案是: 6 2 1 0 0 0 1 0 0 0 规律 1,11,21,1211,111221,下一个数是什么? 下行是对上一行的解释 所以新的应该是3个1 2个2 1个1 :312211 猜数字问题 教授选出两个从2到9的数,把它们的和告诉学生甲,把它们的积告诉学生乙,让他们轮流猜这两个数, 甲说:“我猜不出”, 乙说:“我猜不出”, 甲说:“我猜到了”, 乙说:“我也猜到了”, 问这两个数是多少? 3和4。设两个数为n1,n2,n1> =n2,甲听到的数为n=n1 n2,乙听到的数为m=n1*n2,证明n1=3,n2=4是唯一解。 证明:要证以上命题为真,不妨先证n=7 1)必要性:   i) n> 5 是显然的,因为n <4不可能,n=4或者n=5甲都不可能回答不知道   ii) n> 6 因为如果n=6的话,那么甲虽然不知道(不确定2 4还是3 3)但是无论是2,4还是3,3乙都不可能说不知道(m=8或者m=9的话乙说不知道是没有道理的)   iii) n <8 因为如果n> =8的话,就可以将n分解成 n=4 x 和 n=6 (x-2),那么m可以是4x也可以是6(x-2)而4x=6(x-2)的必要条件是x=6即n=10,那样n又可以分解成8 2,所以总之当n> =8时,n至少可以分解成两种不同的合数之和,这样乙说不知道的时候,甲就没有理由马上说知道。以上证明了必要性。2)充分性当n=7时,n可以分解成2 5或3 4显然2 5不符合题意,舍去,容易判断出3 4符合题意,m=12,证毕于是得到n=7 m=12 n1=3 n2=4是唯一解。 其他问题 水果标签问题 3个箱子里面放了 苹果,梨子,苹果加梨子,标签全错误,只能选择查看一箱的水果来改正所有标签 查看贴苹果和梨标签那一个,如果拿出来的是苹果,代表这一箱只有苹果,因为如果是苹果和梨就代表标签没错了。那么剩下的两箱就是梨,苹果和梨,剩下的标签是梨,苹果,由于标签全错,所以贴着苹果的是梨,贴着梨的是苹果和梨。如果拿出来的是梨,同理代表这一箱只有梨。那么剩下的两箱就是苹果,苹果和梨,剩下的标签就是苹果,梨。由于标签全错,贴着苹果的就是苹果和梨,贴着梨的就是苹果。 便士标签问题(和水果标签一样) 假设在桌上有三个密封的盒,一个盒中有2枚银币(1银币=10便士),一个盒中有2枚镍币(1镍币=5便士),还有一个盒中有1枚银币和1枚镍币。这些盒子被标上10便士、 15便士和20便士,但每个标签都是错误的。允许你从一个盒中拿出1枚硬币放在盒前,看到这枚硬币,你能否说出每个盒内装的东西呢? 吃药问题 某种药方要求非常严格,你每天需要同时服用A、B两种药片各一颗,不能多也不能少。这种药非常贵,你不希望有任何一点的浪费。一天,你打开装药片A的药瓶,倒出一粒药片放在手心;然后打开另一个药瓶,但不小心倒出了两粒药片。现在,你手心上有一颗药片A,两颗药片B,并且你无法区别哪个是A,哪个是B。你如何才能严格遵循药方服用药片,并且不能有任何的浪费? 把手上的三片药各自切成两半,分成两堆摆放。再取出一粒药片A,也把它切成两半,然后在每一堆里加上半片的A。现在,每一堆药片恰好包含两个半片的A和两个半片的B。一天服用其中一堆即可。 硬币问题 如何用一枚硬币等概率地产生一个1到3之间的随机整数?如果这枚硬币是不公正的呢?答案:如果是公正的硬币,则投掷两次,“正反”为1,“反正”为2,“正正”为3,“反反”重来。 如果是不公正的硬币,注意到出现“正反”和“反正”的概率一样,因此令“正反反正”、“反正正反”、“正反正反”分别为1、2、3,其余情况重来。另一种更妙的办法是,投掷三次硬币,“正反反”为1,“反正反”为2,“反反正”为3,其余情况重来。 灯管问题 在房里有三盏灯,房外有三个开关,在房外看不见房内的情况,你只能进门一次,你用什么方法来区分那个开关控制那一盏灯? 打开一个开关。过10分钟后关掉开关,并打开另一个开关。进屋确认可知:亮的灯是由第二次打开的开关控制;摸上去发热的不发亮的灯是由第一次打开的开关控制剩下的第三盏灯是由未操作过的开关控制。 盲人问题 他们都各自买了两对黑袜和两对白袜,八对袜了的布质、大小完全相同,而每对袜了都有一张商标纸连着。两位盲人不小心将八对袜了混在一起。 他们每人怎样才能取回黑袜和白袜各两对呢? 每一对分开,一人拿一只,因为袜子不分左右脚 最大钻石问题 一楼到十楼的每层电梯门口都放着一颗钻石,钻石大小不一。你乘坐电梯从一楼到十楼,每层楼电梯门都会打开一次,只能拿一次钻石,问怎样才能拿到最大的一颗? 选择前五层楼都不拿,观察各层钻石的大小,做到心中有数。后面五个楼层再选择,选择大小接近前五层楼出现过最大钻石大小的钻石。
分享
6
先马后看
尹锴
北京化工大学·2022届

Java面试后端经验分享(不是面经的面经)

写在前面 之前写过一篇 Java 面试知识点汇总,由于我不断补充,现在知识点已经比较庞杂,很多人私信我,说那一篇全是知识点太过庞杂,问我有没有整合的。正好春招和秋招在即,我花费了几个月的时间,把知识点整合成不同的模块并针对不同的知识点以及结合本人自己的面试经历,整合出这篇 java 面试全攻略。希望对大家有所帮助!(本文同步发表在CSDN上史上最全!20/21届春招/秋招 实习/校招 JAVA面试全攻略!复习回顾这一篇就够了!)PS:面经由于还有一些流程没有走完,过几天会一起整理出来回馈给大家 文章目录 写在前面 一、面试那点事 二、知识框架 常见算法和数据结构 操作系统 数据库 计算机网络 Java 语言 项目 + 中间件 三、知识点系统总结 四、面试常见问题总结 Java 语言基础 JVM 容器类集合框架 多线程 计算机网络 数据库 操作系统 五、算法(还在不断刷题补充中...) Java 场景题 回溯、二分查找 动态规划 单调栈 剑指 offer 写在最后 一、面试那点事 在讲述知识点之前,我需要先说明一下互联网面试那点事。 互联网面试基本流程是:笔试 + 2 轮或 3 轮技术面(又叫业务面)+ HR 面试 笔试和 HR 面试这个是需要自己平时的积累的: 笔试基本就是 2 个小时的编程,题目个数在 4 个左右,难度在 LeetCode 中等水平(不同公司难度也不一样)。但是你笔试基本不要想着去 AC,我参加了 20 + 场笔试,很少有全部 AC 的情况,但是我笔试基本都过了,因为笔试只是互联网公司考核的一个方面而不是全部,还会考核你的学历和简历,所以笔试即便答的很差劲,心态也不要爆炸,放平心态继续准备其他的内容,甚至我有一次 4 道题目,只有一道题目得了一半的分,其他题目都是零分,但是还是给我过了笔试。但是这并不代表编程能力不重要,恰恰相反,在后面的业务面试中,所有的公司,我是说所有的!都会进行编程的考察,也就是手撕代码环节!这个容不得半点差池,大部分情况保证跑通面试官给的用例基本就可以,但是少数会比较较真,我面试华为的时候,面试官把我的代码拷贝到他本地去跑用例。所以这个手撕代码的环节是无可避免的。准备的话:剑指 offer67 题和 LeetCode 的 hot100 题这两个是必刷的,而且一遍肯定是不够的,要刷到自己很熟练为止。 HR 面就基本是个人情况的了解,但是也存在问技术的问题,但是前面的业务技术面都过了,这个就问题不大,HR 更多是考察你的性格、人品跟公司是否相符。也是需要慎重对待的。 业务技术面(Java 相关) 本文重点! 所有语言都需要掌握的技术点: 常见算法和数据结构 操作系统 数据库 计算机网络 Java 语言主要的技术点: Java 基础 集合框架 多线程 JVM 项目 + 常见中间件 二、知识框架 复习的时候需要构建自己的知识框架,用时髦的词就是思维导图,这个不是自己去画一个思维导图然后就不管了,我觉得这是一个不断复习不断在脑海中构建导图的过程,复习一个知识点的时候,把这个知识点相关的内容全部串联起来,形成一个思维框架(俗称举一反三)。这样你就神功大成了! 常见算法和数据结构 数组、链表、队列、栈的各种操作(性能,场景) 各类排序算法以及复杂度分析(快排、归并、堆),不同排序算法的稳定性 理解并可以分析时间和空间复杂度。 动态规划、贪心。 回溯算法 二叉树、前中后虚(图考察的很少,只有笔试偶尔遇到) DFS、BFS 算法 单调栈、单调队列 手撕代码环节最常见的考察就是一维数组、二维数组的操作,一维数组找特定子序列,二维数组特定找路径,涉及的算法动态规划、回溯、DFS、BFS 等等。 PS:如果实在没有好的解法,就考虑使用暴力法,因为大部分面试官不会去专业的网站评测,所以就没有超时这个隐患,但是面试官很有可能会询问时空复杂度并进而询问优化方案。 操作系统 进程通信 IPC(几种方式),进程与线程定义与区别 进程调度算法、磁盘扫描算法 虚拟内存、页面置换算法 内核态和用户态的转换的条件、中断、系统调用 互斥与死锁 linux 常用命令(问的时候都会给具体某一个场景) Linux 的 IO 模型 BIO/NIO/AIO、 IO 多路复用 Linux 内核 select poll epoll、边缘触发和水平触发 僵尸进程和孤儿进程 数据库 索引(包括分类及优化方式,失效条件,底层结构 B 树、B + 树的区别优缺点) 优化(explain,慢查询,show profile)、数据库的范式 辅助索引、主键索引、聚簇索引、非聚簇索引、索引回表、索引覆盖、索引下推 联合索引和最左匹配原则 引擎对比(InnoDB,MyISAM) 数据库的锁(行锁,表锁,页级锁,读锁,写锁,悲观锁,乐观锁) 隔离级别,依次解决的问题(脏读、不可重复读、幻读)、隔离级别与加锁的关系 事务的 ACID 分库分表,主从复制,读写分离。 sql 语法(join,union,子查询,having,group by)主要考察 sql 语句的书写 计算机网络 OSI7 层模型(TCP4 层)、每层的协议、 常见协议为位置在 OSI 七层协议的位置(HTTP/TCP/UDP/DNS/IMAP/ARP/ 路由器 / 交换机) http/https 1.0、1.1、2.0、https 加密过程(对称加密和非对称加密) get/post 以及 http 幂等性 http 协议头相关、http 常见的状态码 TCP 与 UDP 比较 TCP 三次握手、四次挥手、拥塞控制(过程、阈值)、流量控制与滑动窗口 TCP 的 time_wait 和 close_wait url 到页面的过程 网络攻击(CSRF、XSS、DDos) Java 语言 1. 基础 面向对象、四个特性、重载重写、继承、多态、反射 常见关键字 final、static、abstract、finalize、transient、native StringBuffer、StringBuilder 和 String、字符常量池 六大设计原则、常见的设计模式(代理、工厂、单例、装饰者、观察者) 异常、常见的异常类 序列化 深拷贝和浅拷贝、值传递和引用传递 抽象类和接口 基本类型的默认值和取值范围以及字节数 2. 多线程 synchronized 关键字底层原理、锁升级原理、轻量级锁、重量级锁 Lock 锁机制、线程通信、、ThreadLocal、Atom 包、AQS、CAS 原理 volatile 关键字、内存屏障、happen-before 原则 同步队列、等待队列、阻塞队列 线程池、线程池的执行流程、线程池的主要参数(coresize、阻塞队列、maxsize、拒绝策略)、线程池的任务递交方式和状态变化。 thread 类的常见方法:sleep、join、yield;sleep 和 wait 方法的区别 线程的五种状态、run 方法和 start 方法 守护线程和用户线程 3. 集合框架 hashmap(这个基本是必考题)hashcode 函数、equals 函数、扩容机制、put 和 get 操作、jdk1.7 和 jdk1.8 的变化、hashmap 的尾部遍历、红黑树的引入 hashmap 的线程安全问题,synchronizedMap、hashtable、concurrentHashMap concurrentHashMap 的 jdk1.7 和 jdk1.8 的变化,底层实现线程安全的方式 常见的集合框架哪些是线程安全的,哪些是线程不安全的 arraylist 和 linkedlist、vector 集合的遍历、迭代器 4.JVM JVM 内存模型、堆、栈、PC 计算器、永久代分别存储的内容 GC 垃圾回收,三种 GC 算法,七种 GC 收集器 CMS 和 G1 的优缺点、执行流程 年老代和年轻代、分代垃圾回收算法 四种引用类型、GCroot 的可达性分析法 对象创建的过程、对象的内存分配 类加载的过程、类加载器 双亲委派机制、tomcat 的反双亲委派机制 JVM 调优,常见的调优参数 内存泄漏和内存溢出 项目 + 中间件 面试的第一个环节就是自我介绍,最好提前准备好腹稿,介绍的基本内容就是你的教育经历 + 工作经历 + 简单的性格介绍。而工作经历中的项目将成为接下来面试官询问的重点,所以最好能准备一个拿得出手的项目。 如果在面试之前已经有工作经历和项目经历,就需要深挖你项目的亮点: 开发的时候使用的技术和中间件 遇到的问题、如何解决问题 是否有优化方案,如何优化你的项目 上面这三个问题基本上是最常见也是最基本的问题,准备项目的时候,一定要把上面这些问题准备好。如果是第一次找工作,最后也是提前编写一个项目练练手,现在比较火爆的项目就是 —— 秒杀系统。因为这个项目基本会用到主流的中间件(spring、Redis、消息队列 MQ、kafka)。而且我在跟面试官交流的时候,面试官对这个项目也是认可的,前提你真的深入其中。 三、知识点系统总结 为了更清晰的展示内容,我开了一个公众号并弄了一个十分钟系列板块,并花了 2 个多月的时间,把我之前所有复习的知识点整理成了大约 40 篇文章,这不是简单的问题 + 解答的形式,而是较为系统的把这个知识点的相关内容展开。相信读者读了这些文章之后有一个较为深刻的的认识。(目前还在不断整理中…) 【001】十分钟搞懂 Java 中的 ==、equals 【002】十分钟搞懂 Java 内存结构 【003】十分钟搞懂 Java 类加载 【004】十分钟搞懂 Java 代码初始化顺序 【005】十分钟搞懂 Java 引用、对象和内存 【006】十分钟搞懂 Java 垃圾回收 【007】十分钟搞懂 HashMap 【008】十分钟搞懂 HashMap 的使用 【009】十分钟搞懂 Java 容器类 【010】十分钟搞懂 Java 中的锁 【011】十分钟搞懂多线程相关概念 【012】十分钟搞懂 Java 锁的底层原理 【013】十分钟搞懂计算机网络相关概念 【014】十分钟搞懂计算机网络 IP 协议 【015】十分钟搞懂计算机网络 TCP 协议 【016】十分钟搞懂计算机网络 HTTP 协议 【017】十分钟搞懂常见的网络攻击 【018】十分钟搞懂数据库基本概念 【019】十分钟搞懂数据库事务 【020】十分钟搞懂数据库索引 【021】十分钟搞懂数据库引擎和主从复制 【022】十分钟搞懂数据库优化 【023】十分钟搞懂操作系统进程线程 【024】十分钟搞懂操作系统内存和中断 【025】十分钟搞懂操作系统互斥和同步 【026】十分钟搞懂 Linux 的常用命令 【027】十分钟搞懂 Linux 的 IO 模型 【028】十分钟搞懂 Java 线程池 【029】十分钟搞懂 Java 中的异常 【030】十分钟搞懂 Java 对象拷贝 【031】十分钟搞懂 Java 反射与代理模式 【032】十分钟搞懂 Java 面向对象特性 【033】十分钟搞懂 Java 常见关键字 【034】十分钟搞懂 Java 设计模式 【035】再谈数据库索引 四、面试常见问题总结 这是我复习过程思考的过程 + 复习过程看的面经 + 知识点的反问。目的是尽可能广的涵盖知识点,这不是面经而是一个查漏补缺的目录。 设计 超过 200 个 问题 涵盖 超过 300 个 知识点 Java 语言基础 == 和 equals 的区别? 拆箱和装箱分别是什么?分别应用在什么场景? String str=“abc” 与 String str=new String (“abc”) 一样吗?为什么? String str=“abc” 和 String str=new String (“abc”); 产生几个对象? String str = new String (“hello”)+new String (“123”); 产生了几个对象? 字符常量池的位置?字符常量池存储的内容? 给定三个变量:i1、i2、i3。Integer i1 = 120;Integer i2 = 120;int i3= 120;i1 和 i2 一样吗?i1 和 i3 呢?为什么?如果把 120 换成 130 呢,i1,12,i3 的关系又如何,为什么? throw 和 throws 的区别? try-catch-finally 中哪个部分可以省略? try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗? 常见的异常类有哪些? java 异常的执行流程? 为什么要使用克隆?如何实现对象克隆? 深拷贝和浅拷贝区别是什么? 值传递和引用传递的区别是什么? 什么是 java 序列化?什么情况下需要序列化?如何避免序列化对象中的属性序列化? 什么是反射?反射的应用场景? 代理模式有什么用?应用场景是什么? 动态代理的实现方式都有什么?哪种实现效率高? 动态代理是什么?与静态代理的区别在于? 抽象类和接口的区别?普通类和抽象类有哪些区别? 抽象类必须要有抽象方法吗?抽象类能使用 final 修饰吗? 局部内部类和匿名内部类为什么只能访问 final 的局部变量? 什么是多态? BIO、NIO、AIO 有什么区别? 同步、异步、阻塞、非阻塞? java 中 IO 流分为几种? final 在 java 中有什么作用?抽象类能使用 final 修饰吗? java 中的 Math.round (-1.5) 等于多少? 管道的类型? 什么是半双工?什么是全双工? 在多线程下选用什么处理大规模字符串? Java 中的设计原则? 什么是组合?什么是聚合? 说一下你熟悉的设计模式? 简单工厂和抽象工厂有什么区别? 装饰者模式和适配器模式以及代理模式的区别? 说出几个在 JDK 库中使用的设计模式? jdk1.8 新增的变化? JVM 说一下 jvm 的主要组成部分?及其作用? jvm 运行时数据区组成? 堆栈的区别? 运行时数据区哪些是线程共享,哪些是线程私有? Java 中成员变量、局部变量、静态变量、常量分别存储在那些内存区域中? 说一下类加载的执行过程? Java 中都有哪些加载器? 什么是双亲委派模型? 反射中,Class.forName () 和 ClassLoader.loadClass () 区别 说一下对象创建的过程? 对象有哪几部分构成?虚拟机如何访问对象? java 中都有哪些引用类型? 怎么判断对象是否可以被回收? 内存泄露和内存溢出分别是什么?什么原因造成?如何避免? 给对象分配内存如何保证线程安全? 说一下 jvm 有哪些垃圾回收算法? 说一下 jvm 有哪些垃圾回收器? 详细介绍一下 CMS 垃圾回收器? 新生代垃圾回收器和老生代垃圾回收器都有哪些?有什么区别? 简述分代垃圾回收器是怎么工作的? G1 为什么能建立可预测的停顿时间模型? Minor Gc 和 Full GC 有什么不同呢? 什么对象会进入老年代? 如果对象的引用被置为 null,垃圾收集器是否会立即释放对象占用的内存? 常量池都包括哪些内容?常量池的位置? 容器类集合框架 java 容器都有哪些? Collection 和 Collections 有什么区别? List、Set、Map 之间的区别是什么? 如何决定使用 HashMap 还是 TreeMap? ArrayList 和 LinkedList 的区别是什么? ArrayList 和 Vector 的区别是什么? 说一下 HashMap 的实现原理? java 如何判断 HashMap 中的元素是否相等?添加的元素是自定义类的时候,需要注意什么? HashMap 为什么引入红黑树? JDK1.8 的 HashMap 有哪些优化? 请写出 HashMap 的添加操作和扩容操作的代码? HashMap 和 Hashtable 有什么区别?HashMap 和 HashSet 呢? final 关键字用于什么场景? ConcurrentHashMap 如何实现线程同步? Map 遍历的两种方式? 哪些集合类是线程安全的? Iterator 怎么使用?有什么特点?Iterator 的 fail-fast 属性是什么? Iterator 和 ListIterator 有什么区别? Arrays 和 Collections 的常用方法 Array 和 ArrayList 有何区别? 在 Queue 中 poll () 和 remove () 有什么区别? 怎么确保一个集合不能被修改? 多线程 什么是锁消除?什么是锁粗化? 乐观锁有哪几种?主要思想是什么? 多线程锁的升级原理是什么(锁膨胀)? 什么是死锁?如何预防死锁?死锁和活锁的区别是什么? 并行和并发有什么区别?同步、异步、阻塞、非阻塞有什么区别?同步等同于阻塞吗? 线程和进程的区别?线程有哪些状态? 守护线程是什么? 创建线程有哪几种方式?线程的 run () 和 start () 有什么区别? ThreadLocal 是什么?有哪些使用场景? sleep 和 wait 方法有什么区别?notify () 和 notifyAll () 有什么区别? 现在有 T1、T2、T3 三个线程,你怎样保证 T2 在 T1 执行完后执行,T3 在 T2 执行完后执行? volatile 有什么用?synchronized 和 volatile 的区别是什么? synchronized 和 Lock 有什么区别? Lock 实现锁的底层原理? 说一下 atomic 的原理? 乐观锁的实现方式? 说一下 synchronized 底层实现原理? 线程池都有哪些状态? 线程池中 submit () 和 execute () 方法有什么区别? 创建线程池有哪几种方式? 创建线程池的各个参数代表的含义? 计算机网络 OSI 七层模型?HTTP 协议对应第几层?IP 协议呢? 从一个 URL 到获取页面的过程? session 的实现原理?cookie 的原理? session 和 cookie 的关系?禁用 cookie 后对 session 的影响? forward 和 redirect 的区别? 内网和外网 IP 地址的区别?ABC 三类 IP 地址的划分 网关和子网掩码的关系是什么? MAC 地址和 IP 地址的关系是什么? 什么是 DNS 服务器? IP 如何映射到 MAC 地址的? TCP 是如何保证可靠传输数据的? TCP 和 UDP 的区别? TCP 三次握手和四次挥手的过程? TCP 为什么需要三次握手?只进行两次会出现什么问题? TCP 第三次握手失败的情况 TCP 是如何处理的? 为什么连接的时候是三次握手,关闭的时候却是四次握手? http1.0 与 http1.1 的区别?什么是 keep-alive 模式? 简单说一下 http2.0? 什么是幂等性?http 的方法是否都符合幂等性?若不符合,怎么避免? https 与 http 的区别? https 加密的过程? https 是否存在安全问题?如何避免? get 方法和 post 方法的区别? 什么 XSS 攻击?如何预防? 什么是 CSRF 攻击?如何预防? 什么是 DDoS 攻击?如何预防 什么是 SQL 注入攻击?如何预防? 数据库 什么是超键?什么是主键?二者有什么关系? 数据库的三范式是什么? char 和 varchar 的区别是什么? delete 和 truncate 有什么区别?谁效率更好? 存储过程和函数的区别? 视图的操作会对基本表产生影响吗? count(*)和 count(列名)谁的效率更高? 索引是什么? 索引的分类?索引失效条件? 索引优化方式? 怎么验证 mysql 的索引是否满足需求? 索引的底层结构是什么?说说各种的特点和缺点? 什么是事务? 事务的 ACID 特性? 事务并发会造成的问题? 事务的隔离级别? 说一下乐观锁和悲观锁?说一下 mysql 的行锁和表锁? 事务的隔离级别和加锁的关系? 两种常见的数据库引擎?分别具有什么特点? 一张自增表里面总共有 7 条数据,删除了最后 2 条数据,重启 MySQL 数据库,又插入了一条数据,此时 id 是几? 什么是主从复制?什么是读写分离? 数据库从哪几方面进行调优? 索引优化方向? mysql 问题排查都有哪些手段?怎么验证 mysql 的索引是否满足需求? 操作系统 什么是僵尸进程?什么是孤儿进程?有什么危害? CPU 的上下文切换有几种?系统中断进行了几次上下文切换? 进程的通信方式?效率最高的通信方式是什么? 进程调度算法有几种?应用最广泛的是什么? 进程和线程的区别? 虚拟内存的作用与特性? 虚拟内存的实现方式?分别有何种缺陷? 页面置换算法? 什么是中断?产生中断的方式? 什么是系统调用? 什么会导致用户态陷入内核态? 陷阱和中断的区别? 互斥和同步的关系? 死锁产生的条件? 信号量的 PV 实现? 生产者消费者的代码实现? 如何动态查看服务器日志文件? 如何打包压缩文件? 修改 /test 下的 aaa.txt 的权限为属主有全部权限,属主所在的组有读写权限, 其他用户只有读的权限? 查找 text.txt 文件中的 abc 的位置? 在 /home 目录下查找以.txt 结尾的文件名? 普通文件 IO 页缓存需要复制几次?具体过程是什么? 常见的 IO 模型? IO 多路复用的 select、poll 和 epoll 函数的区别? 五、算法(还在不断刷题补充中…) PS:这是个人平时刷题的时候一些记录,大家可以参考一下。刷题这个东西,讲究题感,看十道题目不如做一道题目,这个没法取巧,知识点还可以突击背诵,这个是真的日积月累。尤其对应届生来说,哪有那么多项目经验,那有那么多实习经历,手撕代码才是一个码农的基本素养!共勉! Java 场景题 手撕单例模式 LinkedHashMap 底层实现 + LRU 缓存实现 Java 求指定精度的开根号运算 快速求最大公约数和最小公倍数 java 处理超大数 ——BigInteger java 实现排序算法,比较时间复杂度 回溯、二分查找 搞懂回溯算法思想(LeetCode46、47、980) 二分查找算法的万能公式(LeetCode35、704、1095) 动态规划 Java 实现动态规划经典题目 【面试刷题 - 力扣经典】动规:221. 最大正方形 【面试刷题 - 力扣经典】409 最长回文串、647 回文子串、5 最长回文子串 最长回文子串 LeetCode55 跳跃游戏、LeetCode45 跳跃游戏(进阶版) LeetCode56. 合并区间、354. 俄罗斯套娃信封问题(合并区间进阶) 单调栈 单调栈 LeetCode42. 接雨水、LeetCode11. 盛最多水的容器 剑指 offer 剑指 offer 刷题总结 —— 数组篇(一) 剑指 offer 刷题总结 —— 数组篇(二) 剑指 offer 刷题总结 —— 数组篇(三) 剑指 offer 刷题总结 —— 数组篇(四) 剑指 offer 刷题总结 —— 数组篇(五) 剑指 offer 刷题总结 —— 链表篇 剑指 offer 刷题总结 —— 字符串篇(一) 剑指 offer 刷题总结 —— 树篇(一) 剑指 offer 刷题总结 —— 树篇(二) 剑指 offer 刷题总结 —— 树篇(三) 剑指 offer 刷题总结 —— 堆、栈、队列篇 写在最后 以上的问题的答案在前面整理的公众号文章都是能找到的,当然肯定有想直接要答案的同学,个人建议:不要直接看答案,至少看一遍我总结的 40 篇系统文章 能看书是最好最完善的了,其次是看一下系统总结的文章,下下策是直接看问题 + 答案,因为这种方式只是一个很浅的了解,面试官稍微变化一下可能就露馅了。 我也总结了答案,形成了一个 PDF,所以我放在公众号上,大家可以免费获取,直接在后台回复:题目整合 。就可以直接获取了,也不用转发,也不用发朋友圈,也不用花钱,完全免费分享给大家! 不要直接看答案!不要直接看答案!不要直接看答案! 【Java 面试那点事】 这里致力于分享 Java 面试路上的各种知识,无论是技术还是经验,你需要的这里都有! 这里可以让你【快速了解 Java 相关知识】,并且【短时间在面试方面有跨越式提升】 面试路上,你不孤单! 【PDF 截图】
分享
6
先马后看
小翻译小虎
中央财经大学·2022届

大数据 Scala 语言笔记

Scala 语言学习笔记 概述 Scala 简介: Scala 是一门基于 JVM 的多范式编程语言,通俗的说:Scala 是一种运行在 JVM 上的函数式的面向对象语言,之所以这样命名是因为它的设计目标是:随着用户的需求一起成长。Scala 可被广泛应用于各种编程任务,从编写小型的脚本到构建巨型系统都能胜任。正因如此,Scala 得以提供一些出众的特性,例如:它集成了面向对象编程和面向函数式编程的各种特性,以及更高层的并发模型。 Scala 语言的特点: 兼容性 兼容 Java,可以访问庞大的 Java 类库,例如操作 mysql、redis 等。 精简的 Scala 表达能力强,一行代码抵得上多行 Java 代码,开发速度快。 高级的 Scala 可以让程序保持短小、清晰,看起来更简洁、优雅。 静态类型的 Scala 拥有非常先进的静态类型系统,支持类型推断和模式匹配等。 可以开发大数据应用程序 例如 spark 、flink 程序等。 Scala 程序和 Java 程序的对比: Java 源代码通过 Javac 编译,编译结果为 Java 字节码、Java 类库 Scala 源代码通过 scalac 编译,编译结果为 Java 字节码、Java 类库、Scala 类库 使用 Scala 语言创建一个学生类,定义姓名和年龄两个属性,创建一个学生类对象并输出: 复制代码 1 2 3 4 5 6 //创建学生类 case class Student(var name:String, var age:Int) //创建学生对象 val s = Student("sjh", 24) //输出学生对象 print(s) 环境搭建: JDK Scala SDK 下载地址:https://www.scala-lang.org/download/ IDEA 在 plugins 中安装 Scala 插件(插件要与 IDEA 版本一致) 下载地址:https://plugins.jetbrains.com/plugin/1347-scala/versions Scala 解释器: Scala 解释器就像 Linux 命令一样,执行一条代码马上就可以看到执行结果。 启动解释器:win + R,输入 scala 即可。 打印 hello world: 复制代码 1 println("hello world") 退出解释器: 复制代码 1 :quit 小案例: 提示用户输入一句话,并把它打印出来: 复制代码 1 2 3 4 5 6 7 8 scala> import java.util.Scanner//导包 import java.util.Scanner   scala> println("输入你想说的一句话:")//提示用户 输入你想说的一句话:   scala> println("你想说的一句话是:"+ new Scanner(System.in).nextLine())//将用户输入输出 你想说的一句话是:我正在学Scala 基本语法 输出和分号 换行输出: 复制代码 1 println(1,2,3) 不换行输出: 复制代码 1 print(1,2,3) 注意:可以同时打印多个值,使用逗号隔开。 复制代码 1 2 println("hello scala")//单行分号可以不写 println("hello"); println("scala")//多行代码写在一行中间分号不能省略,最后一条代码的分号可省略。 常量 指程序运行过程中值不能发生改变的量。 字面值常量 复制代码 1 2 3 4 5 6 print(10) //整形常量 print(10.1) //浮点型常量 print("scala") //字符串常量 print('a') //字符常量 print(true, false) //布尔常量 print(null) //空常量 自定义常量 变量 格式: 复制代码 1 val/var 变量名:变量类型 = 初始值 val 定义的是不可重新赋值的变量,也就是自定义常量。 var 定义的变量可以被重新赋值。 可以使用类型推断来定义变量,代码更简洁: 复制代码 1 2 var name:String = "sjh" var name = "sjh" 字符串 Scala 提供多种定义字符串的形式 使用双引号 复制代码 1 var name = "sjh" 使用插值表达式,有效避免大量字符串拼接 复制代码 1 val/var 变量名 = s"{变量/表达式}字符串" 实例:定义三个变量,分别保存姓名,年龄,性别,定义一个字符串保存这些信息 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 scala> val name = "sjh" //定义姓名 name: String = sjh   scala> val age = 24 //定义年龄 age: Int = 24   scala> val sex = "male" //定义性别 sex: String = male   scala> val res = s"name=${name},age=${age},sex=${sex}" //保存信息 res: String = name=sjh,age=24,sex=male   scala> print(res) //输出 name=sjh,age=24,sex=male 使用三引号,可以保存大量文本,例如大段 SQL 语句,三引号中的所有内容都会作为字符串的值 复制代码 1 val/var 变量名 = """  字符串的值  """ 惰性赋值 在大数据开发中有时会编写非常复杂的 SQL 语句,当一些变量保存的数据较大时,而这些数据又不需要马上加载到 JVM 中,可以使用惰性赋值来提高效率。 复制代码 1 lazy val/var 变量名 = 值 标识符 标识符就是给变量、方法、类起名字的,Scala 和 Java 中的标识符非常相似。 命名规则: 必须由 大小写英文字母、数字、下划线_、美元符号$ 四部分任意组合。 数字不能开头。 不能和 Scala 关键字重名。 最好做到见名知意。 命名规范: 变量或方法:小驼峰命名,从第二个单词开始每个单词首字母大写。 类或特质:大驼峰命名,每个单词的首字母都大写。 包:全部小写,一般是公司域名反写,多级包用.隔开。 数据类型 Scala 也是一门强类型语言,它里面的数据类型绝大多数与 Java 一样。 基础类型 类型说明 Byte 8 位带符号整数 Short 16 位带符号整数 Int 32 位带符号整数 Long 64 位带符号整数 Char 16 位无符号 Unicode 字符 String Char 类型的序列,字符串 Float 32 位单精度浮点数 Double 64 位单精度浮点数 Boolean true 或 false Scala 和 Java 类型的区别: 所有类型都以大写字母开头 整形使用 Int 而不是 Integer 定义变量可以不写类型,让编译器自动推断 默认整形是 Int,默认浮点型是 Double Scala 的类型关系图: Any 是所有类型的父类,相当于 Java 中的 Object 类。 AnyVal 是所有数值类型的父类,AnyRef 是所有引用类型的父类。 Unit 类似于 Java 中的 void,一般作为返回值。 Null 是所有引用类型的子类,只有一个实例 null。 Nothing 是所有数据类型的子类,不能创建该类型实例,一般结合异常使用。 类型转换 当 Scala 程序在进行运算或赋值时,范围小的数据类型会自动转换为范围大的数据类型值,然后再进行计算。 类型转换分为值类型转换和引用类型转换,值类型转换又分为自动类型转换和强制类型转换。 自动类型转换 范围小的数据类型值会自动转换为范围大的数据类型值,自动类型转换从小到大依次为: 复制代码 1 Byte -> Short -> Int -> Long -> Float -> Double 强制类型转换 将范围大的数据类型值通过一定格式转换为范围小的数据类型值(可能会造成精度缺失)。 格式: 复制代码 1 val/var 变量名:数据类型 = 具体的值.toXxx 例如: 复制代码 1 2 3 4 5 scala> var a:Int = 1 a: Int = 1   scala> var b:Short = a.toShort b: Short = 1 值类型和 String 类型的相互转换 值类型转 String 格式: 复制代码 1 2 val/var 变量名:String = 值类型 + "" val/var 变量名:String = 值类型.toString String 类型转值类型格式: 复制代码 1 val/var 变量名:值类型 = 字符串值.toXxx//如果转换Char要使用toCharArray 键盘录入 使用步骤: 导包 复制代码 1 import scala.io.StdIn 通过 stdIn.readXxx() 接收用户键盘录入的数据 接收字符串数据: 复制代码 1 StdIn.readLine() 接收整数数据: 复制代码 1 StdIn.readInt() 示例:提示用户输入字符串 复制代码 1 2 3 4 5 6 7 scala> import scala.io.StdIn import scala.io.StdIn   scala> print("输入一句话:") 输入一句话: scala> print("输入的是:"+StdIn.readLine()) 输入的是:scala 运算符 算数运算符 包括 +(加号)、-(减号)、*(乘号)、/(除号)、%(取余)。 Scala中没有 ++,--这两个运算符。 a % b,底层是 a - a/b * b Scala 中把字符串和整数数字 n 相乘相当于让字符串重复 n 次。 复制代码 1 2 scala> print("x"*3) xxx 赋值运算符 基本赋值运算符 = 扩展赋值运算符 +=、-=、*=、/=、%= 关系运算符 包括>、>=、<、<=、==、!= 最终结果一定是 true 或 false。 如果需要比较数据值,使用==或者!=,如果比较引用值需要使用 eq 方法。 复制代码 1 2 3 4 5 6 7 8 9 10 scala> val s1 = "a" s1: String = a   scala> val s2 = s1 + "" s2: String = a   scala> print(s1 == s2) true scala> print(s1.eq(s2)) false 逻辑运算符 包括 &&、||、! 最终结果一定是 true 或 false。 位运算符 包括&(按位与)、|(按位或)、^(按位异或)、~(按位取反)、<<(左移一位,相当于乘2)、>>(右移一位,相当于除以2) 位运算符只针对于整形数据,运算符操作的是数据的二进制补码形式。 流程控制 顺序结构 程序按照从上至下、从左至右的顺序依次逐行执行,中间没有任何判断和跳转。 顺序结构是 Scala 中的默认流程结构。 选择结构 if 注意事项: 和 Java 一样,如果大括号内只有一行代码可省略大括号 条件表达式有返回值 没有三元表达式,可以使用 if-else 代替 复制代码 1 2 scala> println(if(1==1) 1 else 0) 1 块表达式: 使用一对大括号表示一个块表达式,块表达式也是有返回值的,最后一个表达式的值就是返回值 复制代码 1 2 3 4 5 6 scala> val n = {      | println(1)      | 1+2      | } 1 n: Int = 3 循环结构 for 循环 复制代码 1 2 3 for(i <- 表达式/数组/集合){     //逻辑 } 例如:打印10次 "hello scala" 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 scala> val n = 1 to 10 n: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)   scala> for( i <- n){      | println("hello scala")      | } hello scala hello scala hello scala hello scala hello scala hello scala hello scala hello scala hello scala hello scala 守卫:for 表达式中的 if 判断语句。 例如输出1 - 10 之间的偶数: 复制代码 1 2 3 4 5 6 scala> for(i <- 1 to 10 if i % 2 == 0 ) println(i) 2 4 6 8 10 推导式:Scala 中的 for 循环也有返回值,可以使用 yield 表达式构建出一个集合。 例如,生成一个10、20...100 的集合: 复制代码 1 2 scala> val set = for(i <- 1 to 10) yield i * 10 set: scala.collection.immutable.IndexedSeq[Int] = Vector(10, 20, 30, 40, 50, 60, 70, 80, 90, 100) while 循环 格式: 复制代码 1 2 3 4 5 初始化条件 while(判断条件){     //循环体     //控制条件 } 例如:打印 1-5 的数字 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 scala> var i = 1 i: Int = 1   scala> while(i <= 5){      | println(i)      | i += 1      | } 1 2 3 4 5 do-while 循环 复制代码 1 2 3 4 5 初始化条件 do{     //循环体     //控制条件 }while(判断条件) break 和 continue 在 Scala 中,移除了 break 和 continue 关键字 如果要使用,需要 scala.util.controle 包下的 Breaks 类的 breakable 和 break 方法 用法: 导包: 复制代码 1 import scala.util.control.Breaks._ 使用 breakable 将 for 表达式包起来 for 表达式中需要退出循环的地方,添加 break() 方法调用。 例如输出 1-10 的数字,遇到5退出: 复制代码 1 2 3 4 5 6 scala> breakable{      |   for( i <- 1 to 10){      |     if(i == 5) break() else print(i)      |   }      | } 1234 continue 的实现和 break 类似,不同的是需要使用 continue 的地方是用 breakable 将 for 表达式的循环体包起来即可。 例如输出 1-10 不能整除 3 的数字: 复制代码 1 2 3 4 5 6 scala> for(i <- 1 to 10){      |   breakable{      |     if(i % 3 == 0) break() else print(i)      |   }      | } 12457810 案例:打印九九乘法表 复制代码 1 2 3 4 5 6 7 8 9 10 11 for(row <- 1 to 9){     for(col <- 1 to row){         print(s"${col} x ${row} = ${col * row}\t")     }     println() } 或 for(row <- 1 to 9;col <- 1 to row){     print(s"${col} x ${row} = ${col * row}\t")     if(row == col) println() } 方法和函数 方法 语法格式: 复制代码 1 2 3 def 方法名(参数名1:参数类型1, 参数名2:参数类型2...)[: 返回值类型] = {     //方法体 } 注意: 参数列表的参数类型不能省略 返回值类型可以省略,由 Scala 编译器自动推断 返回值可以不写 return ,默认就是块表达式的值 示例:定义一个方法用来获取两个整形数字的最大值并返回结果。 复制代码 1 2 3 4 5 def getMax(num1:Int, num2:Int): Int = {     return if(num1 >= num2) num1 else num2 } 或 def getMax(num1:Int, num2:Int) = if(num1 >= num2) num1 else num2 返回值的类型推断 当定义递归方法时,不能省略返回值的类型。 示例:定义一个方法求 5 的阶乘。 复制代码 1 2 def f(n:Int):Int = if(n == 1) n else n * f(n - 1) print(f(5)) 惰性方法 当记录方法返回值的变量被声明为 lazy 时,方法的执行将被推迟,直到我们再次使用该值时方法才会执行,像这样的方法就叫做惰性方法。 注意:lazy 不能修饰 var 类型的变量。 使用场景: 打开数据库连接 提升某些特定模块的启动时间 确保对象中的某些字段优先初始化 示例:定义一个方法获取两个整数和,使用惰性技术调用该方法,然后打印结果。 复制代码 1 2 3 4 5 6 7 8 scala> def add(num1:Int, num2:Int) = num1 + num2 add: (num1: Int, num2: Int)Int   scala> lazy val sum:Int = add(1,2) sum: Int = <lazy>   scala> print(sum) 3 方法参数 默认参数 定义方法时可以给参数一个默认值并调用无参方法,例如: 复制代码 1 2 def add(num1:Int = 1, num2:Int = 1) = num1 + num2 print(add())//2 带名参数 调用方法时可以指定参数的名称进行调用,例如 复制代码 1 2 3 def add(num1:Int = 1, num2:Int = 1) = num1 + num2 print(add(num1 = 2))//3 print(add(10))//11 变长参数 如果方法的参数是不固定的,可以将该方法的参数定义为变长参数。 格式: 复制代码 1 2 3 def 方法名(参数名:参数类型*)[: 返回值类型] = {     //方法体 } 一个方法有且只能有一个变长参数,并且变长参数要放到参数列表的最后面。 例如:定义一个方法计算 n 个数字的和。 复制代码 1 2 3 def getSum(nums:Int*) = nums.sum print(getSum())//0 print(getSum(1, 2, 3, 4))//10 方法调用方式 后缀调用法 与 Java 相同,格式: 复制代码 1 2 对象名.方法名(参数) 例如:Math.abs(-1) 中缀调用法 格式: 复制代码 1 2 对象名 方法名 参数 例如:Math abs -1 在 Scala 中所有的操作符都是方法,操作符是一个方法名是符号的方法。 花括号调用法 方法只有一个参数时才能使用花括号调用法。 例如: 复制代码 1 2 3 4 5 scala> Math.abs{      | print("求绝对值,结果是:")      | -1      | } 求绝对值,结果是:res30: Int = 1 无括号调用法 如果方法没有参数,可以省略方法后面的括号。 例如:定义一个无参方法打印"hello scala",使用无括号调用法 复制代码 1 2 def say() = print("hello scala") say//hello scala 如果方法的返回值类型是 Unit,这样的方法称为过程,过程的 = 可以省略不写,花括号不能省略: 复制代码 1 def say() { print("hello scala") } 函数 Scala 支持函数式编程,Spark/Flink 程序会大量使用函数。 定义 复制代码 1 val 函数变量名 = (参数名1:参数类型1, 参数名2:参数类型2...) => 函数体 函数是一个对象 类似于方法,函数也有参数列表和返回值 函数定义不需要使用 def 定义 无需指定返回值类型 示例:定义一个计算两个整数之和的函数。 复制代码 1 2 val getSum = (a:Int, b:Int) => a + b val sum = getSum(1, 2)//3 方法和函数的区别 方法属于类或者对象,在运行时会加载到 JVM 的方法区。 可以将函数对象赋值给一个变量,在运行时会加载到 JVM 的堆中。 函数是一个对象,继承自 FunctionN,函数对象有apply、curried、toString、tupled这些方法,方法则没有。 结论:在 Scala 中,函数是对象,而方法是属于对象的,可以理解为:方法归属于函数。 可以通过在方法后加上空格和下划线将其转为函数,例如定义一个求和方法并转为函数: 复制代码 1 2 3 def add(a:Int, b:Int):Int = a + b val func = add _ func(1, 2)//3 案例:打印nn乘法表 通过方法: 复制代码 1 2 3 4 5 6 def write(n:Int){     for(row <- 1 to n;col <- 1 to row){         print(s"${col} x ${row} = ${col * row}\t")         if(row == col) println()     } } 通过函数: 复制代码 1 2 3 4 5 6 val func = (n:Int) => {     for(row <- 1 to n;col <- 1 to row){         print(s"${col} x ${row} = ${col * row}\t")         if(row == col) println()     } } 类和对象 类和对象 创建类和对象可以通过 class 和 new 关键字实现,用 class 创建类,用 new 创建对象。 示例:创建一个 Person 类,然后创建其对象并打印。 创建一个 Scala 项目,并创建一个 Object 类(Object 修饰的类是单例对象)。 在 object 类中添加 main 方法。 创建 Person 类,并在 main 方法中创建 Person 类的对象然后输出结果。 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 //实体类 class Person {   } ---------------------------------------------- //测试类 object ClassDemo {     //main方法,作为程序主入口,所有代码执行都从这里开始   def main(args: Array[String]): Unit = {     //创建 Person 对象     val person = new Person()     //打印对象     println(person)   } } 如果类是空的,没有任何成员,可以省略{} 如果构造器参数为空,可以省略() 复制代码 1 2 3 4 5 6 7 8 9 10 11 //简写类和对象 object ClassDemo {     class Person     def main(args: Array[String]): Unit = {     val person = new Person     println(person)   }   } 成员变量 可以使用 var/val 定义成员变量,对象通过 对象名. 的方式访问成员变量。 示例:定义一个 Person 类,包含一个姓名和年龄字段,创建一个具体对象并打印。 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 object ClassDemo {     class Person{     var name = ""     var age = 0   }     def main(args: Array[String]): Unit = {     val person = new Person     person.name = "sjh"     person.age = 24     print(s"姓名:${person.name},年龄:${person.age}")   }   } 使用下划线初始化成员变量 在定义 var 类型的成员变量时,可以使用 _ 初始化成员变量。 val 类型的成员变量,必须要自己手动初始化。 例如: 复制代码 1 2 3 4 class Person{     var name:String = _     var age:Int = _ } 定义和访问成员方法 在 Scala 的类中,也是使用 def 定义方法。 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 object ClassDemo {     class Person{     var name:String = _     var age:Int = _       def printHello(msg:String): Unit = print(msg)     }     def main(args: Array[String]): Unit = {     val person = new Person     print(person.printHello("hello scala"))   }   } 访问修饰符 在 Scala 中没有 public 关键字,没有被标记为 private 和 protected 的成员都是公共的。 Scala 中的权限修饰符只有:privat、private[this]、protected、默认。 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 object ClassDemo {     class Person{     private var name:String = _     private var age:Int = _       //获取姓名     def getName:String = name     //设置姓名     def setName(name:String): Unit = this.name = name     //获取年龄     def getAge:Int = age     //设置年龄     def setAge(age:Int): Unit = this.age = age     }     def main(args: Array[String]): Unit = {     val person = new Person     person.setName("sjh")     person.setAge(24)   }   } 构造器 主构造器 语法: 复制代码 1 2 3 class 类名(var/val 参数名:类型 = 默认值,...){     //构造代码块 } 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 object ClassDemo {     class Person(var name:String = "sjh",var age:Int = 24){     }     def main(args: Array[String]): Unit = {     //空参     val p1 = new Person("s",2)     //全参     val p2 = new Person()     //指定参数     val p3 = new Person(age = 2)   }   } 辅助构造器 语法: 辅助构造器方法名必须叫 this。 复制代码 1 2 3 4 def this(参数名:类型,...){     //第一行需要调用主构造器或其他构造器     //构造器代码 } 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 object ClassDemo {     class Customer(var name:String,var address:String){         def this(array: Array[String]) = {         this(array(0),array(1))       }   }     def main(args: Array[String]): Unit = {     //通过辅助构造器创建对象     val customer = new Customer(Array("sjh", "xi'an"))   }   } 单例对象 定义单例对象和定义类很像,就是把 class 换成 object。 格式: 复制代码 1 object 单例对象名{} 在 object 中定义的成员变量类似 Java 中的静态变量,在内存中只有一个对象。 单例对象中,可以直接使用 单例对象名.的方式调用成员。 例如: 复制代码 1 2 3 4 5 6 7 8 9 10 11 object ClassDemo {     object Dog{     val leg_num = 4   }     def main(args: Array[String]): Unit = {     print(Dog.leg_num)   }   } 单例对象中的方法类似 Java 中的静态方法 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 object ClassDemo {     object Dog{     val leg_num = 4       def say(): Unit = print("dog")   }     def main(args: Array[String]): Unit = {     Dog.say()   }   } main 方法 在 Java 中 main 方法是静态的,Scala 中没有 main 方法,所以必须将其放在一个单例对象中。 创建单例对象 复制代码 1 2 3 4 5 6 7 object ClassDemo {     def main(args: Array[String]): Unit = {     print("hello scala")   }   } 继承 App 特质 复制代码 1 2 3 object ClassDemo extends App {     print("hello scala") } 伴生对象 在 Java 中有一些类会同时有静态内容和非静态内容,在 Scala 中想要实现类似效果可以使用伴生对象来实现。 一个 class 和 object 具有相同的名字,这个 object 被称为伴生对象,这个 class 被称为半生类。 伴生对象和半生类可以互相访问 private 属性,必须写在一个源文件。 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 object ClassDemo {     //半生类,里面内容非静态   class Person{     def eat(): Unit = print("eat " + Person.food)   }     //伴生对象   object Person{     private val food = "rice"   }     def main(args: Array[String]): Unit = {     val person = new Person     person.eat()   }   } 如果某个成员变量权限为 private[this],表示只能在当前类访问,伴生对象也不能直接访问。 apply 方法 可以在创建对象时免去 new 操作,格式: 复制代码 1 2 3 object 伴生对象名{     def apply(参数名:参数类型...) = new 类(...) } 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 object ClassDemo {     //半生类   class Person(name:String, age:Int){   }     //伴生对象   object Person{     def apply(name:String, age:Int): Person = new Person(name, age)   }     def main(args: Array[String]): Unit = {     val person = Person("sjh", 24)   }   } 案例:定义工具类 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import java.text.SimpleDateFormat import java.util.Date   object DateUtils {     var sdf:SimpleDateFormat = _     //日期转字符串   def date2String(date:Date, template:String): String = {     sdf = new SimpleDateFormat(template)     sdf.format(date)   }     //字符串转日期   def string2Date(dateStr:String, template:String): Date = {     sdf = new SimpleDateFormat(template)     sdf.parse(dateStr)   }   } 继承和抽象类 继承 语法: 复制代码 1 2 3 class/object 子类 extends 父类{   } 子类重写方法必须使用 override 修饰,可以使用 override 重新一个 val 字段,父类的 var 字段不可重写。 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 object ClassDemo {     class Person{     val name = ""     var age = 24       def say(): Unit = print("")   }     class Student extends Person{     override val name = "sjh"       override def say(): Unit = print("hello")   }     def main(args: Array[String]): Unit = {     val student = new Student()     student.say()//hello   }   } 类型判断 isInstanceOf 判断对象是否为指定类的对象 asInstanceOf 将对象转换为指定类型 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 object ClassDemo {     class Person{   }     class Student extends Person{     def say(): Unit = print("hello")   }     def main(args: Array[String]): Unit = {     val p:Person = new Student()     if(p.isInstanceOf[Student]) {       val s = p.asInstanceOf[Student]       s.say()     }   }   } isInstanceOf 只能判断对象是否为指定类以及其子类的对象而不能精确判断其类型,如果精确判断可以使用 getClass 和 classOf 来实现。 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 object ClassDemo {     class Person{   }     class Student extends Person{   }     def main(args: Array[String]): Unit = {     val p:Person = new Student()     print(p.getClass == classOf[Person])//false     print(p.getClass == classOf[Student])//true   }   } 抽象类 如果类中有抽象字段或抽象方法,那么该类就必须是抽象类。 抽象字段:没有初始化的变量。 抽象方法:没有方法体。 格式: 复制代码 1 2 3 4 abstract class 抽象类名{     val/var 抽象字段名:类型     def 方法名(参数:参数类型...):返回类型 } 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 object ClassDemo {     abstract class Shape{     val c:Int     def getArea:Double   }     class Square(x:Int) extends Shape{     override val c: Int = x       override def getArea: Double = c * c   }     class Circle(r:Int) extends Shape{     override val c: Int = r       override def getArea: Double = Math.PI * c * c   }     def main(args: Array[String]): Unit = {     val square = new Square(1)     println(square.getArea)//1     val circle = new Circle(1)     println(circle.getArea)//3.141592653589793   }   } 匿名内部类 匿名内部类是继承了类的匿名子类对象 语法: 复制代码 1 2 3 new 类名(){     //重写类中所有的抽象内容 } 如果类的主构造器参数列表为空,小括号可以省略。 作用:对象的成员方法仅调用一次、作为方法的参数传递。 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 object ClassDemo {     abstract class Person{     def sayHello()   }     def show(person: Person): Unit = person.sayHello()     def main(args: Array[String]): Unit = {     val person:Person = new Person {       override def sayHello(): Unit = println("hello")     }     show(person)   }   } 案例:动物类 定义抽象动物类,属性包括:姓名,年龄,行为:跑步和吃饭 定义猫类,重写吃饭方法,并定义独有抓老鼠方法。 定义狗类,重写吃饭方法,并定义独有看家方法。 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 object ClassDemo {      abstract class Animal{     var name = ""     var age = 0       def run(): Unit = println("run")     def eat()   }     class Cat extends Animal{     override def eat(): Unit = println("eat fish")       def catchMouse(): Unit = println("catch mouse")   }     class Dog extends Animal{     override def eat(): Unit = println("eat meat")       def catchThief(): Unit = println("catch thief")   }       def main(args: Array[String]): Unit = {     val animal:Animal = new Cat()     if(animal.isInstanceOf[Cat]) {       val cat = animal.asInstanceOf[Cat]       cat.catchMouse()     } else if(animal.isInstanceOf[Dog]) {       val dog = animal.asInstanceOf[Dog]       dog.catchThief()     } else {       println("not cat or dog")     }   }   } 特质 概述 Scala 中的特质要用关键字 trait 修饰。 特点: 特质可以提高代码的复用性。 特质可以提高代码的扩展性和可维护性。 类与特质是继承关系,类与类只支持单继承,类与特质之间可以单继承也可以多继承。 Scala 的特质中可以有普通字段、抽象字段、普通方法、抽象方法。 如果特质只有抽象内容也叫瘦接口,如果既有抽象内容又有具体内容叫做富接口。 语法: 定义特质 复制代码 1 2 3 trait 特质名称{   } 继承特质 复制代码 1 2 3 class 类名 extends 特质1 with 特质2{   } 示例:类继承单个特质 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 object ClassDemo {     trait Logger{     def log(msg:String)   }     class ConsoleLogger extends Logger{     override def log(msg: String): Unit = println(msg)   }       def main(args: Array[String]): Unit = {     val logger = new ConsoleLogger     logger.log("hello scala")   }   } 示例:类继承多个特质 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 object ClassDemo {     trait MsgSender{     def send(msg:String)   }     trait MsgReceiver{     def receive()   }     class MsgWorker extends MsgSender with MsgReceiver{     override def send(msg: String): Unit = println(s"发送消息:$msg")       override def receive(): Unit = println("接收消息")   }     def main(args: Array[String]): Unit = {     val worker = new MsgWorker     worker.send("hello")     worker.receive()   }   } 示例:object 继承 trait 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 object ClassDemo {     trait MsgSender{     def send(msg:String)   }     trait MsgReceiver{     def receive()   }     object MsgWorker extends MsgSender with MsgReceiver{     override def send(msg: String): Unit = println(s"发送消息:$msg")       override def receive(): Unit = println("接收消息")   }     def main(args: Array[String]): Unit = {     MsgWorker.send("hello scala")     MsgWorker.receive()   }   } 示例:trait 中的成员 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 object ClassDemo {     trait Hero{     val name = ""     val arms = ""     def attack(): Unit = println("发起进攻")     def skill()   }     class Killer extends Hero{     override val name = "sjh"     override val arms = "gun"     override def skill(): Unit = println("kill")   }     def main(args: Array[String]): Unit = {     val killer = new Killer     killer.attack()     killer.skill()   }   } 对象混入 trait 在 Scala 中,类和特质之间无任何继承关系,但通过特定关键字让该类对象具有指定特质中的成员。 语法: 复制代码 1 val/var 对象名 = new 类 with 特质 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 object ClassDemo {     trait Logger{     def log(): Unit = println("log..")   }     class User{     }     def main(args: Array[String]): Unit = {     val user = new User with Logger     user.log()//log..   }   } 使用 trait 实现适配器模式 当某个特质中有多个抽象方法,而我们只需要用到某个或某几个方法时不得不将该特质所有抽象方法重写。针对这种情况可以定义一个抽象类继承该特质,重写特质的所有方法,方法体为空。需要使用哪个方法只需要定义类继承抽象类,重写指定方法即可。 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 object ClassDemo {     trait Play{     def mid()     def top()     def adc()     def jungle()     def support()   }      abstract class Player extends Play{      override def mid(): Unit = {}        override def top(): Unit = {}        override def adc(): Unit = {}        override def jungle(): Unit = {}        override def support(): Unit = {}    }     //新手类   class GreenHand extends Player {     override def support(): Unit = println("我是辅助")   }     def main(args: Array[String]): Unit = {     val player = new GreenHand     player.support()   }   } 使用 trait 实现模板方法模式 在 Scala 中我们可以先定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该结构的情况下重定义该算法的某些特定步骤,这就是模板方法设计模式。 优点:扩展性强、符号开闭原则。 缺点:类的个数增加会导致系统庞大,设计更抽象、增加代码阅读难度。 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 object ClassDemo {     //模板类,计算某个方法的执行时间   abstract class Template{     def code()       def getRuntime: Long = {       val startTime = System.currentTimeMillis()       code()       val endTime = System.currentTimeMillis()       endTime - startTime     }   }     class Concrete extends Template{     override def code(): Unit = for(_ <- 1 to 10000) println("scala")   }     def main(args: Array[String]): Unit = {     println(s"耗时:${new Concrete().getRuntime} ms")   }   } 使用 trait 实现责任链模式 多个 trait 中出现了同一方法,且该方法最后都调用了 super.该方法名(),当类继承了这多个 trait 后就可以依次调用多个 trait 中的此同一个方法了,这就形成了一个调用链。 执行顺序:从右至左、先子类后父类。 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 object ClassDemo {     trait Handler{     def handle(data:String): Unit = {       println("具体的处理数据...4")       println(data)     }   }     trait DataValid extends Handler{     override def handle(data: String): Unit = {       println("验证数据 3")       super.handle(data)     }   }     trait SignValid extends Handler{     override def handle(data: String): Unit = {       println("验证签名 2")       super.handle(data)     }   }     class Payment extends DataValid with SignValid{     def pay(data:String): Unit = {       println("用户发起支付请求 1")       super.handle(data)     }   }     def main(args: Array[String]): Unit = {     val payment = new Payment     payment.pay("发起转账..5")   }   } trait 构造机制 每个特质只有一个无参构造器 遇到一个类继承另一个类以及多个trait的情况,创建该类实例时构造器执行顺序: 执行父类构造器 从左到右依次执行 trait 的构造器 如果trait 有父 trait,先执行父 trait 如果多个 trait 有相同的父 trait,父 trait 构造器只初始化一次 执行子类构造器 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 object ClassDemo {     trait A{     println("A")   }     trait B extends A{     println("B")   }     trait C extends A{     println("C")   }     class D{     println("D")   }     class E extends D  with B with C{     println("E")   }     def main(args: Array[String]): Unit = {     new E//DABCE   }   } trait 继承 class trait 可以继承 class,会将所有的成员都继承下来。 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 object ClassDemo {     class A{     def printMsg(): Unit = println("hello scala")   }     trait B extends A     class C extends B     def main(args: Array[String]): Unit = {     new C().printMsg()//hello scala   }   } 案例:程序员 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 object ClassDemo {     abstract class Programmer{     val name = ""     val age = 0       def eat(): Unit = println("eat")     def code()   }       class JavaProgrammer extends Programmer{     override def code(): Unit = println("精通 java")   }     trait BigData{     def bigData(): Unit = println("精通大数据")   }       class PartJavaProgrammer extends JavaProgrammer with BigData{     override def code(): Unit = {       super.code()       bigData()     }   }     def main(args: Array[String]): Unit = {     val javaProgrammer = new PartJavaProgrammer     javaProgrammer.code()   }   } 包 包 包就是文件夹,用 package 修饰,可以区分重名类。 作用域: 子包可以直接访问父包中的内容。 上层访问下层内容时,可以通过导包(import)或者写全包名的形式实现。 如果上下层有相同的类,使用时采用就近原则(优先使用下层)。 包对象: 要定义在父包中,一般用于对包的功能进行补充、增强。 可见性: 通过访问权限修饰符 private、protected、默认来限定访问修饰符。 格式: 复制代码 1 访问修饰符[包名] 引入: Scala 默认引入了 java.lang 包的全部内容,scala 包以及 Predef 包的部分内容。 包的引入不限于Scala 文件的顶不,而是可以编写到任何需要使用的地方。 如果需要导入某个包中的所有类和特质,使用下划线 _ 实现。 如果需要的时某个包的某几个类和特质,可以通过选取器 {}实现。 如果引入的多个包含有相同的类,可以通过重命名或隐藏解决。 重命名格式: 复制代码 1 import java.util.{HashSet => JavaSet} 隐藏格式: 复制代码 1 import java.util.{HashSet => _,_}//引入util包下除了HashSet的类 样例类 样例类是一种特殊类,一般用于保存数据,在并发编程以及 Flink 等框架中会经常使用。 格式: 复制代码 1 case class 样例类名([var/val] 成员变量名1:类型1...) 如果不写,变量默认修饰符是val。如果要实现某个成员变量值可以被修改,则需要手动添加var 修饰。 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 object ClassDemo {     case class Person(val name:String, var age:Int)     def main(args: Array[String]): Unit = {     val person = new Person(name = "sjh", age = 24)     //person.name = "" 不可修改     person.age = 0   }   } 样例类的默认方法 apply 可以快速使用类名创建对象,省略 new 关键字。 toString 可以在打印时直接打印该对象各个属性值。 equals 可以直接使用 == 直接比较属性值。 hashCode 同一个对象哈希值一定相同,不同对象哈希值一般不同。 copy 可以用来快速创建属性值相同的实例对象,还可以使用带名参数的形式给指定的成员变量赋值。 unapply 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 object ClassDemo {     case class Person(var name:String, var age:Int)     def main(args: Array[String]): Unit = {     val person = Person(name = "sjh", age = 24)     println(person)//Person(sjh,24)     val person1 = person.copy(age = 20)     println(person1)//Person(sjh,20)   }   } 样例对象 用 case 修饰的单例对象就叫样例对象,而且它没有主构造器,主要用在: 枚举值 作为没有任何参数的消息传递 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 object ClassDemo {     //特质 Sex,表示性别   trait Sex     //样例对象,表示男,继承 Sex 特质   case object Male extends Sex     //样例对象,表示女,继承 Sex 特质   case object Female extends Sex     //定义样例类 Person   case class Person(var name:String, var sex:Sex){}     def main(args: Array[String]): Unit = {     val p = Person("sjh", Male)   }   } 案例:计算器 定义样例类 Calculate,并在其中添加四个方法分别用来计算两个整数的加减乘除操作。 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 object ClassDemo {     case class Calculate(a:Int, b:Int){     def add(): Int = a + b     def sub(): Int = a - b     def mul(): Int = a * b     def div(): Int = a / b   }     def main(args: Array[String]): Unit = {     val res = Calculate(1, 1)     println(s"加法: ${res.add()}")//2     println(s"减法: ${res.sub()}")//0     println(s"乘法: ${res.mul()}")//1     println(s"除法: ${res.div()}")//1     }   } 数据结构 数组 定长数组 语法: 复制代码 1 2 val/var 变量名 = new Array[元素类型](数组长度) val/var 变量名 = new Array(元素1, 元素2 ...) 示例: 复制代码 1 2 3 4 5 6 def main(args: Array[String]): Unit = {     val arr = new Array[Int](10)     arr(0) = 1     println(arr(0))//1     println(arr.length)//10 } 变长数组 语法: 复制代码 1 2 val/var 变量名 = ArrayBuffer[元素类型] val/var 变量名 = ArrayBuffer(元素1, 元素2 ...) 示例: 复制代码 1 2 3 4 5 6 def main(args: Array[String]): Unit = {     val arr = ArrayBuffer[Int]()     val arr1 = ArrayBuffer("1", true, 3)     println(arr)//ArrayBuffer()     println(arr1)//ArrayBuffer(1, true, 3) } 增删改: 使用 += 添加单个元素 使用 -= 删除单个元素 使用 ++= 追加一个数组 使用 --= 移除多个元素 示例: 复制代码 1 2 3 4 5 6 7 8 def main(args: Array[String]): Unit = {     val arr = ArrayBuffer("spark", "hadoop", "flink")     arr += "flume"     arr -= "spark"     arr ++= Array("hive", "sqoop")     arr --= Array("sqoop", "hadoop")     println(arr)//ArrayBuffer(flink, flume, hive) } 遍历数组 通过索引 复制代码 1 2 3 4 5 6 for(i <- 0 to arr.length-1)//to包括右     println(arr(i)) for(i <- arr.indices)     println(arr(i)) for(i <- 0 until(arr.length))//until不包括右     println(arr(i)) 通过 for 循环 复制代码 1 2 for (elem <- arr)       println(elem) 数组常用算法 sum :求和 max:求最大值 min:求最小值 sorted:排序,返回一个新的数组 reverse:反转,返回一个新的数组 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 def main(args: Array[String]): Unit = {     val arr = Array(4,1,6,5,2,3)     println(arr.sum)//21     println(arr.max)//6     println(arr.min)//1     val arr1 = arr.sorted     for (elem <- arr1)     print(elem)//123456     println()     val arr2 = arr1.reverse     for (elem <- arr2)     print(elem)//654321 } 元组 元组一般用来存储不同类型的数据,并且长度和元素都不可变。 语法: 复制代码 1 2 3 4 //通过小括号实现 val/var 元组 = (元素1,元素2...) //通过箭头(只适用于有2个元素的情况) val/var 元组 = 元素1 -> 元素2... 示例: 复制代码 1 2 3 4 5 6 def main(args: Array[String]): Unit = {     val tuple = ("sjh", 24)     val tuple1 = "sjh" -> 24     println(tuple)//(sjh,24)     println(tuple1)//(sjh,24) } 访问元组中元素 通过 元组名._编号 形式访问元组中元素,编号从 1 开始。或者通过 元组名.productIterator 获取迭代器遍历。 示例: 复制代码 1 2 3 4 5 6 7 8 9 def main(args: Array[String]): Unit = {     val tuple = "sjh" -> 24     //方法1 通过编号     println(tuple._1)     //方法2 获取迭代器     val iterator = tuple.productIterator     for (elem <- iterator)     println(elem) } 列表 不可变列表 List 存储的数据有序、可重复,有序是指元素的存入和取出顺序是一致的。列表分为不可变列表和可变列表。 不可变列表指的是列表的元素、长度都不可变。 语法: 复制代码 1 2 3 val/var 变量名 = List(元素1,元素2...) val/var 变量名 = Nil val/var 变量名 = 元素1 :: 元素2 :: Nil 可变列表 语法: 复制代码 1 2 val/var 变量名 = ListBuffer[数据类型]() val/var 变量名 = ListBuffer(元素1,元素2...) 可变列表常用操作: 格式 功能 列表名(索引) 根据索引获取元素 列表名(索引) = 值 修改元素值 += 添加单个元素 ++= 追加列表 -= 删除某个元素 --= 删除多个元素 toList 转为不可变列表 toArray 转为数组 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 def main(args: Array[String]): Unit = {     val list = ListBuffer(1, 2, 3)     println(list(0))     list += 4     list ++= List(5, 6, 7)     list -= 7     list --= List(3, 4)     val list1 = list.toList     val array = list.toArray     println(list1)//List(1, 2, 5, 6)     for (elem <- array)  print(elem)//1256 } 列表常用操作 格式 功能 distinct 去重 isEmpty 判断是否为空 ++ 拼接两个列表 head 返回第一个元素 tail 返回除了第一个元素之外的其他元素 reverse 反转并返回新列表 take 获取前缀元素(自定义个数) drop 获取后缀元素(自定义个数) flatten 扁平化操作,返回新列表 zip 拉链操作,合并列表 unzip 拉开操作,拆分列表 toString 转换默认字符串 mkString 转换指定字符串 union 获取两个列表并集元素,返回新列表 intersect 获取两个列表交集元素,返回新列表 diff 获取两个列表差集元素,返回新列表 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 def main(args: Array[String]): Unit = {     val list = List(1, 2, 3, 4)     print(list.isEmpty)//false     val list2 = List(4, 5, 6)     val list3 = list ++ list2     println(list3)//List(1, 2, 3, 4, 4, 5, 6)     println(list3.head)//1     println(list3.tail)//List(2, 3, 4, 4, 5, 6)     //前3个是前缀     println(list3.take(3))//List(1, 2, 3)     //前3个是前缀,获取后缀     println(list3.drop(3))//List(4, 4, 5, 6) } 示例:扁平化操作 将嵌套列表(每个元素都是列表)的所有具体元素单独放到一个新的列表 复制代码 1 2 3 4 5 6 7 8 def main(args: Array[String]): Unit = {     val list1 = List(1, 2)     val list2 = List(3, 4)     val list = List(list1, list2, List(5))     val flatten = list.flatten     println(list)//List(List(1, 2), List(3, 4), List(5))     println(flatten)//List(1, 2, 3, 4, 5) } 示例:拉链与拉开 拉链:将两个列表组合成一个元素为元组的列表 拉开:将一个包含元组的列表,拆解成包含两个列表的元组 复制代码 1 2 3 4 5 6 7 8 def main(args: Array[String]): Unit = {   val names = List("sjh", "a", "bb")   val ages = List(24, 1, 10)   val list1 = names.zip(ages)   println(list1)//List((sjh,24), (a,1), (bb,10))   val tuple1 = list1.unzip   println(tuple1)//(List(sjh, a, bb),List(24, 1, 10)) } 示例:转换字符串 mkString 以指定符号分割元素 复制代码 1 2 3 4 5 def main(args: Array[String]): Unit = {   val list = List(1, 2, 3, 4)   println(list.toString())//List(1, 2, 3, 4)   println(list.mkString(":"))//1:2:3:4 } 集 不可变集 特点:唯一、无序 语法: 复制代码 1 2 3 4 //创建空的不可变集 val/var 变量名 = Set[类型]() //指定元素 val/var 变量名 = Set(元素1, 元素2...) 常用操作: size 获取大小 遍历操作和数组一致 + 添加元素,生成一个新的 Set ++ 拼接集或列表,生成一个新的 Set - 删除一个元素,生成一个新的 Set -- 删除多个元素,,生成一个新的 Set 可变集 导入包 复制代码 1 import scala.collection.mutable.Set 映射 不可变 Map 语法: 复制代码 1 2 3 4 //通过箭头 val/var map = Map(k1->v1, k2->v2...) //通过小括号 val/var map = Map((k1,v1), (k2,v2)...) 可变 Map 导入包 复制代码 1 import scala.collection.mutable.Map 基本操作: map(key) 获取键对应值,不存在返回None map.keys 获取所有键 map.values 获取所有值 遍历 通过普通for实现 getOrElse 根据键获取值,不存在返回指定默认值 + 增加键值对,生成一个新的 Map。如果是可变 Map,直接使用 += 或 ++= 。 - 删除键值对,生成一个新的 Map。如果是可变 Map,直接使用 -= 或 --= 。 示例: 复制代码 1 2 3 4 5 6 7 8 9 def main(args: Array[String]): Unit = {   val map = Map("sjh" -> 24, "ax" -> 10)   println(map.keys)//Set(ax, sjh)   println(map.values)//HashMap(10, 24)   for (elem <- map) { println(elem)}//(ax,10) (sjh,24)   println(map.getOrElse("sjh", 1))//24   map += "abc" -> 10   println(map)//Map(abc -> 10, ax -> 10, sjh -> 24) } 迭代器 使用 iterator 从集合获取迭代器,迭代器的两个方法: hasNext 判断是否有下一个元素 next 返回下一个元素,没有会抛出异常 示例: 复制代码 1 2 3 4 5 6 def main(args: Array[String]): Unit = {     val list = List(1, 2, 3, 4, 5)     val iterator = list.iterator     while (iterator.hasNext)     print(iterator.next())//12345 } 函数式编程 函数式编程指 方法的参数列表可以接收函数对象。 函数名 功能 foreach 遍历集合 map 转换集合 flatmap 扁平化操作 sorted 默认排序 sortBy 按照指定字段排序 sortWith 自定义排序 groupBy 按指定条件分组 reduce 聚合计算 fold 折叠计算 foreach 复制代码 1 2 3 4 5 6 7 8 9 def main(args: Array[String]): Unit = {   val list = List(1, 2, 3, 4, 5)   //函数格式 (函数参数列表) => {函数体}   list.foreach((x:Int) => {println(x)})   //简写格式1 通过类型推断省略参数数据类型   list.foreach(x => println(x))   //简写格式2 函数参数只在函数体出现一次,且函数体没有涉及复杂使用,可以使用下划线简化   list.foreach(println(_)) } map 将一种类型转换为另一种类型,例如将 Int 列表转为 String 列表 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 def main(args: Array[String]): Unit = {     val list = List(1, 2, 3, 4)     //将数字转换为对应个数的 *     val list2 = list.map((x:Int) => {"*" * x})     println(list2)//List(*, **, ***, ****)     //根据类型推断简化     val list3 = list.map(x => "*" * x)     println(list3)//List(*, **, ***, ****)     //下划线     val list4 = list.map("*" * _)     println(list4)//List(*, **, ***, ****) } flatMap 可以理解为先进行 map ,再进行 flatten 操作。 复制代码 1 2 3 4 5 6 7 8 9 def main(args: Array[String]): Unit = {   val list = List("hadoop hive spark flink", "kudu hbase storm")     val list2 =list.map(_.split(" ")).flatten   println(list2)//List(hadoop, hive, spark, flink, kudu, hbase, storm)     val list3 =list.flatMap(_.split(" "))   println(list2)//List(hadoop, hive, spark, flink, kudu, hbase, storm) } filter 过滤出符合一定条件的元素,示例,筛选偶数: 复制代码 1 2 3 4 def main(args: Array[String]): Unit = {   val list = (1 to 6).toList   println(list.filter(_ % 2 == 0))//List(2, 4, 6) } 排序 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 def main(args: Array[String]): Unit = {     //升序排序     val list = List(3, 1, 2, 9, 8)     println(list.sorted)//List(1, 2, 3, 8, 9)     //指定字段排序     val list2 = List("01 hadoop", "02 flume", "03 hive")     println(list2.sortBy(_.split(" ")(1)))//List(02 flume, 01 hadoop, 03 hive)     //自定义排序实现降序     val list3 = List(2, 3, 1, 6, 4, 5)     //第一个下划线表示前面的元素,第二个下划线表示后面的元素     println(list3.sortWith(_ > _))//List(6, 5, 4, 3, 2, 1) } group by 将数据按指定条件进行分组,示例,按照性别分组: 复制代码 1 2 3 4 5 6 7 8 9 10 def main(args: Array[String]): Unit = {     val list = List("sjh"->"男","ssf"->"女","ka"->"男")     //按照元素第二个元素分组     //val map = list.groupBy(x => x._2)     val map = list.groupBy(_._2)     println(map)//Map(男 -> List((sjh,男), (ka,男)), 女 -> List((ssf,女)))     //统计不同性别人数     val map2 = map.map(x => x._1 -> x._2.length)//不能用下划线简化,因为x在后面出现了2次     println(map2)//Map(男 -> 2, 女 -> 1) } reduce 和 fold 示例:计算1-10的和,reduce 相当于 reduceLeft,如果想从右到左计算使用 reduceRight 复制代码 1 2 3 4 5 6 7 8 def main(args: Array[String]): Unit = {     val list = (1 to 10).toList     //x表示聚合操作的结果,y表示下一个元素     var i = list.reduce((x, y) => x + y)     //简化     i = list.reduce(_ + _)     println(i)//55 } fold 和 reduce 很像,只是 fold 多了一个指定初始化值参数 fold 相当于 foldLeft,如果想从右到左计算使用 foldRight 示例:定义一个列表包括1-10,假设初始化值100,计算所有元素和 复制代码 1 2 3 4 5 6 def main(args: Array[String]): Unit = {     val list = (1 to 10).toList     //x表示聚合操作的结果,y表示下一个元素     val i = list.fold(100)(_ + _)     println(i)//155 } 案例:学生成绩单 定义列表,记录学生成绩,格式为:姓名,语文成绩,数学成绩,英语成绩。 获取所有语文成绩在60分以上得同学信息。 获取所有学生的总成绩。 按照总成绩降序排列。 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 def main(args: Array[String]): Unit = {     val list = List(("a", 37, 90 ,100), ("b", 90, 73 ,80), ("c", 60, 90, 76), ("d", 59, 21, 72), ("e", 100, 100, 100))     //获取语文成绩60分以上学生信息     val list1 = list.filter(_._2 > 60)     println(list1)//List((b,90,73,80), (e,100,100,100))       //获取所有学生总成绩     val list2 = list.map(x => x._1 -> (x._2 + x._3 + x._4))     println(list2)//List((a,227), (b,243), (c,226), (d,152), (e,300))       //按照总成绩降序排列     val list3 = list2.sortWith(_._2 > _._2)     println(list3)//List((e,300), (b,243), (a,227), (c,226), (d,152))   } 模式匹配、偏函数、异常、提取器 模式匹配 作用:判断固定值、类型查询、快速获取数据 简单模式匹配 格式: 复制代码 1 2 3 4 5 6 变量 match{     case 常量1 => 表达式1     case 常量2 => 表达式2     case 常量3 => 表达式3     case _ => 表达式4 //默认项 } 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 def main(args: Array[String]): Unit = {     println("输入一个单词")     val word = StdIn.readLine()     word match {         case "hadoop" => println("大数据分布式存储和计算框架")         case "zookeeper" => println("大数据分布式协调服务框架")         case "spark" => println("大数据分布式内存计算框架")         case _ => println("未匹配")     } } 匹配类型 格式: 复制代码 1 2 3 4 5 6 对象名 match{     case 变量名1:类型1 => 表达式1     case 变量名2:类型2 => 表达式2     case _:类型3 => 表达式3//表达式没用到变量名可以使用下划线代替     case _ => 表达式4 //默认项 } 示例: 复制代码 1 2 3 4 5 6 7 8 def main(args: Array[String]): Unit = {     val a:Any = "hadoop"     a match {         case x:String => println(s"${x}是字符串")         case x:Int => println(s"${x}是数字")         case _ => println("未匹配")     } } 守卫 守卫指在 case 中添加 if 条件判断,这样可以让代码更简洁。 格式: 复制代码 1 2 3 4 5 6 变量 match{     case 变量名 if 条件1 => 表达式1     case 变量名 if 条件2 => 表达式2     case 变量名 if 条件3=> 表达式3     case _ => 表达式4 //默认项 } 示例: 复制代码 1 2 3 4 5 6 7 8 def main(args: Array[String]): Unit = {   val a = StdIn.readInt()   a match {     case x if x > 0 => println("正数")     case x if x < 0 => println("负数")     case _ => println("是0")   } } 匹配样例类 要匹配的对象必须声明为 Any。 格式: 复制代码 1 2 3 4 5 6 对象名 match{     case 样例类型1(字段1, 字段2..) => 表达式1     case 样例类型2(字段1, 字段2..) => 表达式2     case 样例类型3(字段1, 字段2..) => 表达式3     case _ => 表达式4 //默认项 } 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 object ClassDemo {     case class Customer(name:String, age:Int)     case class Order(id:Int)     def main(args: Array[String]): Unit = {     val a:Any = Customer("sjh", 20)     a match {       case Customer => println("是customer")       case Order => println("是order")       case _ => println("未匹配")     }   }   } 匹配集合 匹配数组 复制代码 1 2 3 4 5 6 7 8 9 10 11 def main(args: Array[String]): Unit = {   //定义三个数组   val arr1 = Array(1, 2, 3)   val arr2 = Array(0)   val arr3 = Array(0 , 1, 2, 3,4)   arr1 match {     case Array(1, _, _) => println("长度为3,首元素为1")     case Array(0) => println("长度为1,元素0")     case Array(0, _*) => println("首元素0,其余任意")   } } 匹配列表 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 def main(args: Array[String]): Unit = {     //定义三个列表     val list1 = List(1, 2, 3)     val list2 = List(0)     val list3 = List(0, 1, 2, 3,4)     list3 match {         case List(1, _, _) => println("长度为3,首元素为1")         case List(0) => println("长度为1,元素0")         case List(0, _*) => println("首元素0,其余任意")     }     //等价于     list2 match {         case 1 :: _ :: _ ::Nil => println("长度为3,首元素为1")         case 0 :: Nil => println("长度为1,元素0")         case 0 :: _ => println("首元素0,其余任意")     } } 匹配元组 复制代码 1 2 3 4 5 6 7 8 9 10 11 def main(args: Array[String]): Unit = {     //定义三个元组     val a = (1, 2, 3)     val b = (3, 4, 5)     val c = (3, 4)     a match {         case (1, _, _) => println("长度为3,首元素为1")         case (_, _, 5) => println("长度为3,尾元素为5")         case _ => println("不匹配")     } } 变量声明中的模式匹配 在定义变量时,可以使用模式匹配快速获取数据 生成包含 0-10的数字,使用模式匹配分别获取第2、3、4个元素 生成包含 0-10的列表,使用模式匹配分别获取第1、2个元素 复制代码 1 2 3 4 5 6 7 8 9 10 def main(args: Array[String]): Unit = {     val arr = (0 to 10).toArray     val Array(_, x, y, z, _*) = arr     println(x, y, z)//(1,2,3)     val list = (0 to 10).toList     val List(a, b, _*) = list     val c :: d ::tail = list     println(a, b)//(0,1)     println(c, d)//(0,1) } 匹配 for 表达式 定义变量记录学生姓名和年龄,获取所有年龄为20的学生信息: 复制代码 1 2 3 4 5 6 7 8 9 def main(args: Array[String]): Unit = {   val map = Map("sjh" -> 20, "a" -> 21, "asx" -> 20)   //方式一 if   for((k, v) <- map if v == 20)     println(k, v)   //方式二 固定值   for((k, 20) <- map)     println(k, 20) } Option 类型 用来避免空指针异常,具体值使用 Some(x),空值使用 None 示例:定义一个两数相除的方法,使用 Option 类型封装结果 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 object ClassDemo {     def divide(a:Int, b:Int): Option[Int] = {     if(b == 0)       None     else       Some(a / b)   }     def main(args: Array[String]): Unit = {     divide(10, 0) match {       case None => println("除数不能为 0")       case Some(x) => println(s"结果为$x")     }   }   } 偏函数 可以配合集合的函数式编程简化代码。 偏函数是指 被包在花括号内没有 match 的一组 case语句。 示例: 复制代码 1 2 3 4 5 6 7 8 def main(args: Array[String]): Unit = {     val pf:PartialFunction[Int, String] = {         case 1 => "一"         case 2 => "二"         case _ => "未匹配"     }     println(pf(1))//一 } 偏函数可结合 map 函数使用。 定义一个列表包含1-10的数字,将1-3的数字转为[1-3],4-8的数字转为[4-8],其余数字转为(8-*] 复制代码 1 2 3 4 5 6 7 8 9 def main(args: Array[String]): Unit = {   val list = (1 to 10).toList   val list1 = list.map {     case x if x >= 1 && x <= 3 => "[1-3]"     case x if x >= 4 && x <= 8 => "[4-8]"     case _ => "(8,*]"   }   println(list1)//List([1-3], [1-3], [1-3], [4-8], [4-8], [4-8], [4-8], [4-8], (8,*], (8,*]) } 正则表达式 Scala 提供了 Regex 类定义正则表达式 要构造一个 Regex 对象直接使用 String 类的 r 方法即可 建议使用三个双引号表示正则表达式,不需要对其中的反斜杠转义。 格式: 复制代码 1 val 正则对象名 = """具体正则表达式""".r 示例:校验邮箱 复制代码 1 2 3 4 5 6 7 8 def main(args: Array[String]): Unit = {     val regex = """.+@.+\.com""".r     val email = "sad@qq.com"     if(regex.findAllMatchIn(email).nonEmpty)     println("合法")     else     println("不合法") } 示例:过滤出不合法的邮箱 复制代码 1 2 3 4 5 6 def main(args: Array[String]): Unit = {   val regex = """.+@.+\.com""".r   val emailList = List("sad@.com", "asda@qq.com", "***@,cn")   val list = emailList.filter((x) => regex.findAllMatchIn(x).isEmpty)   println(list)//List(sad@.com, ***@,cn) } 示例:获取邮箱运营商 复制代码 1 2 3 4 5 6 7 8 9 10 def main(args: Array[String]): Unit = {     //括号可以充当分组角色,用来提取其中内容     val regex = """.+@(.+)\.com""".r     val emailList = List("sad@.com", "asda@qq.com", "***@,cn")     val list = emailList.map{         case x @ regex(company) => x -> company         case x => x -> "未匹配"     }     println(list)//List((sad@.com,未匹配), (asda@qq.com,qq), (***@,cn,未匹配)) } 异常处理 捕获异常 该方式处理完异常,程序会继续执行 抛出异常 该方式处理完异常,程序会终止执行 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 def main(args: Array[String]): Unit = {     //捕获异常     try{         val i = 10 / 0     }catch {         case _:ArithmeticException => println("算术异常")         case _ => println("其他异常")     }finally {         println("一般用来释放资源")     }     //抛出异常     throw new Exception("发生异常") } 提取器 一个类如果要支持模式匹配,必须要实现一个提取器。 提取器就是指 unapply 方法。 样例类自动实现了 unapply 方法。 要实现提取器,只需要在该类的伴生对象中实现一个unapply 方法即可。 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 object ClassDemo {     class Student(var name:String, var age:Int)     object Student{     //apply 根据给定字段将其封装为 Student 类型对象     def apply(name: String, age: Int): Student = new Student(name, age)       //unapply 根据传入的学生对象,获取其各个属性值     def unapply(s: Student): Option[(String, Int)] = {       if(s == null)         None       else         Some(s.name, s.age)     }   }     def main(args: Array[String]): Unit = {     val s = Student("sjh", 24)     //获取 s 的属性     //通过 unapply     println(Student.unapply(s))     //通过模式匹配 需要实现 unapply方法     s match {       case Student(name, age) => println(s"$name,$age")       case _ => println("未匹配")     }   }   } 案例:随机职业 提示用户录入一个数字(1-5),然后根据数字打印出他的工作。 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 def main(args: Array[String]): Unit = {   println("请输入一个数字,1-5:")   val num = StdIn.readInt()   num match {     case 1 => println("BAT offer")     case 2 => println("BAT offer")     case 3 => println("BAT offer")     case 4 => println("BAT offer")     case 5 => println("BAT offer")     case _ => println("在家科研,哪都别去")   } } 数据的读写 读取数据 在 Source 单例对象中提供了一些获取数据的方法。 按行读取 以行为单位,返回值是一个迭代器类型的对象,通过toArray、toList方法将数据放到数组或列表。 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 def main(args: Array[String]): Unit = {     //创建 Source 对象,关联数据源文件     val source = Source.fromFile("./data/1.txt")//在项目中创建一个 data目录和对应文件     //以行为单位读取数据     val lines:Iterator[String] = source.getLines()     //将读取到的数据封装到 List 集合     val list:List[String] = lines.toList     //打印结果     for(data <- list)     println(data)     //关闭 Source     source.close() } 按字符读取 复制代码 1 2 3 4 5 6 7 8 9 10 11 def main(args: Array[String]): Unit = {     //创建 Source 对象,关联数据源文件     val source = Source.fromFile("./data/1.txt")//默认使用utf-8     //以字符为单位读取数据     val buffered:BufferedIterator[Char] = source.buffered     //打印结果     while(buffered.hasNext)     print(buffered.next())//不能使用println     //关闭 Source     source.close() } 如果文件内容较少,可以直接把它读取到一个字符串中: 复制代码 1 2 3 4 5 6 7 8 9 10 def main(args: Array[String]): Unit = {     //创建 Source 对象,关联数据源文件     val source = Source.fromFile("./data/1.txt")     //将数据读取到字符串     val string = source.mkString     //打印结果     println(string)     //关闭 Source     source.close() } 读取词法单元和数字 词法单元指 以特定符号间隔开的字符串 创建一个文本文件 复制代码 1 2 3 10 2 5 11 2 5 1 3 2 读取所有整数,将结果加1并打印 复制代码 1 2 3 4 5 6 7 8 9 10 11 def main(args: Array[String]): Unit = {     //创建 Source 对象,关联数据源文件     val source = Source.fromFile("./data/1.txt")     //将数据读取到字符串数组 \s 表示空白字符(空格,\t,\r,\n等)     val strArr:Array[String] = source.mkString.split("\\s+")     val intArr:Array[Int] = strArr.map(_.toInt)     //打印结果     for (elem <- intArr) {print(elem + " ")}//11 3 6 12 3 6 2 4 3     //关闭 Source     source.close() } 从 URL 或其他源读取 从 URL 地址读取 复制代码 1 val source = Source.fromURL("http:www.baidu.com") 从字符串读取 复制代码 1 val source = Source.fromString("字符串读取数据") 读取二进制文件 示例:读取图片 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 def main(args: Array[String]): Unit = {   //创建File对象关联文件   val file = new File("./data/1.jpg")   //创建字节输入流   val fis = new FileInputStream(file)   val bytes = new Array[Byte](file.length().toInt)   //开始读取   val len = fis.read(bytes)   println(s"读取到的字节数:$len")   //关闭字节输入流   fis.close() } 写入数据 要使用 Java 的类库 往文件中写入指定内容 复制代码 1 2 3 4 5 6 7 8 def main(args: Array[String]): Unit = {   //创建字节输出流   val fos = new FileOutputStream("./data/1.txt")//目的地不存在会自动创建   //输出   fos.write("GetOffer".getBytes())   //关闭输出流   fos.close() } 序列化和反序列化 要实现序列化必须继承 Serializable 特质(标记接口),如果是样例类可以省略继承 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 case class Person(name:String, age:Int) [extends Serializable]   def main(args: Array[String]): Unit = {   val p = Person("sjh", 24)   //序列化   val outputStream = new ObjectOutputStream(new FileOutputStream("./data/2.txt"))   outputStream.writeObject(p)   outputStream.close()   //反序列化   val inputStream = new ObjectInputStream(new FileInputStream("./data/2.txt"))   val person = inputStream.readObject().asInstanceOf[Person]//读取出的对象是AnyRef,要转换   println(person)   inputStream.close() } 案例:学员成绩表 已知项目 data 文件夹下的 1.txt 记录了学生成绩如下: 复制代码 1 2 3 4 5 张三 37 90 100 李四 90 73 81 王五 60 90 76 赵六 89 21 72 田七 100 100 100 按照学生总成绩进行排名,按照姓名-语文成绩-数学成绩-英语成绩-总成绩的格式,输出到 2.txt 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 case class Student(var name:String,var chinese:Int, var math:Int, var english:Int){   def getSum:Int = chinese + math +english }   def main(args: Array[String]): Unit = {   //获取数据源文件   val source = Source.fromFile("./data/1.txt")   //封装到数组   val array:Iterator[Array[String]] = source.getLines().map(_.split(" "))   //定义可变列表存储学生信息   val stuList = ListBuffer[Student]()   //遍历数组,将数据封装成 Student 对象,添加到可变列表   for(s <- array){     stuList += Student(s(0), s(1).toInt, s(2).toInt, s(3).toInt)   }   //排序   val list = stuList.sortBy(_.getSum).reverse.toList   //通过字符输出流输出文件   val bw = new BufferedWriter(new FileWriter("./data/2.txt"))   bw.write("姓名 语文 数学 英语 总分")   bw.newLine()   for(s <- list){     bw.write(s"${s.name} ${s.chinese} ${s.math} ${s.english} ${s.getSum}")     bw.newLine()//换行   }   //关闭资源   bw.close()   source.close() } 2.txt: 复制代码 1 2 3 4 5 6 姓名 语文 数学 英语 总分 田七 100 100 100 300 李四 90 73 81 244 张三 37 90 100 227 王五 60 90 76 226 赵六 89 21 72 182 高阶函数 Scala 混合了面向对象和函数式特性,如果一个函数的参数列表可以接收函数对象,那么这个函数就被称为高阶函数。 作为值的函数 可以将函数对象传递给方法 。 需求:将一个整数列表中的每个元素转换为对应个数的*。 复制代码 1 2 3 4 5 6 def main(args: Array[String]): Unit = {     val list = (1 to 5).toList     val func = (x:Int) => "*" * x     val list1 = list.map(func)     println(list1)//List(*, **, ***, ****, *****) } 匿名函数 没有赋值给变量的函数就是匿名函数 复制代码 1 2 3 4 5 6 7 def main(args: Array[String]): Unit = {   val list = (1 to 5).toList   val list1 = list.map((x:Int) => "*" * x)   val list2 = list.map("*" * _)   println(list1)//List(*, **, ***, ****, *****)   println(list2)//List(*, **, ***, ****, *****) } 柯里化 柯里化指 将原先接收多个参数的方法转换为多个只有一个参数列表的过程 需求:定义方法完成两个字符串的拼接 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 object ClassDemo {     //普通写法   def merge1(str1:String, str2:String): String = str1 + str2     //柯里化 f1表示函数   def merge2(str1:String, str2:String)(f1:(String, String) => String): String = f1(str1, str2)     def main(args: Array[String]): Unit = {     println(merge1("abc", "def"))//abcdef     println(merge2("abc", "def")(_ + _))//abcdef   }   } 闭包 闭包指 可以访问不在当前作用域范围数据的一个函数。(柯里化就是一个闭包) 通过闭包获取两个整数的和: 复制代码 1 2 3 4 5 def main(args: Array[String]): Unit = {     val x = 10     val sum = (y:Int) => x + y     println(sum(10))//20 } 控制抽象 假设函数 A 的参数列表需要接收一个函数 B,而函数B没有输入值也没有返回值,那么函数A称为控制抽象函数。 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 object ClassDemo {     val func = (f1:() => Unit) => {     println("welcome")     f1()     println("bye")   }     def main(args: Array[String]): Unit = {     func(() => println("shopping.."))   }   } 结果: 复制代码 1 2 3 welcome shopping.. bye 案例:计算器 定义一个方法,用来完成两个 Int 类型数字的计算 具体计算封装到函数中 使用柯里化完成操作 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 object ClassDemo {     //普通写法   def add(a:Int, b:Int): Int = a + b   def sub(a:Int, b:Int): Int = a - b   def mul(a:Int, b:Int): Int = a * b   def div(a:Int, b:Int): Int = a / b     //柯里化   def calculate(a:Int, b:Int)(func:(Int,Int) => Int): Int = func(a, b)     def main(args: Array[String]): Unit = {     println(calculate(1, 1)(_ + _))//2     println(calculate(1, 1)(_ - _))//0     println(calculate(1, 1)(_ * _))//1     println(calculate(1, 1)(_ / _))//1     }   } 隐式转换和隐式参数 隐式转换 隐式转换指用 implicit 关键字 声明的带有 单个参数 的方法。该方法是被自动调用的,用来实现自动将某种类型的数据转换为另一种类型的数据。 示例:手动导入 通过隐式转换,让 File 类的对象具有 read 功能。 执行流程:file对象没有read方法 -> 有隐式转换 -> 将File转为RichFile对象 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 object ClassDemo {     class RichFile(file: File){     //定义 read 方法     def read(): String = Source.fromFile(file).mkString   }     object Implicit{     implicit def file2RichFile(file: File): RichFile = new RichFile(file)   }     def main(args: Array[String]): Unit = {     //手动导入     import Implicit.file2RichFile     val file = new File("./data/1.txt")     file.read()   }   } 自动调用隐式转换: 当对象调用类中不存在的方法或成员时 当方法参数类型与目标类型不一致时 如果在当前作用域存在隐式转换方***自动导入隐式转换 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 object ClassDemo {     class RichFile(file: File){     //定义 read 方法     def read(): String = Source.fromFile(file).mkString   }     def main(args: Array[String]): Unit = {     //自动导入     implicit def file2RichFile(file: File): RichFile = new RichFile(file)       val file = new File("./data/1.txt")     file.read()   }   } 隐式参数 隐式参数指用 implicit 关键字 修饰的变量。调用方法时可以不给定初始值,因为编译器会自动查找缺省值。 使用步骤: 在方法后添加一个参数列表,参数使用 implicit 修饰 在 object 中定义 implicit 修饰的隐式值 调用该方法,可以不传入 implicit 修饰的参数值 和隐式转换一样,可以手动导入,如果作用域内定义了隐式值可以自动导入。 定义一个show方法,实现将传入的值,使用指定前缀分隔符和后缀分隔符包装起来。 例如 show("a")("<<",">>") // <<a>> 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 object ClassDemo {     //name表示姓名,第一个String表示前缀信息,第二个String表示后缀信息   def show(name:String)(implicit delimit:(String, String)): String = delimit._1 + name +delimit._2     //定义单例对象,用来给隐式参数默认值   object Implicit{     implicit val delimit_default: (String, String) = ("<<" ,">>")   }     def main(args: Array[String]): Unit = {     //手动导入     import Implicit.delimit_default     //调用show     println(show("abc"))//<<abc>>     println(show("abc")("<-", "->"))//<-abc->   }   } 自动导入 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 object ClassDemo {     //name表示姓名,第一个String表示前缀信息,第二个String表示后缀信息   def show(name:String)(implicit delimit:(String, String)): String = delimit._1 + name +delimit._2     def main(args: Array[String]): Unit = {     //自动导入     implicit val delimit_default: (String, String) = ("<<" ,">>")     //调用show     println(show("abc"))//<<abc>>     println(show("abc")("<-", "->"))//<-abc->   }   } 案例:获取列表元素平均值 通过隐式转换,获取列表中所有元素的平均值。 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 object ClassDemo {     class RichList(list: List[Int]){     def avg(): Option[Int] = {       if(list.isEmpty)         None       else         Some(list.sum / list.size)     }   }     def main(args: Array[String]): Unit = {     //自动导入     implicit def list2RichList(list: List[Int]): RichList = new RichList(list)     //调用     val list = (1 to 10).toList     println(list.avg())//Some(5)   }   } 递归 递归就是方法自己调用自己 示例:求阶乘 复制代码 1 2 3 4 5 6 7 8 9 object ClassDemo {     def f(n: Int): Int = if(n == 1) n else n * f(n - 1)     def main(args: Array[String]): Unit = {     println(f(5))   }   } 内存图解 Scala 中,内存分为五部分 栈 所有代码的执行、存储局部变量。 按照 FILO 的顺序执行,方法执行完毕后立马被回收。 堆 存储所有new 出来的对象。 在不确定的时间被垃圾收集器回收。 方法区 存储字节码文件,方法等数据。 程序执行完毕后,由操作系统回收资源。 本地方法区 和本地方法相关。 寄存器 和 CPU 相关。 斐波那契数列 已知数列1,1,2,3,5,8,13,求第12个数字。 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 object ClassDemo {     def f(n: Int): Int = {     if(n == 1 || n == 2)       1     else       f(n - 1) + f(n - 2)   }     def main(args: Array[String]): Unit = {     println(f(12))//144   }   } 案例:打印目录文件 定义 printFile 方法,该方法打印该文件夹下所有文件路径。 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 object ClassDemo {     def printFile(dir: File): Unit = {     if(!dir.isDirectory)       println("路径不合法")     else {       //获取该目录下所有文件及文件夹       val files:Array[File] = dir.listFiles()       for(listFile <- files){         if(listFile.isDirectory)           printFile(listFile)         else           println(listFile)       }     }   }     def main(args: Array[String]): Unit = {     printFile(new File("d:/"))   }   } 泛型 泛型 泛型的意思是 泛指某种具体的数据类型,在 Scala 中泛型用 [数据类型] 表示。 泛型方法 示例,定义一个泛型方法,获取任意数据类型的中间元素 复制代码 1 def getMiddleElement[T](array: Array[T]): T = {array(array.length / 2)} 泛型类 示例,定义一个 Pair 泛型类,包含两个字段且字段类型不固定 复制代码 1 class Pair[T](var a:T, var b:T) 泛型特质 复制代码 1 2 3 4 5 6 7 8 9 10 11 trait Logger[T]{   val a:T     def show(b:T) }   object ConsoleLogger extends Logger[String]{   override val a: String = "sjh"     override def show(b: String): Unit = println(b) } 上下界 上界 使用 T <: 类型名 表示给类型添加一个上界,表示该类型必须是 T 或 T 的子类。 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 object ClassDemo {     class Person     class Student extends Person     def demo[T <: Person](array: Array[T]): Unit = println(array)     def main(args: Array[String]): Unit = {     demo(Array(new Person))     demo(Array(new Student))     demo(Array("a"))//报错   }   } 下界 使用 T >: 类型名 表示给类型添加一个下界,表示该类型必须是 T 或 T 的父类。 如果泛型既有上界又有下界,下界写在前面,[T >: A <: B] 协变、逆变、非变 协变:类 A 和 类 B 之间是父子类关系,Pair[A] 和 Pari[B] 之间也有父子关系。 复制代码 1 class Pair[+T]{} 逆变:类 A 和 类 B 之间是父子类关系,但 Pair[A] 和 Pari[B] 之间是子父关系。 复制代码 1 class Pair[-T]{} 非变:类 A 和 类 B 之间是父子类关系,Pair[A] 和 Pari[B] 之间没有任何关系。 复制代码 1 class Pair[T]{} //默认类型是非变的 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 object ClassDemo {     class Super     class Sub extends Super     class Temp1[T]     class Temp2[+T]     class Temp3[-T]     def main(args: Array[String]): Unit = {     //测试非变     val t1:Temp1[Sub] = new Temp1[Sub]     //val t2:Temp1[Super] = t1 报错     //测试协变     val t3:Temp2[Sub] = new Temp2[Sub]     val t4:Temp2[Super] = t3     //测试逆变     val t5:Temp3[Super] = new Temp3[Super]     val t6:Temp3[Sub] = t5   }   } 集合 分类: 可变集合 线程不安全 集合本身可以动态变化,且可变集合提供了改变集合内元素而都方法。 复制代码 1 scala.collection.mutable //需要手动导包 不可变集合 线程安全 默认类库,集合内的元素一旦初始化完成就不可再进行更改,任何对集合的改变都将生成一个新的集合。 复制代码 1 scala.collection.immutable //不需要手动导包 Set 无序、唯一 HashSet SortedSet TreeSet BitSet ListSet Seq 序列、有序、可重复、元素有索引 IndexedSeq 索引序列,随机访问效率高 NumericRange Range的加强 Range 有序整数序列,类似等差数列 Vector 通用不可变的数据结构,获取元素时间长,随机更新快于数组或列表 String 字符串 LinearSeq 线性序列,主要操作首尾元素 List 列表 Queue 队列 Stack 栈 不可变栈已经弃用 Stream 流 Map HashMap SortedMap TreeMap ListMap 可变集合比不可变集合更丰富,例如在 Seq 中,增加了 Buffer 集合,例如 ArrayBuffer 和 ListBuffer。 Traverable Traverable 是一个特质,它的子特质 immutable.Traverable 和 mutable.Traverable 分别是不可变集合和可变集合的父特质。 格式: 创建空的Traverable 对象。 复制代码 1 2 3 val t = Traverable.empty[Int] val t = Traverable[Int]() val t = Nil 创建带参数的Traverable 对象。 复制代码 1 2 val t = List(1, 2, 3).toTraverable val t = Traverable(1, 2, 3)//默认生成List 转置: 使用 transpose 方法。 转置操作时,需要每个集合的元素个数相同。 复制代码 1 2 3 4 5 6 def main(args: Array[String]): Unit = {   val t1 = Traversable(Traversable(1, 4, 7), Traversable(2, 5, 8), Traversable(3, 6, 9))   println(t1)//List(List(1, 4, 7), List(2, 5, 8), List(3, 6, 9))   val transpose = t1.transpose   println(transpose)//List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9)) } 拼接: ++ 可以拼接数据,但是会创建大量临时集合,可以通过 concat 方法实现。 复制代码 1 2 3 4 5 6 def main(args: Array[String]): Unit = {   val t1 = Traversable(1, 2, 3)   val t2 = Traversable(4, 5, 6)   val traversable = Traversable.concat(t1, t2)   println(traversable)//List(1, 2, 3, 4, 5, 6) } 筛选: 利用 collect 方法实现偏函数结合集合使用,从集合中筛选指定数据。 复制代码 1 2 3 4 5 6 7 8 9 10 11 def main(args: Array[String]): Unit = {   val t1 = (1 to 10).toList   def filter:PartialFunction[Int, Int] = {     case x if x % 2 == 0 => x   }   //val t2 = t1.collect(filter)   val t2 = t1.collect({     case x if x % 2 == 0 => x   })   println(t2)//List(2, 4, 6, 8, 10) } scan 方法 复制代码 1 def scan[B](z:B)(op: (B, B) => B) [B] 表示返回值的数据类型,(z:B)表示初始化值,(op: (B, B) => B)表示具体的函数运算。 示例:定义 traversable 集合,存储1-5,假设初始值为1,分别获取每个元素的阶乘值。 复制代码 1 2 3 4 5 6 def main(args: Array[String]): Unit = {   val t1 = 1 to 5   //val seq = t1.scan(1)((a, b) => a * b)   val seq = t1.scan(1)(_ * _)   println(seq)//Vector(1, 1, 2, 6, 24, 120) } 获取集合指定元素 head/last : 获取第一个/最后一个元素,不存在抛出异常 headOption/lastOption : 获取获取第一个/最后一个元素,返回值是 Option find: 查找符号条件的第一个元素 slice :截取集合中的一部分元素,左闭右开 复制代码 1 2 3 4 5 6 7 8 9 def main(args: Array[String]): Unit = {   val t1 = 1 to 5   println(t1.head)//1   println(t1.last)//5   println(t1.headOption)//Some(1)   println(t1.lastOption)//Some(5)   println(t1.find(_ % 2 == 0))//Some(2)   println(t1.slice(0, 2))//Vector(1, 2) } 判断元素是否合法 forall 如果集合中所有元素都满足条件返回 true exist 如果集合中有一个元素满足条件返回 true 复制代码 1 2 3 4 5 def main(args: Array[String]): Unit = {   val t1 = 1 to 5   println(t1.forall(_ % 2 == 0))//false   println(t1.exists(_ % 2 == 0))//true } 聚合函数 count 统计集合中满足条件的元素个数 sum 获取集合元素和 product 获取集合中所有元素成绩 max 获取集合中所有元素最大值 min 获取集合中所有元素最小值 集合类型转换 toList toSet toArray toSeq 填充元素 fill 快速生成指定数量的元素 iterator 根据指定条件,生成指定个数的元素 range 生成某个区间内的指定间隔的所有数据,不传间隔参数默认 1 复制代码 1 2 3 4 5 6 7 8 9 10 def main(args: Array[String]): Unit = {   val t1 = Traversable.fill(5)("a")   println(t1)//List(a, a, a, a, a)   val t2 = Traversable.fill(2, 2, 2)("a")   println(t2)//List(List(List(a, a), List(a, a)), List(List(a, a), List(a, a)))   val t3 = Traversable.iterate(1, 5)(_ * 10)   println(t3)//List(1, 10, 100, 1000, 10000)   val t4 = Traversable.range(1, 100, 7)   println(t4)//List(1, 8, 15, 22, 29, 36, 43, 50, 57, 64, 71, 78, 85, 92, 99) } 案例:随机学生序列 定义一个 Traversable 集合,包含 5 个学生信息,学生姓名年龄随机生成。 按照学生年龄降序排列并打印。 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 object ClassDemo {     case class Student(name:String, age:Int)     def main(args: Array[String]): Unit = {     val names: List[String] = List("aa" ,"bb", "cc", "dd", "ee")     val r:Random = new Random()     val students = Traversable.fill(5)(Student(names(r.nextInt(names.size)), r.nextInt(10) + 20))     val list = students.toList     val list1 = list.sortWith(_.age < _.age)     println(list1)//List(Student(ee,22), Student(bb,23), Student(ee,23), Student(ee,24), Student(aa,26))   }   } Iterable Iterable 表示一个可以迭代的集合,它继承了 Travsersable 特质,同时也是其他集合的父特质。它定义了获取迭代器的方法,这是一个抽象方法。 遍历集合示例: 复制代码 1 2 3 4 5 6 7 8 9 def main(args: Array[String]): Unit = {   val list = List(1, 2, 3, 4, 5)   //方式一 主动迭代   val iterator = list.iterator   while (iterator.hasNext)     print(iterator.next() + " ")   //方式二 被动迭代   list.foreach(x => print(x + " ")) } 分组遍历示例: 复制代码 1 2 3 4 5 6 def main(args: Array[String]): Unit = {   val i = (1 to 5).toIterable   val iterator = i.grouped(2)   while (iterator.hasNext)     print(iterator.next() +" ")//Vector(1, 2) Vector(3, 4) Vector(5) } 按照索引生成元组: 复制代码 1 2 3 4 5 def main(args: Array[String]): Unit = {     val i = Iterable("A", "B", "C", "D", "E")     val tuples = i.zipWithIndex.map(x => x._2 -> x._1)     println(tuples)//List((0,A), (1,B), (2,C), (3,D), (4,E)) } 判断集合是否相同: 复制代码 1 2 3 4 5 6 7 def main(args: Array[String]): Unit = {   val i1 = Iterable("A", "B", "C")   val i2 = Iterable("A", "C", "B")   val i3 = Iterable("A", "B", "C")   println(i1.sameElements(i2))//false   println(i1.sameElements(i3))//true } Seq Seq 特质代表 按照一定顺序排列的元素序列,序列是一种特别的可迭代集合,它的特点是有序、可重复、有索引 创建 Seq 集合: 复制代码 1 2 3 4 def main(args: Array[String]): Unit = {   val seq = (1 to 5).toSeq   println(seq)//Range(1, 2, 3, 4, 5) } 获取长度及元素: 通过 length 或 size 方法获取长度,通过索引直接获取元素。 复制代码 1 2 3 4 5 6 def main(args: Array[String]): Unit = {   val seq = (1 to 5).toSeq   println(seq.length)//5   println(seq.size)//5   println(seq(0))//1 } 获取指定元素的索引值 indexOf 获取指定元素在列表中第一次出现的位置 lastIndexOf 获取指定元素在列表中最后一次出现的位置 indexWhere 获取满足条件的元素,在集合中第一次出现的索引 lastIndexWhere 获取满足条件的元素,在集合中最后一次出现的索引 indexOfSlice 获取指定的子序列在集合中第一次出现的位置 找不到返回 -1。 判断是否包含指定数据: startsWith 是否以指定子序列开头 endsWith 是否以指定子序列结尾 contains 判断是否包含某个指定数据 containsSlice 判断是否包含某个指定子序列 修改指定的元素: updated 修改指定索引位置的元素为指定的值。 patch 修改指定区间的元素为指定的值。 复制代码 1 2 3 4 5 6 7 8 def main(args: Array[String]): Unit = {   val seq = (1 to 5).toSeq   val seq1 = seq.updated(0, 5)   println(seq1)//Vector(5, 2, 3, 4, 5)   //参数1 起始索引 参数2 替换后的元素 参数3 替换几个   val seq2 = seq.patch(1, Seq(1, 2), 3)   println(seq2)//Vector(1, 1, 2, 4, 5) } Stack top 获取栈顶元素 push 入栈 pop 出栈 clear 清除所有元素 mutable.Stack 有一个独有方法 pushAll,把多个元素压入栈中。 ArrayStack 有独有方法为:dup,复制栈顶元素。preseving,执行表达式,执行完毕后恢复栈。 操作示例: 复制代码 1 2 3 4 5 6 7 8 9 def main(args: Array[String]): Unit = {   //从右往左入栈   val s = mutable.Stack(1, 2, 3, 4, 5)   println(s.top)//1   println(s.push(6))//Stack(6, 1, 2, 3, 4, 5)   println(s.pushAll(Seq(7, 8, 9)))//Stack(9, 8, 7, 6, 1, 2, 3, 4, 5)   println(s.pop())//9   println(s.clear())//() } 定义可变栈存储1-5,通过dup方法复制栈顶元素,通过preseving 方法先清空元素再恢复。 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 def main(args: Array[String]): Unit = {   //从右往左入栈   val s = mutable.ArrayStack(1, 2, 3, 4, 5)   //复制栈顶元素   s.dup()   println(s)//ArrayStack(1, 1, 2, 3, 4, 5)   s.preserving({     //该方法执行后,栈中数据会恢复     s.clear()   })   println(s)//ArrayStack(1, 1, 2, 3, 4, 5) } Queue 表示队列,特点是 FIFO,常用的队列是 mutable.Queue,内部以 MutableList 实现。 enqueue 入队 dequeue 出队 dequeueAll 移除所有满足条件的元素 dequeueFirst 移除第一个满足条件的元素 案例:统计字符个数 提示用户录入字符串并接受,统计每个字符出现的次数并打印。 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 def main(args: Array[String]): Unit = {   println("请输入一个字符串:")   val str = StdIn.readLine()   val map = mutable.Map[Char, Int]()   for(c <- str.toCharArray){     if(!map.contains(c))       map += c -> 1     else       map += c -> (map.getOrElse(c, 1) + 1)   }   map.foreach(println(_)) }
分享
1
先马后看
Keddy减肥了吗
北京交通大学·2022届

华为硬件工程师笔试题型

45选择题,单选题40道,多选题5道
分享
6
先马后看
忙着可爱
浙江大学·2022届

张瑞敏再挥铁锤,砸向物联网大门

在中国,因“锤子”而享有盛名的企业家有两位。 一位是锤子科技创始人罗永浩,今年48岁;另一位是海尔集团CEO张瑞敏,今年71岁。 现在,年近半百的罗永浩已经不再像当初那样“锐利”,选择与现实和解,努力地想扮演好直播带货网红的角色。 而年过古稀的张瑞敏却峥嵘依旧,如同过去那样,再次挥起铁锤,这一次,他想要为海尔砸出一个物联网时代的崭新未来。 张瑞敏的第三锤,砸向所有传统桎梏 张瑞敏的故事比罗永浩久远太多,所以现在的年轻人可能对罗永浩2011年砸冰箱的故事有所耳闻,却鲜少有人清楚罗永浩这一维权手段,是在向张瑞敏致敬。 在20世纪80年代,张瑞敏曾做过和罗永浩相同的动作,举起铁锤砸烂冰箱,起因也相似:冰箱的质量有问题。 1985年,有一位用户向海尔反应:工厂生产的电冰箱质量有问题。随后,张瑞敏将库存中所有的400多台冰箱全部检查了一遍,发现76台冰箱有质量问题。他宣布,所有76台有问题的冰箱都需要砸掉,而且要制造冰箱的工人亲手来砸,张瑞明亲自砸了第一锤。 这是张瑞敏第一次在海尔挥起铁锤,一锤下去,把质量观念牢牢钉进海尔人的心里。 凭借质量构建起来的口碑、品牌和消费者信任,经过近二十年的发展,到2004年,让海尔从一个亏空147万元的集体小厂,变成一个年营收1016亿元的庞然大物。也成为了我国家电行业中第一个营业额破千亿的品牌,相比之下,当年的美的、格力营收仅200亿元左右。 “人单合一”是张瑞敏挥起的第二锤,这一锤堪称惊世骇俗,张瑞敏亲手将自己曾经搭建的整个海尔管理体系推倒重来。 自2005年起,海尔从组织架构、产品架构一直到研发体系,彻底进行扁平化管理。将所有员工划归小单元,为员工提供资金、资源等支持,鼓励创业,把偌大的海尔肢解成超过2000家生态小微公司。IBM前传奇总裁郭士纳对这种近乎疯狂的行为评价张瑞敏说:“你是我们这一代人中最勇敢的一个。” 如今,张瑞敏再次挥起第三锤。 这一次,年迈古稀的张瑞敏壮心不已,想砸碎所有传统的桎梏,让海尔全面转型为物联网生态企业。最明显的标志就是2019年青岛海尔正式更名为海尔智家,这表明海尔已经下定决心,要超越传统家电,加速智慧家庭生态建设。 涌向物联网 超出很多人的认知,其实海尔对智能家居的探索,甚至可以追溯到1999年。 1999年,海尔研发人员从市场上了解到,随着网络时代的来临,消费者对网络家电的需求越来越强烈,并推出第一代网络家电,成为网络家电的雏形。4年后,海尔采用蓝牙技术,实现了无线控制白色家电的运行,开启家电无线互联时代。 到2005年,海尔提出了数字家庭全套解决方案,推出“海尔e家”数字家庭系列产品,消费者可以通过一个遥控器控制家中的一切家电,包括控制壁灯和窗帘等。除了缺少语音交互,这已经和我们现在接触到的智能家居相差无几。同时自2005年起,所有海尔普通家电新品,均预留网络接口。 十几年间,海尔的智能家居事业不断稳步推进。到2016年,海尔发布物联网时代首个专为智慧家庭定制的生态操作系统UhomeOS,标志着海尔已经解决了智能家居互联互通的瓶颈。 2017年之后,海尔基于用户体验的智慧家庭解决方案不断更新迭代直至成熟。到2019年,其推出的“5+7+N”智慧成套解决方案已经完全成熟。覆盖客厅、卧室、厨房、阳台、浴室5大场景生活空间;基于用水、空气、洗护、美食、安防、视听、娱乐7种需求提供专业解决方案;并为用户提供N种个性化定制方案。 海尔做智能家居明显不同于其他玩家,相比于小米、华为用智能单品一点一点搭建智能家居互联互通生态,海尔的智慧家庭更倾向于直接针对家居场景和用户需求提供一整套解决方案。 并且面向物联网时代,海尔除了在智能家居行业内不断深耕外,在智能制造领域内更是成就斐然。截至 2019 年 12 月,海尔智家已建成 15 家互联工厂、2 家第四次工业***“灯塔工厂”,已构建起物联网时代下以用户为中心的大规模定制引领体系,形成全球引领行业的高端制造示范标杆。 这一战:惊险 物联网时代的前景固然美妙,但物联网毕竟尚未完全落地。现在的海尔正处在深蹲蓄力阶段,想要一跃而起,跳到物联网时代的大平台上。 但问题在于海尔的起跳点有些低,这让海尔的整个跃迁过程看起来会更加惊险刺激。 在移动互联网时代,海尔的表现算不上特别优秀。从2010年之后,海尔的增速明显开始下滑,尤其相比起美的和格力这两位后起之秀,海尔落伍了。 海尔总营收增速,在2010年之后一路下滑,到2015年已经陷入负增长窘境。 2016年海尔耗费54亿美元巨资收购美国通用电气(GE)的家电业务。接管通用在美国的家电业务基础,让海尔的海外市场发展直接上了一个台阶,同时带动海尔自建高端品牌卡萨帝(Casarte)等在海外市场打开更大局面。 但中国依然是全球最大的家电市场,海外市场提供的增长动力不够持久,也不够强劲,不足以完全抵消国内市场衰退带给海尔的负面影响。 所以在2018年之后,海尔又陷入了营收增速放缓的尴尬境地,被对手的甩开差距也更大。海尔2019年全年实现总营收2007.62亿元,相比之下美的实现营业总收入已经达到2794亿元。 现在海尔的局面不算乐观,未来发展也充满不确定性,不过张瑞敏的心理可能并没有多少恐慌,因为这位古稀老人最擅长的就是抓住时代机遇。 海尔的新机遇和新风险 2012年,张瑞敏受邀到香港科技大学开展讲座,他的题目是:“没有成功的企业,只有时代的企业。”核心观点在于一点:“企业成功只是因为踏准了时代的机遇和节拍,而绝不应骄傲地停下脚步。” 在张瑞敏看来,海尔过去的成功确实赶上了中国改革开放以及“走出去”的潮流,“成功地踏准了节奏”。如今海尔已没有当初那么成功,所以更需要踏准物联网时代的“节奏”。 不同于过去的“质量”、“改革”、“出海”,面对互联网时代,海尔把握节奏的主旋律变成了“体验”。 海尔从客户的需求和体验出发,提出“5+7+N”智慧家庭成套解决方案,这表明海尔已经完成“产品思维”向“体验思维”的转变。 在近期的演讲中,张瑞敏这样强调物联网时代“体验思维”的重要性:“现在还有一部分人坚持地认为要把产品做成行业的老大,但这是毫无意义的。因为用户需要的不是产品,而是一个场景。比如说,用户要的是智慧家庭,不是哪一个产品,要的是产品能互联,最后连成一个场景,产生场景的体验。” 张瑞敏认为物联网时代的主旋律将会是“体验”,现在的海尔也在不断朝这个方向发力,这和智能家居其他主流玩家竞争产品、品牌的思路有很大区别,算得上是海尔的又一次冒险。 这次冒险决定了海尔能否在物联网时代能否崛起,鉴于疫情带来的巨大不确定性和全球经济下滑,海尔冒险的风险性被陡然放大。 但是如果能扛过风险,海尔就很可能会成为物联网时代的最重要参与者之一。
分享
1
先马后看
Big-Watermelon
北京语言大学·2022届

BIGO算法工程师笔试题型

八道问答题,没有编程题
分享
1
先马后看
你挺茬楞阿
伦敦政治经济学院·2022届

Linux 复习

字节一面又来啦,这次要把所有基础知识都好好巩固一下,借鉴了很多很多。 因为自己也是初学,所以如果有不对的地方希望大家纠正一下。 ps命令 pstree -p | grep init 树状结构显示进程,-p显示进程号。 ps -A 显示所有进程信息。 ps -u root 显示指定用户下的进程 ps -ef 显示所有进程 STIME是进程启动时间,TTY是终端,PPID是父进程 ps -l 显示本次登入的PID和相关信息 CMD是什么指令 TIME使用掉的CPU时间 WCHAN表示是否在运行,若为-表示在运作。 SZ表示使用的内存大小 ADDR指出该程序在内存的那个部分。如果是个running的程序,一般就- C是CPU使用率 F代表程序的旗帜,4表示是超级用户 ps aux 显示所有在内存的进程 VSZ虚拟内存使用 RSS固定内存使用 STAT 该程序目前的状态,主要的状态有文件 R:该程序目前正在运作,或者是可被运作 S:该程序目前正在睡眠当中 (可说是idle状态),但可被某些讯号 (signal) 唤醒。 T:该程序目前正在侦测或者是停止了 Z:该程序应该已经终止,但是其父程序却无法正常的终止他,造成zombie (疆尸)程序的状态 chmod命令 chmod [who] [+/-/=] [mode] 文件名 u文件或目录的所有者 a所有用户 g同组用户 o其他用户 RWX可读可写可执行,X=1,W=2,R=4 也可以转换成八进制的形式,顺序是u,g,o 比如chmod a+x,g+w exer1或者chmod 777 exexr1 cat命令 cat可以显示文件内容,可以显示多个文件 cat -n显示行号 cat test1.sh test2.sh > test.sh可以创建一个新文件 cat,不加参数就是输入,然后输出,输出可以重定向到文件。 cat > 1.txt 输入重定向是<,我们可以进行cat <1.txt >2.txt cat命令适合显示短的文本文件。因为文件太大时,前面的内容就滚出屏幕,看不到了。 显示文本文件,我们现在就有两个命令:less和cat。除了它们外,vi也可以显示文本文件,它是用来编辑文本文件的,因此,显示文件是小菜一碟。 这三个命令用来显示文本文件时,less和vi都可以来回滚动,不存在看不见全部内容的问题。 top命令 load average系统负载 PID进程号,PPID父进程号 PR优先级,NI表示nice值(负值表示高优先级) %CPU表示CPU使用率,%MEM表示物理内存使用比, RES进程使用的内存大小,SHR共享内存大小,TIME+表示CPU使用时间 S表示进程状态,Z是僵尸进程,R是运行,S是睡眠,T是跟踪/停止。 netstat命令 1、Active Internet connections有源TCP连接,其中"Recv-Q"和"Send-Q"指接收队列和发送队列。这些数字一般都应该是0。如果不是则表示软件包正在队列中堆积。这种情况只能在非常少的情况见到。 2、Active UNIX domain sockets有源Unix域套接口(和网络套接字一样,但是只能用于本机通信,性能可以提高一倍)。 列名解释: Proto:显示连接使用的协议。 RefCnt:表示连接到本套接口上的进程号。 Types:显示套接口的类型。 State:显示套接口当前的状态。 Path:表示连接到套接口的其它进程使用的路径名。 free命令 total 列显示系统总的可用物理内存和交换空间大小。 used 列显示已经被使用的物理内存和交换空间。 free 列显示还有多少物理内存和交换空间可用使用。 df命令 磁盘文件的内存使用 Mounted on表示挂载点,磁盘文件的入口目录 先发了吧
分享
评论
先马后看
Eidosper
澳大利亚国立大学·2022届

【腾讯内推】腾讯WXG 2021届校招内推

腾讯校招内推!废话不多说,通过这个专属链接投递简历即可参与内推: https://join.qq.com/judge_talent.php?rec_key=xyYDsY89wxjt-_MiAGPSFB4bV-eEsrPOS7Hnh7Qv5Js 上面那个是内推至公司的链接,更欢迎师弟师妹们直接投递WXG,下面这个是WXG专属内推链接: https://join.qq.com/judge_talent.php?rec_key=yVVdEipNI-AkrKgTJsmr6xQIYwOCbanktjcn8kww6o8 本人腾讯微信开放平台前端开发工程师, 欢迎应届师弟师妹踊跃投递微信开放平台开发类岗位,这里有蒸蒸日上的小程序和小游戏业务,心动不如行动赶紧投起来吧,有问题可以给我留言。
分享
1
先马后看
情域
上海交通大学·2022届

秋招中的热门岗位——管培生,真的有传说中那么好吗?

秋招正在火热进行中,我浏览了一下校招的岗位,发现快消、投行、互联网等行业都会有管培生一职,例如玛氏、宝洁、汇丰、阿里、腾讯等名企,并且很多公司的管培生薪资都很高,这一岗位也吸引了很多学生。 管培生是销售吗?到底是做什么的?今天,我就来为大家揭晓管培生的内幕~ 管理培训生是一些大企业自主培养企业中高层管理人员的人才储备计划。通常是在公司各个不同部门实习,了解整个公司运作流程后,再根据其个人专长安排。最后通常可以胜任部门、分公司负责人。训练对象一般是毕业三年之内的大学生,主要是应届毕业生。 管培生的方向有两种,定岗和轮岗。定岗管培生,在企业招聘时就说明了是什么方向;而轮岗管培生,则需要需要在企业部门内轮岗,一段时间之后再根据个人情况定岗。 但是,目前在招聘市场中的管培生,还有两种典型的类别。 第一类,是“正规”管培生。 这类管培生往往是因为实力企业有真实的人才培养需求,需要管培生人才而开启的岗位。这一类管培生得具备高素质高能力,最好是复合人才,还需要全方位对公司有所了解。 像这种实力企业,一旦成为管培生,你将感受到来自企业的大力支持与培养,将在轮岗后定岗到适合你的岗位上,发挥重要作用。 第二类,是“噱头”管培生。 有一些不好招到人的岗位,为了吸引求职者,利用管培生这个名称,包装成一个看上去很高级的岗位,而且往往招聘企业还是知名企业,便更令人信服。还有一些小企业的管培生,更多的就是销售岗位,只是换了一种名称,实际上的工作职责并没有变化。所以同学们一定要结合职位JD加以辨别,不要被“套路”。 成为管培生的优缺点 1)优点 1. 薪水高 快消行业管培生主要分为销售和非销售两种,销售薪酬一般为6K-8K,非销售基本是10K+;互联网的管培生基本是12K;银行类管培生更多都是15K以上;医药行业管培生薪资属于中等水平,一般都是8K-10K。(薪资范围来源各招聘信息) 2. 轮岗 轮岗可以带来更广阔的视野,社交能力强的可以借此拓展network,对拓展我们的专业技能和能力也很有帮助。 3. 晋升机会大 管培生可以接触都不同的上层,受到更多关注,升迁上或者在竞争同岗位时,确实更有优势。 2)缺点 1. 轮岗带来的不适应 对于不少大企业来说,不同的事业部分布在不同的城市,很多管培生轮岗的时候就要几个月换一个城市,由此带来各种搬家、换联系方式等等会很麻烦。 2. 压力大 虽然说管培生的未来发展是成为公司领导,然而并不是所有人都能成功晋升,所以就算入职以后也还要和其他管培生竞争,压力会很大。 3.轮岗变成打杂 有些公司表面上说是互相选择,但实际上就是公司哪个岗位缺人就分配到哪里,甚至出现财务岗的毕业生却在销售岗工作了大半年的情况。 如何选择优质的管培生项目 现在的管培生项目名目繁杂,把前景描述的非常好,实际上可能是个坑…… 那么如何选择优质的管培生项目? 首选当然是大公司了,但是也要考虑行业的特点,不同行业的管培生是不一样的。 快消行业:经验最为丰富,制度比较灵活,管培生通常会有比较快的成长。 咨询行业、“四大”:轮岗时一般从项目入手,项目结束后会被重新打散分配定岗。 金融行业:注重综合能力培养,主要偏重流程性、体验式的培训,跨区域属性较强。 互联网行业:除了技术岗外,产品、财务、市场等方向的管培生最受欢迎。 其次,要考虑下面的几个点: 1.公司是否有完整的培训项目计划; 2.在培训期过后是否有较合理的后续计划保障培训生的持续发展; 3.是否有跨部门轮岗锻炼机会; 4.公司在可预见的未来是否可能提供足够的高层管理职位; 5.自己是否契合公司的文化和价值观, 6.工作的地点,强度等是否符合自己需要; 7.对于薪酬福利等是否满意。 综合上面几点,并且结合自己对于工作的需求,仔细考虑,慎重选择适合自己的管培生项目,入职了才不会后悔。 当然,虽然管培生待遇不错,但也不一定是最好的选择。海小投建议同学们千万别因为不知道自己要什么,而去尝试中小企业的管培生。如果自己都不清楚想做什么,管培岗不仅没法帮你做选择,反而因为目标不清晰,拖延不解决,增加痛苦时长。 所以,同学们还是应该先明确自己的求职目标,再做出求职选择。
分享
评论
先马后看
燕小七
云南大学·2022届

shopee offer

今天刚收到oc,然而还并没有给出薪资。 有朋友们哪了offer吗? 可以评论联系一下啊
分享
11
先马后看
十里故清欢
四川大学·2022届

OFFER求比较 四大vs银行vs金融公司

LZ海龟文科小硕一枚,最近在纠结offer的问题。这三个收入的话肯定是招行>>pwc>现代(8W+)。对于工作氛围,其实我比较倾向稍微稳定一点的环境,因为LZ不是特别拼命的那种人TUT。然后这三个职业发展的问题,我也不是很清楚,所以想听听大家的意见。。。
分享
18
先马后看
夏草
西北农林科技大学·2022届

@想去投行的小伙伴,这篇超实用干货文来了!!

本建议适用前提:本硕学历都挺优秀(如本硕985,或一流财经、政法大学,或本科985+世界前100高校硕士),且家庭条件一般(无法帮衬在一线城市的首付)的应届小伙伴,或者是工作没几年又去读研毕业的应届小伙伴。(以下所指的投行,均是指纯做股权融资的投行,不包含债权融资(含abs)) 一、国内的中小型投行和你们从前听闻的国际大投行差别很大,不仅仅是工作内容的差别,待遇收入以及社会地位的虚荣感差别也很大。对于本硕学历都较好的人,第一份工作,如果不能够进入前五名的头部券商(最多最多到前十,此处排名可见WIND),就真的别去中小型投行了,其他的选择其实更好。 理由如下: 1. 没有背景和资源的应届生进入中小型投行,就完完全全成了被公司/事业部制领导/项目现场负责人等手下的民工,不分昼夜和假日的加班,去到荒凉村镇出差,几个月几个月的驻守,非常非常辛苦,会过早把身体搞差。长期加班,易过劳肥,对心血管也不好,对颈椎腰椎和视力也有影响。一线投行的民工生活会好些,比如住的酒店有健身房,因为项目地点相对中心,目之所及不是远郊的黄土,听之所及不会是低频噪音,能看到别的地方的风景和美食,相对能愉悦身心。 2. 前辈们是非常优秀的引路人和导师的概率也很小(这是由社招进入的门槛决定的,但不排除少数自我奋斗及奋斗得当的,以及入行年份不佳,存在高水准低录取的情况)。环境对人的影响不必多说。关键是还会存在一些学历很低(本科二本及以下)的前辈,素养不太高,在合作中时常惹得心情不佳,或是造成开展工作的困难,让人平添烦恼。(并非学历歧视,但概率上确实存在少部分这样的团队凝聚力的问题) 3. 收入很微薄。是的,你没看错,顶着高大上光环的投行,收入待遇其实很差,时薪特别低。以北上广深为例,事业部制的中小型投行应届生的待遇和五年前都没有什么差别,而房价都至少翻倍了,其他金融行业或者互联网、地产等行业的起薪这些年来涨幅也相当可观。由于并没有像头部券商、国企或是银行提供的宿舍、食堂、健身房、电影卡、购物卡、劳保补贴、蛋糕卡、补充医疗保险、企业年金等福利,扣除租房(至少2500)、吃饭、交通费、置装费和年轻人基本的社交费用,一个月能剩个1000多就不错了(差补另算,但差补也真的不多)。而一线券商或是其他金融行业,待遇能稳步增加,让你辛苦奋斗的时候有满满的幸福感和安定感。 4. 也许有人会就第3点发问:如果项目发出去了,不就能开张吃三年了吗?这得来看个概率论的问题,首先得有个资质不错的项目来做,这个概率假设是20%(中小投行揽到的项目普遍是大券商不要的鸡肋项目),项目组专业能力强,这概率假设是70%,以及其他的低概率(如和会里的强关系),20%*70%*X,算下来概率就10%左右。多少个日夜,你的青春趴在烂项目上,获得成果和高收入很低,而你的同学们,进入银行、基金、券商其他岗位,不用这么频繁的出差到边远地方(没啥精神娱乐),不用长期住在不如家温馨的酒店,还有很好的福利待遇,基础薪金比你略高,且每年增速比你的快,年终奖也稳定可期,旱涝保收。那种贫穷的感受,那种对女朋友/男朋友的亏欠,真的不好受。(此外注意,分钱这事,主要看领导厚不厚道,是否有情义) 5. 这种收入不高又辛苦的工作,还要拖延你的结婚日期和养育小孩的计划,真的不值。对男的而言,过早结婚,家庭的维系很难,没有时间陪伴女朋友/老婆,没有时间陪伴小孩/宠物。对于女生而言,不如换份工作。 二、中小投行适合什么样的人呢? 我觉得有三类人在中小投行比较快乐 : 1. 家境较好,不愁吃穿和买房,仅是因为情怀和对投行工作的热爱,觉得投行比别的工作有趣,拿着低工资低福利也乐呵呵的的人。 2. 学历背景很差(差到过不了头部券商HR的底线),但家里略有一点资源,靠这点资源进投行,好过在其他地方做简单销售啥的。(资源变现的模式看起来更有光环) 3. 带着优质资源和项目过来,可以多赚很多钱的人。(中小券商分成机制比大券商好) 三、不去中小投行去哪儿? 1. 去四大和八大会计事务所。扎扎实实的学技能,选择面很广,终生受益。(此处不建议工作后读研的人士) 2. 去红圈律所。 3. 去银行。(就硕士而言,一线城市尽量去招行、交行、中信、兴业、浦发等非四大行的大行,大概率可免去柜员路,走对公客户经理(积累资源和识别企业的能力)——公司业务部/投行部等资源化路线,或者直接进去分行/总行,走专业化的路线,银行非常稳定,类似公务员,福利待遇却是市场化,非常可观,妥妥超过中小投行业务人员平均水平,工作3-5年,税后30万+是大概率的事,还有各种房补/免费宿舍/免费食堂等无形福利,总之赚得多,花的少,攒的就很多啊) 4. 去做行业研究员。无论是公募基金或者券商,都属于越老越吃香,之后转到投资也有优势。 5. 去互联网行业。互联网行业有很多岗位适合理工科复合金融背景的人士,是香饽饽,抢着要的。互联网行业工作两年+,税前30K-40K,年终4-6个月,也还是相对可观的,非996的挑挑也还是有。 6. 券商、基金、大集团公司的中后台。福利待遇好,办公环境好,朝九晚五,年终奖稳定。 四、为已经进入中小投行的人员正名 1. 能进投行的非依靠资源进入的人都是有一定实力和能力的,学历、长相、身高、工作经历/实习经历,情商,证书,缺二不可。不幸进入中小投行,而非一线投行,很可能是入行年份差,行情不好,无奈的事啊,如2018、2019入行的小伙伴。 2. 很多中小投行里不乏非常努力和优秀的人,项目经历、专业能力和学历都出众,远超过在大券商混大锅饭的人。 3. 若学历良好,却未转到其他行业的,一直坚守中小券商投行,说明非常有情怀,是为了自己的梦想和喜爱的事能坚持下去的人,值得钦佩。 4. 中小投行的路,是条艰难的路,外面很多好走的路,如果因为热爱,耐住清贫和艰辛,坚持下去,一直努力着,一定会看到曙光!
分享
评论
先马后看
阿加
东华大学·2022届

真·学渣的秋招总结

昨天晚上本来写好了,用vim写了2个多小时,在切shell的时候忘记保存,强退了,哭晕在厕所,今早重写好了。都是泪啊 我是广东某工业大学17年应届生, 许多大神、收割机在面经中自称为学渣、渣硕什么的,我这样的真学渣也能理解,毕竟大家总是有更高的目标,周围总是有更神的牛人。 但你们大神都把offer抢完了,学渣这称号就不要和我抢了吧,哈哈 我属于想法太多行动力不够能力不够的人,今年8月之前在某科研单位打杂(名号有点用,其他呵呵),没有找工作的紧迫感和行动力,看过很多面经却仍然没能打好基础。可能依赖心较重,6月中买了叶神的项目初级课,到7月中学完了flask,想着一劳永逸,其实学习没有捷径,即时有人带,知识总是要自己动手自己学,按照自己想法去拓展,否则做项目也没什么意义了。 回顾这2、3个月,只是拿到了一些很一般的offer,碰到名企基本笔试或者一面跪了,碰到几个想去的公司基本hr跪了。(真·学渣无双) 讨论区里谈论具体知识点、计算机经典书以及如何和名企面试官谈笑风生的帖子已经很多了,我就不赘述了。 这篇帖子除了会提到我遇到的面试中的具体知识点,更主要是从个人角度聊聊秋招过程中的一些感触,内容包括以下几点: 之前基础没打好,9月如何被自己坑 10月的面试过程中如何被一些细节坑 我了解到的非名企中,相对比较好的一些公司,以及其薪资待遇 面的岗位基本上都是C++方向 本文适合像我一样方向不明确,没有牛逼经历的普通学生 本文的大部分观点是我个人的总结,不具有普适性,仅供参考 希望下一届的师弟师妹能从我的经验教训中得到一些收获,早早入手好好准备,来年成为收割机。 在细说之前,我们按照知名度、是否上市大公司等因素把所有公司粗略分为A、B、C三类,具体划分我说了算。 部分示例: A类 bat、58、京东、猿题库、迅雷、多益、好未来、wps…… B类 cvte、全志科技、网宿科技、魅族、oppo、yy、高新兴…… C类 小鹅科技、青葡萄科技…… 下文中每个公司都用三元组或者四元组来表示开始,格式为: id级别公司名[地址|简单状态] 8月 1C类小鹅科技深圳 好像是鹅厂的人出来创业。8月鬼使神差投了个实习岗。虽然挂了,还是挺有收获的。 据说吴晓波是其大客户,小鹅负责分析其粉丝数据。实习待遇4-6k,是个挺不错的小公司 一面 1.1选一个你的项目介绍一下,你做了那些工作 遇到了哪些技术问题,怎么解决的,遇到segmentfault怎么调试,有没有看过core文件 1.2python python中类如何定义。python和c++区别、python和shell区别 1.3C++面向对象特点 多态->虚函数 base类不加virtual,调用的是哪个 1.4IO多路复用 1.5socket网络编程 1.6简述快排,时间复杂度,相比冒泡谁更快 数据量,很多相同元素 1.7map内部实现,红黑树 自己如何实现hashmap?vector存key?如何考虑数据量很大的情况,vector不够放。 1.8php微信公众号,关键词回复实现流程,自己搭web服务器没?,用过框架没 二面 1.9快排时间复杂度分析 1.10tcp连接建立三次握手,释放四次挥手过程 1.11若有客户打不开网站,分析原因排错 1.12本网站宕机,如何给客户解释 三面 1.13分析linux启动过程 1.14操作系统多用户登录原理 1.15进程之间通信方式 1.16操作系统如何分配内存 三面挂了,当时操作系统和网络方面还没开始复习,问到就跪了。 2A类网易 实习内推消息漫天飞大家都知道。笔试挂,笔试内容见[2] 秋招被网易、有道刷简历。 9月 1A类58同城 做58模拟题的时候感觉还可以,本以为很有戏,结果左等右等笔试都挂了,好失望。 记得笔试中有个条件概率的题目挺有意思: ios和android用户比例为为3:4。ios端每日访问率为0.012%,android端每日访问率为0.008%,某用户发生一次访问,该用户使用IOS的概率是? 类似问题 现分别有A、B两个容器,在容器A里分别有7个红球和3个白球,在容器B里有1个红球和9 个白球,现已知从这两个容器里任意抽出了一个球,且是红球,问这个红球是来自容器A的概率是多少? P(A|红)=(P(红|A)*P(A))/P(红) =>P(A|红)=7/10*1/2/8/20 类似的 P(ios|visited)=(P(visited|ios)*P(ios))/P(visited)= 0.012%*3/7/(0.012%*3/7+0.008%*4/7) 2B类cvte cvte口碑貌似不太好,校招是以12k工资为噱头的(算比较高吧)。我3月份实习生笔试通过去面试挂在算法上,9月去面试挂在网络和操作系统上。 笔试不难的,提前刷一下cvte的题目,很大可能会遇到类似题目或者原题。通过的人也非常多,一群群的人去黄村做他们一趟趟班车去公司面试。 cvte的流程是一面挂了叫你回去,立即二面才有戏。 3月15号实习面试: C++多态,malloc和new区别(3月的时候我连这个都答不上来。。。),如何判断单链表环,二叉树遍历前序,后序,中序等。 手写二分查找 判断一个数是否素数;如何输出1-100素数 python三种内置对象number/string/list/dict/tuple/file Linux查找grep用法,bash脚本用过没? 9月一面: 2.1介绍自己项目经历 2.2C++中多态。构造函数可以virtual吗?会提示constructorscannotbedeclared virtual 2.3两个栈模拟队列 2.4手写代码找到数组中出现次数第二多的数字:用map存储k-v对,k为数字,v为出现次数 2.5开源库阅读 2.5使用ping命令的过程中具体发生了什么(跪了) 2.6C++多线程编程(跪了) 3A类京东 本来觉得考的挺难,不知怎么就过了,可能是因为A了一个大题吧。在线编程题,采购单和幸运数 一面 3.1多态,构造函数可否为虚 3.2你用什么编译器,编译链接的具体过程。有没有用过什么库 3.3stl中vector相比数组。。。 3.4map实现 3.5ipc 3.6网络编程熟吗,三次握手 3.7数据库索引,底层如何实现:B+树 3.8redis和mysql的区别?redis底层怎么实现的 3.9web服务器有哪几种:IIS、Apache、Tomcat 3.10http协议熟吗getpost 京东面试官人挺好的,我面A类公司感觉有点悬的时候,在提问环节都会抛出大杀器:对于贵公司而言,xxx要求应聘者具备哪些素质呢? 当时面试官听完好像很开心,对着我的简历指点,挺感谢的,大意是我这个科研项目他们不会很看重,他们更喜欢贴近工作的项目,比如写一个简单web服务器。 还比较喜欢业务面设计较广的人,总的来说如下 cpp基础 网络编程实际经验 开源hadoop,spark 我很奇怪为什么业务工程师还需要掌握hadoop这些大数据工具,面试官大意是业务工程师需要会用这些工具,大数据、机器学习工程师更多的是选择合适的框架、定制框架,深入到代码级别。之后好未来的面试官大意也是如此。 4A类猿题库挂 大题中有一个是考网络中几种拥塞控制方法的,当时不会。考完认真看了看谢希仁书对应那节,后来在要出发的面试中问了同样问题,好好装了一下逼。 5A类阿里挂 这笔试题太难了吧 6A类360挂 事后发邮件告知你挂了,服务态度好。 7A类腾讯挂 感觉做的还可以,唉 8A类搜狗挂 10A类百度挂 跳出了几次自动交白卷了6666 考试平台是AMCAT,智力题+3道编程题。题库很多都是重复的。 11B类全志珠海 9月中笔试,10月14号左右一面二面。B类公司的难度比A类低一个档次,基本上技术问题都不是瓶颈了。 核心业务是硬件,校招流程中广州是最后一站,软件岗已经不多了。我是8月份就有师兄推,所以很早关注这家。二面是在大学城雅居乐酒店,看到前面同学面完出来直接签两方(违约金5k),打听到不问技术,于是很激动,以为胜券在握。 到我,刚进门就是一个看起来很和善的面试官对我笑,如沐春风啊。氛围也很轻松,聊聊家里情况、为什么来全志等等,谈笑风生,最后说先回去等消息。过了几天才知道挂了666 教训是任何时候都不能放松警惕啊,任何时候都要让面试官看到你很想去他们公司。 那时候面试官很憨厚的说你这个情况很适合去华为中兴啊?我当即乐的合不拢嘴了,实话实说:华为不要我们学校的,中兴广州站还没开始balaba 后来觉得其实面试官我说的这些肯定没兴趣,当时应该话题转到全志或者全志同其他公司比较这个点上。悔之晚矣。后来面平安科技、中信信用卡也是同样被坑。还是too young啊。 二面是综合面基本没刷人,据说批发价10x14 12A类趋势挂 13A类迅雷挂 14B类要出发广州 9月中在华工宣讲线下笔试,感觉氛围很好,创始人很有想法,提问环节,我还特意问为什么秋招全国只招十几个人,他说主要社招。 注意,各个公司线下笔试一般比线上笔试简单,大家能去尽量去。 本来觉得没戏,10月中突然通知10-19去公司面试。三人一组在隔间等,来了2个面试官,2v3轮流问轮流发言。看别人如何回答还是挺有意思的。顺利一轮、二轮,跟我们说等hr单聊,过了几分钟叫我们回去等消息。后来听说确实有人收到了。 他们业务开发是基于.net的,聊到快走的时候看我有C#项目,特意问我愿不愿意转C#,我当然说愿意。后来也没消息了。 15A类多益广州 中大场,线下笔试挂,都是智力题,真会玩。好像很喜欢985的,工资很高。 16A类wps 3月份在华工有实习笔试,考的都是C++基础知识,挂了。 10月信心满满在中大参加校招笔试,选择好多原题,总体也不难,不知怎么挂了。 17A类小米挂 18B类魅族 25号笔试,给我一份安卓题,事后我核对了一下绝对没投错岗位666,挂 19A类yy 问答题有些难。 19.1linux使用buddy/slab等算法管理内存.简述buddy/slab工作方式 19.2外碎片和内碎片是什么,产生的原因 19.3写正则表达式,校验XXX.XXX.XXX.XXX格式的ipv4地址: 据拿到算法岗的同学,10k 20B类网宿深圳 好像是CDN领域老大。 师兄内推,一面hr面不刷人,二面技术主管问项目,聊完后问智力题:n个螺丝和n个螺母可以一一匹配。你有一组n个螺丝,另一组n个螺母,都是乱序,如何最高效匹配? 类似构建BST思路。 21A类美图 效率很高,在华工线下笔试后当晚发通知面试。 一面 21.1项目 21.2实现抽取代码注释,构造文档的功能,说思路 21.3linux,文本中有多行数据,每一行可能有keywords,找出包含keywords的连续两行行号 21.4epoll 21.5手写链表的快排算法 22A类完美世界挂 23B类平安科技深圳 前面说了,综合面被坑。 计算机专业的有个像样java项目的基本都过了,据说16-18w 24B类国家超级计算机深圳中心 华工宣讲后做性格测试+线下面试,聊得很简单还问期望薪资。没消息,感觉不想招人。 25C类青葡萄深圳 做私有云的,9月底第一个offer。9k 26A类好未来北京 一面是视频面 26.1项目,难点,如何解决 26.2linux,假设有一个log文件,每行包含http返回码,shell找到返回码200的个数。 26.3mysql索引。mysql存储引擎 26.4手写:字符串转int;要考虑的点:空串、负号正号、整数上界0x7FFFFFFF下界0x80000000 26.5对nginx、web服务器了解多少 26.6设计模式 策略模式:定义一系列算法,把他们一个个封装起来并且可以互相替换,使得算法变化独立于使用它的客户 c++手写一个观察者模式 提问环节,好未来想要的合格的c++工程师素质: 熟悉web服务器 熟悉linuxshell mysql调优/缓存/redis;mongodb 异步kafka 会用hadoopspark 10月 1B绿盟 21号笔试后没消息 2CC1广州 10号一面二面,14号hr面 拿到offer。10k 违约金5k。 3C格力珠海 it岗。非常水,不刷人。第一天一面、第二天二面、第三天集体小游戏沟通感情发offer(请脑补传销活动) hr说计算机硕士薪资比较高一年6-7.5w哦,而且是加上各种福利哦,14个月哦。 他们想用业内1/2的价格招一大帮人搞人海战术吧。害我跑了三趟华农。 4B甜橙金融翼支付 华工线下笔试没消息。没记错的话公司1/3都是外包员工,可能不乐意培养应届生吧。 5B深信服 看讨论区就知道了,招人帖子置顶了好久。据说工资高加班费高,要去全志面试,可惜错过线下笔试了。 6B37游戏 宣讲会上用AR视角参观公司,有创意,感觉氛围很好。 线下挂,费解 7A顺丰科技 挂,第一个编程题是破棋盘上的八皇后问题,过了80%后一直超时。。。 据同学ios岗16w 8A去哪儿 10.14测试,好像错过了 9C佳都新太广州 线下笔试后,过了一周去公司面试,挂 据同学,9k 10C金立 错过线下笔试 11A凤凰网挂 12B茁壮网络 线下挂,据同学14-18w 13C深网视界线下挂 14B明朝互动错过 15B易到用车挂 16Boppo 、8月前在空中宣讲获得面试直通卡一张。 一面在粤海喜来登,it岗,问到union和unionall区别。 当晚有未接来电,略喜,几分钟后接到电话了,说抱歉第一个电话打错了balabla。 第二天中午又接到oppo电话,说很抱歉打错电话对您造成的困扰balabala,卧槽真6 17B奥飞娱乐 喜羊羊与灰太狼制作方。 投递后直接在中大一面 17.1epoll特点 17.2保持tcp连接的开销,微信客户端与服务器是tcp还是udp 17.3syn攻击、ddos 17.4cdn原理 17.5爬虫反爬原理,封ip怎么办 收到offer,9x14,深圳 之后我一细查,不是奥飞娱乐母公司,是奥飞投资的一个深圳小公司50人不到。要求转广州未果。 18C南方数码 线下笔过,不想面了 19B博雅互动深圳 据说本科10k,研究生12k。 一面 19.1后台开发需要那些技术 19.2stl中的一些容器 19.3python函数参数传递:值类型,引用类型? python数据类型包括五种: immutable:number、string、tuple mutable:list、dictionary 函数中,immutable类型是值传递,形参是一个独立地址的新变量。mutable类型是引用传递,因为不存在重新赋值。 其中对于list,若想值传递,可以用切片创建副本fun(mylist[:])来实现。 19.4二叉树的非递归遍历 对于任一结点P: 1)循环:只要P不空,就输出P并把P入栈,P指向其左孩子 2)如果栈不空,P指向栈顶元素的右孩子。出栈。 3)如果P或栈不空,返回1) voidpreOrder2(BinTree*root)//非递归前序遍历 { stacks; BinTree*p=root; while(p!=NULL||!s.empty()) { while(p!=NULL) { coutdata<<""; s.push(p); p=p->lchild; } if(!s.empty()) { p=s.top(); s.pop(); p=p->rchild; } } } 二面不问技术,瞎聊。 公司国际化做的很好,但是挺迷信的,网申要填写阴历阳历生辰,二面签到处的hr姐姐又问生辰,几点生的,回头告诉后面这个人生辰没问题。66666在社会主义中国怎么还有这套东西。 20B中信银行信用卡中心深圳 二面挂,基本不刷人,好像喜欢java 21C亚信 笔完没消息 22B分期乐线下挂 23A努比亚 线下挂,没听说谁过了 24B网龙 笔完没消息。貌似8-10k 25BTCL TCL通讯部门,70%研发都在惠州,30%深圳。 hr挂,貌似忘记表现出想去的样子了。。 据说惠州9k 26B有米科技广州大学城 发展迅猛,主要业务好像是广告推荐? 前几天打电话叫我去公司参观,推掉了,昨天叫我9去公司笔试 27C金证科技深圳 笔试挂。据说8k 28B高新兴广州科学城 体量和全志一样都是市值150亿。智能交通研究院C++岗。早上笔试,下面面试。 收到offer,实习4k,转正7-10.5k看实习表现。 29B钜盛华深圳 没投 互联网金融类,好像财大气粗。线下笔试面试,据同学18w 30B房多多深圳 线下笔挂。据同学12k 感触 除了上面提到的公司,被刷简历的、投递之后完全没消息的公司包括: 华为、中兴、优酷土豆、联想、爱奇艺、百度外卖、豆瓣、招行信用卡、美的、猎豹移动、广东移动、vivo、立白、神州数码、联通、新浪、酷派、 共17家,机会都不给,太伤心了。 金9银10确实一点都没错。 A类公司笔试难度、问的深度都超过B类公司。9月被A类公司各种虐,技术问题不服不行。 等到10月,B、C类公司的技术问题已经不是瓶颈了,更多的是面试技巧。总的来说,笔试面试真的是实力+运气,身边的收割机基本上都是实力超群,项目经验扎实,实力越强就越不需要依赖运气。 个人非常认同面试官选人的流程: 过去有没有牛逼的经历(acm等牛逼竞赛,牛逼论文,牛逼实习等等) 方向是不是对口(过去的项目经历,跟目前的岗位匹配度和深度) 基础知识(操作系统,网络,算法,相关业务知识) 这三点重要性我认为是按照先后顺序排列,举个极端点的例子: 你拿过acm金牌然后去面试后台开发岗位,不清楚TIME_WAIT状态的含义,面试官应该不会刷掉你。 但是如果你没有那个奖,然后也没答出来,我想你多半就很危险了。 可惜知之晚矣,希望师弟师妹引以为戒,早早踏实复习。 我看了C++primer,plus,csapp和apue没看下去,啃不下经典书那碰到A类公司真的是被吊打,惨不忍睹啊。刷了一些书还是不够一些大厂的编程题AC不了就没机会面试,再有就是没能及时深入总结,一些考的是重复的,或许应该有取舍吧,秋招每个月几乎每天都是考试、查答案,有些累有些浮躁,或许放弃一些会更好。
分享
4
先马后看
胡宇桐
浙江财经大学·2022届

java后端面试资料整理

去年上岸前的java后端面试资料整理 https://github.com/JGPY/JavaGuideBooster 需要参加实习或者秋招面试的小伙伴速速收藏! 让天下没有难做的生意,让健康触手可得,加入阿里健康,一起投身数字新基建战略!疫情阴霾下,我们注定要站在一起,用科技的微光驱散心中的低迷,阿里健康是阿里巴巴集团“Double H”战略(Health and Happiness)在医疗健康领域的旗舰平台,是阿里巴巴集团投资控股的公司之一,阿里巴巴继淘宝、天猫、蚂蚁金服、阿里云、阿里钉钉之后又一张王牌阿里健康正在欢迎你的加入!加入阿里,更好的世界,更好的你 21届的校招同学,简历请投递到:jasonliu.lb@alibaba-inc.com 也可以链接内推: http://alibaba.tupu360.com/campusActivity/getActivityInfo?activityCode=XuVOss3tNhNH2RfyS77IVO1sgy_zPRhxWYg0FCNYRVs%3D&enter=menu
分享
3
先马后看
gashero
香港城市大学·2022届

写给大家的一些成长建议,共勉

看到很多新同学苦于没有成长,找不到好工作,我深有感触,希望可以和大家一起成长,一起进步,先分享一些自己的总结。 个人介绍 本人it研究生毕业,工作6年,业界称为码农,外界称为程序员。 作为一名步入职场6年的it老同学,来发表一下总结,全部是个人的经历和想法,不包含任何人物映射。 本科毕业后,当时也不知道怎么想的就去考验了,结果没考上心仪的,调剂了一个,读了3年研究生,结果。。。和本科一样的渡过,纯粹是为了拿个证书,对不起父母、对不起年轻的自己啊! IT行业总结 工作了6年后发现,其实学校里的课程都是比较滞后和比较浅的,可以理解为师傅领进门的过程,在这个过程中,兴趣、悟性、坚持会起很大的作用。一定要坚持、一定要热爱,才会有深层次的发展。我们it这个行业虽说都可以来学,但是想学的深入,其实还是仁者见仁智者见智的,这个行业有几个比较显著的特征: 1. 技术范围广:相信这一点大家不会质疑,有前端、客户端、后端、算法、数据分析、人工智能、运维等等,前端、客户端和后端其实还可以细分到很多领域,多到你手脚并用都数不过来; 2. 技术纵向深:每一个技术栈的深度又是何其的深,一个普通资质的人(相信大部分都一样,属于正常人)一般能学到50%的深度,就已经很不错了,同时时间有限,你没有那么多的时间去学习很多的技术栈,而且钻研的很深(高手大牛除外,厉害的人也不在少数); 3. 技术革新快:这几年是不是人工智能、区块链比较火?每隔一段时间就会出来一波新技术,其实新技术的产生并不是无中生有的,都是为了推进某个方向的业务发展而产生的,就像汽车的发明是为了解决马跑不快、驼的货物不够多是一个道理,所以技术革新快了,我们就要不停的去学习,技术都是想通的,想去了解、去掌握使用方法(20%的深度)其实并不难; 成长各阶段梳理 说了这三点后,是不是有的同学都开始畏惧了?其实只要找对方法就不难,但是如何找对方法,这又是另一个问题了,我们从三个阶段再来剖析一下: 初入大学:大一~大二 在这个阶段,其实并不要焦虑太多,就跟着老师去学,去感受这个行业,学好一个基本的语言,学好数据结构,学好网络即可,这个阶段最重要的是: * 培养兴趣 * 培养自学能力 这两点在你今后的成长过程中非常重要,如果这个阶段不培养起来,后面会面临很多的其他困惑,再来培养这两点就很难了,我当时也是不知道的,吃了很多亏,整个成长过程苦不堪言。 即将离校:大三~大四 一般大三的时候是可以选择在暑假去实习的,可以找一些小公司(如果你比较厉害了,可以去试试大公司)去锻炼一下自己,一方面可以了解到企业是怎么工作的,另一方面可以感受一下在工作的过程中应该如何不断学习和成长,毕竟要一边上班一边学习,你会感觉到时间是如此的宝贵,一周一周如白驹过隙啊!在找实习的过程中,千万不要因为待遇而做选择,只要能解决住房,解决温饱即可,待遇一定不是这个阶段所要考虑的,你需要考虑的是:行业方向!因为行业方向决定了你所能接触到的知识应用体系,例如现在做的比较突出的几个行业:电商、出行、区块链、安防、云,随便挑一家满意的,因为这个阶段,你去哪都是学习的,都能学习到很多知识。 而大四的时候,就是你人生中最重要的抉择的时候了,可以类比高考,铆足了劲,冲刺一个最好的公司,因为应届生的第一份工作非常非常的重要,就像一张白纸开始画的第一笔,画的好坏对后面的作图有很大的影响,而这个准备周期不能像准备期末考试那样就一个月,而需要系统的梳理自己的知识体系,弥补不足。不要低估了面试官,不要觉得可以拿网上的面试宝典来糊弄过关,在回答问题时,是真正体会和理解了,还是在背诵面经,一听就知道了。所以我建议还是提前半年准备一下自己期望的领域,一步步充分准备起来,尽量在秋招时找到心仪的工作,否则春招机会比较少,而你的心态也会发生变化。 快速成长期:毕业1~3年 这时候你已经加入到一家心仪的公司了,这个时候你会发现你的成长会特别快,每天都会学习到新的知识,每天都会有变化,这是正常的,这也印证了前面说的:it行业想入门还是很容易的,但是想更深入的成长,还是需要付诸更多的努力的。这个阶段你会发现,学校里学习的东西和工作上用到的很少有一样的,但是如果学校里学的扎实,你在工作中会学的很快,一方面是前面说到的兴趣和学习能力,另一方面更重要的是it行业很多知识是相同的。这里同样有一个忠告:踏踏实实做事,认认真真总结,还是不要在意待遇!多注意每半年的变化,如果没有变化,就认真反思,多找有经验的人沟通; 慢速成长期:毕业4~6年 经过前面的3年的快速成长,你已经熟练掌握了各项技能,对整体架构设计也有些似懂非懂的理解,成长快的同学可能已经在不大不小的公司带了几个应届生了,成长慢一点的同学应该也已经是团队的主要贡献者了,在接下来的3年里,你会发现,在技术上的成长会越来越慢,更多的是架构设计上、业务理解上的成长,这个阶段同样不能丢掉你的老本行:技术要扎实,要硬!同时要多注意自己的软实力,软实力的定义很多,简单来说就是保证你在公司里怎么去沟通、怎么去成事、怎么去争取到更多的资源的非技术能力。 不要觉得软实力虚无缥缈,可能没那么重要(曾经我也是这么觉得的,曾经我是个绝对的唯技术论者),它是决定你能走多远,能跳多高的直接因素,你可以从每个公司的晋升体系里看到它的引子,每个阶段的技术要求里就能感受到它在其中的重要程度越来越高。 正是由于它这么重要,所以它的沉淀也是需要时间的,相比较技术的成长,软实力的成长是很慢的,你去搭一套RocketMQ集群,阅读调试一下源码,很快就会有立竿见影的效果,你可以产出好几篇还不错的分享文章,但是软实力没有那么好提高,而且很多时候会受限于性格、见识、格局而久久看不到成长,关于这点,我也在摸索成长,要经常反思和总结,要相信时间的力量,时间会证明一切。 最后的总结 我在成长过程中也是一路摸爬滚打,没有任何人的指点,所以走的很艰难。例如在大三的时候,如果有个学长可以阶段性的指点一二,如果有已经工作的师兄可以告诉我工作上需要什么,我应该前面的三年可以缩短一半;后来去面试bat,失败了有十来次,每次也不知道具体是什么原因,都是靠面试回忆去猜测可能是哪方面的问题,回来学习和完善,当你真正去招人的是,你就会知道面试记录是多么重要,面试官可以从面试记录里看到你的成长,总是去面试,总是没有成长,就会被定义为缺乏潜力。 前段时间传出来说阿里已经不招30岁以上的P7,35岁以上的P8了,虽然后面辟谣了,但是无风不起浪,it这个行业正在向年轻化发展,毕竟每年那么多人毕业,那么多人走进it圈子。以前不相信程序员是吃青春饭的,渐渐的发现,我在招人的时候也会看年龄看潜力,我会设身处地的想:等我35岁的时候,别人会怎么看我?所以趁着自己还年轻,努力拼一下,成长上去,后面的发展会顺畅很多。
分享
评论
先马后看