Java面试常问32

  1. 什么是Java虚拟机什么Java被称作是“平台无关的编程语言”br> 答:Java虚拟机是一个可以执行Java字节码的虚拟机进程,Java源文件被编译成能被Java虚拟机执行的字节码文件,
    因为Java被编译为字节码文件,由虚拟机解释执行,关于底层硬件平台的东西都由Java虚拟机掌握,真正的Java代码不需要知道,所以与其无关。

  2. Java接口中声明的变量默认是final的,抽象类可以包含非final变量。

  3. Java接口中的成员函数默认是public的,抽象类中的方法可以使四种权限修饰。

  4. 接口和抽象类都不可以被实例化。

  5. 在多线程os中,进程不是一个可执行的实体。

  6. 创建线程有四种方式:

  7. 继承Thread类

    • 实现Runnable接口
    • 使用Executor框架创建线程池
    • 实现Callable接口
  8. 同步方法和同步代码块的区别br> 答:同步方法默认使用this或当前类的class对象作为锁,
    同步代码块可以选择以什么来加锁,比同步方法更加细颗粒化,我们可以选择只在需要同步的代码段进行加锁,而不是整个方法,同步方法使用synchronize关键字进行加锁,而代码块主要是要修饰需要加锁的代码,用synchronize(object){代码内容进行修饰}。

  9. 在监视器(Monitor)内部,是如何做线程同步的序应该做哪种级别的同步br> 答:监视器和锁在Java虚拟机中是一块使用的。监视器监视一块同步代码 块,确保一次只有一个线程执行同步代码块。每一个监视器都和一个对象引 用相关联。线程在获取锁之前不允许执行同步代码。

  10. 如何确保N个线程可以访问N个资源同时又不导致死锁br> 答:使用多线程的时候,一种非常简单的避免死锁的方式就是:指定获取锁的顺序,并强制线程按照指定的顺序获取锁。因此,如果所有的线程都是以同样的顺序加锁和释放锁,就不会出现死锁了。

  11. 什么是迭代器(Iterator)br> 答:Iterator接口提供了很多对集合元素进行迭代的方法。每一个集合类都 包含了可以返回迭代器实例的
    迭代方法。迭代器可以在迭代的过程中删除底层集合的元素,但是不可以直 接调用集合的
    remove(Object Obj)删除,可以通过迭代器的remove()方法删除。
    原因:Iterator 被创建之后会建立一个指向原来对象的单链索引表,当原 来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指 针往后移动的时候就找不到要迭代的对象,所以按照 fail-fast 原则 Iterator 会马上抛出 java.util.ConcurrentModificationException 异 常。
    所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。
    但你可以使用 Iterator 本身的方法 remove() 来删除对象, Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。

  12. Iterator和ListIterator的区别是什么br> 答:1. Iterator可用来遍历Set和List集合,但是ListIterator只能用 来遍 历List。

  13. Iterator对集合只能是前向遍历,ListIterator既可以前向也可以后向。

  14. ListIterator实现了Iterator接口,并包含其他的功能,比如:增加元 素, 替换元素,获取前一个和后一个元素的索引,等等。

  15. 快速失败(fail-fast)和安全失败(fail-safe)的区别是什么br> 答:一:快速失败(fail—fast)
    在用迭代器遍历一个集合对象时,如果遍历过程中对集合对象的结构进行了修改(增加、删除),则会抛出Concurrent Modification Exception。
    原理:迭代器在遍历时直接访问集合中的内容,并且在遍历过程中使用一个 modCount 变量。集合在被遍历期间如果结构发生变化,就会改变modCount的值。每当迭代器使用hashNext()/next()遍历下一个元素之前,都会检测modCount变量是否为expectedmodCount值,是的话就返回遍历;否则抛出异常,终止遍历。
    注意:这里异常的抛出条件是检测到 modCount!=expectedmodCount 这个条件。如果集合发生变化时修改modCount值刚好又设置为了expectedmodCount值,则异常不会抛出。因此,不能依赖于这个异常是否抛出而进行并发操作的编程,这个异常只建议用于检测并发修改的bug。
    场景:java.util包下的集合类都是快速失败的,不能在多线程下发生并发修改(迭代过程中被修改)。
    二:安全失败(fail—safe)
    采用安全失败机制的集合容器,在遍历时不是直接在集合内容上访问的,而是先复制原有集合内容,在拷贝的集合上进行遍历。
    原理:由于迭代时是对原集合的拷贝进行遍历,所以在遍历过程中对原集合所作的修改并不能被迭代器检测到,所以不会触发Concurrent Modification Exception。
    缺点:基于拷贝内容的优点是避免了Concurrent Modification Exception,但同样地,迭代器并不能访问到修改后的内容,即:迭代器遍历的是开始遍历那一刻拿到的集合拷贝,在遍历期间原集合发生的修改迭代器是不知道的。
    场景:java.util.concurrent包下的容器都是安全失败,可以在多线程下并发使用,并发修改。

  16. Comparable和Comparator接口是干什么的出它们的区别br> 答:Comparable & Comparator 都是用来实现集合中元素的比较、排序的,只是 Comparable 是在集合内部定义的方法实现的排序,Comparator 是在集合外部实现的排序,所以,如想实现排序,就需要在集合外定义 Comparator 接口的方法或在集合内实现 Comparable 接口的方法。 Comparator位于包java.util下,而Comparable位于包 java.lang下 Comparable 是一个对象本身就已经支持自比较所需要实现的接口(如 String、Integer 自己就可以完成比较大小操作,已经实现了Comparable接口) 自定义的类要在加入list容器中后能够排序,可以实现Comparable接口,在用Collections类的sort方法排序时,如果不指定Comparator,那么就以自然顺序排序, 这里的自然顺序就是实现Comparable接口设定的排序方式。 而 Comparator 是一个专用的比较器,当这个对象不支持自比较或者自比较函数不能满足你的要求时,你可以写一个比较器来完成两个对象之间大小的比较。 可以说一个是自已完成比较,一个是外部程序实现比较的差别而已。 用 Comparator 是策略模式(strategy design pattern),就是不改变对象自身,而用一个策略对象(strategy object)来改变它的行为。 比如:你想对整数采用绝对值大小来排序,Integer 是不符合要求的,你不需要去修改 Integer 类(实际上你也不能这么做)去改变它的排序行为,只要使用一个实现了 Comparator 接口的对象来实现控制它的排序就行了。

  17. 什么是Java优先级队列(Priority Queue)br> 答:Java中的优先队列底层是一个小顶堆实现的,堆的结构只是在二叉树的基础上做了一些限制,优先队列是不安全的,没有实现同步,使用迭代器遍历的数据是没有经过排序的,只有当堆中元素一个一个弹出的时候才会在外部形成有序序列。

  18. Enumeration接口和Iterator接口的区别有哪些br> 答:Enumeration 是JDK 1.0添加的接口。使用到它的函数包括Vector、Hashtable等类,这些类都是JDK 1.0中加入的,Enumeration存在的目的就是为它们提供遍历接口。Enumeration本身并没有支持同步,而在Vector、Hashtable实现Enumeration时,添加了同步。
    而Iterator 是JDK 1.2才添加的接口,它也是为了HashMap、ArrayList等集合提供遍历接口。Iterator是支持fail-fast机制的:当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。iterator允许调用者删除底层集合里边的元素。

  19. finalize()方法什么时候被调用构函数(finalization)的目的是什么br> 答:垃圾回收器(garbage collector)决定回收某对象时,就会运行该对象的finalize()方法 但是在Java中很不幸,如果内存总是充足的,那么垃圾回收可能永远不会进行,也就是说filalize()可能永远不被执行,显然指望它做收尾工作是靠不住的。 那么finalize()究竟是做什么的呢最主要的用途是回收特殊渠道申请的内存。Java程序有垃圾回收器,所以一般情况下内存问题不用程序员操心。但有一种JNI(Java Native Interface)调用non-Java程序(C或C++),finalize()的工作就是回收这部分的内存。

  20. 如果对象的引用被置为null,垃圾收集器是否会立即释放对象占用的内存br> 答:不会立即释放对象占用的内存。 如果对象的引用被置为null,只是断开了当前线程栈帧中对该对象的引用关系,而 垃圾收集器是运行在后台的线程,只有当用户线程运行到安全点(safe point)或者安全区域才会扫描对象引用关系,扫描到对象没有被引用则会标记对象,这时候仍然不会立即释放该对象内存,因为有些对象是可恢复的(在 finalize方法中恢复引用 )。只有确定了对象无法恢复引用的时候才会清除对象内存。

  21. Java堆的结构是什么样子的么是堆中的永久代(Perm Gen space)br> 答:JVM的堆是运行时数据区,所有类的实例和数组都是在堆上分配内存。它在JVM启动的时候被创建。对象所占的堆内存是由自动内存管理系统也就是垃圾收集器回收。
    堆内存是由存活和死亡的对象组成的。存活的对象是应用可以访问的,不会被垃圾回收。死亡的对象是应用不可访问尚且还没有被垃圾收集器回收掉的对象。一直到垃圾收集器把这些对象回收掉之前,他们会一直占据堆内存空间。
    永久代是用于存放静态文件,如Java类、方法等。持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些class,例如Hibernate 等,在这种时候需要设置一个比较大的持久代空间来存放这些运行过程中新增的类,永久代中一般包含:
    类的方法(字节码…)
    类名(Sring对象)
    .class文件读到的常量信息
    class对象相关的对象列表和类型列表 (e.g., 方法对象的array).
    JVM创建的内部对象
    JIT编译器优化用的信息
    虚拟机中的共划分为三个代:
    年轻代(Young Generation)、年老代(Old Generation)和持久代(Permanent
    Generation)。其中持久代主要存放的是Java类的类信息,与垃圾收集要收集的Java对象关系
    不大。年轻代和年老代的划分是对垃 圾收集影响比较大的。
    年轻代:
    所有新生成的对象首先都是放在年轻代的。年轻代的目标就是尽可能快速的收集掉那些生
    命周期短的对象。年轻代分三个区。一个Eden区,两个 Survivor区(一般而言)。大部分对象在
    Eden区中生成。当Eden区满时,还存活的对象将被复制到Survivor区(两个中的一个),当这
    个 Survivor区满时,此区的存活对象将被复制到另外一个Survivor区,当这个Survivor去也满了
    的时候,从第一个Survivor区复制过来的并且此时还存活的对象,将被复制“年老区
    (Tenured)”。需要注意,Survivor的两个区是对称的,没先后关系,所以同一个区中可能同时
    存在从Eden复制过来对象,和从前一个Survivor复制过来的对象,而复制到年老区的只有从第
    一个Survivor去过来的对象。而且,Survivor区总有一个是空的。同时,根据程序需要,
    Survivor区是可以配置为多个的(多于两个),这样可以增加对象在年轻代中的存在时间,减
    少被放到年老代的可能。
    年老代:
    在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认
    为年老代中存放的都是一些生命周期较长的对象。
    持久代:
    用于存放静态文件,如今Java类、方法等。持久代对垃圾回收没有显著影响,但是有些应
    用可能动态生成或者调用一些class,例如Hibernate 等,在这种时候需要设置一个比较大的持
    久代空间来存放这些运行过程中新增的类。持久代大小通过-XX:MaxPermSize=进行设置。

  22. 串行(serial)收集器和吞吐量(throughput)收集器的区别是什么br> 答:
    Serial 收集器
    Serial 收集器是历史悠久,最基本的收集器。它是一个单线程的收集器(说明:这里的单线程不仅仅是指收集器工作时使用一个CPU或者一条收集线程去收集,并且Serial工作时,必须暂停其他所有的工作线程,也就是“stop the world”,直到垃圾收集完成。)Serial是JVM运行在Client模式默认的新生代收集器。
    throughput收集器
    也叫做Parallel Scavenge 收集器,它的目标是达到一个可控制的吞吐量(throughput),(说明:吞吐量就是CPU用于执行代码的时间和CPU总共消耗时间的比值,即:吞吐量 = 运行代码时间 / (运行代码时间 + 垃圾收集器工作时间)),JVM提供了两个参数以精确的控制吞吐量,-XX:MaxGCPauseMillis 最大收集停顿时间;-XX:GCTimeRatio 垃圾收集时间占总时间的比例。
    总结
    串行收集器在GC时会停止其他所有工作线程(stop-the-world),CPU利用率是最高的,所以适用于要求高吞吐量(throughput)的应用,但停顿时间(pause time)会比较长,所以对web应用来说就不适合,因为这意味着用户等待时间会加长。而并行收集器可以理解是多线程串行收集,在串行收集基础上采用多线程方式进行GC,很好的弥补了串行收集的不足,可以大幅缩短停顿时间,因此对于空间不大的区域(如young generation),采用并行收集器停顿时间很短,回收效率高,适合高频率执行。

  23. JVM的永久代中会发生垃圾回收么/p>

  1. 异常处理完成以后,Exception对象会发生什么变化/li>
  1. 解释一下Applet的生命周期/li>
  1. Applet和普通的Java应用程序有什么区别/li>
  1. 什么是JDBC/li>
  1. try-catch-finally中有关return返回值的表述
  1. PreparedStatement比Statement有什么优势/li>
  1. 什么是Servlet/li>
  1. GenericServlet和HttpServlet有什么区别/li>
  1. Servlet的生命周期
  1. get和post方法比较
    • get是从服务器上获取数据,post是向服务器传送数据。
    • get是把参数数据队列加到提交表单的ACTION属性所指的URL中,值和表单内各个字段一一对应,在URL中可以看到。post是通过HTTP post机制,将表单内各个字段与其内容放置在HTML HEADER内一起传送到ACTION属性所指的URL地址。用户看不到这个过程。
    • 对于get方式,服务器端用Request.QueryString获取变量的值,对于post方式,服务器端用Request.Form获取提交的数据。
    • get传送的数据量较小,不能大于2KB(受限于浏览器)。post传送的数据量较大,一般被默认为不受限制。但理论上,IIS4中最大量为80KB,IIS5中为100KB。
    • get安全性非常低,post安全性较高。但是执行效率却比Post方法好。
      建议: 1、get方式的安全性较Post方式要差些,包含机密信息的话,建议用Post数据提交方式; 2、在做数据查询时,建议用Get方式;而在做数据添加、修改或删除时,建议用Post方式;

什么是web应用程序/p> 文章知识点与官方知识档案匹配,可进一步学习相关知识Java技能树首页概览91437 人正在系统学习中

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2019年9月22日
下一篇 2019年9月22日

相关推荐