面试整理——Java基础

Java基础

一. 面向对象

问:面向对象的三大特性?分别是怎么使用的,给个例子?

答:封装,继承和多态。

比如类把属性和行为封装起来,只提供公共方法被外界访问。

比如父子类间的继承关系,子类继承父类的属性方法。

比如子类通过继承并重写父类方法,同样的方法会有不同的实现。

问:多态的原理是什么?

多态,常说的是运行时多态,在Java中主要实现的方式有:重写,接口和抽象方法。多态的底层实现是动态绑定,即在运行时才把方法调用与方法实现关联起来,通过方法表来实现,表中记录了类定义方法的指针,指向具体的方法代码,当类重写了父类方法,对应的表项就会指向新的代码实现,所以无论引用变量是父类还是子类,最终运行时都能执行正确的代码。

面向对象-多态

问:讲一下重载和重写?

答:重载是:同一类中,用相同的方法名,但参数个数或数据类型不同,返回值、访问修饰和抛出异常可以相同也可以不同,

重写则是:不同类中,子类继承父类方法,有相同的方法描述,但会受限于父类的访问修饰类型,且子类的访问修饰要更大。

第二节 数据类型

问:Java的基本类型有哪几个?各自占了多少位?一个char能放一个汉字吗?

答:8个,byte,short,int,long,float,double,boolean,char

byte是8位,short是16位,int是32位,long是64位,float是32位(单精度),double是64位(双精度),boolean是1位,char则是16位Unicode字符

可以,char是16位Unicode字符,一个汉字占两个字节,所以够放。

问:基本类型和包装类型的区别?涉及自动装箱和拆箱,怎么做的,原理?

答:基本类型有固定的存储空间,包装类则都是对象。对象存放在堆中,而基本类型存放在栈里。缺省值不同,基本类型根据类型有不同的缺省值,而包装类型则为null。

问:传值和传引用的区别?为什么说Java只有值传递?

首先什么是值传递和引用传递?首先这两个专有名词有其特指定义,属于函数调用时参数的求值策略,是对调用函数时,求值和传值方式的描述,而不是对传递内容类型的描述。

应该是根据是否会创建副本,以及是否会影响到原始对象来判断。值传递和引用传递是区分两种内存分配方式,值类型在调用栈上分配,引用类型在堆上分配。值传递会创建副本,无法在函数内改变原值。引用传递则不会创建副本,可以在函数内改变原值。

这些区别和参数类型是值类型或是引用类型无关,如果是值传递,不管是何种类型都会在调用栈上创建一个副本,区别在值类型的副本是原值的复制,引用类型的实例在堆上,在栈上只有它的引用,其副本是引用的复制。

根据值传递和引用传递的定义,Java中应该只有值传递。因为不管形参是哪种数据类型,最终传递给形参的都是实参的拷贝,函数对形参的赋值操作也不能被调用者感知。这种设计其实对应着求值策略中的传共享对象调用

问:货币用哪种数据类型?

答:BigDecimal,因为BigDecimal可以表示精确的浮点数。

双精度浮点型变量double可以处理16位有效数,但在实际应用中,可能需要对更大或者更小的数进行运算和处理。

一般情况下,对于那些不需要准确计算精度的数字,我们可以直接使用Float和Double处理,但是Double.valueOf(String) 和Float.valueOf(String)会丢失精度。所以开发中如果我们需要精确计算的结果,最好使用BigDecimal类来操作。

问:i++++i 的区别?

答:i++ 是先赋值再运算,++i 是先运算再赋值。

1
2
3
int i = 0, j = 0, k = 0;
j = i++; // j值为0,i为1
k = ++j; // k值为1,j为1

第三节 关键字

问:讲讲Java中用来描述作用域的修饰符?

作用域 当前类 同一package 子类 其他package非子类
public
protected ×
default × ×
private × × ×

问:assert?

断言机制主要用于调试,对一个布尔类型的表达式进行检查,正确的程序需要保证此表达式结果为true;若结果出现false表示程序出现异常。一般用来保证程序最基本关键部分的正确性,但为了性能等生产环境不会开启断言。

