一、String能被继承吗?为什么?
不能,String类final修饰,而final类不允许被继承,亦不可修改,改变字符串的值时实质上是新开辟了一份内存空间,创建了一个新的字符串,字符串实质上存储在char[]类型的数组中,
二、int和Integer的区别
1:int是基本数据类型,Integer是包装类型
2:int初始值为0,Integer初始值为null
3:int类型数据存储在栈中,Integer类型数据在[-128,127]时存储在常量池中,超过此范围存储在堆中
三、 String, StringBuffer, StringBuilder 的区别
String是不可变的字符串,可以为null
StringBuffer是可变字符串,效率低,线程安全,不可以为null
StringBuilder是可变字符串,效率高,线程不安全,不可以为null
四、类的实例化顺序
父类静态变量、静态初始化块、子类静态变量、子类静态初始化块,父类非静态变量(成员变量)、父类初始化块、父类构造函数、子类非静态变量、子类初始化块、子类构造函数。
初始化块为{}包含的代码
静态修饰的变量及方法只执行一次,无需实例化亦可调用,可直接使用类名调用,甚至声明一个类的对象为null时,亦可用对象调用
五、抽象类和接口的区别,类可以继承多个类么,接口可以继承多个接口么,类可以实现多个接口么
语法上:
抽象类可以有实现方法,也可以有抽象方法
接口java8后可以有实现方法,default的实现方法如果实现的两个接口中有相同的实现方法,则实现类必须要重写此方法 常量只允许有公共静态常量
类可以继承一个类,实现多个接口
接口可以继承多个接口
作用上:
抽象类相当于一个模板,有公共部分的定义,也允许继承此类的子类有自己的实现
接口相当于一个规范
六、php和Java的区别
1:php是弱类型语言,Java是强类型语言
2:Java是面向对象编程的语言,需要编译代码,php是种服务器脚本语言,不需要编译
3:Java对大小写敏感,php仅对变量的大小写敏感,而函数,关键字,类等不敏感
4:Java使用的是其它的模板引擎,而php内置模板引擎,自身就是模板语言
5:php中有关联数组,类似于java的map
七、final, finally 和 finalize 的区别?
final 用于声明属性,方法和类,表示属性不可变,方法不可被重写,类不可被继承。
finally 是异常处理语句结构的一部分,表示总是执行。
finalize 是 object 类的一个方法,在垃圾收集器执行的时候会调用这个对象回收的方法,供垃圾收集时其他资源的回收,比如关闭文件。
八、Iterator 和 ListIterator 之间有什么区别?
Iterator可以用来遍历list和set,但是只能单向遍历,ListIterator只能遍历List,但是可以双向遍历,它继承了Iterator接口,增加了一些自己的方法,比如增加,删除元素。
九、创建线程的方式
1:继承Thread类创建线程
2:实现Runnable接口创建线程
3:使用Callable和Future创建线程
4:使用线程池例如用Executor框架
十、wait()与 sleep()的区别
sleep方法来自Thread类,wait方法来自Object类,sleep方法不会释放对象锁,也就是睡眠后不会让出系统资源,它需要制定一个睡眠时间,时间到达后自动唤醒;而wait方法需要需要被notify(),或notifyAll()唤醒
十一 、run()、start()、join()方法
run只是线程类的一个普通方法,调用它并未开启新的线程,只是在main主线程中继续按顺序执行;
start是真正的开启了新的线程,线程之间具有并发性,因此它们的父线程可以比它们先结束;
join方法是要求在子线程结束之后才能继续执行父线程
十二、什么是 ThreadLocal?ThreadLocal 和 Synchonized 的区别?
ThreadLocal是线程局部变量,它们的相同之处在与实现多线程中数据隔离
区别:线程局部变量中实现数据隔离的原因是被隔离的数据本身就是只需它去访问,不允许其它数据访问;而Synchonized是为了实现数据的顺序访问;代码如下
package test;
public class Test implements Runnable{
private ThreadLocal<Integer> local = new ThreadLocal<Integer>() { //定义每个窗口已经卖出去的票,初始值为0
public Integer initialValue() {
return 1;
}
};
//Integer count =10;
private int count = 10;//总票数
@Override
public synchronized void run() {
// TODO Auto-generated method stub
while (count>0&&local.get()<=5) {
System.out.println(Thread.currentThread().getName()+"卖出"+(count--)+"号票"+",已经卖出去"+local.get()+"张票");
local.set(local.get()+1);
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Test runnable = new Test();
Thread thread1 = new Thread(runnable,"*********窗口一");
Thread thread2 = new Thread(runnable,"窗口二");
thread1.start();
thread2.start();
}
}
十三、实现Runable接口和继承Thread类的区别
Thread类本身实现了Runable接口,所有并不是普遍认为的资源共享问题,只是类只能单继承,而接口可以多实现,区别在于扩展。
十四、防止表单重复提交
如果是在前台跳转中,用户多次点击提交按钮造成表单重复提交,可以利用js使提交按钮在点击之后为不可用状态;
如果页面已跳转完毕,用户刷新页面显示提交是否重复提交表单,可以在控制器中利用重定向跳转页面。
十五、javaEE和javaSE的区别
javaEE用来开发网站,javaSE用来开发软件
十六、throw和throws的区别
throw作用于方法体中,一旦执行,必将抛出异常;throws作用于方法头上,表示可能会抛出某个或某些异常
十七、java跨平台的原因
java语言首先被编译器执行编译成.class文件,也就是java字节码,.class文件和编译器是跨平台的,然后编译生成的.class文件在不同的平台上有相对应的解释器,因此对于编程者来说,java就实现了跨平台。
十八、垃圾回收的优点和原理。并考虑垃圾回收机制。
在对象创建时开始,垃圾回收器就开始监视着对象的内存地址,大小,引用情况,当GC确定一些对象不被使用时,GC就有责任回收这些对象,程序员可以通过System.gc(),通知GC进行垃圾回收,但GC并不一定会执行
分代垃圾回收:不同的对象的生命周期是不同的,如session对象存活时间一般较长,而生成的string对象,存活时间较短。可能使用一次就不再使用了,因此引入了分代垃圾回收机制,划分为新生代和老年代和持久代,新生代Minor GC,老年代对应Full GC(Major GC),新生代中的对象不稳定容易产生垃圾,因此经常执行Minor GC,老年代中存放的是年轻代中执行多次GC后仍然存活的对象,因此Full GC不经常执行
标记垃圾回收:将被引用的对象进行标记,未被引用的对象并不会被立即清除,一直到内存耗尽时程序挂起,清理所有的未标记对象,当所有的未标记对象清理完毕后,程序继续执行
增量垃圾回收:是为了解决标记垃圾回收的长停顿问题,将堆栈分成多个域,一次仅清理一个域中的垃圾,可减少程序的停顿时间。
十九、垃圾回收算法
标记-清除算法:将标记的对象进行清除,标记和清除的效率都不高,会造成许多的内存碎片;
标记-复制算法:将内存分为两块,当这一块的内存用完啦,就将仍然存活的对象复制到另一块内存中去,然后清除掉这一块的所有对象;适用于新生代,死亡率高,复制的对象较少
标记-整理算法:将标记的对象清除后,让存活的对象向内存的一端移动,去除内存碎片
二十、对象的四种引用类型
1、强引用:GC不会对此种对象进行垃圾回收
2、软引用:GC会在内存溢出前对此类对象进行回收,存储在SoftReference中,当软引用存储的对象被回收后,软引用这个对象也需要进行回收,可以在最初构建这个软引用对象时采用以下方法构建
ReferenceQueue queue = new ReferenceQueue();
SoftReference ref=new SoftReference(aMyObject, queue);
如此,当软用对象所存储的对象被回收后,ref所指定的对象就会被加入到ReferenceQueue中去,我们可以根据此队列是否为null,来判断软引用中存储的对象是否被回收,如果被回收,我们可以把软引用对象的引用清除掉;
也可利用reference.get();方法判断弱引用中存储的对象是否被回收
while ((ref = (EmployeeRef) q.poll()) != null) {
// 清除ref
SoftReference ref = null;
}
3、弱引用:存储在WeakReference中,随时可能会被回收,无论是否会内存溢出
4、虚引用:存储在PhantomReference,必须与引用队列关联使用
https://blog.csdn.net/linzhiqiang0316/article/details/88591907
二十五、为什么重写equals方法时还要重写hashcode方法
首先我们原生equals方法是判断两个对象的内存是否一致,而我们大多数情况下仅需判断对象的数据是否相等即可;而重写equals方法时要遵循一个原则,对象相同,则哈希码相同;哈希码相同,对象不一定相同。如果我们重写equals方法后,不重写hashcode方法,则将两个相同数据的对象当做key存储到set或map中时,仍然会当做两个对象,因为map再对key去重时,调用的是equals和hashcode的双重判断。这俩方方必须同时满足
if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))
二十六、object中定义了哪些方法
clone(),equals(),hashcode(),notify(),notifyAll(),wait(),finalize(),getClass(),toString()
二十七、重载和重写的区别
重载是在同一个类中,对某一个方法进行重载,方法名相同,参数不同(参数类型或个数),方法返回类型及访问权限和是否重载无关;
重写发生在继承中,方法名,参数,返回值类型相同,抛出的异常必须是父类中声明的或父类异常中的子类,访问权限不能父类更小
二十八、继承和实现的区别
类不可以继承多个类,不可以继承接口,可以实现多个接口;
接口可以继承多个接口,不可以实现接口;
二十九、接口和抽象类的区别
抽象类中不一定有抽象方法,但是有抽象方法的话必须设置为抽象类,可以拥有成员变量
接口中的方法默认为public abstract没有方法体,如果要加上方法体的话可以将方法改为静态或将访问权限修改为default
接口中的变量默认为公共静态常量: public static final
接口中的方法默认为: public abstract
类的访问权限为default
三十、单例模式
public class Single {//饿汉式
private Single() {}
private static final Single single = new Single();
public static Single getInstance() {
return single;
}
}
package test;
public class Single {//懒汉式
private Single() {}
private static Single single;
public static Single getInstance() {
// public static synchronized Single getInstance() {
if (single==null) {
single = new Single();
}
return single;
}
}
饿汉式线程安全,懒汉式线程不安全,不过可以通过加锁使懒汉式线程安全
三十一、static和final的区别
static表示静态仅此一份,final表示为不可更改
static修饰的变量或方法可以直接通过类名调用;final修饰的变量表示为常量值不可修改,修饰的方法不能被重写,修饰的类不能被继承;
三十二、匿名内部类
当我们为了使用父类或接口中的某个方法时,我们需要新建一个类继承父类或实现接口,然后new一个子类去调用方法,但是我们可能仅使用一次这个方法,因此生成一个新的类是比较麻烦的,此时我们可以使用匿名内部类。可以简化代码
三十三、基本数据类型
byte,int,double,float,char,boolean,short,long
三十四、Error和Exception的区别
error类一般指与虚拟机相关的问题,如系统崩溃,内存不足等问题,对于此类异常仅依靠程序本身无法恢复,建议让程序终止;
Exception类表示程序可以处理的异常,可以进行捕获处理异常,使程序正常执行。
三十五、异常分为哪几种
分为一般异常和运行时异常,一般异常是在定义时抛出的,这些异常需要被抛出或者捕获,如果不处理将会编译失败;运行异常是在代码执行阶段出现的异常
三十六、集合类型
list可以存储null值,元素有序,ArryList查询快,LinkList增删快,Vector线程安全
set,元素不能重复:HashSet无序可以放入null,TreeSet有序不允许放null
Map:HashMap允许key和value都为null,非线程同步,默认大小是16,增长方式为2的指数倍;
HashTable不允许键值为null,线程同步,默认容量为11,增长方式为old*2+1;
三十七、Collection和Collections的区别
Collection是一个接口,是各种集合结构的父接口,定义了集合的基础操作方法;
Collections是一个类,是一个对集合对象进行操作的帮助类,提供啦对集合的搜索,排序,线程安全化等操作方法
三十八、什么是序列化,如何实现序列化
当我们需要将一个java对象存储到本地文件或通过网络传输时,需要将其转化为字节流的形式,称之为序列化,反之称之为反序列化,要将对象序列化需要在其类前实现Serializable;
三十九、HashMap详解
HashMap的数据结构是一个基于数组的链表结构,在1.8中链表长度超过8时将会转化为红黑树
1、HashMap的主要参数有哪些
capacity:数组长度,默认为16;
MAXIMUM_CAPACITY:极限容量,最大为2的30次方;
负载因子:通过与数组长度的成绩得到阈值,默认0.75;
数组阈值:1.8中当entity超过此阈值时进行扩容,1.7中超过此阈值切添加新数据发生hash碰撞时进行扩容
链表阈值:超过8时转化为红黑树,小于6时转化为列表
2、hash的计算规则
key的hashcode码右移16位后,和原hashcode码异或操作,得到hash
3、key所在位置的计算
将数组长度-1后,转化为2进制,与hash进行与操作,即可得到所在位置
4,插入操作
1.8中,如果没有出现hash冲突,则直接将node放入数组;
如果第一个node出现了hash冲突且key相同,意味着无需添加node,则替换此key的value;
如果没有hash冲突或者无相同的key,意味着需要添加node,
如果此hash对应的数据是以红黑树形式存储的话,则用树的方式添加node
如果此hash对应的数据是以链表形式存储,遍历此链表
在遍历过程中发现了相同的key时,替换value
遍历到结尾还未发现相同key,意味着需要添加node,添加node后进行检测
如果链表的深度超过了8,但数组长度未超过64,则进行数组扩容
如果超过了64,则将链表转化为红黑树
添加node或修改node之后,检查此时键值对个数长度,如果大于阈值,则进行扩容
5、拉链法导致的链表过深问题为什么不用二叉查找树代替,而是用红黑树
二叉查找树在极限情况下会所有节点在一侧,这样就又成了链表结构,不能解决链表过深的问题,而红黑树的特性决定了,它不会像二叉查找树那样出现极限情况
6、红黑树的理解
节点非黑即红,根节点一定是黑色的,如果节点是红色的,则子节点一定是黑色的(反之未必);叶子节点是黑色的空值;从任一节点到每个叶子的所有路径都有相同数目的黑色节点
7、为什么扩容时要设置成2的n次幂
元素存储到hashmap中时,是将元素key的hash值和数组长度减一的二进制进行与运算,如果数组长度是个基数的话会造成数组的部分位置不能存储数据
8、负载因子为什么会影响hashMap性能
首先有序列表索引较快,而链表插入和删除较快;而负载因子大的话,相同长度的列表中可以存储更多数据,则链表长度会加长,索引效率就降低;而负载因子小的话,索引效率增加,但会造成空间浪费
9、有序map和无序map
HashMap存储的时候是无序的,即不计入插入的先后顺序,因为它是按照hash值寻找相应位置进行存放,而存放完成之后,取得时候就是有序的了
LinkedHashMap是有序的,它是HashMap的子类,通过保存对上一个和下一个元素的引用,保证了顺序
四十、初始化和实例化
在实例化一个对象之前,会先对它的类进行初始化;
实例化对象之后,会对实例对象进行初始化
四十一、列举出JAVA中6个比较常用的包
java.net ;java.lang;java.util;java.io;java.sql;java.awt; javax.swing
四十二、Comparable和Comparator接口区别
首先,对集合当中元素排序时,调用Collections.sort()方法,可以有两种方法排序,一种直接传入list集合,,另一种传入list集合以及指定比较器。
第一种是:在创建类时实现Comparable接口,并重写了 compareTO方法;
第二种是:新建了一个类实现了Comparator接口,并重写了compare方法
四十四、HashMap,TreeMap,HashTable的区别?
HashTable不允许<键,值>有空值,HashMap允许<键,值>有空值。
HashTable线程同步,但是HashMap非线程同步。
HashTable中hash数组的默认大小是11,增加方式的old*2+1,
HashMap中hash数组的默认大小是16,增长方式一定是2的指数倍。
TreeMap底层是二叉树结构,线程不同步,将它保存的key默认按照升序排序,键值对可以为null。
HashTable使用Enumeration,HashMap使用Iterator。
四十五、写几个线程安全类,不安全的,支持排序的类名
线程安全类:Vector、Hashtable、Stack。
线程不安全的类:ArrayList、Linkedlist、HashSet、TreeSet、HashMap、TreeMap
支持排序的类有HashSet、LinkedHashSet、TreeSet等(Set接口下的实现都支持排序)
四十六,volatile和synchronized的区别
synchronized是实现了执行控制,同一时刻只能由一个线程访问,volatile直接告诉线程,缓存中的数据不正确,直接去取,写的时候也直接写到主存;
synchronized可能会造成线程堵塞,volatile不会,
volatile仅能作用在变量上,synchronized可以作用在方法,变量和类上
四十七、三次握手与四次挥手
首先TCP报文段首部有20个字节用于存储本报文段的一些信息,包括序号seq(发送的报文段的第一个字节的序号),确认号ack(期待对方发送的下一个报文段的第一个数据字节的序号),以及6个控制位来说明本报文段的性质
三次握手
第一次握手:客户端发送TCP请求报文段(SYN=1,seq=x);(SYN=1的报文段不能携带数据,但是会消耗一个序号),此时客户端进入同步发送状态
第二次握手:服务端接收到请求报文之后,如果同意建立连接,发送SYN=1的确认报文,此时服务端进入同步收到状态
第三次握手:客户端收到服务端的确认报文后,向服务端发送确认报文,客户端进入连接建立状态,服务端接收到确认报文后,服务端进入连接建立状态;此时双方就可以发送报文数据啦
四次挥手:
首先客户端发起FIN=1的连接释放报文,停止发送数据,客户端的状态为终止等待1;
服务端收到释放连接报文后,发送确认报文,服务端进入关闭等待状态,此时客户端不会再向服务端发送数据,但服务端可继续向客户端发送数据,客户端收到确认报文后,进入终止等待2状态;
服务端继续向客户端发送数据,数据发送完毕后,向客户端发送FIN=1的连接释放报文,此时服务端进入最后确认状态
客户端收到请求释放报文后,向服务端发送确认报文,客户端进入时间等待状态,服务端接收到确认报文后,进入连接关闭状态,客户端经过一段时间的等待后也进入连接关闭状态
四十八、Class.loader和Class.forName的区别
class.loader只是将.class文件放入jvm中,不进行任何的解释;Class.forName将.class文件放入jvm后还会执行文件中的静态方法和静态代码块静态变量
四十九、String类的常用方法
indexof():返回指定字符串第一次出现的位置
charAt():返回指定下标的元素字符
length():返回字符串的长度
replace():替换所有指定字符,第一个为老字符,第二个参数为新的字符
replaceAll():替换所有指定字符串
trim():去除字符串两边的空格
split():以特定字符串切割字符串,返回一个字符串数组
五十、synchronized和lock的区别
synchronized是一个java关键字,lock是一个接口
synchronized无法判断是否获取锁的状态,lock可以
synchronized可以自动释放锁,lock需要手动释放
synchronized是非公平的锁,lock默认不公平,可以设置为公平锁
synchronized适合代码少量的同步问题,lock适合大量代码的同步问题(因为synchronized修饰的代码会被编译器优化,切线程不能被中断)
https://www.cnblogs.com/takumicx/p/9338983.html
五十一:栈、堆、常量池
栈中存放基本数据类型,数据唯一,数据的大小和生存周期确定,存储或修改数据时,先查找有没有相同的数据,有的话直接引用此数据,没有的话创建开辟新的空间存储此数据
int a = 3;
int b = a;
System.out.println("a="+a+";b="+b);
System.out.println(a==b);
a=4;
System.out.println("a="+a+";b="+b);
System.out.println(a==b);
堆中存放new出的对象,数据不共享,存储数据时直接开辟新的空间存储数据,修改数据时在原先地址进行数据修改
常量池存放基本类型常量,字符串常量以及指定范围的包装类型常量,数据共享,注意包装类型存储范围,装箱时会调用valueof方法,因此得到的对象可能会被new
类的成员变量及方法的四种访问权限
访问级别 | 访问修饰符 | 同类 | 同包 | 子类 | 不同包 |
公开 | public | √ | √ | √ | √ |
受保护 | protect | √ | √ | √ | × |
默认 | 缺省 | √ | √ | × | × |
私有 | private | √ | × | × | × |
数据库
一、事务的特性及事务并发带来的问题
原子性、隔离性、持久性、一致性
问题:脏读:事务A利用了事务B处理之后的数据,但是事务B发生了回滚
不可重复读:事务A读取数据再次重新读取时,原数据被事务B修改,前后读取数据内容不同,针对更新操作
幻读:事务A读取数据再次重复读取时,原数据被事务B删除或插入;前后读取数据总数不同,针对增加删除操作
二、数据库如何优化
1:SQL优化:
尽量少使用select * ;使用连接查询代替子查询
2:表结构优化:
尽量使用数字类型字段,提高比对效率;
长度不变的数据可以使用char类型;
3:其它优化
对查询频率高的字段适当建立索引;根据表用途的不同使用不同的数据库引擎;读写分离。
三、常见数据库引擎
数据库引擎是用于存储,处理,保护数据的核心服务
InnoDB支持事务处理、外检以及行锁,适用于对数据安全性,事务完整性要求较高的场景;
MyISAM是mysql默认的引擎,不支持事务、行锁、外键,此当修改数据时会锁定整个表,适用于读出记录。注意:使用此引擎,在service层通过事务配置也可以让其完成事务业务。
MEMORY数据存储到内存中,读写速度较快,但不能存储太大的表,
四、视图
视图是有一个表或者多个表组合而成的虚拟表,它本身并不占据物理空间,它所呈现的数据仍然存储在原表当中;
创建视图有两个作用,简化操作和安全性,经常被查询的数据可以定义为视图,这样下次在查询的时候不用再每次指定条件,而通过视图用户只能查询修改他们所能见到的数据。通过视图修改数据时仅允许一个表中产生的视图进行修改。超过一个表不允许修改,具有更好的安全性。
五、索引
索引是指对数据表中的一列或者多列进行排序的一种存储结构,可以加快数据的查询效率,但是索引本身也占据物理空间,且在数据进行增加、删除、修改的时候都需要重新分配索引,又降低了数据的维护速度。分为BTREE和HASH两种结构。
唯一索引:任意两行不能有相同的索引值,可以防止表中存储重复数据(主键索引)。
聚集索引:表中行的物理顺序与键值的逻辑顺序相同。
六,存储过程
存储过程是一个预编译的SQL语句集,如果某个操作需要执行大量sql语句,可以将其加入到存储过程中,比单纯执行SQL要快。相当于把sql语句封装到一个方法中,执行sql时调用方法即可
七、触发器
存储过程是一种特殊的存储过程,存储过程需要手动调用,触发器是在某个事件(符合条件的增删改)发生之前或之后自动执行的。
八、游标
游标是一种能够从包括多条数据记录的结果集中每次提取一条记录进行处理的机制
九、SQL的执行顺序:
from .. on .. join .. where ..group by ..having ..select ..order by ...limit ..
十、三大范式
第一范式:每个列都是最小单元,不可再分。比如:所选课程列包含多个课程,不符合要求,应该分成每个课程的单列
第二范式:不存在对主码的部分依赖,即应当通过主码确定唯一的一行数据:所以可设置主码只有一个
第三范式:在第二范式基础上,非主属性不能互相依赖,既不存在对主码的传递依赖
十一、SQL语言的分类
DML:数据操作语言,用于数据的增删改查,排序操作
DDL:数据定义语言,用于创建视图,索引、表格,此操作是隐性提交的,不能回滚
DCL:数据控制语言,用于授予或回收用户访问数据库的某种权限
十二、数据库的交叉并补操作,mysql不支持后两种
UNION:查询结果连接后去重 补
UNION ALL:查询结果连接 并
INTERSECT:查询相同的 交
MINUS:查询不同的 差
Mybatis
一、缓存
一级缓存的作用域为同一个SqlSession,二级缓存的作用域是同一个namespace中,且当SqlSession关闭时,才会执行二级缓存
二、增删改查的返回值
增加返回增加的条数;
删除返回被操作的记录条数;
修改也是返回被操作的记录条数
三、插入数据之后返回主键id
在定义xml映射器时设置属性useGeneratedKeys值为true,并分别指定属性keyProperty和keyColumn为对应的数据库记录主键字段与Java对象的主键属性。
四、工作原理
1、加载mybatis配置文件,得到文件的字符流(配置文件中配置着数据源,别名,类型转换这些基础配置),
2、通过SqlSessionFactoryBulider读取文件的字符流得到SqlSessionFactory
3、通过SqlSessionFactory得到SqlSession
4、通过SqlSession可以调用Mapper接口中的方法
5、通过接口中的方法调用与其对应的MapperStatement对象
6、MapperStatement对象被解析(sql参数转化,动态sql拼接),生成jdbc Statement对象
7、JDBC执行sql
8、通过MappedStatement中的结果映射关系,将返回结果转化为JavaBean或HashMap进行返回
五、锁机制
共享锁:SELECT ..... LOCK IN SHARE MODE;事务对数据加了共享锁之后,允许其它事务继续加共享锁读取数据,不允许添加排它锁,不允许进行写操作
排它锁:SELECT .... FOR UPDATE,对数据加了排它锁之后,可以进行读和写,其它事务不能在对此数据封装任何形式的锁。对于InnoDB引擎来说,增删改操作会自动给涉及的数据加上排它锁
注意:共享锁在事务结束之后才会释放,但是事务的共享锁可以升级为排它锁,前提是事务操控的数据未被其它事务加锁;因此当有两个事务同时对同一个数据开启了共享锁之后,又同时想把共享锁转化为排它锁时就会发生死锁,所以引入了更新锁。共享锁和排它锁不兼容,与共享锁兼容
更新锁:加了更新锁之后,表示此事务目前只是读操作,但未来可能执行写操作;其它事务可以执行读操作,但是必须等加了更新锁的事务结束后才能执行写操作
更新锁与共享锁兼容,与排它锁不兼容,与自身不兼容
意向锁:表示此表中的数据是否已经被加了锁
计划锁:限制DDL操作,进行DDL操作过程中,不允许sqlsession连接该表,在进行DML过程中,不允许使用DDL语言
悲观锁:每次都假设出现最坏的情况,即认为拿数据后会进行修改,所以会对此数据上锁,比如表锁,行锁,页锁,排它锁。
乐观锁:每次都是假设最好的情况,即认为拿数据时不会进行修改,只在更新数据的时候检查下在此期间数据有没有被其它人修改过,判断有没有别修改可以采用版本号机制或者CAS算法。版本控制:在数据表格中新加一个版本字段,进行更新操作时,判断当前行数据版本字段的值是否和初始时发生了改变;CAS算法:有3个操作数,内存上的值V,旧的预期值A,要更新的信息B,当且仅当A=V时,进行修改
Java Web
一、什么是servlet
servlet是运行在web服务器或应用服务器上的程序,可以接收来自网页表单的用户输入,呈现来自数据库的数据,可以动态生成网页
二、servlet的生命周期
servlet类加载完成实例化,通过init()进行初始化,调用service()处理客户端的请求,调用destroy()方法终止,最后Servlet通过垃圾回收器进行回收
三、jsp内置对象及作用?
request 获取客户端传输过来的信息
response 向客户端响应信息
out 向客户端输出数据
session 保存会话对象,存储在服务器端,浏览器关闭即会失效
application 在服务器上存储数据,只要程序未停止就会一直保存
pagecontext 保存了其它的所有对象
page 代表当前jsp页面本身
exception 表示jsp引擎在执行时会抛出的异常
config 保存当前jsp的配置信息
四、jsp动态引入和静态引入的区别
动态引入是通过jsp动作引入的,可以传递参数,适用于引入动态页面,动作的标志为jsp:
静态引入是通过jsp指令引入的, 适用于静态引入,指令的标志为@
五、应用服务器和web服务器的区别
web服务器用来接收请求和返回响应,只能够处理静态页面;因此那种需要动态处理的数据交给应用服务器处理,处理后的结果再交给web服务器进行响应
六、Tomcat是什么
因为可以通过HTTP提供HTML页面等静态内容的请求访问,所以是一
个WEB服务器;
因为实现了Servlet规范,所以也是一个Servlet容器,可以运行
Servlet程序;
因为可以通过Servlet容器,调用Servlet处理动态请求,所以也是
一个应用服务器;
七、jsp和servlet的区别和联系:
1.jsp经编译后就变成了Servlet.
(JSP的本质就是Servlet,JVM只能识别java的类,不能识别JSP的代码,Web容器将JSP的代码编译成JVM能够识别的java类)
2.jsp更擅长表现于页面显示,servlet更擅长于逻辑控制.
3.Servlet中没有内置对象,
Spring框架
一、什么是spring框架,有哪些主要模块
spring框架是一个为java应用程序的开发提供了综合,广泛的基础性支持的java平台,帮助开发者解决了一些基础性的问题,使得开发人员可以专注于应用程序的开发,包含的模块有数据访问,web,AOP,测试等功能模块
二、使用spring框架有哪些好处
首先,我们可以不用把精力放在基础配置上,其次它提供许多模块,我们可以根据自己的需求添加需要的模块功能加以整合,它提供的控制反转和依赖注入的机制,让我们更容易设计出高内聚低耦合的项目。
三、控制反转IOC和依赖注入DI
在传统项目中我们生成一个对象时,需要自己new生成,在spring中,是通过容器为我们创建和管理对象的,这叫做控制反转,而依赖注入是指我们在一个类中需要另一个类的对象时,不需要自己new,仅需通过生命,容器就会为我们自动注入。因此,控制反转是依赖注入的前提,依赖注入是控制反转的体现。
依赖注入的本质就是自动装配,装配是依赖注入的具体行为。
四、spring装配的类型
no,bytype,byname,construct(根据构造函数中的参数类型),autodetect(自动探测,有构造函数根据构造函数进行装配,没有构造函数根据bytype进行装配)
五,依赖注入的方式有哪些?
set方法注入,
构造器注入,
接口注入
六、BeanFactory和ApplicationContext和FactoryBean的区别
BeanFactory是一个factory,管理着所有的bean,在容器启动时不会去实例化bean,当从容器中取bean时才会去实例化
FactoryBean是一个bean,使用它我们可以自定义一个bean的配置信息加入容器中
ApplicationContext是BeanFactory的实现类,拥有BeanFactory的所有功能,还提供了些其它的功能,比如支持AOP,自动装配。在项目启动时就将所有的bean实例化了,不过可以设置lazy-init=true让bean延迟实例化
六,spring有几种配置方式
基于XML配置,基于注解的配置,基于Java的配置
七、Spring支持的几种bean的作用域
singleton:默认,每个容器中只有一个bean的实例,
prototype:为每一个bean请求提供一个实例
request:为每一个网络请求创建一个实例,在请求完成之后,bean会失效并被垃圾回收器回收
session:确保每个session中有一个bean的实例,在session过期后,bean会随之失效
global-session:所有的session共享一个bean
八、spring框架中的单例bean是线程安全的吗
spring框架并没有对单例的bean进行任何多线程的封装处理,所以并非线程安全的,但是spring中封装的大部分bean是无状态的bean(dao层对象),因此线程是安全的;而对于有状态的bean(modelAndView),可以通过改变它的作用域为prototype来使其线程安全。
九、@Autowired和@Resource的区别
@Autowired默认根据类型进行装配,如果想要使用name装配,可以结合@Quanlifier一起使用
@Resource默认根据name装配,
如果指定type,则按照类型匹配,找不到或找到多个,都会抛出异常
如果指定name,则按照name匹配,找不到则抛出异常
如果同时指定name和type,则按照两者进行寻找
十、spring中用到了哪些设计模式
BeanFactory管理着所有的bean,采用了工厂模式;
bean的创建默认为单例模式;
代理模式:在使用Spring AOP功能时使用了动态代理
模板方法:用来解决代码重复的问题,如RestTemplate,和JpaTemplate
观察者模式:当一个对象状态发生改变时,所有依赖于它的对象都会得到通知记性更新,如spring中listener的实现--ApplicationListener
十一、Spring事务的种类
通过TransactionTemplate或 PlatformTransactionManager实现编程式事务管理
通过AOP或@Transaction实现声明式事务管理,
编程式事务管理可以将事务级别作用到代码块,但是需要在逻辑代码中添加相应的事务管理代码
声明式事务管理更加简单易用,但是事务级别只能作用于方法
事务实现: https://blog.csdn.net/weixin_40486739/article/details/89286590
十二、spring事务的传播行为
1、PROPAGATION_REQUIRED:如果当前存在事务,就加入该事务,不存在,则开启新事务
2、PROPAGATION_SUPPORTS:如果当前存在事务,就加入该事物,不存在则以非事务执行
3、PROPAGATION_MANDATORY:如果当前存在事务,就加入该事务,不存在,抛出异常
4、PROPAGATION_REQUIRES_NEW:无论当前存不存在事务,都创建新事务
5、PROPAGATION_NOT_SUPPORTED:以非事务执行,若当前存在事务,则将事务挂起
6、PROPAGATION_NEVER:以非事务执行,若当前存在事务,则抛出异常
7、PROPAGATION_NESTED:如当前存在事务,则在当前事务内开启子事务,不存在,则开启新事务(父事务回滚,子事务回滚;子事务回滚,父事务不受影响)
https://blog.csdn.net/u010963948/article/details/82761383
十三、Spring隔离级别
1、ISOLATION_DEFAULT:采用后端数据库的级别,mysql为可重复读,oracle为读已提交级别
2、 ISOLATION_READ_UNCOMMITTED:最低隔离级别,读未提交,可能会发生,脏读,幻读,不可重复读
3、 ISOLATION_READ_COMMITTED:读已提交,避免脏读,不能避免幻读和不可重复读
4、 ISOLATION_REPEATABLE_READ:可重复读,即一个事务内两次读取数据时,如果前后数据不一致,此事务读时禁止其他事务写数据;避免了脏读,不可重复读,可能会造成幻读
5、ISOLATION_SERIALIZABLE:串行化,在事务执行时间不允许其它事务对数据做出的增删改操作,安全性最高,效率最低
十四、java反射机制
反射机制指的是程序在运行时能够获得传过来的类的所有属性和方法,调用传输过来的对象的所有属性和方法。可以根据传入的对象动态的进行操作,使操作更加灵活,代码具有更好扩展性,缺点是消耗了更多的性能
十五、spring应用上下文
首先我们进行依赖注入时,是通过spring容器获取对象,但是我们需要将需要注入的对象以及对象之间的依赖关系通过spring的应用上下文来告诉spring时容器
ioc是一种思想,spring实现了ioc,但实现了ioc的还有其它框架
十六、Bean的生命周期
1、spring对bean进行实例化
2、将属性和对其它bean的引用进行注入
3、如果bean实现了BeanNameAware接口,将bean的id传递给setBeanName方法(此接口让bean自己可以获取自己在spring容器中的id)
4、如果bean实现了BeanFactoryAware接口,将调用BeanFactory容器实例传入。(可以获取到他们的BeanFactory)
5、如果实现了ApplicationContextAware接口,将调用setApplicationContext方法,将上下文的引用传入
6、如果实现了BeanPostProcessor接口,将调用postProcessBeforeInitialization方法(在对象实例化前进行操作)
7、如果实现了InitializingBean接口,或者在bean中声明了init-method则调用他们的初始化方法对bean进行初始化(如果两个都指定,则先执行接口中指定的方法,再执行配置中指定的初始化方法)
8、如果实现了BeanPostProcessor接口,将调用postProcessAfterInitialization方法(在对象实例化前进行操作)
9、此时Bean 已经准备就绪.可以被应用程序使用了. 它们将一直驻留在应用上下文中.直到该应用上下文补销毁
10、如果实现了DisposableBean接口,spring将调用它的destroy()接口,如果Bean 使用destroy-method 声明了销毁方法,方法也会被调用。(调用顺序同7)
十七、spring的AOP支持
1、使用@Asepect注解,在类中定义切点及各种通知
2、经典的基于代理的AOP实现,在一个类中实现各种通知的接口,在配置文件中配置切点,切面
https://blog.csdn.net/summer_yuxia/article/details/75104949
十八、什么是线程安全
线程安全是指在多线程访问数据时,采用加锁机制,当一个线程访问该类的某个数据时,提供数据保护,不允许其它线程访问此数据直至当前线程访问结束,由此可以避免数据污染
十九、线程池的好处
1、提高效率:创建线程和销毁线程都是比较消耗系统资源的,线程池为我们提供了一定数量的线程,可以避免频繁的创建和销毁线程
2、方便管理:将线程放在线程池中,对线程的数量及使用情况进行统一管理,避免在程序中额外的创建线程
二十、线程池的无界队列和有界队列
首先理解三个名词,
corePoolSize:线程池的基本线程数量,注意在刚创建线程池时不会创建线程,当有任务提交时才开始创建线程。
maxiMumSize:线程池的最大线程数,可以调用setMaxiMumSize方法定义
poolSize:线程池中当前的线程数量
有界队列:当线程数poolsize小于corepoolSize时,提交的runable任务会直接创建分配一个线程,立刻执行
大于时,将线程任务放在blockqueue中,如果阻塞队列已满,如果poolsize<maximumSize,则创建一个新的线程,如果已经=,则执行reject策略
无界队列:当poolSize<corePoolSize时,提交的runable任务会直接分配一个线程,不小于,则将线程任务放入无界队列中进行等待,直至内存耗尽
二十一、线程池的种类
1、newCachedThreadPool:缓存线程池,线程池中线程不固定,无最大线程数
2、newFixedThreadPool:定长线程池,线程池中线程数量一定,超过corepoolsize时,线程任务在无界队列中等待
3、newSingleThreadExecutor:单例线程池,线程池中线程数固定为1,其它的线程任务在无界队列中进行等待
4、newScheduleThreadPool:定长定时线程池,创建指定数量的线程池,线程的执行可指定延迟执行时间,以及周期
5、newSingleScheduledExector:单例定时线程,创建一个线程的线程池,线程的执行可指定延迟时间,以及周期
二十二、如何给定线程池的线程数量
1、首先cpu密集型程序是指,对业务逻辑的处理计算比较多,io密集型应用是指经常做文件的读写操作,
2,设系统的cpu数量为n,则理论上对于cpu密集型创建的线程数为n+1,对于io密集型创建的线程数为2n+1