跳槽者、应届生必看JAVA面试题系列(二)

文章标题

    • 一: 前言
    • 二: 面试挑战
    • 三: 后端基础知识篇(二)
      • 一: Java中的队列和它们的区别
      • 二: 简单描述下JVM内存模型以及它们的作用
      • 三: 常见的GC算法和它们的差异
      • 四: 反射的优缺点
      • 五: 多继承的弊端和解决方案
      • 六: 抽象类和接口的区别
      • 七: 继承、封装、多态的作用
      • 八: ClassNotFoundException知道?遇到的场景是什么?如何解决?
      • 九: NoClassDefError错误的常见场景
      • 十: hashcode和equals方法的特点
      • 十一: hashcode的作用
      • 十二: 为什么需要重写hashcode方法
      • 十二: java.util包和java.awt包的区别
      • 十三: 项目中常用的包有哪些
      • 十四: fail-fast和fail-safe的区别
      • 十五: Bean工厂和Appcation Context的区别
      • 十六: 垂直拆分和水平拆分
      • 十七: 保证线程安全的方式
      • 十八: 重写equals方法需要注意的事项
      • 十九: JAVA中哪些属性不能被序列化
      • 二十: JRE和JDK的区别
    • 四: 面试题目大纲
    • 五: 总结
    • 六: 热门推荐

一: 前言


JAVA面试必看系列第一章出来后,许多朋友的反馈都还不错,这让我激动万分,想着趁热打铁,继续编写第二章的内容,反馈你们的热情。


二: 面试挑战

  在开始第二章题目之前,还是先案例下"面试挑战": 凡是满足下面的挑战条件的,如果一个月内没有拿到一个Offer的,免费提供简历封装建议和相关面试题目解答。

  如果面试通过的,截图分享,让大家一起见证,具体条件如下:

  1、计算机相关专业或者经过计算机相关专业的培训(不少于3个月,正常来说培训机构培训时间不会少于三个月),准备从事JAVA开发人员。

   2、从事的工作是JAVA开发,年限是1-3年(大神的话就忽略我说的,可以直接退出了)或者是符合计算机相关专业,准备从学校出来就业的。

   3、持续学习本人《面试大全》至少两个月且对其中的内容基本掌握的。

  4、需要提供相关面试证据或者是面试题目。

  如果大家对这个感兴趣的,可以关注【IT学习日记】回复【面试挑战】即可参与,现在参与还免费赠送一份面试资料。


三: 后端基础知识篇(二)


一: Java中的队列和它们的区别

  1、定义
    队列是一个先进先出的数据结构,Queue是JDK1.5引入的。

  2、用途
    将大量的请求转换成服务器能够处理的队列请求,可以保证有序性,如秒杀系统

  3、分类

    第一类: 没有实现阻塞接口,但是实现了Queue和AbstractQueue接口

    (1)、LinkedList:: 实现了Deque接口,双向有序队列

    (2)、PriorityQueue: 有限队列,维护一个有序列表,可以自然排序也可以传递Comparator构造函数实现自定义排序

    (3)、ConcurrentLinkedQueue: 基于链表、线程安全的队列,并发访问不需要同步,它是从尾部添加元素从头部删除元素,对公共的集合访问效率做得很不错,添加删除O(1),查询O(n)。

    第二类: 实现了阻塞接口,concurrent包中引入了BlockQueue接口和五个阻塞队列,他们不是操作就立即向队列中添加或者删除元素,而是线程执行阻塞操作,直至队列有空间可以添加或者有元素可以删除。

    (1)、ArrayBlockingQueue: 数组型有界队列

    (2)LinkedBlockingQueue: 链接节点,支持可选的有界队列

    (3)PriorityBlockingQueue: 一个优先级堆,支持的无界队列

    (4)DelayQueue: 一个优先级堆,支持基于时间的无界队列

    (5)SynchronousQueue: 可以用来在线程间安全的交换单一元素

    三: 关于阻塞队列的操作

    1、add、remove、element: 操作一个已满或者为空的队列时,如果操作的集合为空或者已满时,remove或者add则会抛出异常。

    2、Offer、poll、peek: 在无法完成操作时,只会返回true或者null,不会抛出异常

    3、Take操作: 队列为空的时候阻塞。put操作:队列满时阻塞


