Java面试复习

Java基础:

面向过程:把问题分析为一个个步骤,然后用函数把这些步骤实现,在使用的时候一一调用即可。
面向对象:把构成问题的事务分解成各个对象,通过建立对象描述某个事务在解决整个问题的过程中所发生的行为。

  1. 标识符命名规则:
    可以包含英文字母,0-9数字,$以及_ 但不能是数字开头

  2. instanceof关键字:用来测试一个对象是否为一个类的实例

  3. Java的自动装箱和拆箱
    装箱:将基本数据类型转换为包装器类型(int —> Integer) 调用方法:valueOf(int)方法
    自动装箱时若数值在[-128,127]之外,则创建一个新的Integer对象

拆箱:将包装器类型转换为基本数据类型(Integer—> int) 调用方法:intValue方法

  1. 重载和重写:
    重写:子类继承父类的方法,在方法名,参数列表,返回值相同的情况下,修改方法体内容
    注意:访问修饰符的限制一定要大于被重写方法的访问修饰符限制
    (public>protected>default>private)
    重写方法不能抛出新的检查型异常或者声明比被重写方法更广泛的检查型异常
    重载:在一个类中,在方法名相同的情况下,参数列表(参数类型、个数、顺序)不同。

  2. equals与==的区别
    == 比较的是两个对象的地址是否相同,即是否指向了同一个对象
    equals比较的是两个对象的内容是否相等; 对常量进行比较时,常量放在前面可以避免空指针异常

  3. Hashcode的作用
    返回的是根据对象的内存地址换算出的一个值,当集合要添加新的元素时,会先调用该元素的hashcode方法,定位它的物理位置上是否有元素,如果没有则直接存储在这个位置上,如果有则调用它的equals方法进行比较,相同的话就不存了,不同的话就散列其他的地址。

hash冲突:key值不同的元素可能会映象到哈希表的同一地址上
解决方法:
拉链法:相同hash地址的多个节点通过next指针构成一个单向链表进行存储
开放定址法:一旦发生冲突就去寻找下一个空的散列地址,只要散列地址足够大,空的散列地址总能找到
再哈希:发生冲突时,再使用不同的哈希函数计算地址,直至无冲突。

  1. String、StringBuffer、StringBuilder的区别是什么?
    String是只读字符串,并不是基本数据类型,而是一个对象;从底层源码来看是一个final类型的字符数组,所引用的字符串不能被改变。
    StringBuffer和StringBuilder底层都是可变的字符数组,所以在进行频繁的字符串操作时,建议使用这两个。另外StringBuffer对方法加了锁,所以线程安全,StringBuilder是非线程安全。

  2. ArrayList和LinkedList的区别
    List集合类中元素有序,可重复,支持索引(索引即改查的效率高)

ArrayList底层数据结构是动态数组,查询快,增删慢(需要经过数组扩容),线程不安全
当使用无参构造器创建ArrayList对象时,第一次扩容为10,之后再扩容,则为之前的1.5倍。
LinkedLIst底层数据结构是双链表,查询慢(需要在链表上一个一个遍历),线程不安全,效率高(不用经过数组的扩容)

二者都是线程不安全的,最好在单线程中使用;
  1. Java创建对象的几种方式:
    (1)new创建新对象
    (2)通过反射机制:使用Class对象的newInstance()方法来创建对应类的实例
    (3)采用clone机制:拷贝对象是一个新的对象而不是一个引用,拷贝对象与new操作符返回 的对象区别在于这个拷贝已经包含了一些原来对象的信息,而不是对象的初始信息。
    (4)通过反序列化 :序列化主要用到的流是FileOutputstream和ObjectOutputstream,FileOutputstream用于连接磁盘文件,并把字节写出到该磁盘文件;ObjectOutputStream主要用于将对象写出为可转化为字节的数据。而反序列化是通过FileInputstream和ObjectInputstream获取对象。

  2. +=操作符会进行隐性自动类型转换,a+=b隐式的 将+操作的结果类型强制转换为持有结果的类型,而a=a+b则不会自动进行类型转换。
    如:
    short s = 1;
    s = s +1;
    此处报错,short类型在进行运算时会自动提升为int类型,结果s还是short类型
    应改为: s+=1;,会强转匹配左边的数据类型

  3. transient 阻止被序列化

  4. final有哪些用法:
    1.被final修饰的类不可以被继承
    2.被final修饰的方法不可以被重写
    3.被final修饰的变量不可以被改变,如果修饰引用,则引用不可变,引用指向的内容可变
    4.被final修饰的方法JVM会尝试将其内联,以提高运行效率
    5.被final修饰的常量在编译阶段会存入常量池中

