大厂面试题

请问JDK和JRE的区别是什么?jdk

Java运行时环境(JRE)是将要执行Java程序的Java虚拟机。他同时也包含了执行applet需要的浏览器插件。Java开发工具(JDK)是完整的Java软件开发包,包含了JRE,编译器和其他的工具(比如:Java Doc,Java调试器),可以让开发者开发、编译、执行Java应用程序。

Java中的、LongAdder和AtomicLong有什么区别?jdk

JDK1.8引入了Long Adder类。CAS机制就是,在一个死循环内,不断尝试修改目标值,指导修改成功。如果竞争不激烈,那么修改成功的概率就很高,否则,修改失败的概率就很高,在大量修改失败时,这些原子操作就会进行多次循环尝试,因此性能就会受到影响。
结合ConcurrentHashMap的实现思想,应该可以想到对一种传统AtomicInteger等原子类的改进思路。虽然CAS操作没有锁,但是像减少粒度这种分离热点的思想依然可以使用。将AtomicInteger的内部核心数据value分离成一个数组,每个线程访问时,通过哈希等算法映射到其中一个数字进行计数,而最终的计数结果,则为这个数组的求和累加。热点数据value被分离成多个单元cell,每个cell独自维护内部的值,当前对象的实际值由所有的cell累计合成,这样热点就进行了有效的分离,提高了并行度。

请说明一下JAVA中反射的实现过程和作用分别是什么?反射

JAVA语言编译之后会生成一个.class文件,反射就是通过字节码文件找到某个类、类中的方法以及属性等。反射的实现主要借助一下四个类:Class:类的对象,Constructor:类的构造方法,Field:类中的属性对象,Method:类中的方法对象。
作用:反射机制指的就是程序在运行是能够获得自身的信息。在JAVA中,只要给定类的名字,那么就可以通过反射机制来获取类的所有信息。

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

JVM中的类的装在是由Class Loader和它的子类来实现的。Java ClassLoader是一个重要的Java运行时系统组件。它负责在运行时查找和装入类文件的类。
Java中的所有类,都需要由类加载器装载到JVM中才能运行。类加载器本身也是一个类,而它的工作就是把class文件从硬盘读取到内存中。在写程序的时候,我们几乎不需要关心类的加载,因为这些都是隐式装载的,除非我们有特殊的用法,像是反射,就需要显式的加载所需要的类。类装载方式,有两种:
(1) 隐式装载
程序在运行过程中当碰到通过new等方式生成对象时,隐式调用类装载器加载对应的类到jvm中,
(2)显式装载
通过class.forname()等方法,显式加载需要的类,隐式加载与显式加载的区别:两者本质是一样的。Java类的加载是动态的,它并不会一次性将所有类全部加载后再运行,而是保证程序运行的基础类(像是基类)完全加载到jvm中,至于其他类,则在需要的时候才加载。这当然就是为了节省内存开销。

什么是Java虚拟机?为什么Java被称为“平台无关的编程语言”?JVM

Java虚拟机是一个可以执行Java字节码的虚拟机进程。Java源文件被编译成能被Java虚拟机执行的字节码文件。
Java被设计成允许应用程序可以运行在任意的平台,而不需要程序员为每一个平台单独重写或者是重新编译。Java虚拟机让这个变为可能,因为它知道底层硬件平台的指令长度和其他特性。

请问什么是JVM内存模型?JVM内存模型

Java内存模型(简称JMM),JMM决定一个线程对共享变量的写入合适对另一个线程可见。在抽象的角度来看,JMM定义了线程和主内存之间的抽象关系:线程之间的共享变量存储在主内存中(main memory),每个线程都要一个私有的本地内存(local memory),本地内存中存储了该线程以读/写共享变量的副本。
本地内存是JMM的一个抽象概念,并不真实存在。它涵盖了缓冲,写缓冲区,寄存器以及其他的硬件和编译去优化。关系图如下:
在这里插入图片描述

