文章目录
- 八大基本类型
- 开发过程中用到的集合
- 集合
- ArrayList底层存取值怎么实现的,是不是线程安全的,扩容是怎么实现的
- HashMap的底层原理,ConcurrentHashMap的实现原理,存取值的时候是怎么实现的。
- 重载和重写的区别
- Java创建对象的方式
- Object的默认方法
- 包装类的Cache
- 多态中静态方法的执行
- 反转字符串程序
- Java异常处理机制
- throw和throws的区别
- 常用的IO类
- 代码规范的理解
- 项目中用到final的地方
- 深拷贝和浅拷贝的区别
- 对集合有二次加工的处理吗
- 线程池的创建
- 多线程的使用场景
- 为什么要使用多线程?
- 双亲委派
- JVM结构,运行顺序
- 类加载知识点
- HashMap的遍历方式
- HashSet怎么保证元素唯一
- mysql 中的基础函数
- lock锁
- 锁升级
- sync的实现原理
- sync和volatile
- 怎么理解资源独立分配
- 线程的状态的转换关系,主动阻塞和被动阻塞
- BIO和NIO的区别,怎么实现多路复用
- NIO与IO区别
- fork()函数
- HTTP的缺点
- spring的循环依赖,怎么解决的,为什么需要加个三级缓存?
- HTTPS怎么实现的网络安全性
- 设计模式是用来干嘛的,为什么看设计模式
- Map自定义一个实例作为Map的Key,需要满足什么条件。自定义类作为Key,有什么要求。
- List用什么方式遍历
- Remove删除元素做过什么其他操作
- 进程和线程在地址空间上有什么区别
- 进程是分配资源的基本单位,怎么理解
- 线程和资源有什么关系
- gitee代码冲突怎么解决
- `二`
- Gitee常用命令有哪些
- 工作中用到哪些数据库
- 事务是在哪里应用的
- 数据库中sql优化
- 索引的数据结构
- 索引的作用
- 事务的隔离级别
- 事务的传播方式
- 事务的四大特性
- mybatis分页是怎么做的
- #和$的区别,分别什么情况下使用
- Mysql数据库悲观锁和乐观锁
- SQL:删除重复的记录
- 怎么创建索引
- Get和Post的区别
- Get传参的长度限制
- HTTP状态码
- POST上传有限制,上传文件过大怎么办。
- union和union all的区别
- mysql 中float、double、decimal区别
- 联合索引中,最左的字段放在右边会命中吗?为什么?
- mysql中的几个器
- 索引的分类
- cookie和session的区别
- `三`
- 过滤器拦截器
- 前端传参时,是怎么和对象映射的。
- IOC和AOP
- 动态代理的含义和分类
- AOP是怎么调用的,静态代理和动态代理的区别
- AOP的通知类型
- BeanFactory和ApplicationContext有什么区别
- Mybatis的优缺点
- Mybatis的BIO接口支持重载吗
- SpringMVC的请求原理
- SoringMVC组件
- SpringBoot读取配置文件的配置项,怎么读取。如果读取不到怎么办,除了@Value还有什么。
- SpringBoot中的异常拦截怎么做的
- SpringBoot依赖是怎么导入的
- SpringBoot是怎么读取参数的
- SpringBoot常用注解
- SpringBoot的核心配置文件,什么格式,什么区别
- SpringBoot读取配置文件中的类,接口
- Spring中的路由,怎么凭借路径前后的无意义参数
- Bean生命周期
- Bean的作用域
- 读取XML的几种方式(了解即可)
- 如何解决循环依赖
- Spring的事务
- 介绍一下SpringBoot
- 单例有线程安全问题吗?原型呢?
- HandlerMapping是什么时候工作的,程序启动的时候还是第一次请求的时候
- Spring中的local有没有用过
- Nginx有什么作用,怎么应用的
- 有没有参与过项目部署,怎么实现的
- 异常处理
- SpringBoot是怎么运行的
- Mybatis常用标签
- Mybatis分页实现
- SpringMVC的注解
- SpringBoot如何解决跨域问题
- Spring容器的启动问题
- BeanFactroy怎么理解
- 反向代理的过程
- 负载均衡怎么理解
- `四`
- 流控模式有哪些?
- 项目中有没有用分布式架构
- 项目中有缓存吗,存在哪里的?
- redis数据类型
- redis中存储了哪些数据
- redis常见命令
- redis设置密码怎么登录
- redis常用数据类型,有什么特点
- redis的持久化机制
- 缓存崩坏三问,怎么解决
- 认证和权限是怎么实现的
- MQ的用途/为什么使用消息队列
- `五`
- SpringCloud了解的多不多,尝试搭建微服务项目吗?
- SpringCloud的组件
- 怎么实现分布式锁
- Redis的分布式锁是怎么实现的
- 项目中涉及到高并发的问题了吗
- Linux的权限
- RPC什么原理,怎么调用远端服务像本地服务
- sentinel限流熔断的机制
- MQ 有什么作用?你都用过哪些 MQ 中间件?
- 什么是Dubbo
- `其他`
- 项目模块描述
- 项目使用了哪些技术
- 项目的日志
- 怎么用一个11L,7L的杯子,量出2L水
- 4L水,用1.5L的瓶子和2.5L的瓶子,怎么平均分
- 项目中遇到报错如何定位解决
- 理解老代码会遇见什么问题
- 更改代码影响别人的模块,怎么解决
- 项目里解决过什么有意义的东西
- 出现过哪些异常,什么原因造成的
- 测试时数据量小,发布后数据量大,怎么确保跑的起来
- 改老代码看不懂代码怎么解决
- 服务按领域拆分,按功能拆分,不同模块怎么办
- 改动影响了其他模块,导致出现问题,解决思路是怎么样的。
- 项目的表结构
- 介绍一下近期的项目,技术关键点,有挑战的地方。
- 项目中常用的数据结构,什么场景下使用
- 交互岗位沟通流程
- new String("a") + new String("b") 会创建几个对象
- Redis的持久化机制RDB和AOF的优缺点分别是什么?
- `java基础`
- 权限修饰符
- String 类的常用方法都有那些?
- 成员变量和局部变量的区别
- 创建对象的流程
- 面向对象和面向过程
- 如何跳出外层循环?
- 多态的优点
- throw和throws的区别
- 为什么重写equals,hashcode也要重写?
- InputStream可以new嘛,要怎么创建InputStream流?
- 创建数组过程
- 什么是进程,进程的特点是什么?
- 阻塞的类型
- 如何将字符串反转?
- 数组的方法有哪些?
- 类加载器有哪些?(检查从下往上,加载从上往下)
- 破坏双亲委派模型的三大情况
- 引用类型变量和基本类型变量的区别
- java的特点
- 面向对象和面向过程的区别
- 实现一个函数,功能是统计一个字符串中所有字母的个数
- 字符串和字符的区别
- 整数和浮点数的区别
- 自动装箱和拆箱
- 在Java在,为什么要有无参构造,并说出应用场景?
- 构造器 Constructor 是否可被 override(记住)
- 标准的JavaBean的规则
- mysql中char和varchar有什么区别?
- mybatis的缓存机制
- redis如何管理过期的key?
###
一
八大基本类型
答:byte,short,int,long,float,double,char,boolean
字节数:1,2,4,8,4,8,2,1
范围:
|- byte -|- -128~127-|
|- short -|- -2^15 ~ -2^15-1 -|
|- int -|- -2^31 ~ 2^31-1 -|
|- long -|- -2^63 ~ 2^63-1 -|
|- char -|- 0~65535 -|
开发过程中用到的集合
答:
HashMap,List——利用key不可重复和键值对特性,对多级目录进行分级封装
ConcurrentHashMap——线程安全
ArrayList——实体类封装的时候
集合
答:list、map
list分为ArrayList、LinkedList
set分为HashSet(底层是HashMap的key,保持HashSet唯一是和hashcode有关)、TreeSet
map分为HashMap、TreeMap
list和set的区别是list有序、可以重复;set无序,不可重复
ArrayList底层存取值怎么实现的,是不是线程安全的,扩容是怎么实现的
答:其底层是数组实现的,我们可以在集合中存储任意类型的数据,
扩容:数组长度10,如果要超过默认长度就会触发自动扩容,存储顺序是从后往前传。
1.5倍扩容,CopyOf()。
如果扩容一半不够,就将目标size作为扩容后的容量。
采用的是浅拷贝:只拷贝引用。
底层存值:首先判断容量够不够,然后通过size自增作为下标,通过数组的方式放进去。如果不够,会层层调用grow方法进行扩容。如果调用的是addall方法,则会把添加的集合转为数组并拿到length,进行容量判断,如果不够,则扩容。并且对比扩容的size和新的size比较,以大的为准。
如果指定下标add,会判断下标是否合法,然后判断容量,并通过arraycopy方法,将后半段元素后移1。
底层取值: 如果输入下标取值,则会检查下标是否合法,如果OK,则通过数组的方式取值。并通过arrycopy进行迁移元素,并把最后一个空位设为null。
如果传入一个value,则会判断非空后进行遍历,并取出。
ArrayList 是线程不安全的,非常适合用于对元素进行查找,效率非常高。解决方法:保证它的线程安全性,通常有两种解决办法:第一,使用 synchronized 关键字;第二,可以用 类中的静态方法 synchronizedList(); 对 ArrayList 进行调用即可。
HashMap的底层原理,ConcurrentHashMap的实现原理,存取值的时候是怎么实现的。
答:1、map.put(k,v)实现原理
(1)首先将k,v封装到Node对象当中(节点)。
(2)然后它的底层会调用K的hashCode()方法得出hash值。
(3)通过哈希表函数/哈希算法,将hash值转换成数组的下标,下标位置上如果没有任何元素,就把Node添加到这个位置上。如果说下标对应的位置上有链表。此时,就会拿着k和链表上每个节点的k进行equal。如果所有的equals方法返回都是false,那么这个新的节点将被添加到链表的末尾。如其中有一个equals返回了true,那么这个节点的value将会被覆盖。
2、map.get(k)实现原理
(1)先调用k的hashCode()方法得出哈希值,并通过哈希算法转换成数组的下标。
(2)通过上一步哈希算法转换成数组的下标之后,在通过数组下标快速定位到某个位置上。如果这个位置上什么都没有,则返回null。如果这个位置上有单向链表,那么它就会拿着K和单向链表上的每一个节点的K进行equals,如果所有equals方法都返回false,则get方法返回null。如果其中一个节点的K和参数K进行equals返回true,那么此时该节点的value就是我们要找的value了,get方法最终返回这个要找的value。
重载和重写的区别
答:重写(@Override)是发生在父子类中,子类不满足父类的方法,想要重新写该方法,要满足两同两小一大的原则:两同:方法名相同,参数列表相同;两小:子类的返回类型要小于等于父类的返回类型,子类的抛出异常要小于等于父类抛出的异常;一大:子类的权限修饰符要大于等于父类的权限修饰符
重载(@Overload)是发生在同一个类中,方法名相同,参数列表不同。
Java创建对象的方式
答:new关键字、反序列化【深拷贝】、反射(使用Class类的newInstance调用无参构造器来创建对象;如果有参构造器,则需要使用Class的forname方法和Constructor来进行对象创建)、Object类中的clone方法(要使用clone方法,必须实现cloneable接口并实现其定义的clone方法)【浅拷贝】
Object的默认方法
答:clone、三个wait(参数不同)、equals、hashcode、notify、notifyAll、toString、finalize、getClass、一个本地类的注册方法
包装类的Cache
答:
基本类型不包括:float,double
boolean缓存值:true,false
char缓存值:0~127,故ASSII码里面的字符都有缓存
其它范围:-128~127
特殊的int:上限默认为127,但可通过-XX:AutoBoxCacheMax设置。
实现方式:定义了缓存数组(boolean定义的是常量),且为静态代码块,在类加载时即生成。
多态中静态方法的执行
答:静态方法不同于静态代码块,是由开发者调用。
只能通过类名点处理。子类可以继承父类的静态方法。
如果同名,不算重写,子类只能调用到子类的方法。
反转字符串程序
答:通过StringBuilder类中的reverse()方法;切割递归反转;二分递归反转;通过String类的charAt()的方法来获取字符串中的每一个字符,然后将其拼接为一个新的字符串。
切割递归反转的代码:
public static String reverseTestSix(String s) {
if (s.length() <= 1) {
return s;
}
return reverseTestSix(s.substring(1)) + s.substring(0, 1);
}
二分递归反转的代码:
public static String reverseRecursive(String s){
int length = s.length();
if(length<=1){
return s;
}
String left = s.substring(0,length/2);
String right = s.substring(length/2 ,length);
String afterReverse = reverseRecursive(right)+reverseRecursive(left);//此处是递归的方法调用
return afterReverse;
}
Java异常处理机制
答:声明异常、抛出异常、捕获异常
抛出的顺序:先抛出异常,然后传给调用者,就这样一直一直往上抛,直接抛到main,最后抛给JVM
throw和throws的区别
答:
- throws:用来声明一个方法可能产生的所有异常,不做任何处理而是将异常往上传,谁调用我我就抛给谁。
用在方法声明后面,跟的是异常类名
可以跟多个异常类名,用逗号隔开
表示抛出异常,由该方法的调用者来处理
throws表示出现异常的一种可能性,并不一定会发生这些异常 - throw:则是用来抛出一个具体的异常类型。
用在方法体内,跟的是异常对象名
只能抛出一个异常对象名
表示抛出异常,由方法体内的语句处理
throw则是抛出了异常,执行throw则一定抛出了某种异常
常用的IO类
答:inputstream、outputstream、FileInputStream、BufferedInputStream、ObjectInputStream(反序列化)、Reader、Writer、Fileoutputstrem、Bufferedoutputstrem、Objectoutputstrem(序列化)
代码规范的理解
答:命名规范、注释规范、程序结构化、模块化、养成些接口文档的行为
项目中用到final的地方
答:可以用到类、方法、常量、参数
修饰类的时候,为最终类,无法被继承
修饰方法的时候,为最终方法,可以被继承,不可以重写
修饰变量的时候,为常量,无法被修改
深拷贝和浅拷贝的区别
答:深拷贝和浅拷贝都是对象拷贝
(引用变量)
浅拷贝只是拷贝了源对象的地址,所以源对象的值发生变化时,拷贝对象的值也会发生变化。
深拷贝是拷贝了源对象的所有值,所以即使源对象的所有值发生变化时,拷贝对象的值也不会改变。
又开了一个新的内存存储数据
(基本变量)
不论是浅拷贝还是深拷贝,都会创建一个新的内存,就算源对象的所有值发生变化时,拷贝对象的值也不会改变。
HashMap是浅拷贝
对集合有二次加工的处理吗
线程池的创建
答:自定义创建:
- ThreadPoolExecutor
- ScheduledThreadPoolExecutor
- ForkJoinPool
【ForkJoinPool线程池思想:将大任务分解成若干个小任务,当小任务均执行结束后,将任务做一个整合
使用接口:
RecursiveAction:没有返回值,只是执行任务
RecursiveTask:有返回值,小任务结束后,返回结果。大任务可将小任务返回结果进行整合】
Executors工具类创建:
- Fixed:定长的线程池
- Executors:定时任务
- Single:单线程的
- Cache:缓存
多线程的使用场景
答:1、后台任务,例如:定时向大量(100w以上)的用户发送邮件;
2、异步处理,例如:发微博、记录日志等;
3、分布式计算
为什么要使用多线程?
答:1.防止阻塞主线程,提高吞吐量
2,提高资源的利用率
双亲委派
答:类加载器(Classloader):
类加载阶段中的“通过一个类的全限定名来获取此类的二进制字节流”这个动作放到 Java 虚拟机外部去实现。
作用:加载class文件进入JVM,审查类由谁加载(双亲委派机制),将class重新解析成JVM要求的对象格式
一阶段:加载阶段——字节码加载到内存
1:通过全限定名来获取类的字节流
2:将字节流转为方法区的运行时数据
3:在堆中生成一个Class对象,作为访问入口
二阶段:验证阶段——确保Class文件的字节流中包含的信息符合当前虚拟机的要求
1:格式验证:Class文件格式规范
2:元数据验证:是否符合JAVA语法
3:字节码验证:数据流和控制流分析,确保不危害虚拟机
4:符号引用验证:符合引用转直接引用
三阶段:
1:类资源的内存分配
2:解析引用
3:初始化,执行静态代码
一言概之,双亲委派模型,其实就是一种类加载器的层次关系。
BootStrap——完全由JVM控制,加载JVM需要的类
Extension——服务目标在ext目录下的,依赖等
Application
破坏双亲委派三大情况:
jdk1.2之前
缺陷导致,——通过线程上下文类加载器解决,例如SPI的JDBC
热部署
加载Class的两种方式:
隐式:JVM在解析引用的时候发现内存没有,会申请加载。
显式:this.getClass().getClassLoader().loadClass()
Class.forName()
流程:
收到加载类的请求。
从底向上检查类是否已加载。
如果没有加载,自顶向下尝试加载该类。
优点:
1,防止底层类被篡改。
2,避免重复加载类信息。
JVM结构,运行顺序
答:JVM的基本组成:
- JVM指令集
- 类加载器
- 执行引擎:jvm的核心,解析JVM字节码指令,每个java线程就是一个执行引擎的实例。
- 运行时数据区:将内存分为若干个区
- 本地方法区:调用C方法返回的结果
JVM的结构 - ==JVM的执行过程 ==
- 其中线程私有的:
- 程序计数器:线程私有的,行号指示器。
- 虚拟机栈:栈帧,执行完方法清楚栈帧。调用其他方法推到栈顶(活动栈帧)。
- 本地方法栈
公共的:
- 堆():堆区放对象,堆栈放引用。
堆可以分为年轻代(Eden,S0,S1)和年老代 - 方法区(永久区):常量池,域,方法数据,方法体,构造函数,类中的专有方法,实例初始化,接口初始化。【运行时常量池】
类加载知识点
答:1.类加载的含义:
类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个 java.lang.Class对象,用来封装类在方法区内的数据结构。
2.类加载的过程
它的整个生命周期包括:加载、验证、准备、解析、初始化、使用和卸载七个阶段。
HashMap的遍历方式
答:分为四大类:迭代器、foreach、Lambda、Streams流
使用迭代器(Iterator)EntrySet 的方式进行遍历;
public class HashMapTest {
public static void main(String[] args) {
// 创建并赋值 HashMap
Map<Integer, String> map = new HashMap();
map.put(1, "Java");
map.put(2, "JDK");
map.put(3, "Spring Framework");
map.put(4, "MyBatis framework");
map.put(5, "Java中文社群");
// 遍历
Iterator<Map.Entry<Integer, String>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<Integer, String> entry = iterator.next();
System.out.print(entry.getKey());
System.out.print(entry.getValue());
}
}
}
使用迭代器(Iterator)KeySet 的方式进行遍历;
public class HashMapTest {
public static void main(String[] args) {
// 创建并赋值 HashMap
Map<Integer, String> map = new HashMap();
map.put(1, "Java");
map.put(2, "JDK");
map.put(3, "Spring Framework");
map.put(4, "MyBatis framework");
map.put(5, "Java中文社群");
// 遍历
Iterator<Integer> iterator = map.keySet().iterator();
while (iterator.hasNext()) {
Integer key = iterator.next();
System.out.print(key);
System.out.print(map.get(key));
}
}
}
使用 For Each EntrySet 的方式进行遍历;
public class HashMapTest {
public static void main(String[] args) {
// 创建并赋值 HashMap
Map<Integer, String> map = new HashMap();
map.put(1, "Java");
map.put(2, "JDK");
map.put(3, "Spring Framework");
map.put(4, "MyBatis framework");
map.put(5, "Java中文社群");
// 遍历
for (Map.Entry<Integer, String> entry : map.entrySet()) {
System.out.print(entry.getKey());
System.out.print(entry.getValue());
}
}
}
使用 For Each KeySet 的方式进行遍历;
public class HashMapTest {
public static void main(String[] args) {
// 创建并赋值 HashMap
Map<Integer, String> map = new HashMap();
map.put(1, "Java");
map.put(2, "JDK");
map.put(3, "Spring Framework");
map.put(4, "MyBatis framework");
map.put(5, "Java中文社群");
// 遍历
for (Integer key : map.keySet()) {
System.out.print(key);
System.out.print(map.get(key));
}
}
}
使用 Lambda 表达式的方式进行遍历;
public class HashMapTest {
public static void main(String[] args) {
// 创建并赋值 HashMap
Map<Integer, String> map = new HashMap();
map.put(1, "Java");
map.put(2, "JDK");
map.put(3, "Spring Framework");
map.put(4, "MyBatis framework");
map.put(5, "Java中文社群");
// 遍历
map.forEach((key, value) -> {
System.out.print(key);
System.out.print(value);
});
}
}
使用 Streams API 单线程的方式进行遍历;
public class HashMapTest {
public static void main(String[] args) {
// 创建并赋值 HashMap
Map<Integer, String> map = new HashMap();
map.put(1, "Java");
map.put(2, "JDK");
map.put(3, "Spring Framework");
map.put(4, "MyBatis framework");
map.put(5, "Java中文社群");
// 遍历
map.entrySet().stream().forEach((entry) -> {
System.out.print(entry.getKey());
System.out.print(entry.getValue());
});
}
}
使用 Streams API 多线程的方式进行遍历(效率最高)
public class HashMapTest {
public static void main(String[] args) {
// 创建并赋值 HashMap
Map<Integer, String> map = new HashMap();
map.put(1, "Java");
map.put(2, "JDK");
map.put(3, "Spring Framework");
map.put(4, "MyBatis framework");
map.put(5, "Java中文社群");
// 遍历
map.entrySet().parallelStream().forEach((entry) -> {
System.out.print(entry.getKey());
System.out.print(entry.getValue());
});
}
}
HashSet怎么保证元素唯一
答:HashSet的底层是HashMap的key,所以Hashset可以通过hashcode转换成key来保证元素唯一吧
mysql 中的基础函数
lower(username)
upper(username)
length(username)
substr(username,1,3) --含头含尾
caoncat(username,“123”) --拼接123
replace(username,‘1’,‘100’) --1换100
ifnull(sex,0) --nul换10
round(money,1) ceil(money) floor(money)
select now() – 年与日 时分秒
select curdate() --年与日
select curtime() --时分秒
select now(),hour(now()),minute(now()),second(now()) from emp ;
select now(),year(now()),month(now()),day(now()) from emp ;
lock锁
答:主要用来解决互斥问题。
- void lock()—— 获取锁对象,优先考虑是锁的获取,而非中断。
- void lockInterruptibly()—— 获取锁,但优先响应中断而非锁的获取。
- boolean tryLock() ——试图获取锁,如果返回true,则获取成功,直接使用。不需要继续lock()
- boolean tryLock(long timeout, TimeUnit timeUnit) ——试图获取锁,并设置等待时长。
- void unlock()——释放锁对象
Lock锁的详细
锁升级
sync的实现原理
答:synchronized可以保证方法或者代码块在运行时,同一时刻只有一个方法可以进入到临界区,同时它还可以保证共享变量的内存可见性。
Java中每一个对象都可以作为锁,这是synchronized实现同步的基础:
• 普通同步方法,锁是当前实例对象
• 静态同步方法,锁是当前类的class对象
• 同步方法块,锁是括号里面的对象
sync和volatile
答:1,volatile无法锁定当前变量,sync可以锁定当前变量
2,volatile作用于变量上,sync作用于方法,类,变量
3,volatile只有变量的可见性,sync不仅有变量的可见性,还有变量的原子性
4,volatile不会线程阻塞,sync会导致线程阻塞
5,volatile标记的变量不会被编译器优化,sync标记的变量会被编译器优化
6,在代码中,volatile加在属性上,sync的可以用于任何地方
怎么理解资源独立分配
答:ThreadLocal:
每个Thread内部都有一个Map(ThreadLocalMap),是Thread的一个属性。
key是当前ThreadLocal对象——弱引用,value却是强引用。
内存泄漏问题:
造成内存泄露——解决:手动remove,静态私有。
线程复用问题:前后remove
使用场景:
1:存储用户Session
2:数据库连接,处理数据库事务
3:数据跨层传递
4:spring解决线程安全问题
有状态:有属性——比如pojo
无状态:无属性——controller
线程的状态的转换关系,主动阻塞和被动阻塞
答:等待阻塞,同步阻塞,其他阻塞。
join():并行变串行
interrupt():更改标识,抛异常,中断阻塞
BIO和NIO的区别,怎么实现多路复用
答:BIO是同步阻塞,就是我们平常使用的传统 IO,它的特点是模式简单使用方便,并发处理能力低。
NIO是同步非阻塞,在传统的IO上采用了多路复用
多路复用的含义:
可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。
NIO与IO区别
答:1)Non-blocking IO(非阻塞IO)
IO流是阻塞的,NIO流是不阻塞的。
Java NIO使我们可以进行非阻塞IO操作。比如说,单线程中从通道读取数据到buffer,同时可以继续做别的事情,当数据读取到buffer中后,线程再继续处理数据。写数据也是一样的。另外,非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。
2)Buffer(缓冲区)
IO 面向流(Stream oriented),而 NIO 面向缓冲区(Buffer oriented)。
Buffer是一个对象,它包含一些要写入或者要读出的数据。在NIO类库中加入Buffer对象,体现了新库与原I/O的一个重要区别。在面向流的I/O中·可以将数据直接写入或者将数据直接读到 Stream 对象中。虽然 Stream 中也有 Buffer 开头的扩展类,但只是流的包装类,还是从流读到缓冲区,而 NIO 却是直接读到 Buffer 中进行操作。
3)Channel (通道)
NIO 通过Channel(通道) 进行读写。
通道是双向的,可读也可写,而流的读写是单向的。无论读写,通道只能和Buffer交互。因为 Buffer,通道可以异步地读写。
4)Selectors(选择器)
NIO有选择器,而IO没有。
选择器用于使用单个线程处理多个通道。因此,它需要较少的线程来处理这些通道。线程之间的切换对于操作系统来说是昂贵的。 因此,为了提高系统效率选择器是有用的。
fork()函数
答:用于创建一个进程,所创建的进程复制父进程的代码段/数据段/BSS段/堆/栈等所有用户空间信息;在内核中操作系统重新为其申请了一个PCB,并使用父进程的PCB进行初始化;
子进程执行的位置是fork()函数执行后的代码处,猜想是复制了父进程的PC指针给子进程。
HTTP的缺点
答:1.通信使用明文不加密,内容可能被窃听
2.不验证通信身份,有可能遭遇伪装
3.无法验证报文的完整性,有可能被篡改
spring的循环依赖,怎么解决的,为什么需要加个三级缓存?
答:三级缓存是为了解决在AOP代理过程中产生的循环依赖问题,没有AOP的话,二级缓存可以解决循环依赖的问题
HTTPS怎么实现的网络安全性
答: 用工具(OpenSSL)来生成一个私钥,然后用刚生成的私钥,在提供你自己的域名、公司名称、部门、省份、城市等信息来生成一个待签名证书(即CSR文件,也叫公钥),然后我们拿着这个代签名证书,去CA机构申请证书,CA会根据你提交的信息进行审核,审核通过(就相当于让别人签个名,防伪造)后会下发证书给你(CRT文件,里面包含了公钥,CA的签名,过期时间,申请人提交的信息),当你拿到签名好的证书以后,把它和刚开始的私钥一起部署在服务器里面,这样网站就是HTTPS的了。
扩展知识:
HTTPS采用了 SSL 和 TLS 协议,当我们使用 SSL 时,会变成先和 SSL 通信,然后再由 SSL 和 TCP 进行通信
加密:对称加密、非对称加密和混合加密
认证:数字签名和证书
设计模式是用来干嘛的,为什么看设计模式
答:设计模式是用来是解决软件开发某些特定问题而提出的一些解决方案,也可以理解成解决问题的一些思路。
Map自定义一个实例作为Map的Key,需要满足什么条件。自定义类作为Key,有什么要求。
答:需要满足(1)自定义实例不能是单例的;
List用什么方式遍历
答:迭代器、foreach、for循环、用foreach()方法、使用 Lambda 表达式的方式进行遍历、使用 Streams API 单线程的方式进行遍历、使用 Streams API 多线程的方式进行遍历(效率最高)
Remove删除元素做过什么其他操作
答:
1:检查下标是否合法。
2:检查modCount。
3:根据下标+偏移量删除。
4:size-1
5:返回。
进程和线程在地址空间上有什么区别
答:进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。
进程是分配资源的基本单位,怎么理解
答:一个进程在其执行的过程中可以产生多个线程。与进程不同的是同类的多个线程共享进程的堆和方法区资源,但每个线程有自己的程序计数器、虚拟机栈和本地方法栈
线程和资源有什么关系
gitee代码冲突怎么解决
答:
1:选择相应冲突的代码文件,找到冲突的代码段,并选择合适的代码更改并接受。
2:通过WebIDE在线手动解决。
二
Gitee常用命令有哪些
答:
git config --global user.name "gtiee上的用户名"
git config --global user.email "gitee账户绑定的邮箱"
git pull // 拉取
git push // 推送
创建 Git 本地仓库
mkdir java01 // 创建本地仓库 java01
cd java01 // 进入本地仓库
git init // 初始化本地仓库
touch README.md // 新建项目描述 md 文件
git add . // 将更改的文件全部添加入暂存区
git commit -m "创建java01仓库" // 提交到本地仓库
git remote add origin https://gitee.com/crwoer/java01.git // 关联远程仓库
git push -u origin master // 推送到远程仓库
工作中用到哪些数据库
答:MySQL和Redis
事务是在哪里应用的
答:银行转账的例子,如果A转给B100元,A这里减一百,B会加一百
数据库中sql优化
答:
1.索引不宜太多,一般在五个以内
2.用vachar代替char
3.查询时尽量不要使用select *,而是具体的字段
4.避免在where子句上使用!=或<>操作符
5.尽量用数值代替字符串类型
6.避免在where语句上使用表达式操作
索引的数据结构
答:
BTree结构:BTree又叫多路平衡搜索树,叶子节点只存储了索引
B+Tree 结构:B+Tree为BTree的变种,B+Tree的叶子节点保存所有的key信息和索引信息
索引的作用
答:
- 提高查询速度
- 确保数据的唯一性
- 可以加速表和表之间的连接 , 实现表与表之间的参照完整性
- 使用分组和排序子句进行数据检索时 , 可以显著减少分组和排序的时间
事务的隔离级别
答: 读未提交
读已提交
可重复读(数据库默认的隔离)
可串行化
事务的传播方式
答:
1.REQUIRED(必需的):表示当前方法必须运行在事务中。如果当前事务存在,方法将会在该事务中运行。否则,会启动一个新的事务
2.SUPPORTS(支持的):表示当前方法不需要事务上下文,但是如果存在当前事务的话,那么该方法会在这个事务中运行
3.MANDATORY(强制的):表示该方法必须在事务中运行,如果当前事务不存在,则会抛出一个异常
4.REQUIRED_NEW(需要新的):表示当前方法必须运行在它自己的事务中。一个新的事务将被启动。如果存在当前事务,在该方法执行期间,当前事务会被挂起。
5.NOT_SUPPORTED(不被支持的):表示该方法不应该运行在事务中。如果存在当前事务,在该方法运行期间,当前事务将被挂起。
6.NEVER(不会):表示当前方法不应该运行在事务上下文中。如果当前正有一个事务在运行,则会抛出异常
7.NESTED(嵌套的):表示如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。嵌套的事务可以独立于当前事务进行单独地提交或回滚。如果当前事务不存在,那么其行为与PROPAGATION_REQUIRED一样。
事务的四大特性
答:
原子性:即不可分割性,事务要么全部被执行,要么就全部不被执行。
一致性:事务的执行使得数据库从一种正确状态转换成另一种正确状态
隔离性:在事务正确提交之前,不允许把该事务对数据的任何改变提供给任何其他事务,
持久性:事务正确提交后,其结果将永久保存在数据库中,
mybatis分页是怎么做的
答:
limit关键字实现
interceptor plugin实现
PageHelper实现
#和$的区别,分别什么情况下使用
答:
#{}:编译预处理,在mysql执行过程中,可以用?代替,#{} 适合 在表结构 确定的情况下使用 。可以有效防止sql注入
$ {}:拼接字符串,${} 适合 在表结构不确定的情况下使用。
Mysql数据库悲观锁和乐观锁
答:(1)悲观锁:顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。
传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。悲观锁更适用于多写少读的情况
(2)乐观锁: 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。
乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁。
完整的信息
SQL:删除重复的记录
答:delete [标志字段id],count() into temp1 from [表名]group by [标志字段id]having count()>1
怎么创建索引
答:
#create index 索引名字 on 表名(字段名); #创建索引
create index loc_index on dept(loc); #创建索引
#创建唯一索引--索引列的值必须唯一
CREATE UNIQUE INDEX 索引名 ON 表名(字段名)
CREATE UNIQUE INDEX bindex ON dept(loc)
#创建复合索引,如果您希望索引不止一个列,您可以在括号中列出这些列的名称,用逗号隔开:
CREATE INDEX 索引名 ON 表名 (字段1, 字段2)
CREATE INDEX PIndex ON Persons (LastName, FirstName)
#删除索引
alter table dept drop index 索引名
Get和Post的区别
答:
1.Get的请求参数都显示在地址栏中,不安全;Post的请求参数对于用户是不可见的,安全
2.Get的传输的大小只有2k-4k,Post的传输大小不做限制
3.Get要求form表单提交时采用ACSII字符;Post则采用ISO-10646字符集
4.从执行效率来看,Get的执行效率高于Post的执行效率
Get传参的长度限制
HTTP状态码
答:完整答案
POST上传有限制,上传文件过大怎么办。
union和union all的区别
答:
Union:对两个结果集进行并集操作,不包括重复行,同时进行默认规则的排序;
Union All:对两个结果集进行并集操作,包括重复行,不进行排序;
mysql 中float、double、decimal区别
答:1.float与double都浮点类型,而decimal是定点类型
2.三者都可以使用(M,D)的形式来声明,比如float(5,2),double(5,2),decimal(5,2),M表示总共长度,D表示小数点后面的长度;
3.float、double、decimal也都可以什么用也不加的方式来定义,比如 num1 float,num2 double, num3 decimal,在这种情况下,float、double默认会按你实际存入的数值存储,你存入的是什么就显示什么,不会发生截断,也不会发生四舍五入;而DECIMAL在不指定精度时,默认整数为10,小数为0,即放入的数值小数位将会被截断。总结:当需要表示金额等精度要求比较高的数值时,还是使用decimal(M,D)的方式声明字段好一点,而其他队精度要求相对不高的字段可以使用float(M,D),double(M,D)的方式。
联合索引中,最左的字段放在右边会命中吗?为什么?
答:会命中,因为索引的最左特性
mysql中的几个器
答:
索引的分类
答:
功能区分:
主键索引(聚集索引),唯一索引,普通索引,全文索引
列数区别:
单值索引,联合索引
物理区分:
聚簇索引,非聚簇索引
cookie和session的区别
答:cookie是小型文本文档,存储在本地内存中,断电后不会丢失(永久保存)
session是会话控制,存储在浏览器中,会话关闭时,session消失(临时保存)
三
过滤器拦截器
答:1.过滤器:
依赖于servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作,获取我们想要获取的数据,比如:在过滤器中修改字符编码;在过滤器中修改HttpServletRequest的一些参数,包括:过滤低俗文字、危险字符等
2.拦截器:
依赖于web框架,在SpringMVC中就是依赖于SpringMVC框架。在实现上基于Java的反射机制,属于面向切面编程(AOP)的一种运用。由于拦截器是基于web框架的调用,因此可以使用Spring的依赖注入(DI)进行一些业务操作,同时一个拦截器实例在一个controller生命周期之内可以多次调用。但是缺点是只能对controller请求进行拦截,对其他的一些比如直接访问静态资源的请求则没办法进行拦截处理
3.过滤器和拦截器的区别:
①拦截器是基于java的反射机制的,而过滤器是基于函数回调。
②拦截器不依赖与servlet容器,过滤器依赖与servlet容器。
③拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
④拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
⑤在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
⑥拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。
前端传参时,是怎么和对象映射的。
IOC和AOP
答:IOC(控制反转):把原来用户创建对象的权力交给了Spring进行创建和管理
Spring IOC的注入方式有set注入、构造器注入、注解注入
AOP(面向切面编程):是将那些与核心业务无关,但却对多个对象产生影响的公共行为和逻辑,将其封装成一个可以重复使用的模块
动态代理的含义和分类
答:所谓的动态代理就是指AOP框架不会操作字节码文件,而是每次在运行的时候创建一个临时的AOP对象,这个AOP对象包括了目标对象的所有方法和功能,只对切点进行增强处理,并进行回调原对象的方法
Spring AOP动态代理分为JDK代理和CGlib代理
AOP是怎么调用的,静态代理和动态代理的区别
答:AOP的调用方式:
实现BPP接口,在初始化阶段进行调用方法链。
1.createAopProxy()选择代理类型
2.在invoke()方法中,获取拦截器,判断拦截器链是否为空。
3.获得proceed()方法。
静态代理和动态代理的区别:
1.静态代理只能代理一个类,动态代理可以代理一个接口和接口下面的实现类
2.静态代理在启动前就知道自己的代理对象,动态代理而是在启动后才知道自己的代理对象
AOP的通知类型
答:前置通知[]before]:在切点运行之前执行
后置通知[after-returning]:在切点正常结束之后执行
异常通知[after-throwing]:在切点发生异常的时候执行
最终通知[after]:在切点的最终执行
环绕通知[around]:编码的方式自己定义通知的位置, 用于解决其他通知时序问题
BeanFactory和ApplicationContext有什么区别
答:BeanFactory是最顶级的接口,里面实现了一些Spring的基本方法,是面向Spring自身使用。
BeanFactory一般不会实例化对象,只有从BeanFactory中向bean中拿对象时才会实例化对象
ApplicationContext是BeanFactory的子类,扩展了一些方法,是面向程序员的。
ApplicationContext中只要一启动就会实例化所有的对象
Mybatis的优缺点
答:
优点
1.与JDBC相比,可以省略大量的代码
2.能够与Spring很好的集成
3.很好的与各种数据库兼容
4.通过ORM映射,可以使数据库的字段和pojo类的属性对应
5.灵活,解除sql与程序代码的耦合。
缺点:
1.sql工作量很大
2.sql依赖于数据库,导致数据库移植性差
Mybatis的BIO接口支持重载吗
SpringMVC的请求原理
SoringMVC组件
答:
前端控制器
处理器映射器
处理器适配器
视图解析器
视图
SpringBoot读取配置文件的配置项,怎么读取。如果读取不到怎么办,除了@Value还有什么。
答:
@Value
@ConfigurationProperties
@PropertySource
SpringBoot中的异常拦截怎么做的
SpringBoot依赖是怎么导入的
答:通过pom、右击Generate中的dependency
SpringBoot是怎么读取参数的
SpringBoot常用注解
答:
springbootapplication
springboottest
RestController
getmapping
postmapping
requestmapping
deletemapping
SpringBoot的核心配置文件,什么格式,什么区别
答:
bootstrap和application
yml或properties
优先级不同
bootstrap主要用于额外的资源来加载配置信息
属性不能被覆盖
SpringBoot读取配置文件中的类,接口
Spring中的路由,怎么凭借路径前后的无意义参数
Bean生命周期
答:实例化——>属性赋值——>初始化——>调用——>销毁
Bean的作用域
答:
1.singleton,每一个容器里面只有一个bean实例
2.prototype,为每一个bean创建一个实例
3.request,一个请求对应一个bean实例
4.session,一个session一个bean实例
5.global-session,全局作用域,所有会话一个实例
读取XML的几种方式(了解即可)
答:Dom读取、Dom4j读取、JDom读取、Sax读取、附赠properties的读取
总结:
- dom平台无关,官方解析方式,一次性加载,方便解析,代码容易编写,当文件过大,容易造成内存溢出
- sax基于事件驱动的解析方式,加载时进行验证判断,内存耗费小,不易编码,很难同时访问一个xml中的多处不同数据
- jdom和dom4j是基于sax扩展
- jdom仅使用具体类而不使用接口,api中大量使用了collections类
- dom4j是jdom的一种智能分支,具有性能优异,灵活性好,功能强大和易使用的特点
如何解决循环依赖
Spring的事务
答:Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。真正的数据库层的事务提交和回滚是通过binlog或者redo log实现的。
spring事务实现主要有两种方法
1、编程式,beginTransaction()、commit()、rollback()等事务管理相关的方法
2、声明式,利用注解Transactional 或者aop配置
介绍一下SpringBoot
答:springboot是spring的子项目,可以简化配置和简化开发
单例有线程安全问题吗?原型呢?
HandlerMapping是什么时候工作的,程序启动的时候还是第一次请求的时候
Spring中的local有没有用过
Nginx有什么作用,怎么应用的
答:Nginx的作用:反向代理、负载均衡、动静结合
有没有参与过项目部署,怎么实现的
异常处理
SpringBoot是怎么运行的
Mybatis常用标签
答:
定义sql语句:select(resultType) insert delete update
映射对象:resultMap resultType
动态sql:if foreach choose set
格式化输出:where set trim
关联关系:collection(集合) assocition(单个)
引用:sql includ(sql语句的代码片段)
Mybatis分页实现
答:通过Page插件接口,引入分页插件。
SpringMVC的注解
答:
@RequestMapping
@RequestBody
@ResponseBody
@PathVariable
@RequestParam
@ControllerAdvice
SpringBoot如何解决跨域问题
1:注解@CrossOrigin
2:继承WebMvcConfigurationAdapter,重写addCorsMappings
3:通过过滤器
Spring容器的启动问题
BeanFactroy怎么理解
答:BeanFactroy是最顶级的接口,里面封装了一些Spring基础的一些功能,是面向spring自己的,它不会实例化所有对象,只有从容器中拿bean的时候才会实例化对象
反向代理的过程
负载均衡怎么理解
四
流控模式有哪些?
答:【QPS是每秒钟的请求数量】
直接:当超过阀值,就会被降级、
关联:当关联的资源达到阈值时就会限流自己、
链路:然后再发送请求至"host:port/testA"时,如果1秒内请求次数超过1次,就会自动触发限流。
项目中有没有用分布式架构
项目中有缓存吗,存在哪里的?
答:有,存在redis中
redis数据类型
答:redis数据类型有string、hash、set、list、Zset
redis中存储了哪些数据
答:日志数据和一些不经常修改的数据
redis常见命令
答:答案在这里
redis设置密码怎么登录
redis常用数据类型,有什么特点
答:string 字符串(可以为整形、浮点型和字符串,一个字符串中存储高达512兆字节的任何内容)
list 列表(实现队列,元素不唯一,先入先出原则)
set 集合(各不相同的元素,set元素最大可以包含2的32次方-1个元素)
hash 散列值(hash的key必须是唯一的)
sort set 有序集合(没有重复元素的字符)
redis的持久化机制
答:redis的持久化机制是AOF和RDB两种
RDB,就是在不同的时间点,将 redis 存储的数据生成快照并存储到磁盘等介质上。
AOF,那就是将 redis 执行过的所有写指令记录下来,在下次 redis 重新启动时,只要把这些写指令从前到后再重复执行一遍,就可以实现数据恢复了。
RDB 和 AOF 两种方式也可以同时使用,在这种情况下,如果 redis 重启的话,则会优先采用 AOF 方式来进行数据恢复,这是因为 AOF 方式的数据恢复完整度更高。
缓存崩坏三问,怎么解决
认证和权限是怎么实现的
MQ的用途/为什么使用消息队列
答:削峰填谷、服务解耦、异步调用
五
SpringCloud了解的多不多,尝试搭建微服务项目吗?
SpringCloud的组件
答:
Eureka
Hystrix
Zuul
Feign
Ribbon
spring config 配置中心
怎么实现分布式锁
Redis的分布式锁是怎么实现的
项目中涉及到高并发的问题了吗
Linux的权限
答:1.更改文件权限 (chmod命令)
chmod [可选项] <mode> <file...>
2.常见的文件权限表示形式有:
-rw------- (600) 只有拥有者有读写权限。
-rw-r--r-- (644) 只有拥有者有读写权限;而属组用户和其他用户只有读权限。
-rwx------ (700) 只有拥有者有读、写、执行权限。
-rwxr-xr-x (755) 拥有者有读、写、执行权限;而属组用户和其他用户只有读、执行权限。
-rwx--x--x (711) 拥有者有读、写、执行权限;而属组用户和其他用户只有执行权限。
-rw-rw-rw- (666) 所有用户都有文件读、写权限。
-rwxrwxrwx (777) 所有用户都有读、写、执行权限。
RPC什么原理,怎么调用远端服务像本地服务
sentinel限流熔断的机制
答:直接限流、关联限流、链路限流和降级
MQ 有什么作用?你都用过哪些 MQ 中间件?
答:1.MQ 可以用来实现削峰填谷,也就是使用它可以解决短时间内爆发式的请求任务,在不使用 MQ 的情况下会导致服务处理不过来,出现应用程序假死的情况,而使用了 MQ 之后可以把这些请求先暂存到消息队列中,然后进行排队执行,那么就不会出现应用程序假死的情况了,所以它的第一个应用就是商品秒杀以及产品抢购等使用场景
2.使用 MQ 可以作为消息通讯的实现手段,利用它可以实现点对点的通讯或者多对多的聊天室功能。
3.可使用 MQ 实现对日志的采集和转发,比如有多个日志写入到程序中,然后把日志添加到 MQ,紧接着由日志处理系统订阅 MQ,最后 MQ 将消息接收并转发给日志处理系统,这样就完成了日志的分析和保存功能
常用的 MQ 中间件有 RabbitMQ、Kafka 和 rocketmq 等,其中 Redis 属于轻量级的消息队列,而 RabbitMQ、Kafka 属于比较成熟且比较稳定和高效的 MQ 中间件。
什么是Dubbo
答:工作在soa面向服务分布式框架中的服务管理中间件。Dubbo是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。言简意赅Dubbo是一个服务管理中间件,dubbo 协议就是属于 header+body 形式,而且也有特殊的字符 0xdabb ,这是用来解决 TCP 网络粘包问题的。
其他
项目模块描述
项目使用了哪些技术
项目的日志
怎么用一个11L,7L的杯子,量出2L水
4L水,用1.5L的瓶子和2.5L的瓶子,怎么平均分
项目中遇到报错如何定位解决
理解老代码会遇见什么问题
更改代码影响别人的模块,怎么解决
项目里解决过什么有意义的东西
出现过哪些异常,什么原因造成的
测试时数据量小,发布后数据量大,怎么确保跑的起来
改老代码看不懂代码怎么解决
答:1.先自己根据文档了解一下代码的功能
2.如果实在理解不了,可以找老员工询问来了解
服务按领域拆分,按功能拆分,不同模块怎么办
改动影响了其他模块,导致出现问题,解决思路是怎么样的。
项目的表结构
介绍一下近期的项目,技术关键点,有挑战的地方。
项目中常用的数据结构,什么场景下使用
交互岗位沟通流程
new String(“a”) + new String(“b”) 会创建几个对象
答:
对象1:new StringBuilder()
对象2:new String(“a”)
对象3:常量池中的"a"
对象4:new String(“b”)
对象5:常量池中的"b"
对象6:new String(“ab”)
Redis的持久化机制RDB和AOF的优缺点分别是什么?
答:RDB的优点:
1.RDB对redis对外提供的读写服务,影响非常小,可以让redis保持高性能
2.RDB会生成多个数据文件,每个数据文件都代表了某一个时刻中redis的数据,可以将这种完整的数据文件发送到一些远程的安全存储上去
RDB的缺点:
1.如果想要在redis故障时,尽可能少的丢失数据,那么RDB没有AOF好。
2.如果数据文件特别大,可能会导致对客户端提供的服务暂停数毫秒,或者甚至数秒
AOF的优点:
1.AOF可以更好的保护数据不丢失,一般AOF会每隔1秒,通过一个后台线程执行一次fsync操作,最多丢失1秒钟的数据
2.AOF日志文件以append-only模式写入,所以没有任何磁盘寻址的开销,写入性能非常高,而且文件不容易破损,即使文件尾部破损,也很容易修复
3.AOF日志文件的命令通过非常可读的方式进行记录,这个特性非常适合做灾难性的误删除的紧急恢复。
AOF的缺点:
1.对于同一份数据来说,AOF日志文件通常比RDB数据快照文件更大
2.AOF开启后,支持的写QPS会比RDB支持的写QPS低
java基础
权限修饰符
String 类的常用方法都有那些?
答:
substring(int beginIndex):截取字符串【含头含尾】
substring(int beginIndex,int endIndex):截取字符串【含头不含尾】
length():字符串的长度
contains():是否包含该字符串
charAt():通过下标获取字符
concat():拼接字符串
equals():比较字符串是否相等
isEmpty():判断字符串是否为空
toUpperCase():字符串转大写
toLowerCase():字符串转小写
endsWith():判断是否是以括号里面的字符结尾
startsWith():判断是否是以括号里面的字符开头
split():分割字符串
getBytes():将字符串转成字节数组类型
indexOf():返回指定字符在此字符串中第一次出现处的索引
lastIndexOf():返回指定字符在此字符串中最后一次出现处的索引
hashCode():获取字符串的地址值
replace(char old,char new):将指定字符进行互换
trim():去除两端空格
char[] toCharArray(): 把字符串转换为字符数组;
成员变量和局部变量的区别
答:1,代码位置不同:成员变量在类里方法外;局部变量在方法里和局部代码块中
2,生命周期不同:成员变量随着对象的存在而存在,随着对象的消失而消失;局部变量随着方法的存在而存在,随着方法的消失而消失
3,初始化不同:成员变量无需初始化;而局部变量必须初始化
4,内存位置不同:成员变量在堆内存,局部变量在栈内存
创建对象的流程
答:1,在栈内存中开辟一块空间,存放引用类型Phone类型的变量p
2,在堆内存中开辟一块空间,存放Phone类型的对象
3,要给这个对象进行初始化,比如:String brand = null;
4,当对象准备好以后,会生成一个唯一的地址值,然后将此地址值交给引用类型的变量p来保存
5,如果以后想要操作此对象的各种资源,可以通过p变量保存的地址值找到该对象
面向对象和面向过程
答:面向过程,强调的是过程,凡事都要亲力亲为;面向结果,强调的是结果,不管是谁做的
如何跳出外层循环?
答:int i=0;
int j=0;
a: for(;i<10;i++){
b:for(;j<10;j++){
if(j==4){
break a; //跳出a所在的循环
}
通过break关键字,加外层循环的关键字来跳出的
多态的优点
答:1,忽略某个对象的类型,就可以调用某些方法
2,提供了程序的可维护性和可扩展性
3,统一了调用标准,多态又叫动态类型绑定,实现了类型的解耦
throw和throws的区别
throw语句用在方法体内,表示抛出异常,由方法体内的语句处理。
throws语句用在方法声明后面,表示再抛出异常,由该方法的调用者来处理。
throws主要是声明这个方法会抛出这种类型的异常,使它的调用者知道要捕获这个异常。
throw是具体向外抛异常的动作,所以它是抛出一个异常实例。
为什么重写equals,hashcode也要重写?
答:1.使用hashcode方法提前校验,可以避免每一次比对都调用equals方法,提高效率
2.保证是同一个对象,如果重写了equals方法,而没有重写hashcode方法,会出现equals相等的对象,hashcode不相等的情况,重写hashcode方法就是为了避免这种情况的出现。
代码:
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
RewriteEqHashCode that = (RewriteEqHashCode) o;
return Objects.equals(id, that.id) &&
Objects.equals(name, that.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name);
InputStream可以new嘛,要怎么创建InputStream流?
答:不可以,因为InputStream是抽象类,要创建InputStream需要提供其实现类:FileInputStream、BufferedInputStream、ObjectInputStream。
创建数组过程
答:1. 在内存中开辟连续的空间,用来存放数据,长度是5
2. 给数组完成初始化过程,给每个元素赋予默认值,int类型默认值是0
3. 数组完成初始化会分配一个唯一的地址值
4. 把唯一的地址值交给引用类型的变量a去保存
什么是进程,进程的特点是什么?
答:进程是系统中可以独立运行的程序。特点是独立性、并发性(各进程之间互不影响)、动态性
阻塞的类型
答:等待阻塞、同步阻塞和其他阻塞
如何将字符串反转?
答:通过StringBuilder类中的reverse()方法
数组的方法有哪些?
答:Array.sort:对数组进行排序
Array.copyof:把数组赋值成一个指定长度的新数组
新数组的长度 大于 原数组, 相当于复制,并增加位置
新数组的长度 小于 原数组, 相当于截取一部分数据
Array.toString:把数组里的数据,用逗号连接成一个字符串[值1,值2]
类加载器有哪些?(检查从下往上,加载从上往下)
答:1、启动类加载器(Bootstrap ClassLoader,最大):这个类加载器负责将存放在<JAVA_HOME>\lib目录中的,或被-Xbootclasspath参数所指定的路径中的,并且是虚拟机识别的(例如rt.jar)类库加载到虚拟机内存中;
2、扩展类加载器(Extension ClassLoader,第二小):它负责加载<JAVA_HOME>\lib\ext目录中的,或者被java.ext.dirs系统变量所指定的路径中的所有类库,开发者可以直接使用扩展类加载器;
3、应用程序类加载器(Application ClassLoader,最小):由于这个类加载器是ClassLoader中的getSystemClassLoader()方法的返回值,所以一般也称为系统类加载器。它负责加载用户类路径(claspath)上所指定的类库,开发者可以直接使用这个类加载器。
破坏双亲委派模型的三大情况
答:1、双亲委派模型的第一次“被破坏”是发生在双亲委派模型出现之前——即JDK1.2发布之前;
2、双亲委派模型的第二次“被破坏”是由于模型自身的缺陷导致的;
3、双亲委派模型的第三次“被破坏”是由于用户对程序动态性的追求而导致的,即热部署(OSGI实现模块化热部署)
引用类型变量和基本类型变量的区别
答:引用类型变量:在堆中存储,不被引用时就会被删除
基本类型变量:在栈中存储,当方法使用完成后,就会被删除
java的特点
答:面向对象
可靠性
安全性
平台无关性
支持多线程
支持网络编程(JavaFX网络编程框架)
面向对象和面向过程的区别
答:面向对象只在乎结果,不在乎过程是如何实现的
优点:代码扩展性强
缺点:执行效率低
面向过程强调过程,讲究亲力亲为
优点:执行效率高
缺点:代码扩展性弱
实现一个函数,功能是统计一个字符串中所有字母的个数
答:答案在这里
字符串和字符的区别
答:含义上:
字符串是由双引号引起来的多个字符
字符是由单引号引起来的单个字符
类型上:
字符串是引用类型
字符是基本类型
内存上:
字符在内存大小中占2位
字符在内存大小中占若干位
整数和浮点数的区别
答:整数的二进制表示的是具体的数据范围
浮点数的二进制表示的是指数位(位运算)
浮点数的范围:最大值:2的(2的31次方-1)
自动装箱和拆箱
答:装箱:基本类型转成包装类型
拆箱:包装类型转成基本类型
在Java在,为什么要有无参构造,并说出应用场景?
答:构造方法有两个作用:
- 给成员变量赋值
- 实现该类对象
为什么类中要有无参的构造方法
答:在框架中,创建对象默认使用的都是无参的构造方法,所以我们在开发中,一定要显示的无参构造方法。
构造器 Constructor 是否可被 override(记住)
答:不可以被重写,因为构造器 Constructor无法被继承
标准的JavaBean的规则
答:1.实现序列化接口
2.显示提供无参数的构造方法
3.提供私有属性,对外提供getter和setter方法
mysql中char和varchar有什么区别?
答:相同点:都是用来存字符串
不同点:char长度固定,最大长度255;varchar长度不固定,设置的长度是指最大长度,最大65535
mybatis的缓存机制
答:mybatis有一级缓存和二级缓存
一级缓存作用于单个session,默认开启,无需手动使用;
二级缓存作用于整个mapper,默认开启,但需要手动使用;
如何使用二级缓存:在你的*Mapper.xml文件中添加cache标签即可,如下图
redis如何管理过期的key?
redis采用 定期 + 惰性 删除的方式来管理key
redis会周期性地扫描当前所有key,发现过期的立即清除,这招叫 定期删除;
但是这样有个问题,扫描间隔太长的话,可能导致某些key多存活一个周期;太短的话,又会很影响性能,所以除了定期扫描,redis在使用某个key时会先校验key是否过期,如果过期直接删除,这招叫
惰性删除