个人简介:
📦个人主页:赵四司机
🏆学习方向:JAVA后端开发
📣种一棵树最好的时间是十年前,其次是现在!
🔔博主推荐网站:牛客网 刷题|面试|找工作神器
💖喜欢的话麻烦点点关注喔,你们的支持是我的最大动力。
前言
由于很快到了金九银十的秋招季节,博主最近也在找一些面经资源,但是发现很多都不全,后来我发现了牛客网这个网站,发现里面不仅可以看面经,还能刷题模拟面试,要是你要找各种招聘信息也可以在上面找到,我愿称之为程序员必备网站,下面把它推荐给你们!
链接地址:牛客网
12.ACID靠什么保证
13.HashMap和HashTable的区别是什么
14.Hashmap有哪些线程安全的方式
15.MVCC解决的问题是什么
16.JVM
- 每一个线程都会分配一个栈,一个线程里面一个方法会分配一个栈帧
- 栈帧包含:局部变量表、操作数栈、动态链接、方法出口
- 动态链接:将静态符号在运行时候转变为方法的内存地址,让程序可以根据该地址找到该方法的内部代码
- 栈中假如存放的局部变量的结果是一个对象,则该局部变量存放的是该对象的地址
- 方法区:JDK1.8之前叫永久代或持久代,JDK1.8之后称为元空间,存放常量、静态变量、类信息
- 线程:程序计数器+栈+本地方法栈
17.JVM调优
- 堆:年轻代(1/3) + 老年代(2/3)
- 年轻代:Eden(8/10) + Survivor区(s0(1/10) + s1(1/10))
- GC Roots根节点:线程的本地变量、静态变量、本地方法栈的变量等
- 可达性分析算法:将“GC Roots”对象作为起点,从这些节点开始向下搜索引用的对象,将找到的对象都标记为非垃圾对象,其余未标记的对象都是垃圾对象
- 当Eden区放满时候会触发minor gc,由字节码执行引擎开启垃圾收集线程来完成,GC会将非垃圾对象Obj1移动到Survivor区的s0,该非垃圾对象的分代年龄(存放在对象头)会加一,当Eden区再次放满时候假如Obj1对象还是非垃圾对象,这时候会将Eden区的非垃圾对象以及s0的非垃圾对象移动到s1,然后分代年龄加一。假如再一次触发minor gc,则将s1的非垃圾对象再移到s0,如此反复。假如分代年龄达到15,该对象就会被存到老年区,当老年区被放满则触发full gc,当full gc满了且里面的都为非垃圾对象,则会出现OOM(内存溢出)。
- 当Survivor区放不下时候也会将对象放到老年区
18.Final
19.String、StringBuffer、StringBuilder
- String是final修饰的,每次操作都会产生新的string对象
- StringBuffer和StringBuilder都是在原对象上操作
- StringBuffer是线程安全的,StringBuilder是线程不安全的
- StringBuffer方法是synchronized修饰的
- 性能:StringBuilder>StringBuffer>String
- 优先使用StringBuilder,多线程使用共享变量时使用StringBuffer
20.重载和重写的区别
- 重载:发生在同一个类中,方法名必须相同,参数类型不同、个数不同、顺序不同,方法返回值和访问权限修饰符可以不同,发生在编译时。
- 重写:发生在父子类中,方法名、参数列表必须相同,返回值范围小于等于父类,抛出异常范围小于等于父类,访问修饰符范围大于等于父类;如果父类方法访问修饰符为private则子类就不能重写该方法。
21.接口和抽象类的区别
- 抽象类可以存放普通方法、静态方法和抽象方法,而接口只能存放public abstract方法
- 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的
- 抽象类只能继承一个,接口可以实现多个
- 接口设计的目的是对类的行为进行约束,也就是提供一种机制,可以强制要求不同的类具有相同的行为,它只约束了行为的有无,但不对其如何实现进行约束,一个类实现一个接口,就必须重写接口中所有的方法
- 而抽象类的设计目的是代码的复用,当不同的类具有某些相同的行为(记行为集合A),且其中一部分行为实现方式一致时候(A的非真子集,记为B),可以让这些类都派生于一个抽象类。在这个抽象类中实现了方法B,避免让所有的子类来实现B,这就达到了代码复用的目的。而A减B的部分,留给各个子类自己实现,正是因为A-B在这里没有实现,所以抽象类不允许实例化出来(否则当调用到A-B时,无法执行)。
- 使用场景:当你关注一个事物的本质时候,用抽象类;当你关注一个操作时候,用接口。
22.为什么要有HashCode
23.ArrayList与LinkedList区别
- ArrayList作为List接口主要实现类,是线程不安全的,效率高,底层使用Object[]数组存储。
- 在JDK7中,当创建一个ArrayList数组对象时候,会先创建一个长度为10的Object[]数组(饿汉式),如果这时候要添加第11个元素,就需要进行扩容,默认情况下扩容为原来的1.5倍,且需要将原来的数组复制到新的数组中。由于复制需要耗费计算,因此建议在开发中使用带参的构造器,即一开始就确定数组长度。
- 在JDK8中当创建一个ArrayList对象时候,底层Object[]会初始化为空,当第一次调用add操作时候才会创建一个长度为10的Object[]数组(懒汉式)。
- LinkedList对于频繁的插入、删除时候就建议使用,底层使用双向链表来实现。LinkedList不适合用做查询,因为查询需要逐一遍历。遍历过程必须使用iterator不能使用for循环,因为每次通过for循环通过get(i)获取某一元素时候都需要对list进行重新遍历,性能消耗极大。另外不能使用IndexOf等返回元素索引,并利用其进行遍历,使用IndexOf对list进行遍历,当结果为空时仍会遍历整个链表。
24.HashMap底层实现原理
JDK7:
- 在创建一个HashMap对象之后,底层会创建一个长度为16的一维数组Entry[] table,当执行put(key1,value1)操作时候,首先调用key1所在类的HashCode()计算key1的哈希值,此哈希值经过特殊某种算法计算之后得到在Entry数组中的位置。如果此位置上为空,次数(key1,value1)添加成功,如果此时该位置数据不为空(意味着该位置上可能有一个或者多个数据(以链表形式存在)),比较Key1和已经存在的数据的哈希值,如果都不相等则直接添加(添加在链表前面),如果相同则调用equals方法进行比较,返回false则添加,返回true则将value1值替换匹配位置的value值。在不断添加过程中,假如超过临界值(12)且要添加的位置非空,则将进行扩容,默认扩容为原来的2倍(左移)。
JDK8:
- JDK8中创建一个HashMap对象时候底层不会先创建一个长度为16的数组,而是创建一个空的Node[]数组,当首次执行put操作时候,底层才会创建一个长度为16的数组。
- JDK7中HashMap涉及到的结构只有数组+链表,在JDK8中还添加了红黑树结构,当数组中某一索引位置上的链表长度大于8且当前数据长度大于64时候,此时此索引位置上的所有数据都会改为红黑树存储。当链表长度大于8但是此时数据长度不大于64时候,就会执行扩容操作,而不是进行红黑树变换。
25.ConcurrentHashMap原理,JDK7和JDK8版本的区别
26.Java类加载器
- JDK自带三个类加载器:bootstrap ClassLoader、ExtClassLoader、AppClassLoader
- BootStrap ClassLoader是ExtClassLoader的父类加载器,默认负责加载%JAVA_HOME%lib下的jar包和class文件
- ExtClassLoader是AppClassLoaer的父类加载器,负责加载%JAVA_HOME%lib/ext文件夹下的jar包和class文件
- AppClassLoader是自定义类加载器的父类,负责加载classpath下的类文件。系统类加载器,线程上下文加载器继承ClassLoader实现自定义类加载器
27.双亲委派机制
- 系统类加载器及默认线程上下文加载器向上委派查找缓存是否加载了该类,有则直接返回,没有则继续向上;
- 当委派到顶层之后,缓存中还是没有,则到加载路径中查找,有则直接返回,没有则向下查找;
- 向下查找是查找加载路径,有则直接返回,没有则继续向下查找;
- 双亲委派主要是为了安全性,避免用户自己编写的类动态替换Java的一些核心类,比如String
- 同时也避免了类的重复加载,因为JVM中区分不同的类,不仅仅是根据类名,相同的class文件被不同的ClassLoader加载就是不同的两个类
28.Java中的异常体系
- Java中的所有异常都来自顶级父类Throwable
- Throwable下有两个子类Exception和Error
- Error是程序无法处理的错误,一旦出现这个错误,则程序被迫停止运行
- Exception不会导致程序停止,分为两个部分RunTimeException运行时异常和CheckedException检查异常
- RuntimeException常常发生在程序运行过程中,会导致程序当前线程执行失败,CheckedException常常发生在程序编译过程中,会导致编译不通过。
29.JAVA和C++的区别
虽然Java和C++都是面向对象语言,都支持封装、继承、多态,但是,它们还是有很多不同的地方:
- Java不提供指针直接访问内存,程序内存更安全
- Java的类是单继承的,而C++的类是可以多继承的,但是Java的接口可以实现多继承
- Java有自动内存管理垃圾回收机制(GC),不需要程序员手动释放内存
- C++同时支持方法重载和操作符重载(将符号重新定义,比如可以定义对象a+对象b),而Java只支持方法重载
30.成员变量和局部变量的区别
- 语法形式:从语法上看,成员变量属于类的,而局部变量是在代码块或者方法中定义的变量或者方法参数;成员变量可以被private、public、static等修饰符修饰,而局部变量不能被访问控制修饰符及static所修饰;但是成员变量和局部变量可以被final修饰。
- 存储方式:若一个成员变量被static修饰,那么它是属于类的,否则它是属于实例的,而对象存在于堆中,局部变量存在于栈中。
- 生存时间:若成员变量没有被static修饰,则成员变量是对象的一部分,它随着对象的创建而存在,而局部变量随着方法的调用而自动生成,随着方法的调用结束消亡。
- 默认值:如果成员变量没有赋初始值,这时候会自动赋予默认值(当然被final修饰的成员变量必须显示赋值),而局部变量不会自动赋值。
温馨提示:上面只是我总结的面经知识,如果你想要更全面的可以到网站自行查看喔。
友情链接:牛客网