目录
java
1、Java语言特点
2、JVM vs JDK vs JRE
3、基本数据类型 8种
4、重载和重写区别
5、构造方法有哪些特点?是否可以override
6、 接口和抽象类共同点和区别
7、== 和 equals 区别
8、 String、StringBuffer、StringBuilder区别
9、字符串常量池
10、Exception和Error区别
11、检查型异常 和 非检查型异常
12、finally中的代码一定会被执行吗
13、什么是泛型,作用?
14、反射
15、序列化和反序列化
16、I/O流
17、Hashmap、ArrayList、LinkedList区别
18、 JVM
19、设计模式
20、线程池
数据库
1、MySQL存储引擎
2、MySQL索引
3、MySQL事务
4、并发事务带来哪些问题(脏/幻/不可重复)
5、并发事务的控制方式有哪些
6、SQL标准定义了哪些事务隔离级别
7、表级锁和行级锁区别
8、Redis为什么快?
9、为什么要用Redis/缓存
10、Redis数据结构
常用框架
1、Spring IOC
2、DI
3、AOP
java
1、Java语言特点
简单易学;面向对象(封装、继承、多态);
平台无关性(Java虚拟机实现平台无关性);
支持多线程(Java语言提供了多线程的支持);
可靠性(具备异常处理和字段内存管理机制);
安全性(Java语言提供了多重安全防护机制,如访问权限修饰符、限制程序直接访问操作系统资源);
Java语言支持网络编程并且很方便
封装:把一个对象的状态信息隐藏在对象内部,不允许外部对象直接访问对象的内部信息。但是可以提供一些可以被外界访问的方法来操作属性。就好比我们看不到空调的内部的零件信息(属性),但是可以通过遥控器来控制空调。
继承:继承时使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用继承,可以快速地创建新的类,提高代码的复用,程序的可维护性,节省了大量创建新类的时间。
多态:一个对象具有多种的状态。
2、JVM vs JDK vs JRE
Java虚拟机(JVM)是运行Java字节码的虚拟机。 针对不同的系统有不同的实现,目的是使用相同的字节码。
JDK 是提供给开发者使用的,能够创建和编译Java程序。包含了JRE,同时包含了编译javac以及一些其他工具。
JRE 是java运行时环境。它是运行已编译Java程序所需的所有内容的机会,主要包括Java虚拟机、Java基础类库
3、基本数据类型 8种
- 4种整数型:byte(1)、short(2)、int(4)、long(8)
- 2种浮点型:float(4)、double(8)
- 1种字符类型:char(2)
- 1种布尔型:boolean(4)
4、重载和重写区别
1、重载就是同样的一个方法能够根据输入数据的不同,做出不同的处理。
方法名必须相同,参数类型 / 个数 / 顺序不同,方法返回值和访问修饰符可以不同。
2、重写就是当子类继承父类的相同方法,输入数据一样,但要做出有别于父类的响应时,你就要覆盖父类方法 。
方法名、参数必须相同,子类返回的方法应该比父类方法返回值类型更小或相等,抛出的异常范围小于等于父类,访问修饰符范围大于等于父类
5、构造方法有哪些特点?是否可以override
特点:名字与类名相同;没有返回值,但不能用void声明构造函数;生成类的对象时自动执行,无需调用。
构造方法不能被重写,但可以被重载
6、 接口和抽象类共同点和区别
共同点:
- 都不能被实例化
- 都可以包含抽象方法
- 都可以有默认实现的方法(Java8可以用default关键字在接口中定义默认方法)
区别:
- 接口是行为的抽象,是一种行为的规范,是like a的关系;抽象是对类的抽象,抽象类是is a的关系。
- 接口没有构造方法,抽象类有,方法一般给子类使用
- 接口只有定义,不能有方法的实现,Java1.8中可以定义default方法体,而抽象类可以有定义与实现,方法可以在抽象类中实现
- 抽象体现了继承关系,继承只能单继承。接口体现了实现的关系,实现可以多实现。接口强调特定功能的实现,而抽象类强调所属关系。
- 接口成员变量默认是public static final,必须赋初值,不能被修改;所有的成员方法都是public abstract的。抽象类中成员默认default,可在子类中被重新定义,也可被重新赋值;抽象方法被abstract修饰,不能被private、static、synchronized和native等修饰,必须以分号结尾,不带花括号。
7、== 和 equals 区别
1、==是一个运算符,equals是Object类的一个方法。因此基本数据类型不能使用equals,只有引用类型可以使用equals
2、==两边是基本数据类型,比较的是值,==两边是引用类型比较的是地址;equals从源码上看,如果不重写的话就相当于==号,也就是说比较的是地址,重写后则可以根据自己的规则去定义两个对象之间是否相等。
- equals方法判断两个对象是相等的,那这两个对象的hashcode值也要相等
- 两个对象有相同的 hashcode 值,它们一定相等的。
8、 String、StringBuffer、StringBuilder区别
String:不可变,因为value数组是final类型。因为不可变,所以每次生成新对象。线程安全,是final类型。
StringBuffer:可变,父类(AbstractStringBuilder)的value数组不是final类型。线程安全,原因:方法都用了synchronized。
StringBuiler:可变,因为父类(同上)的value数组不是final类型。线程不安全的,单线程的时候建议使用,因为没加锁,速度快
9、字符串常量池
字符串常量池:是JVM为了提升性能和减少内存消耗,针对字符串(String类)专门开辟的一块区域,主要目的是为了避免字符串的重复创建。
10、Exception和Error区别
在java中,所有的异常都有一个共同的祖先 java.lang 包中的 Throwable 类。Throwable 类中有两个重要的子类:
- Exception:程序本身可以处理的异常,可以通过catch来进行捕获。它可以分为Checked Exception(检查型异常)和(非检查型异常)
- Error:属于程序无法处理的错误,不建议通过catch捕获。例如:Java虚拟机运行错误(Virtual MachineError)、虚拟机内存不够错误(OutOfMemoryError)、类定义错误等。这些错误发生的时候,Java虚拟机一般会选择线程终止。
11、检查型异常 和 非检查型异常
检查型异常:Java代码在编译过程中,如果受检查异常没有被 catch 或 throws 关键字处理的话,就没办法通过编译。比如:classNotFoundException、SQLException
非检查型异常:Java代码在编译过程中,我们即使不处理,也可以正常通过编译,比如:NullPointerException(空指针错误)、参数错误、数组越界错误、类型转换错误等
12、finally中的代码一定会被执行吗
不一定!比如 finally 之前虚拟机被终止运行的话,finally 中的代码就不会被执行。
程序所在线程死亡; 关闭CPU的情况 下都不会被执行。
13、什么是泛型,作用?
Java泛型是JDK5中引入的一个新特性。使用泛型参数,可以增强代码的可读性、稳定性。
编译器可以对泛型参数进行检测,并且通过泛型参数可以指定传入的对象类型。
比如:ArrayList<Person> persons = new ArrayList<Peoson>()这行代码就指明了该ArrayList<Person>()这行代码就只能传入Person对象,如果传入其他类型的对象就会报错。
ArrayList<E> extends AbstractList<E>
并且,原生 List 返回类型是 Object,需要手动转换类型才能使用,使用泛型后编译器自动转换。
泛型的使用方式:
1、泛型类 2、泛型接口 3、泛型方法
14、反射
通过反射可以获取任意一个类的所有属性和方法,还调用这些方法和属性。
优点: 可以让我们的代码更加灵活,为各种框架提供开箱即用的功能提供了遍历。
缺点:增加了安全问题,比如可以无视泛型参数的安全检查。另外,反射的性能也要稍微差点,不过,对于框架来说实际是影响不大的。
应用场景:平时大部分时候在写业务代码,很少会接触到直接使用反射机制的场景。但是,这并不代表反射没有用。正式因为反射,才能轻松的使用各种框架,像Spring/Spring Boot、MyBatis等等都大量使用了。
这些框架中也大量使用了动态代理,而动态代理的实现也依赖反射。
15、序列化和反序列化
序列化:将数据结构或对象转换成二进制字节流的过程
反序列化:将在序列化过程中所生成的二进制字节流转换成数据结构或者对象的过程。
序列化的主要目的是通过网络传输对象或者说是将对象存储到文件系统、数据库、内存中。
16、I/O流
- InputStream / Reader:所有的输入流的基类,前者是字节输入流,后者是字符输入流
- OutputStream / Writer
17、Hashmap、ArrayList、LinkedList区别
Arraylist实现了Collection下的接口,是基于数组的结构,因为地址的连续性,导致长度固定,类型固定,灵活性不足,删除和插入性能降低。捏村不足要动态块肉,每次是原来的1.5倍。
Linkedlist实现了Collectionxia的list和Queue接口,基于双向链表的结构,由于链表的结构,导致查询慢,插入删除快
HashMap实现了Map接口,本质是一个数组,然后通过计算获得其应该存放的下标位置。如下标位置重复,<7存放在链表结构里,>=7存放在树结构中。Key-value映射关系,可以通过key快速查找定位相对于的value值。但是相同的key值也会映射同一下标,导致HashMap结构复杂。
HashMap底层采用数组+链表(JDK1.7),采用数组+链表+红黑树(JDK1.8)。线程不安全
容器:HashMap默认容器长度为16,扩容因子为0.75,以2的n次方扩容,最高可扩容30次。
扩容机制JDK1.8:1、先生成新数组2、遍历老数组中的每个位置上的链表或红黑树(链表元素个数大于8,数组的长度大于等于64,则生成一个新的红黑)3、如果是链表,则直接将链表中的每个元素重新计算下标,并添加到新数组中4、如果是红黑树,先遍历红黑树,先计算出红黑树中每个元素对应在新数组中的下标位置5、所有元素转移完了之后,将新数组赋值给HashMap对象的table属性。
18、 JVM
JVM
一次编写,到处运行;自动内存管理,垃圾回收机制
19、设计模式
【精选】七种常用的设计模式-CSDN博客
20、线程池
【精选】Java 多线程:彻底搞懂线程池_多线程线程池-CSDN博客
优势:
1、降低资源消耗,通过重复利用已创建的线程降低线程创建和销毁造成的消耗;
2、提高响应速度,当任务到达时,任务可以不需要等到线程创建就能立即执行;
3、提高线程的可管理性,线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。
数据库
1、MySQL存储引擎
默认存储引擎是InnoDB。并且,所有存储引擎中只有InnoDB是事务性存储引擎,也就说只有InnoDB支持事务。
- InnoDB提供事务支持,实现了SQL标准定义了四个隔离级别,具有提交(commit)和回滚(rollback)的能力。
- 并且,InnoDB默认使用的 可重读 隔离级别可以解决幻读问题发生。
- InnoDB支持外键。外键对于维护数据一致性非常有帮助,但是对性能有一定损耗。
- 使用InnoDB的数据库在异常崩溃后,数据库重新启动的时候会保证数据库恢复到崩溃前的状态。这个恢复的过程依赖于 redo log
MySQL存储引擎采用的是插件式架构,支持多种存储引擎
2、MySQL索引
索引类型
按照数据结构维度划分:
- B树索引:MySQL里默认和最常用的索引类型。只有叶子节点存储value,非叶子节点只有指针和key
- 哈希索引:类似键值对的形式,一次即可定位
- 全文索引:对文本的内容进行分词,进行搜索。目前只有CHAR、VARCHAR、TEXT列上可以创建全文索引。一般不会使用,效率较低。
按照底层存储方式角度划分:
- 聚簇索引:索引结构和数据一起存放的索引,InnoDB中的主键索引就属于聚簇索引。
优点:查询速度非常快,因为整个B+树本身就是一颗多叉平衡树,叶子节点也都是有序的,定位到索引的节点,就相当于定位到了数据。对排序查找和范围查找优化:聚簇索引对于主键的
- 非聚簇索引:索引结构和数据分开存放的索引,二级索引就属于非聚簇索引。
按照应用维度划分:
- 主键索引:加速查询+列表唯一+表中只有一个
- 普通索引:仅加速查询
- 唯一索引:一个索引包含所有需要查询的字段的值
- 联合索引:多列值组成一个索引,专门用于组合搜索。
- 全文索引
3、MySQL事务
当我们需要插入多条相关联的数据到数据库,可能会因数据库中途突然因为某些原因挂掉;客户端突然因为网络原因连接不上数据库了;并发访问数据库时,多个线程同时写入数据库,覆盖了彼此的更改……这个问题都会导致数据的的不一致性。
事务就是逻辑上的一组操作,要么都执行,要么都不执行。
# 开启一个事务 START TRANSACTION; # 多条 SQL 语句 SQL1,SQL2…… # 提交事务 Commit;
关系型数据库事务都有ACID特性(原子性、一致性、隔离性、持久性)
- 原子性(Atomicity):事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用。
- 一致性(Consistency):执行事务前后,数据保持一致,例如转账业务中,无论事务是否成功,转账者和收款人的总额应该是不变;
- 隔离性(Isolation):并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的;
- 持久性(Durability):一个事务被提交之后。他对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。
4、并发事务带来哪些问题(脏/幻/不可重复)
脏读:一个事务读取数据并且对数据进行了修改,这个修改对其他事务来说是可见的,即使当前事务还没有提交。这时另一个事务读取了这个还未提交的数据,但第一个事务突然回滚,导致数据并没有被提交到数据库,那第二个事务读取到的就是脏数据。
不可重复读:指在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。
幻读:幻读与不可重复读类似。它发生在一个事务读取了几行数据,接着另一个并发事务插入了一些数据时。在随后的查询中,第一个事务就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。
5、并发事务的控制方式有哪些
MySQL中并发事务的控制方式无非两种:锁 和 MVCC。锁可以看作是悲观控制的模式,多版本并发控制(MVCC,Multiversion concurrency control)可以看作是乐观控制的模式。
锁 控制方式下会通过锁来显示控制共享资源而不是通过调度手段,MySQL中主要是通过读写锁来实现并发控制。
- 共享锁(s锁):又称读锁,事务在读取记录的时候获取共享锁,允许多个事务同时获取(锁兼容)
- 排他锁(X锁):又称写锁/独占锁,事务在修改记录的时候获取排他锁,不允许多个事务同时获取。如果一个记录已经被加了排他锁,那其他事务不能再对这条记录加任何类型的锁(锁不兼容)。
6、SQL标准定义了哪些事务隔离级别
- READ-UNCOMMITTED(读未提交):最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读、不可重复读
- READ-COMMITTED(读已提交):允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。
- REPEATABLE-READ(可重复读):对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
- SERIALIZABLE(可串行化):最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。
7、表级锁和行级锁区别
- 表级锁: MySQL 中锁定粒度最大的一种锁(全局锁除外),是针对非索引字段加的锁,对当前操作的整张表加锁,实现简单,资源消耗也比较少,加锁快,不会出现死锁。不过,触发锁冲突的概率最高,高并发下效率极低。
- 行级锁: MySQL 中锁定粒度最小的一种锁,是 针对索引字段加的锁 ,只针对当前操作的行记录进行加锁。 行级锁能大大减少数据库操作的冲突。其加锁粒度最小,并发度高,但加锁的开销也最大,加锁慢,会出现死锁。行级锁和存储引擎有关,是在存储引擎层面实现的。
8、Redis为什么快?
Redis学习-CSDN博客
1、Redis基于内存,内存的访问速度是磁盘的上千倍;
2、Redis主要是单线程事件循环和 IO多路复用
3、Redis内置了多种优化过后的数据类型/结构实现,性能非常高。
9、为什么要用Redis/缓存
1、高性能:用户下一次在访问这些数据的时候就可以直接从缓存种获取了。操作缓存就是操作内存,速度非常快。
2、高并发:操作缓存能够承受的数据库请求数量是远远大于直接访问数据库的,所以我们可以考虑把数据库中的部分数据转移到缓存中去,这样用户的一部分请求会直接到缓存这里而不用经过数据库。进而,我们也就提高了系统整体的并发。
10、Redis数据结构
1、String:最简单、最常用的一个数据类型。可以用来存储任何类型的数据比如:字符串、整数、浮点数、图片、序列化的对象等。
2、Set:存放不能重复的场景:文章点赞、动态点赞等等。获取多个数据源交集、并集和差集的场景:共同好友(交集)、共同粉丝(交集)、共同关注(交集)、好友推荐(差集)等;随机获取数据源中的元素的场景:抽奖系统、随机点名等。
3、Hash:相当于Java中的HashMap,内部存储了很多键值对。实现结构和Java的HashMap是一样的,都是数组+链表。
4、List:相当于LinkedList,它是链表而不是数组,插入删除操作很快。
5、Zset:最具特色的数据结构,类似于SortedSet和HashMap的集合体,一方面它是一个set,保证了内部的唯一性,另一方面它可以给每个value赋予一个score,代表这个value的排序权重。Zset最后一个value被移除后,数据结构被自动删除,内存被回收;Redis有序集合非常适合那些有序无重复数据的存储,例如:排行榜、经验榜等
常用框架
1、Spring IOC
IOC,控制反转,指将对象的控制权转移给Spring框架,由Spring来负责控制对象的生命周期(比如创建、销毁)和对象间的依赖关系。
最直观的表达就是,从前创建对象的时机和主动权都是由自己把握的,如果在一个对象中使用另外的对象,就必须主动通过new指令去创建依赖对象,使用完后还需要销毁。而在IOC中,所有的对象都被Spring控制,控制对象生命周期的不在是引用对象的生命周期,而在IOC中,所有的对象都被Spring控制,控制对象生命周期的是Spring容器,由Spring容器帮我们创建、查找、注入依赖对象,而引用对象只是被动的接收依赖对象。
2、DI
IoC的一个重点就是在程序运行时,动态的向某个对象提供它所需要的其他对象,这一点是通过DI(Dependency Injection。依赖注入)来实现的,即应用程序在运行时依赖IoC容器来动态注入对象所需要的外部依赖。而Spring的DI具体就是通过反射实现注入的,反射允许程序在运行的时候动态生成对象、执行对象的方法、改变对象的属性。
原理:Spring的IoC的实现原理就是工程加工模式加反射机制。
3、AOP
AOP,为面向切面,用于那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块。
几个名词:
1、连接点:程序运行过程中所执行的方法。在SpringAOP中,一个连接点总代表一个方法的执行。
2、切面:被抽取出来的公共模块,可以用来横切多个对象。Aspect切面可以看成Pointcut切点 和 Advice通知 的结合,一个切面可以由多个切点和通知组成。
3、切点:切点用于定义,要对哪些Join point进行拦截
4、通知:要在连接点上执行的动作
5、目标对象:包含连接点的对象,也被称作通知(Advice)的对象。
6、织入:通过动态代理,在目标对象的方法中执行增强逻辑的过程
7、引入:添加额外的方法或者字段到被通知的类。