列举一下,在JAVA虚拟机中哪些对象可作为ROOT对象?JAVA虚拟机

虚拟机栈中的引用对象
方法区中类静态属性引用的对象
方法区中常用引用对象
地方方法栈中JNI引用对象

GC中如何判断对象是否需要被回收?JAVA虚拟机

即使在可达性分析算法中不可达的对象,也并非是“非回收不可”的,这时候它们暂时处于“等待”阶段,要真正宣告一个对象回收,至少要经历两次标记过程:如果对象在进行可达性分析后发现没有与GC Roots相连接的引用链,那它将会被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。 当对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过,虚拟机将这两种情况都视为“没有必要执行”。(即意味着直接回收)
如果这个对象被判定为有必要执行finalize()方法,那么这个对象将会放置在一个叫做F-Queue的队列之中,并在稍后由一个由虚拟机自动建立的、低优先级的Finalizer线程去执行它。这里所谓的“执行”是指虚拟机会触发这个方法,但并不承诺会等待它运行结束,这样做的原因是,如果一个对象在finalize()方法中执行缓慢,或者发生了死循环(更极端的情况),将很可能会导致F-Queue队列中其他对象永久处于等待,甚至导致整个内存回收系统崩溃。finalize()方法是对象逃脱回收的最后一次机会,稍后GC将对F-Queue中的对象进行第二次小规模的标记,如果对象要在finalize()中跳出回收——只要重新与引用链上的任何一个对象建立关联即可,譬如把自己(this关键字)赋值给某个类变量或者对象的成员变量,那在第二次标记时它将被移除出“即将回收”的集合;如果对象这时候还没有逃脱,那基本上它就真的被回收了。

说明一下JAVA虚拟机的作用是什么?java虚拟机

解释运行字节码程序消除平台相关性
jvm将Java字节码解释为具体平台的具体指令。一边的高级语言如要在不同的平台上运行,至少要编译成不同的代码。而引进JVM后,Java语言在不同平台运行时不需要重新编译。Java语言使用模式Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行。
假设一个场景,要求stop the world时间非常短,你会怎么设计垃圾回收机制?
绝大多数新创建的对象分配在Eden区。
在Eden区发生一次GC后,存活的对象移到其中一个Survivor区。
在Eden区发生一次GC后,对象是存放到Survivor区,这个Survivor区已经存在其他存活的对象。
一旦一个Survivor区已满,存活的对象移动到另外一个Survivor区。然后之前那个空间已满
Survivor区将置为空,没有任何数据。
经过重复多次这样的步骤后依旧存活的对象将被移到老年代。

请简单描述一下JVM分区都有哪些?JVM

在这里插入图片描述
java内存通常被划分为5个区域:程序计数器( Program Count Register 、本地方法栈(Native Stack) 、方法区(Methon Area) 、栈(Stack)、堆(Heap)。

请说明一下eden区和survial区的含义以及工作原理?JVM

目前主流的虛拟机实现都采用了分代收集的思想,把整个堆区划分为新生代和老年代;新生代又被划分成Eden空间、From Survivor 和ToSurvivor三块区域。
我们把Eden : From Survivor : To Survivor空间大小设成8:1:1,对象总是在Eden区出生,From Survivor保存当前的幸存对象,To Survivor为空。
一次ge发生后:

  1. Eden区活着的对象+ From Survivor存储的对象被复制到To Survivor
    2)清空Eden和From Survivor ;
    3)颠倒From Survivor和To Survivor 的逻辑关系:From变To,To变From。
    可以看出,只有在Eden空间快满的时候才会触发Minor GC。而Eden空间占新生代的绝大部分,所以Minor GC的频率得以降低。当然,使用
    两个Survivor这种方式我们也付出了一定的代价,如10%的空间浪费、复制对象的开销等。

垃圾回收器的基本原理是什么?垃圾回收

