JAVA常考面试题

  • JDK和JRE的区别

    • Java运行时环境(JRE)。它包括Java虚拟机、Java核心类库和支持文件。它不包含开发工具(JDK)--编译器、调试器和其他工具。

    • Java开发工具包(JDK)是完整的Java软件开发包,包含了JRE,编译器和其他的工具(比如:JavaDoc,Java调试器),可以让开发者开发、编译、执行Java应用程序。

  • 值传递和引用传递

    • 值传递是对基本型变量而言的,传递的是该变量的一个副本,改变副本不影响原变量.

      引用传递一般是对于对象型变量而言的,传递的是该对象地址的一个副本, 并不是原对象本身 。

      一般认为,java内的基础类型数据传递都是值传递. java中实例对象的传递是引用传递

  • 线程和进程的区别

    • a.地址空间和其它资源:进程间相互独立,同一进程的各线程间共享。某进程内的线程在其它进程不可见。

    • b.通信:进程间通信IPC,线程间可以直接读写进程数据段(如全局变量)来进行通信——需要进程同步和互斥手段的辅助,以保证数据的一致性。

    • c.调度和切换:线程上下文切换比进程上下文切换要快得多。

    • d.在多线程OS中,进程不是一个可执行的实体。

  • 线程状态

    • 1. 新建( new ):新创建了一个线程对象。

    • 2. 可运行( runnable ):线程对象创建后,其他线程(比如 main 线程)调用了该对象 的 start ()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获 取 cpu 的使用权 。

    • 3. 运行( running ):可运行状态( runnable )的线程获得了 cpu 时间片( timeslice ) ,执行程序代码。

    • 4. 阻塞( block ):阻塞状态是指线程因为某种原因放弃了 cpu 使用权,也即让出了 cpu timeslice ,暂时停止运行。直到线程进入可运行( runnable )状态,才有 机会再次获得 cpu timeslice 转到运行( running )状态。阻塞的情况分三种:

      (一). 等待阻塞:运行( running )的线程执行 o . wait ()方法, JVM 会把该线程放 入等待队列( waitting queue )中。

      (二). 同步阻塞:运行( running )的线程在获取对象的同步锁时,若该同步锁 被别的线程占用,则 JVM 会把该线程放入锁池( lock pool )中。

      (三). 其他阻塞: 运行( running )的线程执行 Thread . sleep ( long ms )或 t . join ()方法,或者发出了 I / O 请求时, JVM 会把该线程置为阻塞状态。            当 sleep ()状态超时、 join ()等待线程终止或者超时、或者 I / O 处理完毕时,线程重新转入可运行( runnable )状态。

    • 5. 死亡( dead ):线程 run ()、 main () 方法执行结束,或者因异常退出了 run ()方法,则该线程结束生命周期。死亡的线程不可再次复生。

  •  
    • JAVA常考面试题
  • 同步方法和同步代码块的区别

    • 同步方法默认用this或者当前类class对象作为锁;

      同步代码块可以选择以什么来加锁,比同步方法要更细颗粒度,我们可以选择只同步会发生同步问题的部分代码而不是整个方法;

      同步方法使用关键字 synchronized修饰方法,而同步代码块主要是修饰需要进行同步的代码,用   synchronized(object){代码内容}进行修饰;

  • 死锁:

    • 所谓死锁是指多个进程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进。死锁产生的4个必要条件:

    • 互斥条件:进程要求对所分配的资源(如打印机)进行排他性控制,即在一段时间内某 资源仅为一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待。
    • 不剥夺条件:进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能 由获得该资源的进程自己来释放(只能是主动释放)。
    • 请求和保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源 已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。
    • 循环等待条件:存在一种进程资源的循环等待链,链中每一个进程已获得的资源同时被 链中下一个进程所请求。
  • 避免死锁的方法

    • 顺序加锁:所有线程按照相同的顺序获得锁
    • 限时加锁:尝试获取锁的时候加一个限时时间,超时则放弃请求锁
    • 死锁检测:当一个线程请求失败,这个线程可以遍历锁的关系图时都有死锁发生,检测得到可以放弃所有锁
  • Iterator和ListIterator的区别

    • Iterator可用来遍历Set和List集合,但是ListIterator只能用来遍历List。
      Iterator对集合只能是前向遍历,ListIterator既可以前向也可以后向。
      ListIterator实现了Iterator接口,并包含其他的功能,比如:增加元素,替换元素,获取前一个和后一个元素的索引,等等。
  • 快速失败和安全失败

    • 快速失败:使用迭代器遍历集合对象的时候,如果遍历过程中对集合对象进行了修改,则会抛出Concurrent Modification Exception
    • 原理:迭代器在遍历时直接访问集合中的内容,并且在遍历过程中使用了modCount变量,如果集合在遍历中发生了改变,那么modCount就会变化,在下次迭代中,就会检测modCount是否是expectedmodCount的值,是的话继续,否则抛出异常,注意,如果修改了modCount满足modCount = expectedmodCount就不会异常,因此modCount!=expectedmodCount 这个条件才是异常发生的原因。
    • 场景::java.util 包下的集合类都是快速失败的,不能在多线程下发生并发修改
    • 安全失败:采用安全失败机制的集合容器,在遍历时不是直接在集合内容*问的,而是先复制原有集合内容,在拷贝的集
      合上进行遍历
    • 原理:由于迭代时是对原集合的拷贝进行遍历,所以在遍历过程中对原集合所作的修改并不能被迭代器检测到,
      所以不会触发 Concurrent Modification Exception
    • 缺点:基于拷贝内容的优点是避免了 Concurrent Modification Exception,但同样地,迭代器并不能访问到修改后
      的内容,即:迭代器遍历的是开始遍历那一刻拿到的集合拷贝,在遍历期间原集合发生的修改迭代器是不知道的
    • 场景:java.util.concurrent 包下的容器都是安全失败,可以在多线程下并发使用,并发修改。
  • HashMap的工作原理

    • 以key-value的形式存储元素,使用一个hash函数,使用hashcode()和equals()方法向集合添加和检索元素,使用put的时候,计算key的值,然后把value存储在合适的索引上,如果key存在,则替换;一些特性包括容量capacity,负载因子loadFactor,扩容threshold
  • ArrayList和Array的区别:

    • array可以包含基本类型和对象类型,arraylist只可以包含对象类型
    • array大小固定,arraylist的大小动态变化的
    • arraylist提供了更多的方法和特性
  • arraylist和linkedlist的区别

    • arraylist结构是数组,以O(1)的时间复杂度访问数据,但是插入删除需要移动元素,linkedlist是链表,查询速度为O(n),但是插入修改都是更快的O(1),
    • linkedList因为每个节点存储了两个引用,前和后,所以更加占内存
  • Comparable和Comparator接口的区别:

    • Comparable:只包含compareTo()方法,具体来说,返回复数,0,正数来表示已经存在的对象小于,等于,大于输入对象
    • Comparator:包含compare()和equals(),方法同上,equals()用来决定输入参数是否和comparator相等,只有当输入参数也是一个comparator并且输入参数和当前comparator的排序结果是相同的时候,这个方法才返回true
  • 优先级队列

    • PriorityQueue保证每次取出的元素都是队列中权值最小的,元素的大小的评判可以通过元素本身的自然顺序,也可以通过构造时传入的比较器
    • ,线程不安全,出队列入队列都是O(logn),不允许放入null,通过完全二叉树实现的小顶堆
    • JAVA常考面试题

    • 添加元素的堆化过程
    • JAVA常考面试题

    • 移除元素的堆化过程

      JAVA常考面试题