面试涉及问题含有:
Java
JDK8新特性
集合(哈希冲突、HashMap的原理、自动排序的集合TreeSet)
多线程安全问题
String和StringBuffer
JVM
原理、运行流程、内部结构
Linux
查询含有某字符串内容的命令grep
查询进程、GC状态、杀死进程
Hadoop五种节点介绍
--------------------------------------------------------------------------------------------------------
JAVA:
1、JDK8新特性:
Lambda 表达式(闭包)− Lambda允许把函数作为一个方法的参数,函数作为参数传递进方法中。
lambda表达式的重要特征:
可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。
Lambda的设计 可以实现简洁而紧凑的语言结构。最简单的Lambda表达式可 由逗号分隔的参数列表、->符号和语句块 组成,例如:
Arrays.asList("a","b","d").forEach( e ->System.out.println( e ) );Arrays.asList("a","b","d").forEach( ( String e ) -> System.out.println( e ) );Arrays.asList("a","b","d").forEach( e -> { System.out.print( e ); System.out.print( e );} );Stringseparator= ",";Arrays.asList("a","b","d").forEach( ( String e ) -> System.out.print( e + separator ) );Arrays.asList("a","b","d").sort( ( e1, e2 ) -> e1.compareTo( e2 ) );等同于Arrays.asList("a","b","d").sort( ( e1, e2 ) -> { int result = e1.compareTo( e2 );returnresult;} );
方法引用− 方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。
方法引用通过方法的名字来指向一个方法。
方法引用可以使语言的构造更紧凑简洁,减少冗余代码。
方法引用使用一对冒号 :: 。
Java8使用两个新概念扩展了接口的含义:默认方法和静态方法。默认方法使得接口有点类似traits,不过要实现的目标不一样。默认方法使得开发者可以在 不破坏二进制兼容性的前提下,往现存接口中添加新的方法,即不强制那些实现了该接口的类也同时实现这个新加的方法。默认方法和抽象方法之间的区别在于抽象方法需要实现,而默认方法不需要。接口提供的默认方法会被接口的实现类继承或者覆写,例子代码如下:privateinterfaceDefaulable{defaultStringnotRequired(){return"Default implementation"; } }privatestaticclassDefaultableImplimplementsDefaulable{}privatestaticclassOverridableImplimplementsDefaulable{@OverridepublicStringnotRequired(){return"Overridden implementation"; }}Defaulable接口使用关键字default定义了一个默认方法notRequired()。DefaultableImpl类实现了这个接口,同时默认继承了这个接口中的默认方法;OverridableImpl类也实现了这个接口,但覆写了该接口的默认方法,并提供了一个不同的实现。Java8带来的另一个有趣的特性是在接口中可以定义静态方法,例子代码如下:privateinterfaceDefaulableFactory{// Interfaces now allow static methodsstaticDefaulablecreate( Supplier< Defaulable > supplier ){returnsupplier.get(); }}下面的代码片段整合了默认方法和静态方法的使用场景:publicstaticvoidmain( String[] args ){ Defaulable defaulable = DefaulableFactory.create( DefaultableImpl::new); System.out.println( defaulable.notRequired() ); defaulable = DefaulableFactory.create( OverridableImpl::new); System.out.println( defaulable.notRequired() );}输出结果如下:Default implementationOverridden implementation
默认方法− 默认方法就是一个在接口里面有了一个实现的方法。
privateinterfaceDefaulableFactory{// Interfaces now allow static methodsstaticDefaulablecreate( Supplier< Defaulable > supplier ){returnsupplier.get(); }}
新工具− 新的编译工具,如:Nashorn引擎 jjs、 类依赖分析器jdeps。
Stream API−新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。
Date Time API− 加强对日期与时间的处理。
Optional 类− Optional 类已经成为 Java 8 类库的一部分,用来解决空指针异常。
Nashorn, JavaScript 引擎− Java 8提供了一个新的Nashorn javascript引擎,它允许我们在JVM上运行特定的javascript应用。
重复注解:
自从Java 5中引入 注解 以来,这个特性开始变得非常流行,并在各个框架和项目中被广泛使用。不过,注解有一个很大的限制是:在同一个地方不能多次使用同一个注解。Java 8打破了这个限制,引入了重复注解的概念,允许在同一个地方多次使用同一个注解。
在Java 8中使用@Repeatable注解定义重复注解,实际上,这并不是语言层面的改进,而是编译器做的一个trick,底层的技术仍然相同。可以利用下面的代码说明:
packagecom.javacodegeeks.java8.repeatable.annotations;importjava.lang.annotation.ElementType;importjava.lang.annotation.Repeatable;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.lang.annotation.Target;publicclassRepeatingAnnotations{@Target( ElementType.TYPE )@Retention( RetentionPolicy.RUNTIME )public@interfaceFilters { Filter[] value(); }@Target( ElementType.TYPE )@Retention( RetentionPolicy.RUNTIME )@Repeatable( Filters.class )public@interfaceFilter { String value(); };@Filter("filter1")@Filter("filter2")publicinterfaceFilterable{ }publicstatic void main(String[] args) {for( Filter filter: Filterable.class.getAnnotationsByType( Filter.class) ) { System.out.println( filter.value() ); } }}
正如我们所见,这里的Filter类使用@Repeatable(Filters.class)注解修饰,而Filters是存放Filter注解的容器,编译器尽量对开发者屏蔽这些细节。这样,Filterable接口可以用两个Filter注解注释(这里并没有提到任何关于Filters的信息)。
另外,反射API提供了一个新的方法:getAnnotationsByType(),可以返回某个类型的重复注解,例如 Filterable.class.getAnnoation(Filters.class) 将返回两个Filter实例,输出到控制台的内容如下所示: filter1 filter2
2、集合:
哈希冲突:
(见博客:https://www.cnblogs.com/wuchaodzxx/p/7396599.html)
如果两个不同的元素,通过哈希函数得出的实际存储地址相同怎么办?也就是说,当我们对某个元素进行哈希运算,得到一个存储地址,然后要进行插入的时候,发现已经被其他元素占用了,其实这就是所谓的哈希冲突,也叫哈希碰撞。
哈希函数的设计至关重要,好的哈希函数会尽可能地保证 计算简单和散列地址分布均匀,但是,我们需要清楚的是,数组是一块连续的固定长度的内存空间,再好的哈希函数也不能保证得到的存储地址绝对不发生冲突。那么哈希冲突如何解决呢? 哈希冲突的解决方案有多种: 开放定址法(发生冲突,继续寻找下一块未被占用的存储地址),再散列函数法,链地址法,而HashMap即是采用了链地址法,也就是数组+链表的方式。
(1)开放定址法
这种方法也称再散列法,其基本思想是:当关键字 key的哈希地址 p=H( key)出现冲突时,以 p为基础,产生另一个哈希地址 p1,如果 p1仍然冲突,再以 p为基础,产生另一个哈希地址p2, …,直到找出一个不冲突的哈希地址 pi ,将相应元素存入其中。这种方法有一个通用的再散列函数形式:
Hi=( H( key) +d i ) % m i=1, 2,…, n
其中 H( key)为哈希函数, m 为表长, d i 称为增量序列。增量序列的取值方式不同,相应的再散列方式也不同。主要有以下三种:
线性探测再散列
d i i=1, 2, 3, …, m-1
这种方法的特点是:冲突发生时,顺序查看表中下一单元,直到找出一个空单元或查遍全表。
二次探测再散列
作者:Java高级技术
链接:https://www.jianshu.com/p/0c8bb074165b