二: 简单描述下JVM内存模型以及它们的作用


    注: 该图是jdk1.7时对应的JVM内存模型
跳槽者、应届生必看JAVA面试题系列(二)_第1张图片


  1、程序计数器

      用来标识下一条需要执行指令的位置,它是线程私有的。

  2、虚拟机栈

    线程私有,声明周期和线程相同,它描述了Java方法执行的内存模型。每个方法在执行的同时会创建一个栈帧(Stack Frame),用于存储局部变量表,动态链接等信息。从调用到调用完成对应的是一个栈帧从虚拟机栈入栈到出栈的过程。

    局部变量表存放了编译器可知的基本类型、独享引用。Long、Double占用了2个局部变量控件slot,故为非原子性,它在编译时便完成了内存的分配,运行时不会进行修改。

    当申请的栈深度大于虚拟机允许的宽度时会抛出:StackoverFlowError,如虚拟机自动拓展、但申请不到足够的内存时,则抛出OutofMemeryError

  3、本地方法栈

    线程私有、为本地方法(native)服务,如:hotspot是将它和虚拟机栈合并在一起。可能抛出的错误有:StackoverFlowError和OutofMemeryError。

  4、堆

    线程共享、JVM中占用内存最大的一块区域,VM启动时创建,主要目的是: 存放对象实例。当实例没有申请到足够的空间时,堆大小也无法拓展时,会抛出OutofMemeryError错误,它也是GC主要进行收集的地方。(jdk1.8后,常量池也是存放在堆中,因为永久代废除了)

  5、方法区

    线程共享用于存储被虚拟机加载的类信息、变量、静态变量既即时编译的代码,JVM规范是将它和堆进行分开。永久代和元空间其实都是方法区的一种实现。


三: 常见的GC算法和它们的差异


  知识小贴士:

    Hotspot将堆划分为新生代(Young Generation)和年老代(Tetured Generation),新生代又分为Eden去和Survivor区,它们的比例是:8:2。所有新建的对象存放在新生代,其中survivor区又划分为from区和to区,比例是1:1。


  1、标记-清除(Mark Sweap)

    主要的步骤: 标记回收对象,回收被标记的对象

    标记方式有两种: 1、引用计数算法(Reference Counting), 2、可达性分析法(Rechability Analysis)

  缺点:

    回收后会出现大量非连续内存,且需要扫描两次内存,效率低


  2、复制算法(coping)

    思路: 将内存划分为等大的两块区域,一次只用一块,用完将存活的对象复制到另一块,然后清空自己。

    特点:

    解决了标记-清楚算法效率和内存碎片问题,但是需要浪费一块内存空间,利用率不高,主要是用于回收新生代(因为新生代的对象基本是”朝生暮死”,存活的时间很短)


  3、标记-整理(Mark - Compact)算法

    思路:

    从根节点开始对所有可达对象进行一次标记、之后,不是简单的清除未标记的对象,而是将所有存活的对象压缩到内存的一端,之后,清理边界外的所有空间。

    特点:

    避免了内存碎片的产生、同时又不需要两块相同的内存空间,相对来说性价比较高。多适用于老年代的区域回收,因为老年代的对象存活率大。

  4、分代收集算法

    分代收集算法是目前虚拟机使用的回收算法。它解决了标记清除算法不使用于老年代的问题。在不同年代中使用不同的收集方式,新生代存活率低,可以使用复制算法。老年代对象存活率高,没有额外的控件对它进行分配担保,可以使用标记清除或者标记整理算法。


四: 反射的优缺点


  优点:

    体现了灵活性、降低了类之间的耦合性、体现了多态的作用。

  缺点:

    性能存在一定问题。反射本身算是一种解释操作,告诉JVM我们想要做什么并让它满足我们的要求,它会比直接执行操作更慢一些。