mysql

mysql事务

事务特点(ACID ):原子性(Atomicity),一致性(Consistency),隔离性(Isolation)以及持久性(Durability)等

原子性: 一个事务要么全部成功要么全部失败(发生异常或者需要回滚,通过undo log文件恢复,实现回滚)
一致性: 执行事务前后,数据保持一致(如转账业务,无论事务是否成功,两者总金额不变)
持久性: 事务一旦提交,其所作做的修改会永久保存到数据库中,此时即使系统崩溃修改的数据也不会丢失(rodo log)
隔离性: 并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间的数据库是独立的

实现事务功能的三个技术:日志文件(redo log 和 undo log),锁技术以及MVCC
在这里插入图片描述

redo log:叫做重做日志,是用来实现事务的持久性。该日志文件由两部分组成:重做日志缓冲(redo log buffer)以及重做
在这里插入图片描述
修改的内容会先存到Boffer Pool(缓冲池)里头,用作缓存,然后使用后台线程去做缓冲池
和磁盘之间的同步,当进行查询操作时,会先到缓冲池里查找,如果没有命中再去硬盘加载,减少了硬盘的IO开销;
而当同步的时候遇到宕机或者断电(还没来的及执行上图红色操作),引用 了redo log来记录已成功提交事务的修改信息,并把redo log持久化到磁盘,系统重启之后再读取redo log恢复最新数据。

在这里插入图片描述
刷盘时机
InnoDB 存储引擎为 redo log 的刷盘策略提供了 innodb_flush_log_at_trx_commit 参数,它支持三种策略:

0 :设置为 0 的时候,表示每次事务提交时不进行刷盘操作
1 :设置为 1 的时候,表示每次事务提交时都将进行刷盘操作(默认值)
2 :设置为 2 的时候,表示每次事务提交时都只把 redo log buffer 内容写入 page cache
innodb_flush_log_at_trx_commit 参数默认为 1 ,也就是说当事务提交时会调用 fsync 对 redo log 进行刷盘

另外,InnoDB 存储引擎有一个后台线程,每隔1 秒,就会把 redo log buffer 中的内容写到文件系统缓存(page cache),然后调用 fsync 刷盘。
在这里插入图片描述
也就是说,一个没有提交事务的 redo log 记录,也可能会刷盘。
因为在事务执行过程 redo log 记录是会写入redo log buffer 中,这些 redo log 记录会被后台线程刷盘。
在这里插入图片描述

除了后台线程每秒1次的轮询操作,还有一种情况,当 redo log buffer 占用的空间即将达到 innodb_log_buffer_size 一半的时候,后台线程会主动刷盘。

binlog
redo log 是物理日志,记录内容是“在某个数据页上做了什么修改”,属于InnoDB存储引擎
而binlog是逻辑日志,记录内容是语句的原始逻辑,类似于“给ID=2这一行的c字段加1”,属于MYSQL Server层
不管用什么存储引擎,只要发生了表数据更新,都会产生binlog日志
用处:
MYSQL数据库的数据备份、主备、主主、主次都离不开binlog,需要依靠binlog来同步数据,保证数据一致性。
在这里插入图片描述
binlog会记录所有涉及更新数据的逻辑操作,并且是顺序写。

记录格式
binlog日志有三种格式,可以通过binlog_format参数指定
· statement
· row
· mixed

指定statement,记录的内容是SQL语句原文,比如执行一条 update T set update_time = now() where id =1 ,记录内容如下:
在这里插入图片描述
同步数据时,会执行记录的SQL语句,但是有个问题,update_time=now()这里会获取当前系统时间,直接执行会导致与原库的数据不一致。

为了解决这种问题,我们需要指定为row,记录的内容不再是简单的SQL语句了,还包含操作的具体数据,记录内容如下。
在这里插入图片描述
row格式记录的内容看不到详细信息,要通过mysqlbinlog工具解析出来。

update_time=now()变成了具体的时间update_time=1627112756247,条件后面的@1、@2、@3 都是该行数据第 1 个~3 个字段的原始值(假设这张表只有 3 个字段)。

这样就能保证同步数据的一致性,通常情况下都是指定为row,这样可以为数据库的恢复与同步带来更好的可靠性。

但是这种格式,需要更大的容量来记录,比较占用空间,恢复与同步时会更消耗IO资源,影响执行速度。

所以就有了一种折中的方案,指定为mixed,记录的内容是前两者的混合。

MySQL会判断这条SQL语句是否可能引起数据不一致,如果是,就用row格式,否则就用statement格式。

写入机制
binlog的写入时机也非常简单,事务执行过程中,先把日志写到binlog cache,事务提交的时候,再把binlog cache写到binlog文件中。

