京东一面面经(2019-Java后台开发实习生)

目录

1.没有自我介绍

2.对于集合的了解,ArrayList和LinkedList的区别和适应场景,哪个查询的效率高

3.hashmap的构造方法,解决冲突的方法,扩容原理,HashMap的扩容因子

4.treemap的底部实现(红黑树),hashset的去重

5.红黑树,平衡二叉树,(2-3树也说了点)底层结构,查询和插入的复杂性

6.hashtable和hashmap的区别

7.方法的重载和重写的区别

8.面向对象的三大特性

9.继承的实现两种方式(继承类和实现接口)

10.抽象类和接口的区别

11.tcp三次握手四次挥手,网络层有什么协议,OSI七层模型

Tcp的三次握手

12.数据库隔离级别

13.sql优化

14.innodb的特性以及和其它存储引擎的区别

15.mysql的主从分离原理,怎样解决主从复制慢的问题

16.知道什么设计模式,详细说单例模式的实现方式

17.回溯算法的思想,代码怎么写

18.nginx的负载均衡算法的实现

19.stringbuilder和stringbuffer的区别,初始容量是多少

20string都有什么方法

21jvm的内存模型volatile的特性,可以保证原子性吗

22.jvm的垃圾回收算法

23.数据库三范式

24.数据库慢查询怎么解决explain


2.对于集合的了解,ArrayList和LinkedList的区别和适应场景,哪个查询的效率高

集合分为List,Map和Set.他们都是接口,list的实现类有ArrayList,LinkedList,Vector,Map的实现类有HashMap,LinkedHashMap,HashTable,TreeMap,set有三个实现类:HashSet,TreeSet,LinkedHashSer

ArrayList和LinedList的区别:

  1. ArrayList的底层是数组,LinkedList的底层是双向链表
  2. 在ArrayList的中间插入元素不方便,而在LinkedList的中间插入或者删除元素方便
  3. LinkedList不支持高效的随机元素访问

适用场景:ArrayList使用与频繁查询的场景,LinkedList适用于频繁增删的场景,数组的查询,如果已知索引,查询的时间复杂度是o(1),如果不知道索引,查询一个数的时候,时间复杂度是o(n),链表的查询时间复杂度也是o(n),但是链表的存储是不连续的,而数组的存储是连续的,所以数组的查询效率高

3.hashmap的构造方法,解决冲突的方法,扩容原理,HashMap的扩容因子

构造方法:

Hashmap一共有四个构造函数

HashMap()没有指定时,使用默认的初始化大小16,使用默认的加载因子0.75

HashMap(int inititalCapacity)

HashMap(int inititalCapacity,float loadFactor)

指定初始化大小,hashmap调用tablesize,找到大于指定初始化容量大小的最小二次幂值

int n=cap-1;

n|=n>>>1;

n|=n>>>2;

n|=n>>>4;

n|=n>>>8;

n|=n>>>16;

返回n+1表示初始的大小

table初始化不是在初始化时完成的,而是在resize的时候完成的。

解决冲突的方法

参考:https://www.cnblogs.com/wuchaodzxx/p/7396599.html

四种方法:

  1. 开放定址法

1.1线性探测再散列:

    冲突发生时,顺序查看表中下一个单元,直到找到一个空单元,或查遍全表。表后面查完,如果没有,在表头继续查看(相当于是一个循环),步长为1.

1.2二次线性再散列

    冲突发生时,分别在表的左右进行跳跃式探测,较为灵活,不易产生聚集,但缺点是不能探测到整个散列的地址空间。步长是1,-1,4,-4…

1.3伪随机探测再散列

    建立一个随机数发生器,并给定一个随机数作为起始点。(随机数序列是 预先产生的)步长是一个随机序列。

2.拉链法

    把所有具有地址冲突的关键字链在同一个链表中。

3.再哈希法

       构造多个hash函数,当发生冲突时,用其他的哈希函数,产生hash值,   直到不冲突为止。

4.建立公共溢出区

        将哈希表分为基本表和溢出表两个部分,凡是和基本表发生冲突的,一 律填入溢出表。

HashMap怎么解决hash冲突:

采用拉链法(链地址法)。当好多bin被映射到同一个桶时,如果桶中bin<6,采用链表存储,如果bin>8但是Hash表的容量小于64,依然用链表存储,对hash表进行扩容。,然后进行hash表的重构。如果bin>8并且桶的容量大于64,则将链表的结构转换为红黑树的结构进行存储。

