【八股文大白话整理】

Java

重载和重写的区别

这两个都是多态的一种表现形式。
重载是在编译器通过方法中形参的静态类型确定调用方法版本的过程,是多态在编译期的表现形式。判定只有两个条件:1. 方法名一致 2. 形参列表不同
重写是在方法运行时,通过调用者的实际类型来确定调用的方法版本。即子父类中的重写方法在对应的class文件常量池的位置相同,一旦子类没有重写,那么子类的实例就会沿着这个位置往上找,直到找到父类的同名方法。
重写只发生在可见的实例方法中,静态方法不存在重写,形式上的重写只能说是隐藏。私有方法也不存在重写,父类中private 的方法,子类中就算定义了,也是一个新的方法。静态方法和实例方法不存在相互重写。
重写满足一个规则:两同两小一大。两同指方法名和形参列表一致,两小指重写方法的返回值(引用类型)和抛出异常,要和被重写方法的返回值(引用类型)和抛出异常相同或者是其子类。如果返回值是基本数据类型,那么重写方法和被重写方法必须相同,且不存在自动拆装箱的问题。一大是指重写方法的访问修饰符大于等于被重写方法的访问修饰符。

接口和抽象类的区别

  • 接口中都是抽象方法,抽象类中既可以有抽象方法也可以有普通方法
  • 接口采用implement关键字修饰,抽象类使用abstract关键字修饰
  • 接口只能定义静态常量,抽象类可以定义成员变量
  • 子类中必须实现接口的所有方法,抽象类的子类仅需实现所有的抽象方法
  • 一个类可以实现多个接口,但只能继承一个抽象类
  • 接口中不能有构造方法,抽象类中可以有构造方法

final,finally和finalize的区别

finally 是一个关键字,它经常和 try 块一起使用,用于异常处理。使用 try…finally 的代码块中,finally 部分的代码一定会被执行,所以我们经常在 finallv 方法中用于资源的关闭操作。
JDK1.7 中,推荐使用 try-with-resources 优雅的关闭资源,它直接使用 try0 进行资源的关闭即可,就不用写 finally 关键字了。finalize 是 Object 对象中的一个方法,用于对象的回收方法,这个方法我们一般不推荐使用,finalize 是和垃圾回收关联在一起的,在 Java9 中,将 finalize 标记为了 deprecated,如果没有特别原因,不要实现 finalize 方法,也不要指望他来进行垃圾回收。

内部类有哪些分类

内部类有四种:成员内部类,局部内部类,匿名内部类,静态内部类。
静态内部类是定义在类内部的静态类,静态内部类可以访问外部类所有的静态变量,不可访问外部类的非静态变量。
成员内部类是定义在类内部,成员位置上的非静态类,就是成员内部类。成员内部类可以访问外部类所有的变量和方法。包括静态和非静态,私有和公有。
局部内部类是定义在方法中的内部类。定义在实例方法中的局部类可以访问外部类的所有变量和方法,定义在静态方法中的局部类只能访问外部类的静态变量和方法。
匿名内部类是没有名字的内部类,必须继承一个抽象类或者实现一个接口,不能定义任何静态成员和静态方法。当所在的方法的形参需要被匿名内部类使用时,必须声明为final。匿名内部类不能是抽象的,必须实现继承的类或者实现的接口的所有抽象方法。

反射的基本原理和反射创建类实例的三种方式

反射机制就是使 Java 程序在运行时具有自省(introsp ect) 的能力,通过反射我们可以直接操作
类 和对象,比如获取某个类的定义,获取类的属性和方法 构造方法等。
创建类实例的三种方式是
⚫ 对象实例.getClass();
⚫ 通过 ClassforName()创建
⚫ 对象实例.newInstance)方法创建

序列化和反序列化

序列化就是将对象转换成字节序列格式,反序列化是将字节序列格式转换成对象。

