记第三次面试

这次面试时间较长,
整体和面试官聊的也比较愉快,
本以为会问到一下多线程的问题,
结果最后被怼了事务。
总体来进行一次复盘。
挑选一些有趣的问题:

笔试题:


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
最左匹配原则
全表扫描比索引快
字符串类型数据要用 引号引起来
< > !=

线程池的实现

底层工作原理:
1. 提交任务 ,
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奔溃怎么排查?


日志文件的记录,线上系统奔溃, 根据保留的日志文件排查信息。

配置tomcat来运行多个应用

学习建议:

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值