HashMap的扩容

Hashmap在容量超过负载因子所定义的容量之后,就会扩容。Hashmap的默认负载因子是0.75.阈值=0.75*容量,也就是说当前hashmap存储的容量超过负载因子的容量就会扩容。这时就会将hashmap的大小扩大为原来数组的两倍。并将原来的对象放入新的数组中。这个过程叫做再hash,因为他调用hash方法来确定。

HashMap的扩容因子默认的是0.75(也可以再跟面试官说一下扩容因子自定义的时候需要什么)

4.treemap的底部实现(红黑树),hashset的去重

TreeMap是基于红黑树的实现,因此它要求一定要有key比较的方法,要么传入Comparator实现,要么实现Comparable接口,在put操作是,基于红黑树的遍历,基于comparator来比较key应该放在树的左边还是右边,如果找到相等的key,则直接替换掉value

HashSet在存元素时会调用对象的hashcode方法进行计算出存储索引的位置,如果其存储索引已经存在元素(Hash碰撞)则和该索引位置上所有的元素进行equals比较,如果该位置没有其他元素或者比较的结果都是false就存进去,否则就不存,所以可以看见元素是按照hash值来找位置的,故而无序且可以保证无重复元素,因此我们在往HashSet集合中存储元素时,元素对象应该正确重写Object类的hashcode和equals方法,否则会出现不可预知的错误。set集合中,相同的元素可能会存储[set先用hashcode比较,然后用equals比较,如果没有写equals方法的话,有可能存储重复的元素],而且hashcode 的冲突会加大。

5.红黑树,平衡二叉树,(2-3树也说了点)底层结构,查询和插入的复杂性

这个具体查阅我的博客:https://blog.csdn.net/if_i_were_a/article/details/89380875

https://blog.csdn.net/if_i_were_a/article/details/89371048

红黑树与2-3树等价

红黑树的定义:

1.每个节点定义成红色或者黑色的

2.根节点是黑色的

3.每个叶子节点(最后的空节点)也是黑色的,定义空这样的节点是红色的,而不是左右子树都为空的节点,空树本身也是红黑树

4.如果一个节点是红色的,那么他的孩子节点都是黑色的

5.从任意一个节点到叶子节点,经过的黑色节点是一样的

红黑树在查找的时候时间复杂度不如平衡二叉树,虽然都是logn级别,但是红黑树在构造的时候,高度比平衡二叉树高,所以红黑树的适用场景是增删比较多的情况

 

6.hashtable和hashmap的区别

  1. HashMap是线程不安全的,HashTable实线程安全的 HashMap的效率比HashTable高 。HashTable是synchronize,多个线程访问时,不需要自己为他的方法实现同步,而HashMap需要自己为他的方法实现同步
  2. HashMap允许值为null(key和value都可以为null),HashTable不允许值为null,(key和value的值)
  3. HashMap的迭代器iterator是fail-fast机制的,而HashTable的迭代时enumeration机制的
  4. [HashTable继承自Dictionary接口且实现了接口,而HashMap继承自AbstractMap且实现了map接口] dictionary是和map结构类似,但是过时了
  5. Hashtable不要求底层数组的容量一定是2的整数次幂,而HashMap要求一定是2的整数次幂
  6. HashTable扩容时将容量扩展为原来的2倍加1,而HashMap扩容时将容量扩展为原来的2倍

7.方法的重载和重写的区别

方法的重载和重写都是实现多态的方式,前者实现的是编译时的多态性,而后者实现的是运行时的多态性。重载指的是一个类中具有多个功能相似的函数。重写是指子类继承了父类的方法并且覆盖了子类的方法。

方法重载的规则:

  1. 方法名一致,参数列表中的顺序,类型,个数不同
  2. 重载的方法与返回值无关
  3. 重载可以抛出不同的异常,可以有不同的修饰符

方法重写的命名规则

  1. 参数列表必须与被重写的方法一致,返回值类型必须相同
  2. 构造方法不能被重写,声明为final的方法不能被重写,声明为static的方法不能被重写,但是可以被重新声明
  3. 访问权限不能比父类中的方法权限更低
  4. 重写的方法不能抛出比父类更多的异常。因为子类可以解决父类的一些问题,而不能比父类有更多的问题。