对应GC来说,当程序员创建对象时,GC就开始监控这个对象的地址、大小以及使用情况。通常,GC采用有向图的方式记录和管理堆(heap)中的所有对象。通过这种方式确定哪些对象是“可达的”,哪些对象是“不可达的”。当GC确定一些对象为“不可达”时,GC就有责任回收这些内存空间。当然程序猿可以手动执行System.gc(),通知GC运行,但是Java语言规范并不保证GC一定会执行。

请说明一下垃圾回收的优点以及原理?垃圾回收

Java语言中一个显著的特点就是引入了垃圾回收机制,使c++程序员最头疼的内存管理的问题迎刃而解,它使得Java程序员在编写程序的时候不再需要考虑内存管理。由于有个垃圾回收机制,Java中的,对象不再有"作用域"的概念,只有对象的引用才有"作用域"。
垃圾回收可以有效的防止内存泄露,有效的使用可以使用的内存。垃圾回收器通常是作为一个单独的低级别的线程运行,不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收,程序员不能实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。回收机制有分代复制垃圾回收和标记垃圾回收,增量垃圾回收。

请问,在Java中会存在内存泄漏吗?内存

Java中的确存在Java的内存泄露,并且事态可以变得相当严重。
Java garbage collector自动释放哪些内存里面。程序不在需要的对象,以此避免大多数的其他程序上下文的内存泄漏。但是Java应用程序依旧会有相当的内存泄漏。查找原因会十分困难。
有两类主要的Java内存泄漏:
1.非必要的对象引用、
Java代码常常保留对于不再需要的对象引用,并且这组织了内存的垃圾收集器的工作。 Java对象通常被其他对象包含引用,为此一个单一对象可以保持整个对象树在内存中,于是导致了如下问题:在向数组添加对象以后遗漏了对于他们的处理直到你再次使用对象的时候都不释放引用。比如一个菜单指令可以插入一个对象实例引用并且不释放便于以后再次调用的时候使用,但是也许永远不会发生。
在其他引用依然需要旧有状态的时候贸然修改对象状态.比如当你为了在一个文本文件里面保存一些属性而使用一个数组,诸如”字符个数”等字段在不再需要的时候依然保留在内存当中。允许一个长久执行的线程所引用的对象.设置引用为NULL也无济于事,在线程退出和空闲之前,对象不会被收集释放。
2.为释放的系统资源
Java方法可以定位Java实例以外的堆内存,诸如针对视窗和位图的内存资源.Java常常通过JNI(Java Native Interface) 调用C/C++子程序定位这些资源。

简述一下GC算法?JVM

①GC (GarbageCollection 垃圾收集), GC的对象是堆空间和永久区
②GC算法包含:引用计数法,标记清除,标记压缩,复制算法。
③引用计数器的实现很简单,对于一个对象A,只要有任何一个对象引用了A,则A的引用计数器就加1,当引用失效时,引用计数器就减1。只要对象A的引用计数器的值为0,则对象A就不可能再被使用。
④标记-清除算法是现代垃圾回收算法的思想基础。标记-清除算法将垃圾回收分为两个阶段:标记阶段和清除阶段。一种可行的实现是,在标记阶段,首先通过根节点,标记所有从根节点开始的可达对象。因此,未被标记的对象就是未被引用的垃圾对象。然后,在清除阶段,清除所有未被标记的对象。与标记-清除算法相比,复制算法是一种相对高效的回收方法不适用于存活对象较多的场合如老年代将原有的内存空间分为两块,每次只使用其中一块,在垃圾回收时,将正在使用的内存中的存活对象复制到未使用的内存块中,之后,清除正在使用的内存块中的所有对象,交换两个内存的角色,完成垃圾回收。

请问运行时异常与受检异常有什么区别?异常

