1 自增面试题
public static void main(String[] args) {
int i = 1 ;
i=i++;
int j = i++;
int k = i+ ++i*i++;
System.out.println("i="+i);//4
System.out.println("j="+j);//1
System.out.println("k="+k);//11
}
// 局部变量() 操作数栈()
//i++,与++i的关系, i++是先将值压入操作数栈中,后来再把值给回局部变量
// i 局部变量(1) 操作数栈(1)
// 执行 i++ 局部变量 i的值 + 1 =2
// 执行完后局部变量=2,
// 然后将操作数栈的值重新给回局部变量,所以i的值又变回1
// i 局部变量(2) 操作数栈(1)
// 执行int j = i++
// i 局部变量(1) 操作数栈(1)
// j 局部变量(0) 操作数栈(无)
// 执行完后i的局部变量+1 ,然后将i的操作数栈的值给了j
// i 局部变量(2) 操作数栈(无)
// j 局部变量(1) 操作数栈(无)
//此时i的值2 , j的值为1 k的值为0
// int k = i+ ++i*i++;
// i 局部变量(2) 操作数栈()
// k 局部变量(0) 操作数栈()
// int k = i+ ++i*i++; 先算前面再算后边,所以先将i的值压入操作数栈
// i 局部变量(2) 操作数栈(2)
// k 局部变量(0) 操作数栈(无)
// int k = i+ ++i*i++; 开始算后边的++i,优先级较高,先将局部变量+1 再压入操作数栈
// 压入的 操作数栈(3)
// i 局部变量(3) 操作数栈(2)
// k 局部变量(0) 操作数栈(无)
// int k = i+ ++i*i++; 开始算最后边的i++,先压入操作数栈,再让局部变量+1
// 压入的 操作数栈(3)
// 压入的 操作数栈(3)
// i 局部变量(4) 操作数栈(2)
// k 局部变量(0) 操作数栈(无)
// 至此所有数据压入完毕,开始算最后的结果
// ++i压入的操作数栈为3,i++压入的操作数栈为3 ++i*i++ = 3*3 =9
// i+ 压入的操作数栈是2 所以i+ ++i*i++ = 2 + 9 = 11
// 最后将操作数栈的值赋值给k=11 ,而i的局部变量是4
//最终的结果为i=4 j=1 k=11
public static void main(String[] args) {
int i = 1 ;
i++;
int j = i++;
int k = i+ ++i*i++;
System.out.println("i="+i);//5
System.out.println("j="+j);//2
System.out.println("k="+k);//19
}
2 什么是Singleton
解决懒汉式线程安全问题(加锁)
public class Singleton4 {
private static Singleton4 instance;
private Singleton4(){
}
public static Singleton4 getInstance(){
//=============待优化
synchronized(Singleton4.class){
if(instance == null){
instance = new Singleton4();
}
}
return instance;
//==================优化,提高性能,(如果已经存在一个对象,就不用加锁了,直接返回这个对象)
if(instance==null){
synchronized(Singleton4.class){
if(instance == null){
instance = new Singleton4();
}
}
}
return instance;
}
}
懒汉式2
/**
* 在内部类被加载和初始化时,才创建INSTANCE实例对象
* 静态内部类不会自动随着外部类的加载和初始化而初始化,他是要单独去加载和初始化的
* 因为是在内部类加载和初始化时,创建的,因此是线程安全的
*/
public class Singleton5 {
private Singleton5(){
}
private static class Inner{
private static final Singleton5 INSTANCE = new Singleton5();
}
public static Singleton5 getInstance(){
return Inner.INSTANCE;
}
}
3 以下代码执行的顺序是什么?
4 编程题: 有n步台阶,一次只能上一步或两步,共有多少种走法
public class 台阶走法 {
//编程题: 有n步台阶,一次只能上一步或两步,共有多少种走法
public int f(int n){
if(n==1||n==2){
return n;
}
return f(n-2)+f(n-1);//递归
自己画图 4台阶是5种走法 5台阶是 8种
//5 f3 + f4
// 3 f2+f3
// 结果 3+ 2+3 =8
// 7 f5 + f4
// f3+f4 + f2+f3
// 3 + f2+f3 + 2+3
// 3+2+3 + 5
// =13
}
public static void main(String[] args) {
台阶走法 台阶走法 = new 台阶走法();
long start = System.currentTimeMillis();
System.out.println(台阶走法.f(40));//165580141
long end = System.currentTimeMillis();
System.out.println(end-start);//589
}
}
public class test2 {
public static int total(int step){
if(step==1||step==2){
return step;
}
int oneStep =2;//最后走一步,说明到了第二层台阶的坐标处,有两种走法
int twoStep =1;//最后走2步,说明在第一层台阶的坐标处,有一种走法
int sum =0;
//现在第三步台阶,那么最后走一步和最后走2步的之前的走法加起来就是总的方法
for(int i=3;i<=step;i++){
sum = oneStep+twoStep;//到达第三步台阶的总方法
//当下一次加1台阶的时候为4,最后走一步的台阶位置坐标变成了最后走2步的台阶的位置
twoStep = oneStep;//最后走2步的原本坐标位置是1,现在坐标位置是2 2+2 =4
//然后当前的sum的坐标就是最后走一步的坐标
oneStep = sum;//最后走一步的原本坐标位置是2,现在坐标位置是3, 3+1 =4
}
return sum;
}
public static void main(String[] args) {
System.out.println(total(5));
}
}
5 数据库常考
一 数据概念
假设现在有两个事务: t1 和t2
1 脏读
(1) t1 将某条记录的AGE值从20修改为30
(2) t2 读取了t1更新后的值30
(3) t1 回滚,AGE值恢复到了20
(4) 此时t2读取到的30就是一个无效值
就是读取到了别人更新但是还没有提交的数据
2 不可重复读
(1) t1 读取了AGE值为20
(2) t2 将AGE值修改为30
(3) t1 再次读取AGE值为30,和第一次读取的值不一致
不可重复读,读到的值没有重复
3 幻读
1 t1 读取了STUDENT表中的一部分数据
2 t2 向STUDENT表中插入了新的行
3 t1 读取STUDENT表时,多出了一些行
幻读:通俗点来说就是你妈在你不知道的时候放了钱进银行卡,你去查的时候发现多了钱,
以为出现了幻觉
二、隔离级别:
数据库系统必须具有隔离并发运行各个事务的能力,使他们不会相互影响,避免各种并发问题
一个事务与其他事务隔离的级别称为隔离级别,SQL标准中规定了多种事务隔离级别,不同隔离
级别对应不同的干扰程度,隔离级别越高,数据一致性越好,但并发性越弱
1 读未提交 Read uncommitted 、
允许t1读取 t2未提交的修改
2读已提交Read committed 、
要求t1只能读取 t2已提交的修改
3可重复读Repeatable read 、
确保t1可以多次从一个字段中读取到相同的值,即t1执行期间禁止其他事务对这个字段进行更新
4串行化 Serializable
确保t1可以多次从一个表读取到相同的行,在t1执行期间,禁止其他事务对这个表进行添加、更新
删除等操作,可以避免任何并发问题,但性能十分低下