8.面向对象的三大特性

封装继承和多态,重载和重写是实现多态的形式(这个面试官没有让详细说)

9.继承的实现两种方式(继承类和实现接口)

继承类,和接口两种方式

10.抽象类和接口的区别

  1. 从抽象的角度来看,类是对对象的抽象,抽象类是对类的抽象,接口是对行为的抽象
  2. 从适用的场景来看,如果行为跨越不同的类,可以使用接口,对于一些相似的类对象,让其继承抽象类
  3. 从设计角度来看,抽象类是从子类中发现了不同的东西,泛化出父类,然后子类继承父类,接口是不知道子类的实现,方法如何实现还不确定,预先定义
  4. 从表象上来看:
  1. 抽象类中可以有方法的实现,接口中不能有方法的实现
  2. 抽象类可以有构造方法,接口不能有构造方法
  3. 抽象类可以有不同的访问权限修饰符,接口的方法权限修饰符是public
  4. 抽象类继承用extends,接口用implements
  5. 一个类可以继承一个抽象类和多个抽象方法

相同点:

  1. 都不能实例化
  2. 都可以作为引用类型
  3. 一个类如果继承了某个抽象类,或者实现了某个接口,都需要实现其中的全部抽象方法。

11.tcp三次握手四次挥手,网络层有什么协议,OSI七层模型

Tcp的三次握手

  1. 第一次握手: 建立连接。客户端发送连接请求报文段,将SYN置为1,Seq为X,客户端进入SYN_SEND状态,等待服务器的确认
  2. 第二次握手: 服务器收到客户端的SYN报文段,需要对这个SYN报文段进行确认,设置ACK为x+1(seq+1),同时,自己还要发哦送SYN请求信息,将SYN位置为1,seq为y,服务器端将所有信息放到一个报文段(即SYN+ACK报文段)中,一并发送给客户端,此时服务器进入SYN_RECV状态
  3. 第三次握手:客户端收到服务器的SYN+ACK报文段,然后将ACK置为y+1,向服务器发送ACK报文段,这个报文段发送完毕后,客户端和服务器端都进入ESTABLISHED状态,完成TCP三次握手

TCP四次挥手

(1)第一次挥手:Client 发送一个 FIN,用来关闭 Client 到 Server 的数据传送,Client进入 FIN_WAIT_1 状态。

(2)第二次挥手:此时服务器端可能还要给客户端传送数据,不能急着关闭。Server 收到 FIN 后,发送一个 ACK 给 Client,确认序号为收到序号 seq+1(与 SYN 相同,一个FIN 占用一个序号),Server 进入 CLOSE_WAIT 状态。

(3)第三次挥手:服务器端数据传送完成之后,Server 发送一个 FIN,用来关闭 Server到 Client 的数据传送,Server 进入 LAST_ACK 状态。

(4)第四次挥手:Client 收到 FIN 后,Client 进入 TIME_WAIT 状态,接着发送一个ACK 给 Server,确认序号为收到序号+1,Server 进入 CLOSED 状态,完成四次挥手。

网络层的协议有IP协议,(TCP协议是传输层的)

应用层  表示层  会话层  传输层 网络层  传输链路层 物理层 

12.数据库隔离级别

串行化: 可避免脏读,不可重复读,幻读的发生

可重复读  可避免脏读不可重复读的发生

读已提交 可避免脏读的发生

读未提交  最低级别,可以避免数据的丢失

13.sql优化

  1. 应尽量避免全表扫描,在where及order by涉及的列上建立的索引。加快查询速度
  2. 应尽量避免在where字段中对字段进行null值判断,否则放弃使用索引进行全表扫描

Select id from t where num is null

可以在num在设置默认值0,确保表中num列没有null值

意思就是设置为0也不要设置成为nul

  1. 用exist代替in,exist跟索引有关
  2. 用varchar代替char,因为首先变长字段存储空间小,可以节省存储空间,查询效率高
  3. 不要使用select * from t用具体的字段列表来代替”*”,
  4. 尽量避免向客户端返回大数据量,用limit进行分页
  5. 用in来代替or
  6. Like双百分号无法使用索引
  7. 批量insert插入
  8. 使用连接来代替子查询,子查询会建立一个临时的表
  9. 在建立有索引的字段上不要使用函数,这样会使得索引失效
  10. Exist使用的是外表较大的查询,in使用的是内表较大的查询
  11. 使用union会对查询的结果自动去重,并且按照默认的顺序进行排序