问:Java有哪几种移位运算符?

  • << :左移运算符。
  • >> :右移运算符。
  • >>> :无符号右移。

问:Switch 是否能作用在 Byte 上,是否能作用在 Long 上,是否能作用在 String 上 ?

switch(expr1) 中,expr1 是一个整数表达式。因此传递给 switch 和 case 语句的参数应该是 intshortchar 或者 bytelongString 都不能作用于 swtich。

问:谈谈 final, finally, finalize ?

  • final:修饰
  • finally:代码块,和try-catch组合使用,一般用来执行清除工作或缺省处理。
  • finalize:Object方法,用于在垃圾收集器将对象从内层中清除出去之前做一些必要的清理工作。垃圾收集器会确认对象是否已没有引用。

问:谈谈 static ?

  • 静态方法内不能调用非静态方法

第四节 字符串

问:String是不是java的基本类型?

答:不是,String是引用类型,虽然有常量的一些特性。

问:String为什么要是final类型的?

答:要保证字符串的不可变性,从而保证使用字符串时的安全高效。字符串常量池的设计采用享元模式,需要字符串的不可变性。假如字符串可变,共享元素在一处被改变,所有使用者都会感知到变化。如果字符串可变性会使软件安全性降低,不可变就意味着不会被篡改,同样也意味着线程安全。

问:String,StringBuffer,StringBuilder的区别?

答:String是字符串常量,不可变,之后有了针对线程安全的StringBuffer,但StringBuffer性能太差,实际使用也不能保证完全的安全。后来又有了非线程安全的StringBuilder用于频繁改变字符串的场景,同时将字符串拼接隐性的转换为StringBuilder。

问:字符串编码的区别?

答:字符串编码用固定的字节来表示一系列字符,常见的如ASCII,Unicode 和 UTF-8等。最早由美国制定的ASCII只包含常见的英文字母和数字等,后来各个国家制定了包含自家语言的编码格式如包含中文的GB2312等。多种标准的诞生也带来了各种冲突和乱码的现象,所以便催生出Unicode标准统一所有语言。

ASCII编码是1个字节,Unicode编码通常是2个字节。因此如果我们是纯英文文本使用Unicode就要多出一倍的存储空间,为了减少这种浪费,又出现了可变长编码:UTF-8。将一个Unicode字符根据不同的数字大小编码成1-6个字节,英文字母是1个字节,汉字则是3个字节。

UTF-8这种特性同时也使它兼容了ASCII编码,使得一些上了历史的软件也能在新的编码标准下工作。目前计算机内存中统一使用Unicode编码,当需要保存到硬盘或进行传输时就转换为UTF-8编码。

问:char 型变量中能不能存贮一个中文汉字?为什么?

答:String是字符串常量,不可变,之后有了针对线程安全的StringBuffer,但StringBuffer性能太差,实际使用也不能保证完全的安全。后来又有了非线程安全的StringBuilder用于频繁改变字符串的场景,同时将字符串拼接隐性的转换为StringBuilder。

问:简单描述String的原生方法intern?

String的intern()方法是一个 native原生方法,如果常量池中存在当前字符串,就会直接返回此字符串,若常量池没有,则先将字符串放入常量池内再返回。

字符串常量池是一个有固定大小的HashTable,所以当存入的字符串变多时就会导致哈希冲突,使链表过长,导致String.intern()性能大幅下降。可以通过参数 -XX:StringTableSize 指定常量池大小。

字符串常量池在Java 7版本前位于非堆区Perm Gen(永久代,HotSpot独有),后迁移到堆中,而Perm Gen在Java 8时被移除,其中的方法区移到了Metaspace(元空间),Metaspace不位于虚拟机内,而是使用本地内存,所以理论上最大可用空间是系统整个内存空间,将元数据剥离出Perm Gen提高GC效率,字符串与类元数据分开提升了独立性。

