一、Java基础
1.面向过程和面向对象的区别
面向过程:分析出解决问题的步骤,根据步骤用代码一一实现的编程方法。
面向对象:把解决问题的事物分解成多个对象,而建立对象的目的也不是为了完成一个个步骤,而是为了描述某个事物在解决整个问题的过程中所发生的行为。
2.Java的三大特性
封装:通常认为封装是把数据和操作数据的方法封装起来,对数据的访问只能通过已定义的接口。
继承:继承是从已有类得到继承信息创建新类的过程。提供继承信息的类被称为父类(超类/基类),得到继承信息的被称为子类(派生类)。
多态:分为编译时多态(方法重载)和运行时多态(方法重写)。要实现多态需要做两件事:一是子类继承父类并重写父类中的方法,二是用父类型引用子类型对象,这样同样的引用调用同样的方法就会根据子类对象的不同而表现出不同的行为。
3.重载和重写的区别?
重载:编译时多态、同一个类中同名的方法具有不同的参数列表、不能根据返回类型进行区分【因为:函数调用时不能指定类型信息,编译器不知道你要调哪个函数】;
重写(又名覆盖):运行时多态、子类与父类之间、子类重写父类的方法具有相同的返回类型、更好的访问权限。
4.String 类的常用方法都有那些?
indexOf():返回指定字符的索引。
charAt():返回指定索引处的字符。
replace():字符串替换。
trim():去除字符串两端空白。
split():分割字符串,返回一个分割后的字符串数组。
getBytes():返回字符串的 byte 类型数组。
length():返回字符串长度。
toLowerCase():将字符串转成小写字母。
toUpperCase():将字符串转成大写字符。
substring():截取字符串。
equals():字符串比较。
5.抽象类和接口的区别
抽象类可以定义构造函数,接口不可以
抽象类可以定义抽象方法、具体方法,接口只能定义抽象方法
抽象类可以包含静态方法,接口不可以
抽象类的成员权限是public、protected,接口只可以是public
java8开始接口可default修饰符定义默认方法和定义static修饰的静态方法
java9开始接口可定义私有方法
6.有哪些io流
根据处理数据类型的不同分为:字符流和字节流
根据数据流向不同分为:输入流和输出流
7.jdk1.8的新特性
Lambda表达式:Lambda允许函数作为参数传递到方法中。
方法引用:可以直接引用已有Java类或对象的方法或构造器。
Date Time API:加强对日期与时间的处理。
Optional类:用来解决空指针异常。
JavaScript引擎:允许程序在JVM上运行特定的javascript应用。
默认方法:可以理解为一个在接口里面有了一个实现的方法。
新工具:加入像是Nashorn引擎 jjs、 类依赖分析器jdeps的新的编译工具。
Stream API:可以把函数式编程风格引入到Java中。
8.JDK、JRE、JVM 三者之间的关系?
JDK(Java Development Kit):是 Java 开发工具包,是整个 Java 的核心,包括了 Java 运行环境 JRE、Java 工具和 Java 基础类库。
JRE( Java Runtime Environment):是 Java 的运行环境,包含 JVM 标准实现及 Java 核心类库。
JVM(Java Virtual Machine):是 Java 虚拟机,是整个 Java 实现跨平台的最核心的部分,能够运行以 Java 语言写作的软件程序。所有的 Java 程序会首先被编译为 .class 的类文件,这种类文件可以在虚拟机上执行。
9.== 和 equals 的区别?
= =:如果比较的对象是基本数据类型,则比较的是数值是否相等;如果比较的是引用数据类型,则比较的是对象的地址值是否相等
equals 方法:用来比较两个对象的内容是否相等。注意:equals 方法不能用于比较基本数据类型的变量。如果没有对 equals 方法进行重写,则比较的是引用类型的变量所指向的对象的地址(很多类重写了 equals 方法,比如 String、Integer 等把它变成了值比较,所以一般情况下 equals 比较的是值是否相等)。
10.BIO、NIO、AIO 有什么区别?
BIO:Block IO 同步阻塞式 IO,就是我们平常使用的传统 IO,它的特点是模式简单使用方便,并发处理能力低。同步阻塞I/O模式,数据的读取写入必须阻塞在一个线程内等待其完成。
NIO:New IO 同步非阻塞 IO,是传统 IO 的升级,客户端和服务器端通过 Channel(通道)通讯,实现了多路复用。
二、SpringBoot
1.SpringBoot优点
独立运行(内嵌了内嵌了各种 servlet 容器,Tomcat等)
简化配置,spring-boot-starter-web 启动器自动依赖其他组件,简少了 maven 的配置。
自动部署,能根据当前类路径下的类、jar 包来自动配置 bean,
无代码生成和xml配置,配置过程中无代码生成,也无需 XML 配置文
解决了maven依赖版本冲突
配置监控,完成系统服务的监控和应用,,可以监控服务及应用
2.SpringBoot注解
@SpringBootApplication 核心注解
@SpringBootConfiguration:标注当前是配置类
@EnableAutoConfiguration:自动配置
@ComponentScan:扫描
@RestController:用于标注控制层组件(如struts中的action),包含@Controller和@ResponseBody;
@Repository:用于标注数据访问组件,即DAO组件;
RequestMapping:会将 HTTP 请求映射到 MVC 和 REST 控制器的处理方法上。
GetMapping、PostMapping 、DeleteMapping 、PutMapping
@PropertySource :导入properties文件
@Autowired:默认按类型装配,如果我们想使用按名称装配
@column:如果字段名和列名相同,则可以省略。
@ID:表示该属性为主键。
3.springcloud的核心组件
Spring Cloud Eureka:服务注册与发现
Spring Cloud Zuul:服务网关
Spring Cloud Ribbon:客户端负载均衡
Spring Cloud Feign:声明性的Web服务客户端
Spring Cloud Hystrix:断路器
Spring Cloud Confifig:分布式统一配置管理
4. SpringBoot和SpringCloud的区别?
SpringBoot专注于快速方便的开发单个个体微服务。
SpringCloud是关注全局的微服务协调整理治理框架,它将SpringBoot开发的一个个单体微服务整合并管理起来,为各个微服务之间提供,配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等等集成服务
SpringBoot可以离开SpringCloud独立使用开发项目, 但是SpringCloud离不开SpringBoot ,属于依赖的关系
SpringBoot专注于快速、方便的开发单个微服务个体,SpringCloud关注全局的服务治理框架。
5.Spring Boot 的核心配置文件有哪几个
核心配置文件是 application 和 bootstrap 配置文件。
application 配置文件这个容易理解,主要用于 Spring Boot 项目的自动化配置。
bootstrap 配置文件有以下几个应用场景。
6.Spring Boot 的配置文件有哪几种格式?它们有什么区别?
.properties 和 .yml,它们的区别主要是书写格式不同。
1).properties
app.user.name = javastack
2).yml
app: user: name: javastack
spring注入的三种方式是:
构造器注入;setter注入;接口注入。
三、sql
1.如何理解索引的
索引类似图书中的目录索引,可以提高数据检索的效率,降低数据库的IO成本。可以理解为:快速查找排好序的一种数据结构。
2.MySQL索引有哪些
主键索引:不允许重复,不允许为空值。如果表中没有定义主键,InnoDB会选择一个唯一的非空索引代替。
唯一索引:用来建立索引的列的值必须是唯一的,可以为空。
普通索引:用表中普通的列构建的索引,没有任何限制。
全文索引:用大文本对象的列构建的索引。
组合索引:用多个列组合而成的索引,这多个列中不允许有空值。
3.数据库创建索引的缺点?
缺点:
第一,创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。
第二,索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大。
第三,当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。
4.MySQL的排序
order by 排序字段 升序(ASC)降序(desc)
5.select语句的执行顺序
from子句识别查询表的数据;
where子句基于指定的条件对记录进行筛选;
group by 子句将数据划分成多个组别,如按性别男、女分组;
有聚合函数时,要使用聚集函数进行数据计算;
Having子句筛选满足第二条件的数据;
执行select语句进行字段筛选
筛选重复数据;
对数据进行排序;
执行limit进行结果限定
6.MySQL关键字
select、insert、updata、delete、in、and、like、left join、on
7.SQL优化策略
不能使用select * 查询(会增加SQL执行时间和网络开销)
不建议使用子查询
like优化
尽量避免使用text类型
主键索引id的查询是最高的,在MySQL中尽量所有的update都使用主键id去更新
所有数据都得在保存到数据库前进行处理。
如果没有用到变长字段的话比如varchar,那就采用固定大小的纪录格式比如char.
在一个SQL语句中,如果一个where条件过滤的数据库记录越多,定位越准确,则该where条件越应该前移。
应绝对避免在order by子句中使用表达式。
小心使用 IN 和 OR,需要注意In集合中的数据量。建议集合中的数据不超过200个。
8.mybatis的#和$的区别
#{}是占位符,是将传入的值当做字符串的形式,使用的 JDBC 对象是PreparedStatement 对象,执行sql语句的效率更高。能够避免 sql 注入,使得sql语句的执行更加安全。
${}是拼接符,是将传入的数据直接进行字符串拼接,执行sql语句的效率较低。
1.mybatis 返回list集合 怎么处理 返回枚举类型
返回List集合时,需要yyyyy将resultType的值定义为集合中元素类型,而不是返回集合本身。
9.resulttype和resultMap区别
resultMap:如果查询出来的结果的列名和实体属性不一致,通过定义一个resultMap对列名和pojo属性名之间作一个映射关系
resultType:使用resultType进行输出映射,只有查询结果显示的列名和实体的属性名一致时,该列才可以映射成功。
10.主键和外键区别
1.主键是唯一标识一条记录,不能有重复的,而外键是另一表的主键,可以重复。
2.主键不允许为空,而外键可以。
3.主键是用来保证数据完整性,而外键是用来和其他表建立联系的。
4.主键只有一个,外键可以有多个。
四、redis
1.redis是如何配置到项目的
maven 项目 pom.xml 文件中除了Springboot相关依赖还要加入
在resource 下的application.yml配置文件中加入redis服务器地址等配置信息
2.Redis支持的数据类型有哪些?
字符串
hash
list
set
zset
3.Redis为什么是单线程的?
代码更清晰,处理逻辑更简单;
不用考虑各种锁的问题,不存在加锁和释放锁的操作,没有因为可能出现死锁而导致的性能问题;
不存在多线程切换而消耗CPU;
无法发挥多核CPU的优势,但可以采用多开几个Redis实例来完善;
4.什么是缓存穿透?怎么解决?
1、缓存穿透
一般的缓存系统,都是按照key去缓存查询,如果不存在对用的value,就应该去后端系统查找(比如DB数据库)。一些恶意的请求会故意查询不存在的key,请求量很大,就会对后端系统造成很大的压力。这就叫做缓存穿透。
2、怎么解决?
对查询结果为空的情况也进行缓存,缓存时间设置短一点,或者该key对应的数据insert之后清理缓存。
对一定不存在的key进行过滤。可以把所有的可能存在的key放到一个大的Bitmap中,查询时通过该Bitmap过滤。
3、缓存雪崩
当缓存服务器重启或者大量缓存集中在某一时间段失效,这样在失效的时候,会给后端系统带来很大的压力,导致系统崩溃。
4、如何解决?
在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其它线程等待;
做二级缓存;
不同的key,设置不同的过期时间,让缓存失效的时间尽量均匀;
5.session和Cookie的区别
存储位置不同:cookie数据保存在客户端。session数据保存在服务器端。
数据类型不同:两者都是key-value结构,cookie:value只能是字符串类型。session:value是object类型。
存储数据大小不同:cookie:一个 cookie存储的数据不超过3K。session:session存储在服务器上可以任意存储数据。当 session存储数据太多时,服务器可选择进行清理。
生命周期不同:cookie:cookie的生命周期当浏览器关闭的时候就消亡了,cookie的生命周期是累计的,从创建时就开始计时,30min后cookie生命周期结束。session:session的生命周期是间隔的,从创建时开始计时如在30min内没有访问session,那么session生命周期就被销毁。
对象不同:cookie:是针对每个网站的信息,每个网站只能对应一个,其他网站无法访问,这个文件保存在客户端,每次您拨打相应网站,浏览器都会查找该网站的 cookies,如果有,则会将该文件发送出去。cookies文件的内容大致上包括了诸如用户名、密码、设置等信息。session:是针对每个用户的,只有客户端才能访问,程序为该客户添加一个 session。session中主要保存用户的登录信息、操作信息等等。此 session将在用户访问结束后自动消失(如果也是超时)。
五、多线程
1.创建线程的几种方式?
继承 Thread 类创建线程;
实现 Runnable 接口创建线程;
通过 Callable 和 Future 创建线程;
通过线程池创建线程。
2.Java 线程同步的几种方法?
使用 Synchronized 关键字;
wait 和 notify;
使用特殊域变量 volatile 实现线程同步;
使用可重入锁实现线程同步;
使用阻塞队列实现线程同步;
使用信号量 Semaphore。
3.线程池参数
corePoolSize 核心工作的线程数量
maximumPoolSize 线程池最大的线程数量
keepAliveTime 空闲线程可存活的最大时间
unit 时间单位
workQueue 阻塞队列(一般分为有界和无界)
threadFactory 线程工厂,生产线程
rejectedExecutionHandler 拒绝策略(常用四种,也可以自定义)
4.什么是死锁
死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。
解决方法:
在系统中已经出现死锁后,应该及时检测到死锁的发生,并采取适当的措施来解除死锁。
死锁预防。
这是一种较简单和直观的事先预防的方法。方法是通过设置某些限制条件,去破坏产生死锁的四个必要条件中的一个或者几个,来预防发生死锁。预防死锁是一种较易实现的方法,已被广泛使用。但是由于所施加的限制条件往往太严格,可能会导致系统资源利用率和系统吞吐量降低。
死锁避免。
系统对进程发出的每一个系统能够满足的资源申请进行动态检查,并根据检查结果决定是否分配资源;如果分配后系统可能发生死锁,则不予分配,否则予以分配。这是一种保证系统不进入死锁状态的动态策略。
死锁检测和解除。
先检测:这种方法并不须事先采取任何限制性措施,也不必检查系统是否已经进入不安全区,此方法允许系统在运行过程中发生死锁。但可通过系统所设置的检测机构,及时地检测出死锁的发生,并精确地确定与死锁有关的进程和资源。检测方法包括定时检测、效率低时检测、进程等待时检测等。
然后解除死锁:采取适当措施,从系统中将已发生的死锁清除掉。
5.脏读 不可重复读 幻读
脏读,读到了其他事务未提交的数据,未提交意味着这些数据可能会回滚,也就是可能最终不会存到数据库中,也就是不存在的数据。读到了并一定最终存在的数据。
不可重复读,是在一个事务内,最开始读到的数据和事务结束前的任意时刻读到的同一批数据出现不一致的情况。(偏更新)
幻读,比如select 某记录是否存在,不存在,准备插入此记录,但执行 insert 时发现此记录已存在,无法插入,此时就发生了幻读。(偏插入)
6.常见的运行时异常
ClassCastException(类转换异常)
比如 Object obj=new Object(); String s=(String)obj;
IndexOutOfBoundsException(下标越界异常)
NullPointerException(空指针异常)
ArrayStoreException(数据存储异常,操作数组时类型不一致)
BufferOverflowException(IO操作时出现的缓冲区上溢异常)
InputMismatchException(输入类型不匹配异常)
ArithmeticException(算术异常)
注意:运行时异常都是RuntimeException子类异常。
7.get和post的区别?
a、get是用来从服务器上获取数据,而post是用来向服务器传递数据;
b、get将表单中数据按照variable=value的形式,添加到action所指向的URL后面,并且两者用"?“连接,变量之间用”&"连 接;而post是将表单中的数据放在form的数据体中,按照变量与值对应的方式,传递到action所指定的URL。
c、get是不安全的,因为在传输过程中,数据是被放在请求的URL中;而post的所有操作对用户来说都是不可见的。
d、get传输的数据量小,这主要应为受url长度限制;而post可以传输大量的数据,所有上传文件只能用post提交。 e、get限制form表单的数据集必须为ASCII字符;而post支持整个IS01 0646字符集。
f、get是form表单的默认方法。
六、事务
1.如何开启事务,
- 只需要在类或者方法上添加注解 @Transaction 即可开启事务;
- 在配置类中使用注解 @EnableTransactionManagement 然后指定开启事务的地方,这样即使不添加注解 @Transactional 也可以在指定地方开启事务。
事务的隔离阶段
Read uncommitted 读未提交,
顾名思义,就是一个事务可以读取另一个未提交事务的数据。
存在脏读问题:读取未提交的数据,也被称之为脏读(Dirty Read)
Read committed 读提交
就是一个事务要等另一个事务提交后才能读取数据。存在不可重复读问题:同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。
Repeatable read重复读,
就是在开始读取数据(事务开启)时,不再允许修改操作
存在幻读问题:幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。
Serializable 序列化
最高的事务隔离级别,在该级别下,事务串行化顺序执行,可以避免脏读、不可重复读与幻读
2.不用java代码处理返回结果 0 1
3.git代码提交步骤
第1步:同步远程仓库代码:git pull 同步远程仓库代码到本地
第2步:查看当前状态:git status
第3步:提交代码到本地git缓存区:git add 文件名1 文件名2 .
第4步:推送代码到本地git库:git commit -m “提交代码备注” 推送修改到本地git库中
第5步:提交本地代码到远程仓库:git push <远程主机名> <远程分支名> 把当前提交到git本地仓库的代码推送到远程主机的某个远程分之上。
4.没有commit 有冲突怎么处理
首先提交本地修改到git仓,保存自己修改的数据
更新本地代码,即将本地代码与服务器最新代码保持一致
将自己修改的代码融合进本地最新的代码,最后提交。
git 新建分支
创建新分支 git branch 分支名称
切换分支 git checkout 分支名称
git checkout -b 分支名称
合并分支
git checkout master
git merge 分支名称
查看版本号:
可以使用命令“git log”查看:
使用“git reset --hard 目标版本号”命令将版本回退: