目录
五:Session和Cookie的区别,Cookie可以被修改吗?
一:项目的系统开发和设计思路
一般来说系统的开发和设计思路的话,就是一般现在的项目基本上都是前后端分离架构来实现的,所以在项目的设计时,要分层次结构来划定。
前后端分离架构中,前端一般是有专业的前端工程师来写的,因此我们步需要过分的关注前端,可以在github上找到相关的前端项目即可。
而我们是后端开发工程师,因此在后端上着重关注,例如单体项目的话,可以选择springboot技术来实现,在数据库方面可以选择mysql来实现,然后在该架构上先实现项目的基本运行骨架,之后在骨架上添砖加瓦,例如若访问量过大可以选择缓存,而缓存的实现可以选择redis,但也要注意使用redis会遇到的问题(缓存雪崩,缓存击穿,缓存穿透,数据的意一致性等),若是数据量过大可以选择分库分表等技术。
但项目是微服务项目的话,可以选择springcloud技术来实现,然后要加强springcloud各个组件的使用和注意事项等。因此在项目的系统开发和设计思路方面要记住一点就是技术是服务于业务的,因此要注重业务的实现再去选择技术方案。
二:Java的反射是什么?在项目中有用到吗?
Java的反射就是程序在运行期间可以动态的获取类的基本结构信息,方法,变量,字段值等并且可以动态的创建对象,调用方法和修改字段值等。
在Java中获取反射类一般有三种方法:
1.通过class.forName()方法
Class UserClass = Class.forName("com.lcyy.interview.User");
2.通过类名.class方法
Class<User> userClass = User.class;
3.通过ClassLoder的.LoaderClass方法ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
Class<?> loadClass = systemClassLoader.loadClass("com.lcyy.interview.User");
在项目中没有显示的用到反射,但是侧面也用到了反射,例如,在项目的日志方面,使用的是springAOP来实现,AOP的底层实现是通过代理来实现,而代理有两种类型JDKproxy,CGLib代理,而JDKproxy的底层就是通过反射来实现的。还有在数据库层面的使用的mybatis底层也是通过反射来实现的。
三:多态的实现原理
多态是面向对象编程的一个重要的思想,指的是通过父类类型的引用变量来引用子类对象,并且在运行时根据对象的类型来确定调用哪个方法
而多态的底层实现主要是通过动态绑定+虚拟方法调用来实现
**动态绑定:**是指在编译时,编译器只知道变量的声明类型,而不知道实际的对象类型,在运行时JVM会动态绑定来解析具体的对象类型。
虚拟方法调用 :所有的非私有的,非静态的,非final修饰的方法都是隐式的指定为虚拟方法,虚拟机会根据实际对象的类型来确定要调用哪个方法。
因此可以总结为:多态的实现原理就是依靠的动态绑定+虚拟方法调用来实现的,主要流程如下:创建父类的引用变量,并将其赋值给子类对象,在运行时动态绑定来确定引用变量所指向的实际对象类型,然后根据实际对象的类型调用相应的方法。
四:项目中的redis是用在了哪里
redis是一个很实用的非关系型数据库,redis的适用场景有很多:
可以用redis来存储Session,可以用redis来实现JWT的session自动续期
分布式缓存的实现也可以用redis,布隆过滤器也可以用redis来实现。
redis还可以实现消息队列,延迟队列,使用特有的数据结构来实现点赞榜的排名和排行榜
五:Session和Cookie的区别,Cookie可以被修改吗?
①Cookie可以存储在浏览器或者本地,Session只能存在服务器
②session 能够存储任意的 java 对象,cookie 只能存储 String 类型的对象
③Session比Cookie更具有安全性(Cookie有安全隐患,通过拦截或本地文件找得到你的cookie后可以进行攻击)
④Session占用服务器性能,Session过多,增加服务器压力
⑤单个Cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个Cookie,Session是没有大小限制和服务器的内存大小有关
六:常见的网络攻击有哪些
常见的网络攻击有HTTP协议下的中间人攻击和DDOS攻击
中间人攻击 的完整流程:
A向B请求公钥,但是却被C截获。
C向B发送公钥请求。
B将公钥发给C。
C截获了B的公钥,然后替换成自己的公钥发给A。
A将C的公钥当成了B的公钥,并用其加密信息,发给B。
C截获了加密信息,用自己的私钥解密,获得明文。同时伪造新的信息,再用B的公钥加密,发给B。
B获得加密信息,用自己的私钥解密
DDOS攻击:
DDOS是从DOS的基础上发展而来的,有一台电脑对另一台电脑的攻击变成了多台电脑对一台电脑的攻击,Dos是一种拒绝服务(Denial of Service),DDos是一种分布式拒绝服务(Distributed Denial of Service)在互联网上DDOS攻击暴力而非常有效。表现为:你通过大量的数据包和目标服务器建立连接,占用目标服务器的带宽,导致目标服务器无法再去为正常的用户提供服务,表现为服务器炸了,如果是阿里云,当DDos攻击达到一定量,会触发阿里云服务器提供的"防御措施",服务器直接被冻结
七:索引的类型和底层实现
索引的分类: 可以从不同的类型来进行索引的分类,例如
按照字段类型分类:主键索引:一张表只有一个主键索引,不能重复且不能为null
唯一索引:一张表可以有多个唯一索引,不能重复,但可以为null
普通索引:一张表可以有多个普通索引,包含了多个字段,可以重复,可以为null
全文索引:是一种可以通过关键字来查找的一种索引
按照物理存储结构 来说,又可以分为
聚簇索引:一般来说是表中的主键索引,如果没有主键索引默认是表中第一个不能为null的唯一索引,如果还是没有则是InnoDB每行数据内置的6字节Rowid作为聚簇索引
非聚簇索引:二级索引,一个表中可以有多个非聚簇索引
按照数量 来分类,又可以分为
单列索引:对表中单个列进行创建的索引,适用于对单个列进行频繁的查询,排序或者过滤才会用到
联合索引:对多个列进行创建的索引,可以对多个列的值进行排序,查询等
索引的底层实现
mysql中大部分的存储引引擎是通过B+树来实现的,B+数中非叶子节点存储的是主键id,叶子节点存储的是数据值,因此查询性能是比较高的
B+树的特性:
1.非叶子节点只存储键值和指向下一节点的指针
2.所有叶子节点都在同一个级别,并且包含所有的键值和对应的数据行指针或者行数据
3.所有叶子节点在同一层上,采用双向链表连接,方便范围查询
八:项目中的日志记录用什么
单体项目中的日志记录通常采用的式spring自带的一个slf4j+Logback来实现,通常是在需要的采集日志的地方加上lombok的注解(@Sl4j)来实现
微服务项目中可以使用Skywalking进行链路追踪来实现错误日志和异常日志的输出。
九:手撕代码题
三个线程交替打印ABC
java
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
* 3 个线程交替打印 ABC
*/
public class ThreadLoopPrint {
// 共享计数器
private static int sharedCounter = 0;
public static void main(String[] args) {
// 打印的内容
String printString = "ABC";
// 定义循环栅栏
CyclicBarrier cyclicBarrier = new CyclicBarrier(3, () -> {
});
// 执行任务
Runnable runnable = new Runnable() {
@Override
public void run() {
for (int i = 0; i < printString.length(); i++) {
synchronized (this) {
sharedCounter = sharedCounter > 2 ? 0 : sharedCounter; // 循环打印
System.out.println(printString.toCharArray()[sharedCounter++]);
}
try {
// 等待 3 个线程都打印一遍之后,继续走下一轮的打印
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
};
// 开启多个线程
new Thread(runnable).start();
new Thread(runnable).start();
new Thread(runnable).start();
}
}
力扣283.移动零
java
class Solution {
public void moveZeroes(int[] nums) {
int left = 0,right = 0;
while(right < nums.length){
if(nums[right] != 0){
int temp = nums[left];
nums[left] = nums[right];
nums[right] = temp;
left++;
}
right++;
}
}
}