更新日期:2020年1月1日
2019年
我是从大二暑假开始,正式进入Java的学习。大二上学期的时候,学校开设了只有11周的Java程序设计课程,我当时也没有对Java产生太大的兴趣,把考试应付过了,把课程设计应付过了也就没有再继续深入学习Java了。大二下学期以后,我开始参加学科竞赛,在“中青杯”数学建模竞赛中获得省一等奖,“电工杯”数学建模竞赛获得省二等奖,“高教杯”全国大学生数学建模竞赛获得省三等奖,我那时的想法是,借助自己自学的一些Python知识以及Excel知识,还有信息与计算科学专业打下的数学功底,来为将来成为一名数据分析师做准备。但是,我慢慢觉得数据分析的工作是比较枯燥的,数据清洗的工作会花费挺多的时间,真正建模型和做分析的时间不多,内心的成就感远远不及自己动手编写出一个程序的成就感。在了解了互联网市场的人才需求,综合考虑了自身的条件以后,我在大二暑假开始正式投入Java的学习。我先从Java SE的基础知识开始,跟着视频,以1.5倍数来看,把每个视频的代码都动手敲一遍,遇到有不懂的地方也会去查阅书籍,到了七月底,正式学习完Java SE,确切地说,正式学习完比较基础的Java SE,像多线程、网络编程、反射等知识我都是很快地略过的。然后自己也动手写了一个简单的学生成绩管理系统,它是基于Java Swing的,持久层是利用txt文件,也是当作对Java基础语法的一个小练手:
完成这个小项目以后,已经是八月中旬了,我开始投入Java EE的学习,我是一直跟着黑马程序员培训班的Java开发工程师就业班的视频来学习的。当时我觉得我走了挺多弯路,我学了很多较老的技术,如Servlet、JSP等,而且学得很慢,主要是刚刚开始接触Java Web,很多配置也是云里雾里的,很多错误也调试了很久才得以解决。曾经还有段时间花了很多时间在JSP语法的学习上面,没有尽早地接触和理解Spring、SpringMVC、MyBatis框架是比较失误的事情。
慢慢地到了十月份,计算机网络这门课程有个串口通信的实验,我也运用Java Swing和虚拟串口写了一个串口通信聊天室。
到了十一月份,计算机网络有一个课程设计是基于TCP/IP协议的Socket通信,这是我接触到的第一个较大的工程。我主要复杂客户端后台的开发以及实时语音模块的客户端服务端的开发
这个注册界面是Web端的,后台我是用原生的Servlet和JSP编写的,前端是用LayUI框架搭建的
聊天主界面,可以实现发送文字、发送文件(断点续传)、聊天信息的保存,其实就是简易版的QQ功能,界面在高仿微信
还要实时语音的功能,后期我会专门写一遍博客来介绍,也会将代码开源到GitHub上。
转眼间就到十二月了,我也才开始Spring、SpringMVC和MyBatis框架的学习,我还是跟着哔哩哔哩的视频来学习,目前也只是会使用,很多底层的细节和设计思想也没有深入理解,也自己动手做了一个网站,学生信息管理及选课系统,并部署到了阿里云服务器上。
可以访问此链接来看到我的项目:http://101.37.13.188:8080/StudentSystemZ/
体验账号&密码&身份
admin&123456&管理员
12345&12345&教师
201712010329&201712010329&学生
后端:Spring+SpringMVC+MyBatis+MySQL
前端:LayUI+Ajax
功能:管理员:院系、课程、学生信息、教师信息、用户管理,当添加/删除 学生/教师时会将学生学号/教师编号作为系统的用户名和密码及其身份,作为学生/教师登录该系统的登录信息;学生:选课退课、查成绩、查改个人信息;教师:任课、给选其课的学生录入成绩、查改个人信息。
不足:由于前端能力欠缺,界面设计不够友好;由于时间问题还有一些功能未完善。
管理员的后台布局
我自认为能做出这个项目就能够在企业中干简单的活了,于是赶紧写了一份简历,在拉勾网上海投了,然后收到了6家公司的面试邀请,其中有两家公司距离太远就没去面试。
最终打算去面试的公司就是这四家:
人总是要突破自己的舒适区,及时很多东西不懂,也去努力地拼一把!所谓初生牛犊不怕虎,我能够用SSM开发出第一个框架,就还是有较强的学习能力的。
1.时间:2019年12月31日 10:00
2.学历背景:华南农业大学(双非)信息与计算科学专业(非科班)
3.笔试(30分钟)有5道大题,我答得很烂,题目挺简单的:
第一题:你用过哪些Map类?请写出它们的区别。
看到这个题目,我还是很有底气的,因为在准备面试前有在牛客网上留意相关的知识点。我只回答到了用过HashMap,了解过Hashtable和TreeMap,区别是:HashMap的键和值可以取null,线程不安全,Hashtable的键值不可以取null,线程安全,TreeMap底层是红黑树实现。
比较标准的答案是:
Map体系:
---| Map接口 将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。
---| HashMap 采用哈希表(哈希表的底存数据结构是链表数组)实现,所以无序
---| TreeMap 可以对健进行排序
---|Hashtable:
底层是哈希表数据结构,线程是同步的,不可以存入null键,null值。
效率较低,被HashMap 替代。
---|HashMap:
底层是哈希表数据结构,线程是不同步的,可以存入null键,null值。
要保证键的唯一性,需要覆盖hashCode方法,和equals方法。
---| LinkedHashMap:
该子类基于哈希表又融入了链表。可以Map集合进行增删提高效率。
---|TreeMap:
底层是二叉树数据结构。可以对map集合中的键进行排序。需要使用Comparable或者Comparator 进行比较排序。return 0,来判断键的唯一性。
另外还有ConcurrentHashMap,CoucurrentHashMap是线程安全的,采用分段锁机制,减少锁的粒度。
第二题:描述一个新的任务添加到线程池的过程
当时我是凭着自己的一点点零星记忆编了上去,因为之前没用过线程池,对线程的知识掌握的程度非常不够。
比较标准的答案是:
这里可以看到有一个任务队列,然后还有一个工作的线程池。这个队列是用来干什么的呢?当我们提交的任务不能被及时执行的时候,可以入队列,等待被执行的。现在对于线程池的提交任务流程做一个简单的图解。主要以cachedThreadPool为例。
图中所有创建的线程都会被放到线程池的hashset中记录下来。
1.提交任务首先判断是否是null,如果是null就抛出空指针异常,如果不是执行2。
2.判断线程池中工作的线程数是否小于核心线程池的大小。如果小于执行 3,如果大于执行4
3.创建一个线程来执行提交的任务,如果失败重新获取线程池状态,然后执行4,成功就返回
4.判断线程池的状态是否在运行和尝试向把任务加入等待队列,如果线程池已经关闭或者放入等待队列失败,执行6。如果放入队列成功执行5
5.因为成功的入队了,我们需要重新判断线程池的状态,因为在放入队列的过程中线程池的状态可能会发生变化。如果发现线程池的状态不是在运行就将刚才添加的任务从队列中移除,然后执行拒绝策略。如果是在运行状态执行7
6.尝试创建一个线程来执行任务,如果创建线程失败就执行拒绝策略
7.判断当前的工作线程数是不是0如果不是就返回,如果是就创建一个线程!
原文链接
涉及到多线程的知识,我还是要补一补啊
第三题:请写出一个单例模式的类
由于前不久接触了Spring框架,所以我写的答案是:由Spring依赖注入的类默认是单例模式的,例如SqlSessionFactory
比较标准的答案是:
public class SingleObject {
//创建 SingleObject 的一个对象
private static SingleObject instance = new SingleObject();
//让构造函数为 private,这样该类就不会被实例化
private SingleObject(){}
//获取唯一可用的对象
public static SingleObject getInstance(){
return instance;
}
public void showMessage(){
System.out.println("Hello World!");
}
}
public class SingletonPatternDemo {
public static void main(String[] args) {
//不合法的构造函数
//编译时错误:构造函数 SingleObject() 是不可见的
//SingleObject object = new SingleObject();
//获取唯一可用的对象
SingleObject object = SingleObject.getInstance();
//显示消息
object.showMessage();
}
}
执行程序,输出结果:
Hello World!
还有什么懒汉式、饿汉式的实现方式,后期再慢慢补咯
详见菜鸟教程——单例模式
第四题:Redis的数据类型?
我的回答是:字符串(String), 哈希(Hash), 列表(list), 集合(sets) 和 有序集合(sorted sets)等
答案虽然对了,但是我还没使用过Redis,以后的项目中也需要慢慢用到
第五题:用过哪些消息队列?使用场景是什么?
我当时没有做这个题目,因为不会。
比较正确的答案是:
消息队列,一般我们会简称它为MQ(Message Queue)
队列是一种先进先出的数据结构。
消息队列可以简单理解为:把要传输的数据放在队列中。
主要特点是异步处理,主要目的是减少请求响应时间和解耦。所以主要的使用场景就是将比较耗时而且不需要即时(同步)返回结果的操作作为消息放入消息队列。同时由于使用了消息队列,只要保证消息格式不变,消息的发送方和接收方并不需要彼此联系,也不需要受对方的影响,即解耦和。使用场景的话,举个例子:假设用户在你的软件中注册,服务端收到用户的注册请求后,它会做这些操作:校验用户名等信息,如果没问题会在数据库中添加一个用户记录如果是用邮箱注册会给你发送一封注册成功的邮件,手机注册则会发送一条短信分析用户的个人信息,以便将来向他推荐一些志同道合的人,或向那些人推荐他发送给用户一个包含操作指南的系统通知等等……但是对于用户来说,注册功能实际只需要第一步,只要服务端将他的账户信息存到数据库中他便可以登录上去做他想做的事情了。至于其他的事情,非要在这一次请求中全部完成么?值得用户浪费时间等你处理这些对他来说无关紧要的事情么?所以实际当第一步做完后,服务端就可以把其他的操作放入对应的消息队列中然后马上返回用户结果,由消息队列异步的进行这些操作。或者还有一种情况,同时有大量用户注册你的软件,在高并发情况下注册请求开始出现一些问题,例如邮件接口承受不住,或是分析信息时的大量计算使cpu满载,这将会出现虽然用户数据记录很快的添加到数据库中了,但是却卡在发邮件或分析信息时的情况,导致请求的响应时间大幅增长,甚至出现超时,这就有点不划算了。面对这种情况一般也是将这些操作放入消息队列(生产者消费者模型),消息队列慢慢的进行处理,同时可以很快的完成注册请求,不会影响用户使用其他功能。所以在软件的正常功能开发中,并不需要去刻意的寻找消息队列的使用场景,而是当出现性能瓶颈时,去查看业务逻辑是否存在可以异步处理的耗时操作,如果存在的话便可以引入消息队列来解决。否则盲目的使用消息队列可能会增加维护和开发的成本却无法得到可观的性能提升,那就得不偿失了。
4.第一轮就是技术面试
首先是公司的技术主管来面试我,他先看了下我的笔试答案,问了我一些问题,我比较多都是没有回答上来的,因为我的基础知识太不牢固了,很多知识点都没有掌握。另外他还在我笔试题目的基础上,拓展了一些问题来问:
1.可以用什么类来替换Hashtable?
正确答案:ConcurrentHashMap
2.Redis是用来干什么?
通常局限点来说,Redis也以消息队列的形式存在,作为内嵌的List存在,满足实时的高并发需求。而通常在一个电商类型的数据处理过程之中,有关商品,热销,推荐排序的队列,通常存放在Redis之中,期间也包扩Storm对于Redis列表的读取和更新。
Redis的优点
性能极高 – Redis能支持超过 100K+ 每秒的读写频率。
丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
原子 – Redis的所有操作都是原子性的,同时Redis还支持对几个操作全并后的原子性执行。
丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。
3.谈谈你对Spring的认识
这一点我回答得比较好,因为我想到过既然我的项目中首次使用了Spring,那么面试问到的概率就极大。然后我也把比较标准的答案贴出来,作为今后面试的参考吧:https://blog.csdn.net/zhang150114/article/details/90478753
这篇博客写得非常详细了,我也会继续研读的。
4.说说MyBatis?
这一问我回答的是MyBatis是一个持久层框架,它对查询结果的封装程度好,而且十分轻量,有两种配置方式,一是注解配置,二是xml配置。然后面试官继续追问,你喜欢用什么配置?我回答注解,因为注解比较清晰,比较简单,在单表查询的时候用注解配置比较容易。如果遇到较为复杂的多表查询,我会考虑使用注解。然后面试官继续追问,那如果在一个系统中,简答查询用注解配置,复杂查询用xml配置,你觉得这样好吗?如果是你会怎么做?我说不太好,因为容易混乱,如果是我,我会使用注解配置,提高编写注解的能力和水平,也是可以完成多表查询的。另外,他还追问道,如果你往数据库表中刚刚插入一条用户,怎么查询出来?我回答的方法比较幼稚,我说在表新增一个字段,刚刚插入的用户这个字段设置为new,查询的时候就就只查询字段为new的记录,查询完毕后就把它修改成old,就查询不到了。显然这方法不可行,面试官问我,要是很多用户同时注册呢?我回答不上来了,为了表现出我好学的一面,我问他怎么实现?他说MyBatis有一个功能可以做到,让我回去了解下。
下面,我给出比较正确的回答:
对MyBatis的理解:
https://www.cnblogs.com/lanqi/p/7851552.html
使用XML配置还是注解配置的问题:
涉及的表字段少,业务简单,所以去用注解简单方便,个人认为mybatis强大之处在于他的动态sql,xml的可维护性高。而且在实际开发中表结构往往很复杂,所以在实际开发中建议大家用xml,即便很简单的业务,这样方便统一,也方便日后的维护修改。而且xml可以用mybatis generator自动生成也很方便。
原文链接:https://blog.csdn.net/yy119388974
查询刚刚插入的数据:
在ybatis的Mapper.xml的insert中设置:useGeneratedKeys=“true” keyProperty=“对象中的属性名”
https://blog.csdn.net/yt66222199/article/details/83791036
5.然后问了一下我的项目经历,由于是我独立做的项目,所以也比较熟悉,回答的结果也让他比较满意。
长舒一口气,技术面终于结束了。面完后就觉得要凉凉。
5.HR面试
主要是问了我在大学期间参加了什么社团,成绩怎么样,兴趣爱好如何,如何与他人合作啊等等。然后她们还问了我一个问题,我觉得我回答得不够谨慎,她们问我,可以实习多久,我说五到六个月,暑假不一定会在这继续实习(我内心是想自己可以去大厂实习的),然后她们继续问我心目中的公司规模是怎么样的?我说了互联网大厂,技术氛围要比较好,然后说如果去不了大厂可以选择中小型公司,继续提升自己的能力。面试完后一想,我就觉得我要凉了,既然选择了到他们的公司来面试,这的不应该说想要去更好的互联网公司,而应该把心目中的公司描述成和他们公司一支才可以。另外,一个公司招实习生说希望实习生能够转正的,公司不会这么容易就把培养了这么久的实习生放走,又去招收新的实习生。所以我觉得,今后的面试尽可能回答能够实习到大四,并争取转正。
6.主管面试
也问了我挺多问题,主要是考察我的综合能力,我自认为我的综合能力还算可以,就不一一列举了。
7.面试结果
当天下午就收到了,果然还是凉了。不过这次面试还是积累了挺多经验,也知道自己那些知识比较薄弱,也开始慢慢地知道面试官问题背后的意图了,希望2020年1月2日、1月3日的三场面试能够被捞上岸吧!不得不说,珠江新城的写字楼真的太豪华了,真的希望以后可以在珠江新城的高级写字楼工作啊啊啊!
第一次正式的实习面试,over,继续加油咯!我会继续更新的,直到我找到实习!
————————————————————————————————
更新时间:2020年1月2日
总结了第一场面试后的知识点,粗略阅读了《Java程序员面试宝典》
笔试考得比较基础,主要是一些常见的Java基础知识、Web基础知识以及几道很简单的逻辑题和一道求和道编程题,除了选择题中涉及的排序算法我没有选出来以外,其他的都还好,这也让我意识到我算法方面的薄弱,寒假开始后会开始学习。
笔试完后就是HR面,问的东西也是比较常规。自我介绍她要求我说一些简历上没有的,我回答得还算流畅。然后是问我如何协调学生工作、入党、学习等事情,接着是问我有没有升学、考公的打算等,总而言之,个人经历的问题只要把自己的经历、体会和思考给表达出来就可以了,而且回答的时候要记得分点,想好以后再回答。很顺利地,我就进入到了第二轮技术面试。
面试官很和蔼,浏览了一下我的简历后就开始问我问题了。
1.关于集合框架
我就说了Set、Map和List