面试过去了一个月,现在也算靴子落地,入职软通,先后拿到四家公司的offer(倒不是今年疫情影响,是本人真的很菜),本地一家小公司薪资给的少直接放弃了,还有一个上海有智和美亚柏科的感觉面试没问多少东西问的也比较浅也放弃了,最后选择了现在的公司。
面试这么多家公司,还是不得不提一家公司---浙江大华,面试官面问题真的很有水准。强烈推荐。
下面是我这个月的一些面试总结:
Java基础
1:代码优化怎么做的
(1)尽可能使用局部变量
(2)及时关闭流
(3)尽量采用懒加载的策略,即在需要的时候才创建
(4)循环内不要不断创建对象引用
(5)尽量使用HashMap、ArrayList、StringBuilder,除非线程安全需要,否则不推荐使用Hashtable、Vector、
StringBuffer,后三者由于使用同步机制而导致了性能开销
2:项目中哪里用到了单例模式
(1)数据库连接池的设计一般也是采用单例模式
(2)多线程的线程池的设计一般也是采用单例模式,这是由于线程池要方便对池中的线程进行控制
(3)spring中的IOC的bean配置的scope="singleton",也是单例,scope="prototype"为多例模式
3: java的序列化和反序列化什么含义 生成的serialVersionUID有什么用
实现Serializbale接口,序列化的原本意图是希望对一个Java对象作一下“变换成字节序列,这样一来方便持久化存储到磁盘,避
免程序运行结束后对象就从内存里消失,另外变换成字节序列也更便于网络运输和传播
4:jdk lambda表达式几种使用方式,取最大和最小值
5:平时重构从哪方面考虑
(1)函数有没有扩展性
(2)函数写法优化
(3)有没有可复用的代码
6:怎么设计一个安全的对外接口
(1)数据加密
(2)数据加签
(3)时间戳机制
7:声明bean的几种方式
(1)基于XML的bean定义
(2)基于注解的bean定义
(3)基于Java类的bean定义
8:跨域什么?常见的解决方式有哪些?
(1):cors
(2):jsonp
(3):postMessage
8,List如何实现边遍历边删除?
Jdk8之后支持最便捷的办法使用removeIf()
集合
1, Hashmap原理,jdk1.7和1.8有什么区别
JDK1.7: 组成方式为数组+链表,线程不安全:因为采用头插入法:容易造成死锁与数据丢失
JDK1.8:组成采用数组+链表+红黑树。线程不安全:改为采用尾部插入,但仍会造成数据丢失
2:ConcurrentHashMap线程安全怎么实现的
采用分段锁,jdk1.8之后把锁的锁的粒度降得更低
3:常用集合中哪些集合是线程安全的?
Vector、HashTable、Properties是线程安全的; ArrayList、LinkedList、HashSet、TreeSet、HashMap、TreeMap等都是线程不安全的。
4:list转map,list中有重复的怎么办
(1)使用for循环
(2)利用JDK8中Collectors.toMap方法进行转换
流
1,常用到的IO流有哪些?两者有什么区别?
(1)常用字节流:InputStream和OutputStream。字节流也能对文本进行读取,但是它的主要使用的场景是读取无法直接获取文本
信息的二进制文件,比如音乐文件、视频文件、图片文件等等
(2)常用字符流:Reader和Writer。常用来对文本进行操作
区别:字节流中没有用到缓冲区,直接操作文件;而字符流中用到了缓冲区,先将数据放入缓冲区,再从缓存写入文件。
实际技巧
1:一般io操作会捕获异常,然后在catch中释放资源,有更简单的办法吗。
加上 finally方法,在finally中关闭资 源
设计模式
1:设计模式,说说简单工厂模式和抽象工厂模式怎么实现的,区别
2:代理模式,
它的核心思想,是将对目标的访问转移到代理对象上。这样做的好处就是,目标对象在不改变代码的情况下,可以通过代理对象加一
些额外的功能。这是一种编程思想,在不改变原有代码的情况下,通过代理增加一些扩展功能。代理模式包含三个接口:接口对象,
目标对象,代理对象,常见的代理模式分为静态代理和动态代理,
(1)静态代理的缺点的是不灵活,如果目标接口修改,那么目标对象与代理对象都得做出修改。
(2)java中的动态代理分为JDK动态代理和cglib代理,Jdk的动态代理由Proxy这个类来生成。CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。
Mybatis相关:
1,MyBatis二级缓存介绍
2,mybatis,一对一,一对多,多对多怎么做
一对一用association,一对多用collection,多对多collection里面嵌套collection
3,mybatis的#和$有什么区别
(1)#{}:是以预编译的形式,将参数设置到sql语句中;PreparedStatement;防止sql注入
(2)${}:取出的值直接拼装在sql语句中;会有安全问题;
数据库相关
1:数据库有哪几种索引
数据库索引分为:B+树索引(聚簇索引和辅助索引和联合索引),哈希索引和位图索引。
2:如何确定sql是否命中索引?
执行:explain select * from servers
3:sql优化处理方式
(1)分解关联查询
(2)SELECT子句中避免使用*号
(3)使用表或列的别名,使用简短的别名也能稍微提高一些SQL的性能
(4)用IN替代OR
4:mysql优化,什么时候不会用到索引
(1)select *,可能会导致不走索引
(2)where后面有函数运算,导致不走索引
(3)like查询使用通配符开头不会用到索引
5:jpa和mybatis区别
(1)jpa是对象与对象之间的映射,而mybatis是对象和结果集的映射
(2)jpa移植性比较好,不用关心用什么数据库,因为mybatis自由写sql语句,所以当项目移植的时候还需要改sql
6:什么是数据库死锁
是指两个或两个以上的事务在执行过程中,因争夺资源而造成的一种互相等待的现象。说明有等待才会有死锁,解决死锁可以通过去掉等待,比如回滚事务
7:mysql有一条数据死锁了,怎么排查问题,mysql表死锁,怎么排查
(1)通过应用业务日志定位到问题代码,找到相应的事务对应的sql
(2)确定数据库隔离级别
(3)找DBA执行下show InnoDB STATUS看看最近死锁的日志
8:mysql导入大量数据怎么优化
(1)insert批量执行,禁止单条insert value
(2)开启事务处理,批量提交
(3)主键顺序插入,效率更高
9:mybatis和jdbc怎么防止sql注入
JDBC 的 PrepareStatement 可以阻止 SQL 注入攻击,MyBatis 之类的 ORM 框架也可以阻止 SQL 注入,如何实现的?因
已经进行了预编译,在程序运行时第一次操作数据库之前,SQL语句已经被数据库分析,编译和优化,为SQL语句在程序运行前对应
的执行计划也会缓存下来并允许数据库已参数化的形式进行查询,当运行时动态地把参数传给PreprareStatement时,即
使参数里有敏感字符如 or '1=1’也数据库会作为一个参数一个字段的属性值来处理而不会作为一个SQL指令,如此,就起到了SQL注入的作用了
10:mysql事务隔离级别
(1)未提交读(READ UNCOMMITTED):事务的修改,即使没有提交,对其他事务也都是可见的
(2)已提交读(READ COMMITTED):一个事务只能看见已经提交的事务的修改结果
(3)可重复读(REPEATABLE REA):是MySQL的默认事务隔离级别
(4)串行化(SERIALIZABLE)
11:where和内连接有什么区别
12,左连接 ,右连接,内连接和全外连接的4者区别
left join (左连接):返回包括左表中的所有记录和右表中连接字段相等的记录。
right join (右连接):返回包括右表中的所有记录和左表中连接字段相等的记录。
inner join (等值连接或者叫内连接):只返回两个表中连接字段相等的行。
full join (全外连接):返回左右表中所有的记录和左右表中连接字段相等的记录。
Spring
1:springboot的启动过程(流程比较复杂,后续补充)
2:SpringMvc的启动过程
(1)一个请求匹配前端控制器 DispatcherServlet 的请求映射路径(在 web.xml中指定), WEB 容器将该请求转交给 DispatcherServlet 处理
(2)DispatcherServlet 接收到请求后, 将根据请求信息交给处理器映射器(HandlerMapping)
(3)HandlerMapping 根据用户的url请求 查找匹配该url的 Handler,并返回一个执行链
(4)DispatcherServlet 再请求 处理器适配器(HandlerAdapter) 调用相应的 Handler 进行处理并返回 ModelAndView 给 DispatcherServlet
(5)DispatcherServlet 将 ModelAndView 请求 ViewReslover(视图解析器)解析,返回具体 View
(6)DispatcherServlet 对 View 进行渲染视图(即将模型数据填充至视图中)
(7)DispatcherServlet 将页面响应给用户
3:SpringBoot热部署
深层原理是使用了两个ClassLoader,一个Classloader加载那些不会改变的类(第三方Jar包),另一个ClassLoader加载会更改
的类,称为restart ClassLoader,这样在有代码更改的时候,原来的restart ClassLoader 被丢弃,重新创建一个restart
ClassLoader,由于需要加载的类相比较少,所以实现了较快的重启时间。
4:springboot打包成jar之后,怎么做到不重新打包修改他的properties配置文件
(1)第一种方式手动指定spring.config.location配置文件位置:java -jar myspring.jar--spring.config.location=D:\JavaSite\config\application.properties
(2)根据配置文件优先级,在当前配置文件优先级之前创建配置文件,配置文件有优先级为
工程根目录:./config/
工程根目录:./
classpath:/config/
classpath:/
5:你用过SpringBoot的哪些注解
(1)启动项目相关的:
@SpringBootApplication,@EnableAutoConfiguration,@ComponentScan,@Configuration
(2)SpringBean相关的
@Autowirted,@Resource,@Compent,@Repository,@Service, @Controlle
@RestController(是@Controller+@ResponseBody的组合),@Configuration
(3)前后端传值:@RequestParam,@RequestBody,
(4)读取配置文件:@value,@ConfigurationProperties,PropertySource
6:Spring的Bean默认是单例还是多例,我想改成多例的怎么办
spring生成对象默认是单例的。修改scope属性值singleton改为prototyp
7:spring的ioc,aop怎么实现的
8:ioc容器有什么优点
IOC 或 依赖注入把应用的代码量降到最低。它使应用容易测试,单元测试不再需要单例和JNDI查找机制。最小的代价和最小的侵入
性使松散耦合得以实现。IOC容器支持加载服务时的饿汉式初始化和懒加载。
9:springboot和spring的不同
Spring Boot 只是 Spring 本身的扩展,使开发,测试和部署更加方便。
(1):内嵌 Servlet 容器,可以直接打成jar包,通过 java -jar xx.jar 运行项目。
(2):提供 starter pom 系列,简化maven的依赖加载,减少依赖冲突的发生。
(3)支持自动化配置,如下图。application.properties 文件在引入springboot和未引入springboot时,是不一样的。
10:springboot有哪些特性?
(1):组件自动装配
(2):嵌入式web 容器
(3):生产准备特性 指标、健康检查、外部化配置等
11:SpringBoot自动装配怎么实现的?
当我们的SpringBoot项目启动的时候,会先导入AutoConfigurationImportSelector,这个类会帮我们选择所有候选的配置,
我们需要导入的配置都是SpringBoot帮我们写好的一个一个的配置类,那么这些配置类的位置,存在与META-INF/
spring.factories文件中,通过这个文件,Spring可以找到这些配置类的位置,于是去加载其中的配置。
12:spring事务传播行为
spring支持7种事务传播行为,确定客户端和被调用端的事务边界,说得通俗一点就是多个具有事务控制的service的相互调用时所形成的复杂的事务边界控制
(1)required 表示当前方法必须在一个具有事务的上下文中运行,如有客户端有事务在进行,那么被调用端将在该事务中
运行,否则的话重新开启一个事务。(如果被调用端发生异常,那么调用端和被调用端事务都将回滚)
(2)supports 表示当前方法不必需要具有一个事务上下文,但是如果有一个事务的话,它也可以在这个事务中运行
(3)not_supported 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
(4)never 表示当方法务不应该在一个事务中运行,如果存在一个事务,则抛出异常
(5)mandatory 表示当前方法必须在一个事务中运行,如果没有事务,将抛出异常
(6)nested 支持当前事务,新增Savepoint点,与当前事务同步提交或回滚。
(7)requires_new 新建事务,如果当前存在事务,把当前事务挂起。
13:Spring事务隔离级别
1)DEFAULT (默认)
2)READ_UNCOMMITTED (读未提交)
3)READ_COMMITTED (读已提交)
4)REPEATABLE_READ (可重复读)
5)SERIALIZABLE(串行化)
14:aop实现方式,jdk动态代理和cglib动态代理区别
15:ioc容器有什么优点
16:SpringBoot如何解决跨域,具体怎么配置
SpringBoot可以基于Cors解决跨域问题,通过实现WebMvcConfigurer 接口,使用接口 中的addCorsMappings()方法,其中的构
造参数为CorsRegistry
17:spring怎么解决循环依赖
通过三级缓存
18:springBean生命周期
19:yml文件里有一些属性,怎么获取这些属性
(1):通过@Value
(2):@ConfigurationProperties
20:Spring用到了那些设计模式
简单工厂,工厂方法,单例,适配器,包装器, 代理,观察者, 策略
21:Springboot中的@SpringBootApplication是那三个注解的组合注解?
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
微服务
1:springcloud用过哪些组件
(1)Eruka注册中心(可实现服务高可用)
(2)Ribbon负载均衡组件(可实现负载均衡)
(3)Feign:基于Feign的动态代理机制,根据注解和选择的机器,拼接请求URL地址,发起请求
(4)gateway(网关组件)
(5)SpringCloudOatuh2(统一认证)
2: springcloud组件、用途,负载均衡的几种算法
3:eureka搭过集群吗
4:讲讲熔断机制
分布式
1:分布式session怎么解决
(1)粘性session
(2)服务器session复制
(3)session共享机制
算法
1:红黑树
Rabbitmq
1:Rabbitmq实现原理
2:rabbitmq重复消费怎么解决,除了数据库里查记录还有其他什么方法
3:分布式锁怎么实现,redis实现方式死锁怎么解决
(1)实现分布式锁定的最简单方法是直接创建一个锁定表并使用该表中的数据,如果要锁定方法或资源,请在表中添加一条记录,
以便在解除锁定时删除该记录,除了在操作数据表中添加和删除记录外,还可以使用数据库中提供的锁实现分布式锁定。
(2)基于redis来实现分布式锁,解决死锁方式未设置过期时间
(3)使用zookeeper来实现分布式锁
Redis:
1:redis查看内存占用命令:
用info命令就可以查看,如查看redis大的内存使用情况:info memory
2:redis持久化方式,有什么区别
(1):快照方式(RDB, Redis DataBase)
优势:
--- 适合大规模的数据恢复
--- 对数据完整性和一致性要求不高
劣势:
---在一定间隔时间做一次备份,所以如果redis意外down掉的话,就会丢失最后一次快照后的所有修改。
(2):文件追加方式(AOF, Append Only File)
优势:
--- 每次修改同步,每次发生数据变更会被立即记录到磁盘,性能 较差但数据完整性比较
--- 每秒同步:appendfsync everysec异步操作,每秒记录,如果一秒内宕机,仅一秒内的数据丢失
劣势:
--- 文件追加方式效率慢
(3):混合持久化方式
3:redis内存淘汰策略有几种
4:redis优点
(1)速度快,完全基于内存
(2)丰富的数据类型,Redis有8种数据类型,当然常用的主要是 String、Hash、List、Set、 SortSet 这5种类型
5:redis的缓存淘汰策略
JVM
1:JVM调过优吗?有哪些参数可以调,具体怎么调
2:jvm内存模型
3:jvm参数调优怎么做的
4:内存泄漏和溢出有什么区别
内存泄漏是指程序中动态分配的堆内存由于某种原因未释放或者无法释放,造成的程序运行速度变慢和崩溃等后果。GC无法回收。
内存溢出是通俗理解就是内存不够,是指系统中存在中无法回收的内存或者使用的内存过多,最终使程序运行大于能提供的最大内存。
线程
1:什么是线程安全?
当多个线程同时访问同一个对象时,调用这个对象的方法都可以得到正确的结果,那么我们称这个对象是线程安全的。
2:sleep和wait区别?
(1):wait() 是Object中定义的方法,所以每一个类的实例都可以调用这个方法。wait()只能在synchronized block中调用。
它会释 放synchronized时加在object上的锁。sleep()是定义Thread中的native静态类方法,所以Thread.sleep()可以在任何
情况下调用。Thread.sleep()将会暂停当前线程,并且不会释放任何锁资源
(2)wait是需要通过notify(),notifyAll()唤醒,sleep不需要唤醒,当设置的时间到了之后自动唤醒。
3:创建线程的几种方式,创建线程池几个参数的含义,线程饱和策略
线程池实现原理:
在线程池中存在几个概念:核心线程数、最大线程数、任务队列。核心线程数指的是线程池的基本大小;最大线程数指的是,
同一时刻线程池中线程的数量最大不能超过该值;任务队列是当任务较多时,线程池中线程的数量已经达到了核心线程数,这
时候就是用任务队列来存储我们提交的任务
4:线程池有哪些参数:
· 1. corePoolSize:线程池常驻核心线程数
· 2.maximumPoolSize:能够容纳的最大线程数
· 3.keepAliveTime:空闲线程存活时间
· 4.unit:存活时间单位
· 5.workQueue:存放提交但未执行任务的队列
· 6.threadFactory:创建线程的工厂类
· 7.handler:等待队列满后的拒绝策略
5:创建线程池有几种方式:
(1):newFixedThreadPool
(2):newSingleThreadExecutor
(3):newScheduleThreadPool
(4):newCachedThreadPool
6:线程拒绝策略(饱和策略):
(1)AbortPolicy:丢弃任务并抛出RejectedExecutionException异常
(2)DiscardOldestPolicy:丢弃队列最前面的任务,然后重新提交被拒绝的任务
(3)DiscardPolicy:丢弃任务,但是不抛出异常。
(4)CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务
7:有哪些队列,你线程池一般用哪种队列
8:lock和synchronized区别,最大的区别是
(1):Lock是一个接口,而synchronized是Java中的关键字
(2):synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主
动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;
9:synchronized是不是重量级锁
10:线程的run方法和start方法有什么区别
通常,系统通过调用线程类的start()方法来启动一个线程、此时该线程处于就绪状态,等待调度,即就是这个线程可以被JVM来调
度执行。在调度过程中,JVM底层通过调用线程类的run()方法来完成实际的操作,当run()方法结束后,此线程就会终止。
如果直接调用线程类的run()方法,此时run()方法仅仅被当做一个普通的函数调用,程序中仍然只有主线程这一个线程
start()方法能够异步的调用run()方法,但是直接调用run()方法却是同步的。
项目实际应用类问题
1:博客点赞功能的实现
2:项目中redis分布式锁怎么用的
3:实际项目开发中创建过什么索引,哪些情况建那些索引
4,hashMap平时用来干嘛
常见简单的代码逻辑
1:描述下文件下载的代码
2:描述下登录的代码逻辑