五: 多继承的弊端和解决方案


  弊端: 如果有多个父类,有相同的功能时,子类调用,会产生不确定性,所以JAVA中类的只有单继承。

  解决: 通过”实现”解决,因为接口中的功能都是未实现的,需要子类明确。接口的出现避免了单继承的局限性,所以,一般是父类中定义的事物的基本功能,接口定义的是事物的拓展功能。


六: 抽象类和接口的区别


  一: 相同点

    都不能直接实例对象,都可以包含抽象方法


  二: 不同点

    1、接口中除了静态方法和默认方法外只能存在抽象方法,但是抽象类中既可以存在抽象方法也可以存在非抽像方法。

    2、接口可以多实现,但是类只能单继承

    3、接口中只能定义常量,抽象类中可以定义常量和变量

    4、接口中没有构造函数,抽象类中有构造函数


七: 继承、封装、多态的作用


  继承: 子类自动拥有父类所有可以继承的属性和方法


  封装: 隐藏对象的属性和方法的细节实现,提供一些公共访问的方式


  多态: 配合继承与方法的重写提高代码的重用性和拓展性,如无方法重写,则多态同样无意义。


八: ClassNotFoundException知道?遇到的场景是什么?如何解决?


  场景:

    1、调用Classs.forName(“类的全限路径”)加载类时


    2、ClassLoader.findSystemClass方法调用时


    3、ClassLoader.loadClass方法时

  解决:

    检查类名是否正确或者是否真的存在需要加载的类


九: NoClassDefError错误的常见场景


  场景:

    1、类依赖的class或者jar包不存在


    2、类文件存在,但是存在于不同的域中


    3、大小写问题,javac编译时是无视大小写的,可能编译出的class文件和想要的不一样


十: hashcode和equals方法的特点


  1、重写equals方法则必须同时重写hashCode方法


  2、如果两个对象的equals方法相等,则两个对象的hashCode也一定相等


  3、如果两个对象的hashCode相等,那么两个对象的equals方法不一定相等,只能说明两个对象在散列存储结构中,存放在相同的一个位置


十一: hashcode的作用


  用于快速定位对象在散列表的位置。在JVM中new一个对象时,会将这个对象丢到Hash表中,下次再进行对象的比较或者取该丢向时,根据该对象的hashCode从hash表中获取,目的,提高获取对象的效率。


  若HashCode相同则再去调用equals方法,所以hashCode是用于查找的,而equals方法是用于判断两个对象是否相等。


十二: 为什么需要重写hashcode方法


  HashMap或者HashSet中如果不重写会导致存对象进去了,但是取对象的时候却取不到正确的。重写hashCode时为了保证相同的对象有相同的hashCode。


十二: java.util包和java.awt包的区别


  Java,util包中存放的是常用的工具包,如集合。


  Java.awt包存放的是: 包含用于创建用户界面和绘制图形图像的所有类。


十三: 项目中常用的包有哪些


  Java.lang: 提供利用 Java 编程语言进行程序设计的基础类。


  java.util: 包含集合框架、遗留的 collection 类、事件模型、日期和时间设施、国际化和各种实用工具类


  java.io.*: Java的核心库java.io提供了全面的IO接口。包括:文件读写、标准设备输出等。


  java.net.*: 包含与网络相关的一些类库。


  java.sql.*: 包含了与数据库相关的一些类库。


  此外还有如果java.util.concurrent等与线程安全相关的包。


十四: fail-fast和fail-safe的区别


  并发修改: 当一个线程或者多个线程在遍历集合时,另外的线程对该集合进行了内容变动(添加、删除、修改)。

  Fail-fast-快速失败: java.util下的集合都是这种模式

    在遍历集合的时候,如果进行了并发修改,会抛出concurrentModificationException异常,因为它所有的操作都是在原来的集合中进行的,在遍历的时候判断是否存在下一个元素时会进行:expectModcount和modCount的判断,如果不相等,则直接抛出异常。

  Fail-Safe-安全失败: java.util.concurrent下的集合都是这种模式

    属于这种机制的集合,任何对集合的操作(添加、修改、删除)都会在当前集合的复制出来的集合上操作,不会直接在当前的集合上进行,所以不会抛出异常,但是会存在以下的问题:

    1、需要复制集合,产生无效对象,开销较大

    2、无法保证读取的数据是目前原始数据结构中的最新数据