编译阶段字面量存入Class文件中的常量池表,当类在运行阶段被加载,常量池表会被加载到方法区,并将对应数据存放到运行时常量池。

问:创建字符串时的内部流程?两种字符串实例化方式在内存分配上有区别吗?

编译阶段字面量存放在Class文件的常量池表中,类加载阶段时将字符串字面量实例化,并驻留在字符串常量池中,执行阶段若遇到 new 关键字则需要在堆中实例化,并直接返回引用。

所以是有区别的,字符串常量赋值方式在类加载阶段就实现了实例化,并将字符串驻留在字符串常量池,而 new 实例化对象需要等到执行阶段,并不会和字符串常量池有关联。

第五节 类与接口

问:什么是泛型?

泛型,即参数化类型,把类型当作参数一样传递,使代码被不同的类型变量重用,提高代码利用率和整洁性。

泛型和类型擦除

问:Comparable 和 Comparator 接口是干什么的,其区别?

Comparable 是排序接口,表示实现类支持排序,就可以通过工具类Collections.sort或Arrays.sort等进行排序。

Comparator 则是比较器接口,实现类本身不支持排序,而是支持对另一个类进行排序的比较器。

Comparable实现类具有排序属性,相当于内部比较器。Comparator实现类就是一个比较类,相当于外部比较器。

问:接口和抽象类,你是怎么理解的?

从设计来讲接口是对动作的抽象,而抽象类是对根源的抽象。例如员工是抽象类,而部门经理、研发人员等是实现类,而员工的行为可以抽象为接口,如工作接口、休息接口、吃饭接口等。

从语法来讲,抽象被类继承、接口被类实现,抽象类可以没有抽象方法,但一旦有抽象方法就必须是抽象类,接口则默认声明方法是 public abstract ,而成员变量默认是 public static final 。继承只能单一继承,而实现可以实现多个,所以抽象类成本要比接口大,接口扩展性更强。

问:异常类?

throwable为父类,子为error跟exception,exception分runtime(空指针,越界等)跟checkexception(sql,io,找不到类等异常)

问:一般异常和运行时异常的区别?

问:Java中的异常处理机制?

通过面向对象的思想设计,将不同的异常分类,每种异常都可以抽象为一个对象,当方法出现异常时就会抛出一个对应的异常对象。可以对这个异常进行捕获和处理,一般通过 trycatchthrowthrowsfinally等关键字。

第六节 文件与流

问:说下如何操控文件?(输入输出)怎么关闭呢? 发生异常怎么办?

答:通过I/O流来对文件进行操作,为了确保流的关闭会在finally语句块中进行close,Java 7后增加了带资源的try语句,try块退出后会自动关闭资源。这样即使发生异常,也能确保不会因为流未关闭而造成内存泄漏或一直占用文件的情况。

IO流

问:讲讲你所知道的IO流?

  1. 根据传输的基本单位分为字节流字符流,字节流一般以Stream命名,字符流则以Reader/Writer命名。
  2. 字节流用来处理字节,字符流用来处理字节流不方便处理的Unicode格式(字节流一次只能操作一个字节)。
  3. 根据读出或写入一个字节序列可以把字节流分为输出流和输入流,流处理的对象可以是文件、网络连接或内存块。

问:讲讲字符流和字节流的区别?

  • 处理对象不同,虽然本质上计算机传输都是字节,但字符流提供了对Unicode的直接操作,字节流则只能处理字节。
  • 字节流操作时不会用到缓冲区,直接在文件操作,而字符流则会先在缓冲区上操作,在关闭时再强制性的把缓冲区内容输出,缓冲区其实就是一块特殊的内存区域,读取速度要远远高于读取磁盘的速度。
  • 字符流通过字节流来实现

NIO

问:知道NIO吗?对比IO简单谈一下?

NIO即New IO,在JDK 1.4时引入,二者有相同的作用但实现方式不同。NIO效率要比IO高很多。

IO主要包括类File,outputStream,inputStream,writer,reader,seralizable(5类1接口)

