马士兵java八股问题

1.面向对象的特征有哪些方面

java面向对象的三大特性:

        封装:封装把一个对象的属性私有化,隐藏对象的属性和实现细节,仅对外提供公共访问方法(就是把属性设置为private ,在类中实现static方法用于访问这些属性),提高代码的复用性和安全性。

        继承:使用已存在的类的定义作为基础建立新类的技术,新类的定义可以 增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通 过使用继承可以提高代码复用性。继承是多态的前提。关于继承如下 3 点请记住: 1. 子类拥有父类非 private 的属性和方法。2. 子类可以拥有自己属性和方法,即子类可以对父类进行扩展。3. 子类可以用自己的方式实现父类的方法。

        多态:记住重写和重载就OK,重写是方法名和参数列表都一样(在调用这些方法时就会调用子类的方法,而重载是方法名一样,参数列表可不同。可以添加新的。所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒 底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。让程序可以选择多个运行状态,这就是多态性。

        Java实现多态有三个必要条件:继承、重写、父类引用指向子类对象

2.ArrayList LinkedList 的区别是什么

ArrayList 底层以数组实现,是一种随机访问模式。因此查找的时候非常快。ArrayList 在顺序添加一个元素的时候非常方便。而 LinkedList 双向链表的数据结构实现。

LinkedList ArrayList 更占内存,因为 LinkedList 的节点除了存储数据,还存储了两个引用,一个指向前一个元素,一个指向后一个元素。
ArrayList LinkedList 都是不同步的,也就是 不保证线程安全。
3.接口和抽象类的区别是什么
        接口的方法默认是public。所有方法在接口中不能有实现,必须在实现类中重写。而抽象类中可以有非抽象方法。   一个类可以实现多个接口,但抽象类概念 的抽象,是一种模板设计,接口是行为的抽象,是一种行为的规范。
4.哲学家进餐问题:  解决方法:①当所有的筷子(所有的锁)合并成一个集合、列表(一把锁),一个人使用,其他人无法使用   (锁粗化) ②混进一个左撇子  ③混进奇偶数的左撇子
5.什么是MySQl:   MySQL 是一个 关系型数据库管理系统
什么是SQL:(StructuredQueryLanguage) 结构化查询语言
数据库中的数据类型:
        整数类型包括 TINYINT SMALLINT MEDIUMINT INT BIGINT ,分别表示 1 字节、 2 字节、 3 节、 4 字节、 8 字节整数。任何整数类型都可以加上 UNSIGNED 属性,表示数据是无符号的,即非负整 数。
        实数类型 包括 FLOAT DOUBLE DECIMAL DECIMAL可以用于存储比BIGINT还大的整型,能存储精确 的小数。而 FLOAT DOUBLE 是有取值范围的,并支持使用标准的浮点进行近似计算。(只是近似的计算,如果有带小数计算的话,还是得使用DECIMAL进行数据类型定义)
        字符串类型,包括 VARCHAR CHAR TEXT BLOBVARCHAR 用于存储可变长字符串,它比定长类型更节省空间。
                        
                         VARCHAR使用额外1或2个字节存储字符串长度 。列长度小于 255 字节时,使用 1 字节表示,否则使用 2 字节表示。
                        CHAR是定长的,根据定义的字符串长度分配足够的空间。 CHAR 适合存储很短的字符串,或者所有值都接近同一个长度。CHAR存储的内容超出设置的长度时,内容同样会被截断。对于经常变更的数据来说, CHARVARCHAR更好,因为CHAR不容易产生碎片   存取速度要比 varchar快很多, 因为其长度固定,所以会占据多 余的空间,是空间换时间的做法;
                         尽量避免使用TEXT/BLOB类型 ,查询时会使用临时表,导致严重的性能开销。
        日期和时间类型: 尽量使用timestamp ,空间效率高于 datetime
6.数据库的索引:索引是一种 特殊的文件 ,包含对数据表所有记录的 引用指针,它是要占据物理空间的(存在磁盘) 。索引是一种 数据结构 ,索引的实现通常使用 B+树(一种平衡多叉树) ,更通俗的说,索引就相当于 目录 (想一下字典的按音查找),本质就是通过不断缩小想要获取数据的范围来筛选出最终想要的结果,把随机的事件变成顺序事件。 
索引的类型:① 主键索引:数据列不允许重复,不允许为Null,一个表只有一个主键
                      ② 唯一索引:数据列不允许重复,允许为Null  ,一个表可以多个列创建唯一索引
                      ③ 普通索引:没有唯一的限制,允许为Null  
                      ④ 全文索引:目前搜索引擎使用的
B树存的是主键,叶子节点对应除主键外的字段  ,叶子节点包含了非叶子节点的数据(多存了一份),并且都是排好序的   在Mysql中, 一个Innodb页就是一个B+树的节点  叶子节点是双向指针
索引的数据结构:B+树(MySQL默认的—)和哈希表     
        B+树可以支持范围查询和模糊查询(从根出发,子节点,叶子节点),B+ 空间利用率更高 ,可减少 I/O 次数,磁盘读写代价更低, 对于聚簇索引,存储了索引和整行的数据,因此不需要回表查询 ;哈希表对于单个查询(等值查询)较快(调用一次hash函数就能查到),但不稳定,且 必须进行回表查询
较频繁作为查询条件(where后面的字段)的字段才去创建索引
7.数据库的存储引擎: MySQL 中的数据、索引以及其他对象是 如何存储 的,是 一套文件系统的实
。  常用的存储引擎:Innodb引擎:支持事务,提供行级锁和外键的约束。常用于电商网站(结账不成功能够回滚)不支持全文索引  MyIASM引擎: 不提供事务的支持,也不支持行级锁和外键(以读写插入为主的应用程序,比如博客系统、新闻门户网站)。 支持全文索引      MEMORY 引擎:所有的数据都在内存中,数据的处理速度快,但是安全性不高。(断电)  
InnoDB 索引是聚簇索引, MyISAM 索引是非聚簇索引。  ( 索引和数据放在同一个文件当中就是聚簇索引,找到了索引也就找到了数据
8. MyISAM InnoDB 存储引擎使用的锁:
        MyISAM 采用表级锁 (table-level locking)
        InnoDB 支持行级锁 (row-level locking) 和表级锁,默认为行级锁
锁粒度:范围
9.行锁会出现死锁且开销大,但并发能力强,锁冲突概率最低
   表锁不会出现死锁,且开销小,但并发能力弱,容易发生锁冲突
10.死锁及其解决:
        死锁是指两个或多个事务在同一资源上相互占用,并请求锁定对方的资源,从而导致恶性循环的现象。
        方法:1、在同一个事务中,尽可能做到 一次锁定所需要的所有资 源,减少死锁产生概率;
                   2、. 对于非常容易产生死锁的业务部分,可以尝试使用 升级锁定颗粒度 ,通过表级锁定来减少死锁产生的 概率;
        
11.索引覆盖:就是当前查询的Sql语句想要查询的字段已经包含了在当前索引当作了,不用回表,直接将结果返回
12.最左前缀原则:对于联合索引,比如针对a,b,c三个字段建立了一个联合索引,那么在写sql时就一定要提供a字段的条件,因为底层的B+树是按照a,b,c三个字段从左往右去比较大小进行排序的。
13.Innodb是如何实现事务的:
        Innodb通过Buffer Pool,LogBuffer,Redo Log,Undo Log来实现事务,以一个update语句为例: 1.Innodb在收到一个update语句后,会先根据条件找到数据所在的页,并将该页缓存在Buffer Pool中(内存中) 2.执行update语句,修改Buffer Pool中的数据,也就是内存中的数据  3。针对update语句生成—个RedoLog对象,并存入LogBuffer中  4.针对update语句生成 undolog日志,用于 事务回滚  5.如果事务提交,那么则把RedoLog对象进行持久化,后续还有其他机制将Buffer Pool中所修改的数据页持久化到磁盘中  6.如果事务回滚,则利用undolog日志进行回滚
14.Mysql慢查询该如何优化:   1.检查是否走了索引,如果没有则优化SQL利用索引       2.检查所利用的索引,是否是最优索引  3,检查所查字段是否都是必须的,是否查询了过多字段,查出了多余数据4.检查表中数据是否过多,是否应该进行分库分表了  5.检查数据库实例所在机器的性能配置,是否太低,是否可以适当增加资源
15.Redis有哪些数据结构?分别有哪些典型的应用场景?Redis的数据结构有:
        1.字符串:可以用来做最简单的数据,可以缓存某个简单的字符串,也可以缓存某个json格式的字符串,Redis分布式锁的实现就利用了这种数据结构,还包括可以实现计数器、Session共享、分布式ID
        2.哈希表:可以用来存储一些key-value对,更适合用来 存储对象
        3.列表: Redis的列表通过命令的组合,既可以当做栈,也可以当做队列来使用,可以用来缓存类似微信公众号、微博等 消息流数据(双向链表来实现)
        4.集合:和列表类似,也可以存储多个元素,但是不能重复,集合可以进行交集、并集、差集操作,从而可以实现类似, 我和某人共同关注的人、朋友圈点赞等功能
        5.有序集合:集合是无序的,有序集合可以设置顺序,可以用来实现 排行榜功能。每个元素包含数据本身和一个对应的分数(score),zset的数据本身不允许重复,但是score允许重复
16.分布式锁:
        分布式锁是控制分布式系统之间 同步访问 共享资源的一种方式,不同系统或者同一系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,需要通过一定的互斥手段来防止彼此的干扰,以保证一致性。
        Redis实现分布式锁(Redis支持基本的事务操作): SET key value  NX  EX second  实现分布式锁,当指定键不存在时,向Redis 中添加一个键值对,并设置过期时间,需要释放锁时,使用get key  比较前后value是否一致,如果一致,使用delete删除键即可,否则会进行回滚(其他客户端改变了键值对)(最重要的)
        然后还要利用lua脚本来保证多个redis操作的原子性
        同时
还要考虑到锁过期 ,所以需要额外的一个看门狗(watch dog)定时任务来 监听锁是否需要续约
        同时还要考虑到redis节点挂掉后的情况,所以需要采用红锁的方式来同时向N/2+1个节点申请锁,都申请到了才证明获取锁成功,这样就算其中某个redis节点挂掉了,锁也不能被其他客户端获取到
 
17.Redis的数据结构有:
        1.字符串:可以用来做最简单的数据,可以缓存某个简单的字符串,也可以缓存某个json格式的字符串, Redis分布式锁的实现就利用了这种数据结构,还包括可以实现计数器、Session共享、分布式ID
        2.哈希表:可以用来存储一些key-value对,更适合用来存储 对象
        3.列表:Redis的列表通过命令的组合,既可以当做栈,也可以当做队列来使用,可以用来缓存类似微信公众号、微博等 消息流数据
        4.集合:和列表类似,也可以存储多个元素,但是不能重复,集合可以进行交集、并集、差集操作,从而可以实现类似, 我和某人共同关注的人、朋友圈点赞等功能
        5.有序集合:集合是无序的,有序集合可以设置顺序,可以用来实现排行榜功能
18. 缓存穿透、缓存击穿、缓存雪崩分别是什么
        缓存中存放的大多都是 热点数据,目的就是可以让请求直接从缓存中获取到数据,而不用访问Mysql.
        1,缓存雪崩:如果缓存中某一时刻 大批热点数据同时过期,那么就可能导致大量请求直接访问Mysql了,解决办法就是在过期时间上增加一点随机值,另外如果搭建一个高可用的Redis集群也是防止缓存雪崩的有效手段
        2.缓存击穿:和缓存雪崩类似,缓存雪崩是大批热点数据失效,而缓存击穿是指 某一个热点key突然失效,也导致了大量请求直接访问Mysql数据库,这就是缓存击穿,解决方案就是考虑 这个热点key不设过期时间
        3,缓存穿透:假如某一时刻访问redis的 大量key都在redis中不存在(比如黑客故意伪造一些乱七八糟的key),那么也会给数据造成压力,这就是缓存穿透,解决方案是使用 布隆过滤器,它的作用就是如果它认为一个key不存在,那么这个key就肯定不存在,所以可以在缓存之前加一层布隆过滤器来拦截不存在的key
19.Redis和Mysql如何保证数据一致
         延时双删(删了两次redis),步骤是:先删除Redis缓存数据,再更新Mysql,延迟几百毫秒再删除Redis缓存数据,这样就算在更新Mysq时,有其他线程读了Mysql,把老数据读到了Redis中,那么也会被删除掉,从而保持数据一致.
20. 互斥同步锁( 悲观锁) 非互斥同步锁( 乐观锁):
       什么是悲观镇。什么是乐观锁?
        悲观锁:修改数据把数据锁住,在更改。别人此时无法访问       synchronized和Lock类
        乐观锁:常用就是 CAS( 比较和替换 算法。 版本号,原子类AtomicInteger
        实际场景举例;
        乐观锁( 假设不会发生并发冲突): push代码到仓库  先检查版本号,版本号不一致的话就得先拉取,在合并,然后上传,一致的话就直接上传
        悲观锁( 假定必发生并发冲突):数据库中select xxo for update;
        乐观锁添加一个字段version =1; 如果某个线程改掉过这行记录,version =2;此时进行update xcxcx where version =1 这个就无效
        悲观锁的劣势:1、阻塞、唤醒,性能劣势  阻塞需要排队,唤醒需要时间 乐观锁的效率高于悲观锁; 2、永久阻塞(永远不能释放锁) 3、优先级,阻塞的优先级越高,持有锁的优先级就越低。导致优先级反转的问题   也就是优先级低的线程拿到锁,会阻塞优先高的线程拿到锁
        适用场景
        乐观锁:并发 写入少,大多数都是读操作
        悲观锁: 并发写入多的情况,临界区有IO操作,临界区代码复杂,临界区竞争激烈
21. for update
        

       select查询语句是不会加锁的,但是select .......for update除了有查询的作用外,还会加锁呢,而且它是悲观锁。那么它加的是行锁还是表锁,这就要看是不是用了索引/主键。没用索引/主键的话就是表锁,否则就是是行锁。  锁住了就会阻塞(执行写操作时)

22.视图: 是一种虚拟表,在物理上是不存在的,其内容与真实的表相似,是从 一个或几个基本表 (或视图)导出的表,基表中的数据发生变化,从视图中查询出的数据也随之改变,视图的建立和删除不影响基本表, 对视图内容的更新(添加,删除和修改)直接影响基本表 。是为了提高复杂SQL语句的复用性 表操作的安全性
         当视图来自多个基本表时,不允许添加和删除数据。
视图的作用 :保护数据。可以给用户授予表的特定部分的访问权限而不是整个表的访问权限
23.Sql语句分为几类:
        数据定义语言 DDL(Data Definition Language): Create drop alter  
        数据查询语言 DQL( Data Query Language ): Select
        数据操纵语言DML  Data Manipulation Language Insert Update Delete
         数据控制功能 DCL Data Control Language ): Grant Revoke Commit Rollback
24.非聚簇索引不一定会回表查询, 这取决于查询语句所要求的字段 是否全部命中了索引 ,如果全部命中了索引,那么就不必再进行回表查询   
        假设我们在员工表的年龄上建立了索引,那么当进行select age from employee
where age < 20 的查询时,在索引的叶子节点上,已经包含了 age 信息,不会再次进行回表查询
25. int(20)中的20 指 显示字符的长度 ,但仍占 4 字节存储, 存储范围不变
       char(10) 表示存储定长的 10 个字符,不足 10个就用空格补齐,空格表示占位不算一个字符
        varchar(10) 表示存储 10个变长的字符,,空格也按一个字符存储
26. drop delete truncate的区别
        delete是逐行删除表中数据,速度慢, 可回滚
        truncate是直接删除表中数据 , 不可回滚        上面两个操作 表结构都还在 ,只是表数据没了
        而drop是直接 从数据库中删除表 ,索引和权限都会被删除, 不可回滚
27. explain语句结果中各字段的含义
         type ( 非常重要,可以看到 有没有走索引 ) 访问类型
        key  实际上使用的索引
        key_len  实际使用到的索引长度
        rows 预估需要读取的记录条数
28.  字段为什么要求定义为 not null
         null值会占用更多的字节 ,且会在程序中造成很多与预期不符的情况。
29. CRUD比较慢,如何优化?分库分表该怎么做:
        1. 限定数据的范围: 务必禁止不带任何限制数据范围条件的查询语句。比如:我们当用户在查询订单 历史的时候,我们可以控制在一个月的范围内。;
        2. 读/写分离: 经典的数据库拆分方案,主库负责写,从库负责读;
        3. 缓存: 使用MySQL的缓存,另外对重量级、更新少的数据可以考虑使用应用级别的缓存;
        4. 通过分库分表的方式进行优化:
                ①垂直分表(一张表中的列进行拆分): 根据数据库里面 数据表列的相关性进行拆分 。 例如,用户表中既有用户的登录信息又有用户的基本信息, 可以将用户表拆分成两个单独的表,甚至放到单独的库做分库。有点:行数据变少,简化表的结构,易于维护  缺点:主键会出现冗余,让事务变得复杂
                ②水平分表(一张表中行进行拆分)
 30.Mysql 默认隔离级别: Repeatable Read
31.分布式锁一般有三种实现方式:①。 基于Redis的分布式锁  ②。 基于ZooKeeper的分布式锁(使用 顺序节点临时节点的特性,临时节点:客户端与服务器端建立连接时创建,断开连接时删除。 顺序节点:当客户端进行请求时,先创建节点,然后比较节点的序号,当比自己序号小的节点并没有占用资源时,则使用,否则进入循环等待)  ③。数据库的乐观锁,实际上就是 创建一张新表,请求占用时就insert(利用主键和唯一索引的特性),删除时则delete。
        主流的实现方式就前两种。zookeeper分布式锁的特点是 高一致性,因为zookeeper保证的是 CP,所以由它实现的分布式锁更可靠,不会出现混乱。redis分布式锁的特点是 高可用,因为redis保证的是 AP,所以由它实现的分布式锁可能不可靠,不稳定(一旦redis中的数据出现了不一致),可能会出现多个客户端同时加到锁的情况。
  • 一致性(C:Consistency) 
  • 可用性(A:Available)
  • 分区容错性(P:Partition Tolerance)
32.分布式ID的生成方案:

自增的就容易泄密,随机的话索引效率太低
最好的就是雪花算法,在java中雪花算法生成的id(64位)是用Long存储的 ,snowflake可以保证所有生成的id是按时间趋势递增,而且在整个分布式系统内不会产生重复id(因为有时间戳和工作机器id)
33. Redis持久化,Redis是单线程
        RDB:快照的形式,比如说每一个小时保存一次当前的快照
        AOF:二进制文件,每次写操作的时候才会记录  
        AOF文件保存的数据集比RDB要完整
34.Redis缓存回收
        是因为内存满了,需要释放一些,而Redis删除缓存是因为用不到了,或者过期了
        

以上这种策略还是得根据具体业务来选定 

35.常见的集群分类

        ①主从复制集群  ②分片集群(分而治之)

36.分布式锁的使用原因:

        在单体架构中,多个线程都是属于同一个进程的,所以在线程并发执行时,遇到资源竞争时,可以利用ReentrantLock   synchronized等技术来作为锁,来控制共享资源的使用。
        而在分布式架构中,多个线程是可能处于不同进程中的,而这些线程并发执行遇到资源竞争时,利用ReentrantLock.synchronized等技术是没办法来控制多个进程中的线程的,所以需要分布式锁,意思就是,需要一个分布式锁生成器,分布式系统中的应用程序都可以来使用这个生成器所提供的锁,从而达到多个进程中的线程使用同一把锁。

        

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值