为什么Java中String是不可变类

  1. String 类中包含char数组value,整型的offset和count三个属性,这三个属性都是private的,且没有提供方法修改数值,因此在初始化后无法从外部改变
  2. String 类中的这三个属性都是被final修饰的,无法从内部进行改变
  3. 方法区有一块特殊存储区域-字符串常量池,当创建字符串是,如果在常量池中找到相同的字符串值,则会返回一个已存在字符串的引用而不会创建一个新的对象,假设字符串是可变的,则会导致其他引用这个字符串的变量的值发生变化。

ArrayList和Vector的区别

ArrayList是List的主要实现类,底层用Object[] 存储,线程不安全。Vector是List的古老实现类,底层使用Object[] 存储,线程安全。

ArrayList和LinkedList区别

  • ArrayListLinkedList 都不保证线程安全
  • ArrayList 底层使用Object 数组,LinkedList底层使用双向链表,jdk1.6之前为循环链表,jdk1.7之后取消了循环。
  • ArrayList支持快速随机访问,LinkedList不支持
  • ArrayList的空间浪费主要体现在list的列表会预留一定容量的空间,而LinkedList的空间花费主要体现在它的每一个元素都要消耗比ArrayList更多的空间。

Comparable和Comparator的区别

Comparable 接口是java.lang 包的接口,可实现compareTo(Object obj) 用于排序。Comparator 接口是java.util 包的接口,可实现compare(Object obj1, Object obj2) 用来排序。

Collection和Collections的区别

java.util.Collection 是一个集合接口(集合类的一个顶级接口)。它提供了对集合对象进行基本操作的通用接口方法。
Collections 则是集合类的一个工具类/帮助类,其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。

无序性和不可重复性的含义

无序性是指存储的数据在底层数组中并非按照数组索引的顺序添加,而是根据数据的哈希值决定。
不可重复性是指添加的元素按照equals() 判断时,返回false,需要同时重写equals() 方法和hashcode() 方法。

比较HashSet,LinkedHashSet和TreeSet三者的异同

HashSet 是Set接口的主要实现类,底层是HashMap,线程不安全,可以存储null值。LinkedHashSetHashSet的子类,能按照添加的顺序遍历。TreeSet 底层使用红黑树,元素是有序的,排序方式有自然排序和定制排序。

Queue与Deque的区别

Queue是单端队列,只能从一端插入元素,另一端删除元素,实现上一般遵循先进先出规则,它扩展了Collection 的接口。Deque 是双端队列,在队列两端均可以插入或删除元素,在Queue 基础上增加了在队首和队尾进行插入和删除的方法。

请谈一下对PriorityQueue的认识

PriorityQueue 是在jdk1.5中被引入,与Queue 的区别是PriorityQueue 总是优先级最高的元素先出队。它利用了二叉堆的数据结构实现,底层使用可变长的数组来存储数据。通过堆元素的上浮和下沉,实现了在O(logn)的时间复杂度内插入元素和删除堆顶元素。它是非线程安全的,且不支持存储null和non-Comparable的对象。它默认是小顶堆,但可以接收一个Comparator作为构造参数,从而自定义元素优先级的先后。

HashMap和Hashtable的区别

  • HashMap是非线程安全的,Hashtable 是线程安全的。
  • HashMapHashtable 效率高
  • HashMap 可以存储null的key和value,但null作为键只能有一个,null作为值可以有多个。Hashtable 不允许有null键和null值,否则抛出NullPointerException
  • 创建时如果不指定容量的初始值,Hashtable 初始大小为11,每次扩容变为2n+1,HashMap 初始大小为16,每次扩容变为2n。如果指定容量初始值,Hashtable 会直接使用初始值而HashMap会扩充到2的幂次方

HashSet如何检查重复

比较对象的hashcode值和调用equals() 方法,如果两者均相同,则视为重复元素。在openjdk8中,hashSet的add方法只是简单的调用了HashMap的put方法,是否存在相同元素会在add方法的返回值处体现。