使用union all查询的结果包括重复值 不排序

14.innodb的特性以及和其它存储引擎的区别

两种存储引擎的大致区别表现在:

  1. InnoDB支持事务,MyISAM不支持,这一点非常重要。事务是一种高级的处理方式,如在一些列增删该中只要哪个出错还可以回滚还原,而MyISAM不可以
  2. MyISAM适合查询以及插入为主的应用,InnoDB适合频繁修改以及涉及到安全性较高的应用
  3. InnoDB支持外键,MyISAM不支持
  4. InnoDB支持行锁
  5. 清空整个表时,InnoDB是一行一行的删除,效率非常慢。MyISAM会重建表
  6. Mysql5.5.5以后,InnoDB是默认引擎
  7. InnoDB不支持全文索引
  8. 对于自增长的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中可以和其他字段一起建立联合索引

应用场景:
myisam适合做很多count计算,插入不频繁,查询非常频繁 ,没有事务

InnoDB适合可靠性要求较高,或者要求事务 表的更新和查询都相当频繁,并且行锁的机会比较大的情况。

15.mysql的主从分离原理,怎样解决主从复制慢的问题

型网站为了减轻服务器的压力,将读操作和写操作相分离

对于数据库的不停的连接,数据库会崩溃,造成数据库的数据丢失,后果不堪设想

读操作和写操作分别导入不同的服务器集群去实现

1、数据库层面的主从配置实现

2. 代码层面的读写分离实现[无需改动现有的代码]

主从同步如何工作

1. Master将对数据库的操作记录到二进制日志文件中,写入完成后,master通知存储引擎提交事务[Binary log]

2. slave将master的二进制文件拷入到自己的文件中[slave log]

3. sql thread的线程读取relay log中的日志,重做事务,使得slave中的数据与master的数据保持一致

 

主从复制慢可以减少主从同步的相隔时间

16.知道什么设计模式,详细说单例模式的实现方式

设计模式有...

单例模式https://mp.csdn.net/postedit/83001963

17.回溯算法的思想,代码怎么写

用回溯算法解决问题的一般步骤:

1、 针对所给问题,定义问题的解空间,它至少包含问题的一个(最优)解。

2 、确定易于搜索的解空间结构,使得能用回溯法方便地搜索整个解空间 。

3 、以深度优先的方式搜索解空间,并且在搜索过程中用剪枝函数避免无效搜索。

代码来源:http://www.cnblogs.com/hygeia/p/5812128.html

