京东面经学习----答案整理

1.[Java 基础] Java 中的==和equals区别

首先,==是运算符,equals方法是java.lang.Object类的方法。
== : 它的作⽤是判断两个对象的地址是不是相等。即,判断两个对象是不是同⼀个对象(基本数据类型:⽐较的是值,引⽤数据类型:⽐较的是内存地址)。
equals() : 它的作⽤也是判断两个对象是否相等。但它⼀般有两种使⽤情况:

  • 类没有覆盖 equals() ⽅法。则通过 equals() ⽐较该类的两个对象时,等价于通过“==”⽐较这两个对象。
  • 类覆盖了 equals() ⽅法。⼀般,我们都覆盖 equals() ⽅法来⽐较两个对象的内容是否相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)。

同时,String 中的 equals ⽅法是被重写过的,因为 object 的 equals ⽅法是⽐较的对象的内存地址,⽽ String 的 equals ⽅法⽐较的是对象的值。

2. [Java基础] hashmap 的实现原理、1.8 之后的改变

HashMap是我们非常常用的数据结构,由数组和链表组合构成的数据结构。
大概如下,数组里面每个地方都存了Key-Value这样的实例,在JDK1.7叫Entry,在Java1.8中叫Node。

先来说一下1.8之前的。

JDK1.8 之前 HashMap 底层是 数组和链表 结合在⼀起使⽤也就是 链表散列HashMap 通过keyhashCode 经过扰动函数处理过后得到 hash 值,然后通过 (n - 1) & hash 判断当前元素存放的位置(这⾥的 n 指的是数组的⻓度),如果当前位置存在元素的话,就判断该元素与要存⼊的元素的 hash 值以及 key 是否相同,如果相同的话,直接覆盖,不相同就通过拉链法解决冲突。

而所谓扰动函数指的就是 HashMap 的 hash ⽅法。使⽤ hash ⽅法也就是扰动函数是为了防⽌⼀些实现⽐较差的 hashCode() ⽅法。 换句话说使⽤扰动函数之后可以减少碰撞。

拉链法就是:将链表和数组相结合。也就是说创建⼀个链表数组,数组中每⼀格就是⼀个链表。若遇到哈希冲突,则将冲突的值加到链表中即可。

相⽐于之前的版本, JDK1.8 之后在解决哈希冲突时有了较⼤的变化,当链表⻓度⼤于阈值(默认为 8)(将链表转换成红⿊树前会判断,如果当前数组的⻓度⼩于 64,那么会选择先进⾏数组扩容,⽽不是转换为红⿊树)时,将链表转化为红⿊树,以减少搜索时间。

详见:阿里面试官没想到一个HashMap,我能跟他扯半小时

3. [Java 基础]接口和抽象类的区别

  1. 接⼝的⽅法默认是 public ,所有⽅法在接⼝中不能有实现(Java 8 开始接⼝⽅法可以有默认实现),⽽抽象类可以有⾮抽象的⽅法。
  2. 接⼝中除了 static 、 final 变量,不能有其他变量,⽽抽象类中则不⼀定。
  3. ⼀个类可以实现多个接⼝,但只能实现⼀个抽象类。接⼝⾃⼰本身可以通过 extends 关键字扩展多个接⼝。
  4. 接⼝⽅法默认修饰符是 public ,抽象⽅法可以有 public 、 protected 和 default 这些修饰符(抽象⽅法就是为了被重写所以不能使⽤ private 关键字修饰!)。
  5. 从设计层⾯来说,抽象是对类的抽象,是⼀种模板设计,⽽接⼝是对⾏为的抽象,是⼀种⾏为的规范。

详见:Java抽象类与接口详解

4. [Java 基础]可变长参数

Java1.5提供了一个叫varargs的新功能,就是可变长度的参数。

定义实参个数可变的方法:只要在一个形参的"类型"与"参数名"之间加上三个连续的"."(即"…",英文里的句中省略号),就可以让它和不确定个实参相匹配。

5. [Java 新特性] java8 有哪些新特性

Java8新特性:

  • Lambda表达式
  • 函数式接口
  • 方法引用与构造器引用
  • Stream API
  • 接口的默认方法与静态方法
  • 新时间日期API
  • 其他新特性

其中,引用最广泛的新特性是Lambda表达式和Stream API。

详见:Java8有哪些新特性?