HashMap的长度为什么是2的幂次方

为了能让 HashMap 存取高效,尽量较少碰撞,也就是要尽量把数据分配均匀。我们上面也讲到了过了,Hash 值的范围值-2147483648 到 2147483647,前后加起来大概 40 亿的映射空间,只要哈希函数映射得比较均匀松散,一般应用是很难出现碰撞的。但问题是一个40 亿长度的数组,内存是放不下的。所以这个散列值是不能直接拿来用的。用之前还要先做
对数组的长度取模运算,得到的余数才能用来要存放的位置也就是对应的数组下标。这个数组下标的计算方法是“ (n - 1) & hash”。(n 代表数组长度)。这也就解释了 HashMap 的长度为什么是 2 的幂次方。
我们首先可能会想到采用%取余的操作来实现。但是,重点来了:“取余(%)操作中如果除数是 2 的幂次则等价于与其除数减一的与(&)操作(也就是说hash%length==hash&(length-1)的前提是 length 是 2 的 n 次方;)。” 并且 采用二进制位操作 &,相对于%能够提高运算效率,这就解释了 HashMap 的长度为什么是 2 的幂次方。

fail-fast和fail-safe

fail-fast 是 Java 中的一种 快速失败 机制,java.u til 包下所有的集合都是快速失败的,快速失败会抛出 ConcurrentModificationException 异常,fail-fast 你可以把它理解为一种快速检测机制它只能用来检测错误,不会对错误进行恢复,fail-fast 不一定只在多线程环境下存在,ArrayList 也会抛出这个异常,主要原因是由于 modCount 不等于 expectedModCount。
fail-safe 是 Java 中的一种安全失败机制,它表示的是在遍历时不是直接在原集合上进行访问,而是先复制原有集合内容,在拷贝的集合上进行遍历。 由于迭代时是对原集合的拷贝进行遍历,所以在 遍历过程中对原集合所作的修改并不能被迭代器检测到 所以不会触发 ConcurrentModificationException。java.util.conc urrent 包下的容器都是安全失败的,可以在多线程条件下使用,并发修改。

HashMap和ConcurrentHashMap的区别

ConcurrentHashMap 对整个桶数组进行了分割分段(Segment),然后在每一个分段上都用 lock 锁进行保护,相对于 HashTable 的 synchronized 锁的粒度更精细了一些,并发性能更好,而 HashMap 没有锁机制,不是线程安全的。(JDK1.8 之后 ConcurrentHashMap 启用了一种全新的方式实现,利用 CAS 算法。)
HashMap 的键值对允许有 null,但是 ConCurrentHashMap 都不允许。

ConcurrentHashMap和Hashtable的区别

从底层数据结构上来看:JDK1.7的ConcurrentHashMap底层采用分段的数组+链表实现,JDK1.8采用的数据结构和HashMap1.8的结构一样,数组+链表/红黑树。Hashtable是采用数组+链表的形式,数组是主体,链表是为了解决哈希冲突而存在的。
从实现线程安全的方式上看:在JDK1.7的时候,ConcurrentHashMap(分段锁)对整个桶数组进行了分割分段(Segment),每一把锁只锁容器其中一部分数据,多线程访问容器里不同数据段的数据,就不会存在锁竞争,提高并发访问率。 到了 JDK1.8 的时候已经摒弃了 Segment 的概念,而是直接用 Node 数组+链表+红黑树的数据结构来实现,并发控制使用 synchronized 和 CAS 来操作。Hashtable使用synchronized来保证线程安全,当一个线程访问同步方法时,其他线程也访问同步方法,可能会进入阻塞或轮询状态,如果使用put添加元素,另一个线程不能使用put添加元素,也不能使用get,竞争会越来越激烈,效率越来越低。

ConcurrentHashMap线程安全的具体实现方式