1: int a[n],i;
   2: 初始化数组a[];
   3: i = 1;
   4: while (i>0(有路可走)   and  (未达到目标))  // 还未回溯到头
   5: {
   6:     if(i > n)                                              // 搜索到叶结点
   7:     {   
   8:           搜索到一个解,输出;
   9:     }
  10:     else                                                   // 处理第i个元素
  11:     { 
  12:           a[i]第一个可能的值;
  13:           while(a[i]在不满足约束条件且在搜索空间内)
  14:           {
  15:               a[i]下一个可能的值;
  16:           }
  17:           if(a[i]在搜索空间内)
  18:          {
  19:               标识占用的资源;
  20:               i = i+1;                              // 扩展下一个结点
  21:          }
  22:          else 
  23:         {
  24:               清理所占的状态空间;            // 回溯
  25:               i = i –1; 
  26:          }
  27: }

18.nginx的负载均衡算法的实现

  1. 轮询(默认)
  2. 加权weight
  3. Ip_hash
  4. Fair
  5. url_hash

19.stringbuilder和stringbuffer的区别,初始容量是多少

共同点:都继承与AbstractStringBuilder

  1. 可变不可变:string是常量,在修改时不会改变
  2. 执行速度: StringBuilder>StringBuffer>String
  3. 线程安全 stringBuider是线程不安全的,stringbuffer是线程安全的string类也是线程安全的

stringbuider的初始容量是:16

20string都有什么方法

indexOf,charAt,toLowerCase,toUpperCase,repalceOf,repalceAll,split,substring,trim,intern,concat,contains...

21jvm的内存模型volatile的特性,可以保证原子性吗

JMM决定一个线程对共享变量的写吐何时对另一个线程可见。线程之间的共享内存在主内存中,每个线程还有一个私有的本地内存,本地内存中存储了用于读写的共享变量的副本

A线程与B线程通信需要经过两个步骤

  1. 线程A把本地更新的共享变量刷新到主内存中
  2. 然后,线程B把从主内存中更新已被线程A更新过的共享变量读出来,更改自己的私有的内存变量

volatile保证了内存的可见性,和禁止指令重排序,不具备原子性

22.jvm的垃圾回收算法

标记清除,标记整理,复制,分代回收

标记清除法:
标记清除法包括两个阶段:”标记”和“清除”。在标记阶段,确定要回收的对象,并做标记。在清除阶段,紧随标记阶段,将标记阶段确定不可用的对象清除。标记清除算法是基础的收集算法,标记和清除阶段的效率不高,而且清除后产生大量的不连续空间,这样当程序需要分配大内存对象时,可能无法找到足够的连续空间。

复制算法

复制算法是把内存分成大小相等的两块,每次使用其中一块,当垃圾回收的时候,把存活的对象复制到另一块上,然后把这块内存整个清理掉。复制算法实现简单,但是由于每次只能使用其中的一半,造成内存的利用率不高。现在的jvm用复制方法收集新生代,由于新生代中大部分对象(98%)都是朝生夕死的,所有两块内存的比例不是1:1大概是8:1

标记整理算法

标记整理算法和标记清除算法一样,但是标记整理算法不是把存活对象复制到另外一块内存,而是把存活对象往内存的一端移动,然后直接回收便捷以外的内存。标记-整理算法提高了内存的利用率,并且它适合在收集对象存活时间较长的老年代

分代收集是根据对象的存活时间把内存分为新生代和老年代,根据各个对象的存活特点,每个代采用不同的垃圾回收算法,新生代采用复制算法,老年代采用标记整理算法,算法的实现设计大量的程序细节,而且不同的虚拟平台实现的方法也各不相同

GC的两次标记过程

在可达性分析后发现GC ROOTS没有任何引用链相连时,会被第一次标记,并且进行一次筛选,判断此对象是否有必要执行finalize()方法

如果没有必要执行该方法;[对象没有覆盖finalize方法,finalize方法已经被jvm调用过],这种情况就可以认为对象已死,可以回收

有必要执行该方法时

GC将对F-  queue队列中的对象进行第二次小规模的标记

Finalize()方法是对象逃脱死亡的最后一次机会

如果对象在其finalize()方法中重新与引用链上的任何一个对象建立关联,第二次标记时会将其移除即将回收的集合

如果对象没有,也可以认为对象已死,可以回收了

一个对象的finalize()方法只会被系统自动调用一次,经过finalize()方法逃脱死亡的对象,第二次不会再调用

23.数据库三范式

1NF:字段不可分 原子性,否则就不是关系数据库

2NF: 有主见,非主键字段依赖主键,唯一性一个表只说明一个事务

3NF:非主见字段不能相互依赖,每列都与主键有直接关系,不存在传递依赖

24.数据库慢查询怎么解决explain

分析Mysql语句查询性能的方法除了使用explain输出执行几行,还可以让MYsql记录下查询超过指定时间的语句,我们将超过指定时间的sql语句查询成为慢查询

记录慢查询的方法  查看慢查询的时间定义show varaiables like “long%”

使用explain表示查询sql语句,得到的结果的解释:

Id:select查询的序列号 若没有子查询和联合查询,id都是1,Mysql会按照id从大到小的顺序执行query,在相同的情况下,则从上到下执行

Select_type: select查询的类型(simple,primary,union)主要是区别普通查询和联合查询子查询之类的复杂查询

Table:输出的行所用的表

Type联合查询所使用的类型,从最好到最差

System.const,eq_ref,ref,fulltext,ref_or_null,index_merge,unqiue_subquery,index_sunsquery,range,index,all

Possible_keys在查询过程中可能用到的索引,如果为空,则没有相关的索引

Key:访问过程中实际用到的索引。如果没有索引被选择,键是NULL

Key_len:使用索引的长度。这个值可以得出一个多重主键里MYSQL实际使用了哪一部分

Ref:显示哪个字段或常数与key一起被使用

Rows返回请求数据的行数,在innodb上是不准确的

Extra附加说明

你可能感兴趣的:(面经)