阿里-面经3(钉钉面试的准备)

为什么要用Aop?

    假如没有aop,那么在做日志处理的时候,我们需要在每个方法中添加日志处理,而这些操作都是重复的,所以使用aop的一个好处就是减少代码的重用。假如两个方法是强耦合的,假如某个时候我们不需要某个功能了,或者想替换成其他功能,那么必须一个个地进行修改,而通过aop的动态代理,可以将一些横向的功能抽离出来形成独立的模块,然后在指定位置插入

Aop的代理模式?

     aop的代理模式分为静态代理和动态代理,静态代理是AspectJ,是在编译期就进行代理的,它的缺点就是代理对象的接口只服务于一种类型的对象,假如接口增加了一种方法,那么不仅实现该接口的方法需要实现该接口,代理类也要实现。动态代理分为Jdk动态代理和CGLIB动态代理,jdk代理只提供接口的代理,不支持类的代理,而CGLIB动态代理是通过继承来实现的,在运行时会为类生成一个子类,该子类对父类的特定的方法做了增强处理,以此来实现的aop,CGLIB是通过继承来实现的,所以假如一个类被声明为final的话,那么该类就无法通过CGLIB动态代理了

+,String,StringBuilder,StringBuffer?

     String是一个final类,是不能够被继承的,它的成员方法都是final的,所以方法也不能被覆盖,String的底层是通过一个final的char数组来进行保存字符串的,String的+是创建一个新的String对象,它的substring()和concat方法都不是在原来的字符串进行操作的,而是创建一个新的String对象,意思就是对String对象的任何改变都不会影响到原来的对象

    String str = "hello world"可能创建一个对象,也看不创建对象,假如常量池中不存在该对象,那么就创建,假如存在,就会直接利用原来的值,也就是str指向那个常量的内存地址,这样无论你创建多少个“hello world”,都只有一个内存地址被分配,而假如通过new String(“hello world”)来创建一个新的string时,就不是这种情况了,这个时候可能创建一个对象也可能创建两个,首先,堆里面的对象是可以重复的,那么堆首先会创建一个,然后加入常量池没有,就会再创建一个,所以每次new都是一个新的对象

        三者的区别:string用+时是创建一个新的对象,然后让原来的string指向新的对象的内存地址。而StringBuilder是变量,只生成了一个对象,new操作只有一次,它的+不会新创建对象,该操作是在原有对象上进行的,所以,当进行大量的修改字符串的操作时,选StringBuilder的好处大得多,而StringBuffer其实和StringBuilder几乎一样,除了StringBuffer是线程安全的

       三者的适用场景:假如是在循环体外的拼接,用string和StringBuilder一样。假如在循环体内,用StringBuilder,毫无疑问,当然,多线程下用StringBuffer来代替StringBuilder

什么是线程安全?

       如果代码所在的进程中有多个线程同时运行,而这些线程可能会同时运行这段代码,假如每次运行的结果都和单线程下运行的结果一样,那么就是线程安全的

Synchronized和lock?

     synchronized是java的关键字,是jvm层面上的,Lock就是一个类,synchronized获取锁的线程执行完同步代码,会释放锁,线程发生异常时,jvm会让线程释放锁,Lock必须在finally中释放锁,不然容易造成死锁。synchronized是隐式地释放和获取锁的,而Lock的是显示的释放和获取锁,synchronized是可重入,不可中断,非公平的,而lock可中断,还可以选择公平和非公平,并且synchronized不能设置超时时间。两种锁的底层实现方式也有所不同:synchronized主要是靠的monitorenter和monitorexit这两个指令来实现的,而Lock的实现机制主要是CAS,是一种乐观锁,它的底层是volatile和CAS操作

ThreadLocal?

    该类能够将线程中的某个值与保存值的对象关联起来,ThreadLocal提供了get和set方法,这些方法会为每一个使用该变量的线程保存一份独立的副本,因此我们通过get操作总是能够获取到最新的该线程的值。

    它主要是用来防止对可变的单实例变量或全局变量进行共享,还有当某个频繁执行地操作需要一个对象时,又不想频繁地创建和销毁该对象就可以用到ThreadLocal

   在我们第一次调用get方法时,会调用initialValue方法获取初始值,ThreadLocal的底层用到ThreadlocalMap,它的key永远都是该线程,set操作就是将自己作为key,值作为value放进该map中。这样每一个线程都维护一个单独的ThreadLocalMap,这样设计能够减少内存的使用,但是可能会出现内存泄漏(这里会出现弱引用,因为key线程是一个长生命周期的对象,持有了value那个短生命周期的引用)

