秋招记录贴(天津)
笔试面试经历
由于我是河北人,不想离家太远,也不想北漂,女朋友也在天津,所以投的大部分都是天津的公司,和极少数北京公司,想来天津的同学欢迎交流。
以下是我走完流程的所有公司
- 渤海银行总行信息科技部 8月18号已投 29号笔试 9月6号面试 收到体检通知 offer
- 京东(北京) 8月24已投 9月11号笔试 16号一面 17号二面 28号hr面 offer
- 中科创达 9月9号已投 11号笔试 17号一面 18号hr面 offer
- 宏信建发 8月13号被要简历 14号一面过, 二面过 offer
以下是尚未开始or流程中途结束的有代表性的公司
- 紫光展锐 8月4号已投 31号笔试 无消息
- 联想(天津) 8月7号已投 25号笔试 9月7号面试 感谢信
- 海康威视(天津) 8月15号已投 26号笔试 拒面试
- 易华录 8月17号已投 无消息
- 麒麟 8月23号已投 无消息
- 中科曙光 已投 9月22号笔试 拒面试
- 南大通用 9月5号已投 无消息
- 经纬恒润 9月9号已投 18号一面 拒二面
- 阿里(北京) 9月9日已投 9月17号笔试 一面后进池子
- 邮储(天津) 9月11日已投
- 天津银行总行信息科技岗
- 四大行省分行信息科技岗
还有一些非天津的公司此处不列举
。。。
吐槽
天津真的是让人又爱又恨,可选择性真的太少了,而且想来天津的同学基本都会投这些家公司,竞争一点也不小,具体的天津的工作岗位可以参考我的帖子,也可以参考两位大佬。链接如下。
https://www.nowcoder.com/discuss/699049?source_id=profile_create_nctrack&channel=-1
https://gitee.com/csguide/Programmer-look-at-China/blob/main/%E5%A4%A9%E6%B4%A5.md
经验
- 简历:不要拿着一份简历去海投,要有针对性的投递,比如假如你投java开发工程师的岗位,简历里面就尽量不要出现一些跟java无关的实习经历或者跟java无关的项目。这样没有太大的意义。
- 怎么验证自己简历合不合格呢?
可以找同届的同学进行简历互相交换修改一下,修改完成后可以提前找几个不想去的互联网公司投一下试试简历到底能不能过。如果总是收不到笔试邀请那就说明自己的简历肯定存在问题。 - 笔试:建议早点刷题!建议早点刷题!建议早点刷题! 今年感觉无论是一些银行总行的科技部或者互联网大厂笔试都多多少少有算法题的。而且大厂面试手撕算法已经成了家常便饭。所以一定要有足够的题目储备,才能应对各种算法笔试,否则真的大厂笔试关都过不了的。
- 面试:可参考每家公司的面经,比较灵活。但是一定要对自己简历里所有的东西都了如指掌,包括项目中的细节。
- 面试练手:在面试自己最想去的公司之前尽量投几个练手的公司给自己提前安排几场面试,就当做是模拟考试了,当你面试的多了,自然就会轻松应对面试中出现的状况。(第一次面试真的很紧张,记忆犹新)
项目
一定要对自己的项目了如指掌,包括能从你项目中延伸出的一些经典面试问题。 如果你是高并发项目要清楚自己核心业务部分能承担多少QPS。(不然在面试中总是说高并发,多线程,但是具体项目能承受的并发数是多少不清楚,岂不是很尴尬。)
面经
java基础
equals和==区别?
- ==:对于基本数据类型,比较的是值,对于引用数据类型比较的是地址。
- equals:对于未重写过equals方法的类,equals和==方法是一样的,对于重写过的类,equals比较的是值。
基本数据类型
- 整数类型:byte、short、int、long
- 浮点型:float、double
- 布尔类型:boolean
- 字符型:char
了解java自动拆装箱吗
- java语法糖
- 以int和Integer举例装箱时jvm自动调用 Integer 的 valueOf(int)方法,将int转换为Integer对象。
- 拆箱时自动调用的是 Integer 的 intValue 方法,将Integer对象转换为int基本类型。
三大特性
- 封装:将一个对象私有化,并提供一些可以被外界访问的属性和方法。
- 继承:使用已经存在的类作为基础,去建立新的类,和现实中继承一样,子类继承父类,有父类的实例域和方法,也可以重写父类的方法。
- 多态:一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中的实现方法,必须在由程序运行期间才能决定。
重载和重写
- 重写:子类中把父类本身有的方法重新写一遍,在方法名,参数列表,返回类型等都相同的情况下, 对方法体进行修改或重写,子类函数的访问修饰权限不能少于父类的。
- 重载:在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同甚至是参数顺序不同)则视为重载。
final、finally与finalize的区别
- final:1、被final修饰的类不可以被继承;2、被final修饰的方法不可以被重写;3、被final修饰的变量不可以被改变。
- finally:finally作为异常处理的一部分,它只能用在try/catch语句中
- finalize:Object类中的方法,这个方法在gc启动,该对象被回收的时候被调用。其实gc可以回收大部分的对象,所以一般是不需要程序员去实现finalize的。
static
- static修饰成员变量和成员方法时,我们将其称之为静态变量和静态方法。
- 静态变量是随着类加载时被完成初始化的,它在内存中仅有一个,且JVM也只会为它分配一次内存,同时类所有的实例都共享静态变量,可以直接通过类名来访问它。
String,StringBuffer,StringBuilder
- 运行速度快慢为:StringBuilder > StringBuffer > String
- String最慢的原因:String为字符串常量,而StringBuilder和StringBuffer均为字符串变量,即String对象一旦创建之后该对象是不可更改的,但后两者的对象是变量,是可以更改的。
- 在线程安全上,StringBuilder是线程不安全的,而StringBuffer是线程安全的(很多方法可以带有synchronized来保证)
- 都是final类,不允许被继承
反射
- Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息。
- 性能不好,会先去看看这个类有没有被加载过,没有的话会有类加载的过程。
- 三种方式
- 通过class.forname(包名.类名)
- 类.class
- 对象.getClass()
异常
异常可以大体分为两类, 运行时异常RuntimeException,运行时异常。
- 运行时异常RuntimeException类及其子类这些异常是程序中可以选择捕获处理,也可以不处理。这些异常一般由程序逻辑错误引起,程序应该从逻辑角度尽可能避免这类异常的发生。
- NullPointerException:空指针异常;出现原因:调用了未经初始化的对象或者是不存在的对象。
- IndexOutOfBoundsException:数组角标越界异常,常见于操作数组对象时发生。
- ClassCastException:数据类型转换异常。
- 非运行时异常从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。
- IOException:一般在读写数据的时候会出现这种问题。
- ClassNotFoundException:意思就是找不到指定的class。
- SQLException:SQL 异常,操作数据库时的 SQL 语句错误。
Collection和Collections区别
- Collection 是一个集合接口。它提供了对集合对象进行基本操作的通用接口方法。LinkedList,ArrayList,Set
- Collections是一个包装类。它包含有各种有关集合操作的静态多态方法,就像一个工具类
浅拷贝&深拷贝
- 浅拷贝:只拷贝了源对象的地址(本质是一个对象),源对象的数值发生改变时,拷贝对象跟着一起改变
- 深拷贝:拷贝了源对象所有的值,而不只是地址,源对象的值发生改变时,拷贝对象不会随之改变
序列化&反序列化
- 序列化:将对象写入到IO流中。
- 反序列化:从IO流中恢复对象序列化机制允许将实现序列化的Java对象转换为字节序列,这些字节序列可以保存在磁盘上,或通过网络传输,传输完毕后恢复成原来的对象。
幂等性
- 接口幂等性就是用户对同一操作发起的一次请求和多次请求结果是一致的,不会因为多次点击而产生了副作用,比如支付场景,用户购买了商品,支付扣款成功,但是返回结果的时候出现了网络异常,此时钱已经扣了,用户再次点击按钮,此时就会进行第二次扣款,返回结果成功,用户查询余额发现多扣钱了,流水记录也变成了两条。。。这就没有保证接口幂等性。
集合
集合中最最常问的就是Hashmap,ConcurrentHashMap,ArrayList,LinkedList 一定要熟悉。
Map
HashTable
线程安全,底层是由Synchronize保证安全的,效率低,几乎已经弃用。
TreeMap
底层红黑树,天然支持排序,默认情况下通过Key值的自然顺序进行排序。
HashMap(线程不安全)
HashMap要熟悉两个版本(1.7和1.8)
扩容机制
- 默认的初始化大小为 16。创建时如果给定了容量初始值,那么而 HashMap 会将其扩充为 2 的幂次方大小。也就是说 HashMap 总是使用 2 的幂作为哈希表的大小
- 为什么HashMap 总是使用 2 的幂作为哈希表的大小?
- 为了能让 HashMap 存取⾼效,尽量减少碰撞,也就是要尽量把数据分配均匀。Hash 值的范围值-2147483648到2147483647,前后加起来⼤概40亿的映射空间,只要哈希函数映射得比较均匀松散,⼀般应⽤是很难出现碰撞的。但问题是⼀个40亿⻓度的数组,内存是放不下的。所以这个散列值是不能直接拿来⽤的。⽤之前还要先做对数组的⻓度取余运算,得到的余数才能⽤来当做要存放的具***置也就是对应的数组下标。相对于取余操作来说位运算的效率更快,而取余运算 hash%length和位运算 hash&(length-1)相等的前提是 length 是2的 n 次方
- 为什么HashMap 总是使用 2 的幂作为哈希表的大小?
- LoadFactory 默认0.75(可修改),每次扩充,容量变为原来的 2 倍
- JDK8时当链表长度大于8的时候,并且数组长度没超过64,就先尝试扩容,如果超过64了,就会把链表变成红黑树
- 创建一个空数组重新rehash
重写equals必须重写HashCode
- 如果equals()方法得出的结果相同,那么hashCode()的结果也必须相同。而默认的hashCode()是内存地址的散列值,不同对象的地址一定是不一样的。而在业务场景下,我们认为两个不同对象的值是相同的(也就是equals()结果为true),所以也必须保证二者的hashCode()结果是相同的,就必须重写默认的按对象地址散列的方式了。
ConcurrentHashMap(线程安全)
ConcurrentHashMap要熟悉两个版本(1.7和1.8)
- 1.7:底层采用数组+链表的形式,底层是一个个HashEntry
- 采用segment分段锁进行加锁,粒度比较大,继承了reentranLock,在尝试加锁的时候会先尝试获取锁如果存在并发竞争会进行自旋尝试,如果自旋失败会发生阻塞。
- get高效 volatile修饰 不需要加锁。
- 1.8:底层数组+链表+红黑树的形式,底层是一个个node
- 底层采用CAS+synchronized进行加锁,开始存在并发竞争时,会进行cas尝试,如果失败会进行自旋尝试,如果再失败就
synchronized保证 - 锁粒度比较小,synchronized 只锁定当前链表或红⿊⼆叉树的⾸节点(JDK1.6 以后对 synchronized 锁做了很多优化(详见多任务))
- 底层采用CAS+synchronized进行加锁,开始存在并发竞争时,会进行cas尝试,如果失败会进行自旋尝试,如果再失败就
List
ArrayList(线程不安全)
- 底层数据结构是数组。
- 查找访问速度快,增删效率低。
- 数组的大小默认为10,以无参数构造方法创建 ArrayList 时,实际上初始化赋值的是一个空数组。当真正对数组进行添加元素操作时,才真正分配容量。即向数组中添加第一个元素时,数组容量扩为10。
- 扩容:新的数组容量是旧的数组容量的1.5倍,本质才用的是数组的拷贝。
LinkedList(线程不安全)
Vector(线程安全)
- 使用了 synchronized 进行加锁,保证了线程安全,效率低。
- 扩容:默认为原来的两倍,若指定capacityIncrement,则按照指定的来。
计算机网络
计算机网络的知识点我认为可以完全串成一个体系,以面试连环炮的形式进行学习记忆更加事半功倍。
你了解http的请求过程吗?(在浏览器输入url到显示主页过程)
- DNS解析(网站到ip地址)
- DNS缓存查找顺序:浏览器,若浏览器缓存未命中,会检查操作系统中对应的已经解析的结果,windows在C盘的host中,若没有就分级查询 :本地DNS服务器(它可能就在你城市的某个角落,一般到这一级就能解析出大部分的ip地址了),根域名服务器,顶级域名服务器,主域名服务器
- TCP连接(三次握手)
- 发送http请求
- 服务器处理请求并返回http报文
- 浏览器解析渲染页面
- 断开连接(四次挥手)
那既然提到了三次握手你简单介绍一下吧。
- 三次握手是由客户端发起的,当客户端想和服务端连接的时候客户端会向服务端发送一个
SYN=1, client_seq=x
的报文 - 服务端收到后知道客户端想与我建立连接,会回复给客户端一个ACK报文,报文中
SYN=1, ACK=1, server_seq=y, server_ack=x+1
- 这时已经完成了两次握手,这时候对于客户端来说它知道自己可以成功接收消息,也知道自己可以发送消息,但是对于服务端来说,它只知道自己可以接受消息,并不知道自己是否可以正确发送消息,此时还需要第三次握手,即客户端回传给服务端一个ACK报文报文中
ACK=1, client_ack=y+1, client_seq=x+1
那四次挥手呢?
- 四次挥手是由客户端发起的,当客户端想和服务端断开连接的时候客户端会向服务端发送一个
FIN=1, seq=u
报文 - 服务端收到报文后知道客户端想和我断开连接,然后立马回复给一个ACK报文,报文中
ACK=1, seq=v, ack=u+1
,告知客户端它收到了报文 - 过一会等服务端发送完数据之后,会给客户端发送一个FIN报文,报文中
FIN=1,ACK=1,seq=w,ack=u+1
- 客户端收到报文后,知道服务端消息也都完全发送完毕,想要断开连接,会回复给服务端一个ACK报文,报文中
ACK=1,seq=u+1,acl=w+1
那四次挥手完毕后是立马结束吗?
- 不是
- 最后要等两个时间周期,2MSL时间去向ACK消息最大存活时间(MSL) + 来向FIN消息的最大存活时间(MSL)。
- 客户端不知道服务端收没收到ack报文,所以要等2MSL是为了等待在2MSL这段时间中可能出现的服务端FIN超时重传,如果服务端真的需要超时重传,那么一定会在这段时间里进行,反之,若过了这段时间还没有重传,则可以确认ACK被服务端收到了。
那既然是基于TCP的,TCP的安全可靠是怎么保证的?
- 校验和:接收方和发送方进行数据的校验和比对,如果发送方和接收方的校验和不一致那传输有误
- 确认应答(ack)与序列号:TCP将每个字节的数据都进行了编号。保证数据的按序到达,提高效率。可实现多次发送,一次确认。去除重复数据。接收方对于按序到达的数据会进行确认(ack),发送方如果收到了已发送的数据的确认报文,则继续传输下一部分数据
- 超时重传:当报文发出后在一定的时间内未收到接收方的确认(ack),发送方就会进行重传
- 连接管理:三次握手,四次挥手
- 流量控制:TCP支持根据接收端的处理能力,来决定发送端的发送速度
- 拥塞控制:解决了两台主机之间因传送速率(网络拥堵)而可能引起的丢包问题。为此TCP引入慢启动机制,先发出少量数据,就像探路一样,先摸清当前的网络拥堵状态后,再决定按照多大的速度传送数据。
那我们现在视频面试的软件是基于什么协议?
- UDP
- UDP不需要建立连接,远程收到UDP报文后不需要给出任何确认,开销小,速度快
- 适用于直播,视频,语音
UDP与刚才聊得TCP有什么区别呢?
- TCP是面向连接的协议,提供可靠传输,在收发数据之前需要通过三次握手建立连接,并且通过校验、序号等机制保证传输数据的正确性;UDP是无连接的协议,提供尽最大努力交付,适合实时应用
- TCP提供流量控制和拥塞控制,而UDP没有
- TCP对系统资源要求较高,速度比UDP慢
- TCP数据报没有边界,可能出现粘包问题,而UDP是一个独立的数据报,不会出现粘包现象
- TCP提供点到点的通信,而UDP支持一对一、一对多、多对多的通信
HTTP1.0和HTTP1.1有什么区别?
- 连接:
- 1.0 短连接,每次请求建立一个连接,HTTP基于TCP/IP协议的,每次建立断开连接都要经历三次握手四次挥手,开销大。
- 1.1长链接,流水线方式:客户收到响应报文之前就可以发送下一次的请求报文,非流水线方式:收到响应后才能发送下一个请求
- 错误状态响应码:
- 1.1新增24个错误状态响应码,比如410表示服务器上某个资源被永久删除
- 缓存处理:
- 1.1引入了更多的缓存控制策略比如IF-Match,If-no-match等可供选择的缓存头来控制缓存策略
- 带宽优化和网络连接的使用:
- 1.0中存在浪费带宽的现象,比如客户端只想要某个对象的一部分,而服务器却把整个对象送过来了,而且不支持断点续传的功能。
- 1.1在请求头引入了range头域,允许只请求某个部分。
HTTP中get和post有什么区别?
- get用于请求,post用于对表单的提交,相当于把信息交给服务器等待服务器作出响应
- get不安全(因为参数放在url中),post安全(请求体,对于用户不可见)
- get的url有长度限制,post放在请求体中没长度限制
- get请求会被浏览器主动缓存,post不会
- get会发一个TCP数据包,http header和data一起发送,服务器响应200。post发送两个TCP数据包,先发送header服务器响应100,在发送data,服务器响应200.
那刚刚聊完了http了,https请求过程或者说加解密流程又是啥呢?
- 浏览器发送https请求后,会使用443端口进行连接
- https需要使用一套CA数字证书,证书内有一个公钥和一个私钥,私钥服务器自己保存,服务器收到请求后,将包含公钥的证书返回给客户端
- 客户端收到证书,验证合法性,若不通过显示https警告,通过则继续
- 客户端生成一个用于对称加密的随机key并用证书里的公钥加密发送给服务端
- 服务端收到后使用私钥进行解密
- 服务端使用客户端发送过来的随机key对要传输的http数据进行对称加密,将密文返回客户端
- 客户端使用随机key对称解密密文,得到http明文
- 后续https请求使用之前交换好的随机key进行对称加解密
cookie和session区别?
- cookie数据存放在客户的浏览器上,session数据放在服务器上
- cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗;session安全
- session会在一定时间内保存在服务器上,当访问量增加时,会比较占用服务器的性能(session存到redis)。考虑到减轻服务器性能方面,应当使用cookie
- 单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie;
token和session区别?
- 服务器不需要记录任何东西,每次都是一个无状态的请求,浏览器访问Web服务器后认证成功后生成Token并返回给客户端,客户端浏览器后续的请求都会把这个Token带到服务器端去解密验证,以此判定请求是否合法
- Session是存放在服务器端的
- Token是放在客户端存储
- token传递的方式也不限于cookie传递,session要依赖于cookie传输Jsessionid (如果浏览器禁用了cookie/不支持cookie,可以通过URL重写的方式发送到服务)
- token 和 cookie 本质上没啥区别,只不过 token 只是一个字符串,访问的时候可以放在 url 的参数,请求头里等,不像 cookie 那么重量级
HTTP状态码有了解吗?
- 1xx 提示信息,代表当前是协议被处理的阶段,还需要后续操作
- 2xx 请求成功,请求报文已经收到并且被成功处理
- 200 ok 表明请求成功
- 3xx 重定向,资源位置发生了变动,需要客户端重新发送请求
- 301 Moved Permanently 永久重定向
- 302 Moved Temporarily 临时重定向
- 4xx客户端错误,客户端发送的报文有误,服务器端无法处理
- 400 Bad Request 客户端请求有误
- 403 Forbidden 服务器禁止访问资源
- 404 Not Found 请求的资源不存在
- 5xx 服务器错误,服务器处理请求的时候内部出了错误
- 500 Interval Server Error 服务器端出现了错误
- 502 Bad Gateway 网关返回的错误码
分享不易,如果你觉得文章还不错,你的转发、分享、点赞、关注、留言就是对我最大的鼓励。感谢您的阅读!