JAVA面经—23届秋招面经总结----(七)
苏小妍10.18 一面(Java开发):
1.自我介绍
2.学过哪些课程?
3.继承与实现的区别
- 数量不同:java只支持接口的多继承,不支持“继承”的多继承,继承在java中具有单根性,子类只能继承一个父类。总结就是:单继承,多实现。
- 修饰不同:继承:extends;实现:iimplements
- 属性不同:在接口中只能定义全局变量和无实现的方法。而在继承中可以定义属性方法,变量,常量等。
- 调用不同:当接口被类实现时,在类中一定要实现接口中的抽象方法;而继承想调用哪个方法就调用哪个方法。
4.重载重写的区别
- 方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。
重写发生在子类与父类之间, 重写方法返回值和形参都不能改变,与方法返回值和访问修饰符无关,即重载的方法不能根据返回类型进行区分。即外壳不变,核心重写!
重载(overloading) 是在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同。每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。最常用的地方就是构造器的重载。
5.重载相同方法名怎样区分?
根据参数类型或者返回值类型区分。
6. 重载的方法能否根据返回值类型进行区分?
不能。
7.多态的理解
本质上多态分两种:
1、编译时多态(又称静态多态,如:重载(overload))
2、运行时多态(又称动态多态,如:重写(override))
我们通常所说的多态指的都是运行时多态,也就是编译时不确定究竟调用哪个具体方法,一直延迟到运行时才能确定。这也是为什么有时候多态方法又被称为延迟方法的原因。
Java实现多态有 3 个必要条件:继承、重写和向上转型。只有满足这 3 个条件,开发人员才能够在同一个继承结构中使用统一的逻辑实现代码处理不同的对象,从而执行不同的行为。
继承:在多态中必须存在有继承关系的子类和父类。
重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。
向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才既能可以调用父类的方法,又能调用子类的方法。
8.List和Set的区别
- List特点:元素有放入顺序,元素可重复 。
- Set特点:元素无放入顺序,元素不可重复,重复元素会覆盖掉。
9.final修饰的变量可以修改吗?修饰对象的情况呢?
- final修饰的变量不可修改。
- final修饰的对象,内容可变,引用不可变。
10. threadlocal了解吗?
ThreadLocal,即线程本地变量。如果你创建了一个ThreadLocal变量,那么访问这个变量的每个线程都会有这个变量的一个本地拷贝,多个线程操作这个变量的时候,实际是操作自己本地内存里面的变量,从而起到线程隔离的作用,解决了线程安全问题。
内存泄露问题:如果ThreadLocal(ThreadLocalMap的Key)被垃圾回收器回收了,但是因为ThreadLocalMap生命周期和Thread是一样的,它这时候如果不被回收,就会出现这种情况:ThreadLocalMap的key没了,value还在,这就会「造成了内存泄漏问题」。
11. 乐观锁和悲观锁了解吗?
-
乐观锁:总是乐观地假设最好的情况,每次去拿数据的时候都认为别人不会修改这个数据,所以不会上锁,只会要对数据进行更新时判断一下在此期间(拿到数据到更新的期间)别人有没有去更改这个数据,可以使用版本号机制和CAS(Compare And Swap)算法实现。
-
悲观锁:总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。Java中Synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。
12.线程池核心参数的作用与执行流程,默认的丢弃策略
- corePoolSize : 核心线程大小。线程池一直运行,核心线程就不会停止。
- maximumPoolSize :线程池最大线程数量。非核心线程数量=maximumPoolSize-corePoolSize
- keepAliveTime :非核心线程的心跳时间。如果非核心线程在keepAliveTime内没有运行任务,非核心线程会消亡。
- workQueue :阻塞队列。ArrayBlockingQueue,LinkedBlockingQueue等,用来存放线程任务。
- defaultHandler :饱和策略。ThreadPoolExecutor类中一共有4种饱和策略。通过实现RejectedExecutionHandler接口。
(AbortPolicy : 线程任务丢弃报错。默认饱和策略。) - ThreadFactory :线程工厂。新建线程工厂。
执行流程:
- 线程池执行execute/submit方法向线程池添加任务,当任务小于核心线程数corePoolSize,线程池中可以创建新的线程。
- 当任务大于核心线程数corePoolSize,就向阻塞队列添加任务。
- 如果阻塞队列已满,需要通过比较参数maximumPoolSize,在线程池创建新的线程,当线程数量大于maximumPoolSize,说明当前设置线程池中线程已经处理不了了,就会执行饱和策略。
13.了解的设计模式有哪些,设计模式的原则有哪些?
- 单例模式、工厂模式。
- 单一职责原则 (Single Responsibility Principle)
- 开放-关闭原则 (Open-Closed Principle)
- 里氏替换原则 (Liskov Substitution Principle)
- 依赖倒转原则 (Dependence Inversion Principle)
- 接口隔离原则 (Interface Segregation Principle)
- 迪米特法则(Law Of Demeter)
- 组合/聚合复用原则 (Composite/Aggregate Reuse Principle)
14.什么是依赖注入?
- 依赖:bean对象的创建依赖于容器!
- 注入:bean对象中的所有属性,由容器来注入!
15.注入的方式有几种?
- 构造函数注入
- setter 注入
- 接口注入(命名空间注入,p命名和c命名空间注入,不能直接使用,需要导入xml约束!)
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
16.注入可能会产生循环依赖,了解什么是循环依赖吗?
①构造器的循环依赖:这种依赖spring是处理不了的,直 接抛出BeanCurrentlylnCreationException异常。
②单例模式下的setter循环依赖:通过“三级缓存”处理循环依赖。
③非单例循环依赖:无法处理。
出现情况:A的某个field或者setter依赖了B的实例对象,同时B的某个field或者setter依赖了A的实例对象。
17.了解AOP吗?事务的回滚通过什么注解实现?
-
Spring AOP :面向切面编程,实现横切逻辑的控制,现在项目开发是分层开发,第一层是controller 层(各种controller)、service层、dao层,横切是在每一层之间进行切割,横切时,可以给service层加事务的控制,这个时候在操作数据库操作出现问题时,需要对事务进行回滚时,从而保证数据的一致性。
因为事务的操作可能会涉及到多个表的操作,所以需要通过切面操作,保证事务的边界放在service层。
AOP的底层是动态代理,动态代理的实现有两种方法:JDKproxy JDK 动态代理:通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口 。CGLIB 如果目标类没有实现接口,那么 Spring AOP 会选择使用 CGLIB 来动态代理目标类 。 -
@Transactional
18.索引的分类?
1、从存储结构上来划分:BTree索引(B-Tree或B+Tree索引),Hash索引,full-index全文索引,R-Tree索引。这里所描述的是索引存储时保存的形式,
2、从应用层次来分:普通索引,唯一索引,复合索引。
普通索引:即一个索引只包含单个列,一个表可以有多个单列索引
唯一索引:索引列的值必须唯一,但允许有空值
复合索引:多列值组成一个索引,专门用于组合搜索,其效率大于索引合并
聚簇索引(聚集索引):并不是一种单独的索引类型,而是一种数据存储方式。具体细节取决于不同的实现,InnoDB的聚簇索引其实就是在同一个结构中保存了B-Tree索引(技术上来说是B+Tree)和数据行。
非聚簇索引: 不是聚簇索引,就是非聚簇索引
加粗样式
3、根据中数据的物理顺序与键值的逻辑(索引)顺序关系: 聚集索引,非聚集索引。
19.为什么用B+树作索引?
-
B+树的磁盘读写代价更低:B+树的内部节点并没有指向关键字具体信息的指针,因此其内部节点相对B(B-)树更小,如果把所有同一内部节点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多,一次性读入内存的需要查找的关键字也就越多,相对IO读写次数就降低了。
-
由于B+树的数据都存储在叶子结点中,分支结点均为索引,方便扫库,只需要扫一遍叶子结点即可,但是B树因为其分支结点同样存储着数据,我们要找到具体的数据,需要进行一次中序遍历按序来扫,所以B+树更加适合在区间查询的情况,所以通常B+树用于数据库索引。
20.索引下推了解吗?
**作用:**减少回表次数。
官方例子和解释如下:
在 people_table中有一个二级索引(zipcode,lastname,address),查询是SELECT * FROM people WHERE zipcode=’95054′ AND lastname LIKE ‘%etrunia%’ AND address LIKE ‘%Main Street%’;
如果没有使用索引下推技术,则MySQL会通过zipcode=’95054’从存储引擎中查询对应的数据,返回到MySQL服务端,然后MySQL服务端基于lastname LIKE ‘%etrunia%’ and address LIKE ‘%Main Street%’来判断数据是否符合条件
如果使用了索引下推技术,则MYSQL首先会返回符合zipcode=’95054’的索引,然后根据lastname LIKE ‘%etrunia%’ and address LIKE ‘%Main Street%’来判断索引是否符合条件。如果符合条件,则根据该索引来定位对应的数据,如果不符合,则直接reject掉。
21.事务的隔离级别,默认隔离级别是什么?
- Read Uncommitted(读取未提交内容)
- Read Committed(读取提交内容)
- Repeatable Read(可重读)(默认级别)
- Serializable(可串行化)
22.可重复读会产生什么情况?怎么解决?
会产生幻读:系统管理员 A 将数据库中所有学生的成绩从具体分数改为 ABCDE 等级,但是系统管理员 B 就在这个时候插入了一条具体分数的记录,当系统管理员 A 改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。
**解决:**通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。
23.MVCC了解吗?
MVCC, 即多版本并发控制。MVCC 的实现,是通过保存数据在某个时间点的快照来实现的。根据事务开始的时间不同,每个事务对同一张表,同一时刻看到的数据可能是不一样的。
24.Mysql有哪些锁?
按照锁的粒度把数据库锁分为:
- 行级锁
- 表级锁
- 页级锁
从锁的类别上来讲,分为: - 共享锁(读锁),当用户要进行数据的读取时,对数据加上共享锁。共享锁可以同时加上多个。
- 排他锁(写锁),当用户要进行数据的写入时,对数据加上排他锁。排他锁只可以加一个,他和其他的排他锁,共享锁都相斥。