异常表示程序运行过程中可能出现的非正常状态,运行时异常表示虛拟机的通常操作中可能遇到的异常,是一种常见运行错误,只要程序设计得没有问题通常就不会发生。受检异常跟程序运行的上下文环境有关,即使程序设计无误,仍然可能因使
用的问题而引发。Java编译器要求方法必须声明抛出可能发生的受检异常,但是并不要求必须声明抛出未被捕获的运行时异常。
异常和继承一样,是面向对象程序设计中经常被滥用的东西,在Effective Java中对异常的使用给出了以下指导原则:
-不要将异常处理用于正常的控制流(设计良好的API不应该强迫它的调用者为了正常的控制流而使用异常)
-对可以恢复的情况使用受检异常,对编程错误使用运行时异常
-避免不必要的使用受检异常(可以通过一些状态检测手段来避免异常的发生)
-优先使用标准的异常
-每个方法抛出的异常都要有文档
-保持异常的原子性
-不要在catch中忽略掉捕获到的异常

请问什么时Java序列化?以及如何实现Java序列化?序列化

序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决在对对象流进行读写操作时所引发的问题。.

序列化的实现:将需要被序列化的类实现Serializable接口,该接口没有需要实现的方法,implements Serializable只是为了标注该对象是可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,接着,使用ObjectOutputStream对象的writeObject(Object obj)方法就可以将参数为obj的对象写出(即保存其状态),要恢复的话则用输入流。

请说明一下Java中的异常处理机制的原理以及如何应用?异常

当JAVA程序违反了JAVA的语义规则时,JAVA虚拟机就会将发生的错误表示为一个异常。违反语义规则包括2种情况。一种是JAVA类库内置的语义检查。例如数组下标越界,会引发IndexOutOfBoundsException;访问null的对象时会引发NullPointerException。另- -种情况就是JAVA允许程序员扩展这种语义检查,程序员可以创建自己的异常,并自由选择在何时用throw关键字引发异常。所有的异常都是java.lang.Thowable的子类。

请问Spring中Bean的作用域有哪些?框架

在Spring的早期版本中,仅有两个作用域:
singleton和prototype,前者表示Bean以单例的方式存在; 后者表示每次从容器中调用Bean时,都会返回一个新的实例,prototype 通常翻译为原型。
设计模式中的创建型模式中也有一个原型模式,原型模式也是一个常用的模式,例如做一个室内设计软件,所有的素材都在工具箱中,而每次从工具箱中取出的都是素材对象的一个原型,可以通过对象克隆来实现原型模式。Spring 2.x中针对WebApplicationContext新增了3个作用域,分别是: request (每次HTTP请求都会创建一个新的Bean)、session (同一个HttpSession共享同一个Bean,不同的HttpSession使用不同的Bean)和globalSession (同一个全局Session 共享一个Bean)。
单例模式和原型模式都是重要的设计模式。一般情况下,无状态或状态不可变的类适合使用单例模式。在传统开发中,由于DAO持有Connection这个非线程安全对象因而没有使用单例模式;但在Spring环境下,所有DAO类对可以采用单例模式,因为Spring利用AOP和JavaAPI中的ThreadLocal对非线程安全的对象进行了特殊处理。

请谈一谈Spring中自动装配的方式有哪些?spring框架

  • no:不进行自动装配,手动设置Bean的依赖关系。
  • byName:根据Bean的名字进行自动装配。
  • byType:根据Bean的类型进行自动装配。
  • constructor:类似于byType,不过是应用于构造器的参数,如果正好有一个Bean与构造器的参数类型相同则可以自动装配,否则会导致错误。
  • autodetect: 如果有默认的构造器,则通过constructor的方式进行自动装配,否则使用byType的方式进行自动装配。自动装配没有自定义装配方式那么精确,而且不能自动装配简单属性(基本类型、字符串等),在使用时应注意。

请问error和exception有什么区别?异常

error表示恢复不是不可能但很困难的情况下的一种严重问题。比如说内存溢出。不可能指望程序能
处理这样的情况。
exception表示一种设计或实现问题。也就是说,它表示如果程序运行正常,从不会发生的情况。

