这次面试时间较长,
整体和面试官聊的也比较愉快,
本以为会问到一下多线程的问题,
结果最后被怼了事务。
总体来进行一次复盘。
挑选一些有趣的问题:
笔试题:
String,Integer,Double 能不能被继承?
上源码:
public final class Byte extends Number implements Comparable<Byte>
public final class Short extends Number implements Comparable<Short>
public final class Integer extends Number implements Comparable<Integer>
public final class Long extends Number implements Comparable<Long>
public final class Float extends Number implements Comparable<Float>
public final class Double extends Number implements Comparable<Double>
public final class Boolean implements java.io.Serializable,Comparable<Boolean>
public final class Character implements java.io.Serializable, Comparable<Character>
public final class String implements java.io.Serializable, Comparable<String>, CharSequence
我们发现 8种基本类型的包装类,都是不可以继承的。String引用类型也是不能继承的
为什么8种类型的包装类不允许被继承?
Comparable接口能做什么
为什么9种类型只有三种实现了 Serializable 接口
checked 异常 uncheck异常
什么是 checked 异常 什么是 unchecked异常。首先我们需要明白它的概念。
unchecked异常:
实际上就是我们平时所说的 RuntimeException,运行时异常,代码在编译阶段不会报错,告诉你需要异常处理。例如:indexOutOfBound , NullPoint, ClassCast
checked异常:
也就是平时我们在写代码的时候,编译器告诉我们需要异常处理,try{}catch{}或者 写一个抛出异常申明(throws),
除RuntimeException 以外的异常都是 checked异常。
以下是java异常的一个架构图:
简述一下反射,反射创建类的过程
反射,是指,程序运行时,对于任意一个类都能够知道这个类所有的属性和方法;并且对于任意一个对象,都能够调用它的任意一个方法;
这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。
明白反射概念以后,我们需要思考,为什么需要反射。
实际上,当拿到一个类的时候,肯定要直接使用关键字new进行对象的实例化操作,这属于习惯性的做法。
但是有了Class类对象,那么就可以做到,利用反射来实现对象实例化操作。
我们写的代码种,new 是耦合的最大元凶,而使用反射,我们就可以避开new 的方式,使程序的拓展性更强,完成解耦的目的
//反射获取 方式一:源码阶段
try {
Class<?> aClass = Class.forName("com.entity.User");
Field[] fields = aClass.getFields();
Method[] methods = aClass.getMethods();
Constructor<?>[] constructors = aClass.getConstructors();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//反射获取 方式二:类对象阶段
Class<User> bClass = User.class;
bClass.getFields();
bClass.getMethods();
bClass.getConstructors();
User user = new User();
//反射获取 方式三:运行阶段
Class<? extends User> cClass = user.getClass();
cClass.getFields();
cClass.getMethods();
cClass.getConstructors();
}
通过配置文件动态的去执行类中的方法
//创建Properties对象
Properties p = new Properties();
ClassLoader classLoader = ReflectTest.class.getClassLoader();
//获取配置文件
InputStream inputStream = classLoader.getResourceAsStream("application.properties");
p.load(inputStream);
//加载配置文件定义数据
String className = p.getProperty("className");
String mName = p.getProperty("methodName");
//加载至内存
Class cls = Class.forName(className);
//创建对象
Object obj = cls.newInstance();
//获取方法对象
Method method = cls.getMethod(mName);
//执行方法
method.invoke(obj);
反射详解?
手写冒泡排序
public static void bubbleSorts(int[] array){
//循环的次数统计
int count = 0;
//设置标志位,对排好序的不再排序
boolean falg;
for (int i = 0; i < array.length; i++) {
falg = false;
for (int j = 1; j < array.length - i; j++) {
count++;
//异或运算,不用开辟新的变量空间
if(array[j-1]>array[j]) {
array[j-1] ^= array[j];
array[j] ^= array[j-1];
array[j-1] ^= array[j];
falg = true;
}
}
//如果排好序就跳出循环
if (!falg){
break;
}
}
}
int[] a = new int[-5] 运行会怎样
//编译器并不会报错,程序运行后报异常
java.lang.NegativeArraySizeException
面试题:
Object里面都有哪些方法?(9个)
wait(); //线程等待,释放CPU,释放对象锁
wait(timeout); //线程等待,timeout 等待超时,毫秒级别,超时自动唤醒
wait(timeout,naos); //线程等待,naos 微秒级别,唤醒延迟
notify(); //唤醒某一个wait()的线程,具体唤醒那个看操作系统的线程调度
natifyAll(); //唤醒所有 wait()的线程
toString(); //对象转String,通常重写
equals(); //比较对象地址,通常重写
hashCode(); //计算hashCode值
getClass(); //反射
你说说protected权限修饰符用来干嘛的?
你肯定被问过 四大权限修饰符的作用域。但你肯定很少被问过,为什么需要protected修饰符,protected修饰符通常用来做什么。
protected 作用域,同类,子类。
protected 修饰的方法,通常是想要被用来继承。(涨姿势)
hashCode() 与 equals()
sleep() 与 wait() 以及wait()的重载方法
sleep() 线程睡眠等待,释放CPU,但不释放对象锁
wait() 线程等待, 释放CPU,释放对象锁
AOP的底层实现,两种动态代理的区别
jdk自带代理:需要实现 InvokeHandler 接口,重写 Invoke方法
CGlib代理:使用继承父类的子类代理
你在项目中哪里用到过AOP
aop 和 aspectJ
用户鉴权
全局异常处理
消息通知
jdbc事务
## spring事务和 jdbc事务区别 [spring ,jdbc,mysql事务大对比](https://blog.csdn.net/a16310320524/article/details/106544768)
为什么用mybatis 而不用jdbc了
@Transational() 实现原理,有哪些参数可填
可填参数,
上源码:
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
@AliasFor("transactionManager")
String value() default "";
//指定目标事务管理器
@AliasFor("value")
String transactionManager() default "";
//事务传播属性
Propagation propagation() default Propagation.REQUIRED;
//事务隔离级别
Isolation isolation() default Isolation.DEFAULT;
//事务超时时间
int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
//事务只读
boolean readOnly() default false;
//指定事务回滚
Class<? extends Throwable>[] rollbackFor() default {};
String[] rollbackForClassName() default {};
//指定事务不回滚
Class<? extends Throwable>[] noRollbackFor() default {};
String[] noRollbackForClassName() default {};
- transactionManager = " "
@Transation() 失效的情况
1.添加注解的方法不是public修饰的;
2.并不是所有的异常都能触发回滚,默认只有这些会触发回滚"运行时、未检查异常(继承自 RuntimeException 的异常)或者 Error",所以如果想要所有的异常都回滚,需要在注解上添加(rollbackFor = Exception.class)这个参数和值。
3.事务只有在方法抛出异常时才会回滚,如果方法中的异常被try-catch捕获,则不会回滚,如果业务需要在catch中进行业务逻辑处理,则需要手动回滚,在catch中添加以下语句:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
4.如果在controller层调用service方法(方法A)没有添加@Transactional注解,那么即使方法A调用(有注解的)方法B,也不会触发事务;
5.配置文件是否开启事务
6.数据库表是否支持事务
7.Service层是否加了@service
@Transation() 默认回滚哪些异常
mysql 索引失效的情况
like "%xxx"
or
最左匹配原则
全表扫描比索引快
字符串类型数据要用 引号引起来
< > !=
线程池的实现
3. 常驻线程是否满了? 未满,就执行。否则,下一步
4. 阻塞队列是否满了? 未满,队列等候,否则,下一步
5. 线程池是否满了? 未满,创建线程,否则,下一步
6. 拒绝
线程池创建
ExecutorService pool = Executors.
1.newFixedThreadPool(int) 一池固定个数
2.newSingleThreadPool() 一池一个
3.newCachedThreadPool 可扩容
我看过线程池源码:底层都是new 一个 ThreadPoolExecutor(线程池实现类)
七大参数:
1.int corePoolsize 常驻线程数
2.int maximunPoolSize 最大线程数
3.long keepAliveTime 存活时间
4.TimeUtil util
5. BlockingQueue blockQueue 阻塞队列
6.ThreadFactory threadFactory 线程工厂,创建线程
7.RejectExecutionHandle handler 拒绝策略(队满拒绝执行)
自定义线程池:
ExecutorService pool = new ThreadPoolExecutor(
2, 5,
3, TimeUnit.SECONDS,
new LinkedBlockingDeque<Runnable>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
四大拒绝策略:
1.AbortPolicy (默认拒绝策略) 抛异常中断处理
2.CallerRunPolicy 不抛弃任务,不抛异常,回退给调用者
3.DisCardPolicy 抛弃任务不报错
4.DisCardOldPolicy 抛弃等待时间最长的任务,不报错
项目中哪里使用了线程池,为什么选择线程池,不用线程池行不行?
数据库中创建表 int(num) 括号里面的值有什么意义?
数据库单表上限记录,表记录达到多少会有明显的性能下降
数据达到 2000万,数据库性能明显下降。数据达到300 建议 可以建立索引
阿里实战给出的结果 数据达到 500万 考虑分表分库
springBoot redis配置文件,底层如何加载的
@SpringBootApplication 注解都做了什么(源码)
Eureka , nacos 注册中心的对比,技术选型
自己讲了一下JVM 类加载器
类加载器作用:
负责加载 .class文件将 .class 文件加载至内存中,并转化为方法区中的运行时数据结构
类加载器分类:
启动类加载器(C++写的,jdk自带的类)拓展类加载器(java写的,javax拓展类)
应用程序加载器(用户自定义类文件)
双亲委派:
收到一个类加载请求,首先不会尝试加载这个类,而是先委派给双亲完成(最高父类)沙箱安全:
自己代码不会污染源码,保证每次加载的都是同一个类。用户自定义类文件 与jdk中自带类文件 重名,会出现什么问题,加载了哪个类,会不会报错。
OOM你如何进行排查
-XX:+PrintGCDetail
来打印 jvm日志,根据日志来排查信息
如果线上系统OOM奔溃怎么排查?
日志文件的记录,线上系统奔溃, 根据保留的日志文件排查信息。