一、java基础
1.1this和super的区别
this指当前类对象,用在此类中调用当前类对象的属性和方法。并且可以调用构造函数,但是只能在构造函数中,只能写在代码的第一行。super指父类的类对象,用在子类中来调用父类的属性和方法,并且可以用来调用父类的构造方法,但是必须写在代码的第一行。
1.2抽象类和接口的区别
抽象类:被abstract关键字修饰的类成为抽象类,抽象类中包含抽象方法,也包含非抽象方法。接口:被interface关键字修饰的类成为接口,接口中只能存在抽象方法。二者的区别:(1)抽象类中的变量包含public、private、protect,接口中的变量只能是final类型的;(2)抽象类中的方法可以是抽象的,也可以是非抽象的,接口中的方法只能是抽象的;(3)抽象类中的方法可以被子类重写,也可以不被重写,接口中的方法都要被实现类重写;(4)一个类只能去继承一个父类,但能实现多个接口;
1.3多态的三种形式
多态体现了现实事物中所具备的多种形态,在java中代表同一个对象既属于子类也属于父类,指代父类引用指向子类对象。多态的三个必要条件:(1)必须存在继承关系;(2)必须有方法的重写;(3)父类的引用指向子类多态的三种形式:
1、 普通类多态定义的格式父类 变量名 = new 子类();class Fu {}class Zi extends Fu {}//类的多态使用Fu f = new Zi();2、 抽象类多态定义的格式abstract class Fu {public abstract void method();}class Zi extends Fu {public void method(){System.out.println(“重写父类抽象方法”);}}//类的多态使用Fu fu= new Zi();3、接口多态定义的格式interface Fu {public abstract void method();}class Zi implements Fu {public void method(){System.out.println(“重写接口抽象方法”);}}//接口的多态使用Fu fu = new Zi();————————————————版权声明:本文为CSDN博主「好吃不过炸酱面」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/lingang1991/article/details/69905944
1.4static的用法和区别
用法:可以用来修饰类、变量、方法、代码块。
区别:用来修饰类的时候该类是静态内部类;
用来修饰变量的时候,该变量可以被可以被所有的实例化对象所共享;用来修饰方法的时候,该方法只能用类名来调用;用来修饰代码块的时候,该代码块被称为静态代码块,静态代码块在整个类加载的时候只会执行一次;
1.5final的用法和作用
用法:final可以用来修饰类、方法、成员变量、普通变量、引用
作用:用来修饰类的时候此类不可以被继承;
用来修饰方法的时候此方法不可以被重写;用来修饰成员变量的时候此成员变量必须初始化,并且一旦赋值便不可再改变;用来修饰局部变量的时候,可以不初始化,但是一旦进行赋值便也不可再改变;用来修饰引用的时候,表示引用不可改变,但是引用指向的内容可以改变;
1.6ArrayList的初始容量和扩容过程
使用无参构造创建一个arrayList对象的时候底层会创建一个初始容量是0的数组,当使用add方法的时候会将数组的容量扩到10,当添加的元素超过10的时候会创建一个新的数组,容量是前一个数组的1.5倍,并把原来的数组复制到新的数组中。
1.7HashMap的底层结构
HashMap是一种依据数组+单向链表+红黑树实现存在的键值对的数据结构。底层结构是数组。对于要存的键值对,先通过Hash函数把键作为参数计算出相应的值,再根据计算出来的值指定数据存储的位置。当通过Hash函数计算出来的值有冲突时,先对键通过equal进行比较,相同时进行覆盖,不同则添加到链表上,链表如果过长效率就会大大降低,在jdk1.8中,当链表的长度超过8是,就会转为红黑树,效率就会得到大大的提升。
1.8HashMap的头插法和尾插法的区别?
头插法是JDK1.7时使用的插入方法,头插法时操作速度时最快的,每次插入时,头结点都会发生改变位最新,因为底层使用的是单链表的纵向延伸,但是头插法在多线程下回忆起链表的死循环。
尾插法是JDK1.8是使用的插入方法,1.8使用的红黑树采用的尾插法,插入时插入到链表的最后一节点之后,当链表的长度大于8时就会转换成红黑树,链表的长度不会大于8,能够有效的避免出现逆序和链表死循环的问题。
1.9ConCurrentHashMap的底层实现原理?
在JDK1.7版本中,ConcurrentHashMap的数据结构是由一个Segment数组和多个HashEntry组成,Segment数组的意义就是将一个大的table分割成多个小的table来进行加锁,也就是锁分离技术,而每一个Segment元素存储的是HashEntry数组+链表,这个和HashMap的数据存储结构一样。
JDK1.8的实现已经摒弃了Segment的概念,而是直接用Node数组+链表+红黑树的数据结构来实现
1.10请写出4种创建线程的方式
a.实现Runnable接口,重写里面的run方法。由于Runnable是函数式接口,所以可以使用lamda表达式。
b. 创建一个子类实现Callable接口,重写里面的call方法;
使用FutureTask 接收 Callable接口的实现类; 通过Thread将线程启动 通过FutureTask 中的get方法,获取子线程的返回值
c.继承Thread 重写run方法
d.通过线程池创建子线程
public class Thread4 {public static void main(String[] args) {ExecutorService executorService = new ThreadPoolExecutor(// 核心线程数3,// 最大线程数5,// 空闲线程的等待时间1L,// 时间单位TimeUnit.SECONDS,// 等待队列new ArrayBlockingQueue<>(3),// 线程工厂,用来创建线程Executors.defaultThreadFactory(),// 拒绝策略new ThreadPoolExecutor.AbortPolicy());for (int i=0;i<20;i++){executorService.execute(()->{System.out.println(Thread.currentThread().getName()+"===>正在执行");});}executorService.shutdown();}}
1.11聊聊线程的生命周期
新建状态(New):至今尚未启动的线程的状态。线程刚被创建,但尚未启动。如:Thread t = new MyThread();
就绪状态(Runnable):当调用线程对象的start()方法(t.start();),线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行;
运行状态(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。注:就 绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;
阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才有机会再次被CPU调用以进入到运行状态。
死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
1.13谈谈sleep和wait的区别
sleep是Thread类的方法,wait是Object类的方法;
从使用角度看sleep可以在任何地方使用,而wait只能在同步方法或者同步块中使用;
从CPU及资源锁释放方面来看,sleep,wait调用后都会暂停当前线程并让出cpu的执行时间,但不同的是sleep不会释放当前持有的对象的锁资源,到时间后会继续执行,而wait会放弃所有锁并需要notify/notifyAll后重新获取到对象锁资源后才能继续执行。
二、常用框架
2.1 谈谈对微服务的理解
微服务是一种分布式系统解决方案,把复杂的系统设计与开发的问题拆分为几个简单功能的子系统,把一个大的项目拆分为几个子模块,每个模块导入各自需要的依赖,每个项目有自己的项目名,有自己的端口号,可以独自运行,被浏览器访问。
2.2 请写出Nacos的作用
2.3 请写出gateway的好处和作用
2.4 SpingCloud框架中的各种O
VO(View Object):视图对象,用于展示层,它的作用是把某个指定页面(或组件)的所有数据封装起来。
DTO(Data Transfer Object):数据传输对象,这个概念来源于J2EE的设计模式,原来的目的是为了EJB的分布式应用提供粗粒度的数据实体,以减少分布式调用的次数,从而提高分布式调用的性能和降低网络负载,但在这里,我泛指用于展示层与服务层之间的数据传输对象。
DO(Domain Object):领域对象,就是从现实世界中抽象出来的有形或无形的业务实体。
PO(Persistent Object):持久化对象,它跟持久层(通常是关系型数据库)的数据结构形成一一对应的映射关系,如果持久层是关系型数据库,那么,数据表中的每个字段(或若干个)就对应PO的一个(或若干个)属性。
三、数据库
3.1请谈谈sql优化
sql优化需要先开启慢查询日志对sql语句的等级进行判定,需要在逻辑上以及硬件上对sql进行优化。
sql优化需要遵从三点:
最大化利用索引,尽量避免全表扫描,减少无效数据的查询。
3.2事务的三种注入方式
1、编码式,直接创建一个事务对象。
2、通过AOP进行注入
3、通过注解的方式
四、Redis
JVM
内存模型(1.7 和1.8),每个区域做什么
程序计数器(线程私有):
是当前线程锁执行字节码的行号治时期,每条线程都有一个独立的程序计数器,这类内存也称为“线程私有”的内存。正在执行java方法的话,计数器记录的是虚拟机字节码指令的地址(当前指令的地址)。如果是Natice方法,则为空。
java 虚拟机栈
也是线程私有的。
每个方法在执行的时候也会创建一个栈帧,存储了局部变量,操作数,动态链接,方法返回地址。
每个方法从调用到执行完毕,对应一个栈帧在虚拟机栈中的入栈和出栈。
通常所说的栈,一般是指在虚拟机栈中的局部变量部分。
局部变量所需内存在编译期间完成分配,如果线程请求的栈深度大于虚拟机所允许的深度,则StackOverflowError。
如果虚拟机栈可以动态扩展,扩展到无法申请足够的内存,则OutOfMemoryError。
本地方法栈(线程私有)
和虚拟机栈类似,主要为虚拟机使用到的Native方法服务。也会抛出StackOverflowError 和OutOfMemoryError。
Java堆(线程共享)
被所有线程共享的一块内存区域,在虚拟机启动的时候创建,用于存放对象实例。
对可以按照可扩展来实现(通过-Xmx 和-Xms 来控制)
当队中没有内存可分配给实例,也无法再扩展时,则抛出OutOfMemoryError异常。
方法区(线程共享)
被所有方法线程共享的一块内存区域。
用于存储已经被虚拟机加载的类信息,常量,静态变量等。
这个区域的内存回收目标主要针对常量池的回收和堆类型的卸载。