NIO三大核心内容 selector(选择器,用于监听channel),channel(通道),buffer(缓冲区)。NIO选择器允许一个单独的线程监视多个输入通道。

IO是面向流设计,NIO则面向缓冲。因为IO面向流,所以意味着每次直接从流读取字节直到读取完毕。NIO因为面向缓冲,可以将缓冲区的数据任意移动位置。

IO属于阻塞式IO,NIO则属于非阻塞式IO。IO的流是阻塞的,这意味着当一个线程读写数据时,此线程不能同时处理其他事情。而NIO会让线程从通道获取当前可用的数据,当数据还未能读取或写入前,线程可以去做其他事情。线程通常会将在非阻塞式IO上的空闲时间用于去其他通道执行IO操作,所以一个线程可以管理多个输入和输出通道。

问:如何理解同步异步?阻塞与非阻塞?

理解这些概念要结合相应的语境,一般主要在进程通信或I/O系统调用方面讨论这些概念。

进程通信:进程间通信由send()和receive()两种动作完成,消息的传递可能是阻塞非阻塞的,也可以叫做同步异步的,此处二者指相同概念

可以根据和发送或接收的组合分为以下四种方式。

  • 阻塞式发送(blocking send):发送方进程会被一直阻塞, 直到消息被接受方进程收到。
  • 非阻塞式发送(nonblocking send): 发送方进程调用 send() 后, 立即就可以其他操作。
  • 阻塞式接收(blocking receive):接收方调用 receive() 后一直阻塞, 直到消息到达可用。
  • 非阻塞式接受(nonblocking receive): 接收方调用 receive() 函数后, 要么得到一个有效的结果,要么得到一个空值, 即不会被阻塞。

阻塞是指进程在发起一个系统调用(System Call)后,等待调用操作完成时,内核将进程挂起为等待(waiting)状态,以确保它此时不会被调度执行。

完整的IO操作包括两个阶段:1.查看数据是否就绪;2.进行数据拷贝,内核将数据拷贝到用户线程。

I/O System Call:阻塞与系统调用紧密相关,现代计算机中物理通信操作通常是异步的,而操作系统则默认提供阻塞式的I/O系统调用接口(blocking systemcall),这样使应用代码编写更简单(代码执行顺序与编写顺序一致)。当然也会提供非阻塞式的I/O系统调用接口(nonblocking systemcall),不会挂起程序,而是立刻返回一个值。

同步异步主要针对用户线程和内核交互。

  • 阻塞式I/O系统调用:进程发起系统调用后挂起,直到调用操作完成。
  • 非阻塞式I/O系统调用:进程发起系统调用后立刻返回一个值,而不会挂起。
  • 同步I/O系统调用:用户线程发起I/O请求后,用户线程或内核不断轮询数据是否就绪,就绪后将数据从内核拷贝回用户线程。
  • 异步I/O系统调用:用户线程发起I/O请求,之后都由内核完成,完成后通知用户线程。与非阻塞式的I/O系统调用类似的是,二者不会等待I/O操作完成,应用程序可以继续执行其他操作,待I/O完成时操作系统通知调用进程。二者的区别是非阻塞会立即返回数据(无论数据是否完整),而异步则要求结果是完整的,允许延迟获取。

解答来源:怎样理解阻塞非阻塞与同步异步的区别?萧萧

问:同步I/O和异步I/O的区别?

  • 同步IO用户线程会阻塞,数据拷贝阶段由用户线程完成。
  • 异步IO用户线程不会阻塞,数据拷贝阶段由内核完成,且会延迟等待完整结果。

I/O模型

问:谈谈5种IO模型?

5种IO模型分别为:阻塞IO、非阻塞IO、多路复用IO、信号驱动IO、异步IO。

一个完整的IO操作包括两个阶段:查看数据是否就绪,进行数据拷贝。