JDK1.7:
首先将数据分为一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据时,其他段的数据也能被其他线程访问。ConcurrentHashMap 是由 Segment 数组结构和 HashEntry 数组结构组成。Segment 实现了 ReentrantLock,所以 Segment 是一种可重入锁,扮演锁的角色。HashEntry 用于存储键值对数据。一个 ConcurrentHashMap 里包含一个 Segment 数组。Segment 的结构和 HashMap 类似,是一种数组和链表结构,一个 Segment 包含一个 HashEntry 数组,每个 HashEntry 是一个链表结构的元素,每个 Segment 守护着一个 HashEntry 数组里的元素,当对 HashEntry 数组的数据进行修改时,必须首先获得对应的 Segment 的锁。

JDK1.8:
ConcurrentHashMap 取消了 Segment 分段锁,采用 CAS 和 synchronized 来保证并发安全。数据结构跟 HashMap1.8 的结构类似,数组+链表/红黑二叉树。Java 8 在链表长度超过一定阈值(8)时将链表(寻址时间复杂度为 O(N))转换为红黑树(寻址时间复杂度为O(log(N)))synchronized 只锁定当前链表或红黑二叉树的首节点,这样只要 hash 不冲突,就不会
产生并发,效率又提升 N 倍。

TreeMap和TreeSet在排序时如何比较元素

TreeSet 要求存放的对象所属的类必须实现 Comparable 接口,该接口提供了比较元素的 compareTo()方法,当插入元素时会回调该方法比较元素的大小。TreeMap 要求存放的键值对映射的键必须实现 Comparable 接口从而根据键对元素进行排序。

Collection工具类的sort方法如何比较元素

第一种要求传入的待排序容器中存放的对象比较实现 Comparable 接口以实现元素的比较。
第二种要求传入Comparator 接口的子类型,需重写compare方法实现元素的比较。

BigDecimal的4大坑

  1. 使用BigDecimal构造函数时,尽量传递字符串而非浮点类型,如果无法满足前者则采用BigDecimal#valueOf方法来构造初始化值,否则参数类型为double时会存在精度损失
  2. 如果比较两个BigDecimal值的大小,采用其实现的compareTo方法;如果严格限制精度的比较,那么则可考虑使用equals方法
  3. 在使用BigDecimal进行(所有)运算时,一定要明确指定精度和舍入模式
  4. BigDecimal转换为字符串的3个方法:toPlainString() 不使用科学计数法;toString() 在必要时使用科学计数法; toEngineeringString() 在必要时使用工程计数法

BigDecimal的坑

MySQL

索引相关

索引相关sql
  • 创建索引: CREATE INDEX indexName ON tableName (columnName(length) [ASC|DESC]);
    ALTER TABLE tableName ADD INDEX indexName(columnName(length) [ASC|DESC]);
  • 查询索引: SHOW INDEX FROM tableName;
  • 删除索引: DROP INDEX indexName ON tableName;
InnoDB与MyISAM索引的区别

MyISAM索引文件和数据文件是分离的,使用B+树实现,主键索引和辅助索引实现是一致的。索引文件存储记录所在页的指针,指向其物理位置。InnoDB的辅助索引data域存储相应记录主键的值而不是地址,其数据文件本身就是主索引文件。

其他

一条select语句,只有当查询条件中了包含多列索引的第一个字段时,才能使用多列索引。

聚簇索引是逻辑上连续且物理空间上也连续。非聚簇索引是逻辑上连续但物理空间上不连续。聚簇索引中,索引数据和表数据在磁盘中的位置是一起的,而非聚簇索引则是分开的,索引节点和表数据之间,用物理地址的方式维护两者的联系。

事务与锁相关

ACID原则
  • Atomicity: 原子性:组成一个事务的一组sql要么全部执行成功,要么全部执行失败
  • Consistency:一致性:一个事务中的所有操作,要么一起改变数据库中的数据,要么都不改变。
  • Isolation: 独立性:多个事务之间相互独立,互不影响。
  • Durability:持久性:一个事务一旦被提交会保持永久性。