请问什么时IoC和DI?并且简要说明一下DI是如何实现的?控制反控

loC (Inversion of Control)叫控制反转,DI (Dependency Injection) 叫依赖注入,是对1oC更简单的诠释。控制反转是把传统上
由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。所谓的"控制反转“就是对组件对象控制权的转移,从程序代码本身转移到了外部容器,由容器来创建对象并管理对象之间的依赖关系。IoC体现了好莱坞原则
“Don’t call me, we will call you”。依赖注入的基本原则是应用组件不应该负责查找资源或者其他依赖的协作对象。配置对象的工作应该由容器负责,查找资源的逻辑应该从应用组件的代码中抽取出来,交给容器来完成。DI是对loC更准确的描
述,即组件之间的依赖关系由容器在运行期决定,形象的来说,即由容器动态的将某种依赖关系注入到组件之中。
一个类A需要用到接口B中的方法,那么就需要为类A和接口B建立关联或依赖关系,最原始的方法是在类A中创建一个接口B的实现类C的实例,但这种方法需要开发人员自行维护二者的依赖关系,也就是说当依赖关系发生变动的时侯需要修改代码并
重新构建整个系统。如果通过-一个容器来管理这些对象以及对象的依赖关系,则只需要在类A中定义好用于关联接口B的方法(构造器或setter方法),将类A和接口B的实现类C放入容器中,通过对容器的配置来实现二者的关联。
依赖注入可以通过setter方法注入(设值注入)、构造器注入和接口注入三种方式来实现,Spring支持setter注入和构造器注入,通常使用构造器注入来注入必须的依赖关系,对于可选的依赖关系,则setter注入是 更好的选择,setter注 入需要类提供无参构造器或者无参的静态工厂方法来创建对象。

请说明一下Spring中BeanFactory和ApplicationCpntext的区别是什么?spring框架

BeanFactory是spring中比较原始,比较古老的Factory。因为比较古老,所以BeanFactory无法支持spring插件,例如: AOP、Web应用等功能。
ApplicationContext是BeanFactory的子类,因为古老的BeanFactory无法满足不断更新的spring的需求,于是ApplicationContext就基本上代替了BeanFactory的工作,以一种更面向框架的工作方式以及对上下文进行分层和实现继承,并在这个基础上对功能进行扩展:
<1>MessageSource,提供国际化的消息访问
<2>资源访问(如URL和文件)
<3>事件传递
<4> Bean的自动装配
<5>各种不同应用层的Context实现
区别:
<1>如果使用ApplicationContext,如果配置的bean是singleton,那么不管你有没有或想不想用它,它都会被实例化。好处是可以预先加载,坏处是浪费内存。
<2>BeanFactory,当使用BeanFactory实例化对象时,配置的bean不会马上被实例化,而是等到你使用该bean的时候(getBean) 才会被实例化。好处是节约内存,坏处是速度比较慢。多用于移动设备的开发。
<3>没有特殊要求的情况下,应该使用ApplicationContext完成。因为BeanFactory能完成的事情,ApplicationContext都能完成, 并且提供了更多接近现在开发的功能。

请说明一下springIOC原理是什么?如果你要实现IOC需要做什么?简述一下实现步骤 spring