前四种都是同步IO,只有异步IO是真正的异步式IO,因为前四种都至少会在IO操作的第二个阶段使用户线程阻塞,且前四种只有第一阶段不同,第二阶段都是阻塞拷贝。

  • 阻塞IO即读写操作都需要等待;
  • 非阻塞IO则是当数据未就绪时返回一个错误信息,用户线程持续轮询;
  • 多路复用IO一个线程可以管理多个socket,同时检测多个资源,但线程会阻塞直到有资源可用,轮询也是通过内核而非用户线程执行;
  • 信号驱动IO在数据未就绪时不会阻塞,等接收到就绪信号时再通过信号函数调用IO读写操作;
  • 异步IO则是内核发送信号之前就自行将数据拷贝到用户线程,最后信号表示IO操作已完成。

问:什么是I/O多路复用?相比非阻塞I/O为何效率更高?

线程不断的轮询多个Socket的状态,当有可用的Socket后再调用I/O读写操作。多个Socket只需一个线程管理,只有真正进行读写操作时才会使用IO资源。

效率高的原因是非阻塞的轮询由用户线程来做,而多路复用由内核来轮询Socket状态,用户线程处于阻塞状态。

第七节 其它

问:谈下equals和==的区别?equals和hashcode的用法及区别?为什么重写equals方法时还要重写hashcode方法?

hashcode方法用于创建散列表时获取对象的哈希码值,equals则用于对象的等值判断。

equals相等则hashcode必定相等,hashcode相等equals未必相等。前者是散列表取值时需要先判断hashcode(hashcode比较效率较高),所以只有hashcode相等才能取到正确的值。哈希值相等的两个对象未必是相等的(哈希冲突),因为哈希码并不是百分百可靠。

重写equals方法时还要重写hashcode方法是因为,重写equals后很可能导致equals相等时hashcode却不相同,会在许多散列表的使用场景下出错(Set或HashMap取值),所以重写equals时也要重写hashcode。

equals和hashCode异同

问:为什么Java不允许静态方法访问非静态变量?

因为非静态变量需要关联一个实例化对象,这与静态的设计相违背。

问:讲讲序列化?

Java通过序列化把对象写入和读出流,也就是转为字节序列,方便在网络中传输或者传递对象。Java序列化基于两个接口:Serializable和Externalizable,Serializable接口有默认序列化机制。序列化也可以用来实现深拷贝。

对象流和序列化

问:深拷贝与浅拷贝?

深拷贝和浅拷贝主要区别在是否支持引用类型的拷贝,浅拷贝对于可变对象无法保证数据安全,深拷贝会把对象里面嵌套对象这种结构完整的拷贝下来。

Java对象克隆

问:反射的原理,怎么确定类,怎么调方法?

反射即动态加载对象,并对对象进行剖析,也就是在运行时分析类(如泛型会在编译后擦除,通过反射可以获取泛型信息)。对于类,反射可以获取类的完整信息,对于对象可以调用任意属性和方法。

获取类的字节码对象(Class)可以通过object.getClass()、Object.class、Class.forName(“xxx”)三种方法。

通过 getDeclaredMethods() 方法获得类的所有方法, getDeclaredMethod(String) 方法获取指定方法名的方法,并通过 Method对象.invoke() 调用此方法。

问:如何通过反射和设置对象私有字段的值?

首先使用反射提供的setAccessible(true),使我们可以访问到非public的变量。然后使用反射提供的getDeclaredFields()方法获取某个类的所有声明字段或getDeclaredField()方法获取指定字段。

问:动态代理?

什么是动态代理?指代理类在运行时创建,而非编译阶段生成的代理模式。解决了静态代理存在的代码冗余等问题,动态生成代理对象,用完即销毁。核心是Proxy和InvocationHandler。

动态代理步骤:

  1. 获取 RealSubject上的所有接口列表;
  2. 确定要生成的代理类的类名,默认为:com.sun.proxy.$ProxyXXXX
  3. 根据需要实现的接口信息,在代码中动态创建该 Proxy 类的字节码;
  4. 将对应的字节码转换为对应的 Class 对象;
  5. 创建 InvocationHandler 实例 handler,用来处理 Proxy 所有方法调用;
  6. ProxyClass 对象以创建的 handler 对象为参数,实例化一个 proxy 对象。