脏读,幻读,不可重复读

脏读是指一个事务读到了其他事务还未提交的数据。
不可重复读是指多次读取同一数据,先后读取到的数据不一致。
幻读:另外一个事务在第一个事务要处理的目标数据范围内新增了数据,然后先于第一个事务提交。

数据库隔离级别
  • 读未提交(read uncommited):事务还未提交,其变更就能被别的事务看到
  • 读已提交(read commited):事务提交之后,其变更才能被其他事务看到
  • 可重复读(repeatable read):事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据时一致的。
  • 串行化(serializable):对于同一行记录,写会加写锁,读会加读锁。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。

读未提交级别是基于写互斥锁实现的,当出现多个事务同时操作同一数据的情况时,需要先获取锁资源才允许对数据进行写操作。

实现上,数据库里面会创建一个视图,访问的时候以视图的逻辑结果为准。在可重复读隔离级别下,这个视图是在事务启动的时候创建,读提交隔离级别是在每个sql语句开始执行的时候创建,读未提交隔离级别直接返回记录上的最新值,串行化隔离级别直接用加锁的方式避免串行访问。

事务的实现机制

事务是基于数据库连接的,每个连接在MySQL中用一条工作线程维护。任意一条写sql的执行都会记录三个日志:undo log,redo log, bin log。其中bin log与事务机制无关。undo log主要记录sql的撤销日志,比如目前是insert语句,就记录一条delete日志。redo log记录当前sql归属事务的状态以及记录修改内容和修改页的位置,它是一种预写式日志,在数据发生更改之前会先记录一条prepare状态的日志,然后再执行写操作。

当mysql执行时,遇到start transaction 开始事务的命令,会将后续所有写操作全部关闭自动提交,然后在redo log中为每一条sql语句记录一条prepare状态的日志,并生成对应的撤销日志到undo log。接下来再执行sql,将要写入的数据更新到缓冲区。如果遇见commit提交事务,则先将当前事务中所有的sql的redo log改为commit状态,然后由mysql后台线程进行刷盘。如果遇见rollback回滚事务,则在undo log中找到对应撤销sql执行,将缓冲区内更新过的数据还原。

MySQL的锁机制

以互斥性的维度划分可分为共享锁和排他锁。共享锁是指不同事务之间不会相互排斥,可以同时获取的锁。排他锁是指不同事务之间会相互排斥,同时只能允许一个事务获取的锁。

以锁粒度的维度划分可以分为:

  1. 表锁:又分为全局锁,元数据锁,意向锁,自增锁。InnoDB的锁机制是基于聚簇索引实现的,当sql执行时,如果能在聚簇索引命中数据则加行锁,否则加表锁。元数据锁又称为MDL锁,所有存储引擎的表都会存在一个.frm 文件, 这个文件中主要存储表的结构,该锁就是基于这个文件中的元数据加的,主要在更改表结构时使用。意向锁是InnoDB中为了支持多粒度的锁,兼容表锁和行锁而设计。自增锁是为了维护并发事务下自增字段的有序性设计的。全局锁是基于整个数据库加锁的,此时整个数据库只能允许读,不允许写,一般在对整库做数据备份时使用。
  2. 行锁又称为记录锁,获取行级别的共享锁使用select ... lock in share mode 获取行级别的排他锁使用select ... for update 。间隙锁是用来解决幻读问题的,如果锁加在两条数据之间,锁定的区域就是两条数据之间的间隙,如果加在头尾那区间另一端就是无穷小或无穷大。临键锁是前两者的结合体,每次锁定左开右闭的区间,InnoDB中当尝试对一条数据加锁时,默认加的是临键锁。当事务执行插入语句阻塞时,会生成一个插入意向锁,然后执行插入操作,但当多个事务要向一个区间插入数据时,插入意向锁不会排斥其他事务。
select for update是加行锁还是加表锁

select for update加了行锁还是表锁?