HashMap和ConcurrentHashMap?

     hashMap它是通过hashing原来实现的,它的get和put方法用来获取和保存一个键值对,首先是put方法,会根据传入的key的哈希值找到对应的bucket,然后将该键值对放上去,hashmap的get方法首先会根据传入的key,调用hashcode找到对应的bucket,然后再调用equals方法找到对应的键值对,返回该值。hashmap不是线程安全的,因为hashmap存在着负载因子,当容量达到了负载因子时,就会进行扩容,也就是再哈希,而这个过程会为hashmap中的元素重新计算一个位置并放到新的数组中,而这个过程中当多个线程进行put操作时假如key的hashcode相同,他们就会形成一个环,当下一次调用get方法来获取该value时,就会造成死循环,所以不是线程安全的。哦,对了,hashmap可能还会存在哈希冲突,不过,当出现哈希冲突时,对应的bucket会形成一个链表,所以就能放在链表的下一个节点了。假如要想使hashmap线程安全,我们可以通过Collections.SynchronizedMap包装hashmap,或者直接使用concurrentHashMap.

     concurrentHashMap是线程安全的,其实HashTable也是线程安全的,只不过concurrentHashMap的性能更好,在1.7版本中,concurrentHashMap使用的是分段锁策略来实现的线程安全,而在1.8版本中,使用的是synchronized+CAS来实现的线程安全。然后我想说下1.8版本concurrentHashMap是怎么实现的,它是通过数组+链表+红黑树实现的。它的初始化是一个空实现,真正的初始化操作是在put操作里进行的,假入put时发现没有初始化,会先进行初始化,然后假如没有hash冲突就会用CAS的方式进行插入,如果有冲突,就会用synchronized上锁进行插入,这里有两种put方式;1.当前是链表,那么直接遍历到链表尾部进行插入,2是当节点数大于8个时,转换为红黑树,然后break出去,再进来插入。get操作就直接定位通过hashcode定位到对应位置,首节点符合就直接返回,否则就向下遍历,假入不匹配,返回null。

      这就是我对hashmap和concurrenthashMap的了解

OOM?

     OOM就是内存溢出。可能是因为新的对象太大,而堆的内存空间不够就会发生,也有可能是出现了内存泄漏,也就是长生命周期的对象持有着短生命周期对象的引用,导致那个对象无法被回收

    解决方案:直接增大堆内存,或者去检查代码,看看哪里有上面的情况出现

双亲委派模型?

      就是要求除了启动类加载器外,每一个类加载器都必须要有自己的父类,类加载器主要分为启动类加载器,扩展类加载器,应用程序类加载器,自定义类加载器。当一个类要进行加载时,并不会交给当前的类加载器去处理,而是会将请求委托给父类,直到顶层,假如启动类加载器也加载不了,那么才会向下让子类进行加载。双亲委派模型确保了不会重复加载一个类,也保证了核心类不会被篡改,也保证了类的优先级。当然,有些是会破坏双亲委派模型的,比如JNDI和Spring都破坏了,他们使用的类加载器是线程上下文类加载器

mysql的存储引擎?

    主要分为InnoDB和myisAm两种,现在InnoDB是mysql的默认存储引擎。他们的区别是,InnoDB支持事务,支持外键,并且支持行级锁,而myisAM不支持,但是myisAM支持全文索引。所以,在读比较多的情况下,建议使用myisAM,在写比较多的场景下,建议使用innoDB。

分布式下如何解决并发写入?

    使用分布式锁

三个线程轮流打印出abcabc,怎么做?

   

什么时候应该进行垃圾回收?

      新生代:新生代的eden满了,就会触发新生代GC,当一个对象大于老年代中最大连续内存空间时,老年代就会进行老年代GC

synchronized了解吗?什么时候会出现?

    了解,当需要进行多线程时的安全操作时,也就是多个线程都要访问一个方法时,想让一次只有一个线程能够进入方法内时就需要用到synchronized

进程和线程的区别?

    进程是系统资源调度的基本单元,而线程是cpu调度的基本单元,每个进程都有独立的内存空间,而多个线程共享一个内存空间,一个进程可以有多个线程,线程也叫作轻量级进程。

二叉查找树的时间复杂度?

    LogN

什么时候内存会溢出?

    如果要存放的对象太大,堆的内存空间不足够时就会产生内存溢出

    当一个长生命周期的对象持有一个短生命周期的引用时,导致那个对象无法被垃圾回收,这样的对象越来越多,就会导致内存溢出

HashMap容量大了再扩容,比较耗时怎么办?

     hashMap的初始容量预设大一点

快排的原理?

    分治

项目有难点吗?

    自我感觉我的项目其实没什么难点,但是对我来说很合适,因为通过这个项目将我所学的,我会的东西都用上了,虽然可能深度不够,但是我感觉宽度还是不错的

用语言描述一棵二叉树?

      二叉树是是用链表实现的,他的左右节点分别指向左右子树,然后它自己会有一个值,由于看起来像是一棵倒立的数,所以这种数据结构就是树