代理类命名格式固定,一旦在运行中创建则和普通类无异。代理类都继承自Proxy类,通过实现接口的方式来实现代理。

问:为什么JDK动态代理只能代理接口?

因为JDK动态代理创建代理对象需要继承标准类库中的 Proxy 类,且Java遵守单继承多实现,所以JDK只能通过实现来代理接口。

问:Spring中AOP的实现采用那种代理方式?

Spring虽然采用了AspectJ的标准注解,但未采用其静态代理的模式(特定的编译器和语法在编译阶段实现代理),而是动态代理。

其支持的动态代理实现方式有两种:JDK动态代理和CGLib,Spring会默认使用JDK动态代理,当目标对象非接口时会强制转换为CGLib。Spring Boot则在2.x版本后默认使用CGlib(理由是相比JDK动态代理更少出现转换问题)。

问:有人说jdk动态代理性能比cglib要差,如果是,依据是什么?

这应该是一个过时的问题,在JDK 1.8之前的版本或许JDK动态代理生成的代理类运行效率要弱于CGLib,但之后的版本应该是JDK动态代理要更强一些。

过去较差的原因,目前还未深究过,简单的推测是因为基于接口的实现要多一部分开销?TODO

问:Java中的事件机制?

java 事件机制包括三个部分:事件事件监听器事件源

  • 事件:一般继承自 java.util.EventObject 类,封装了事件源对象及跟事件相关的信息。
  • 事件监听器:实现 java.util.EventListener 接口,注册在事件源上,当事件源的属性或状态改变时,取得相应的监听器调用其内部的回调方法
  • 事件源:事件发生的地方,由于事件源的某项属性或状态发生了改变(比如 BUTTON 被单击、TEXTBOX 的值发生改变等等)导致某项事件发生。换句话说就是生成了相应的事件对象。因为事件监听器要注册在事件源上,所以事件源类中应该要有盛装监听器的容器(List,Set 等等)。

第八节 设计模式

问:项目中有使用过哪些设计模式?

  • 模板方法模式:
  • 单例模式:
  • 工厂模式:
  • 观察者模式:
  • 适配器模式:
  • 代理模式:
  • 策略模式:

问: JDK 中几个常见的设计模式?

  • 单例模式:用于 Runtime,Calendar 和其他的一些类中。
  • 工厂模式:被用于各种不可变的类如 Boolean,像 Boolean.valueOf。
  • 观察者模式:被用于 Swing 和很多的事件监听中。
  • 装饰器模式: 被用于 Java IO 中的各种字节和字符流,InputStream和XXInputStream,如BufferedReader和BufferedWriter,增强了 Reader和Writer,通过Buffer读写提高性能。

问: Spring 中用了哪些设计模式?

  • 简单工厂模式:如BeanFactory等。
  • 工厂模式:AbstractFactoryBean
  • 单例模式:
  • 适配器模式:
  • 包装区模式:
  • 代理模式:
  • 观察者模式:
  • 策略模式:
  • 模板方法模式:

问:生产者消费者模式?要求手写出代码

问:手写出线程安全的单例模式?

问:设计模式中常见原则知道一些吗?

  • 单一职责原则每个类只能有单一的功能。当类职责过多时,一个职责的变化就会影响或抑制到完成其它职责的能力。
  • 开放-封闭原则软件中的实体(如类、函数)支持扩展,不支持修改。Open for extension,Closed for modification。当面对需要变化时,更应该通过新增代码,而不是修改现有代码来完成。从而保证可维护、可扩展、可复用和高灵活性。开发人员应该对程序中呈现出频繁变化的部分做出抽象。在实际开发中,将抽象层和实现层分离,不修改抽象,只处理实现。
  • 里氏代换原则子类型必须能够替换掉它们的父类型。只有这样才能保证父类被复用,而子类可以在父类基础上
  • 依赖倒转原则:
  • 迪米特法则也叫最少知识原则,一个类应当对其它类尽可能少去了解。其实就是类尽量不把与别的类的交互放在内部函数中,尽量放在第三方类处理;类尽量将成员变量和方法设为私有。从而降低类之间耦合,提高复用。

