Java SE面试题(1)

1. 请你说说Java和PHP的区别

  • PHP暂时还不支持像Java那样JIT运行时编译热点代码
  • PHP的库函数用C实现,而Java核心运行时类库(jdk/jre/lib/rt.jar,大于60MB)用Java编写(jdk/src.zip)
  • PHP内置模板引擎,自身就是模板语言.而Java Web需要使用JSP容器如Tomcat或第三方模板引擎
  • PHP也可以运行在多线程模式下,而Java多线程编程需要Java开发者编码参与.

2. 哈希表的存储过程

Java SE面试题(1)_第1张图片

3. 请你解释为什么重写equals还要重写hashcode?

HashMap中的比较key是这样的,先求出key的hashcode(),比较其值是否相等,若相等再比较equals(),若相等则认为他们是相等的。若equals()不相等则认为他们不相等。
如果只重写equals没有重写hashCode(),就会导致相同的key值也被hashcode认为是不同的key值(因为没有重写hashCode(),则任何对象的hashCode()值都不相等),就会在hashmap中存储相同的key值(map中key值不能相同),这就不符合条件了。

4. 你知道java8的新特性吗,请简单介绍一下

  • Lambda 表达式 − Lambda允许把函数作为一个方法的参数(函数作为参数传递进方法中。
  • 方法引用− 方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。
  • 默认方法− 默认方法就是一个在接口里面有了一个实现的方法。
  • 新工具− 新的编译工具,如: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应用。

5. 请你介绍一下map的分类和常见的情况

java为数据结构中的映射定义了一个接口java.util.Map;它有四个实现类,分别是HashMap Hashtable LinkedHashMap 和TreeMap.

  • Map主要用于存储健值对,根据键得到值,因此不允许键重复(重复了覆盖了),但允许值重复。
  • Hashmap 是一个最常用的Map,它根据键的HashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度,遍历时,取得数据的顺序是完全随机的。 HashMap最多只允许一条记录的键为Null;允许多条记录的值为 Null;HashMap不支持线程的同步,即任一时刻可以有多个线程同时写HashMap;可能会导致数据的不一致。如果需要同步,可以用 Collections的synchronizedMap方法使HashMap具有同步的能力,或者使用ConcurrentHashMap。
  • Hashtable与 HashMap类似,它继承自Dictionary类,不同的是:它不允许记录的键或者值为空;它支持线程的同步,即任一时刻只有一个线程能写Hashtable,因此也导致了 Hashtable在写入时会比较慢。
  • LinkedHashMap 是HashMap的一个子类,保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的.也可以在构造时用带参数,按照应用次数排序。在遍历的时候会比HashMap慢,不过有种情况例外,当HashMap容量很大,实际数据较少时,遍历起来可能会比 LinkedHashMap慢,因为LinkedHashMap的遍历速度只和实际数据有关,和容量无关,而HashMap的遍历速度和他的容量有关。
  • TreeMap实现SortMap接口,能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用Iterator 遍历TreeMap时,得到的记录是排过序的。
  • 一般情况下,我们用的最多的是HashMap,在Map 中插入、删除和定位元素,HashMap 是最好的选择。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。如果需要输出的顺序和输入的相同,那么用LinkedHashMap 可以实现,它还可以按读取顺序来排列.

6. 请你谈谈关于Synchronized和lock

synchronized是Java的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。JDK1.5以后引入了自旋锁、锁粗化、轻量级锁,偏向锁来有优化关键字的性能。

Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现;synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;Lock可以让等待锁线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。

7. 请你介绍一下volatile?

volatile关键字是用来保证有序性和可见性的。这跟Java内存模型有关。比如我们所写的代码,不一定是按照我们自己书写的顺序来执行的,编译器会做重排序,CPU也会做重排序的,这样的重排序是为了减少流水线的阻塞的,引起流水阻塞,比如数据相关性,提高CPU的执行效率。需要有一定的顺序和规则来保证,不然程序员自己写的代码都不知带对不对了,所以有happens-before规则,其中有条就是volatile变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作;有序性实现的是通过插入内存屏障来保证的。可见性:首先Java内存模型分为,主内存,工作内存。比如线程A从主内存把变量从主内存读到了自己的工作内存中,做了加1的操作,但是此时没有将i的最新值刷新会主内存中,线程B此时读到的还是i的旧值。加了volatile关键字的代码生成的汇编代码发现,会多出一个lock前缀指令。Lock指令对Intel平台的CPU,早期是锁总线,这样代价太高了,后面提出了缓存一致性协议,MESI,来保证了多核之间数据不一致性问题。

8. 请解释hashCode()和equals()方法有什么联系?

Java对象的eqauls方法和hashCode方法是这样规定的:

  1. 相等(相同)的对象必须具有相等的哈希码(或者散列码)。
  2. 如果两个对象的hashCode相同,它们并不一定相同。

9. 请简单描述一下JVM加载class文件的原理是什么?

Java中的所有类,都需要由类加载器装载到JVM中才能运行。类加载器本身也是一个类,而它的工作就是把class文件从硬盘读取到内存中。

类装载方式,有两种
(1)隐式装载,程序在运行过程中当碰到通过new 等方式生成对象时,隐式调用类装载器加载对应的类到jvm中,
(2)显式装载,通过class.forname()等方法,显式加载需要的类 ,隐式加载与显式加载的区别:两者本质是一样的。

Java类的加载是动态的,它并不会一次性将所有类全部加载后再运行,而是保证程序运行的基础类(像是基类)完全加载到jvm中,至于其他类,则在需要的时候才加载。这当然就是为了节省内存开销。

10. 请你讲讲Java里面的final关键字是怎么用的?

当用final修饰一个类时,表明这个类不能被继承。也就是说,如果一个类你永远不会让他被继承,就可以用final进行修饰。final类中的成员变量可以根据需要设为final,但是要注意final类中的所有成员方法都会被隐式地指定为final方法。

11. 请说明如何通过反射获取和设置对象私有字段的值?

可以通过类对象的getDeclaredField()方法字段(Field)对象,然后再通过字段对象的setAccessible(true)将其设置为可以访问,接下来就可以通过get/set方法来获取/设置字段的值了。

package cn.itcast.demo;

import java.lang.reflect.Constructor;

/*
 * 反射获取私有的构造方法运行
 * 不推荐,破坏了程序的封装性,安全性
 * 暴力反射
 */
public class ReflectDemo4 {

    public static void main(String[] args) throws Exception {
        Class c=Class.forName("cn.itcast.demo.Person");
        Constructor con=c.getDeclaredConstructor(int.class,String.class);
        //Constructor类,父类AccessibleObject,定义方法setAccessible(boolean b)
        con.setAccessible(true);
        Object obj=con.newInstance(18,"李四");
        System.out.println(obj);
    }

}

12. 请说明内部类可以引用他包含类的成员吗,如果可以,有没有什么限制吗?

  • 内部类如果不是static的,那么它可以访问创建它的外部类的所有属性,内部类如果是static的,那么它只可以访问创建它的外部类对象的所有static属性。
  • 一般普通类只有public或package的访问修饰,而内部类可以实现static,protected,private等修饰。
  • 当从外部类继承的时候,内部类是不会被覆盖的,它们是完成独立的实体,每个都在自己的命名空间内,如果内部类中明确的继承,就可以覆盖原来内部类的方法。

13. 请你说说Static Nested Class 和 Inner Class的不同

  1. 静态内部类可以有静态成员(方法,属性),而非静态内部类则不能有静态成员(方法,属性)。

  2. 静态内部类只能访问外部类的静态成员,而非静态内部类可以访问外部类的所有成员(方法,属性)。

  3. 实例化一个非静态的内部类的方法:

    a. 先生成一个外部类对象实例。

    OutClassTest oc1 = new OutClassTest();

    b. 通过外部类对象实例生成内部类对象

    OutClassTest.InnerClass no_static_inner = oc1.new InnerClass();

  4. 实例化一个静态内部类的的方法:

    a. 不依赖与外部类的实例,直接实例化内部类对象。

    OutClassTest.InnerStaticClass inner = new OutClassTest.InnerStaticClass();

    b. 调用内部静态类的方法或静态变量,通过类名直接调用

    OutClassTest.InnerStaticClass.static_value

    OutClassTest.innerStatic.getMessage()

你可能感兴趣的:(Java SE面试题(1))