十五: Bean工厂和Appcation Context的区别


  Bean工厂:

    是Spring的原始接口,Bean工厂实现的容器特点是:每次获取对象的时候才会去创建对象,而不是在容器启动的时候去加载所有的对象。这是因为早期机器的容量和资源都是比较稀缺的,如果在启动时一次加载完所有的对象,资源可能全被占用,程序无法正常运行。

  Bean工厂的优缺点:

  优点:
    1、项目启动速度快,且资源占用少

  缺点:
    因为对象是在获取的时候才进行创建,所以无法在启动时检查出对象配置是否存在问题,需要在获取的时候才知道.

  ApplicationContext:
    它是继承了Bean工厂,同时拓展了许多功能,每次容器启动的时候会创建所有的对象。

  优点:
    可以及时发现对象配置的问题,因为在容器启动的时候会创建所有的对象。

  缺点:
    项目启动速度较慢,且资源占用较多。


十六: 垂直拆分和水平拆分


  垂直拆分:
    把一个数据库中不同的业务单元的数据分配到不同的数据库中,如:用户信息存存储在库1,订单信息存储在库2。


  水平拆分:
    根据一定的规则,将同一个业务单元的数据分配存储在不同的数据库中,防止单表的数据量太大,导致查询速率降低。


十七: 保证线程安全的方式


  1、添加锁,如synchronized,Reentractlock


  2、使用ThreadLocal线程副本,每个线程独享一份数据,互不干扰


  3、使用阻塞队列,线性执行任务


  4、使用JDK提供的原子类如java.concurrent.atomic包下的类


十八: 重写equals方法需要注意的事项


  注: java规范中要求重写equals方法需要具有以下的特性:


  1、自反性: 针对非空的x,使用x.equals(x)应该返回true


  2、对称性: 针对x,y,如果x.equals(y)为true,那么y.equals(x)也应该为true


  3、传递性: 如有x,y,z,存在x.equals(y)和y.equals(z)都为True,那么x.equals(z)也应该为true


  4、一致性: 如果比较对象未发生改变,则反复调用equals方法应该返回同样的结果


  5、对于任意的非空x,x.equals(null)应该返回false


十九: JAVA中哪些属性不能被序列化


  1、被static修饰的属性,它是属于类级别的,序列化针对的是对象。序列化保存的是对象的状态,静态变量是以类的状态,因此序列化并不保存静态变量。这里的不能序列化的意思,是序列化信息中不包含这个静态成员域


  2、被transient修饰的属性


二十: JRE和JDK的区别


  JRE:
    核心的内容是JVM及相关的核心类库及支持文件。


  JDK:
    除了包含JRE外,还包含了JAVA工具(编译器、调试器等)和java的基础类库,开发者可以进行: 开发 -> 编译 -> 执行java应用程序。


四: 面试题目大纲


   注意: 题目不止这些,会一直持续不断更新最新的面试题和面试资料。


五: 总结


  由于文章篇幅的限制,面试大全的第二章暂时到这里就告一段落。如果有意见或者建议,可以在下方或者私信留言,看到会及时回复,也欢迎大家参加面试挑战和面试题投稿,希望大家早日获得心仪的Offer,如果觉得文字对你有帮助,欢迎关注和点赞

  面试大全系列文章会保持稳定的更新速度,大概每周两更到三更,感兴趣和可以关注我。


  如果想参加面试挑战,可以私信回复【面试挑战】即可,如果想进行面试题目投稿,可以私信回复【面试题目投稿】即可,如果想获取更多面试问题和资料,查看最新的面试题目更新进度,可以关注我,私信【面试资料】即可,谢谢大家的阅读和关注。

在这里插入图片描述


六: 热门推荐


1、跳槽者、应届生必看JAVA面试题系列(一)

2、面试宝典(一) - 让你不再错过“金九银十“的求职浪潮之简历包装篇

3、轻松写出优雅的Restful风格API

你可能感兴趣的:(面试经验,java,面试,必看系列,2021java面试题目,最新java面试题)