第九节 JDK 8 新特性

问:java8有了解吗?

有了解,Lambda表达式,函数式编程,流这些都有用过,也整理过相关内容如下。

Java8的新特性

问:讲讲Lambda表达式?使用场景?优点?

java也开始承认了函数式编程, 就是说函数既可以作为参数,也可以作为返回值, 大大的简化了代码的开发

解决了Java无法传递代码段的问题,可以用在一些频繁被多处使用的代码段或者说策略,通过行为参数化可以更高效的进行开发,提高代码简洁性。

问:谈谈流?和集合对比?

流是为了在一些如需要进行复杂计算以及多核的场景下代替集合而设计的,集合的主要目的是为了存储和访问数据,而流则是主要用于描述对数据的计算。

相较于集合,流采用了更高级的语言表达,流水线的结构可以减少遍历,自动的并行化流操作可以有效利用多核性能。

问:default关键字 ?

打破接口里面是只能有抽象方法,不能有任何方法的实现,接口里面也可以有方法的实现了

问:新时间日期APILocalDate | LocalTime | LocalDateTime ?

之前使用的java.util.Date月份从0开始,我们一般会+1使用,很不方便,java.time.LocalDate月份和星期都改成了enum java.util.Date和SimpleDateFormat都不是线程安全的,而LocalDate和LocalTime和最基本的String一样,是不变类型,不但线程安全,而且不能修改。 新接口更好用的原因是考虑到了日期时间的操作,经常发生往前推或往后推几天的情况。用java.util.Date配合Calendar要写好多代码,而且一般的开发人员还不一定能写对。

问:JDK1.7与JDK1.8 ConcurrentHashMap对比 ?

(1):JDK1.7版本的ReentrantLock+Segment+HashEntry(数组)

(2):JDK1.7采用segment的分段锁机制实现线程安全

(3):JDK1.8版本中synchronized+CAS+HashEntry(数组)+红黑树

(4):JDK1.8采用CAS+Synchronized保证线程安全

(5):查询时间复杂度从原来的遍历链表O(n),变成遍历红黑树O(logN)

1.8 HashMap数组+链表+红黑树来实现hashmap,当碰撞的元素个数大于8时 & 总容量大于64,会有红黑树的引入 除了添加之后,效率都比链表高,1.8之后链表新进元素加到末尾

问:JDK1.8使用synchronized来代替重入锁ReentrantLock ?

(1):因为粒度降低了,在相对而言的低粒度加锁方式,synchronized并不比ReentrantLock差

(2):基于JVM的synchronized优化空间更大

(3):在大数据量下,基于API的ReentrantLock会比基于JVM的内存压力开销更多的内存

第十节 JDK 9 新特性

问:模块系统 ?

模块是一个包的容器,Java 9 最大的变化之一是引入了模块系统(Jigsaw 项目)。

问:集合工厂方法 ?

通常,您希望在代码中创建一个集合(例如,List 或 Set ),并直接用一些元素填充它。 实例化集合,几个 “add” 调用,使得代码重复。 Java 9,添加了几种集合工厂方法:

1
2
Set<Integer> ints = Set.of(123);
List<String> strings = List.of("first""second");

问:改进的 Stream API ?

Stream 接口中添加了 4 个新的方法:dropWhile, takeWhile, ofNullable。还有个 iterate 方法的新重载方法

问:改进的 Javadoc ?

Javadoc 现在支持在 API 文档中的进行搜索。另外,Javadoc 的输出现在符合兼容 HTML5 标准。

redis代理集群模式,spring有哪些注解,b+b 红黑树区别,三次握手,valitile重排序底层代码, cas 事务的4个特性,java8 java11 特性, filter和interceptor的区别 @autowired原理, dispatcherservlet,分布式事务解决方案spring都有哪些模块,fork join队列,排序算法,