一、字节提前批java后台开发面试一面
1. 字符编码的utf8 gbk为什么设计这么多格式。
1)ASCII 编码
众所周知,计算机只能处理0和1,任何符号都转换为0和1的序列才能处理。计算机中8个位(bit)作为一个字节,所以1个字节能产生2的8次方个0和1的不同组合,也就是说1个字节做多能表示256种字符。ASCII编码就是用1个字节来存储字符,计算机最初是美国人发明的,他们的符号不多,所以还将8个0和1序列中的第一位固定为0,ASCII只能表示127个字符。
2)GBK 编码
美国佬的符号不多,所以ASCII编码够用,但是其他国家就不行了,每个国家符号数量都不一样,就各自指定了自己的编码。例如我们中国就制定了GB2312编码。GB2312编码用2个字节表示一个字符。
3)Unicode 编码
每个国家都用自己的编码,编码一朵就容易乱套,也没法交流,所以需要一种编码把各个国家的编码都囊括进去,这就是Unicode编码的由来。所以,Unicode也被称为万国码。Unicode编码也用2个字节存储一个字符。Unicode 又称 UTF-16。
4)utf-8 编码
Unicode编码解决了编码不能通用的问题,但是却容易浪费内存,尤其是在存储英文的时候,例如一个字符“A”,ASCII编码只需要1个字节就够,但是Unicode编码必须要用2个字节。为了解决这一问题,就有了utf-8编码。 utf-8编码把存储英文依旧用一个字节,汉字就3个字节。特别是生僻的编程4-6字节,如果传输大量英文,utf-8作用就很明显了。
utf-8编码进行存储时有极大地优势,但是当读取到计算机内存时却不大合适,因为utf-8编码是变长的,不方便寻址和索引,所以在计算机内存中,还是转化为Unicode编码合适些。这就可以解释为什么每次读取文本时,要将编码转化为Unicode编码,而将内存中的字符写入文件存储时,要将编码转化为utf-8了。
2. 进程线程区别?简单
3. 死锁怎么产生的,怎么避免死锁。简单
(互斥、不可剥夺、循环等待、请求与保持。 破坏四个条件)
4. Java线程安全的保证?简单
volatile 保证可见性 禁止指令重排序 【内存屏障】
synchronized
Lock
5. Tcp,https在哪一层?简单
6. 为什么把网络分为这么多层
OSI 七层模型。OSI5层模型
各种问题都写成一套协议来规定双方通信的规则,但是呢?万一其中哪些规则通信中出现问题,影响到了其他规则,最常见的就是数据包,一个数据包中如果包含各种各样的协议,就乱套了
7. 子网掩码
1.子网掩码(Subnet Mask)又叫网络掩码、地址掩码,必须结合IP地址一起对应使用
2.只有通过子网掩码,才能表明一台主机所在的子网与其他子网的关系,使网络正常工作
3.子网掩码和IP地址做“与”运算,分离出IP地址中的网络地址和主机地址,用于判断该IP地址是在本地网络上,还是在远程网络网上
4.子网掩码还用于将网络进一步划分为若干子网,以避免主机过多而拥堵或过少而IP浪费
8. http https的区别,https的详细流程
(1)HTTPS是密文传输,HTTP是明文传输;
(2)默认连接的端口号是不同的,HTTPS是443端口,而HTTP是80端口;
(3)HTTPS请求的过程需要CA证书要验证身份以保证客户端请求到服务器端之后,传回的响应是来自于服务器端,而HTTP则不需要CA证书;
(4)HTTPS=HTTP+加密+认证+完整性保护。
1.客户端想服务器发起HTTPS的请求,连接到服务器的443端口;
2.服务器将非对称加密的公钥传递给客户端,以证书的形式回传到客户端
3.服务器接受到该公钥进行验证,就是验证2中证书,如果有问题,则HTTPS请求无法继续;如果没有问题,则上述公钥是合格的。(第一次HTTP请求)客户端这个时候随机生成一个私钥,成为client key,客户端私钥,用于对称加密数据的。使用前面的公钥对client key进行非对称加密;
4.进行二次HTTP请求,将加密之后的client key传递给服务器;
5.服务器使用私钥进行解密,得到client key,使用client key对数据进行对称加密
6.将对称加密的数据传递给客户端,客户端使用非对称解密,得到服务器发送的数据,完成第二次HTTP请求。
9. MySQL中索引的数据结构有两种,一种是Hash,另一种是BTree区别是很莫?
B+树的特征
1、有K个孩子的节点就有K个关键字。也就是孩子数量=关键字数。
2、非叶子节点的关键字也会同时存在在子节点中,并且是在子节点中所有关键字的最大或最小。
3、非叶子节点仅用于索引,不保存数据记录,跟记录有关的数据都放在叶子节点中。
4、所有关键字都在叶子节点出现,叶子节点构成一个有序链表,而且叶子节点本身按照关键字的大小从小到大顺序链接。
键值Key通过Hash映射找到桶bucket。桶指的是一个能存储一条或多条记录的存储单位。一个桶的结构包含了一个内存指针数组,桶中的每行数据都会指向下一行,形成链表结构,当遇到Hash冲突时,会在桶中进行键值的查找。
Hash索引与B+树索引的区别
由于Hash索引结构和B+ 树不同,因此在索引使用上也会有差别:
(1)Hash索引不能进行范围查询,而B+树可以。
这是因为Hash索引指向的数据是无序的,而B+ 树的叶子节点是个有序的链表。
(2)Hash索引不支持联合索引的最左侧原则(即联合索引的部分索引无法使用),而B+树可以。
对于联合索引来说,Hash索引在计算Hash值的时候是将索引键合并后再一起计算Hash值,所以不会针对每个索引单独计算Hash值。因此如果用到联合索引的一个或多个索引时,联合索引无法被利用。
(3)Hash索引不支持Order BY排序,而B+树支持。
因为Hash索引指向的数据是无序的,因此无法起到排序优化的作用,而B**+树索引数据是有序的**,可以起到对该字段Order By 排序优化的作用。
(4)Hash索引无法进行模糊查询。而B+ 树使用 LIKE 进行模糊查询的时候,LIKE后面前模糊查询(比如%开头)的话可以起到优化的作用。
(5)Hash索引在等值查询上比B+树效率更高。
不过也存在一种情况,就是索引列的重复值如果很多,效率就会降低。这是因为遇到Hash冲突时,需要遍历桶中的行指针来进行比较,找到查询的关键字非常耗时。所以Hash索引通常不会用到重复值多的列上,比如列为性别,年龄等。
10. 联合索引生效条件?失效条件?如何使用它们?
生效条件
1.两个或者多个列上的索引叫做复合或联合索引。
2.mysql中从左到右使用索引的字段,一个查询可以只使用索引中的一部分,但只能是最左侧。
3.创建符合索引时,应该仔细考虑列的顺序。对索引中所有列或仅对前几列执行搜索时,4.复合索引将会非常有用,仅对后面的任意列执行搜索时,复合索引没有任何用处。
失效条件
1.减少或者避免 select *
2.在使用<> 或 !=时会导致索引失并且进行全盘扫描
3.like以通配符开头 ‘%abc…’ 开头会导致索引失效,全盘扫描
4.在索引列上做计算、函数、类型转换会导致索引失效
5.存储引擎不能使用索引范围右边的列
6.is null not is null 无法使用索引
建议:
1.单键索引,尽量选择对于当前select适配性更好的索引
2.使用组合索引时,当前查询过滤性最好的字段在索引中的位置越靠前越好
3.使用组合索引时,尽量选择可以能够包含当前查询条件中更多字段的索引
11. 数据库三范式? 简单
写题
1.
sql:学生成绩表 table1, 学生、课程、成绩,(name,sbuject,score),查询出所有课程都大于80分的学生的平均成绩。
select avg(score) from tb_score where name in (select distinct name from tb_score where score > 80);
算法:求全排列的下一个数:如1234 下一个数是1243,1243下一个数是1324.
原题leetcode - https://leetcode-cn.com/problems/next-permutation/
二、字节一二三面试题
字节一面:7月29日(1hour)
1.springIOC的设计思想
IoC,用白话来讲,就是由容器控制程序之间的关系,而非传统实现中,由程序代码直接操控。这也就是所谓“控制反转”的概念所在:控制权由应用代码中转到了外部容器,控制权的转移,是所谓反转。
2.Bean的生命周期
1.Bean的实例化阶段 2.Bean的设置属性阶段 3.Bean的 初始化阶段 4.Bean的销毁阶段
1.Bean容器找到Spring配置文件中BeanDefination的定义;
2.Bean容器利用java 反射机制实例化Bean;
3.Bean容器为实例化的Bean设置属性值;
4.如果Bean实现了BeanNameAware接口,则执行setBeanName方法;
5.如果Bean实现了BeanClassLoaderAware接口,则执行setBeanClassLoader方法;
6.如果Bean实现了BeanFactoryAware接口,则执行setBeanFactory方法;
如果 ……真的,到这我经常忘记,但前面三个Aware接口肯定能记住;
7.如果Bean实现了ApplicationContextAware接口,则执行setApplicationContext方法;
8.如果加载了BeanPostProcessor相关实现类,则执行postProcessBeforeInitialization方法;
9.如果Bean实现了InitializingBean接口,则执行afterPropertiesSet方法;
10.如果Bean定义初始化方法(PostConstruct注解或者配置的init-method),则执行定义的初始化方法;
11.如果加载了BeanPostProcessor相关实现类,则执行postProcessAfterInitialization方法;
12.当要销毁这个Bean时,如果Bean实现了DisposableBean接口,则执行destroy方法。
3.Mysql用的什么引擎,Innodb的索引大概讲一下?简单
4.接上一问讲到的B+树,为什么使用B+树而不使用B树?
因为B树不管叶子节点还是非叶子节点,都会保存数据,这样导致在非叶子节点中能保存的指针数量变少,B+树的飞叶子节点存放的是索引。
判断一种数据结构作为索引的优劣主要是看在查询过程中的磁盘IO渐进复杂度,一个好的索引应该是尽量减少磁盘IO操作次数
1.B树只适合随机检索,而B+树同时支持随机检索和顺序检索
2.B+树空间利用率更高。因为内部节点不存储数据,只存储索引值,因为相比较B树来说,B+树一个节点可以存储更多的索引值,从而使整颗B+树变得更矮,减少了I/O次数,3.磁盘读写代价更低,I/O读写次数是影响索引检索效率的最大因素
4.B+树的查询效率更加稳定。B树搜索有可能会在非叶子节点阶数,约靠近根节点的记录查找时间越短,其性能等价于在关键字全集内做一次二分查找。而在B+树中,顺序检索比较明显,随机检索时,任何关键字的查找都必须走一条从根节点到叶节点的路,所有关键字的查找路径相同,导致每一个关键字的查询效率相当
5.B树在在基于范围查询的操作上的性能没有B+树好,因为B+树的叶子节点使用了指针顺序的链接在一起,只要遍历叶子节点就可以实现整棵树的遍历,相比较B+树来说,由于B树的叶子节点是相互独立的,所以对于范围查询,需要从根节点再次出发查询,增加了磁盘I/O操作次数
6.增删文件(节点)时,效率更高,因为B+树的叶子节点包含了所有关键字,并以有序的链表结构存储,这样可很好提高增删效率
5.链表这种结构可以像B+树一样优化查询吗,怎么做(回答变成跳表)简单
6.Java线程安全集合有哪些,concurrenthashmap如何做到线程安全?简单
7.hashmap在什么情况下出现线程不安全(回答插入节点时,会短暂的形成环形)
8.hashmap扩容时为什么线程不安全???
了解HashMap的扩容首先要了解HashMap几个非常重要的常量:
static final float DEFAULT_LOAD_FACTOR = 0.75f;//负载因子 Capactity:HashMap的当前长度(2的n次幂) LoadFActor:负载因子,默认为0.75f; //在每次put之后,会有下面这个判断: if (++size > threshold) resize(); threshold = Capactity * LoadFActor,threshold为临界值,当长度大于临界值时,进行扩容(resize() )操作; hashMap的ReSize不是简单的把长度扩大,而是经过一下两个步骤: 1、扩容 创建一个新的Entry空数组,长度是原hashMap数组的 2 倍; 2、ReHash 因为长度变长,Hash的规则也随之改变了。所以要遍历原Entry数组,把所有的Entry重新Hash到新的数组。 至此,HashMap完成了扩容操作。
总结版
HashMap在put的时候,插入的元素超过了容量(由负载因子决定)的范围就会触发扩容操作,就是rehash,这个会重新将原数组的内容重新hash到新的扩容数组中,在多线程的环境下,存在同时其他的元素也在进行put操作,如果hash值相同,可能出现同时在同一数组下用链表表示,造成闭环,导致在get时会出现死循环,所以HashMap是线程不安全的。
实现线程安全的几种方式
1.Collections.synchronizedMap()返回一个新的baiMap,这个新的map就是线程安全du的。 这个要求大家习惯基于接口编程,因为返回的并不是HashMap,而是一个Map的实现。
2.java.util.concurrent.ConcurrentHashMap. 这个方法比方法一有了很大的改进。
3.Hashtable,Hashtable通过对整个表上锁实现线程安全,因此效率比较低
9.String是不是线程安全的???
String是final修饰的类,是不可变的,所以是线程安全的。
不可变类的线程都是安全的,因为他们都是只读的
10.Synchronized的底层原理???
一、作用
确保线程互斥的访问同步代码
保证共享变量的修改能够及时可见
有效解决重排序问题
二、用法
修饰普通方法
修饰静态方法
修饰代码块
修饰类
三、原理
同步代码块是通过 monitorenter 和 monitorexit 指令获取线程的执行权
同步方法通过加 ACC_SYNCHRONIZED 标识实现线程的执行权的控制
11.AQS怎么保证锁的可重入性???简单
1、AQS是一个JAVA线程同步的框架。是JDK中很多锁工具的核心实现框架。
2、 在AQS中,维护了一个信号量state和一个线程组成的双向链表队列。其中,这个线程队列,就是用来给线程排队的,而state就像是一个红绿灯,用来控制线程排队或者放行的。 在不同的场景下,有不用的意义。
3、在可重入锁这个场景下,state就用来表示加锁的次数。0标识无锁,每加一次锁,state就加1。释放锁state就减1。
12.内存管理的基本方式有哪些???
常见的内存管理方式有块式管理,页式管理, 段式管理, 段页式管理。
13.LRU怎么实现???(1)复杂度的查找
最近最久未使用 :如果一个数据在最近一段时间没有被访问到,那么在将来它被访问的可能性也很小
1.用一个数组来存储数据,给每一个数据项标记一个访问时间戳,每次插入新数据项的时候,先把数组中存在的数据项的时间戳自增,并将新数据项的时间戳置为0并插入到数组中。每次访问数组中的数据项的时候,将被访问的数据项的时间戳置为0。当数组空间已满时,将时间戳最大的数据项淘汰。
2.利用一个链表来实现,每次新插入数据的时候将新数据插到链表的头部;每次缓存命中(即数据被访问),则将数据移到链表头部;那么当链表满的时候,就将链表尾部的数据丢弃。
3.利用链表和hashmap。当需要插入新的数据项的时候,如果新数据项在链表中存在(一般称为命中),则把该节点移到链表头部,如果不存在,则新建一个节点,放到链表头部,若缓存满了,则把链表最后一个节点删除即可。在访问数据的时候,如果数据项在链表中存在,则把该节点移到链表头部,否则返回-1。这样一来在链表尾部的节点就是最近最久未访问的数据项。
对于第一种方法, 需要不停地维护数据项的访问时间戳,另外,在插入数据、删除数据以及访问数据时,时间复杂度都是O(n)。对于第二种方法,链表在定位数据的时候时间复杂度为O(n)。所以在一般使用第三种方式来是实现LRU算法。
实现方案
使用LinkedHashMap实现
LinkedHashMap底层就是用的HashMap加双链表实现的,而且本身已经实现了按照访问顺序的存储。此外,LinkedHashMap中本身就实现了一个方法removeEldestEntry用于判断是否需要移除最不常读取的数,方法默认是直接返回false,不会移除元素,所以需要重写该方法。即当缓存满后就移除最不常用的数。
字节二面:8月3号(50min)(记不太清了,只写了几个记忆深的问题)