①loC (Inversion of Control,控制倒转)。这是spring的核心,贯穿始终。所谓loC,对于spring框架来说,就是由spring来负责控制对象的生命周期和对象间的关系。
loC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI (Dependency Injection,依赖注入)来实现的。比如对象A需要操作数据库,以前我们总是要在A中自己编写代码来获得一个Connection对象,有了spring我们就只需要告诉spring, A中需要一个Connection,至于这个Connection怎么构造,何时构造,A不需要知道。在系统运行时,spring会在适当的时候制造-个Connection,然后像打针一样,注射到A当中,这样就完成了对各个对象之间关系的控制。A需要依赖Connection才能正常运行,而这个Connection是由spring注入到A中的,依赖注入的名字就这么来的。那么DI是如何实现的呢? Java1.3之后一个重要特征是反射(reflection),它允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性,spring就是通过反射来实现注入的。在一个对象中,如果要使用另外的对象,就必须得到它(自 己new一个,或者从JNDI中查询一个),使用完之后还要将对象销毁(比如Connection等), 对象始终会和其他的接口或类藕合起来。
②实现I0C的步骤
定义用来描述bean的配置的Java类
解析bean的配置,將bean的配置信息转换为上面的BeanDefinition对象保存在内存中,spring中采用HashMap进行对象存储,其中会用到一些xml解析技术遍历存放BeanDefinition的HashMap对象,逐条取出BeanDefinition对象,获取bean的配置
信息,利用Java的反射机制实例化对象,將实例化后的对象保存在另外一个Map中即可。

请说明一下Spring框架为企业级开发带来的好处有哪些?框架

  • 非侵入式:支持基于POJO的编程模式,不强制性的要求实现Spring框架中的接口或继承Spring框架中的类。
  • IoC容器: IoC容器帮助应用程序管理对象以及对象之间的依赖关系,对象之间的依赖关系如果发生了改变只需要修改配置文件而不是修改代码,因为代码的修改可能意味着项目的重新构建和完整的回归测试。有了1oC容器,程序员再也不需要自己编写工厂、单例,这一点特别符合Spring的精神"不要重复的发明轮子”。
  • AOP (面向切面编程) :将所有的橫切关注功能封装到切面(aspect) 中,通过配置的方式将横切关注功能动态添加到目标代码上,进一步实现了业务逻辑和系统服务之间的分离。另一方面,有了AOP程序员可以省去很多自己写代理类的工作。
  • MVC : Spring的MVC框架为Web表示层提供了更,好的解决方案。
  • 事务管理:Spring以宽广的胸怀接纳多种持久层技术,并且为其提供了声明式的事务管理,在不需要任何一行代码的情况下就能够完成事务管理。
  • 其他:选择Spring框架的原因还远不止于此,Spring为Java企业级开发提供了一站式选择,你可以在需要的时候使用它的部分和全部,更重要的是,甚至可以在感觉不到Spring存在的情况下,在你的项目中使用Spring提供的各种优秀的功能。

请简单谈一下spring框架的优点都有哪些?spring

Spring是-个轻量级的DI和AOP容器框架,在项目的中的使用越来越广泛,它的优点主要有以下几点:
Spring是一个非侵入式框架,其目标是使应用程序代码对框架的依赖最小化,应用代码可以在没有Spring或者其他容器的情况运行。
Spring提供了一个-致的编程模型,使应用直接使用POJO开发,从而可以使运行环境隔离开来。
Spring推动应用的设计风格向面向对象及面向接口编程转变,提高了代码的重用性和可测试性。
Spring改进了结构体系的选择,虽然作为应用平台,Spring可以帮助我们选择不同的技术实现,比如从Hibernate切换到其他的ORM工具,从Struts切换到Spring MVC,尽管我们通常不会这么做,但是我们在技术方案上选择使用Spring作为应用平台,
Spring至少为我们提供了这种可能性的选择,从而降低了平台锁定风险。

请简述一下Hibernate常见优化策略?Hibernate

①制定合理的缓存策略(二级缓存、查询缓存)。 ②采用合理的Session管理机制。 ③尽量使用延迟加载特性。 ④设定合理的批处理参数。 ⑤如果可以,选用UUID作为主键生成器。 ⑥如果可以,选用基于版本号的乐观锁替代悲观锁。 ⑦在开发过程中,开启hibernate.show_ sql选 项查看生成的SQL,从而了解底层的状况;开发完成后关闭此选项。 ⑧考虑数据库本身的优化,合理的索引、恰当的数据分区策略等都会对持久层的性能带来可观的提升,但这些需要专业的DBA (数据库管理员)提供支持。 cc