6. [Java 多线程]介绍下ThreadLocal和使用场景

通常情况下,我们创建的变量是可以被任何⼀个线程访问并修改的。如果想实现每⼀个线程都有⾃⼰的专属本地变量就可以使用 ThreadLocal 类。
ThreadLocal 类主要解决的就是让每个线程绑定⾃⼰的值,可以将 ThreadLocal 类形象的⽐喻成存放数据的盒⼦,盒⼦中可以存储每个线程的私有数据。
如果创建了⼀个 ThreadLocal 变量,那么访问这个变量的每个线程都会有这个变量的本地副本,这也是 ThreadLocal 变量名的由来。他们可以使⽤ get和 set ⽅法来获取默认值或将其值更改为当前线程所存的副本的值,从⽽避免了线程安全问题。

详见:ThreadLocal 是什么?有哪些使用场景?

7. [JVM] jvm 优化工具

详见:https://blog.csdn.net/fd135/article/details/104286840

8. [设计模式]简单工厂和抽象工厂的区别

简单工厂模式对对象创建管理方式最为简单,因为其仅仅简单的对不同类对象的创建进行了一层薄薄的封装。该模式通过向工厂传递类型来指定要创建的对象。

所谓抽象工厂模式就是她提供一个接口,用于创建相关或者依赖对象的家族,而不需要明确指定具体类。

同时:
简单工厂模式
是由一个工厂对象创建产品实例,简单工厂模式的工厂类一般是使用静态方法,通过不同的参数的创建不同的对象实例。
可以生产结构中的任意产品,不能增加新的产品

抽象工厂模式
提供一个创建一系列相关或相互依赖对象的接口,而无需制定他们具体的类,生产多个系列产品。
生产不同产品族的全部产品,不能新增产品,可以新增产品族

详见:
设计模式之工厂模式(factory pattern)
设计模式总结

9. [设计模式]熟悉的设计模式有哪些

10. [设计模式]优化if-else方法

  1. 可以在if中提前return,减少else判断
  2. 使用三目运算符,从而放弃使用if-else
  3. 在用if-else判断某个对象是否为null时,可以用java8提供的Optional类
  4. 使用which-case或者枚举
  5. 表驱动法
    表驱动法是指我们可以将信息存在于表中,从表中取,而不必用if else逻辑去寻找,大可以将这里的“表”理解为一种容器。
    例如我们可以将每月的天数存在数组中,需要时,直接从数组中获取,而不是用if else输出。
  6. 策略模式+工厂模式

详见:【JAVA】优化if else的几种方式

11. [MySQL] MySQL 里行锁和表锁及其特性

mysql常用引擎有MYISAM和InnoDB,而InnoDB是mysql默认的引擎。MYISAM不支持行锁,而InnoDB支持行锁和表锁。
mysql的行锁是通过索引加载的,即是行锁是加在索引响应的行上的,要是对应的SQL语句没有走索引,则会全表扫描,行锁则无法实现,取而代之的是表锁。

表锁:不会出现死锁,发生锁冲突几率高,并发低。
行锁:会出现死锁,发生锁冲突几率低,并发高。

详见:
行锁与表锁详解
细谈数据库表锁和行锁

12. [MySQL] 介绍乐观锁、悲观锁、重入锁、排他锁

  • 悲观锁:认为数据随时会被修改,因此每次读取数据之前都会上锁,防止其它事务读取或修改数据;应用于数据更新比较频繁的场景;

  • 乐观锁:操作数据时不会上锁,但是更新时会判断在此期间有没有别的事务更新这个数据,若被更新过,则失败重试;适用于读多写少的场景。乐观锁的实现方式有:

    • 加一个版本号或者时间戳字段,每次数据更新时同时更新这个字段;
    • 先读取想要更新的字段或者所有字段,更新的时候比较一下,只有字段没有变化才进行更新
  • 排它锁(Exclusive Lock)/ X锁:事务对数据加上X锁时,只允许此事务读取和修改此数据,并且其它事务不能对该数据加任何锁;

  • 可重入锁:也叫递归锁,指的是同一线程外层函数获得锁之后,内层递归函数仍然有获取该锁的代码,但不受影响。

详见:关于乐观锁、悲观锁、可重入锁…

13. [算法题]递归实现单链表反转

猜你喜欢

转载自blog.csdn.net/qq_45884783/article/details/123125208