JD
职位描述: 1、负责制定应用运维管理体系的标准、流程、规范及落地实施,探索、研究新的应用运维技术方向; 2、负责应用服务系统的整体规划、架构设计及优化等工作,保障业务系统性能、可用性与稳定性; 3、负责应用系统灾备体系的建立; 4、负责处理系统方面日常变更、控制突发情况,对疑难问题进行分析并解决; 5、参与设计和优化应用服务系统的监控报警系统、策略和实施。
任职要求: 1、本科学士及以上,计算机科学,软件科学技术,电子信息工程等相关专业,应届毕业生; 2、有良好的Java基础知识,掌握Spring、SpringMVC、MyBatis、SpringBoot等主流框架技术的应用;具备良好的沟通交流能力、理解能力,条理清晰,认真负责,团队协作意识强;能够按要求撰写技术文档,有良好的工作计划制定和总结习惯;具有较强的学习和独立分析能力、工作责任心。
个人介绍
我是xxx, 我来自xxxx大学, 今年23岁, 我熟悉Java语法,了解Spring,SpringMVC,Springboot等常见web框架,熟悉Mybatis及MybatisPlus开发过程. 熟悉MySQL数据库,能熟练地进行增删改查等常见操作, 能编写复杂的SQL语句, 了解Mysql性能优化, 掌握SpringCloud微服务技术, 掌握分布式事务, 多线程等高性能开发技术. 在校期间获通过大学英语四级, 获得过计算机三级信息安全技术, 数学建模等奖项和证书.
知识准备
其他需要的查阅我之前的笔记即可.
在校项目-问答系统
MyBatis
SpringMVC开发流程
SpringBoot开发流程
使用的拦截器是HandlerInterceptor接口实现, 利用preHandle和afterCompletion做用户验证, 用户拦截和方向, 用户删除.
SpringCloud
用户存储
1private static final ThreadLocal<Long> tl = new ThreadLocal<>();
拦截器实现GlobalFilter接口, 利用filter方法做拦截.
JWT: 配置类实现keyPair方法利用加密文件和密码作为生成. 后面的keyPair来生成jwtSigner, 并且解密和加密都要用到.JWT.create()加密, JWT.of解密
Java三大特性
封装, 继承, 多态.
1、封装,就是将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问。
2、继承,就是子类拥有父类的所有属性和方法,从而实现了实现代码的复用。
3、多态,就是父类引用指向子类对象,从而产生多种形态。
工作中异常怎么处理
统一的异常处理包, 定义各种的异常. 有一个父异常继承的RuntimeException
工作中一般是用try catch处理异常而不是直接抛出去, 在catch部分会构造自己定义的异常, 然后写上异常的原因, 并且还可能发送日志或邮件进行记录.
throw和throws的区别
throws
和 throw
是 Java 中间的关键词,但它们的用法不同。
throws
关键字用于声明一种方法可能抛出的异常类型。它通常出现在方法的声明中,其次是一种或多种异常类型。在方法体内,可能会出现异常,但不会进行异常处理。调用此方法的代码需要异常处理。
throw
关键字用于手动抛出异常。它通常用于方法体内部,后面有一个异常对象。它表示代码运行过程中有特殊情况,需要立即抛出异常。
总之,throws
用于声明可能抛出的异常, throw
用于手动抛出异常。
八大排序算法
插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序、基数排序等
-
插入排序不说了.
-
希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。但希尔排序是非稳定排序算法。
希尔排序的基本思想: 先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。
-
选择排序, 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置, 再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
-
冒泡排序不说了.
-
归并排序将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。, 归并排序是递归算法的一个实例,这个算法中基本的操作是合并两个已排序的数组
-
快速排序不说了
-
堆排序, 堆是一个近似 完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。第一个非叶子节点,我们从它开始逐一向前分别把每个元素作为根节点进行 shift down 操作满足最大堆的性质。
操作就是先把一个序列映射到堆上(完全二叉树) ,从第一个非叶子节点进行shift down, 如何从一个最大堆中取出一个元素,称为 shift down
-
基数排序是桶排序的扩展,它的基本思想是:将整数按位数切割成不同的数字,然后按每个位数分别比较。 具体做法是:将所有待比较数值统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。
List为什么输出内容而不是地址
Object
类的toString()
方法中,返回的是 getClass().getName() + "@" + Integer.toHexString(hashCode())
也就是地址值,打印ArrayList
对象没有输出地址值,便可知道ArrayList
重写了toString()
方法.
不过这个重写是在外祖父那里重写的.
分析源码:
-
使用
Iterator
迭代器判断集合中是否含有元素,没有的话就只返回一对"[]" -
在循环外创建
StringBuilder
对象,先添加左方括号 -
循环集合,添加当前元素到
StringBuilder
对象 -
判断当前元素是否为最后一位,是则添加右方括号,执行
StringBuilder
的toString()
方法并返回,不是则添加一个逗号一位空格,继续下一层循环
常量优化机制
https://blog.csdn.net/li847250110/article/details/132112931
静态常量可以再编译器确定字面量,但常量并不一定在编译期就确定了, 也可以在运行时确定,所以 Java 针对某些情况制定了常量优化机制。
1、给一个变量赋值,如果“=”号右边是常量的表达式没有一个变量,那么就会在编译阶段计算该表达式的结果。 2、然后判断该表达式的结果是否在左边类型所表示范围内。 3、如果在,那么就赋值成功,如果不在,那么就赋值失败。
常量优化机制顾名思义,只能有常量参与表达式,不能有变量参与
这个有很多方面. 这里贴案例自己理解.
1byte b1 = 1 + 2;
2System.out.println(b1);
3// 输出结果 3
4
5byte b1 = 3;
6byte b2 = 4;
7byte b3 = b1 + b2;
8System.out.println(b3); // 程序报错
9
10byte b1 = 3;
11byte b2 = 4;
12byte b3 = b1 + b2;
13System.out.println(b3); // 程序报错
14byte b4 = b1 + 3;
15System.out.println(b4); // 程序报错
16
17byte b1 = 3;
18byte b3 = b1 + 4;
19System.out.println(b3); // 程序报错
20
21byte b1 = 127 + 2;
22System.out.println(b4); // 程序报错
23
24int num1 = 10;
25final int num2 = 10;
26byte var1 = num1 + 20; // 存在变量,编译报错
27byte var2 = num2 + 20; // 编译通过
28
29int a = 1;
30int b = 2;
31int c = a + b;
32System.out.println(c);
33
34 byte b=1;
35 byte c=2;
36 byte d=1+2;//编译通过正常执行
37 // byte e=b+c;//编译出错
38 byte e=(byte)(b+c);//强转之后不会出错
39
40
41byte var = 10;
42var = var + 20; // 编译报错,运算中存在变量
43var += 20; // 等效于: var = (short) (var + 20); 没有走常量优化机制,而是进行了类型转换
44
45String s1 = "abc";
46String s2 = "a"+"b"+"c";
47System.out.println(s1 == s2); //true
48
49String a = "a1";
50String b = "a" + 1;
51System.out.println((a == b)); //result = true
52
53String a = "atrue";
54String b = "a" + true;
55System.out.println((a == b)); //result = true
56
57String a = "a3.4";
58String b = "a" + 3.4;
59System.out.println((a == b)); //result = true
60
61
62String s1 = "ab";
63String s2 = "abc";
64String s3 = s1 + "c";
65System.out.println(s3 == s2); //false
66
67
为什么小数不能进行常量优化
HTTP和HTTPS的区别
1、https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
3、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
4、http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
TCP协议三次握手和四次挥手
三次握手(开始交流)
第一次:客户端向服务端发送连接请求报文段,标识为syn(建立连接),产生一个序列号seq=x,表明传送数据时的第一个数据字节序号为 x
第二次:服务端的TCP 收到连接请求报文段后,如果同意,则发挥连接同意报文
服务端在连接同意报文中使用俩个标识SYN和ACK,其随机序列号为seq=y,确认序列号为ack=x+1
第三次:客户端收到服务端的报文,发送确认报文ACK,随机序列号为seq=x+1,ack=y+1
四次挥手(挥手再见)
TCP是基于全双工通信的,所以双方都可以主动释放连接。 四次挥手的意义就在于,当 A 发送完最后一条数据之后,但可能B还有未发送给A 的数据。 所以A在发送完收据后可以请求释放连接,此时B给与A响应,告诉A我知道你想断开连接,此时A还可以继续接收B发送的信息。 在B处理完工作后,也请求释放连接。A同意后,就断开连接。 这样可以保证数据正常可靠的交互。
第一次:数据传输结束后,通信双方都可以释放连接
假设A已经向B传输完数据,A就可以发生释放连接报文段,并停止发送数据,主动关闭TCP连接
A 连接释放报文首部 FIN,其序列号 seq = u,等待 B 的确认。
第二次:B收到后,发送确认报文,意思是我收到了确认号 ack = u+1,而这个报文段自己的序号为seq = v
从A 到 B 这个方向的连接就释放了,TCP 连接处于半关闭状态。B 若发送数据,A仍需要接收
第三次:当B发送完数据后,就可以释放连接。
B 发出的连接释放报文 的 FIN,序号为w,ack仍为u+1
第四次: A 收到连接释放报文后,必须发出确认。确认好 ack = w +1,序号seq = u+1。
(ack都是在seq的基础上+1, 而sql要么是新生成的, 要么是ack的.)
如何遍历map数据
-
使用
for-each
循环遍历Map.Entry
1for (Map.Entry<String, Integer> entry : map.entrySet()) { 2 System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue()); 3}
-
使用 for-each 循环遍历 keySet
1for (String key : map.keySet()) { 2 Integer value = map.get(key); 3 System.out.println("Key: " + key + ", Value: " + value); 4 }
-
使用 Iterator 遍历 Map.Entry
1Iterator<Map.Entry<String, Integer>> iterator = map.entrySet().iterator(); 2 while (iterator.hasNext()) { 3 Map.Entry<String, Integer> entry = iterator.next(); 4 System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue()); 5 }
-
使用 Stream API 遍历 Map
1map.entrySet().stream() 2 .forEach(entry -> System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue())); 3 } 4
HashMap为什么要扩容
HashMap的默认大小是16。
当HashMap里面的元素个数超过临界值的时候会自动触发扩容。等于负载因子 乘以 容量大小,负载因子的默认值是0.75,而容量大小默认是16,。也就是说,第1次扩容的动作会在元素个数达到12的时候触发,扩容的大小是原来的2倍。HashMap的最大容量是Integer.MAX_VALUE也就是2的31次方减1。
由于动态扩容机制的存在,所以我们在实际应用的时候,最好在集合初始化的时候明确去指定集合的大小,从而避免频繁扩容带来性能上的消耗。
JVM内存模型
方法区, 虚拟机栈, 本地方法栈, 堆(新生代, 老年代), 程序计数器
工作中SQL如何优化的
- 对insert, 分成多个insert, 按主键顺序插入.同时手动事务提交. 或者用load指令
- 对主键, 降低主键长度, 插入数据尽量顺序插入, 尽量不要使用UUID做主键或者其他自然主键, 如身份证, 业务操作避免对主键的修改.
- 对order by, 根据排序字段建立合适的索引, 多字段排序时, 遵循最左前缀法则. 尽量使用覆盖索引, 多字段排序, 一个升序一个降序, 此时需要注意联合所以在创建时的规则, 如果不可避免的出现filesort, 大数据量排序时, 可以适当增大排序缓冲区大小
- 对于group by, 还是根据分组字段创建索引, 准寻最左前缀法则
- 对于limit分页, 一般分页查询时, 通过创建覆盖索引能够较好地提高性能, 可以通过覆盖查询+子查询的形式进行优化
- count, count(*) ≈ count(1) > count(主键) > count(字段)
- update, Innodb的行锁是针对索引加的锁, 不是针对记录加的锁, 使用的条件一定要有索引不然就是表锁; 该索引不能失效, 否则行锁变为列锁
Spring和SpringMVC的区别(实现原理)
Spring是一个综合性的应用程序开发框架,提供了依赖注入、面向切面编程、事务管理等功能,旨在简化企业级应用程序的开发。而Spring MVC是Spring框架中的一个模块,用于Web应用程序的开发,实现了MVC(Model-View-Controller)模式。
Spring的核心功能是IoC容器和AOP,它可以帮助开发者管理对象之间的依赖关系,实现松耦合的应用程序设计。而Spring MVC的核心功能是控制器、视图解析器等Web相关组件,用于协调请求和响应之间的关系,实现Web应用程序的开发。
Spring是一个综合性的框架,可以与其他模块集成,如Hibernate、iBatis、JMS、JDBC等。而Spring MVC是基于Spring功能之上添加的Web框架,它已经集成了这些模块的功能,使得开发者可以更快速地开发Web应用程序。
为什么用SpringBoot, 去掉SSM框架
编码更简单(与第三方框架快速整合), 配置变得更简单(Application.yaml, 不需要多个配置文件), 部署更简单(启动类Application一键部署, 不需要tomcat).
SpringMVC, SpringBoot, SpringCloud三者区别
Spring和SpringMVC:Spring是一站式轻量级java开发框架,其核心是控制反转(IOC)和面向切面(AOP),为开发WEB层而开发的WEB(springMvc)、业务层(Ioc)、持久层(jdbcTemplate)SpringMVC是Spring基础上的MVC框架,主要处理web开发的路径映射和视图渲染,属于spring框架中web层开发的一部分;
SpringMVC VS SpringBoot:SpringMVC属于企业WEB开发的MVC框架,包括前端视图开发、文件配置、后台接口逻辑开发等,XML、config等配置比较复杂;与SpringMVC框架相比,SpringBoot框架更注重微服务后台接口的开发,而不是前端视图的开发;
SpringBoot和SpringCloud:SpringBoot采用默认大于配置的概念,集成了快速开发的多个Spring插件,自动过滤不需要配置的多余插件,简化了项目的开发配置过程,在一定程度上取消了xml配置,是一套快速配置开发的脚手架,单个微服务可以快速开发;SpringCloud的大部分功能插件都是基于SpringBoot实现的。SpringCloud注重整体微服务的整合和管理,整合和管理多个SpringBoot单个微服务;SpringCloud依赖于SpringBoot开发,SpringBoot可以独立开发;
@Autowired和@resource区别
1.来源不同 @Autowired 和 @Resource 来自不同的“父类”,其中 @Autowired 是 Spring 定义的注解,而 @Resource 是 Java 定义的注解
2.依赖查找顺序不同 依赖注入的功能,是通过先在 Spring IoC 容器中查找对象,再将对象注入引入到当前类中。而查找有分为两种实现:按名称(byName)查找或按类型(byType)查找,其中 @Autowired 和 @Resource 都是既使用了名称查找又使用了类型查找,但二者进行查找的顺序却截然相反。 @Autowired 先根据类型(byType)查找,如果存在多个(Bean)再根据名称(byName)进行查找; @Resource 先根据名称(byName)查找,如果(根据名称)查找不到,再根据类型(byType)进行查找。
3.支持的参数不同
4.依赖注入的支持不同 @Autowired 支持属性注入、构造方法注入和 Setter 注入,而 @Resource 只支持属性注入和 Setter 注入