因为一个事务的binlog不能被拆开,无论这个事务多大,也要确保一次性写入,所以系统会给每个线程分配一个块内存作为binlog cache。

我们可以通过binlog_cache_size参数控制单个线程 binlog cache 大小,如果存储内容超过了这个参数,就要暂存到磁盘(Swap)。

binlog日志刷盘流程如下
在这里插入图片描述
上图的 write,是指把日志写入到文件系统的 page cache,并没有把数据持久化到磁盘,所以速度比较快
上图的 fsync,才是将数据持久化到磁盘的操作
write和fsync的时机,可以由参数sync_binlog控制,默认是0。

为0的时候,表示每次提交事务都只write,由系统自行判断什么时候执行fsync。
在这里插入图片描述
虽然性能得到提升,但是机器宕机,page cache里面的 binlog 会丢失。

为了安全起见,可以设置为1,表示每次提交事务都会执行fsync,就如同 redo log 日志刷盘流程 一样。

最后还有一种折中方式,可以设置为N(N>1),表示每次提交事务都write,但累积N个事务后才fsync。
在这里插入图片描述

在出现IO瓶颈的场景里,将sync_binlog设置成一个比较大的值,可以提升性能。

同样的,如果机器宕机,会丢失最近N个事务的binlog日志。

总结:

redo log是用来恢复数据的 用于保障,已提交事务的持久化特性(保证事务的持久性

undo log:叫做回滚日志,用于记录数据被修改前的信息。(保证事务的原子性
每次写入数据或者修改数据之前都会把修改前的信息记录到 undo log。

MySQL锁技术:
共享锁(shared lock),又叫做"读锁"

事务再读取记录的时候获取共享锁,允许多个事务同时获取

排他锁(exclusive lock),又叫做"写锁"

写锁会排斥其他所有获取锁的请求,一直阻塞,直到写入完成释放锁。

总结:

通过读写锁,可以做到读读可以并行,但是不能做到写读,写写并行
事务的隔离性就是根据读写锁来实现的!

事务的实现
前面讲的重做日志,回滚日志以及锁技术就是实现事务的基础。

事务的原子性是通过 undo log 来实现的

事务的持久性性是通过 redo log 来实现的

事务的隔离性是通过 (读写锁+MVCC)来实现的

而事务的终极大 boss 一致性是通过原子性,持久性,隔离性来实现的!

如果不考虑事务的隔离性:
1.脏读: 是指 一个事务处理过程中读取了另一个未提交的事务中的数据
例:A向B转账,两条SQL语句,第一条B账户+100元,第二条A账户-100元,先执行第一 条语句,B账户钱已经到账(此时即发生了脏读),而第二条无论是否执行,只要事务不提交,所有事务都会回滚,而A账户的钱并没有减少。
2.不可重复读: T1事务第一次读取某个数据,而T2事务立马修改了这个数据并提交到数据库,T1事务再次读取时得到不同的结果。
3.幻读: 事务T1对一个表中所有行的某个数据项做了“1修改为2”的操作。此时事务T2又插入了一行数据,且该数据项还是为1,并提交给了数据库,当事务T1 再次查询时发现有一行未被修改。

MYSQL数据库的四种事务隔离级别
Read Uncommitted(读取未提交内容):最低级别,任何情况都无法保证
Read Committed(读取已提交内容):可避免脏读的发生
Repeatable Read(可重读):可避免脏读、不可重复读的发生 (MYSQL数据库默认
Serializable(可串行化) :可避免脏读、不可重复读、幻读的发生

MySQL高性能优化规范

  1. 所有表使用InnoDB存储引擎
  2. 所有表和字段的字符集统一使用UTF-8
  3. 所有表和字段都要添加注释
  4. 尽量控制单表数据量大小在500万以内
  5. 避免更多的关联操作
  6. 禁止存储文件(如图片)这类大的二进制数据

MySQL索引

索引的底层数据结构
Hash表

为什么MYSQL没有使用Hash表作为索引的数据结构?

  1. Hash冲突问题
  2. Hash索引不支持顺序和范围查询

多线程
Tomcat每处理一个请求都会从线程池里边用一个线程去处理,这显然是多线程的操作。然后每个请求找到Servlet,执行对应的service()方法。

而我们的service方法是无状态的,多个线程请求service方法,往往都没有操作共享变量,不操作共享变量就不会有线程安全问题。在这里插入图片描述
线程池:
在这里插入图片描述
假如多个任务同时触发,有些任务执行时间可能较长,请求就有可能会被阻塞,而如果我们放到线程池中去线程就会直接返回success。可以提高系统的吞吐量

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值