锁的兼容性:

在这里插入图片描述

RC隔离级别+条件为唯一索引+命中:加三把锁:IX意向排他锁(表锁不影响插入),唯一索引的X行级排他锁,主键的X行级排他锁
RC隔离级别+主键:加两把锁,一把IX意向排他锁(不影响插入),一把对应主键的X排他锁(行锁,会锁住那一行)
RC隔离级别+普通索引:命中加三把锁,IX意向排他锁(表锁)、两把X排他锁(行锁,分别对应普通索引的X锁,对应主键的X锁);未命中加一把锁,IX意向排他锁(表锁,不影响插入)
RC隔离级别+无索引:加两把锁,IX意向排他锁(表锁)、一把X排他锁(行锁,对应主键的X锁)如果查询条件对应列上无索引,mysql会全表扫描过滤给每条记录上x锁,后又对不满足条件的记录解锁。
RR隔离级别+唯一索引+命中:加三把锁,一把IX意向排他锁 (表锁,不影响插入),一把对应主键的X排他锁(行锁),一把对应唯一索引的X排他锁 (行锁)
RR隔离级别+主键:加两把锁,一把IX意向排他锁(表锁,不影响插入),一把对应主键的X排他锁(行锁,影响对应主键那一行的插入)
RR隔离级别+普通索引:加四把锁,一把IX意向排他锁 (表锁,不影响插入),一把对应主键的X排他锁(行锁),一把对应唯一索引的X排他锁 (行锁),一把间隙锁(会影响插入)
RR隔离级别+无索引:全表行锁,走聚簇索引进行全部扫描

MVCC相关

begin/start transaction命令不是一个事务的起点,在执行到它们之后的第一个操作InnoDB表的语句,事务才真正启动。

InnoDB引擎中存在四个隐藏字段:

因为InnoDB引擎的表时按聚簇索引的格式存储,因此在构建索引树的时候会选择一个具备唯一非空属性的字段,作为聚簇索引的字段来构建树。如果表结构中不存在这样的字段,会隐式定义一个顺序递增的列row_id 来作为聚簇索引列。

对于一条delete语句而言,执行删除时不会立马删除表的数据,而是将这条数据的delete_bit 字段改为 1/true ,由后台线程自动清理,这样有利于索引树结构的构建。

对于每一个创建的事务,InnoDB会为其分配一个顺序递增的事务id,表中的隐藏字段trx_id 记录最近一次改动当前数据的事务ID。注意mysql在分配事务id时,所有包含写入sql的事务顺序递增,select查询id=0,手动开启的事务也会分配id。

rollback_pointer 记录undo log中旧版本数据的地址。

