以下是我记录的一些重点问题和面试中被问到没答上来的问题,包括java基础、关系型数据库、Redis、计算机网络、Spring、Java多线程、vue
fail-safe: 安全失败,concurrent包下的容器都是该机制,可以在多线程下并发修改
fail-fast:快速失败,如果Java集合在使用迭代器遍历的过程中进行了增删操作则会抛出异常即使没有并发也会抛出
强引用: A a=new A(); GC永远不会回收这种对象
软引用: 有用但是非必须对象 在发送OOM时会把这些对象进行二次回收
弱引用: 非必须对象 被弱引用关联的对象只能生存到下次GC前
虚引用: 最弱的一种引用关系 存在的目的就是能在这个对象被GC时收到一个系统通知
id:标识符
type:表的连接类型
1.clean:清理项目
pre-clean(执清理前需要完成的工作)–> clean(清除上次构建过程中生成的文件,比如编译后的class文件)—>post-clean:(执行清理后需要完成的工作)
2.default:构建项目
Default生命周期是Maven生命周期中最重要的一个,绝大部分工作都发生在这个生命周期中。
其中比较重要和常用的阶段:
validate:检测项目结构是否正常,必要的配置文件是否存在
initialize:做构建前的初始化操作,比如初始化参数,创建必要目录
generate-sources:产生在编译过程中需要的源代码
process-sources:处理源代码,比如过滤值
compile:编译项目源代码
process-classes:产生编译过程中生成的文件
generate-test-sources:产生编译过程中测试相关的代码
process-test-sources:处理测试代码
generate-test-resources:产生测试中资源在classpath中的包
process-test-resources:复制并处理资源文件,至目标测试目录
test-compile 编译测试源代码。
process-test-classes 产生编译测试代码过程的文件test 使用合适的单元测试框架运行测试。这些测试代码不会被打包或部署。
prepare-package 处理打包前需要初始化的准备工作
package 接受编译好的代码,打包成可发布的格式,如 JAR 。
pre-integration-test 做好集成测试前的准备工作,比如集成环境的参数设置
integration-test 集成测试
post-integration-test 完成集成测试前的准备工作,比如集成环境的参数设置
verify 检测测试后的包是否完好
install 将包安装至本地仓库,以让其它项目依赖。
deploy 将最终的包复制到远程的仓库,以让其它开发人员与项目共享。
运行任何一个阶段的时候,它前面的所有阶段都会被运行,这也就是为什么我们运行mvn install 的时候,代码会被编译,测试,打包。此外,Maven的插件机制是完全依赖Maven的生命周期的,因此理解生命周期至关重要。
3.site:生项目站点
pre-site:执行一些需要在生成站点文档之前的操作
site:生成项目的站点文档
post-site:执行一些需要在生成站点文档之后完成的工作,并为部署做准备
site-destory:将生成的站点文档部署到特定服务器上
这里经常用到的是site阶段和site-deploy阶段,用以生成和发布Maven站点,这可是Maven相当强大的功能,Manager比较喜欢,文档及统计数据自动生成,很好看。
如何创建表在mysql中?
方法:使用关键字create.
例子:create table demo.person {
age int ,
weight int,
hobby varchar
}
如何修改表结构?
场景1.修改字段
方法1:使用关键词alter 、change,可以改变表字段的名称和类型,但是转换的类型有限制,不能从数值类型转换为字符类型.
例子:alter table demo.person change age year int ;
方法2:使用关键词alter 、modify,可以改变类型,但是转换的类型有限制,不能从数值类型转换为字符类型.
例子:alter table demo.person modify age int ;
场景2.新增字段
方法1:使用关键词alter 、add,可以新增表字段;
例子:alter table demo.person add father varchar
1NF:属性不可再分
2NF:满足第一范式;且不存在部分依赖,即非主属性必须完全依赖于主属性。(主属性即主键;完全依赖是针对于联合主键的情况,非主键列不能只依赖于主键的一部分)
3NF:满足第二范式;且不存在传递依赖,即非主属性不能与非主属性之间有依赖关系,非主属性必须直接依赖于主属性,不能间接依赖主属性。
String值创建后不能修改,任何对String的修改都会引发新的String对的生成
StringBuffer:跟String类似,但是值可以修改,使用synchronized来保证线程安全
StringBuilder:StringBuffer的非线程安全版本
NullPointerException:
NumberFormatException:字符转换异常
IOException:IO异常
FileNotFoundException:
缓存 点赞、排行榜、计数器等功能 共享session 分布式锁 消息中间件
避免走全表,
1.在where order by的列上建立索引
2.避免null判断
3.少使用计算、函数、类型转换(字符串单引号)
4.少用!= <>
5.少用or
父类静态变量(静态代码块)-》子类静态变量-》父类非静态变量–》父类构造器–》子类非静态变量–》子类构造器
HTTP明文传输,安全上有窃听、篡改、冒充风险
HTTPS通过混合加密来解决窃听 摘要算法来解决篡改 数字证书解决冒充
(1)offer()和add()区别:
增加新项时,如果队列满了,add会抛出异常,offer返回false。
(2)poll()和remove()区别:
poll()和remove()都是从队列中删除第一个元素,remove抛出异常,poll返回null。
(3)peek()和element()区别:
peek()和element()用于查询队列头部元素,为空时element抛出异常,peek返回null。
采用Collections包下的unmodifiableMap方法,通过这个方法返回的map,是不可以修改的。他会报 java.lang.UnsupportedOperationException错。
同理:Collections包也提供了对list和set集合的方法。
Collections.unmodifiableList(List)
Collections.unmodifiableSet(Set)
java中方法用final修饰参数的作用
在方法参数前面加final关键字就是为了防止数据在方法体重被修改。
主要分为两种情况:第一,用final修饰基本数据类型;第二,用final修饰引用数据类型。
第一种情况,修饰基本数据类型,这时参数的值在方法体内是不能被修改的,即不能被重新赋值。否则编译就不通过。
第二种情况,修饰引用类型。这时参数变量所引用的对象是不能被改变的。但是对于引用数据类型,如果修改其属性的话是完全可以的。
所以,final这个关键字,想用的话就用基本数据类型,还是很有作用的。
final变量:
对于基本类型使用final:它就是一个常量,数值恒定不变
对于对象引用使用final:使得引用恒定不变,一旦引用被初始化指向一个对象,就无法再把 它改为指向另一个对象。然而,对象自身却是可以被修改的,java并没有提供使任何对象恒定不变的途径。这一限制同样也使用数组,它也是对象。
什么是CAS问题?
当执行campare and swap会出现失败的情况。例如,一个线程先读取共享内存数据值A,随后因某种原因,线程暂时挂起,同时另一个线程临时将共享内存数据值先改为B,随后又改回为A。随后挂起线程恢复,并通过CAS比较,最终比较结果将会无变化。这样会通过检查,这就是ABA问题。 在CAS比较前会读取原始数据,随后进行原子CAS操作。这个间隙之间由于并发操作,最终可能会带来问题。
如何解决?
设置版本号
通常来说,我们的 JVM 参数配置大多还是会遵循 JVM 官方的建议,例如:
jvm.gc.time:每分钟的GC耗时在1s以内,500ms以内尤佳
jvm.gc.meantime:每次YGC耗时在100ms以内,50ms以内尤佳
jvm.fullgc.count:FGC最多几小时1次,1天不到1次尤佳
jvm.fullgc.time:每次FGC耗时在1s以内,500ms以内尤佳
1.分析和定位当前系统的瓶颈
(1)CPU
1)CPU指标
2)JVM 内存指标
JDK1.8 中,由于多线程对HashMap进行put操作,调用了HashMap#putVal(),具体原因:假设两个线程A、B都在进行put操作,并且hash函数计算出的插入下标是相同的,当线程A执行完第六行代码后由于时间片耗尽导致被挂起,而线程B得到时间片后在该下标处插入了元素,完成了正常的插入,然后线程A获得时间片,由于之前已经进行了hash碰撞的判断,所有此时不会再进行判断,而是直接进行插入,这就导致了线程B插入的数据被线程A覆盖了,从而线程不安全。
AOF:
用 AOF 日志的方式来恢复数据其实是很慢的,因为 Redis 执行命令由单线程负责的,而 AOF 日志恢复数据的方式是顺序执行日志里的每一条命令,如果 AOF 日志很大,这个「重放」的过程就会很慢了。
RDB:
在 Redis 恢复数据时, RDB 恢复数据的效率会比 AOF 高些,因为直接将 RDB 文件读入内存就可以,不需要像 AOF 那样还需要额外执行操作命令的步骤才能恢复数据。
从左到右
过滤器(Filter):用于属性甄别,对象收集(不可改变过滤对象的属性和行为)
拦截器(Interceptor):用于对象拦截,行为干预(可以改变拦截对象的属性和行为)
拦截器本质上是面向切面编程(AOP),符合横切关注点的功能都可以放在拦截器中来实现,主要的应用场景包括:
过滤器应用场景:
创建前、创建后、载入前、载入后、更新前、更新后、销毁前、销毁后。
对于GET:
后端用@RequestParam
@GetMapping("/listtest")
public Integer test(@RequestParam List<Integer> arr){
for (Integer i : arr) {
System.out.println(i);
}
return 1;
}
对于POST:
使用@RequestBody
@PostMapping("/postlist")
public String test2(@RequestBody List<Integer> arr){
for (Integer i : arr) {
System.out.println(i);
}
return "hello";
}
@Value
用于注入application.yml定义的属性
public class A{
@Value("${push.start:0}") 如果缺失,默认值为0
private Long id;
}
@RestController
组合@Controller 和@Response Body
@RequestParam
获取request请求的参数值
public List<CopperVO> getOpList(HttpServletRequest request,
@RequestParam(value = "pageIndex", required = false) Integer pageIndex,
@RequestParam(value = "pageSize", required = false) Integer pageSize) {
}
@ResponseBody
支持将返回值放在response体内,而不是返回一个页面。比如Ajax接口,可以用此注解返回数据而不是页面。此注解可以放置在返回值前或方法前
@PathVariable
用来获得请求url中的动态参数
@Import(Config1.class)
导入Config1配置类里实例化的bean
@Configuration
public class CDConfig {
@Bean // 将SgtPeppers注册为 SpringContext中的bean
public CompactDisc compactDisc() {
return new CompactDisc(); // CompactDisc类型的
}
}
@Configuration
@Import(CDConfig.class) //导入CDConfig的配置
public class CDPlayerConfig {
@Bean(name = "cDPlayer")
public CDPlayer cdPlayer(CompactDisc compactDisc) {
// 这里会注入CompactDisc类型的bean
// 这里注入的这个bean是CDConfig.class中的CompactDisc类型的那个bean
return new CDPlayer(compactDisc);
}
}
局部变量太多会导致GC多 因为局部变量会被频繁回收
根据迪米特法则,应减少陌生的类作为局部变量,会增加耦合
局部变量位于jvm栈,递归层数多时可能引起栈溢出
局部变量是线程私有(线程封闭的)
String str=“a”+"b"创建了几个对象?
一个 String常量的累加操作中,编译器会进行优化,如果是 String str = “a” + “b”,那相当于String str = “ab”; ,常量池中会创建一个ab的对象
String str = new String(“a”) + new String(“b”)几个?
在堆中创建了三个字符串对象(a字符串对象,b字符串对象,ab字符串对象),在堆中的常量池中创建了2个字符串对象(a字符串对象,b字符串对象),一共创建了5个字符串对象。
Sting s="a"和String s=new String(“a”)区别?
两个语句都会先去字符串常量池检查是否存在a 如果有则直接使用 如果没有则在常量池中创建 a 对象
另外String s =new String(“a”)还会在堆离创建一个 a 的对象实例
所以前者被后者包含
建立TCP连接过程
调用系统函数 socket (),创建并绑定一个 IP 地址和端口。
调用系统函数 listen (),进行地址监听。此时可以通过 netstate 命令查看对应端口是否被监听。
调用系统函数 accept (),从内核获取客户端的连接,如果没有客户端进行连接,则会阻塞等待。
最后调用完成需要close() 连接