插入排序,快速排序?

    插入排序:将待排序的数据分为两部分,一部分是有序的,另一部分是无序的,从无序的那部分里面将每个元素在有序的这边找到合适的位置进行插入,这就是插入排序,时间复杂度O(N^2),所以是比较慢的。

   

快排,时间复杂度:NLogn

优先队列构建过程:

  优先队列是一种用来维护一组元素构成的集合S的数据结构,并且每个元素都有一个关键key,元素之间的比较是通过比较key来比较的。优先队列包括最大优先队列和最小优先队列,它的实现可以选择堆这个数据结构。最大优先队列一般将一个元素插入到集合S中,返回集合S中最大key的元素,返回并删除集合S中具有最大key的元素等

    插入操作:首先把一个元素放到所有元素的下一位置,然后执行“上浮操作”,发现比它大的,则进行交换,一直到它对应的位置(这里说的是最小堆)

   移除操作:在队列非空情况下移除集合中第一个元素,也就是下标为0的元素,然后将集合中最后一个元素移到下标为0的位置开始进行下沉操作,和比它小的进行交换位置,直到到底自己的位置

为什么MyisAM不支持行锁?而innoDB支持?

    因为myisAM的一级索引和二级索引都指向物理行,当通过一级索引或者二级索引来查询数据的时候,都是先查找到物理位置,然后再在物理位置上去寻找数据。而InnoDB的一级索引存储索引,二级索引存储的是主键的id,通过一级索引进行查找的时候能够很快查到数据,通过二级索引查找数据的时候,需要先找到对应的主键id,然后才能查找到对应的数据,也就是说InnoDB在一级索引时在叶子结点上存放数据,在非叶子节点上存储了行的数据,也叫作聚簇索引。所以,InnoDB支持行锁,因为InnoDB的索引和数据是在一起的,而myisAM的索引和数据是分离的,myisAM天生就是非聚簇索引,之所以innoDB可以锁行,是因为InnoDB的索引结构上即存储了索引,又存储了数据,而myisAM的索引指向的是另一片数据,所以没法精确地锁住数据段

什么情况下放弃使用索引?

     当数据量不多时,当数据不是频繁使用时,当列值中可以有null时就放弃使用索引吧

Object的方法有哪些?

    hashcode(),equals(),clone(),toString(),finalize()

什么是深拷贝与浅拷贝?

   浅拷贝:被复制的对象的所有变量都与原对象有相同的值,索引的引用对象任然指向原来的对象,也就是说浅拷贝不复制引用对象

  深拷贝:除了被复制的对象的所有变量都有原来的对象的值之外,还把引用对象也指向了被复制的对象

继承和组合的区别?

    组合可以显示地获得被包含类的对象,而继承是隐式地获得父类的对象的

   组合是在运行时期确定的,继承是在编译时期决定的

   组合是一种松耦合,继承是紧耦合

   在使用继承关系时,可以实现类型的回溯, 即父类变量引用子类变量,通过此实现多态,而组合不行

http协议?

   http协议是一种超文本传输协议,是应用层上的协议,允许将html从web服务器发送到浏览器,它是一种无状态的协议,并且请求只能由客户端发起,而服务器不能主动发送数据,它是一种基于tcp/ip的协议

数据库的分页过程:

    InnoDB中存储空间管理的最小单位是页,页的默认大小是16kb。每个页中都存放了数据。页与页之间通过双向链表连接,索引中的数据会根据主键的值从小到大排列并用单向链表连接,在建立目录的过程中规定了下一个数据页的主键值必须大于上一个数据页的主键值。当一个页中的数据超过了范围就会产生新的页,这个时候主键小的跑到上一个页,大的往后一个页移动,这就是说页分裂

rabbitmq的三种常用路由?

   1.direct:这种模式下,交换机根据routingkey进行完全匹配,匹配失败则丢弃消息

   2.fanout:这种模式会完全忽略掉路由键,只要向交换机中发送消息,就会广播给与交换机绑定的所有消息队列

   3.top: 这种模式可以和路由键进行模糊匹配,如果失败则丢弃消息,如果匹配多个结果,则向多个结果都发消息

ioc的好处?

   对象的构建假如果依赖非常多的对象,并且层次很深的话,外层在构造对象时会很麻烦,而ioc帮我们管理对象的创建,只需要在配置文件里指定如何构建就行,最外层的对象不需要关心深层次对象是如何创建的。也就是假如我们修改深层次的对象的话,那么上层的所有类几乎都要去进行修改,这样的维护成本太高,而假如用ioc,我们只需要修改你要修改的那个类就行了,不用去修改其他上层楼,并且我们在创建实例时不需要了解他的细节。

      

发布了208 篇原创文章 · 获赞 0 · 访问量 5969

猜你喜欢

转载自blog.csdn.net/qq_40058686/article/details/104684443