语句更新一次会生成一个undo log,同时该行数据也会存在多个版本,插入新的undo log时采用头插法,mysql根据undo log和版本计算出需要显示的值。即通过下图中的v和u算出来更新的语句(图片来自mysql45讲资源获取码mdad

在这里插入图片描述
InnoDB为每个事务构造了一个数组,用来保存这个事务启动的瞬间,当前启动了但还没提交的所有事务ID,也就是ReadView快照。

ReadView包含四个核心内容:

  • creator_trx_id: 创建当前这个ReadView的事务Id
  • trx_ids:在生成当前ReadView时,系统内活跃的事务ID列表
  • up_limit_id: 活跃的事务列表中,最小的事务id
  • low_limit_id: 在生成当前ReadView时,系统中要给下一个事务分配的ID值。

在这里插入图片描述
当出现版本链时,旧版本的数据,其隐藏列trx_id不能在ReadView.trx_ids 活跃事务列表中,因为这意味着产生这条旧数据的事务仍未提交。当隐藏列的trx_id 大于目前快照的最大事务ID时,MVCC会自动跳过该版本的数据。

在这里插入图片描述

在这里插入图片描述
但是更新数据的时候都是先读后写的,此时只能读到当前的值,这又被称为当前读。所以此处事务B查询到的结果是3,事务A是1。另外select语句如果加锁了,也是当前读。
上面这种情况是事务C更新后立马提交的情况,如果事务B的更新语句先于事务C的提交发起,此时事务C虽然还未提交但是(1,2)这个版本已经生成,写锁还未释放,而事务B是当前读,必须读最新版本且加锁,所以就被锁上了。

其他

数据库范式
  1. 第一范式指每列的值具有原子性,不可再分割
  2. 要满足第二范式必须先满足第一范式,如果表是单主键,那么主键以外的列必须完全依赖于主键;如果表是复合主键,那么主键以外的列必须完全依赖于主键,不能仅依赖主键的一部分。
  3. 要满足第三范式必须先满足第二范式,第三范式要求表中的非主键列必须和主键直接相关不能间接相关。
  4. 巴斯科德范式是对第三范式的补充,它在第三范式基础上要求联合主键中的字段不能存在依赖。

Redis

设计模式

单例模式

class Chinese {
	private static Chinese objref = new Chinese();
	private Chinese() {}
	public static Chinese getInstance() {
		return objref;
	}
}

public class TestChinese {
	public static void main(String[] args) {
		Chinese obj1 = Chinese.getInstance();
		Chinese obj2 = Chinese.getInstance();
		System.out.println(obj1 == obj2);
	}
}

饿汉式单例模式实现,类一旦加载,就把单例初始化完成,保证getInstance() 时单例已经存在。懒汉式是调用getInstance() 时,才初始化这个单例。

seata相关

seata学习笔记

错题知识点合集

  1. 要将文件中一个字符写入另一个文件首先要读入(FileInputStream) 到内存中去,再读出(FileOutputStream)

  2. 执行顺序: 父类静态代码块,静态变量->子类静态代码块,静态变量->父类局部代码块,成员变量->子类局部代码块,成员变量->子类构造函数 (按声明顺序执行)

  3. session用来表示用户会话,session对象在服务端维护,一般tomcat设定session生命周期为30分钟,超时将失效,也可以主动设置无效。

  4. 接口中方法默认是abstract public ,在接口中只写函数声明是符合语法规则的,但是变量默认是public final static 修饰的,表示静态常量,必须在声明时初始化。

  5. Thread中默认有实现run()方法,没有重写就是调用父类的Thread的run方法。

  6. java系统提供3种类加载器: 启动类加载器(Bootstrap ClassLoader),扩展类加载器,应用程序类加载器

  7. SpringBoot三种配置文件加载优先级: properties > yml > yaml

  8. SpringBoot的maven打包插件会将编写的class文件放在classes目录下,程序所依赖的jar包放在lib目录下,且一并打包启动jar包用的工具。在jar包描述文件MANIFEST.MF 中指定jar的启动 类加载器类和启动类。

  9. springboot配置文件层级:
    在这里插入图片描述

  10. jedis连接redis服务器是直连模式,当多线程模式下使用jedis会存在线程安全问题,解决方案可以通过配置连接池使每个连接专用,这样整体性能就大受影响。

  11. lettuce是基于netty框架进行与Redis服务器连接,底层设计中采用StatefulRedisConnectionStatefulRedisConnection 自身是线程安全的,可以保障并发访问安全问题,所以一个连接可以被多线程复用。

  12. Arrays.asList 转换完成后的 List 不能再进行结构化的的修改,即不能再进行任何 List 元素的增加或者减少的操作

  13. javac.exe是编译功能javaCompiler
    java.exe是执行class,如果没有编译的话是不能执行的,同理,javac.exe编译完以后如果没有java.exe执行的话也是没有运行的

参考资料

  1. 尚硅谷MySQL数据库高频面试题
  2. 黑马程序员SpringBoot2全套视频教程,springboot零基础到项目实战(spring boot2完整版)
  3. 全解MySQL终章:这份爆肝30W字的数据库宝典赠与有缘的你!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值